Changeset 111:f9415e5b6d0c in livinglogic.java.ul4

Show
Ignore:
Timestamp:
06/23/08 21:05:04 (11 years ago)
Author:
Walter Doerwald <walter@…>
Branch:
default
Message:

Port the code tokenizer to Java.

Location:
library/src/com/livinglogic/ull
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • library/src/com/livinglogic/ull/Compiler.java

    r107 r111  
    22 
    33import java.util.Properties; 
    4 import java.util.regex.Pattern; 
    5 import java.util.regex.Matcher; 
    64import java.util.List; 
    7 import java.util.LinkedList; 
    85 
    96import org.python.core.PyObject; 
     
    2724    } 
    2825 
    29     public static List tokenize(String source, String startdelim, String enddelim) 
    30     { 
    31         Pattern tagPattern = Pattern.compile(escapeREchars(startdelim) + "(print|code|for|if|elif|else|end|render)(\\s*((.|\\n)*?)\\s*)?" + escapeREchars(enddelim)); 
    32         LinkedList tags = new LinkedList(); 
    33         Matcher matcher = tagPattern.matcher(source); 
    34         int pos = 0; 
    35  
    36         int start; 
    37         int end; 
    38         while (matcher.find()) 
    39         { 
    40             start = matcher.start(); 
    41             end = start + matcher.group().length(); 
    42             if (pos != start) 
    43                 tags.add(new Location(source, null, pos, start, pos, start)); 
    44             int codestart = matcher.start(3); 
    45             int codeend = codestart + matcher.group(3).length(); 
    46             tags.add(new Location(source, matcher.group(1), start, end, codestart, codeend)); 
    47             pos = end; 
    48         } 
    49         end = source.length(); 
    50         if (pos != end) 
    51             tags.add(new Location(source, null, pos, end, pos, end)); 
    52         return tags; 
    53     } 
    54  
    55     private static String escapeREchars(String input) 
    56     { 
    57         int len = input.length(); 
    58  
    59         StringBuffer output = new StringBuffer(len); 
    60  
    61         for (int i = 0; i < len; ++i) 
    62         { 
    63             char c = input.charAt(i); 
    64             if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) 
    65                 output.append('\\'); 
    66             output.append(c); 
    67         } 
    68         return output.toString(); 
    69     } 
    70  
    7126    public static Template compile(String source) 
    7227    { 
     
    7631    public static Template compile(String source, String startdelim, String enddelim) 
    7732    { 
    78         List tags = tokenize(source, startdelim, enddelim); 
     33        List tags = Template.tokenizeTags(source, startdelim, enddelim); 
    7934        return compiler.compile(source, tags, startdelim, enddelim); 
    8035    } 
  • library/src/com/livinglogic/ull/Template.java

    r105 r111  
    1212import java.util.Iterator; 
    1313import java.util.Map; 
     14import java.util.regex.Pattern; 
     15import java.util.regex.Matcher; 
    1416 
    1517public class Template 
    1618{ 
     19    // used by the code tokenizer 
     20    private static Pattern tokenPattern; 
     21    private static Pattern namePattern; 
     22    private static Pattern floatPattern; 
     23    private static Pattern hexintPattern; 
     24    private static Pattern octintPattern; 
     25    private static Pattern binintPattern; 
     26    private static Pattern intPattern; 
     27    private static Pattern whitespacePattern; 
     28    private static Pattern escaped8BitCharPattern; 
     29    private static Pattern escaped16BitCharPattern; 
     30    private static Pattern escaped32BitCharPattern; 
     31 
     32    static 
     33    { 
     34        // Initializes regular expressions 
     35        tokenPattern = Pattern.compile("\\(|\\)|\\[|\\]|\\.|,|==|\\!=|=|\\+=|\\-=|\\*=|/=|//=|%=|%|:|\\+|-|\\*|//|/"); 
     36        namePattern = Pattern.compile("[a-zA-Z_][\\w]*"); 
     37        // We don't have negatve numbers, this is handled by constant folding in the AST for unary minus 
     38        floatPattern = Pattern.compile("(\\d+(\\.\\d*)?[eE][+-]?\\d+|\\d+\\.\\d*([eE][+-]?\\d+)?)"); 
     39        hexintPattern = Pattern.compile("0[xX][\\da-fA-F]+"); 
     40        octintPattern = Pattern.compile("0[oO][0-7]+"); 
     41        binintPattern = Pattern.compile("0[bB][01]+"); 
     42        intPattern = Pattern.compile("\\d+"); 
     43        whitespacePattern = Pattern.compile("\\s+"); 
     44        escaped8BitCharPattern = Pattern.compile("\\\\x[0-9a-fA-F]{2}"); 
     45        escaped16BitCharPattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); 
     46        escaped32BitCharPattern = Pattern.compile("\\\\U[0-9a-fA-F]{8}"); 
     47    } 
     48 
    1749    class IteratorStackEntry 
    1850    { 
     
    815847        } 
    816848    } 
     849 
     850    public static List tokenizeTags(String source, String startdelim, String enddelim) 
     851    { 
     852        Pattern tagPattern = Pattern.compile(escapeREchars(startdelim) + "(print|code|for|if|elif|else|end|render)(\\s*((.|\\n)*?)\\s*)?" + escapeREchars(enddelim)); 
     853        LinkedList tags = new LinkedList(); 
     854        Matcher matcher = tagPattern.matcher(source); 
     855        int pos = 0; 
     856 
     857        int start; 
     858        int end; 
     859        while (matcher.find()) 
     860        { 
     861            start = matcher.start(); 
     862            end = start + matcher.group().length(); 
     863            if (pos != start) 
     864                tags.add(new Location(source, null, pos, start, pos, start)); 
     865            int codestart = matcher.start(3); 
     866            int codeend = codestart + matcher.group(3).length(); 
     867            tags.add(new Location(source, matcher.group(1), start, end, codestart, codeend)); 
     868            pos = end; 
     869        } 
     870        end = source.length(); 
     871        if (pos != end) 
     872            tags.add(new Location(source, null, pos, end, pos, end)); 
     873        return tags; 
     874    } 
     875 
     876    private static String escapeREchars(String input) 
     877    { 
     878        int len = input.length(); 
     879 
     880        StringBuffer output = new StringBuffer(len); 
     881 
     882        for (int i = 0; i < len; ++i) 
     883        { 
     884            char c = input.charAt(i); 
     885            if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))) 
     886                output.append('\\'); 
     887            output.append(c); 
     888        } 
     889        return output.toString(); 
     890    } 
     891 
     892    public static List tokenizeCode(Location location) throws LexicalException 
     893    { 
     894        String source = location.getCode(); 
     895 
     896        LinkedList tokens = new LinkedList(); 
     897 
     898        int pos = 0; 
     899        int stringStartPos = 0; // The starting position of a string constant 
     900        int stringMode = 0; // 0 == default; 1 == single-quoted string; 2 == double-quoted strings 
     901        StringBuffer collectString = null; // characters are collected here, while we're in a string constant 
     902 
     903        try 
     904        { 
     905            while (source.length() != 0) 
     906            { 
     907                Matcher tokenMatcher = tokenPattern.matcher(source); 
     908                Matcher nameMatcher = namePattern.matcher(source); 
     909                Matcher floatMatcher = floatPattern.matcher(source); 
     910                Matcher hexintMatcher = hexintPattern.matcher(source); 
     911                Matcher octintMatcher = octintPattern.matcher(source); 
     912                Matcher binintMatcher = binintPattern.matcher(source); 
     913                Matcher intMatcher = intPattern.matcher(source); 
     914                Matcher whitespaceMatcher = whitespacePattern.matcher(source); 
     915                Matcher escaped8BitCharMatcher = escaped8BitCharPattern.matcher(source); 
     916                Matcher escaped16BitCharMatcher = escaped16BitCharPattern.matcher(source); 
     917                Matcher escaped32BitCharMatcher = escaped32BitCharPattern.matcher(source); 
     918 
     919                int len; 
     920                if (stringMode==0 && tokenMatcher.lookingAt()) 
     921                { 
     922                    len = tokenMatcher.end(); 
     923                    tokens.add(new Token(pos, pos+len, tokenMatcher.group())); 
     924                } 
     925                else if (stringMode==0 && nameMatcher.lookingAt()) 
     926                { 
     927                    len = nameMatcher.end(); 
     928                    String name = nameMatcher.group(); 
     929                    if (name.equals("in") || name.equals("not") || name.equals("or") || name.equals("and") || name.equals("del")) 
     930                        tokens.add(new Token(pos, pos+len, name)); 
     931                    else if (name.equals("None")) 
     932                        tokens.add(new None(pos, pos+len)); 
     933                    else if (name.equals("True")) 
     934                        tokens.add(new True(pos, pos+len)); 
     935                    else if (name.equals("False")) 
     936                        tokens.add(new False(pos, pos+len)); 
     937                    else 
     938                        tokens.add(new Name(pos, pos+len, name)); 
     939                } 
     940                else if (stringMode==0 && floatMatcher.lookingAt()) 
     941                { 
     942                    len = floatMatcher.end(); 
     943                    tokens.add(new Float(pos, pos+len, Double.parseDouble(floatMatcher.group()))); 
     944                } 
     945                else if (stringMode==0 && hexintMatcher.lookingAt()) 
     946                { 
     947                    len = hexintMatcher.end(); 
     948                    tokens.add(new Int(pos, pos+len, Integer.parseInt(hexintMatcher.group().substring(2), 16))); 
     949                } 
     950                else if (stringMode==0 && octintMatcher.lookingAt()) 
     951                { 
     952                    len = octintMatcher.end(); 
     953                    tokens.add(new Int(pos, pos+len, Integer.parseInt(octintMatcher.group().substring(2), 8))); 
     954                } 
     955                else if (stringMode==0 && binintMatcher.lookingAt()) 
     956                { 
     957                    len = binintMatcher.end(); 
     958                    tokens.add(new Int(pos, pos+len, Integer.parseInt(binintMatcher.group().substring(2), 2))); 
     959                } 
     960                else if (stringMode==0 && intMatcher.lookingAt()) 
     961                { 
     962                    len = intMatcher.end(); 
     963                    tokens.add(new Int(pos, pos+len, Integer.parseInt(intMatcher.group()))); 
     964                } 
     965                else if (stringMode==0 && source.startsWith("'")) 
     966                { 
     967                    stringStartPos = pos; 
     968                    len = 1; 
     969                    stringMode = 1; 
     970                    collectString = new StringBuffer(); 
     971                } 
     972                else if (stringMode==0 && source.startsWith("\"")) 
     973                { 
     974                    stringStartPos = pos; 
     975                    len = 1; 
     976                    stringMode = 2; 
     977                    collectString = new StringBuffer(); 
     978                } 
     979                else if (stringMode==1 && source.startsWith("'") || (stringMode==2 && source.startsWith("\""))) 
     980                { 
     981                    len = 1; 
     982                    stringMode = 0; 
     983                    tokens.add(new Str(stringStartPos, pos+len, collectString.toString())); 
     984                    collectString = null; 
     985                } 
     986                else if (stringMode==0 && whitespaceMatcher.lookingAt()) 
     987                { 
     988                    len = whitespaceMatcher.end(); 
     989                } 
     990                else if (stringMode!=0 && source.startsWith("\\\\")) 
     991                { 
     992                    len = 2; 
     993                    collectString.append("\\"); 
     994                } 
     995                else if (stringMode!=0 && source.startsWith("\\'")) 
     996                { 
     997                    len = 2; 
     998                    collectString.append("'"); 
     999                } 
     1000                else if (stringMode!=0 && source.startsWith("\\\"")) 
     1001                { 
     1002                    len = 2; 
     1003                    collectString.append("\""); 
     1004                } 
     1005                else if (stringMode!=0 && source.startsWith("\\a")) 
     1006                { 
     1007                    len = 2; 
     1008                    collectString.append("\u0007"); 
     1009                } 
     1010                else if (stringMode!=0 && source.startsWith("\\b")) 
     1011                { 
     1012                    len = 2; 
     1013                    collectString.append("\u0008"); 
     1014                } 
     1015                else if (stringMode!=0 && source.startsWith("\\f")) 
     1016                { 
     1017                    len = 2; 
     1018                    collectString.append("\u000c"); 
     1019                } 
     1020                else if (stringMode!=0 && source.startsWith("\\n")) 
     1021                { 
     1022                    len = 2; 
     1023                    collectString.append("\n"); 
     1024                } 
     1025                else if (stringMode!=0 && source.startsWith("\\r")) 
     1026                { 
     1027                    len = 2; 
     1028                    collectString.append("\r"); 
     1029                } 
     1030                else if (stringMode!=0 && source.startsWith("\\t")) 
     1031                { 
     1032                    len = 2; 
     1033                    collectString.append("\t"); 
     1034                } 
     1035                else if (stringMode!=0 && source.startsWith("\\v")) 
     1036                { 
     1037                    len = 2; 
     1038                    collectString.append("\u000b"); 
     1039                } 
     1040                else if (stringMode!=0 && source.startsWith("\\e")) 
     1041                { 
     1042                    len = 2; 
     1043                    collectString.append("\u001b"); 
     1044                } 
     1045                else if (stringMode!=0 && escaped8BitCharMatcher.lookingAt()) 
     1046                { 
     1047                    len = 4; 
     1048                    collectString.append((char)Integer.parseInt(escaped8BitCharMatcher.group().substring(2), 16)); 
     1049                } 
     1050                else if (stringMode!=0 && escaped16BitCharMatcher.lookingAt()) 
     1051                { 
     1052                    len = 6; 
     1053                    collectString.append((char)Integer.parseInt(escaped16BitCharMatcher.group().substring(2), 16)); 
     1054                } 
     1055                else if (stringMode!=0 && escaped32BitCharMatcher.lookingAt()) 
     1056                { 
     1057                    len = 10; 
     1058                    throw new RuntimeException("character " + escaped32BitCharMatcher.group() + " (outside the BMP) not supported"); 
     1059                } 
     1060                else if (stringMode!=0) 
     1061                { 
     1062                    len = 1; 
     1063                    collectString.append(source.charAt(0)); 
     1064                } 
     1065                else 
     1066                { 
     1067                    throw new LexicalException(pos, pos+1, source.substring(0, 1)); 
     1068                } 
     1069                pos += len; 
     1070                source = source.substring(len); 
     1071            } 
     1072            if (stringMode != 0) 
     1073                throw new UnterminatedStringException(); 
     1074        } 
     1075        catch (LocationException ex) 
     1076        { 
     1077            throw ex; 
     1078        } 
     1079        catch (Exception ex) 
     1080        { 
     1081            // decorate inner exception with location information 
     1082            throw new LocationException(ex, location); 
     1083        } 
     1084        return tokens; 
     1085    } 
    8171086} 
  • library/src/com/livinglogic/ull/ullc.py

    r108 r111  
    2222def _compile(template, tags): 
    2323    opcodes = [] 
    24     scanner = Scanner() 
    25     parseexpr = ExprParser(scanner).compile 
    26     parsestmt = StmtParser(scanner).compile 
    27     parsefor = ForParser(scanner).compile 
    28     parserender = RenderParser(scanner).compile 
     24    parseexpr = ExprParser().compile 
     25    parsestmt = StmtParser().compile 
     26    parsefor = ForParser().compile 
     27    parserender = RenderParser().compile 
    2928 
    3029    # This stack stores for each nested for/foritem/if/elif/else the following information: 
     
    9897 
    9998 
    100 import java 
    101  
    102 ### 
    103 ### Tokenizer 
    104 ### 
    105  
    106 class Scanner(spark.GenericScanner): 
    107     def __init__(self): 
    108         spark.GenericScanner.__init__(self, re.UNICODE) 
    109         self.collectstr = [] 
    110  
    111     def tokenize(self, location): 
    112         self.rv = [] 
    113         self.start = 0 
    114         try: 
    115             spark.GenericScanner.tokenize(self, location.code) 
    116             if self.mode != "default": 
    117                 raise ull.UnterminatedStringException() 
    118         except ull.LocationException, exc: 
    119             raise 
    120         except java.lang.Exception, exc: 
    121             raise ull.LocationException(exc, location) 
    122         return self.rv 
    123  
    124     def token(self, start, end, s): 
    125         self.rv.append(ull.Token(start, end, s)) 
    126     token.spark = {"default": ["\\(|\\)|\\[|\\]|\\.|,|==|\\!=|=|\\+=|\\-=|\\*=|/=|//=|%=|%|:|\\+|-|\\*|//|/"]} 
    127  
    128     def none(self, start, end, s): 
    129         self.rv.append(ull.None(start, end)) 
    130     none.spark = {"default": ["None"]} 
    131  
    132     def true(self, start, end, s): 
    133         self.rv.append(ull.True(start, end)) 
    134     true.spark = {"default": ["True"]} 
    135  
    136     def false(self, start, end, s): 
    137         self.rv.append(ull.False(start, end)) 
    138     false.spark = {"default": ["False"]} 
    139  
    140     def name(self, start, end, s): 
    141         if s in ("in", "not", "or", "and", "del"): 
    142             self.rv.append(ull.Token(start, end, s)) 
    143         else: 
    144             self.rv.append(ull.Name(start, end, s)) 
    145     name.spark = {"default": ["[a-zA-Z_][\\w]*"]} 
    146  
    147     # We don't have negatve numbers, this is handled by constant folding in the AST for unary minus 
    148     def float(self, start, end, s): 
    149         self.rv.append(ull.Float(start, end, float(s))) 
    150     float.spark = {"default": ["\\d+(\\.\\d*)?[eE][+-]?\\d+", "\\d+\\.\\d*([eE][+-]?\\d+)?"]} 
    151  
    152     def hexint(self, start, end, s): 
    153         self.rv.append(ull.Int(start, end, int(s[2:], 16))) 
    154     hexint.spark = {"default": ["0[xX][\\da-fA-F]+"]} 
    155  
    156     def octint(self, start, end, s): 
    157         self.rv.append(ull.Int(start, end, int(s[2:], 8))) 
    158     octint.spark = {"default": ["0[oO][0-7]+"]} 
    159  
    160     def binint(self, start, end, s): 
    161         self.rv.append(ull.Int(start, end, int(s[2:], 2))) 
    162     binint.spark = {"default": ["0[bB][01]+"]} 
    163  
    164     def int(self, start, end, s): 
    165         self.rv.append(ull.Int(start, end, int(s))) 
    166     int.spark = {"default": ["\\d+"]} 
    167  
    168     def beginstr1(self, start, end, s): 
    169         self.mode = "str1" 
    170         self.start = start 
    171     beginstr1.spark = {"default": ["'"]} 
    172  
    173     def beginstr2(self, start, end, s): 
    174         self.mode = "str2" 
    175         self.start = start 
    176     beginstr2.spark = {"default": ['"']} 
    177  
    178     def endstr(self, start, end, s): 
    179         self.rv.append(ull.Str(self.start, end, "".join(self.collectstr))) 
    180         self.collectstr = [] 
    181         self.mode = "default" 
    182     endstr.spark = {"str1": ["'"], "str2": ['"']} 
    183  
    184     def whitespace(self, start, end, s): 
    185         pass 
    186     whitespace.spark = {"default": ["\\s+"]} 
    187  
    188     def escapedbackslash(self, start, end, s): 
    189         self.collectstr.append("\\") 
    190     escapedbackslash.spark = {"str1": ["\\\\\\\\"], "str2": ["\\\\\\\\"]} 
    191  
    192     def escapedapos(self, start, end, s): 
    193         self.collectstr.append("'") 
    194     escapedapos.spark = {"str1": ["\\\\'"], "str2": ["\\\\'"]} 
    195  
    196     def escapedquot(self, start, end, s): 
    197         self.collectstr.append('"') 
    198     escapedapos.spark = {"str1": ['\\\\"'], "str2": ['\\\\"']} 
    199  
    200     def escapedbell(self, start, end, s): 
    201         self.collectstr.append("\a") 
    202     escapedbell.spark = {"str1": ["\\\\a"], "str2": ["\\\\a"]} 
    203  
    204     def escapedbackspace(self, start, end, s): 
    205         self.collectstr.append("\b") 
    206     escapedbackspace.spark = {"str1": ["\\\\b"], "str2": ["\\\\b"]} 
    207  
    208     def escapedformfeed(self, start, end, s): 
    209         self.collectstr.append("\f") 
    210     escapedformfeed.spark = {"str1": ["\\\\f"], "str2": ["\\\\f"]} 
    211  
    212     def escapedlinefeed(self, start, end, s): 
    213         self.collectstr.append("\n") 
    214     escapedlinefeed.spark = {"str1": ["\\\\n"], "str2": ["\\\\n"]} 
    215  
    216     def escapedcarriagereturn(self, start, end, s): 
    217         self.collectstr.append("\r") 
    218     escapedcarriagereturn.spark = {"str1": ["\\\\r"], "str2": ["\\\\r"]} 
    219  
    220     def escapedtab(self, start, end, s): 
    221         self.collectstr.append("\t") 
    222     escapedtab.spark = {"str1": ["\\\\t"], "str2": ["\\\\t"]} 
    223  
    224     def escapedverticaltab(self, start, end, s): 
    225         self.collectstr.append("\v") 
    226     escapedverticaltab.spark = {"str1": ["\\\\v"], "str2": ["\\\\v"]} 
    227  
    228     def escapedescape(self, start, end, s): 
    229         self.collectstr.append("\x1b") 
    230     escapedescape.spark = {"str1": ["\\\\e"], "str2": ["\\\\e"]} 
    231  
    232     def escaped8bitchar(self, start, end, s): 
    233         self.collectstr.append(unichr(int(s[2:], 16))) 
    234     escaped8bitchar.spark = {"str1": ["\\\\x[0-9a-fA-F]{2}"], "str2": ["\\\\x[0-9a-fA-F]{2}"]} 
    235  
    236     def escaped16bitchar(self, start, end, s): 
    237         self.collectstr.append(unichr(int(s[2:], 16))) 
    238     escaped16bitchar.spark = {"str1": ["\\\\u[0-9a-fA-F]{4}"], "str2": ["\\\\u[0-9a-fA-F]{4}"]} 
    239  
    240     def text(self, start, end, s): 
    241         self.collectstr.append(s) 
    242     text.spark = {"str1": [".|\\n"], "str2": [".|\\n"]} 
    243  
    244     def default(self, start, end, s): 
    245         raise ull.LexicalException(start, end, s) 
    246     default.spark = {"default": ["(.|\\n)+"], "str1": ["(.|\\n)+"], "str2": ["(.|\\n)+"]} 
    247  
    248     def error(self, start, end, s): 
    249         raise ull.LexicalException(start, end, s) 
    250  
    251  
    25299### 
    253100### Parsers for different types of code 
     
    257104    emptyerror = "expression required" 
    258105 
    259     def __init__(self, scanner, start="expr0"): 
     106    def __init__(self, start="expr0"): 
    260107        spark.GenericParser.__init__(self, start) 
    261         self.scanner = scanner 
    262108 
    263109    def compile(self, template, location): 
     
    265111            raise ValueError(self.emptyerror) 
    266112        try: 
    267             ast = self.parse(self.scanner.tokenize(location)) 
     113            ast = self.parse(ull.Template.tokenizeCode(location)) 
    268114            registers = ull.Registers() 
    269115            return ast.compile(template, registers, location) 
     
    487333    emptyerror = "loop expression required" 
    488334 
    489     def __init__(self, scanner, start="for"): 
    490         ExprParser.__init__(self, scanner, start) 
     335    def __init__(self, start="for"): 
     336        ExprParser.__init__(self, start) 
    491337 
    492338    def for0(self, (iter, _0, cont)): 
     
    510356    emptyerror = "statement required" 
    511357 
    512     def __init__(self, scanner, start="stmt"): 
    513         ExprParser.__init__(self, scanner, start) 
     358    def __init__(self, start="stmt"): 
     359        ExprParser.__init__(self, start) 
    514360 
    515361    def stmt_assign(self, (name, _0, value)): 
     
    549395    emptyerror = "render statement required" 
    550396 
    551     def __init__(self, scanner, start="render"): 
    552         ExprParser.__init__(self, scanner, start) 
     397    def __init__(self, start="render"): 
     398        ExprParser.__init__(self, start) 
    553399 
    554400    def render(self, (name, _1, expr, _2)):