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 0e91fb3f2e5..0eb6d961bce 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 @@ -44,6 +44,11 @@ DRL_NOT : 'not'; DRL_IN : 'in'; DRL_FROM : 'from'; DRL_MATCHES : 'matches'; +DRL_ACCUMULATE : 'accumulate' | 'acc'; +DRL_INIT : 'init'; +DRL_ACTION : 'action'; +DRL_REVERSE : 'reverse'; +DRL_RESULT : 'result'; DRL_SALIENCE : 'salience'; DRL_ENABLED : 'enabled'; 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 c150a480e4a..1b96c788b3b 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 @@ -46,6 +46,11 @@ lhsExpression : LPAREN lhsExpression RPAREN #lhsExpressionEnclosed | lhsExpression (DRL_OR lhsExpression)+ #lhsOr ; +// and is accepted for accumulate +lhsAndForAccumulate : lhsUnary (DRL_AND lhsUnary)+ + | LPAREN DRL_AND lhsUnary+ RPAREN + ; + /* lhsUnary : ( lhsExists namedConsequence? | lhsNot namedConsequence? @@ -61,6 +66,7 @@ lhsUnary : ( lhsExists | lhsNot | lhsPatternBind + | lhsAccumulate ) ; lhsPatternBind : label? ( LPAREN lhsPattern (DRL_OR lhsPattern)* RPAREN | lhsPattern ) ; @@ -257,9 +263,35 @@ mapEntry | fromWindow | fromExpression ) */ -patternSource : fromExpression ; +patternSource : fromExpression + | fromAccumulate + ; + fromExpression : conditionalOrExpression ; + +/* +fromAccumulate := ACCUMULATE LEFT_PAREN lhsAnd (COMMA|SEMICOLON) + ( INIT chunk_(_) COMMA ACTION chunk_(_) COMMA + ( REVERSE chunk_(_) COMMA)? RESULT chunk_(_) + | accumulateFunction + ) RIGHT_PAREN +*/ +fromAccumulate : DRL_ACCUMULATE LPAREN lhsAndForAccumulate (COMMA|SEMI) + ( DRL_INIT LPAREN initBlockStatements=blockStatements RPAREN COMMA DRL_ACTION LPAREN actionBlockStatements=blockStatements RPAREN COMMA ( DRL_REVERSE LPAREN reverseBlockStatements=blockStatements RPAREN COMMA)? DRL_RESULT LPAREN expression RPAREN + | accumulateFunction + ) + RPAREN (SEMI)? + ; + +blockStatements : blockStatement* ; + +/* +accumulateFunction := label? ID parameters +*/ +accumulateFunction : label? IDENTIFIER LPAREN drlExpression RPAREN; + + /* lhsExists := EXISTS ( (LEFT_PAREN (or_key|and_key))=> lhsOr // prevents '((' for prefixed and/or @@ -277,6 +309,19 @@ lhsExists : DRL_EXISTS lhsPatternBind ; */ lhsNot : DRL_NOT lhsPatternBind ; +/** + * lhsAccumulate := (ACCUMULATE|ACC) LEFT_PAREN lhsAnd (COMMA|SEMICOLON) + * accumulateFunctionBinding (COMMA accumulateFunctionBinding)* + * (SEMICOLON constraints)? + * RIGHT_PAREN SEMICOLON? + */ + +lhsAccumulate : DRL_ACCUMULATE LPAREN lhsAndForAccumulate (COMMA|SEMI) + accumulateFunction (COMMA accumulateFunction)* + (SEMI constraints)? + RPAREN (SEMI)? + ; + rhs : DRL_THEN consequence ; consequence : RHS_CHUNK* ; 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 22858fba9fc..e3e5a499df8 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 @@ -9,6 +9,7 @@ import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.RuleNode; +import org.drools.drl.ast.descr.AccumulateDescr; import org.drools.drl.ast.descr.AndDescr; import org.drools.drl.ast.descr.AnnotationDescr; import org.drools.drl.ast.descr.AttributeDescr; @@ -25,6 +26,7 @@ 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.PatternSourceDescr; import org.drools.drl.ast.descr.RuleDescr; import org.drools.drl.ast.descr.UnitDescr; @@ -234,17 +236,66 @@ private OrDescr getOrDescrWithMultiplePatternDescr(DRLParser.LhsPatternBindConte public PatternDescr visitLhsPattern(DRLParser.LhsPatternContext ctx) { PatternDescr patternDescr = 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(patternDescr.getResource()); - patternDescr.setSource(from); + PatternSourceDescr patternSourceDescr = (PatternSourceDescr) visitPatternSource(ctx.patternSource()); + patternSourceDescr.setResource(patternDescr.getResource()); + patternDescr.setSource(patternSourceDescr); } List constraintDescrList = visitConstraints(ctx.constraints()); constraintDescrList.forEach(patternDescr::addConstraint); return patternDescr; } + @Override + public PatternDescr visitLhsAccumulate(DRLParser.LhsAccumulateContext ctx) { + AccumulateDescr accumulateDescr = new AccumulateDescr(); + accumulateDescr.setInput(visitLhsAndForAccumulate(ctx.lhsAndForAccumulate())); + + // accumulate function + for (DRLParser.AccumulateFunctionContext accumulateFunctionContext : ctx.accumulateFunction()) { + accumulateDescr.addFunction(visitAccumulateFunction(accumulateFunctionContext)); + } + + PatternDescr patternDescr = new PatternDescr("Object"); + patternDescr.setSource(accumulateDescr); + List constraintDescrList = visitConstraints(ctx.constraints()); + constraintDescrList.forEach(patternDescr::addConstraint); + return patternDescr; + } + + @Override + public FromDescr visitFromExpression(DRLParser.FromExpressionContext ctx) { + FromDescr fromDescr = new FromDescr(); + fromDescr.setDataSource(new MVELExprDescr(ctx.getText())); + return fromDescr; + } + + @Override + public AccumulateDescr visitFromAccumulate(DRLParser.FromAccumulateContext ctx) { + AccumulateDescr accumulateDescr = new AccumulateDescr(); + accumulateDescr.setInput(visitLhsAndForAccumulate(ctx.lhsAndForAccumulate())); + if (ctx.DRL_INIT() != null) { + // inline custom accumulate + accumulateDescr.setInitCode(getTextPreservingWhitespace(ctx.initBlockStatements)); + accumulateDescr.setActionCode(getTextPreservingWhitespace(ctx.actionBlockStatements)); + if (ctx.DRL_REVERSE() != null) { + accumulateDescr.setReverseCode(getTextPreservingWhitespace(ctx.reverseBlockStatements)); + } + accumulateDescr.setResultCode(ctx.expression().getText()); + } else { + // accumulate function + accumulateDescr.addFunction(visitAccumulateFunction(ctx.accumulateFunction())); + } + return accumulateDescr; + } + + @Override + public AccumulateDescr.AccumulateFunctionCallDescr visitAccumulateFunction(DRLParser.AccumulateFunctionContext ctx) { + String function = ctx.IDENTIFIER().getText(); + String bind = ctx.label() == null ? null : ctx.label().IDENTIFIER().getText(); + String[] params = new String[]{getTextPreservingWhitespace(ctx.drlExpression())}; + return new AccumulateDescr.AccumulateFunctionCallDescr(function, bind, false, params); + } + @Override public List visitConstraints(DRLParser.ConstraintsContext ctx) { if (ctx == null) { @@ -304,12 +355,20 @@ public BaseDescr visitLhsOr(DRLParser.LhsOrContext ctx) { @Override public BaseDescr visitLhsAnd(DRLParser.LhsAndContext ctx) { + return createAndDescr(visitDescrChildren(ctx)); + } + + private AndDescr createAndDescr(List descrList) { AndDescr andDescr = new AndDescr(); - List descrList = visitDescrChildren(ctx); descrList.forEach(andDescr::addDescr); return andDescr; } + @Override + public BaseDescr visitLhsAndForAccumulate(DRLParser.LhsAndForAccumulateContext ctx) { + return createAndDescr(visitDescrChildren(ctx)); + } + @Override public BaseDescr visitLhsUnary(DRLParser.LhsUnaryContext ctx) { return (BaseDescr) visitChildren(ctx); 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 011926dc1b3..96134e5ee28 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 @@ -305,7 +305,6 @@ void parse_fromWithInlineListMethod() { " System.err.println(\"Invalid customer id found!\"); \n" + " o.addError(\"Invalid customer id\"); \n" + "end \n"; - System.out.println(source); PackageDescr pkg = parser.parse(source); assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse(); @@ -2011,7 +2010,6 @@ public void parse_QualifiedClassname() throws Exception { assertThat(p.getObjectType()).isEqualTo("com.cheeseco.Cheese"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_Accumulate() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2034,7 +2032,6 @@ public void parse_Accumulate() throws Exception { assertThat(pattern.getObjectType()).isEqualTo("Person"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateWithBindings() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2356,7 +2353,6 @@ public void parse_Eval() throws Exception { assertThat(rule1.getLhs().getDescrs().size()).isEqualTo(1); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateReverse() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2382,7 +2378,6 @@ public void parse_AccumulateReverse() throws Exception { assertThat(pattern.getObjectType()).isEqualTo("Person"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateExternalFunction() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2426,7 +2421,7 @@ public void parse_CollectWithNestedFrom() throws Exception { assertThat(people.getObjectType()).isEqualTo("People"); } - @Disabled("Priority : High | Implement accumulate") + @Disabled("Priority : High | Implement accumulate and Implement from collect") @Test public void parse_AccumulateWithNestedFrom() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2448,7 +2443,6 @@ public void parse_AccumulateWithNestedFrom() throws Exception { assertThat(people.getObjectType()).isEqualTo("People"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateMultipleFunctions() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2482,7 +2476,6 @@ public void parse_AccumulateMultipleFunctions() throws Exception { assertThat(pattern.getObjectType()).isEqualTo("Cheese"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateMnemonic() throws Exception { String drl = "package org.drools.mvel.compiler\n" + @@ -2515,7 +2508,6 @@ public void parse_AccumulateMnemonic() throws Exception { assertThat(pattern.getObjectType()).isEqualTo("Cheese"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateMnemonic2() throws Exception { String drl = "package org.drools.mvel.compiler\n" + @@ -2596,7 +2588,6 @@ public void parse_ImportAccumulate() throws Exception { assertThat(pattern.getObjectType()).isEqualTo("Cheese"); } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateMultipleFunctionsConstraint() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2701,7 +2692,6 @@ public void parse_RuleParseLhs3() throws Exception { } - @Disabled("Priority : High | Implement accumulate") @Test public void parse_AccumulateMultiPattern() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile(