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 5f83f08f16 [incubator-kie-drools#5706] Grouped accessors for nested
objects broken (#5790)
5f83f08f16 is described below
commit 5f83f08f169c0c4922e7bd842ae612c607f96dc8
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Tue Mar 19 11:39:52 2024 +0900
[incubator-kie-drools#5706] Grouped accessors for nested objects broken
(#5790)
* [incubator-kie-drools#5706] Grouped accessors for nested objects broken
* Update
drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/DRLVisitorImpl.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]>
---------
Co-authored-by: Jiří Locker <[email protected]>
---
.../drl/parser/antlr4/MiscDRLParserTest.java | 34 ++++++++++
.../org/drools/drl/parser/antlr4/DRLParser.g4 | 2 +-
...ringUtils.java => Antlr4ParserStringUtils.java} | 8 +--
.../drools/drl/parser/antlr4/DRLVisitorImpl.java | 47 +++++++++++---
.../org/drools/drl/parser/lang/DRL6Parser.java | 41 +-----------
.../drools/drl/parser/util/ParserStringUtils.java | 74 ++++++++++++++++++++++
.../drl/parser/util/ParserStringUtilsTest.java | 66 +++++++++++++++++++
7 files changed, 220 insertions(+), 52 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 0b394bbdd3..9e2d4f9d5b 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
@@ -3654,4 +3654,38 @@ class MiscDRLParserTest {
ExprConstraintDescr constraintDescr = (ExprConstraintDescr)
patternDescr.getConstraint().getDescrs().get(0);
assertThat(constraintDescr.toString()).isEqualToIgnoringWhitespace("$containsL
: address!.city.contains(\"L\")");
}
+
+ @Test
+ void groupedConstraints() {
+ final String text = "package org.drools\n" +
+ "rule R1\n" +
+ "when\n" +
+ " $p : Person( address.(city.startsWith(\"I\") &&
city.length() == 5 ) )\n" +
+ "then\n" +
+ "end\n";
+ PackageDescr packageDescr = parser.parse(text);
+ RuleDescr ruleDescr = packageDescr.getRules().get(0);
+ PatternDescr patternDescr = (PatternDescr)
ruleDescr.getLhs().getDescrs().get(0);
+ ExprConstraintDescr constraintDescr = (ExprConstraintDescr)
patternDescr.getConstraint().getDescrs().get(0);
+ assertThat(constraintDescr.toString())
+ .as("prefix should be appended to each element")
+ .isEqualToIgnoringWhitespace("address.city.startsWith(\"I\")
&& address.city.length() == 5");
+ }
+
+ @Test
+ void groupedConstraintsWithNullSafeDereferencing() {
+ final String text = "package org.drools\n" +
+ "rule R1\n" +
+ "when\n" +
+ " $p : Person( address!.(city!.startsWith(\"I\") &&
city!.length() == 5 ) )\n" +
+ "then\n" +
+ "end\n";
+ PackageDescr packageDescr = parser.parse(text);
+ RuleDescr ruleDescr = packageDescr.getRules().get(0);
+ PatternDescr patternDescr = (PatternDescr)
ruleDescr.getLhs().getDescrs().get(0);
+ ExprConstraintDescr constraintDescr = (ExprConstraintDescr)
patternDescr.getConstraint().getDescrs().get(0);
+ assertThat(constraintDescr.toString())
+ .as("prefix should be appended to each element")
+ .isEqualToIgnoringWhitespace("address!.city!.startsWith(\"I\")
&& address!.city!.length() == 5");
+ }
}
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 c358c66309..7523592f98 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
@@ -128,7 +128,7 @@ lhsPattern : QUESTION? objectType=drlQualifiedName LPAREN
positionalConstraints?
positionalConstraints : constraint (COMMA constraint)* SEMI ;
constraints : constraint (COMMA constraint)* ;
constraint : ( nestedConstraint | conditionalOrExpression ) ;
-nestedConstraint : ( IDENTIFIER ( DOT | HASH ) )* IDENTIFIER DOT LPAREN
constraints RPAREN ;
+nestedConstraint : ( IDENTIFIER ( DOT | NULL_SAFE_DOT | HASH ) )* IDENTIFIER
(DOT | NULL_SAFE_DOT ) LPAREN constraints RPAREN ;
// TBD: constraint parsing could be delegated to DRL6ExpressionParser
conditionalOrExpression : left=conditionalAndExpression (OR
right=conditionalAndExpression)* ;
diff --git
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserStringUtils.java
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
similarity index 93%
rename from
drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserStringUtils.java
rename to
drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
index 22ea2a7fa6..8c874cc3c1 100644
---
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/ParserStringUtils.java
+++
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/antlr4/Antlr4ParserStringUtils.java
@@ -23,12 +23,12 @@ import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.misc.Interval;
/**
- * Collection of String utilities used by DRLParser.
- * This may be merged in drools-util
+ * Collection of String utilities used by antlr4 DRLParser.
*/
-public class ParserStringUtils {
+public class Antlr4ParserStringUtils {
- private ParserStringUtils() {
+ private Antlr4ParserStringUtils() {
+ // Private constructor to prevent instantiation.
}
/**
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 c37284fa51..487a09c3ea 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.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.RuleNode;
@@ -59,10 +60,11 @@ import org.drools.drl.ast.descr.UnitDescr;
import org.drools.drl.ast.descr.WindowDeclarationDescr;
import static
org.drools.drl.parser.antlr4.DRLParserHelper.getTextWithoutErrorNode;
-import static
org.drools.drl.parser.antlr4.ParserStringUtils.getTextPreservingWhitespace;
-import static
org.drools.drl.parser.antlr4.ParserStringUtils.getTokenTextPreservingWhitespace;
-import static
org.drools.drl.parser.antlr4.ParserStringUtils.safeStripStringDelimiters;
-import static org.drools.drl.parser.antlr4.ParserStringUtils.trimThen;
+import static
org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.getTextPreservingWhitespace;
+import static
org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.getTokenTextPreservingWhitespace;
+import static
org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.safeStripStringDelimiters;
+import static org.drools.drl.parser.antlr4.Antlr4ParserStringUtils.trimThen;
+import static org.drools.drl.parser.util.ParserStringUtils.appendPrefix;
import static org.drools.util.StringUtils.unescapeJava;
/**
@@ -533,7 +535,7 @@ public class DRLVisitorImpl extends
DRLParserBaseVisitor<Object> {
behaviorDescr.setType(ctx.DRL_WINDOW().getText());
behaviorDescr.setSubType(ctx.IDENTIFIER().getText());
List<DRLParser.DrlExpressionContext> drlExpressionContexts =
ctx.expressionList().drlExpression();
- List<String> parameters =
drlExpressionContexts.stream().map(ParserStringUtils::getTextPreservingWhitespace).collect(Collectors.toList());
+ List<String> parameters =
drlExpressionContexts.stream().map(Antlr4ParserStringUtils::getTextPreservingWhitespace).collect(Collectors.toList());
behaviorDescr.setParameters(parameters);
return behaviorDescr;
}
@@ -620,17 +622,42 @@ public class DRLVisitorImpl extends
DRLParserBaseVisitor<Object> {
}
/**
- * Takes one constraint as String and create ExprConstraintDescr
+ * Takes one constraint as String and create ExprConstraintDescr.
+ * In case of nested constraint, it could be multiple ExprConstraintDescr
objects.
*/
@Override
- public ExprConstraintDescr visitConstraint(DRLParser.ConstraintContext
ctx) {
+ public List<ExprConstraintDescr>
visitConstraint(DRLParser.ConstraintContext ctx) {
+ List<ExprConstraintDescr> descrList = new ArrayList<>();
+ if (ctx.nestedConstraint() != null) {
+ // nested constraint requires special string manipulation
+ return visitNestedConstraint(ctx.nestedConstraint());
+ }
+ // get a simple constraint as String
String constraint = visitConstraintChildren(ctx);
if (!constraint.isEmpty()) {
ExprConstraintDescr constraintDescr = new
ExprConstraintDescr(constraint);
constraintDescr.setType(ExprConstraintDescr.Type.NAMED);
- return constraintDescr;
+ descrList.add(constraintDescr);
+ return descrList;
}
- return null;
+ return descrList;
+ }
+
+ /**
+ * Append a prefix to nested constraints.
+ * For example,
+ * address.(city.startsWith("I"), city.length() == 5)
+ * becomes
+ * address.city.startsWith("I"), address.city.length() == 5
+ */
+ @Override
+ public List<ExprConstraintDescr>
visitNestedConstraint(DRLParser.NestedConstraintContext ctx) {
+ Token prefixStartToken = ctx.start;
+ Token prefixEndToken =
tokenStream.get(ctx.LPAREN().getSymbol().getTokenIndex() - 1);
+ String prefix = tokenStream.getText(prefixStartToken, prefixEndToken);
+ List<ExprConstraintDescr> exprConstraintDescr =
visitConstraints(ctx.constraints());
+ exprConstraintDescr.forEach(d -> d.setText(appendPrefix(prefix,
d.getText())));
+ return exprConstraintDescr;
}
@Override
@@ -797,6 +824,8 @@ public class DRLVisitorImpl extends
DRLParserBaseVisitor<Object> {
Object childResult = c.accept(this);
if (childResult instanceof BaseDescr) {
aggregator.add((BaseDescr) childResult);
+ } else if (childResult instanceof List) {
+ aggregator.addAll((List<BaseDescr>) childResult);
}
}
return aggregator;
diff --git
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/lang/DRL6Parser.java
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/lang/DRL6Parser.java
index ebfec99223..f23b7063e2 100644
---
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/lang/DRL6Parser.java
+++
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/lang/DRL6Parser.java
@@ -85,6 +85,8 @@ import org.kie.internal.builder.conf.LanguageLevelOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.drools.drl.parser.util.ParserStringUtils.appendPrefix;
+
public class DRL6Parser extends AbstractDRLParser implements DRLParser {
private static final Logger LOG =
LoggerFactory.getLogger(DRL6Parser.class);
@@ -3778,44 +3780,7 @@ public class DRL6Parser extends AbstractDRLParser
implements DRLParser {
private String toExpression(String prefix, int first, int last) {
String expr = input.toString(first, last);
- if (prefix.length() == 0) {
- return expr;
- }
- StringBuilder sb = new StringBuilder();
- toOrExpression(sb, prefix, expr);
- return sb.toString();
- }
-
- private void toOrExpression(StringBuilder sb, String prefix, String expr) {
- int start = 0;
- int end = expr.indexOf("||");
- do {
- if (start > 0) {
- sb.append(" || ");
- }
- toAndExpression(sb, prefix, end > 0 ? expr.substring(start, end) :
expr.substring(start));
- start = end + 2;
- end = expr.indexOf("||", start);
- } while (start > 1);
- }
-
- private void toAndExpression(StringBuilder sb, String prefix, String expr)
{
- int start = 0;
- int end = expr.indexOf("&&");
- do {
- if (start > 0) {
- sb.append(" && ");
- }
- sb.append(toExpression(prefix, end > 0 ? expr.substring(start,
end) : expr.substring(start)));
- start = end + 2;
- end = expr.indexOf("&&", start);
- } while (start > 1);
- }
-
- private String toExpression(String prefix, String expr) {
- expr = expr.trim();
- int colonPos = expr.indexOf(":");
- return colonPos < 0 ? prefix + expr : expr.substring(0, colonPos + 1)
+ " " + prefix + expr.substring(colonPos + 1).trim();
+ return appendPrefix(prefix, expr);
}
private boolean speculateNestedConstraint() throws RecognitionException {
diff --git
a/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/util/ParserStringUtils.java
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/util/ParserStringUtils.java
new file mode 100644
index 0000000000..bca3dca91f
--- /dev/null
+++
b/drools-drl/drools-drl-parser/src/main/java/org/drools/drl/parser/util/ParserStringUtils.java
@@ -0,0 +1,74 @@
+/**
+ * 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.
+ */
+package org.drools.drl.parser.util;
+
+/**
+ * String utilities used by DRL Parser. Not dependent on ANTLR version.
+ */
+public class ParserStringUtils {
+
+ private ParserStringUtils() {
+ // Private constructor to prevent instantiation.
+ }
+
+ /**
+ * Append a prefix to a grouped constraint.
+ * Even if the constraint contains || and/or &&, append the prefix to each
element.
+ */
+ public static String appendPrefix(String prefix, String expr) {
+ if (prefix.length() == 0) {
+ return expr;
+ }
+ StringBuilder sb = new StringBuilder();
+ appendPrefixToOrExpression(sb, prefix, expr);
+ return sb.toString();
+ }
+
+ private static void appendPrefixToOrExpression(StringBuilder sb, String
prefix, String expr) {
+ int start = 0;
+ int end = expr.indexOf("||");
+ do {
+ if (start > 0) {
+ sb.append(" || ");
+ }
+ appendPrefixToAndExpression(sb, prefix, end > 0 ?
expr.substring(start, end) : expr.substring(start));
+ start = end + 2;
+ end = expr.indexOf("||", start);
+ } while (start > 1);
+ }
+
+ private static void appendPrefixToAndExpression(StringBuilder sb, String
prefix, String expr) {
+ int start = 0;
+ int end = expr.indexOf("&&");
+ do {
+ if (start > 0) {
+ sb.append(" && ");
+ }
+ sb.append(appendPrefixToExpression(prefix, end > 0 ?
expr.substring(start, end) : expr.substring(start)));
+ start = end + 2;
+ end = expr.indexOf("&&", start);
+ } while (start > 1);
+ }
+
+ private static String appendPrefixToExpression(String prefix, String expr)
{
+ expr = expr.trim();
+ int colonPos = expr.indexOf(":");
+ return colonPos < 0 ? prefix + expr : expr.substring(0, colonPos + 1)
+ " " + prefix + expr.substring(colonPos + 1).trim();
+ }
+}
diff --git
a/drools-drl/drools-drl-parser/src/test/java/org/drools/drl/parser/util/ParserStringUtilsTest.java
b/drools-drl/drools-drl-parser/src/test/java/org/drools/drl/parser/util/ParserStringUtilsTest.java
new file mode 100644
index 0000000000..9ef0e6edd5
--- /dev/null
+++
b/drools-drl/drools-drl-parser/src/test/java/org/drools/drl/parser/util/ParserStringUtilsTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+package org.drools.drl.parser.util;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ParserStringUtilsTest {
+
+ @Test
+ public void appendPrefix() {
+ String prefix = "prefix.";
+ String expr = "a == 1";
+ String result = ParserStringUtils.appendPrefix(prefix, expr);
+ assertThat(result).isEqualToIgnoringWhitespace("prefix.a == 1");
+ }
+
+ @Test
+ public void appendPrefixWithAnd() {
+ String prefix = "prefix.";
+ String expr = "a == 1 && b.equals(\"foo\")";
+ String result = ParserStringUtils.appendPrefix(prefix, expr);
+ assertThat(result).isEqualToIgnoringWhitespace("prefix.a == 1 &&
prefix.b.equals(\"foo\")");
+ }
+
+ @Test
+ public void appendPrefixWithOr() {
+ String prefix = "prefix.";
+ String expr = "a == 1 || b.equals(\"foo\")";
+ String result = ParserStringUtils.appendPrefix(prefix, expr);
+ assertThat(result).isEqualToIgnoringWhitespace("prefix.a == 1 ||
prefix.b.equals(\"foo\")");
+ }
+
+ @Test
+ public void appendPrefixWithANDOr() {
+ String prefix = "prefix.";
+ String expr = "a == 1 && b.equals(\"foo\") || c == 2 &&
d.equals(\"bar\")";
+ String result = ParserStringUtils.appendPrefix(prefix, expr);
+ assertThat(result).isEqualToIgnoringWhitespace("prefix.a == 1 &&
prefix.b.equals(\"foo\") || prefix.c == 2 && prefix.d.equals(\"bar\")");
+ }
+
+ @Test
+ public void appendPrefixWithBindingVariable() {
+ String prefix = "prefix.";
+ String expr = "$a : a == 1 && $b : b.equals(\"foo\")";
+ String result = ParserStringUtils.appendPrefix(prefix, expr);
+ assertThat(result).isEqualToIgnoringWhitespace("$a : prefix.a == 1 &&
$b : prefix.b.equals(\"foo\")");
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]