From 2b8866ecfe96bde45496140e68721a53b5714562 Mon Sep 17 00:00:00 2001 From: Toshiya Kobayashi Date: Fri, 13 Oct 2023 18:25:21 +0900 Subject: [PATCH] [DROOLS-7301] Implement query (#37) - Also partially fixes [DROOLS-7302] Implement semicolon delimiter --- .../main/antlr4/org/drools/parser/DRLLexer.g4 | 3 +- .../antlr4/org/drools/parser/DRLParser.g4 | 11 +++++-- .../org/drools/parser/DRLVisitorImpl.java | 32 +++++++++++++++++++ .../org/drools/parser/MiscDRLParserTest.java | 8 +---- 4 files changed, 43 insertions(+), 11 deletions(-) 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 d200e7c6e80..2bb35093aab 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 @@ -35,6 +35,7 @@ DRL_RULE : 'rule'; DRL_QUERY : 'query'; DRL_WHEN : 'when'; DRL_THEN : 'then' -> pushMode(RHS); +DRL_QUERY_END : 'end'; DRL_AND : 'and'; DRL_OR : 'or'; @@ -153,5 +154,5 @@ DrlUnicodeEscape mode RHS; RHS_WS : [ \t\r\n\u000C]+ -> channel(HIDDEN); -DRL_END : 'end' [ \t]* ('\n' | '\r\n' | EOF) {setText("end");} -> popMode; +DRL_END : 'end' [ \t]* SEMI? [ \t]* ('\n' | '\r\n' | EOF) {setText("end");} -> popMode; RHS_CHUNK : ~[ \t\r\n\u000C]+ ; 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 e531c3d91c8..d418d82da95 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,9 +19,10 @@ compilationUnit : packagedef? unitdef? drlStatementdef* ; drlStatementdef : importdef | globaldef - | functiondef - | attributes | ruledef + | attributes + | functiondef + | querydef ; packagedef : PACKAGE name=drlQualifiedName SEMI? ; @@ -38,6 +39,10 @@ globaldef : DRL_GLOBAL type drlIdentifier SEMI? ; ruledef : DRL_RULE name=stringId (EXTENDS parentName=stringId)? drlAnnotation* attributes? lhs rhs DRL_END ; +// query := QUERY stringId parameters? annotation* lhsExpression END + +querydef : DRL_QUERY name=stringId formalParameters? drlAnnotation* lhsExpression+ DRL_QUERY_END SEMI?; + lhs : DRL_WHEN lhsExpression* ; lhsExpression : LPAREN lhsExpression RPAREN #lhsExpressionEnclosed @@ -147,7 +152,7 @@ drlKeywords | DRL_QUERY | DRL_WHEN | DRL_THEN - | DRL_END + | DRL_QUERY_END | DRL_AND | DRL_OR | DRL_EXISTS 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 596e31c7e47..1d33e459754 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 @@ -32,6 +32,7 @@ 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.QueryDescr; import org.drools.drl.ast.descr.RuleDescr; import org.drools.drl.ast.descr.UnitDescr; @@ -85,6 +86,8 @@ private void applyChildrenDescrs(PackageDescr packageDescr, List desc packageDescr.addAttribute((AttributeDescr) descr); } else if (descr instanceof RuleDescr) { packageDescr.addRule((RuleDescr) descr); + } else if (descr instanceof QueryDescr) { + packageDescr.addRule((QueryDescr) descr); } }); } @@ -186,6 +189,32 @@ private void slimLhsRootDescr(AndDescr root) { descrList.forEach(root::addOrMerge); // This slims down nested AndDescr } + @Override + public QueryDescr visitQuerydef(DRLParser.QuerydefContext ctx) { + QueryDescr queryDescr = new QueryDescr(safeStripStringDelimiters(ctx.name.getText())); + + DRLParser.FormalParametersContext formalParametersContext = ctx.formalParameters(); + if (formalParametersContext != null) { + DRLParser.FormalParameterListContext formalParameterListContext = formalParametersContext.formalParameterList(); + List formalParameterContexts = formalParameterListContext.formalParameter(); + formalParameterContexts.forEach(formalParameterContext -> { + DRLParser.TypeTypeContext typeTypeContext = formalParameterContext.typeType(); + DRLParser.VariableDeclaratorIdContext variableDeclaratorIdContext = formalParameterContext.variableDeclaratorId(); + queryDescr.addParameter(typeTypeContext.getText(), variableDeclaratorIdContext.getText()); + }); + } + + ctx.drlAnnotation().stream().map(this::visitDrlAnnotation).forEach(queryDescr::addAnnotation); + + ctx.lhsExpression().stream() + .flatMap(lhsExpressionContext -> visitDescrChildren(lhsExpressionContext).stream()) + .forEach(descr -> queryDescr.getLhs().addDescr(descr)); + + slimLhsRootDescr(queryDescr.getLhs()); + + return queryDescr; + } + @Override public AnnotationDescr visitDrlAnnotation(DRLParser.DrlAnnotationContext ctx) { AnnotationDescr annotationDescr = new AnnotationDescr(ctx.name.getText()); @@ -254,6 +283,9 @@ private OrDescr getOrDescrWithMultiplePatternDescr(DRLParser.LhsPatternBindConte @Override public PatternDescr visitLhsPattern(DRLParser.LhsPatternContext ctx) { PatternDescr patternDescr = new PatternDescr(ctx.objectType.getText()); + if (ctx.QUESTION() != null) { + patternDescr.setQuery(true); + } if (ctx.patternFilter() != null) { patternDescr.addBehavior(visitPatternFilter(ctx.patternFilter())); } 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 ca78882b598..c25bb3274f6 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 @@ -913,7 +913,6 @@ public void parse_LineNumberIncludingCommentsInRHS() throws Exception { Pattern.DOTALL | Pattern.MULTILINE).matcher(rhs).matches()).isTrue(); } - @Disabled("Priority : High | Implement semicolon delimiter") @Test public void parse_LhsSemicolonDelim() throws Exception { final RuleDescr rule = parseAndGetFirstRuleDescrFromFile( @@ -1017,7 +1016,6 @@ public void parse_NotExistWithBrackets() throws Exception { assertThat(exPattern.getObjectType()).isEqualTo("Foo"); } - @Disabled("Priority : High | Implement query") @Test public void parse_SimpleQuery() throws Exception { final QueryDescr query = parseAndGetFirstQueryDescrFromFile( @@ -1057,7 +1055,6 @@ public void parse_SimpleQuery() throws Exception { assertThat(bindingDescr.getExpression()).isEqualTo("a4:a==4"); } - @Disabled("Priority : High | Implement query") @Test public void parse_QueryRuleMixed() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -2313,7 +2310,7 @@ public void parse_Restrictions() throws Exception { assertThat(fieldConstr.getExpression()).isEqualTo("bar > 1 || == 1"); } - @Disabled("Priority : High | Implement semicolon delimiter") + @Disabled("Priority : High | Implement semicolon delimiter | Implement from collect") @Test public void parse_Semicolon() throws Exception { final PackageDescr pkg = parseAndGetPackageDescrFromFile( @@ -3042,7 +3039,6 @@ public void parse_PositionalConstraintsOnly() throws Exception { assertThat(fcd.getType()).isEqualTo(ExprConstraintDescr.Type.POSITIONAL); } - @Disabled("Priority : High | Implement query") @Test public void parse_IsQuery() throws Exception { final String text = "rule X when ?person( \"Mark\", 42; ) then end"; @@ -3062,7 +3058,6 @@ public void parse_IsQuery() throws Exception { assertThat(fcd.getType()).isEqualTo(ExprConstraintDescr.Type.POSITIONAL); } - @Disabled("Priority : Mid | Implement query with from") @Test public void parse_FromFollowedByQuery() throws Exception { // the 'from' expression requires a ";" to disambiguate the "?" @@ -3083,7 +3078,6 @@ public void parse_FromFollowedByQuery() throws Exception { } - @Disabled("Priority : Mid | Implement query with from") @Test public void parse_FromWithTernaryFollowedByQuery() throws Exception { // the 'from' expression requires a ";" to disambiguate the "?"