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]

Reply via email to