This is an automated email from the ASF dual-hosted git repository.

tkobayas pushed a commit to branch dev-new-parser
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/dev-new-parser by this push:
     new 4784201b5e [incubator-kie-drools-5716] [new-parser] mismatched input 
'if'/'do' (… (#5831)
4784201b5e is described below

commit 4784201b5e19b1b4082962ccbebc4bfef11e2b3a
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Thu Apr 11 10:56:46 2024 +0900

    [incubator-kie-drools-5716] [new-parser] mismatched input 'if'/'do' (… 
(#5831)
    
    * [incubator-kie-drools-5716] [new-parser] mismatched input 'if'/'do' 
(support named consequences)
    
    * Update 
drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
    
    Co-authored-by: Jiří Locker <[email protected]>
    
    * Update 
drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
    
    Co-authored-by: Jiří Locker <[email protected]>
    
    * resolve duplicate difinition
    
    ---------
    
    Co-authored-by: Jiří Locker <[email protected]>
---
 .../drl/parser/antlr4/MiscDRLParserTest.java       | 171 +++++++++++++++++++++
 .../org/drools/drl/parser/antlr4/DRLLexer.g4       |   2 +
 .../org/drools/drl/parser/antlr4/DRLParser.g4      |  49 ++++--
 .../drl/parser/antlr4/Antlr4ParserStringUtils.java |  10 +-
 .../drools/drl/parser/antlr4/DRLVisitorImpl.java   |  94 ++++++++++-
 5 files changed, 302 insertions(+), 24 deletions(-)

diff --git 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
index 2d21323828..5e3cf7c6af 100644
--- 
a/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
+++ 
b/drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
@@ -19,6 +19,7 @@ import org.drools.drl.ast.descr.AttributeDescr;
 import org.drools.drl.ast.descr.BaseDescr;
 import org.drools.drl.ast.descr.BehaviorDescr;
 import org.drools.drl.ast.descr.CollectDescr;
+import org.drools.drl.ast.descr.ConditionalBranchDescr;
 import org.drools.drl.ast.descr.EntryPointDeclarationDescr;
 import org.drools.drl.ast.descr.EntryPointDescr;
 import org.drools.drl.ast.descr.EvalDescr;
@@ -30,6 +31,7 @@ import org.drools.drl.ast.descr.FunctionDescr;
 import org.drools.drl.ast.descr.GlobalDescr;
 import org.drools.drl.ast.descr.ImportDescr;
 import org.drools.drl.ast.descr.MVELExprDescr;
+import org.drools.drl.ast.descr.NamedConsequenceDescr;
 import org.drools.drl.ast.descr.NotDescr;
 import org.drools.drl.ast.descr.OrDescr;
 import org.drools.drl.ast.descr.PackageDescr;
@@ -3997,4 +3999,173 @@ class MiscDRLParserTest {
                 .map(QualifiedName::getFullName)
                 .containsExactlyInAnyOrder("com.sample.ParentTrait", 
"UncleTrait", "org.test.GrandParentTrait");
     }
+
+    @Test
+    void namedConsequenceDo() {
+        final String text =
+                "rule R when\n" +
+                "  $r : Result()\n" +
+                "  $p1 : Person(name == \"Mark\")\n" +
+                "  do[FoundMark]\n" +
+                "  $p2 : Person(name != \"Mark\", age > $p1.age)\n" +
+                "then\n" +
+                "  $r.addValue($p2.getName() + \" is older than \" + 
$p1.getName());\n" +
+                "then[FoundMark]\n" +
+                "  $r.addValue(\"Found \" + $p1.getName());\n" +
+                "end";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
+        assertThat(namedConsequenceDescr.getName()).isEqualTo("FoundMark");
+
+        
assertThat(ruleDescr.getConsequence().toString()).isEqualTo("$r.addValue($p2.getName()
 + \" is older than \" + $p1.getName());");
+        
assertThat(ruleDescr.getNamedConsequences().get("FoundMark").toString()).isEqualTo("$r.addValue(\"Found
 \" + $p1.getName());");
+    }
+
+    @Test
+    void namedConsequenceIfElse() {
+        final String text =
+                "rule R1 dialect \"mvel\" when\n" +
+                        "    $a: Cheese ( type == \"stilton\" )\n" +
+                        "    if ( $a.price > Cheese.BASE_PRICE ) do[t1] else 
do[t2]\n" +
+                        "    $b: Cheese ( type == \"cheddar\" )\n" +
+                        "then\n" +
+                        "    results.add( $b.getType() );\n" +
+                        "then[t1]\n" +
+                        "    results.add( $a.getType() );\n" +
+                        "then[t2]\n" +
+                        "    results.add( $a.getType().toUpperCase() );\n" +
+                        "end\n";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(1);
+        
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
+        
assertThat(conditionalBranchDescr.getConsequence().getName()).isEqualTo("t1");
+        
assertThat(conditionalBranchDescr.getElseBranch().getConsequence().getName()).isEqualTo("t2");
+    }
+
+    @Test
+    void namedConsequenceIfElseBreak() {
+        final String text =
+                "rule R1 dialect \"mvel\" when\n" +
+                        "    $a: Cheese ( type == \"stilton\" )\n" +
+                        "    if ( $a.price > Cheese.BASE_PRICE ) break[t1] 
else break[t2]\n" +
+                        "    $b: Cheese ( type == \"cheddar\" )\n" +
+                        "then\n" +
+                        "    results.add( $b.getType() );\n" +
+                        "then[t1]\n" +
+                        "    results.add( $a.getType() );\n" +
+                        "then[t2]\n" +
+                        "    results.add( $a.getType().toUpperCase() );\n" +
+                        "end\n";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(1);
+        
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
+        
assertThat(conditionalBranchDescr.getConsequence().getName()).isEqualTo("t1");
+        
assertThat(conditionalBranchDescr.getElseBranch().getConsequence().getName()).isEqualTo("t2");
+    }
+
+    @Test
+    void namedConsequenceNestedIf() {
+        final String text =
+                "rule R1 dialect \"mvel\" when\n" +
+                        "    $a: Cheese ( type == \"stilton\" )\n" +
+                        "    if ( $a.price > Cheese.BASE_PRICE ) do[t1] else 
if ($a.price == Cheese.BASE_PRICE ) do[t2]\n" +
+                        "    $b: Cheese ( type == \"cheddar\" )\n" +
+                        "then\n" +
+                        "    results.add( $b.getType() );\n" +
+                        "then[t1]\n" +
+                        "    results.add( $a.getType() );\n" +
+                        "then[t2]\n" +
+                        "    results.add( $a.getType().toUpperCase() );\n" +
+                        "end\n";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(1);
+        
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
+        
assertThat(conditionalBranchDescr.getConsequence().getName()).isEqualTo("t1");
+        ConditionalBranchDescr elseBranch = 
conditionalBranchDescr.getElseBranch();
+        
assertThat(elseBranch.getCondition().getContent().toString()).isEqualTo("$a.price
 == Cheese.BASE_PRICE");
+        assertThat(elseBranch.getConsequence().getName()).isEqualTo("t2");
+    }
+
+    @Test
+    void namedConsequenceAfterExists() {
+        final String text =
+                "rule R when\n" +
+                        "  $r : Result()\n" +
+                        "  exists( Person(name == \"Mark\") )\n" +
+                        "  do[FoundMark]\n" +
+                        "  $p2 : Person(name != \"Mark\", age > $p1.age)\n" +
+                        "then\n" +
+                        "  $r.addValue($p2.getName() + \" is older than \" + 
$p1.getName());\n" +
+                        "then[FoundMark]\n" +
+                        "  $r.addValue(\"Found \" + $p1.getName());\n" +
+                        "end";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
+        assertThat(namedConsequenceDescr.getName()).isEqualTo("FoundMark");
+    }
+
+    @Test
+    void namedConsequenceAfterNot() {
+        final String text =
+                "rule R when\n" +
+                        "  $r : Result()\n" +
+                        "  not( Person(name == \"Mark\") )\n" +
+                        "  do[NotFoundMark]\n" +
+                        "  $p2 : Person(name != \"Mark\", age > $p1.age)\n" +
+                        "then\n" +
+                        "  $r.addValue($p2.getName() + \" is older than \" + 
$p1.getName());\n" +
+                        "then[FoundMark]\n" +
+                        "  $r.addValue(\"NotFound \" + $p1.getName());\n" +
+                        "end";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
+        assertThat(namedConsequenceDescr.getName()).isEqualTo("NotFoundMark");
+    }
+
+    @Test
+    void namedConsequenceIfElseAfterEval() {
+        final String text =
+                "rule R1 dialect \"mvel\" when\n" +
+                        "    $a: Cheese ( type == \"stilton\" )\n" +
+                        "    eval($a.price > 0) if ( $a.price > 
Cheese.BASE_PRICE ) do[t1] else do[t2]\n" +
+                        "    $b: Cheese ( type == \"cheddar\" )\n" +
+                        "then\n" +
+                        "    results.add( $b.getType() );\n" +
+                        "then[t1]\n" +
+                        "    results.add( $a.getType() );\n" +
+                        "then[t2]\n" +
+                        "    results.add( $a.getType().toUpperCase() );\n" +
+                        "end\n";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        ConditionalBranchDescr conditionalBranchDescr = 
(ConditionalBranchDescr) ruleDescr.getLhs().getDescrs().get(2);
+        
assertThat(conditionalBranchDescr.getCondition().getContent().toString()).isEqualTo("$a.price
 > Cheese.BASE_PRICE");
+        
assertThat(conditionalBranchDescr.getConsequence().getName()).isEqualTo("t1");
+        
assertThat(conditionalBranchDescr.getElseBranch().getConsequence().getName()).isEqualTo("t2");
+    }
+
+    @Test
+    void namedConsequenceAfterEnclosed() {
+        final String text =
+                "rule R when\n" +
+                        "  $r : Result()\n" +
+                        "  ( Person(name == \"Mark\") or Person(name == 
\"Mario\") )\n" +
+                        "  do[FoundMarkOrMario]\n" +
+                        "  $p2 : Person(name != \"Mark\", age > $p1.age)\n" +
+                        "then\n" +
+                        "  $r.addValue($p2.getName() + \" is older than \" + 
$p1.getName());\n" +
+                        "then[FoundMark]\n" +
+                        "  $r.addValue(\"Found \" + $p1.getName());\n" +
+                        "end";
+        PackageDescr packageDescr = parser.parse(text);
+        RuleDescr ruleDescr = packageDescr.getRules().get(0);
+        NamedConsequenceDescr namedConsequenceDescr = (NamedConsequenceDescr) 
ruleDescr.getLhs().getDescrs().get(2);
+        
assertThat(namedConsequenceDescr.getName()).isEqualTo("FoundMarkOrMario");
+    }
 }
diff --git 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
index dc974ecac8..631d2a49a1 100644
--- 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
+++ 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLLexer.g4
@@ -172,6 +172,8 @@ RHS_STRING_LITERAL
     | ('\'' ( DrlEscapeSequence | ~('\\'|'\'') )* '\'') { setText( 
normalizeString( getText() ) ); }
     ;
 
+RHS_NAMED_CONSEQUENCE_THEN : DRL_THEN LBRACK IDENTIFIER RBRACK ;
+
 RHS_CHUNK
     : ~[ ()[\]{},;\t\r\n\u000C]+ // ;}) could be a delimitter proceding 'end'. 
()[]{},; are delimiters to match RHS_STRING_LITERAL
     | LPAREN
diff --git 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
index 6e975bc3fe..e5cfc957cc 100644
--- 
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
+++ 
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRLParser.g4
@@ -90,12 +90,12 @@ parameter : type? drlIdentifier ; // type is optional. 
Removed (LEFT_SQUARE RIGH
 
 lhs : DRL_WHEN lhsExpression* ;
 
-lhsExpression : LPAREN lhsExpression RPAREN             #lhsExpressionEnclosed
-              | lhsUnary                                #lhsUnarySingle
-              | LPAREN DRL_AND lhsExpression+ RPAREN    #lhsAnd
-              | lhsExpression (DRL_AND lhsExpression)+  #lhsAnd
-              | LPAREN DRL_OR lhsExpression+ RPAREN     #lhsOr
-              | lhsExpression (DRL_OR lhsExpression)+   #lhsOr
+lhsExpression : LPAREN lhsExpression RPAREN namedConsequenceInvocation? 
#lhsExpressionEnclosed
+              | lhsUnary                                                
#lhsUnarySingle
+              | LPAREN DRL_AND lhsExpression+ RPAREN                    #lhsAnd
+              | lhsExpression (DRL_AND lhsExpression)+                  #lhsAnd
+              | LPAREN DRL_OR lhsExpression+ RPAREN                     #lhsOr
+              | lhsExpression (DRL_OR lhsExpression)+                   #lhsOr
               ;
 
 // lhsAnd is used as a label in lhsExpression rule. But some other rules 
explicitly use the def, so lhsAndDef is declared.
@@ -110,18 +110,19 @@ lhsUnary : ( lhsExists namedConsequence?
            | lhsEval consequenceInvocation*
            | lhsForall
            | lhsAccumulate
-           | LPAREN lhsOr RPAREN namedConsequence?
+           | LPAREN lhsOr RPAREN namedConsequence? // this part is handled by 
#lhsExpressionEnclosed
            | lhsPatternBind consequenceInvocation*
            ) SEMI? ;
 */
 
 lhsUnary : (
-           lhsExists
-           | lhsNot
-           | lhsEval
+           lhsExists namedConsequenceInvocation?
+           | lhsNot namedConsequenceInvocation?
+           | lhsEval consequenceInvocation*
            | lhsForall
            | lhsAccumulate
-           | lhsPatternBind
+           | conditionalBranch // not in the above old parser definition, but 
actually implemented in the old parser
+           | lhsPatternBind consequenceInvocation*
            ) SEMI? ;
 
 lhsPatternBind : (label|unif)? ( LPAREN lhsPattern (DRL_OR lhsPattern)* RPAREN 
| lhsPattern ) ;
@@ -157,6 +158,25 @@ xpathPrimary : label? xpathChunk+ ;
 xpathChunk : xpathSeparator drlIdentifier (DOT drlIdentifier)* (HASH 
drlIdentifier)? (LBRACK xpathExpressionList RBRACK)? ;
 xpathExpressionList : label? drlExpression (COMMA label? drlExpression)* ;
 
+// named consequence
+
+// consequenceInvocation := conditionalBranch | namedConsequence
+consequenceInvocation : conditionalBranch | namedConsequenceInvocation ;
+
+// conditionalBranch := IF LEFT_PAREN conditionalExpression RIGHT_PAREN
+//                      ( namedConsequence | breakingNamedConsequence )
+//                      ( ELSE ( namedConsequence | breakingNamedConsequence | 
conditionalBranch ) )?
+conditionalBranch : IF LPAREN conditionalOrExpression RPAREN
+                    ( do1=namedConsequenceInvocation | 
break1=breakingNamedConsequenceInvocation )
+                    ( ELSE ( do2=namedConsequenceInvocation | 
break2=breakingNamedConsequenceInvocation | conditionalBranch ) )? ;
+
+// namedConsequence := DO LEFT_SQUARE ID RIGHT_SQUARE BREAK?
+namedConsequenceInvocation : DO LBRACK drlIdentifier RBRACK ; // BREAK? is not 
actually implmented in the old parser
+
+// breakingNamedConsequence := BREAK LEFT_SQUARE ID RIGHT_SQUARE
+breakingNamedConsequenceInvocation : BREAK LBRACK drlIdentifier RBRACK ;
+
+
 relationalOperator
     : EQUAL
     | NOTEQUAL
@@ -488,9 +508,12 @@ lhsAccumulate : (DRL_ACCUMULATE|DRL_ACC) LPAREN lhsAndDef 
(COMMA|SEMI)
                  RPAREN (SEMI)?
                  ;
 
-rhs : DRL_THEN consequence ;
+rhs : DRL_THEN consequenceBody namedConsequence* ;
+
+consequenceBody : ( RHS_STRING_LITERAL | RHS_CHUNK )* ;
 
-consequence : ( RHS_STRING_LITERAL | RHS_CHUNK )* ;
+// THEN LEFT_SQUARE ID RIGHT_SQUARE chunk
+namedConsequence : RHS_NAMED_CONSEQUENCE_THEN consequenceBody ;
 
 stringId : ( IDENTIFIER | DRL_STRING_LITERAL ) ;
 
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
index 86e841cc12..a33eb143dd 100644
--- 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
@@ -66,13 +66,13 @@ public class Antlr4ParserStringUtils {
     }
 
     /**
-     * Just remove leading "then"
+     * Extract name from "then[name]" of RHS_NAMED_CONSEQUENCE_THEN
      */
-    public static String trimThen(String rhs) {
-        if (rhs.startsWith("then")) {
-            return rhs.substring("then".length());
+    public static String extractNamedConsequenceName(String 
namedConsequenceThen) {
+        if (namedConsequenceThen.toLowerCase().startsWith("then[") && 
namedConsequenceThen.endsWith("]")) {
+            return namedConsequenceThen.substring("then[".length(), 
namedConsequenceThen.length() - 1);
         } else {
-            throw new DRLParserException("rhs has to start with 'then' : rhs = 
" + rhs);
+            throw new DRLParserException("namedConsequenceThen has to be 
surrounded by 'then[', ']' : " + namedConsequenceThen);
         }
     }
 
diff --git 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
index 846a9bff9e..ba9157897e 100644
--- 
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
+++ 
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.java
@@ -35,6 +35,7 @@ import org.drools.drl.ast.descr.AttributeDescr;
 import org.drools.drl.ast.descr.BaseDescr;
 import org.drools.drl.ast.descr.BehaviorDescr;
 import org.drools.drl.ast.descr.CollectDescr;
+import org.drools.drl.ast.descr.ConditionalBranchDescr;
 import org.drools.drl.ast.descr.EntryPointDeclarationDescr;
 import org.drools.drl.ast.descr.EntryPointDescr;
 import org.drools.drl.ast.descr.EvalDescr;
@@ -47,6 +48,7 @@ import org.drools.drl.ast.descr.FunctionImportDescr;
 import org.drools.drl.ast.descr.GlobalDescr;
 import org.drools.drl.ast.descr.ImportDescr;
 import org.drools.drl.ast.descr.MVELExprDescr;
+import org.drools.drl.ast.descr.NamedConsequenceDescr;
 import org.drools.drl.ast.descr.NotDescr;
 import org.drools.drl.ast.descr.OrDescr;
 import org.drools.drl.ast.descr.PackageDescr;
@@ -60,9 +62,9 @@ import org.drools.drl.ast.descr.UnitDescr;
 import org.drools.drl.ast.descr.WindowDeclarationDescr;
 import org.drools.drl.ast.descr.WindowReferenceDescr;
 
+import static 
org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.extractNamedConsequenceName;
 import static 
org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.getTextPreservingWhitespace;
 import static 
org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.getTokenTextPreservingWhitespace;
-import static org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.trimThen;
 import static 
org.drools.drl.parser.antlr4.DRLParserHelper.getTextWithoutErrorNode;
 import static org.drools.drl.parser.util.ParserStringUtils.appendPrefix;
 import static 
org.drools.drl.parser.util.ParserStringUtils.safeStripStringDelimiters;
@@ -292,8 +294,17 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         }
 
         if (ctx.rhs() != null) {
+            // default consequence
             ruleDescr.setConsequenceLocation(ctx.rhs().getStart().getLine(), 
ctx.rhs().getStart().getCharPositionInLine()); // location of "then"
-            
ruleDescr.setConsequence(trimThen(getTokenTextPreservingWhitespace(ctx.rhs(), 
tokenStream))); // RHS is just a text
+            
ruleDescr.setConsequence(getTokenTextPreservingWhitespace(ctx.rhs().consequenceBody(),
 tokenStream)); // RHS is just a text
+
+            // named consequences
+            ctx.rhs().namedConsequence()
+                     .forEach(namedConsequenceCtx -> {
+                         String name = 
extractNamedConsequenceName(namedConsequenceCtx.RHS_NAMED_CONSEQUENCE_THEN().getText());
+                         String body = 
getTokenTextPreservingWhitespace(namedConsequenceCtx.consequenceBody(), 
tokenStream);
+                         ruleDescr.addNamedConsequences(name, body);
+                     } );
         }
 
         return ruleDescr;
@@ -558,6 +569,74 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
         patternDescr.addConstraint(exprConstraintDescr);
     }
 
+    @Override
+    public NamedConsequenceDescr 
visitNamedConsequenceInvocation(DRLParser.NamedConsequenceInvocationContext 
ctx) {
+        NamedConsequenceDescr namedConsequenceDescr = 
BaseDescrFactory.builder(new 
NamedConsequenceDescr(ctx.drlIdentifier().getText()))
+                .withParserRuleContext(ctx)
+                .build();
+        return namedConsequenceDescr;
+    }
+
+    @Override
+    public NamedConsequenceDescr 
visitBreakingNamedConsequenceInvocation(DRLParser.BreakingNamedConsequenceInvocationContext
 ctx) {
+        NamedConsequenceDescr namedConsequenceDescr = 
BaseDescrFactory.builder(new 
NamedConsequenceDescr(ctx.drlIdentifier().getText()))
+                .withParserRuleContext(ctx)
+                .build();
+        namedConsequenceDescr.setBreaking(true);
+        return namedConsequenceDescr;
+    }
+
+    /**
+     * process
+     *
+     * if (condition) do[namedConsequence1] else do[namedConsequence2]
+     *
+     * into a ConditionalBranchDescr
+     */
+    @Override
+    public ConditionalBranchDescr 
visitConditionalBranch(DRLParser.ConditionalBranchContext ctx) {
+        ConditionalBranchDescr conditionalBranchDescr = 
BaseDescrFactory.builder(new ConditionalBranchDescr())
+                .withParserRuleContext(ctx)
+                .build();
+        EvalDescr evalDescr = BaseDescrFactory.builder(new EvalDescr())
+                .withParserRuleContext(ctx.conditionalOrExpression())
+                .build();
+        
evalDescr.setContent(getTextPreservingWhitespace(ctx.conditionalOrExpression()));
+        conditionalBranchDescr.setCondition(evalDescr);
+
+        // main branch
+        if (ctx.do1 != null) {
+            NamedConsequenceDescr namedConsequenceDescr = 
visitNamedConsequenceInvocation(ctx.do1);
+            conditionalBranchDescr.setConsequence(namedConsequenceDescr);
+        } else if (ctx.break1 != null) {
+            NamedConsequenceDescr namedConsequenceDescr = 
visitBreakingNamedConsequenceInvocation(ctx.break1);
+            conditionalBranchDescr.setConsequence(namedConsequenceDescr);
+        }
+
+        // else branch
+        if (ctx.do2 != null) {
+            ConditionalBranchDescr elseBranchDescr = 
BaseDescrFactory.builder(new ConditionalBranchDescr())
+                    .withParserRuleContext(ctx.do2)
+                    .build();
+            conditionalBranchDescr.setElseBranch(elseBranchDescr);
+            NamedConsequenceDescr namedConsequenceDescr = 
visitNamedConsequenceInvocation(ctx.do2);
+            elseBranchDescr.setConsequence(namedConsequenceDescr);
+        } else if (ctx.break2 != null) {
+            ConditionalBranchDescr elseBranchDescr = 
BaseDescrFactory.builder(new ConditionalBranchDescr())
+                    .withParserRuleContext(ctx.break2)
+                    .build();
+            conditionalBranchDescr.setElseBranch(elseBranchDescr);
+            NamedConsequenceDescr namedConsequenceDescr = 
visitBreakingNamedConsequenceInvocation(ctx.break2);
+            elseBranchDescr.setConsequence(namedConsequenceDescr);
+        } else if (ctx.conditionalBranch() != null) {
+            // nested if
+            ConditionalBranchDescr nestedConditionalBranchDescr = 
visitConditionalBranch(ctx.conditionalBranch());
+            conditionalBranchDescr.setElseBranch(nestedConditionalBranchDescr);
+        }
+
+        return conditionalBranchDescr;
+    }
+
     @Override
     public ForallDescr visitLhsForall(DRLParser.LhsForallContext ctx) {
         ForallDescr forallDescr = BaseDescrFactory.builder(new ForallDescr())
@@ -792,9 +871,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
     }
 
     @Override
-    public BaseDescr 
visitLhsExpressionEnclosed(DRLParser.LhsExpressionEnclosedContext ctx) {
+    public List<BaseDescr> 
visitLhsExpressionEnclosed(DRLParser.LhsExpressionEnclosedContext ctx) {
         // enclosed expression is simply stripped because Descr itself is 
encapsulated
-        return (BaseDescr) visit(ctx.lhsExpression());
+        return visitDescrChildren(ctx);
     }
 
     @Override
@@ -887,8 +966,8 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
     }
 
     @Override
-    public BaseDescr visitLhsUnary(DRLParser.LhsUnaryContext ctx) {
-        return visitDescrChildren(ctx).get(0); // lhsUnary has only one child
+    public List<BaseDescr> visitLhsUnary(DRLParser.LhsUnaryContext ctx) {
+        return visitDescrChildren(ctx); // lhsUnary may have 
consequenceInvocation, so not always a single child
     }
 
     /**
@@ -924,6 +1003,9 @@ public class DRLVisitorImpl extends 
DRLParserBaseVisitor<Object> {
             Object childResult = c.accept(this);
             if (childResult instanceof BaseDescr) {
                 aggregator.add(new DescrNodePair((BaseDescr) childResult, c)); 
// pairing the returned Descr and the parser node
+            } else if (childResult instanceof List) {
+                List<BaseDescr> descrList = (List<BaseDescr>) childResult;
+                descrList.forEach(descr -> aggregator.add(new 
DescrNodePair(descr, c))); // pairing the returned Descr and the parser node
             }
         }
         return aggregator;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to