From c346cfc0e603c07574c2da09325d00cb2b49eb32 Mon Sep 17 00:00:00 2001 From: Toshiya Kobayashi Date: Thu, 24 Aug 2023 16:16:16 +0900 Subject: [PATCH] [DROOLS-7288] Failed to parse complex parentheses (#27) * [DROOLS-7288] Failed to parse complex parentheses - bump to 8.43.0.Final * additional tests --- .../antlr4/org/drools/parser/DRLParser.g4 | 14 ++- .../org/drools/parser/DRLVisitorImpl.java | 41 +++---- .../org/drools/parser/MiscDRLParserTest.java | 112 +++++++++++++++++- 3 files changed, 130 insertions(+), 37 deletions(-) diff --git a/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLParser.g4 b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLParser.g4 index af10b445e97..c150a480e4a 100644 --- a/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLParser.g4 +++ b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLParser.g4 @@ -36,10 +36,15 @@ globaldef : DRL_GLOBAL type drlIdentifier SEMI? ; ruledef : DRL_RULE name=stringId (EXTENDS stringId)? drlAnnotation* attributes? lhs rhs DRL_END ; -lhs : DRL_WHEN lhsExpression? ; -lhsExpression : lhsOr+ ; -lhsOr : LPAREN DRL_OR lhsAnd+ RPAREN | lhsAnd (DRL_OR lhsAnd)* ; -lhsAnd : LPAREN lhsAnd RPAREN | LPAREN DRL_AND lhsUnary+ RPAREN | lhsUnary (DRL_AND lhsUnary)* ; +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 + ; /* lhsUnary : ( lhsExists namedConsequence? @@ -57,6 +62,7 @@ lhsUnary : ( | lhsNot | lhsPatternBind ) ; + lhsPatternBind : label? ( LPAREN lhsPattern (DRL_OR lhsPattern)* RPAREN | lhsPattern ) ; /* diff --git a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java index 7f69502301d..22858fba9fc 100644 --- a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java +++ b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLVisitorImpl.java @@ -186,17 +186,12 @@ public AttributeDescr visitAttribute(DRLParser.AttributeContext ctx) { @Override public List visitLhs(DRLParser.LhsContext ctx) { if (ctx.lhsExpression() != null) { - return visitLhsExpression(ctx.lhsExpression()); + return visitDescrChildren(ctx); } else { return new ArrayList<>(); } } - @Override - public List visitLhsExpression(DRLParser.LhsExpressionContext ctx) { - return visitDescrChildren(ctx); - } - @Override public BaseDescr visitLhsPatternBind(DRLParser.LhsPatternBindContext ctx) { if (ctx.lhsPattern().size() == 1) { @@ -294,33 +289,25 @@ public NotDescr visitLhsNot(DRLParser.LhsNotContext ctx) { return notDescr; } + @Override + public BaseDescr visitLhsExpressionEnclosed(DRLParser.LhsExpressionEnclosedContext ctx) { + return (BaseDescr) visit(ctx.lhsExpression()); + } + @Override public BaseDescr visitLhsOr(DRLParser.LhsOrContext ctx) { - if (!ctx.DRL_OR().isEmpty()) { - OrDescr orDescr = new OrDescr(); - List descrList = visitDescrChildren(ctx); - descrList.forEach(orDescr::addDescr); - return orDescr; - } else { - // No DRL_OR means only one lhsAnd - return visitLhsAnd(ctx.lhsAnd().get(0)); - } + OrDescr orDescr = new OrDescr(); + List descrList = visitDescrChildren(ctx); + descrList.forEach(orDescr::addDescr); + return orDescr; } @Override public BaseDescr visitLhsAnd(DRLParser.LhsAndContext ctx) { - if (ctx.lhsAnd() != null) { - return visitLhsAnd(ctx.lhsAnd()); - } - if (!ctx.DRL_AND().isEmpty()) { - AndDescr andDescr = new AndDescr(); - List descrList = visitDescrChildren(ctx); - descrList.forEach(andDescr::addDescr); - return andDescr; - } else { - // No DRL_AND means only one lhsUnary - return visitLhsUnary(ctx.lhsUnary().get(0)); - } + AndDescr andDescr = new AndDescr(); + List descrList = visitDescrChildren(ctx); + descrList.forEach(andDescr::addDescr); + return andDescr; } @Override diff --git a/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/MiscDRLParserTest.java b/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/MiscDRLParserTest.java index dd88f613513..011926dc1b3 100644 --- a/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/MiscDRLParserTest.java +++ b/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/MiscDRLParserTest.java @@ -1389,22 +1389,21 @@ public void parse_OrBindingWithBrackets() throws Exception { assertThat((String) rule.getConsequence()).isEqualToIgnoringWhitespace( "System.out.println( \"Mark and Michael\" + bar );"); } - @Disabled("Priority : High | Failed to parse complex parentheses") @Test - public void parse_BracketsPrecedence() throws Exception { + void parenthesesOrAndOr() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( "brackets_precedence.drl" ); - assertThat(pkg.getRules().size()).isEqualTo(1); + assertThat(pkg.getRules()).hasSize(1); final RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 ); final AndDescr rootAnd = (AndDescr) rule.getLhs(); - assertThat(rootAnd.getDescrs().size()).isEqualTo(2); + assertThat(rootAnd.getDescrs()).hasSize(2); final OrDescr leftOr = (OrDescr) rootAnd.getDescrs().get( 0 ); - assertThat(leftOr.getDescrs().size()).isEqualTo(2); + assertThat(leftOr.getDescrs()).hasSize(2); final NotDescr not = (NotDescr) leftOr.getDescrs().get( 0 ); final PatternDescr foo1 = (PatternDescr) not.getDescrs().get( 0 ); assertThat(foo1.getObjectType()).isEqualTo("Foo"); @@ -1413,13 +1412,114 @@ public void parse_BracketsPrecedence() throws Exception { final OrDescr rightOr = (OrDescr) rootAnd.getDescrs().get( 1 ); - assertThat(rightOr.getDescrs().size()).isEqualTo(2); + assertThat(rightOr.getDescrs()).hasSize(2); final PatternDescr shoes = (PatternDescr) rightOr.getDescrs().get( 0 ); assertThat(shoes.getObjectType()).isEqualTo("Shoes"); final PatternDescr butt = (PatternDescr) rightOr.getDescrs().get( 1 ); assertThat(butt.getObjectType()).isEqualTo("Butt"); } + @Test + void parenthesesAndOrOr() { + final String drl = "rule and_or_or\n" + + " when\n" + + " (Foo(x == 1) and Bar(x == 2)) or (Foo(x == 3) or Bar(x == 4))\n" + + " then\n" + + "end"; + PackageDescr pkg = parser.parse(drl); + + assertThat(pkg.getRules()).hasSize(1); + final RuleDescr rule = (RuleDescr) pkg.getRules().get(0); + final AndDescr rootAnd = (AndDescr) rule.getLhs(); + assertThat(rootAnd.getDescrs()).hasSize(1); + + final OrDescr topOr = (OrDescr) rootAnd.getDescrs().get(0); + assertThat(topOr.getDescrs()).hasSize(2); + + final AndDescr leftAnd = (AndDescr) topOr.getDescrs().get(0); + assertThat(leftAnd.getDescrs()).hasSize(2); + final PatternDescr foo1 = (PatternDescr) leftAnd.getDescrs().get(0); + assertThat(foo1.getObjectType()).isEqualTo("Foo"); + final PatternDescr bar1 = (PatternDescr) leftAnd.getDescrs().get(1); + assertThat(bar1.getObjectType()).isEqualTo("Bar"); + + final OrDescr rightOr = (OrDescr) topOr.getDescrs().get(1); + assertThat(rightOr.getDescrs()).hasSize(2); + final PatternDescr foo2 = (PatternDescr) rightOr.getDescrs().get(0); + assertThat(foo2.getObjectType()).isEqualTo("Foo"); + final PatternDescr bar2 = (PatternDescr) rightOr.getDescrs().get(1); + assertThat(bar2.getObjectType()).isEqualTo("Bar"); + } + + @Test + void parenthesesOrAndAnd() { + final String drl = "rule or_and_and\n" + + " when\n" + + " (Foo(x == 1) or Bar(x == 2)) and (Foo(x == 3) and Bar(x == 4))\n" + + " then\n" + + "end"; + PackageDescr pkg = parser.parse(drl); + + assertThat(pkg.getRules()).hasSize(1); + final RuleDescr rule = (RuleDescr) pkg.getRules().get(0); + final AndDescr rootAnd = (AndDescr) rule.getLhs(); + assertThat(rootAnd.getDescrs()).hasSize(2); + + final OrDescr leftOr = (OrDescr) rootAnd.getDescrs().get(0); + assertThat(leftOr.getDescrs()).hasSize(2); + final PatternDescr foo1 = (PatternDescr) leftOr.getDescrs().get(0); + assertThat(foo1.getObjectType()).isEqualTo("Foo"); + final PatternDescr bar1 = (PatternDescr) leftOr.getDescrs().get(1); + assertThat(bar1.getObjectType()).isEqualTo("Bar"); + + final AndDescr rightAnd = (AndDescr) rootAnd.getDescrs().get(1); + assertThat(rightAnd.getDescrs()).hasSize(2); + final PatternDescr foo2 = (PatternDescr) rightAnd.getDescrs().get(0); + assertThat(foo2.getObjectType()).isEqualTo("Foo"); + final PatternDescr bar2 = (PatternDescr) rightAnd.getDescrs().get(1); + assertThat(bar2.getObjectType()).isEqualTo("Bar"); + } + + @Test + void parenthesesAndOrOrOrAnd() throws Exception { + final String drl = "rule and_or_or_or_and\n" + + " when\n" + + " (Foo(x == 1) and (Bar(x == 2) or Foo(x == 3))) or (Bar(x == 4) or (Foo(x == 5) and Bar(x == 6)))\n" + + " then\n" + + "end"; + PackageDescr pkg = parser.parse(drl); + + assertThat(pkg.getRules()).hasSize(1); + final RuleDescr rule = (RuleDescr) pkg.getRules().get(0); + final AndDescr rootAnd = (AndDescr) rule.getLhs(); + assertThat(rootAnd.getDescrs()).hasSize(1); + + final OrDescr topOr = (OrDescr) rootAnd.getDescrs().get(0); + assertThat(topOr.getDescrs()).hasSize(2); + + final AndDescr leftAnd = (AndDescr) topOr.getDescrs().get(0); + assertThat(leftAnd.getDescrs()).hasSize(2); + final PatternDescr foo1 = (PatternDescr) leftAnd.getDescrs().get(0); + assertThat(foo1.getObjectType()).isEqualTo("Foo"); + final OrDescr leftOr = (OrDescr) leftAnd.getDescrs().get(1); + assertThat(leftOr.getDescrs()).hasSize(2); + final PatternDescr bar1 = (PatternDescr) leftOr.getDescrs().get(0); + assertThat(bar1.getObjectType()).isEqualTo("Bar"); + final PatternDescr foo2 = (PatternDescr) leftOr.getDescrs().get(1); + assertThat(foo2.getObjectType()).isEqualTo("Foo"); + + final OrDescr rightOr = (OrDescr) topOr.getDescrs().get(1); + assertThat(rightOr.getDescrs()).hasSize(2); + final PatternDescr bar2 = (PatternDescr) rightOr.getDescrs().get(0); + assertThat(bar2.getObjectType()).isEqualTo("Bar"); + final AndDescr rightAnd = (AndDescr) rightOr.getDescrs().get(1); + assertThat(rightAnd.getDescrs()).hasSize(2); + final PatternDescr foo3 = (PatternDescr) rightAnd.getDescrs().get(0); + assertThat(foo3.getObjectType()).isEqualTo("Foo"); + final PatternDescr bar3 = (PatternDescr) rightAnd.getDescrs().get(1); + assertThat(bar3.getObjectType()).isEqualTo("Bar"); + } + @Disabled("Priority : High | Implement eval") @Test public void parse_EvalMultiple() throws Exception {