@@ -558,12 +558,70 @@ private StatementNode parseExpressionStatement() {
558558 return expr ;
559559 }
560560
561- private ExprNode parseExpression () { return parseComparisonExpression (); }
561+ private ExprNode parseExpression () {
562+ if (match (ALL , ANY )) {
563+ return parseBooleanChain ();
564+ }
565+ return parseComparisonExpression ();
566+ }
567+
568+
569+ private ExprNode parseBooleanChain () {
570+ Token startToken = currentToken ();
571+ Token typeToken = consume ();
572+ boolean isAll = typeToken .type == ALL ;
573+ if (match (ID )) {
574+
575+ ExprNode arrayExpr = ASTFactory .createIdentifier (consume ().text );
576+
577+ if (match (EQ , NEQ , GT , LT , GTE , LTE )) {
578+ Token op = consume ();
579+
580+ ExprNode right = parseAdditiveExpression ();
581+
582+ List <ExprNode > chainArgs = new ArrayList <ExprNode >();
583+ chainArgs .add (right );
584+
585+ EqualityChainNode chain = ASTFactory .createEqualityChain (arrayExpr , op .text , isAll , chainArgs );
586+ setNodePosition (chain , startToken );
587+ return chain ;
588+ } else {
589+ throw new ParseError ("Expected comparison operator after 'all/any <arrayName>' but found " +
590+ getTypeName (currentToken ().type ) + " ('" + currentToken ().text +
591+ "') at line " + currentToken ().line + ":" + currentToken ().column );
592+ }
593+ } else {
594+ consume (LBRACKET );
595+ List <ExprNode > expressions = new ArrayList <ExprNode >();
596+
597+ if (!match (RBRACKET )) {
598+ expressions .add (parseExpression ());
599+ if (!match (COMMA ) && !match (RBRACKET )) {
600+ throw new ParseError ("Boolean chain requires at least two expressions or a comma after the first expression." );
601+ }
602+ while (tryConsume (COMMA )) {
603+ expressions .add (parseExpression ());
604+ }
605+ }
606+ consume (RBRACKET );
607+ BooleanChainNode node = ASTFactory .createBooleanChain (isAll , expressions );
608+ if (node != null ) {
609+ node .setSourcePosition (startToken .line , startToken .column );
610+ }
611+ return node ;
612+ }
613+ }
562614
563615 private ExprNode parseComparisonExpression () {
564616 Token startToken = currentToken ();
565617 ExprNode left = parseAdditiveExpression ();
566618
619+ // --- NEW: Check for reverse equality chain (e.g., 'x == any[...]') ---
620+ if (match (EQ , NEQ , GT , LT , GTE , LTE ) && isEqualityChainReverse ()) {
621+ Token op = consume ();
622+ return parseEqualityChain (left , op .text );
623+ }
624+
567625 if (match (EQ , NEQ , GT , LT , GTE , LTE )) {
568626 Token op = consume ();
569627
@@ -578,27 +636,53 @@ private ExprNode parseComparisonExpression() {
578636 return left ;
579637 }
580638
581- private ExprNode parseEqualityChain (ExprNode left , String operator ) {
639+ private ExprNode parseEqualityChain (ExprNode left , String operator ) {
582640 Token startToken = currentToken ();
583641 Token chainTypeToken = consume ();
584642 boolean isAllChain = chainTypeToken .type == ALL ;
585643
586- consume (LPAREN );
644+ // --- UPDATED: Looking for LBRACKET instead of LPAREN ---
645+ consume (LBRACKET );
587646
588647 List <ExprNode > chainArgs = new ArrayList <ExprNode >();
589- if (!match (RPAREN )) {
648+ // --- UPDATED: Looking for RBRACKET instead of RPAREN ---
649+ if (!match (RBRACKET )) {
590650 chainArgs .add (parseChainArgument ());
591651 while (tryConsume (COMMA )) {
592652 chainArgs .add (parseChainArgument ());
593653 }
594654 }
595- consume (RPAREN );
655+ // --- UPDATED: Consuming RBRACKET instead of RPAREN ---
656+ consume (RBRACKET );
596657
597658 EqualityChainNode chain = ASTFactory .createEqualityChain (left , operator , isAllChain , chainArgs );
598659 setNodePosition (chain , startToken );
599660 return chain ;
600661 }
601662
663+ private MethodCallNode parseConditionalChainCall (MethodCallNode call ) {
664+ Token chainTypeToken = consume ();
665+ boolean isAllChain = chainTypeToken .type == ALL ;
666+ call .chainType = isAllChain ? "all" : "any" ;
667+
668+ // --- UPDATED: Mandate LBRACKET and RBRACKET for chain arguments ---
669+ consume (LBRACKET );
670+
671+ List <ExprNode > chainArgs = new ArrayList <ExprNode >();
672+ if (!match (RBRACKET )) {
673+ chainArgs .add (parseChainArgument ());
674+ while (tryConsume (COMMA )) {
675+ chainArgs .add (parseChainArgument ());
676+ }
677+ }
678+
679+ // --- UPDATED: Consume RBRACKET ---
680+ consume (RBRACKET );
681+
682+ call .chainArguments = chainArgs ;
683+ return call ;
684+ }
685+
602686 private ExprNode parseAdditiveExpression () {
603687 Token startToken = currentToken ();
604688 ExprNode left = parseMultiplicativeExpression ();
@@ -732,29 +816,6 @@ private MethodCallNode parseMethodCall() {
732816 return call ;
733817 }
734818
735- private MethodCallNode parseConditionalChainCall (MethodCallNode call ) {
736- Token chainTypeToken = consume ();
737- boolean isAllChain = chainTypeToken .type == ALL ;
738- call .chainType = isAllChain ? "all" : "any" ;
739-
740- boolean hasParens = tryConsume (LPAREN );
741-
742- List <ExprNode > chainArgs = new ArrayList <ExprNode >();
743- if (!match (RPAREN )) {
744- chainArgs .add (parseChainArgument ());
745- while (tryConsume (COMMA )) {
746- chainArgs .add (parseChainArgument ());
747- }
748- }
749-
750- if (hasParens ) {
751- consume (RPAREN );
752- }
753-
754- call .chainArguments = chainArgs ;
755- return call ;
756- }
757-
758819 private ExprNode parseChainArgument () {
759820 if (match (BANG )) {
760821 consume (BANG );
@@ -921,9 +982,50 @@ private boolean isIndexAssignment() {
921982 int p = position ; try { if (tokens .get (p ++).type != ID ) return false ; if (p >= tokens .size () || tokens .get (p ++).type != LBRACKET ) return false ; int bd = 1 ; while (p < tokens .size () && bd > 0 ) { if (tokens .get (p ).type == LBRACKET ) bd ++; else if (tokens .get (p ).type == RBRACKET ) bd --; p ++; } if (bd != 0 ) return false ; while (p < tokens .size () && tokens .get (p ).type == LBRACKET ) { p ++; bd = 1 ; while (p < tokens .size () && bd > 0 ) { if (tokens .get (p ).type == LBRACKET ) bd ++; else if (tokens .get (p ).type == RBRACKET ) bd --; p ++; } if (bd != 0 ) return false ; } return p < tokens .size () && tokens .get (p ).type == ASSIGN ; } catch (IndexOutOfBoundsException e ) { return false ; }
922983 }
923984
924- private boolean isMethodCallFollows () {
925- int p = position ; try { if (tokens .get (p ).type != ID ) return false ; p ++; while (p < tokens .size () && tokens .get (p ).type == DOT ) { p ++; if (p >= tokens .size () || tokens .get (p ).type != ID ) return false ; p ++; } return p < tokens .size () && tokens .get (p ).type == LPAREN ; } catch (IndexOutOfBoundsException e ) { return false ; }
985+ private boolean isMethodCallFollows () {
986+ int p = position ;
987+ try {
988+ if (tokens .get (p ).type != ID ) return false ;
989+ p ++;
990+ while (p < tokens .size () && tokens .get (p ).type == DOT ) {
991+ p ++;
992+ if (p >= tokens .size () || tokens .get (p ).type != ID ) return false ;
993+ p ++;
994+ }
995+ if (p >= tokens .size () || tokens .get (p ).type != LPAREN ) return false ;
996+ p ++;
997+
998+ if (p < tokens .size () && (tokens .get (p ).type == ALL || tokens .get (p ).type == ANY )) {
999+ p ++;
1000+ return p < tokens .size () && tokens .get (p ).type == LBRACKET ;
1001+ }
1002+
1003+ return true ;
1004+ } catch (IndexOutOfBoundsException e ) {
1005+ return false ;
1006+ }
9261007 }
1008+
1009+ // --- NEW: Helper for reverse equality chain ---
1010+ private boolean isEqualityChainReverse () {
1011+ int p = position ;
1012+ try {
1013+ // Check for Operator
1014+ if (tokens .get (p ).type != EQ && tokens .get (p ).type != NEQ &&
1015+ tokens .get (p ).type != GT && tokens .get (p ).type != LT &&
1016+ tokens .get (p ).type != GTE && tokens .get (p ).type != LTE ) return false ;
1017+ p ++;
1018+
1019+ // Check for ALL/ANY followed by LBRACKET
1020+ if (tokens .get (p ).type != ALL && tokens .get (p ).type != ANY ) return false ;
1021+ p ++;
1022+
1023+ return tokens .get (p ).type == LBRACKET ;
1024+ } catch (IndexOutOfBoundsException e ) {
1025+ return false ;
1026+ }
1027+ }
1028+
9271029
9281030 private boolean isReturnSlotAssignment () {
9291031 int p = position ; try { if (tokens .get (p ++).type != ID ) return false ; while (p < tokens .size () && tokens .get (p ).type == COMMA ) { p ++; if (p >= tokens .size () || tokens .get (p ++).type != ID ) return false ; } if (p >= tokens .size () || tokens .get (p ++).type != ASSIGN ) return false ; if (p >= tokens .size () || tokens .get (p ++).type != LBRACKET ) return false ;
0 commit comments