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 aa202f5ad9 [incubator-kie-drools#5705] [new-parser] no viable
alternative after … (#5767)
aa202f5ad9 is described below
commit aa202f5ad97002c87cd5e981bfb53d0c4107fbca
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Thu Mar 7 17:09:28 2024 +0900
[incubator-kie-drools#5705] [new-parser] no viable alternative after …
(#5767)
* [incubator-kie-drools#5705] [new-parser] no viable alternative after
contains operator
* - Add comment
* Update
drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
Co-authored-by: Jiří Locker <[email protected]>
* Update
drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
Co-authored-by: Jiří Locker <[email protected]>
* Update
drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
Co-authored-by: Jiří Locker <[email protected]>
* Update
drools-drl/drools-drl-parser-tests/src/test/java/org/drools/drl/parser/antlr4/MiscDRLParserTest.java
Co-authored-by: Jiří Locker <[email protected]>
* - add javadoc to ParserHelper.isPluggableEvaluator
---------
Co-authored-by: Jiří Locker <[email protected]>
---
.../drl/parser/antlr4/MiscDRLParserTest.java | 73 +++++++++++++++++++++-
.../drools/drl/parser/antlr4/DRL6Expressions.g4 | 7 ++-
.../org/drools/drl/parser/antlr4/DRLLexer.g4 | 10 ++-
.../org/drools/drl/parser/antlr4/DRLParser.g4 | 21 +++++--
.../org/drools/drl/parser/antlr4/ParserHelper.java | 8 +++
5 files changed, 108 insertions(+), 11 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 cbc9686acb..c869a19062 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
@@ -39,11 +39,12 @@ import org.drools.drl.ast.descr.RuleDescr;
import org.drools.drl.ast.descr.TypeDeclarationDescr;
import org.drools.drl.ast.descr.TypeFieldDescr;
import org.drools.drl.ast.descr.WindowDeclarationDescr;
-import org.drools.drl.parser.antlr4.DRLParserWrapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.assertThat;
@@ -3538,4 +3539,74 @@ class MiscDRLParserTest {
assertThat(ruleDescr.getName()).isEqualTo("R1");
assertThat(ruleDescr.getNamespace()).isEqualTo("org.drools");
}
+
+ /**
+ * Each test input is a constraint expression covering one of the existing
DRL operators. The test is successful if the parser has
+ * no errors and the descriptor's expression string is equal to the input.
+ *
+ * @param constraint expression using an operator
+ */
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "country matches \"[a-z]*\"",
+ "country not matches \"[a-z]*\"",
+ "person memberOf $europeanDescendants",
+ "person not memberOf $europeanDescendants",
+ "countries contains \"UK\"",
+ "countries not contains \"UK\"",
+ "countries excludes \"UK\"",
+ "countries not excludes \"UK\"",
+ "firstName soundslike \"John\"",
+ "firstName not soundslike \"John\"",
+ "routingValue str[startsWith] \"R1\"",
+ "routingValue not str[startsWith] \"R1\""
+ })
+ void constraintOperators(String constraint) {
+ final String text = "package org.drools\n" +
+ "rule R1\n" +
+ "when\n" +
+ " $p : Person(" + constraint + ")\n" +
+ "then\n" +
+ "end\n";
+
+ PackageDescr packageDescr = parser.parse(text);
+
+ RuleDescr ruleDescr = packageDescr.getRules().get(0);
+ AndDescr lhs = ruleDescr.getLhs();
+ PatternDescr patternDescr = (PatternDescr) lhs.getDescrs().get(0);
+ ExprConstraintDescr exprConstraintDescr = (ExprConstraintDescr)
patternDescr.getConstraint().getDescrs().get(0);
+
assertThat(exprConstraintDescr.getExpression()).isEqualToIgnoringWhitespace(constraint);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ "country matches \"[a-z]*\" || matches \"[A-Z]*\"",
+ "country not matches \"[a-z]*\" || not matches \"[A-Z]*\"",
+ "person memberOf $europeanDescendants || memberOf
$africanDescendants",
+ "person not memberOf $europeanDescendants || not memberOf
$africanDescendants",
+ "countries contains \"UK\" || contains \"US\"",
+ "countries not contains \"UK\" || not contains \"US\"",
+ "countries excludes \"UK\" || excludes \"US\"",
+ "countries not excludes \"UK\" || not excludes \"US\"",
+ "firstName soundslike \"John\" || soundslike \"Paul\"",
+ "firstName not soundslike \"John\" && not soundslike \"Paul\"",
+ "routingValue str[startsWith] \"R1\" || str[startsWith] \"R2\"",
+ "routingValue not str[startsWith] \"R1\" && not str[startsWith]
\"R2\""
+ })
+ void halfConstraintOperators(String constraint) {
+ final String text = "package org.drools\n" +
+ "rule R1\n" +
+ "when\n" +
+ " $p : Person(" + constraint + ")\n" +
+ "then\n" +
+ "end\n";
+
+ PackageDescr packageDescr = parser.parse(text);
+
+ RuleDescr ruleDescr = packageDescr.getRules().get(0);
+ AndDescr lhs = ruleDescr.getLhs();
+ PatternDescr patternDescr = (PatternDescr) lhs.getDescrs().get(0);
+ ExprConstraintDescr exprConstraintDescr = (ExprConstraintDescr)
patternDescr.getConstraint().getDescrs().get(0);
+
assertThat(exprConstraintDescr.getExpression()).isEqualToIgnoringWhitespace(constraint);
+ }
}
diff --git
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRL6Expressions.g4
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRL6Expressions.g4
index 2b4a62e913..51ea965a0f 100644
---
a/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRL6Expressions.g4
+++
b/drools-drl/drools-drl-parser/src/main/antlr4/org/drools/drl/parser/antlr4/DRL6Expressions.g4
@@ -838,10 +838,11 @@ in_key
;
operator_key
- // TODO get rid of the DRL_MATCHES token or introduce DRL_CONTAINS etc. for
consistency.
- : {(helper.isPluggableEvaluator(false))}? id=(IDENTIFIER|DRL_MATCHES) {
helper.emit($id, DroolsEditorType.KEYWORD); }
+ // At the moment, we list possible DRLLexer tokens here, but we may be able
to improve this by isolating lexers. IDENTIFIER is required to accept custom
operators
+ // We need to keep this semantic predicate for custom operators
+ : {(helper.isPluggableEvaluator(false))}?
id=(IDENTIFIER|DRL_MATCHES|DRL_MEMBEROF|DRL_CONTAINS|DRL_EXCLUDES|DRL_SOUNDSLIKE|DRL_STR)
{ helper.emit($id, DroolsEditorType.KEYWORD); }
;
neg_operator_key
- : {(helper.isPluggableEvaluator(true))}? id=IDENTIFIER {
helper.emit($id, DroolsEditorType.KEYWORD); }
+ : {(helper.isPluggableEvaluator(true))}?
id=(IDENTIFIER|DRL_MATCHES|DRL_MEMBEROF|DRL_CONTAINS|DRL_EXCLUDES|DRL_SOUNDSLIKE|DRL_STR)
{ helper.emit($id, DroolsEditorType.KEYWORD); }
;
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 a54ee07fda..79c439586f 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
@@ -45,8 +45,6 @@ DRL_NOT : 'not';
DRL_IN : 'in';
DRL_FROM : 'from';
DRL_COLLECT : 'collect';
-DRL_MATCHES : 'matches';
-DRL_MEMBEROF : 'memberOf';
DRL_ACCUMULATE : 'accumulate';
DRL_ACC : 'acc';
DRL_INIT : 'init';
@@ -58,6 +56,14 @@ DRL_EVAL : 'eval';
DRL_FORALL : 'forall';
DRL_OVER : 'over';
+// constraint operators
+DRL_MATCHES : 'matches';
+DRL_MEMBEROF : 'memberOf';
+DRL_CONTAINS : 'contains';
+DRL_EXCLUDES : 'excludes';
+DRL_SOUNDSLIKE : 'soundslike';
+DRL_STR : 'str';
+
// temporal operators
DRL_AFTER : 'after';
DRL_BEFORE : 'before';
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 5ae8c9016b..d65c9e2b73 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
@@ -129,6 +129,8 @@ positionalConstraints : constraint (COMMA constraint)* SEMI
;
constraints : constraint (COMMA constraint)* ;
constraint : ( nestedConstraint | conditionalOrExpression ) ;
nestedConstraint : ( IDENTIFIER ( DOT | HASH ) )* IDENTIFIER DOT LPAREN
constraints RPAREN ;
+
+// TBD: constraint parsing could be delegated to DRL6ExpressionParser
conditionalOrExpression : left=conditionalAndExpression (OR
right=conditionalAndExpression)* ;
conditionalAndExpression : left=inclusiveOrExpression (AND
right=inclusiveOrExpression)* ;
inclusiveOrExpression : left=exclusiveOrExpression (BITOR
right=exclusiveOrExpression)* ;
@@ -149,9 +151,18 @@ relationalOperator
| GE
| GT
| LT
+ | drlRelationalOperator
| temporalOperator
;
+drlRelationalOperator
+ : DRL_NOT? DRL_MATCHES
+ | DRL_NOT? DRL_MEMBEROF
+ | DRL_NOT? DRL_CONTAINS
+ | DRL_NOT? DRL_EXCLUDES
+ | DRL_NOT? DRL_SOUNDSLIKE
+ | DRL_NOT? DRL_STR LBRACK IDENTIFIER RBRACK ;
+
/* function := FUNCTION type? ID parameters(typed) chunk_{_} */
functiondef : DRL_FUNCTION typeTypeOrVoid? IDENTIFIER formalParameters block ;
@@ -200,6 +211,10 @@ drlKeywords
| DRL_FROM
| DRL_MATCHES
| DRL_MEMBEROF
+ | DRL_CONTAINS
+ | DRL_EXCLUDES
+ | DRL_SOUNDSLIKE
+ | DRL_STR
| DRL_ACCUMULATE
| DRL_ACC
| DRL_INIT
@@ -249,13 +264,9 @@ drlExpression
| drlExpression bop=(MUL|DIV|MOD) drlExpression
| drlExpression bop=(ADD|SUB) drlExpression
| drlExpression (LT LT | GT GT GT | GT GT) drlExpression
- | drlExpression bop=(LE | GE | GT | LT) drlExpression
- | drlExpression temporalOperator drlExpression
| drlExpression bop=INSTANCEOF (typeType | pattern)
- | drlExpression bop=DRL_MATCHES drlExpression
- | drlExpression DRL_NOT? DRL_MEMBEROF drlExpression
+ | drlExpression relationalOperator drlExpression
| drlExpression bop=DRL_UNIFY drlExpression
- | drlExpression bop=(EQUAL | NOTEQUAL) drlExpression
| drlExpression bop=BITAND drlExpression
| drlExpression bop=CARET drlExpression
| drlExpression bop=BITOR drlExpression
diff --git
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
index 82d40b6302..1d533e3c51 100644
---
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
+++
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserHelper.java
@@ -231,6 +231,14 @@ public class ParserHelper {
return text2Validate != null &&
DroolsSoftKeywords.isOperator(text2Validate, negated);
}
+ /**
+ * Check if the next token is a registered operator.
+ * The registry is dynamic, so we can add custom operators dynamically.
+ * @see org.drools.drl.parser.impl.Operator#addOperatorToRegistry(String,
boolean)
+ *
+ * @param negated true if the operator needs to support negation
+ * @return true if the next token is a registered operator
+ */
public boolean isPluggableEvaluator( boolean negated ) {
return isPluggableEvaluator( 1,
negated );
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]