@@ -28,23 +28,23 @@ public static Statement parse(List<Token> tokens) {
2828
2929 private static final Token EOF = new Token (TokenType .EOF , "" , -1 , -1 );
3030
31- private static final EnumMap <TokenType , BinaryExpression .Operator > assignOperator ;
31+ private static final EnumMap <TokenType , BinaryExpression .Operator > ASSIGN_OPERATORS ;
3232 static {
33- assignOperator = new EnumMap (TokenType .class );
34- assignOperator .put (TokenType .EQ , null );
35- assignOperator .put (TokenType .PLUSEQ , BinaryExpression .Operator .ADD );
36- assignOperator .put (TokenType .MINUSEQ , BinaryExpression .Operator .SUBTRACT );
37- assignOperator .put (TokenType .STAREQ , BinaryExpression .Operator .MULTIPLY );
38- assignOperator .put (TokenType .SLASHEQ , BinaryExpression .Operator .DIVIDE );
39- assignOperator .put (TokenType .PERCENTEQ , BinaryExpression .Operator .REMAINDER );
40- assignOperator .put (TokenType .AMPEQ , BinaryExpression .Operator .AND );
41- assignOperator .put (TokenType .CARETEQ , BinaryExpression .Operator .XOR );
42- assignOperator .put (TokenType .BAREQ , BinaryExpression .Operator .OR );
43- assignOperator .put (TokenType .COLONCOLONEQ , BinaryExpression .Operator .PUSH );
44- assignOperator .put (TokenType .LTLTEQ , BinaryExpression .Operator .LSHIFT );
45- assignOperator .put (TokenType .GTGTEQ , BinaryExpression .Operator .RSHIFT );
46- assignOperator .put (TokenType .GTGTGTEQ , BinaryExpression .Operator .URSHIFT );
47- assignOperator .put (TokenType .ATEQ , BinaryExpression .Operator .AT );
33+ ASSIGN_OPERATORS = new EnumMap (TokenType .class );
34+ ASSIGN_OPERATORS .put (TokenType .EQ , null );
35+ ASSIGN_OPERATORS .put (TokenType .PLUSEQ , BinaryExpression .Operator .ADD );
36+ ASSIGN_OPERATORS .put (TokenType .MINUSEQ , BinaryExpression .Operator .SUBTRACT );
37+ ASSIGN_OPERATORS .put (TokenType .STAREQ , BinaryExpression .Operator .MULTIPLY );
38+ ASSIGN_OPERATORS .put (TokenType .SLASHEQ , BinaryExpression .Operator .DIVIDE );
39+ ASSIGN_OPERATORS .put (TokenType .PERCENTEQ , BinaryExpression .Operator .REMAINDER );
40+ ASSIGN_OPERATORS .put (TokenType .AMPEQ , BinaryExpression .Operator .AND );
41+ ASSIGN_OPERATORS .put (TokenType .CARETEQ , BinaryExpression .Operator .XOR );
42+ ASSIGN_OPERATORS .put (TokenType .BAREQ , BinaryExpression .Operator .OR );
43+ ASSIGN_OPERATORS .put (TokenType .COLONCOLONEQ , BinaryExpression .Operator .PUSH );
44+ ASSIGN_OPERATORS .put (TokenType .LTLTEQ , BinaryExpression .Operator .LSHIFT );
45+ ASSIGN_OPERATORS .put (TokenType .GTGTEQ , BinaryExpression .Operator .RSHIFT );
46+ ASSIGN_OPERATORS .put (TokenType .GTGTGTEQ , BinaryExpression .Operator .URSHIFT );
47+ ASSIGN_OPERATORS .put (TokenType .ATEQ , BinaryExpression .Operator .AT );
4848 }
4949
5050 private final List <Token > tokens ;
@@ -156,10 +156,10 @@ private Statement statement() {
156156 return functionDefine ();
157157 }
158158 if (match (TokenType .MATCH )) {
159- return new ExprStatement ( match () );
159+ return match ();
160160 }
161161 if (lookMatch (0 , TokenType .WORD ) && lookMatch (1 , TokenType .LPAREN )) {
162- return new ExprStatement (function (qualifiedName ()));
162+ return new ExprStatement (functionChain (qualifiedName ()));
163163 }
164164 return assignmentStatement ();
165165 }
@@ -185,7 +185,7 @@ private DestructuringAssignmentStatement destructuringAssignment() {
185185 } else {
186186 variables .add (null );
187187 }
188- match (TokenType .COMMA );
188+ consume (TokenType .COMMA );
189189 }
190190 consume (TokenType .EQ );
191191 return new DestructuringAssignmentStatement (variables , expression ());
@@ -227,36 +227,37 @@ && lookMatch(foreachIndex + 2, TokenType.WORD) && lookMatch(foreachIndex + 3, To
227227 // for key, value : arr || for (key, value : arr)
228228 return foreachMapStatement ();
229229 }
230-
231- boolean openParen = match (TokenType .LPAREN ); // необязательные скобки
230+
231+ // for (init, condition, increment) body
232+ boolean optParentheses = match (TokenType .LPAREN );
232233 final Statement initialization = assignmentStatement ();
233234 consume (TokenType .COMMA );
234235 final Expression termination = expression ();
235236 consume (TokenType .COMMA );
236237 final Statement increment = assignmentStatement ();
237- if (openParen ) consume (TokenType .RPAREN ); // скобки
238+ if (optParentheses ) consume (TokenType .RPAREN ); // close opt parentheses
238239 final Statement statement = statementOrBlock ();
239240 return new ForStatement (initialization , termination , increment , statement );
240241 }
241242
242243 private ForeachArrayStatement foreachArrayStatement () {
243- boolean openParen = match (TokenType .LPAREN ); // необязательные скобки
244+ boolean optParentheses = match (TokenType .LPAREN );
244245 final String variable = consume (TokenType .WORD ).getText ();
245246 consume (TokenType .COLON );
246247 final Expression container = expression ();
247- if (openParen ) consume (TokenType .RPAREN ); // скобки
248+ if (optParentheses ) consume (TokenType .RPAREN ); // close opt parentheses
248249 final Statement statement = statementOrBlock ();
249250 return new ForeachArrayStatement (variable , container , statement );
250251 }
251252
252253 private ForeachMapStatement foreachMapStatement () {
253- boolean openParen = match (TokenType .LPAREN ); // необязательные скобки
254+ boolean optParentheses = match (TokenType .LPAREN );
254255 final String key = consume (TokenType .WORD ).getText ();
255256 consume (TokenType .COMMA );
256257 final String value = consume (TokenType .WORD ).getText ();
257258 consume (TokenType .COLON );
258259 final Expression container = expression ();
259- if (openParen ) consume (TokenType .RPAREN ); // скобки
260+ if (optParentheses ) consume (TokenType .RPAREN ); // close opt parentheses
260261 final Statement statement = statementOrBlock ();
261262 return new ForeachMapStatement (key , value , container , statement );
262263 }
@@ -296,6 +297,26 @@ private Statement statementBody() {
296297 return statementOrBlock ();
297298 }
298299
300+ private Expression functionChain (Expression qualifiedNameExpr ) {
301+ // f1()()() || f1().f2().f3() || f1().key
302+ final Expression expr = function (qualifiedNameExpr );
303+ if (lookMatch (0 , TokenType .LPAREN )) {
304+ return functionChain (expr );
305+ }
306+ if (lookMatch (0 , TokenType .DOT )) {
307+ final List <Expression > indices = variableSuffix ();
308+ if (indices == null | indices .isEmpty ()) return expr ;
309+
310+ if (lookMatch (0 , TokenType .LPAREN )) {
311+ // next function call
312+ return functionChain (new ContainerAccessExpression (expr , indices ));
313+ }
314+ // container access
315+ return new ContainerAccessExpression (expr , indices );
316+ }
317+ return expr ;
318+ }
319+
299320 private FunctionalExpression function (Expression qualifiedNameExpr ) {
300321 // function(arg1, arg2, ...)
301322 consume (TokenType .LPAREN );
@@ -426,13 +447,13 @@ private Expression assignmentStrict() {
426447 }
427448
428449 final TokenType currentType = get (0 ).getType ();
429- if (!assignOperator .containsKey (currentType )) {
450+ if (!ASSIGN_OPERATORS .containsKey (currentType )) {
430451 pos = position ;
431452 return null ;
432453 }
433454 match (currentType );
434455
435- final BinaryExpression .Operator op = assignOperator .get (currentType );
456+ final BinaryExpression .Operator op = ASSIGN_OPERATORS .get (currentType );
436457 final Expression expression = expression ();
437458
438459 return new AssignmentExpression (op , (Accessible ) targetExpr , expression );
@@ -683,18 +704,18 @@ private Expression primary() {
683704 }
684705 return variable ();
685706 }
686-
707+
687708 private Expression variable () {
688709 // function(...
689710 if (lookMatch (0 , TokenType .WORD ) && lookMatch (1 , TokenType .LPAREN )) {
690- return function (new ValueExpression (consume (TokenType .WORD ).getText ()));
711+ return functionChain (new ValueExpression (consume (TokenType .WORD ).getText ()));
691712 }
692713
693714 final Expression qualifiedNameExpr = qualifiedName ();
694715 if (qualifiedNameExpr != null ) {
695716 // variable(args) || arr["key"](args) || obj.key(args)
696717 if (lookMatch (0 , TokenType .LPAREN )) {
697- return function (qualifiedNameExpr );
718+ return functionChain (qualifiedNameExpr );
698719 }
699720 // postfix increment/decrement
700721 if (match (TokenType .PLUSPLUS )) {
@@ -726,7 +747,7 @@ private Expression qualifiedName() {
726747 }
727748 return new ContainerAccessExpression (current .getText (), indices );
728749 }
729-
750+
730751 private List <Expression > variableSuffix () {
731752 // .key1.arr1[expr1][expr2].key2
732753 if (!lookMatch (0 , TokenType .DOT ) && !lookMatch (0 , TokenType .LBRACKET )) {
0 commit comments