root/livinglogic.java.ul4/src/main/antlr3/com/livinglogic/ul4/UL4.g @ 920:6090c7799c51

Revision 920:6090c7799c51, 15.7 KB (checked in by Walter Doerwald <walter@…>, 5 years ago)

Implement if expressions.

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
150STRING3
151    : '"""' (options {greedy=false;}:TRIQUOTE)* '"""'
152    |  '\'\'\'' (options {greedy=false;}:TRIAPOS)* '\'\'\''
153    ;
154
155fragment
156TRIQUOTE
157    : ('"'|'""')? (ESC_SEQ|~('\\'|'"'))+
158    ;
159
160fragment
161TRIAPOS
162    : ('\''|'\'\'')? (ESC_SEQ|~('\\'|'\''))+
163    ;
164
165fragment
166ESC_SEQ
167    : '\\' ('a'|'b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
168    | UNICODE1_ESC
169    | UNICODE2_ESC
170    | UNICODE4_ESC
171    ;
172
173fragment
174UNICODE1_ESC
175    : '\\' 'x' HEX_DIGIT HEX_DIGIT
176    ;
177
178fragment
179UNICODE2_ESC
180    : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
181    ;
182
183fragment
184UNICODE4_ESC
185    : '\\' 'U' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
186    ;
187
188
189/* Rules common to all tags */
190
191none returns [AST node]
192    : NONE { $node = new Const(location, getStart($NONE), getEnd($NONE), null); }
193    ;
194
195true_ returns [AST node]
196    : TRUE { $node = new Const(location, getStart($TRUE), getEnd($TRUE), true); }
197    ;
198
199false_ returns [AST node]
200    : FALSE { $node = new Const(location, getStart($FALSE), getEnd($FALSE), false); }
201    ;
202
203int_ returns [AST node]
204    : INT { $node = new Const(location, getStart($INT), getEnd($INT), Utils.parseUL4Int($INT.text)); }
205    ;
206
207float_ returns [AST node]
208    : FLOAT { $node = new Const(location, getStart($FLOAT), getEnd($FLOAT), Double.parseDouble($FLOAT.text)); }
209    ;
210
211string returns [AST node]
212    : STRING { $node = new Const(location, getStart($STRING), getEnd($STRING), Utils.unescapeUL4String($STRING.text.substring(1, $STRING.text.length()-1))); }
213    | STRING3 { $node = new Const(location, getStart($STRING3), getEnd($STRING3), Utils.unescapeUL4String($STRING3.text.substring(3, $STRING3.text.length()-3))); }
214    ;
215
216date returns [AST node]
217    : DATE { $node = new Const(location, getStart($DATE), getEnd($DATE), Utils.isoparse($DATE.text.substring(2, $DATE.text.length()-1))); }
218    ;
219
220color returns [AST node]
221    : COLOR { $node = new Const(location, getStart($COLOR), getEnd($COLOR), Color.fromrepr($COLOR.text)); }
222    ;
223
224name returns [Var node]
225    : NAME { $node = new Var(location, getStart($NAME), getEnd($NAME), $NAME.text); }
226    ;
227
228literal returns [AST node]
229    : e_none=none { $node = $e_none.node; }
230    | e_false=false_ { $node = $e_false.node; }
231    | e_true=true_ { $node = $e_true.node; }
232    | e_int=int_ { $node = $e_int.node; }
233    | e_float=float_ { $node = $e_float.node; }
234    | e_string=string { $node = $e_string.node; }
235    | e_date=date { $node = $e_date.node; }
236    | e_color=color { $node = $e_color.node; }
237    | e_name=name { $node = $e_name.node; }
238    ;
239
240/* List literals */
241list returns [com.livinglogic.ul4.List node]
242    :
243        open='['
244        close=']' { $node = new com.livinglogic.ul4.List(location, getStart($open), getEnd($close)); }
245    |
246        open='[' {$node = new com.livinglogic.ul4.List(location, getStart($open), -1); }
247        e1=expr_if { $node.append($e1.node); }
248        (
249            ','
250            e2=expr_if { $node.append($e2.node); }
251        )*
252        ','?
253        close=']' { $node.setEnd(getEnd($close)); }
254    ;
255
256listcomprehension returns [ListComprehension node]
257    @init
258    {
259        AST _condition = null;
260    }
261    :
262        open='['
263        item=expr_if
264        'for'
265        n=nestedlvalue
266        'in'
267        container=expr_if
268        (
269            'if'
270            condition=expr_if { _condition = $condition.node; }
271        )?
272        close=']' { $node = new ListComprehension(location, getStart($open), getEnd($close), $item.node, $n.lvalue, $container.node, _condition); }
273    ;
274
275/* Dict literal */
276fragment
277dictitem returns [DictItem node]
278    :
279        k=expr_if
280        ':'
281        v=expr_if { $node = new DictItemKeyValue($k.node, $v.node); }
282    |
283        '**'
284        d=expr_if { $node = new DictItemDict($d.node); }
285    ;
286
287dict returns [Dict node]
288    :
289        open='{'
290        close='}' { $node = new Dict(location, getStart($open), getEnd($close)); }
291    |
292        open='{' { $node = new Dict(location, getStart($open), -1); }
293        i1=dictitem { $node.append($i1.node); }
294        (
295            ','
296            i2=dictitem { $node.append($i2.node); }
297        )*
298        ','?
299        close='}' { $node.setEnd(getEnd($close)); }
300    ;
301
302dictcomprehension returns [DictComprehension node]
303    @init
304    {
305        AST _condition = null;
306    }
307    :
308        open='{'
309        key=expr_if
310        ':'
311        value=expr_if
312        'for'
313        n=nestedlvalue
314        'in'
315        container=expr_if
316        (
317            'if'
318            condition=expr_if { _condition = $condition.node; }
319        )?
320        close='}' { $node = new DictComprehension(location, getStart($open), getEnd($close), $key.node, $value.node, $n.lvalue, $container.node, _condition); }
321    ;
322
323generatorexpression returns [GeneratorExpression node]
324    @init
325    {
326        AST _condition = null;
327        int _end = -1;
328    }
329    :
330        item=expr_if
331        'for'
332        n=nestedlvalue
333        'in'
334        container=expr_if { _end = $container.node.getEnd(); }
335        (
336            'if'
337            condition=expr_if { _condition = $condition.node; _end = $condition.node.getEnd(); }
338        )? { $node = new GeneratorExpression(location, $item.node.getStart(), _end, $item.node, $n.lvalue, $container.node, _condition); }
339    ;
340
341atom returns [AST node]
342    : e_literal=literal { $node = $e_literal.node; }
343    | e_list=list { $node = $e_list.node; }
344    | e_listcomp=listcomprehension { $node = $e_listcomp.node; }
345    | e_dict=dict { $node = $e_dict.node; }
346    | e_dictcomp=dictcomprehension { $node = $e_dictcomp.node; }
347    | open='(' e_genexpr=generatorexpression close=')' { $node = $e_genexpr.node; $node.setStart(getStart($open)); $node.setEnd(getEnd($close)); }
348    | open='(' e_bracket=expr_if close=')' { $node = $e_bracket.node; $node.setStart(getStart($open)); $node.setEnd(getEnd($close)); }
349    ;
350
351/* For variable unpacking in assignments and for loops */
352nestedlvalue returns [Object lvalue]
353    :
354        n=expr_subscript { $lvalue = $n.node; }
355    |
356        '(' n0=nestedlvalue ',' ')' { $lvalue = java.util.Arrays.asList($n0.lvalue); }
357    |
358        '('
359        n1=nestedlvalue
360        ','
361        n2=nestedlvalue { $lvalue = new ArrayList(2); ((ArrayList)$lvalue).add($n1.lvalue); ((ArrayList)$lvalue).add($n2.lvalue); }
362        (
363            ','
364            n3=nestedlvalue { ((ArrayList)$lvalue).add($n3.lvalue); }
365        )*
366        ','?
367        ')'
368    ;
369
370
371/* Function/method call, attribute access, item access, slice access */
372expr_subscript returns [AST node]
373    @init
374    {
375        AST index1 = null;
376        AST index2 = null;
377        boolean slice = false;
378    }
379    :
380        e1=atom { $node = $e1.node; }
381        (
382            /* Attribute access */
383            '.'
384            n=name { $node = new Attr(location, $e1.node.getStart(), $n.node.getEnd(), $node, $n.text); }
385        |
386            /* Function/method call */
387            '(' { $node = new Call(location, $e1.node.getStart(), -1, $node); }
388            (
389                /* No arguments */
390            |
391                /* "**" argument only */
392                '**' rkwargs=exprarg { ((Call)$node).setRemainingKeywordArguments($rkwargs.node); }
393                ','?
394            |
395                /* "*" argument only (and maybe **) */
396                '*' rargs=exprarg { ((Call)$node).setRemainingArguments($rargs.node); }
397                (
398                    ','
399                    '**' rkwargs=exprarg { ((Call)$node).setRemainingKeywordArguments($rkwargs.node); }
400                )?
401                ','?
402            |
403                /* At least one positional argument */
404                a1=exprarg { ((Call)$node).append($a1.node); }
405                (
406                    ','
407                    a2=exprarg { ((Call)$node).append($a2.node); }
408                )*
409                (
410                    ','
411                    an3=name '=' av3=exprarg { ((Call)$node).append($an3.text, $av3.node); }
412                )*
413                (
414                    ','
415                    '*' rargs=exprarg { ((Call)$node).setRemainingArguments($rargs.node); }
416                )?
417                (
418                    ','
419                    '**' rkwargs=exprarg { ((Call)$node).setRemainingKeywordArguments($rkwargs.node); }
420                )?
421                ','?
422            |
423                /* Keyword arguments only */
424                an1=name '=' av1=exprarg { ((Call)$node).append($an1.text, $av1.node); }
425                (
426                    ','
427                    an2=name '=' av2=exprarg { ((Call)$node).append($an2.text, $av2.node); }
428                )*
429                (
430                    ','
431                    '*' rargs=exprarg { ((Call)$node).setRemainingArguments($rargs.node); }
432                )?
433                (
434                    ','
435                    '**' rkwargs=exprarg { ((Call)$node).setRemainingKeywordArguments($rkwargs.node); }
436                )?
437                ','?
438            )
439            close=')' { $node.setEnd(getEnd($close)); }
440        |
441            /* Item/slice access */
442            '['
443            (
444                ':'
445                (
446                    e2=expr_if { index2 = $e2.node; }
447                )? { $node = Slice.make(location, $e1.node.getStart(), -1, $node, null, index2); }
448            |
449                e2=expr_if { index1 = $e2.node; }
450                (
451                    ':' { slice = true; }
452                    (
453                        e3=expr_if { index2 = $e3.node; }
454                    )?
455                )? { $node = slice ? Slice.make(location, $e1.node.getStart(), -1, $node, index1, index2) : Item.make(location, $e1.node.getStart(), -1, $node, index1); }
456            )
457            close=']' { $node.setEnd(getEnd($close)); }
458        )*
459    ;
460
461/* Negation */
462expr_neg returns [AST node]
463    :
464        e1=expr_subscript { $node = $e1.node; }
465    |
466        minus='-' e2=expr_neg { $node = Neg.make(location, getStart($minus), $e2.node.getEnd(), $e2.node); }
467    ;
468
469/* Multiplication, division, modulo */
470expr_mul returns [AST node]
471    @init
472    {
473        int opcode = -1;
474    }
475    :
476        e1=expr_neg { $node = $e1.node; }
477        (
478            (
479                '*' { opcode = 0; }
480            |
481                '/' { opcode = 1; }
482            |
483                '//' { opcode = 2; }
484            |
485                '%' { opcode = 3; }
486            )
487            e2=expr_neg { 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; } }
488        )*
489    ;
490
491/* Addition, substraction */
492expr_add returns [AST node]
493    @init
494    {
495        boolean add = false;
496    }
497    :
498        e1=expr_mul { $node = $e1.node; }
499        (
500            (
501                '+' { add = true; }
502            |
503                '-' { add = false; }
504            )
505            e2=expr_mul { $node = add ? Add.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node) : Sub.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
506        )*
507    ;
508
509/* Comparisons */
510expr_cmp returns [AST node]
511    @init
512    {
513        int opcode = -1;
514    }
515    :
516        e1=expr_add { $node = $e1.node; }
517        (
518            (
519                '==' { opcode = 0; }
520            |
521                '!=' { opcode = 1; }
522            |
523                '<' { opcode = 2; }
524            |
525                '<=' { opcode = 3; }
526            |
527                '>' { opcode = 4; }
528            |
529                '>=' { opcode = 5; }
530            )
531            e2=expr_add { 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; } }
532        )*
533    ;
534
535/* "in"/"not in" operator */
536expr_contain returns [AST node]
537    @init
538    {
539        boolean not = false;
540    }
541    :
542        e1=expr_cmp { $node = $e1.node; }
543        (
544            (
545                'not' { not = true; }
546            )?
547            'in'
548            e2=expr_cmp { $node = not ? NotContains.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node) : Contains.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
549        )?
550    ;
551
552/* Not operator */
553expr_not returns [AST node]
554    :
555        e1=expr_contain { $node = $e1.node; }
556    |
557        n='not' e2=expr_not { $node = Not.make(location, getStart($n), $e2.node.getEnd(), $e2.node); }
558    ;
559
560
561/* And operator */
562expr_and returns [AST node]
563    :
564        e1=expr_not { $node = $e1.node; }
565        (
566            'and'
567            e2=expr_not { $node = And.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
568        )*
569    ;
570
571/* Or operator */
572expr_or returns [AST node]
573    :
574        e1=expr_and { $node = $e1.node; }
575        (
576            'or'
577            e2=expr_and { $node = Or.make(location, $node.getStart(), $e2.node.getEnd(), $node, $e2.node); }
578        )*
579    ;
580
581/* If expression operator */
582expr_if returns [AST node]
583    :
584        e1=expr_or { $node = $e1.node; }
585        (
586            'if'
587            e2=expr_or
588            'else'
589            e3=expr_or { $node = IfExpression.make(location, $e1.node.getStart(), $e3.node.getEnd(), $e1.node, $e2.node, $e3.node); }
590        )?
591    ;
592
593exprarg returns [AST node]
594    : ege=generatorexpression { $node = $ege.node; }
595    | e1=expr_if { $node = $e1.node; }
596    ;
597
598expression returns [AST node]
599    : ege=generatorexpression EOF { $node = $ege.node; }
600    | e=expr_if EOF { $node = $e.node; }
601    ;
602
603
604/* Additional rules for "for" tag */
605
606for_ returns [For node]
607    :
608        n=nestedlvalue
609        'in'
610        e=expr_if { $node = new For(location, location.getStartCode(), $e.node.getEnd(), $n.lvalue, $e.node); }
611        EOF
612    ;
613
614
615/* Additional rules for "code" tag */
616
617stmt returns [AST node]
618    : nn=nestedlvalue '=' e=expr_if EOF { $node = new SetVar(location, location.getStartCode(), $e.node.getEnd(), $nn.lvalue, $e.node); }
619    | n=expr_subscript '+=' e=expr_if EOF { if ($n.node instanceof LValue) $node = new AddVar(location, location.getStartCode(), $e.node.getEnd(), (LValue)$n.node, $e.node); else throw new RuntimeException("lvalue required"); }
620    | n=expr_subscript '-=' e=expr_if EOF { if ($n.node instanceof LValue) $node = new SubVar(location, location.getStartCode(), $e.node.getEnd(), (LValue)$n.node, $e.node); else throw new RuntimeException("lvalue required"); }
621    | n=expr_subscript '*=' e=expr_if EOF { if ($n.node instanceof LValue) $node = new MulVar(location, location.getStartCode(), $e.node.getEnd(), (LValue)$n.node, $e.node); else throw new RuntimeException("lvalue required"); }
622    | n=expr_subscript '//=' e=expr_if EOF { if ($n.node instanceof LValue) $node = new FloorDivVar(location, location.getStartCode(), $e.node.getEnd(), (LValue)$n.node, $e.node); else throw new RuntimeException("lvalue required"); }
623    | n=expr_subscript '/=' e=expr_if EOF { if ($n.node instanceof LValue) $node = new TrueDivVar(location, location.getStartCode(), $e.node.getEnd(), (LValue)$n.node, $e.node); else throw new RuntimeException("lvalue required"); }
624    | n=expr_subscript '%=' e=expr_if EOF { if ($n.node instanceof LValue) $node = new ModVar(location, location.getStartCode(), $e.node.getEnd(), (LValue)$n.node, $e.node); else throw new RuntimeException("lvalue required"); }
625    | e=expression EOF { $node = $e.node; }
626    ;
Note: See TracBrowser for help on using the browser.