root/livinglogic.java.ul4/src/main/antlr3/com/livinglogic/ul4/UL4.g @ 796:8db43aa29203

Revision 796:8db43aa29203, 14.2 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Update to the current state of the Python implmentation.

Templates and functions are merged again.

AST nodes keep their start and end index for simplified toString() formatting.

Line 
1grammar UL4;
2
3options
4{
5    language=Java;
6    backtrack=true;
7    TokenLabelType=CommonToken;
8}
9
10@header
11{
12    package com.livinglogic.ul4;
13
14    import java.util.Date;
15
16    import com.livinglogic.ul4.Utils;
17    import com.livinglogic.ul4.Color;
18}
19
20@lexer::header
21{
22    package com.livinglogic.ul4;
23}
24
25
26@lexer::members
27{
28    private Location location;
29
30    public UL4Lexer(Location location, CharStream input)
31    {
32        this(input);
33        this.location = location;
34    }
35
36    @Override
37    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
38    {
39        String message = getErrorMessage(e, tokenNames) + " (at index " + e.index + ")";
40        throw new SyntaxException(message, e);
41    }
42}
43
44@parser::members
45{
46    private Location location;
47
48    public UL4Parser(Location location, TokenStream input)
49    {
50        this(input);
51        this.location = location;
52    }
53
54    @Override
55    public void displayRecognitionError(String[] tokenNames, RecognitionException e)
56    {
57        String message = getErrorMessage(e, tokenNames) + " (at index " + e.index + ")";
58        throw new SyntaxException(message, e);
59    }
60
61    public int getStart(CommonToken token)
62    {
63        return location.startcode + token.getStartIndex();
64    }
65
66    public int getEnd(CommonToken token)
67    {
68        return location.startcode + token.getStopIndex() + 1;
69    }
70}
71
72NONE
73    : 'None'
74    ;
75
76TRUE
77    : 'True'
78    ;
79
80FALSE
81    : 'False'
82    ;
83
84NAME
85    : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
86    ;
87
88fragment
89DIGIT
90    : '0'..'9'
91    ;
92
93fragment
94BIN_DIGIT
95    : ('0'|'1')
96    ;
97
98fragment
99OCT_DIGIT
100    : '0'..'7'
101    ;
102
103fragment
104HEX_DIGIT
105    : ('0'..'9'|'a'..'f'|'A'..'F')
106    ;
107
108/* We don't have negative ints (as this would lex "1-2" wrong) */
109INT
110    : DIGIT+
111    | '0' ('b'|'B') BIN_DIGIT+
112    | '0' ('o'|'O') OCT_DIGIT+
113    | '0' ('x'|'X') HEX_DIGIT+
114    ;
115
116fragment
117EXPONENT
118    : ('e'|'E') ('+'|'-')? DIGIT+
119    ;
120
121FLOAT
122    : DIGIT+ '.' DIGIT* EXPONENT?
123    | '.' DIGIT+ EXPONENT?
124    | DIGIT+ EXPONENT
125    ;
126
127fragment
128TIME
129    : DIGIT DIGIT ':' DIGIT DIGIT ( ':' DIGIT DIGIT ( '.' DIGIT DIGIT DIGIT DIGIT DIGIT DIGIT)?)?;
130
131DATE
132    : '@' '(' DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT ('T' TIME?)? ')';
133
134COLOR
135    : '#' HEX_DIGIT HEX_DIGIT HEX_DIGIT
136    | '#' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
137    | '#' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
138    | '#' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
139    ;
140
141WS
142    : (' '|'\t'|'\r'|'\n') { $channel=HIDDEN; }
143    ;
144
145STRING
146    : '"' ( ESC_SEQ | ~('\\'|'"'|'\r'|'\n') )* '"'
147    | '\'' ( ESC_SEQ | ~('\\'|'\''|'\r'|'\n') )* '\''
148    ;
149
150fragment
151ESC_SEQ
152    : '\\' ('a'|'b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
153    | UNICODE1_ESC
154    | UNICODE2_ESC
155    | UNICODE4_ESC
156    ;
157
158fragment
159UNICODE1_ESC
160    : '\\' 'x' HEX_DIGIT HEX_DIGIT
161    ;
162
163fragment
164UNICODE2_ESC
165    : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
166    ;
167
168fragment
169UNICODE4_ESC
170    : '\\' 'U' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
171    ;
172
173
174/* Rules common to all tags */
175
176none returns [AST node]
177    : NONE { $node = new Const(location, getStart($NONE), getEnd($NONE), null); }
178    ;
179
180true_ returns [AST node]
181    : TRUE { $node = new Const(location, getStart($TRUE), getEnd($TRUE), true); }
182    ;
183
184false_ returns [AST node]
185    : FALSE { $node = new Const(location, getStart($FALSE), getEnd($FALSE), false); }
186    ;
187
188int_ returns [AST node]
189    : INT { $node = new Const(location, getStart($INT), getEnd($INT), Utils.parseUL4Int($INT.text)); }
190    ;
191
192float_ returns [AST node]
193    : FLOAT { $node = new Const(location, getStart($FLOAT), getEnd($FLOAT), Double.parseDouble($FLOAT.text)); }
194    ;
195
196string returns [AST node]
197    : STRING { $node = new Const(location, getStart($STRING), getEnd($STRING), Utils.unescapeUL4String($STRING.text.substring(1, $STRING.text.length()-1))); }
198    ;
199
200date returns [AST node]
201    : DATE { $node = new Const(location, getStart($DATE), getEnd($DATE), Utils.isoparse($DATE.text.substring(2, $DATE.text.length()-1))); }
202    ;
203
204color returns [AST node]
205    : COLOR { $node = new Const(location, getStart($COLOR), getEnd($COLOR), Color.fromrepr($COLOR.text)); }
206    ;
207
208name returns [Var node]
209    : NAME { $node = new Var(location, getStart($NAME), getEnd($NAME), $NAME.text); }
210    ;
211
212literal returns [AST node]
213    : e_none=none { $node = $e_none.node; }
214    | e_false=false_ { $node = $e_false.node; }
215    | e_true=true_ { $node = $e_true.node; }
216    | e_int=int_ { $node = $e_int.node; }
217    | e_float=float_ { $node = $e_float.node; }
218    | e_string=string { $node = $e_string.node; }
219    | e_date=date { $node = $e_date.node; }
220    | e_color=color { $node = $e_color.node; }
221    | e_name=name { $node = $e_name.node; }
222    ;
223
224/* List literals */
225list returns [com.livinglogic.ul4.List node]
226    :
227        open='['
228        close=']' { $node = new com.livinglogic.ul4.List(location, getStart($open), getEnd($close)); }
229    |
230        open='[' {$node = new com.livinglogic.ul4.List(location, getStart($open), -1); }
231        e1=expr1 { $node.append($e1.node); }
232        (
233            ','
234            e2=expr1 { $node.append($e2.node); }
235        )*
236        ','?
237        close=']' { $node.setEnd(getEnd($close)); }
238    ;
239
240listcomprehension returns [ListComprehension node]
241    @init
242    {
243        AST _condition = null;
244    }
245    :
246        open='['
247        item=expr1
248        'for'
249        n=nestedname
250        'in'
251        container=expr1
252        (
253            'if'
254            condition=expr1 { _condition = $condition.node; }
255        )?
256        close=']' { $node = new ListComprehension(location, getStart($open), getEnd($close), $item.node, $n.varname, $container.node, _condition); }
257    ;
258
259/* Dict literal */
260fragment
261dictitem returns [DictItem node]
262    :
263        k=expr1
264        ':'
265        v=expr1 { $node = new DictItemKeyValue($k.node, $v.node); }
266    |
267        '**'
268        d=expr1 { $node = new DictItemDict($d.node); }
269    ;
270
271dict returns [Dict node]
272    :
273        open='{'
274        close='}' { $node = new Dict(location, getStart($open), getEnd($close)); }
275    |
276        open='{' { $node = new Dict(location, getStart($open), -1); }
277        i1=dictitem { $node.append($i1.node); }
278        (
279            ','
280            i2=dictitem { $node.append($i2.node); }
281        )*
282        ','?
283        close='}' { $node.setEnd(getEnd($close)); }
284    ;
285
286dictcomprehension returns [DictComprehension node]
287    @init
288    {
289        AST _condition = null;
290    }
291    :
292        open='{'
293        key=expr1
294        ':'
295        value=expr1
296        'for'
297        n=nestedname
298        'in'
299        container=expr1
300        (
301            'if'
302            condition=expr1 { _condition = $condition.node; }
303        )?
304        close='}' { $node = new DictComprehension(location, getStart($open), getEnd($close), $key.node, $value.node, $n.varname, $container.node, _condition); }
305    ;
306
307generatorexpression returns [GeneratorExpression node]
308    @init
309    {
310        AST _condition = null;
311        int _end = -1;
312    }
313    :
314        item=expr1
315        'for'
316        n=nestedname
317        'in'
318        container=expr1 { _end = $container.node.getEnd(); }
319        (
320            'if'
321            condition=expr1 { _condition = $condition.node; _end = $condition.node.getEnd(); }
322        )? { $node = new GeneratorExpression(location, $item.node.getStart(), _end, $item.node, $n.varname, $container.node, _condition); }
323    ;
324
325atom returns [AST node]
326    : e_literal=literal { $node = $e_literal.node; }
327    | e_list=list { $node = $e_list.node; }
328    | e_listcomp=listcomprehension { $node = $e_listcomp.node; }
329    | e_dict=dict { $node = $e_dict.node; }
330    | e_dictcomp=dictcomprehension { $node = $e_dictcomp.node; }
331    | '(' e_genexpr=generatorexpression ')' { $node = $e_genexpr.node; }
332    | '(' e_bracket=expr1 ')' { $node = $e_bracket.node; }
333    ;
334
335/* For variable unpacking in assignments and for loops */
336nestedname returns [Object varname]
337    :
338        n=name { $varname = $n.text; }
339    |
340        '(' n0=nestedname ',' ')' { $varname = java.util.Arrays.asList($n0.varname); }
341    |
342        '('
343        n1=nestedname
344        ','
345        n2=nestedname { $varname = new ArrayList(2); ((ArrayList)$varname).add($n1.varname); ((ArrayList)$varname).add($n2.varname); }
346        (
347            ','
348            n3=nestedname { ((ArrayList)$varname).add($n3.varname); }
349        )*
350        ','?
351        ')'
352    ;
353
354/* Function/method call, attribute access, item access, slice access */
355expr9 returns [AST node]
356    @init
357    {
358        AST index1 = null;
359        AST index2 = null;
360        boolean slice = false;
361    }
362    :
363        e1=atom { $node = $e1.node; }
364        (
365            /* Attribute access */
366            '.'
367            n=name { $node = new GetAttr(location, $e1.node.getStart(), $n.node.getEnd(), $node, $n.text); }
368        |
369            /* Function/method call */
370            '(' { $node = ($node instanceof GetAttr) ? ((GetAttr)$node).makeCallMeth() : new CallFunc(location, $e1.node.getStart(), -1, $node); }
371            (
372                /* No arguments */
373            |
374                /* "**" argument only */
375                '**' rkwargs=exprarg { ((Callable)$node).setRemainingKeywordArguments($rkwargs.node); }
376                ','?
377            |
378                /* "*" argument only (and maybe **) */
379                '*' rargs=exprarg { ((Callable)$node).setRemainingArguments($rargs.node); }
380                (
381                    ','
382                    '**' rkwargs=exprarg { ((Callable)$node).setRemainingKeywordArguments($rkwargs.node); }
383                )?
384                ','?
385            |
386                /* At least one positional argument */
387                a1=exprarg { ((Callable)$node).append($a1.node); }
388                (
389                    ','
390                    a2=exprarg { ((Callable)$node).append($a2.node); }
391                )*
392                (
393                    ','
394                    an3=name '=' av3=exprarg { ((Callable)$node).append($an3.text, $av3.node); }
395                )*
396                (
397                    ','
398                    '*' rargs=exprarg { ((Callable)$node).setRemainingArguments($rargs.node); }
399                )?
400                (
401                    ','
402                    '**' rkwargs=exprarg { ((Callable)$node).setRemainingKeywordArguments($rkwargs.node); }
403                )?
404                ','?
405            |
406                /* Keyword arguments only */
407                an1=name '=' av1=exprarg { ((Callable)$node).append($an1.text, $av1.node); }
408                (
409                    ','
410                    an2=name '=' av2=exprarg { ((Callable)$node).append($an2.text, $av2.node); }
411                )*
412                (
413                    ','
414                    '*' rargs=exprarg { ((Callable)$node).setRemainingArguments($rargs.node); }
415                )?
416                (
417                    ','
418                    '**' rkwargs=exprarg { ((Callable)$node).setRemainingKeywordArguments($rkwargs.node); }
419                )?
420                ','?
421            )
422            close=')' { $node.setEnd(getEnd($close)); }
423        |
424            /* Item/slice access */
425            '['
426            (
427                ':'
428                (
429                    e2=expr1 { index2 = $e2.node; }
430                )? { $node = GetSlice.make(location, $e1.node.getStart(), -1, $node, null, index2); }
431            |
432                e2=expr1 { index1 = $e2.node; }
433                (
434                    ':' { slice = true; }
435                    (
436                        e3=expr1 { index2 = $e3.node; }
437                    )?
438                )? { $node = slice ? GetSlice.make(location, $e1.node.getStart(), -1, $node, index1, index2) : GetItem.make(location, $e1.node.getStart(), -1, $node, index1); }
439            )
440            close=']' { $node.setEnd(getEnd($close)); }
441        )*
442    ;
443
444/* Negation */
445expr8 returns [AST node]
446    :
447        e1=expr9 { $node = $e1.node; }
448    |
449        minus='-' e2=expr8 { $node = Neg.make(location, getStart($minus), $e2.node.getEnd(), $e2.node); }
450    ;
451
452/* Multiplication, division, modulo */
453expr7 returns [AST node]
454    @init
455    {
456        int opcode = -1;
457    }
458    :
459        e1=expr8 { $node = $e1.node; }
460        (
461            (
462                '*' { opcode = 0; }
463            |
464                '/' { opcode = 1; }
465            |
466                '//' { opcode = 2; }
467            |
468                '%' { opcode = 3; }
469            )
470            e2=expr8 { switch (opcode) { case 0: $node = Mul.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 1: $node = TrueDiv.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 2: $node = FloorDiv.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 3: $node = Mod.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; } }
471        )*
472    ;
473
474/* Addition, substraction */
475expr6 returns [AST node]
476    @init
477    {
478        boolean add = false;
479    }
480    :
481        e1=expr7 { $node = $e1.node; }
482        (
483            (
484                '+' { add = true; }
485            |
486                '-' { add = false; }
487            )
488            e2=expr7 { $node = add ? Add.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node) : Sub.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
489        )*
490    ;
491
492/* Comparisons */
493expr5 returns [AST node]
494    @init
495    {
496        int opcode = -1;
497    }
498    :
499        e1=expr6 { $node = $e1.node; }
500        (
501            (
502                '==' { opcode = 0; }
503            |
504                '!=' { opcode = 1; }
505            |
506                '<' { opcode = 2; }
507            |
508                '<=' { opcode = 3; }
509            |
510                '>' { opcode = 4; }
511            |
512                '>=' { opcode = 5; }
513            )
514            e2=expr6 { switch (opcode) { case 0: $node = EQ.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 1: $node = NE.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 2: $node = LT.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 3: $node = LE.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 4: $node = GT.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; case 5: $node = GE.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); break; } }
515        )*
516    ;
517
518/* "in"/"not in" operator */
519expr4 returns [AST node]
520    @init
521    {
522        boolean not = false;
523    }
524    :
525        e1=expr5 { $node = $e1.node; }
526        (
527           
528            (
529                'not' { not = true; }
530            )?
531            'in'
532            e2=expr5 { $node = not ? NotContains.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node) : Contains.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
533        )?
534    ;
535
536/* Not operator */
537expr3 returns [AST node]
538    :
539        e1=expr4 { $node = $e1.node; }
540    |
541        n='not' e2=expr3 { $node = Not.make(location, getStart($n), $e2.node.getEnd(), $e2.node); }
542    ;
543
544
545/* And operator */
546expr2 returns [AST node]
547    :
548        e1=expr3 { $node = $e1.node; }
549        (
550            'and'
551            e2=expr3 { $node = And.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
552        )*
553    ;
554
555/* Or operator */
556expr1 returns [AST node]
557    :
558        e1=expr2 { $node = $e1.node; }
559        (
560            'or'
561            e2=expr2 { $node = Or.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
562        )*
563    ;
564
565exprarg returns [AST node]
566    : ege=generatorexpression { $node = $ege.node; }
567    | e1=expr1 { $node = $e1.node; }
568    ;
569
570expression returns [AST node]
571    : ege=generatorexpression EOF { $node = $ege.node; }
572    | e=expr1 EOF { $node = $e.node; }
573    ;
574
575
576/* Additional rules for "for" tag */
577
578for_ returns [For node]
579    :
580        n=nestedname
581        'in'
582        e=expr1 { $node = new For(location, location.getStartCode(), $e.node.getEnd(), $n.varname, $e.node); }
583        EOF
584    ;
585
586
587/* Additional rules for "code" tag */
588
589stmt returns [AST node]
590    : nn=nestedname '=' e=expr1 EOF { $node = new StoreVar(location, location.getStartCode(), $e.node.getEnd(), $nn.varname, $e.node); }
591    | n=name '+=' e=expr1 EOF { $node = new AddVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); }
592    | n=name '-=' e=expr1 EOF { $node = new SubVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); }
593    | n=name '*=' e=expr1 EOF { $node = new MulVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); }
594    | n=name '/=' e=expr1 EOF { $node = new TrueDivVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); }
595    | n=name '//=' e=expr1 EOF { $node = new FloorDivVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); }
596    | n=name '%=' e=expr1 EOF { $node = new ModVar(location, location.getStartCode(), $e.node.getEnd(), $n.text, $e.node); }
597    | e=expression EOF { $node = $e.node; }
598    ;
Note: See TracBrowser for help on using the browser.