This is an automated email from the ASF dual-hosted git repository.
tkobayas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new 2c350fd929 Precompile regex pattern for 'matches' operator and make it
part of the lambda predicate class (#6469)
2c350fd929 is described below
commit 2c350fd929325e56e6131cf85b329c1e06ede234
Author: Dima Solomonov <[email protected]>
AuthorDate: Tue Oct 7 07:14:57 2025 +0300
Precompile regex pattern for 'matches' operator and make it part of the
lambda predicate class (#6469)
* Precompile regex pattern for 'matches' operator and make it part of the
lambda predicate class
* respect dynamic regex expressions on which case fallback to the original
path: D.eval lambda content with MatchesOperator implementation
* respect more cases like negative checks, explicit cast when invoking
matches, etc...
* addressing PR comments
---------
Co-authored-by: dima.solomonov <[email protected]>
---
.../java/org/drools/model/functions/Operator.java | 6 +-
.../generator/expressiontyper/ExpressionTyper.java | 8 +-
.../generator/operatorspec/NativeOperatorSpec.java | 6 +-
.../generator/operatorspec/RegexOperatorSpec.java | 108 +++++++++++++++++++++
.../lambdareplace/MaterializedLambdaPredicate.java | 38 ++++++--
.../execmodel/generator/ExpressionTyperTest.java | 20 ++--
.../model/codegen/project/RuleCodegenTest.java | 16 +++
.../resources/org/drools/simple/cep/cep-regex.drl | 28 ++++++
.../org/drools/mvel/parser/ast/expr/RegexExpr.java | 68 +++++++++++++
9 files changed, 274 insertions(+), 24 deletions(-)
diff --git
a/drools-model/drools-canonical-model/src/main/java/org/drools/model/functions/Operator.java
b/drools-model/drools-canonical-model/src/main/java/org/drools/model/functions/Operator.java
index b0b534f86f..ad30403ccd 100644
---
a/drools-model/drools-canonical-model/src/main/java/org/drools/model/functions/Operator.java
+++
b/drools-model/drools-canonical-model/src/main/java/org/drools/model/functions/Operator.java
@@ -61,7 +61,7 @@ public interface Operator<A, B> extends Predicate2<A, B[]> {
String getOperatorName();
class Register {
- private static final Map<String, Operator> opMap = new HashMap<>();
+ private static final Map<String, Operator<?, ?>> opMap = new
HashMap<>();
static {
register( InOperator.INSTANCE );
@@ -75,7 +75,7 @@ public interface Operator<A, B> extends Predicate2<A, B[]> {
register( StringLengthWithOperator.INSTANCE );
}
- public static void register(Operator operator) {
+ public static void register(Operator<?, ?> operator) {
opMap.put( operator.getOperatorName(), operator);
}
@@ -83,7 +83,7 @@ public interface Operator<A, B> extends Predicate2<A, B[]> {
return opMap.containsKey( opName );
}
- public static Operator getOperator(String opName) {
+ public static Operator<?, ?> getOperator(String opName) {
return opMap.get( opName );
}
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
index ddfd916f29..b6d7a175eb 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java
@@ -75,6 +75,7 @@ import
org.drools.model.codegen.execmodel.generator.UnificationTypedExpression;
import
org.drools.model.codegen.execmodel.generator.drlxparse.NumberAndStringArithmeticOperationCoercion;
import
org.drools.model.codegen.execmodel.generator.operatorspec.NativeOperatorSpec;
import org.drools.model.codegen.execmodel.generator.operatorspec.OperatorSpec;
+import
org.drools.model.codegen.execmodel.generator.operatorspec.RegexOperatorSpec;
import
org.drools.model.codegen.execmodel.generator.operatorspec.TemporalOperatorSpec;
import org.drools.mvel.parser.ast.expr.DrlNameExpr;
import org.drools.mvel.parser.ast.expr.FullyQualifiedInlineCastExpr;
@@ -480,6 +481,9 @@ public class ExpressionTyper {
if (ModelGenerator.temporalOperators.contains(operator )) {
return TemporalOperatorSpec.INSTANCE;
}
+ if ("matches".equals(operator)) {
+ return RegexOperatorSpec.INSTANCE;
+ }
if ( org.drools.model.functions.Operator.Register.hasOperator(
operator ) ) {
return NativeOperatorSpec.INSTANCE;
}
@@ -801,11 +805,11 @@ public class ExpressionTyper {
private TypedExpressionCursor binaryExpr(BinaryExpr binaryExpr) {
TypedExpressionResult left = toTypedExpression(binaryExpr.getLeft());
TypedExpression leftTypedExpression = left.getTypedExpression()
- .orElseThrow(() -> new
NoSuchElementException("TypedExpressionResult doesn't contain
TypedExpression!"));
+ .orElseThrow(() -> new
NoSuchElementException("TypedExpressionResult doesn't contain
TypedExpression!"));
binaryExpr.setLeft(leftTypedExpression.getExpression());
TypedExpressionResult right = toTypedExpression(binaryExpr.getRight());
TypedExpression rightTypedExpression = right.getTypedExpression()
- .orElseThrow(() -> new
NoSuchElementException("TypedExpressionResult doesn't contain
TypedExpression!"));
+ .orElseThrow(() -> new
NoSuchElementException("TypedExpressionResult doesn't contain
TypedExpression!"));
binaryExpr.setRight(rightTypedExpression.getExpression());
if
(shouldConvertArithmeticBinaryToMethodCall(binaryExpr.getOperator(),
leftTypedExpression.getType(), rightTypedExpression.getType())) {
Expression compiledExpression =
convertArithmeticBinaryToMethodCall(binaryExpr,
leftTypedExpression.getOriginalPatternType(), ruleContext);
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/NativeOperatorSpec.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/NativeOperatorSpec.java
index 7d77bbb9bd..89663ece09 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/NativeOperatorSpec.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/NativeOperatorSpec.java
@@ -45,7 +45,7 @@ public class NativeOperatorSpec implements OperatorSpec {
MethodCallExpr methodCallExpr = createDslTopLevelMethod( EVAL_CALL );
String opName = pointFreeExpr.getOperator().asString();
- Operator operator = addOperatorArgument( context, methodCallExpr,
opName );
+ Operator<?, ?> operator = addOperatorArgument( context,
methodCallExpr, opName );
if (operator != null && !operator.isCompatibleWithType(
left.getRawClass() )) {
context.addCompilationError( new InvalidExpressionErrorResult(
"Cannot use contains on class " + left.getRawClass() + " in expression '" +
PrintUtil.printNode(pointFreeExpr) + "'" ) );
}
@@ -72,8 +72,8 @@ public class NativeOperatorSpec implements OperatorSpec {
methodCallExpr;
}
- protected Operator addOperatorArgument( RuleContext context,
MethodCallExpr methodCallExpr, String opName ) {
- Operator operator = Operator.Register.getOperator( opName );
+ protected Operator<?, ?> addOperatorArgument( RuleContext context,
MethodCallExpr methodCallExpr, String opName ) {
+ Operator<?, ?> operator = Operator.Register.getOperator( opName );
try {
// if the operator has an INSTANCE field avoid the operator lookup
at runtime
operator.getClass().getField( "INSTANCE" );
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/RegexOperatorSpec.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/RegexOperatorSpec.java
new file mode 100644
index 0000000000..f7f6731122
--- /dev/null
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/operatorspec/RegexOperatorSpec.java
@@ -0,0 +1,108 @@
+/*
+ * 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.model.codegen.execmodel.generator.operatorspec;
+
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.body.FieldDeclaration;
+import com.github.javaparser.ast.body.VariableDeclarator;
+import com.github.javaparser.ast.expr.EnclosedExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.NameExpr;
+import com.github.javaparser.ast.expr.CastExpr;
+import com.github.javaparser.ast.expr.BinaryExpr;
+import com.github.javaparser.ast.expr.NullLiteralExpr;
+import com.github.javaparser.ast.expr.UnaryExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import org.drools.model.codegen.execmodel.generator.RuleContext;
+import org.drools.model.codegen.execmodel.generator.TypedExpression;
+import
org.drools.model.codegen.execmodel.generator.expressiontyper.ExpressionTyper;
+import org.drools.mvel.parser.ast.expr.PointFreeExpr;
+import org.drools.mvel.parser.ast.expr.RegexExpr;
+
+import java.util.regex.Pattern;
+
+import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
+import static org.drools.util.StringUtils.md5Hash;
+
+public class RegexOperatorSpec extends NativeOperatorSpec {
+ public static final RegexOperatorSpec INSTANCE = new RegexOperatorSpec();
+
+ public Expression getExpression(RuleContext context, PointFreeExpr
pointFreeExpr, TypedExpression left, ExpressionTyper expressionTyper) {
+ if (canPrecompileRegex(pointFreeExpr.getRight())) {
+ Expression regexExpression = pointFreeExpr.getRight().getFirst()
+ .orElseThrow(() -> new IllegalStateException("Failed to
parse regex expression"));
+
+ NameExpr regexFieldName = new NameExpr("regexp_" +
md5Hash(regexExpression.toString()));
+
+ return new RegexExpr(
+ getClassMemberFieldDeclaration(regexFieldName,
regexExpression),
+ getClassMemberInvocationExpression(pointFreeExpr, left,
regexFieldName)
+ );
+ } else {
+ return super.getExpression(context, pointFreeExpr, left,
expressionTyper);
+ }
+ }
+
+ private EnclosedExpr getClassMemberInvocationExpression(PointFreeExpr
pointFreeExpr, TypedExpression left, NameExpr regexFieldName) {
+ // we need to cast the left expression to CharSequence, otherwise it
might fail in cases of missing type safety
+ // e.g. test method parameters (_this) is of a raw type Map
+ EnclosedExpr typeSafeStringToMatch = new EnclosedExpr(new
CastExpr(toClassOrInterfaceType(CharSequence.class), left.getExpression()));
+
+ MethodCallExpr matchesCallExpr = new MethodCallExpr(
+ new MethodCallExpr(regexFieldName, "matcher",
NodeList.nodeList(typeSafeStringToMatch)),
+ "matches"
+ );
+
+ // null string should not match
+ BinaryExpr compoundRegexCallExpr = new BinaryExpr(
+ new BinaryExpr(left.getExpression(), new NullLiteralExpr(),
BinaryExpr.Operator.NOT_EQUALS),
+ pointFreeExpr.isNegated() ? new UnaryExpr(matchesCallExpr,
UnaryExpr.Operator.LOGICAL_COMPLEMENT) : matchesCallExpr,
+ BinaryExpr.Operator.AND
+ );
+
+ return new EnclosedExpr(compoundRegexCallExpr);
+ }
+
+ private FieldDeclaration getClassMemberFieldDeclaration(NameExpr
regexFieldName, Expression regexExpression) {
+
+ MethodCallExpr compiledRegexField = new MethodCallExpr(
+ new NameExpr(Pattern.class.getName()), "compile",
NodeList.nodeList(regexExpression)
+ );
+
+ VariableDeclarator variableDeclarator = new VariableDeclarator(
+ toClassOrInterfaceType(Pattern.class),
+ regexFieldName.getName(),
+ compiledRegexField
+ );
+
+ return new FieldDeclaration(
+ NodeList.nodeList(Modifier.privateModifier(),
Modifier.staticModifier(), Modifier.finalModifier()),
+ variableDeclarator
+ );
+ }
+
+ private boolean canPrecompileRegex(NodeList<Expression>
regexPatternExpression) {
+ return regexPatternExpression.size() == 1 &&
+ regexPatternExpression.getFirst()
+ .filter(StringLiteralExpr.class::isInstance)
+ .isPresent();
+ }
+}
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/util/lambdareplace/MaterializedLambdaPredicate.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/util/lambdareplace/MaterializedLambdaPredicate.java
index 0b3aa5fee9..dfa6175e3e 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/util/lambdareplace/MaterializedLambdaPredicate.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/util/lambdareplace/MaterializedLambdaPredicate.java
@@ -19,16 +19,11 @@
package org.drools.model.codegen.execmodel.util.lambdareplace;
import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
-import com.github.javaparser.ast.expr.AssignExpr;
-import com.github.javaparser.ast.expr.BooleanLiteralExpr;
-import com.github.javaparser.ast.expr.Expression;
-import com.github.javaparser.ast.expr.MethodCallExpr;
-import com.github.javaparser.ast.expr.NameExpr;
-import com.github.javaparser.ast.expr.ObjectCreationExpr;
-import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
@@ -36,10 +31,12 @@ import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.PrimitiveType;
import com.github.javaparser.utils.StringEscapeUtils;
import org.drools.model.functions.PredicateInformation;
+import org.drools.mvel.parser.ast.expr.RegexExpr;
-import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.createSimpleAnnotation;
-import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toClassOrInterfaceType;
-import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.toStringLiteral;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.drools.model.codegen.execmodel.generator.DrlxParseUtil.*;
public class MaterializedLambdaPredicate extends MaterializedLambda {
@@ -65,6 +62,11 @@ public class MaterializedLambdaPredicate extends
MaterializedLambda {
}
private void createTestMethod(EnumDeclaration classDeclaration) {
+ collectRegexExpressions(lambdaExpr).stream()
+ .map(RegexExpr::getCompiledRegexMember)
+ .distinct()
+ .forEach(classDeclaration::addMember);
+
MethodDeclaration methodDeclaration =
classDeclaration.addMethod("test", Modifier.Keyword.PUBLIC);
methodDeclaration.setThrownExceptions(NodeList.nodeList(toClassOrInterfaceType(java.lang.Exception.class)));
methodDeclaration.addAnnotation(createSimpleAnnotation("Override"));
@@ -76,6 +78,22 @@ public class MaterializedLambdaPredicate extends
MaterializedLambda {
methodDeclaration.setBody(new BlockStmt(NodeList.nodeList(new
ReturnStmt(clone.getExpression()))));
}
+ /**
+ * recursively traverse the node tree and collect all RegexExpr
+ * @param node
+ * @return
+ */
+ private Collection<RegexExpr> collectRegexExpressions(Node node) {
+ if (node instanceof RegexExpr) {
+ return Collections.singletonList((RegexExpr) node);
+ } else {
+ return node.getChildNodes().stream()
+ .map(this::collectRegexExpressions)
+ .flatMap(Collection::stream)
+ .toList();
+ }
+ }
+
private void createPredicateInformationMethod(EnumDeclaration
classDeclaration) {
MethodDeclaration methodDeclaration =
classDeclaration.addMethod("predicateInformation", Modifier.Keyword.PUBLIC);
methodDeclaration.addAnnotation("Override");
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
index fea155e03b..f1595a6c1e 100644
---
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/generator/ExpressionTyperTest.java
@@ -60,16 +60,15 @@ import static
org.drools.model.codegen.execmodel.generator.DrlxParseUtil.THIS_PL
public class ExpressionTyperTest {
private HashSet<String> imports;
- private PackageModel packageModel;
private TypeResolver typeResolver;
private RuleContext ruleContext;
- private KnowledgeBuilderImpl knowledgeBuilder = new KnowledgeBuilderImpl();
- private RuleDescr ruleDescr = new RuleDescr("testRule");
+ private final KnowledgeBuilderImpl knowledgeBuilder = new
KnowledgeBuilderImpl();
+ private final RuleDescr ruleDescr = new RuleDescr("testRule");
@BeforeEach
public void setUp() throws Exception {
imports = new HashSet<>();
- packageModel = new PackageModel("", "", null, null, new
DRLIdGenerator());
+ PackageModel packageModel = new PackageModel("", "", null, null, new
DRLIdGenerator());
typeResolver = new ClassTypeResolver(imports,
getClass().getClassLoader());
ruleContext = new RuleContext(knowledgeBuilder, knowledgeBuilder,
packageModel, typeResolver, ruleDescr);
imports.add(Person.class.getCanonicalName());
@@ -107,11 +106,20 @@ public class ExpressionTyperTest {
}
@Test
- public void pointFreeTest() {
+ public void pointFreeForDynamicRegexMatchesOperatorTest() {
+ final PointFreeExpr expression = new PointFreeExpr(null, new
NameExpr("name"), NodeList.nodeList(new MethodCallExpr("getEmail")), new
SimpleName("matches"), false, null, null, null, null);
+ TypedExpressionResult typedExpressionResult = new
ExpressionTyper(ruleContext, Person.class, null,
true).toTypedExpression(expression);
+ final TypedExpression actual =
typedExpressionResult.getTypedExpression().get();
+ final TypedExpression expected =
typedResult("D.eval(org.drools.model.operators.MatchesOperator.INSTANCE,
_this.getName(), _this.getEmail())", String.class);
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ public void pointFreeForStaticRegexMatchesOperatorTest() {
final PointFreeExpr expression = new PointFreeExpr(null, new
NameExpr("name"), NodeList.nodeList(new StringLiteralExpr("[A-Z]")), new
SimpleName("matches"), false, null, null, null, null);
TypedExpressionResult typedExpressionResult = new
ExpressionTyper(ruleContext, Person.class, null,
true).toTypedExpression(expression);
final TypedExpression actual =
typedExpressionResult.getTypedExpression().get();
- final TypedExpression expected =
typedResult("D.eval(org.drools.model.operators.MatchesOperator.INSTANCE,
_this.getName(), \"[A-Z]\")", String.class);
+ final TypedExpression expected = typedResult("(_this.getName() != null
&& regexp_49CE5AB50F4FBCBE25DB1AF1EC5CACE2.matcher(((java.lang.CharSequence)
_this.getName())).matches())", String.class);
assertThat(actual).isEqualTo(expected);
}
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/project/RuleCodegenTest.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/project/RuleCodegenTest.java
index d7eb5e37b2..453b4e11de 100644
---
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/project/RuleCodegenTest.java
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/project/RuleCodegenTest.java
@@ -130,6 +130,22 @@ public class RuleCodegenTest {
assertRules(2, 1, generatedFiles.size() - externalizedLambda -
legacyApiFiles);
}
+ @ParameterizedTest
+
@MethodSource("org.drools.model.codegen.project.RuleCodegenTest#contextBuilders")
+ public void generateCepRegexRule(DroolsModelBuildContext.Builder
contextBuilder) {
+ withLegacyApi(contextBuilder);
+
+ RuleCodegen ruleCodegen = getRuleCodegenFromFiles(
+ contextBuilder,
+ new File(RESOURCE_PATH +
"/org/drools/simple/cep/cep-regex.drl"));
+
+ Collection<GeneratedFile> generatedFiles =
ruleCodegen.withHotReloadMode().generate();
+ assertHasLegacyApiFiles(generatedFiles);
+ int externalizedLambda = 2;
+ int legacyApiFiles = 2;
+ assertRules(2, 1, generatedFiles.size() - externalizedLambda -
legacyApiFiles);
+ }
+
@ParameterizedTest
@MethodSource("org.drools.model.codegen.project.RuleCodegenTest#contextBuilders")
public void generateCepRule(DroolsModelBuildContext.Builder
contextBuilder) {
diff --git
a/drools-model/drools-model-codegen/src/test/resources/org/drools/simple/cep/cep-regex.drl
b/drools-model/drools-model-codegen/src/test/resources/org/drools/simple/cep/cep-regex.drl
new file mode 100644
index 0000000000..4a7dfd62ad
--- /dev/null
+++
b/drools-model/drools-model-codegen/src/test/resources/org/drools/simple/cep/cep-regex.drl
@@ -0,0 +1,28 @@
+/**
+ * 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.simple.cep
+
+import org.drools.model.codegen.project.data.Person
+
+declare Person @role(event) end
+
+rule IsTest when
+ Person( name matches "tst1", name matches "tst2" || matches "tst3" )
+then
+end
diff --git
a/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/expr/RegexExpr.java
b/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/expr/RegexExpr.java
new file mode 100644
index 0000000000..9abc474479
--- /dev/null
+++
b/drools-model/drools-mvel-parser/src/main/java/org/drools/mvel/parser/ast/expr/RegexExpr.java
@@ -0,0 +1,68 @@
+/*
+ * 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.mvel.parser.ast.expr;
+
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.FieldDeclaration;
+import com.github.javaparser.ast.expr.EnclosedExpr;
+import com.github.javaparser.ast.expr.LiteralExpr;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+
+public final class RegexExpr extends LiteralExpr {
+
+ private final FieldDeclaration compiledRegexMember;
+ private final EnclosedExpr matchesEvaluationExpr;
+
+ @AllFieldsConstructor
+ public RegexExpr(FieldDeclaration compiledRegexMember, EnclosedExpr
matchesEvaluationExpr) {
+ super();
+
+ this.compiledRegexMember = compiledRegexMember;
+ this.matchesEvaluationExpr = matchesEvaluationExpr;
+ }
+
+ @Override
+ public <R, A> R accept(GenericVisitor<R, A> v, A arg) {
+ if (v instanceof CloneVisitor) {
+ return (R) new RegexExpr(compiledRegexMember.clone(),
matchesEvaluationExpr.clone());
+ } else {
+ return v.visit(matchesEvaluationExpr, arg);
+ }
+ }
+
+ @Override
+ public <A> void accept(VoidVisitor<A> v, A arg) {
+ v.visit(matchesEvaluationExpr, arg);
+ }
+
+ @Override
+ public boolean remove(Node node) {
+ if (node == null) {
+ return false;
+ }
+ return super.remove(node);
+ }
+
+ public FieldDeclaration getCompiledRegexMember() {
+ return compiledRegexMember;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]