This is an automated email from the ASF dual-hosted git repository. mariofusco pushed a commit to branch dev-new-parser in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
commit 37185cf825775b9c73c9172028b9c64747de1fe7 Author: Toshiya Kobayashi <[email protected]> AuthorDate: Sun May 29 16:34:48 2022 +0900 Enhance test/grammar coverage. and, or, listExpression (#7) --- drools-drl/drools-drl10-parser/pom.xml | 6 ++ .../src/main/antlr4/org/drools/parser/DRLLexer.g4 | 3 + .../src/main/antlr4/org/drools/parser/DRLParser.g4 | 28 ++++- .../java/org/drools/parser/DRLVisitorImpl.java | 52 ++++++--- .../java/org/drools/parser/MiscDRLParserTest.java | 120 +++++++++++++++++++++ 5 files changed, 192 insertions(+), 17 deletions(-) diff --git a/drools-drl/drools-drl10-parser/pom.xml b/drools-drl/drools-drl10-parser/pom.xml index 599ec8ab07..93eefbc5d0 100644 --- a/drools-drl/drools-drl10-parser/pom.xml +++ b/drools-drl/drools-drl10-parser/pom.xml @@ -47,6 +47,12 @@ <version>${version.junit}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>${version.org.assertj}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> diff --git a/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLLexer.g4 b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLLexer.g4 index 0f4ee3cc48..8ba1364c40 100644 --- a/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLLexer.g4 +++ b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRLLexer.g4 @@ -32,6 +32,9 @@ WHEN : 'when'; THEN : 'then'; END : 'end'; +KWD_AND : 'and'; +KWD_OR : 'or'; + EXISTS : 'exists'; NOT : 'not'; IN : 'in'; 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 2818590bd5..c9db7951aa 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 @@ -19,8 +19,8 @@ ruledef : RULE name=stringId (EXTENDS stringId)? drlAnnotation* attributes? WHEN lhs : lhsExpression ; lhsExpression : lhsOr* ; -lhsOr : LPAREN OR lhsAnd+ RPAREN | lhsAnd (OR lhsAnd)* ; -lhsAnd : LPAREN AND lhsUnary+ RPAREN | lhsUnary (AND lhsUnary)* ; +lhsOr : LPAREN KWD_OR lhsAnd+ RPAREN | lhsAnd (KWD_OR lhsAnd)* ; +lhsAnd : LPAREN KWD_AND lhsUnary+ RPAREN | lhsUnary (KWD_AND lhsUnary)* ; /* lhsUnary : ( lhsExists namedConsequence? @@ -38,7 +38,7 @@ lhsUnary : ( | lhsNot | lhsPatternBind ) ; -lhsPatternBind : label? ( LPAREN lhsPattern (OR lhsPattern)* RPAREN | lhsPattern ) ; +lhsPatternBind : label? ( LPAREN lhsPattern (KWD_OR lhsPattern)* RPAREN | lhsPattern ) ; /* lhsPattern : xpathPrimary (OVER patternFilter)? | @@ -58,7 +58,27 @@ andExpression : left=equalityExpression (BITAND right=equalityExpression)* ; equalityExpression : left=instanceOfExpression ( ( op=EQUAL | op=NOTEQUAL ) right=instanceOfExpression )* ; instanceOfExpression : left=inExpression ( 'instanceof' right=type )? ; inExpression : left=relationalExpression ( 'not'? 'in' LPAREN drlExpression (COMMA drlExpression)* RPAREN )? ; -relationalExpression : expression? ; // TODO +relationalExpression : expression? ; // TODO : shiftExpression, additiveExpression, multiplicativeExpression, unaryExpression, unaryExpressionNotPlusMinus, ..., primary + +/* extending JavaParser */ +primary + : LPAREN expression RPAREN + | THIS + | SUPER + | literal + | identifier + | typeTypeOrVoid DOT CLASS + | nonWildcardTypeArguments (explicitGenericInvocationSuffix | THIS arguments) + | inlineListExpression + ; + +inlineListExpression + : LBRACK expressionList? RBRACK + ; + +expressionList + : expression (COMMA expression)* + ; drlExpression : conditionalExpression ( op=assignmentOperator right=drlExpression )? ; conditionalExpression : left=conditionalOrExpression ternaryExpression? ; 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 d93c707abe..98f6388b49 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 @@ -2,6 +2,7 @@ package org.drools.parser; import java.util.ArrayDeque; import java.util.Deque; +import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -19,7 +20,8 @@ public class DRLVisitorImpl extends DRLParserBaseVisitor<Object> { private RuleDescr currentRule; private PatternDescr currentPattern; - private Deque<ConditionalElementDescr> currentConstructStack = new ArrayDeque<>(); // e.g. whole LHS, not, exist + + private final Deque<ConditionalElementDescr> currentConstructStack = new ArrayDeque<>(); // e.g. whole LHS (= AndDescr), NotDescr, ExistsDescr @Override public Object visitCompilationUnit(DRLParser.CompilationUnitContext ctx) { @@ -86,23 +88,47 @@ public class DRLVisitorImpl extends DRLParserBaseVisitor<Object> { @Override public Object visitLhsPatternBind(DRLParser.LhsPatternBindContext ctx) { - // TODO: this logic will likely be split to visitLhsPattern if (ctx.lhsPattern().size() == 1) { - DRLParser.LhsPatternContext lhsPatternCtx = ctx.lhsPattern(0); - currentPattern = new PatternDescr(lhsPatternCtx.objectType.getText()); + Object result = super.visitLhsPatternBind(ctx); + PatternDescr patternDescr = (PatternDescr) currentConstructStack.peek().getDescrs().get(0); if (ctx.label() != null) { - currentPattern.setIdentifier(ctx.label().IDENTIFIER().getText()); + patternDescr.setIdentifier(ctx.label().IDENTIFIER().getText()); } - if (lhsPatternCtx.patternSource() != null) { - String expression = lhsPatternCtx.patternSource().getText(); - FromDescr from = new FromDescr(); - from.setDataSource(new MVELExprDescr(expression)); - from.setResource(currentPattern.getResource()); - currentPattern.setSource(from); + return result; + } else if (ctx.lhsPattern().size() > 1) { + OrDescr orDescr = new OrDescr(); + currentConstructStack.peek().addDescr(orDescr); + currentConstructStack.push(orDescr); + try { + Object result = super.visitLhsPatternBind(ctx); + List<? extends BaseDescr> descrs = orDescr.getDescrs(); + for (BaseDescr descr : descrs) { + PatternDescr patternDescr = (PatternDescr) descr; + if (ctx.label() != null) { + patternDescr.setIdentifier(ctx.label().IDENTIFIER().getText()); + } + } + return result; + } finally { + currentConstructStack.pop(); } - currentConstructStack.peek().addDescr(currentPattern); + } else { + throw new IllegalStateException("ctx.lhsPattern().size() == 0 : " + ctx.getText()); + } + } + + @Override + public Object visitLhsPattern(DRLParser.LhsPatternContext ctx) { + currentPattern = new PatternDescr(ctx.objectType.getText()); + if (ctx.patternSource() != null) { + String expression = ctx.patternSource().getText(); + FromDescr from = new FromDescr(); + from.setDataSource(new MVELExprDescr(expression)); + from.setResource(currentPattern.getResource()); + currentPattern.setSource(from); } - Object result = super.visitLhsPatternBind(ctx); + Object result = super.visitLhsPattern(ctx); + currentConstructStack.peek().addDescr(currentPattern); currentPattern = null; return result; } 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 caabed1592..07746c0299 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 @@ -10,11 +10,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import junit.framework.TestCase; +import org.assertj.core.api.Assertions; +import org.drools.drl.ast.descr.AndDescr; +import org.drools.drl.ast.descr.BaseDescr; import org.drools.drl.ast.descr.FromDescr; 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.NotDescr; +import org.drools.drl.ast.descr.OrDescr; import org.drools.drl.ast.descr.PackageDescr; import org.drools.drl.ast.descr.PatternDescr; import org.drools.drl.ast.descr.RuleDescr; @@ -22,6 +26,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + /* * This test class is being ported from org.drools.mvel.compiler.lang.RuleParserTest */ @@ -277,4 +283,118 @@ public class MiscDRLParserTest extends TestCase { assertEquals("customerService.getCustomer(o.getCustomerId())", ((FromDescr) customer.getSource()).getDataSource().getText()); } + + @Test + public void testFromWithInlineList() throws Exception { + String source = "rule XYZ \n" + + " when \n" + + " o: Order( ) \n" + + " not( Number( ) from [1, 2, 3] ) \n" + + " then \n" + + " System.err.println(\"Invalid customer id found!\"); \n" + + " o.addError(\"Invalid customer id\"); \n" + + "end \n"; + PackageDescr pkg = parser.parse(source); + assertFalse(parser.getErrors().toString(), + parser.hasErrors()); + + RuleDescr rule = (RuleDescr) pkg.getRules().get(0); + assertEquals("XYZ", + rule.getName()); + + PatternDescr number = (PatternDescr) ((NotDescr) rule.getLhs().getDescrs().get(1)).getDescrs().get(0); + assertThat(((FromDescr) number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1, 2, 3]"); + } + + @Test + public void testFromWithInlineListMethod() throws Exception { + String source = "rule XYZ \n" + + " when \n" + + " o: Order( ) \n" + + " Number( ) from [1, 2, 3].sublist(1, 2) \n" + + " then \n" + + " System.err.println(\"Invalid customer id found!\"); \n" + + " o.addError(\"Invalid customer id\"); \n" + + "end \n"; + PackageDescr pkg = parser.parse(source); + assertFalse(parser.getErrors().toString(), + parser.hasErrors()); + + RuleDescr rule = (RuleDescr) pkg.getRules().get(0); + assertEquals("XYZ", + rule.getName()); + + assertFalse(parser.hasErrors()); + PatternDescr number = (PatternDescr) rule.getLhs().getDescrs().get(1); + + assertThat(((FromDescr) number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1, 2, 3].sublist(1, 2)"); + } + + @Test + public void testFromWithInlineListIndex() throws Exception { + String source = "rule XYZ \n" + + " when \n" + + " o: Order( ) \n" + + " Number( ) from [1, 2, 3][1] \n" + + " then \n" + + " System.err.println(\"Invalid customer id found!\"); \n" + + " o.addError(\"Invalid customer id\"); \n" + + "end \n"; + PackageDescr pkg = parser.parse(source); + + assertFalse(parser.getErrors().toString(), + parser.hasErrors()); + + RuleDescr rule = (RuleDescr) pkg.getRules().get(0); + assertEquals("XYZ", + rule.getName()); + + assertFalse(parser.hasErrors()); + PatternDescr number = (PatternDescr) rule.getLhs().getDescrs().get(1); + assertThat(((FromDescr) number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1, 2, 3][1]"); + } + + @Test + public void testRuleWithoutEnd() throws Exception { + String source = "rule \"Invalid customer id\" \n" + + " when \n" + + " o: Order( ) \n" + + " then \n" + + " System.err.println(\"Invalid customer id found!\"); \n"; + parser.parse(source); + assertTrue(parser.hasErrors()); + } + + @Test + public void testOrWithSpecialBind() throws Exception { + String source = "rule \"A and (B or C or D)\" \n" + + " when \n" + + " pdo1 : ParametricDataObject( paramID == 101, stringValue == \"1000\" ) and \n" + + " pdo2 :(ParametricDataObject( paramID == 101, stringValue == \"1001\" ) or \n" + + " ParametricDataObject( paramID == 101, stringValue == \"1002\" ) or \n" + + " ParametricDataObject( paramID == 101, stringValue == \"1003\" )) \n" + + " then \n" + + " System.out.println( \"Rule: A and (B or C or D) Fired. pdo1: \" + pdo1 + \" pdo2: \"+ pdo2); \n" + + "end\n"; + PackageDescr pkg = parser.parse(source); + assertFalse(parser.getErrors().toString(), + parser.hasErrors()); + + RuleDescr rule = pkg.getRules().get(0); + AndDescr lhs = rule.getLhs(); + assertEquals(2, + lhs.getDescrs().size()); + + PatternDescr pdo1 = (PatternDescr) lhs.getDescrs().get(0); + assertEquals("pdo1", + pdo1.getIdentifier()); + + OrDescr or = (OrDescr) rule.getLhs().getDescrs().get(1); + assertEquals(3, + or.getDescrs().size()); + for (BaseDescr pdo2 : or.getDescrs()) { + assertEquals("pdo2", + ((PatternDescr) pdo2).getIdentifier()); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
