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 4c2a7e761f [new-parser] Fix AccumulateTest and add groupBy support
(#5876)
4c2a7e761f is described below
commit 4c2a7e761fc31bd9143d6640a1f624fa5beea2ef
Author: Jiří Locker <[email protected]>
AuthorDate: Tue Apr 30 07:38:34 2024 +0200
[new-parser] Fix AccumulateTest and add groupBy support (#5876)
* Fix AccumulateTest
* Add GroupBy support
---
.../drl/parser/antlr4/MiscDRLParserTest.java | 102 ++++++++++++++++++++-
.../org/drools/drl/parser/antlr4/groupBy.drl | 26 ++++++
.../org/drools/drl/parser/antlr4/DRLLexer.g4 | 3 +-
.../org/drools/drl/parser/antlr4/DRLParser.g4 | 21 ++++-
.../drools/drl/parser/antlr4/DRLVisitorImpl.java | 34 ++++++-
5 files changed, 178 insertions(+), 8 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 8422827031..d400c7b00f 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
@@ -34,6 +34,7 @@ import org.drools.drl.ast.descr.ForallDescr;
import org.drools.drl.ast.descr.FromDescr;
import org.drools.drl.ast.descr.FunctionDescr;
import org.drools.drl.ast.descr.GlobalDescr;
+import org.drools.drl.ast.descr.GroupByDescr;
import org.drools.drl.ast.descr.ImportDescr;
import org.drools.drl.ast.descr.MVELExprDescr;
import org.drools.drl.ast.descr.NamedConsequenceDescr;
@@ -479,7 +480,7 @@ class MiscDRLParserTest {
// e.g. "package" is not allowed in a package value in Java, so it
doesn't make sense to test. (Right to raise a parser error)
PackageDescr pkg = parseAndGetPackageDescr(source);
-
+
assertThat(pkg.getRules()).hasSize(1);
}
@@ -2085,6 +2086,43 @@ class MiscDRLParserTest {
assertThat(col.getEndLine()).isEqualTo(25);
}
+ @Test
+ public void parse_GroupBy() throws Exception {
+ final PackageDescr pkg = parseAndGetPackageDescrFromFile(
"groupBy.drl" );
+
+ assertThat(pkg.getRules().size()).isEqualTo(1);
+ final RuleDescr rule = pkg.getRules().get(0);
+ assertThat(rule.getLhs().getDescrs().size()).isEqualTo(1);
+
+ final PatternDescr outPattern = (PatternDescr)
rule.getLhs().getDescrs().get( 0 );
+ final GroupByDescr groupBy = (GroupByDescr) outPattern.getSource();
+
assertThat(groupBy.getGroupingKey()).isEqualToIgnoringWhitespace("$initial");
+
assertThat(groupBy.getGroupingFunction()).isEqualToIgnoringWhitespace("$p.getName().substring(0,
1)");
+ assertThat(groupBy.getActionCode()).isNull();
+ assertThat(groupBy.getReverseCode()).isNull();
+ assertThat(groupBy.getFunctions()).hasSize(2);
+
assertThat(groupBy.getFunctions().get(0).getFunction()).isEqualToIgnoringWhitespace("sum");
+
assertThat(groupBy.getFunctions().get(1).getFunction()).isEqualToIgnoringWhitespace("count");
+
+ assertThat(groupBy.getFunctions().get(0).getParams()).hasSize(1);
+
assertThat(groupBy.getFunctions().get(0).getParams()[0]).isEqualToIgnoringWhitespace("$age");
+
+ assertThat(groupBy.getFunctions().get(1).getParams()).hasSize(0);
+
+ assertThat(groupBy.isExternalFunction()).isTrue();
+
+ final PatternDescr pattern = groupBy.getInputPattern();
+ assertThat(pattern.getObjectType()).isEqualTo("Person");
+ assertThat(pattern.getConstraint().getDescrs()).hasSize(1);
+
assertThat(pattern.getConstraint().getDescrs().get(0).getText()).isEqualToIgnoringWhitespace("$age
: age < 30");
+
+ assertThat(pattern.getConstraint().getDescrs()).hasSize(1);
+
assertThat(pattern.getConstraint().getDescrs().get(0).getText()).isEqualToIgnoringWhitespace("$age
: age < 30");
+
+ assertThat(outPattern.getConstraint().getDescrs()).hasSize(1);
+
assertThat(outPattern.getConstraint().getDescrs().get(0).getText()).isEqualToIgnoringWhitespace("$sumOfAges
> 10");
+ }
+
@Test
public void parse_QualifiedClassname() throws Exception {
final PackageDescr pkg = parseAndGetPackageDescrFromFile(
@@ -2139,6 +2177,68 @@ class MiscDRLParserTest {
assertThat(pattern.getObjectType()).isEqualTo("Person");
}
+ /**
+ * - Optional semicolon at the end of statements (int x = 0).
+ * - Optional comma delimiting init, action, and result.
+ */
+ @Test
+ public void accumulateWithoutOptionalDelimiters() throws Exception {
+ String source = "rule \"AccumulateParserTest\"\n"
+ + "when\n"
+ + " $counter:Integer() from accumulate( $person : Person(
age > 21 ),\n"
+ + " init( int x = 0
)\n"
+ + " action( x++ )\n"
+ + " result( new
Integer(x) ) );\n"
+ + "then\n"
+ + "end\n";
+ final PackageDescr pkg = parseAndGetPackageDescr( source );
+
+ assertThat(pkg.getRules().size()).isEqualTo(1);
+ final RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
+ assertThat(rule.getLhs().getDescrs().size()).isEqualTo(1);
+
+ final PatternDescr outPattern = (PatternDescr)
rule.getLhs().getDescrs().get( 0 );
+ final AccumulateDescr accum = (AccumulateDescr) outPattern.getSource();
+ assertThat(outPattern.getIdentifier()).isEqualToIgnoringWhitespace(
"$counter");
+ assertThat(accum.getInitCode()).isEqualToIgnoringWhitespace( "int x =
0");
+ assertThat(accum.getActionCode()).isEqualToIgnoringWhitespace( "x++");
+ assertThat(accum.getResultCode()).isEqualToIgnoringWhitespace( "new
Integer(x)");
+
+ final PatternDescr pattern = (PatternDescr) accum.getInputPattern();
+ assertThat(pattern.getObjectType()).isEqualTo("Person");
+ }
+
+ /**
+ * When the accumulate function (e.g. count()) has no arguments.
+ */
+ @Test
+ public void accumulateCount() throws Exception {
+ String source = "rule R when\n" +
+ " accumulate (\n" +
+ " Person(), $result : count() " +
+ " )" +
+ "then\n" +
+ "end";
+ final PackageDescr pkg = parseAndGetPackageDescr( source );
+
+ assertThat(pkg.getRules().size()).isEqualTo(1);
+ final RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
+ assertThat(rule.getLhs().getDescrs().size()).isEqualTo(1);
+
+ final PatternDescr outPattern = (PatternDescr)
rule.getLhs().getDescrs().get( 0 );
+ final AccumulateDescr accum = (AccumulateDescr) outPattern.getSource();
+ assertThat(accum).isNotNull();
+
+ final PatternDescr pattern = (PatternDescr) accum.getInputPattern();
+ assertThat(pattern.getObjectType()).isEqualTo("Person");
+
+ assertThat(accum.getFunctions()).hasSize(1);
+ AccumulateDescr.AccumulateFunctionCallDescr accumulateFunction =
accum.getFunctions().get(0);
+ assertThat(accumulateFunction.getBind()).isEqualTo("$result");
+ assertThat(accumulateFunction.getFunction()).isEqualTo("count");
+ assertThat(accumulateFunction.getParams()).isEmpty();
+ }
+
@Test
public void parse_Collect() throws Exception {
final PackageDescr pkg = parseAndGetPackageDescrFromFile(
diff --git
a/drools-drl/drools-drl-parser-tests/src/test/resources/org/drools/drl/parser/antlr4/groupBy.drl
b/drools-drl/drools-drl-parser-tests/src/test/resources/org/drools/drl/parser/antlr4/groupBy.drl
new file mode 100755
index 0000000000..9ca6ed7e83
--- /dev/null
+++
b/drools-drl/drools-drl-parser-tests/src/test/resources/org/drools/drl/parser/antlr4/groupBy.drl
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+rule "GroupByParserTest"
+when
+ groupby( $p: Person ( $age : age < 30 ); // SOURCE_PATTERN
+ $initial : $p.getName().substring(0, 1); // GROUPING_FUNCTION
+ $sumOfAges : sum($age), // 2 ACC_FUNCTIONS, one
summing the ages of the persons in the group
+ $countOfPersons : count(); // and the other simply
counting them
+ $sumOfAges > 10 ) // CONSTRAINT filtering
away groups
+then
+end
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 52716591ad..58719554de 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
@@ -60,6 +60,7 @@ DRL_ENTRY_POINT : 'entry-point';
DRL_EVAL : 'eval';
DRL_FORALL : 'forall';
DRL_OVER : 'over';
+DRL_GROUPBY : 'groupby';
// constraint operators
DRL_MATCHES : 'matches';
@@ -189,4 +190,4 @@ RHS_CHUNK
| RBRACE
| COMMA
| SEMI
- ;
\ No newline at end of file
+ ;
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 fb6a9bf68c..b173157c93 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
@@ -134,6 +134,7 @@ lhsUnary : (
| lhsEval consequenceInvocation*
| lhsForall
| lhsAccumulate
+ | lhsGroupBy
| conditionalBranch // not in the above old parser definition, but
actually implemented in the old parser
| lhsPatternBind consequenceInvocation*
) SEMI? ;
@@ -184,7 +185,7 @@ relationalOperator
drlRelationalOperator : DRL_NOT? builtInOperator ;
/* function := FUNCTION type? ID parameters(typed) chunk_{_} */
-functiondef : DRL_FUNCTION typeTypeOrVoid? IDENTIFIER formalParameters
drlBlock ;
+functiondef : DRL_FUNCTION typeTypeOrVoid? drlIdentifier formalParameters
drlBlock ;
/* extending JavaParser qualifiedName */
@@ -335,7 +336,7 @@ fromAccumulate := ACCUMULATE LEFT_PAREN lhsAnd
(COMMA|SEMICOLON)
) RIGHT_PAREN
*/
fromAccumulate : (DRL_ACCUMULATE|DRL_ACC) LPAREN lhsAndDef (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
+ ( DRL_INIT LPAREN initBlockStatements=chunk RPAREN COMMA?
DRL_ACTION LPAREN actionBlockStatements=chunk RPAREN COMMA? ( DRL_REVERSE
LPAREN reverseBlockStatements=chunk RPAREN COMMA?)? DRL_RESULT LPAREN
expression RPAREN
| accumulateFunction
)
RPAREN (SEMI)?
@@ -346,7 +347,10 @@ blockStatements : drlBlockStatement* ;
/*
accumulateFunction := label? ID parameters
*/
-accumulateFunction : label? IDENTIFIER LPAREN drlExpression RPAREN;
+accumulateFunction : label? IDENTIFIER conditionalExpressions ;
+
+// parameters := LEFT_PAREN (conditionalExpression (COMMA
conditionalExpression)* )? RIGHT_PAREN
+conditionalExpressions : LPAREN (conditionalExpression (COMMA
conditionalExpression)* )? RPAREN ;
// fromCollect := COLLECT LEFT_PAREN lhsPatternBind RIGHT_PAREN
@@ -409,6 +413,15 @@ lhsAccumulate : (DRL_ACCUMULATE|DRL_ACC) LPAREN lhsAndDef
(COMMA|SEMI)
RPAREN (SEMI)?
;
+lhsGroupBy : DRL_GROUPBY LPAREN lhsAndDef (COMMA|SEMI)
+ groupByKeyBinding SEMI
+ accumulateFunction (COMMA accumulateFunction)*
+ (SEMI constraints)?
+ RPAREN (SEMI)?
+ ;
+
+groupByKeyBinding : label? conditionalExpression ;
+
rhs : DRL_THEN consequenceBody namedConsequence* ;
consequenceBody : ( RHS_STRING_LITERAL | RHS_CHUNK )* ;
@@ -483,7 +496,7 @@ drlBlock
;
/* extending JavaParser blockStatement */
drlBlockStatement
- : drlLocalVariableDeclaration SEMI
+ : drlLocalVariableDeclaration SEMI?
| drlStatement
| localTypeDeclaration
;
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 f568256b8e..5fef172405 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
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
@@ -48,6 +49,7 @@ import org.drools.drl.ast.descr.FromDescr;
import org.drools.drl.ast.descr.FunctionDescr;
import org.drools.drl.ast.descr.FunctionImportDescr;
import org.drools.drl.ast.descr.GlobalDescr;
+import org.drools.drl.ast.descr.GroupByDescr;
import org.drools.drl.ast.descr.ImportDescr;
import org.drools.drl.ast.descr.MVELExprDescr;
import org.drools.drl.ast.descr.NamedConsequenceDescr;
@@ -202,7 +204,7 @@ public class DRLVisitorImpl extends
DRLParserBaseVisitor<Object> {
} else {
functionDescr.setReturnType("void");
}
- functionDescr.setName(ctx.IDENTIFIER().getText());
+ functionDescr.setName(ctx.drlIdentifier().getText());
// add function parameters
DRLParser.FormalParametersContext formalParametersContext =
ctx.formalParameters();
@@ -700,6 +702,31 @@ public class DRLVisitorImpl extends
DRLParserBaseVisitor<Object> {
return patternDescr;
}
+ @Override
+ public Object visitLhsGroupBy(DRLParser.LhsGroupByContext ctx) {
+ GroupByDescr groupByDescr = BaseDescrFactory.builder(new
GroupByDescr())
+ .withParserRuleContext(ctx)
+ .build();
+ groupByDescr.setInput(visitLhsAndDef(ctx.lhsAndDef()));
+
+ if (ctx.groupByKeyBinding().label() != null) {
+
groupByDescr.setGroupingKey(ctx.groupByKeyBinding().label().drlIdentifier().getText());
+ }
+
groupByDescr.setGroupingFunction(getTextPreservingWhitespace(ctx.groupByKeyBinding().conditionalExpression()));
+
+ // accumulate function
+ for (DRLParser.AccumulateFunctionContext accumulateFunctionContext :
ctx.accumulateFunction()) {
+
groupByDescr.addFunction(visitAccumulateFunction(accumulateFunctionContext));
+ }
+
+ PatternDescr patternDescr = new PatternDescr("Object");
+ patternDescr.setSource(groupByDescr);
+ List<ExprConstraintDescr> constraintDescrList =
visitConstraints(ctx.constraints());
+ constraintDescrList.forEach(patternDescr::addConstraint);
+
+ return patternDescr;
+ }
+
@Override
public BehaviorDescr visitPatternFilter(DRLParser.PatternFilterContext
ctx) {
BehaviorDescr behaviorDescr = BaseDescrFactory.builder(new
BehaviorDescr())
@@ -756,7 +783,10 @@ public class DRLVisitorImpl extends
DRLParserBaseVisitor<Object> {
public AccumulateDescr.AccumulateFunctionCallDescr
visitAccumulateFunction(DRLParser.AccumulateFunctionContext ctx) {
String function = ctx.IDENTIFIER().getText();
String bind = ctx.label() == null ? null :
ctx.label().drlIdentifier().getText();
- String[] params = new
String[]{getTextPreservingWhitespace(ctx.drlExpression())};
+
+ String[] params =
ctx.conditionalExpressions().conditionalExpression().stream()
+ .map(RuleContext::getText)
+ .toArray(String[]::new);
return new AccumulateDescr.AccumulateFunctionCallDescr(function, bind,
false, params);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]