Skip to content

Commit

Permalink
Enhance test/grammar coverage. and, or, listExpression (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
tkobayas authored and mariofusco committed Feb 14, 2024
1 parent bd18973 commit 37185cf
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 17 deletions.
6 changes: 6 additions & 0 deletions drools-drl/drools-drl10-parser/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${version.org.assertj}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ WHEN : 'when';
THEN : 'then';
END : 'end';

KWD_AND : 'and';
KWD_OR : 'or';

EXISTS : 'exists';
NOT : 'not';
IN : 'in';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ ruledef : RULE name=stringId (EXTENDS stringId)? drlAnnotation* attributes? WHEN

lhs : lhsExpression ;
lhsExpression : lhsOr* ;
lhsOr : LPAREN OR lhsAnd+ RPAREN | lhsAnd (OR lhsAnd)* ;
lhsAnd : LPAREN AND lhsUnary+ RPAREN | lhsUnary (AND lhsUnary)* ;
lhsOr : LPAREN KWD_OR lhsAnd+ RPAREN | lhsAnd (KWD_OR lhsAnd)* ;
lhsAnd : LPAREN KWD_AND lhsUnary+ RPAREN | lhsUnary (KWD_AND lhsUnary)* ;

/*
lhsUnary : ( lhsExists namedConsequence?
Expand All @@ -38,7 +38,7 @@ lhsUnary : (
| lhsNot
| lhsPatternBind
) ;
lhsPatternBind : label? ( LPAREN lhsPattern (OR lhsPattern)* RPAREN | lhsPattern ) ;
lhsPatternBind : label? ( LPAREN lhsPattern (KWD_OR lhsPattern)* RPAREN | lhsPattern ) ;

/*
lhsPattern : xpathPrimary (OVER patternFilter)? |
Expand All @@ -58,7 +58,27 @@ andExpression : left=equalityExpression (BITAND right=equalityExpression)* ;
equalityExpression : left=instanceOfExpression ( ( op=EQUAL | op=NOTEQUAL ) right=instanceOfExpression )* ;
instanceOfExpression : left=inExpression ( 'instanceof' right=type )? ;
inExpression : left=relationalExpression ( 'not'? 'in' LPAREN drlExpression (COMMA drlExpression)* RPAREN )? ;
relationalExpression : expression? ; // TODO
relationalExpression : expression? ; // TODO : shiftExpression, additiveExpression, multiplicativeExpression, unaryExpression, unaryExpressionNotPlusMinus, ..., primary

/* extending JavaParser */
primary
: LPAREN expression RPAREN
| THIS
| SUPER
| literal
| identifier
| typeTypeOrVoid DOT CLASS
| nonWildcardTypeArguments (explicitGenericInvocationSuffix | THIS arguments)
| inlineListExpression
;

inlineListExpression
: LBRACK expressionList? RBRACK
;

expressionList
: expression (COMMA expression)*
;

drlExpression : conditionalExpression ( op=assignmentOperator right=drlExpression )? ;
conditionalExpression : left=conditionalOrExpression ternaryExpression? ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

Expand All @@ -19,7 +20,8 @@ public class DRLVisitorImpl extends DRLParserBaseVisitor<Object> {

private RuleDescr currentRule;
private PatternDescr currentPattern;
private Deque<ConditionalElementDescr> currentConstructStack = new ArrayDeque<>(); // e.g. whole LHS, not, exist

private final Deque<ConditionalElementDescr> currentConstructStack = new ArrayDeque<>(); // e.g. whole LHS (= AndDescr), NotDescr, ExistsDescr

@Override
public Object visitCompilationUnit(DRLParser.CompilationUnitContext ctx) {
Expand Down Expand Up @@ -86,23 +88,47 @@ public Object visitLhs(DRLParser.LhsContext ctx) {

@Override
public Object visitLhsPatternBind(DRLParser.LhsPatternBindContext ctx) {
// TODO: this logic will likely be split to visitLhsPattern
if (ctx.lhsPattern().size() == 1) {
DRLParser.LhsPatternContext lhsPatternCtx = ctx.lhsPattern(0);
currentPattern = new PatternDescr(lhsPatternCtx.objectType.getText());
Object result = super.visitLhsPatternBind(ctx);
PatternDescr patternDescr = (PatternDescr) currentConstructStack.peek().getDescrs().get(0);
if (ctx.label() != null) {
currentPattern.setIdentifier(ctx.label().IDENTIFIER().getText());
patternDescr.setIdentifier(ctx.label().IDENTIFIER().getText());
}
if (lhsPatternCtx.patternSource() != null) {
String expression = lhsPatternCtx.patternSource().getText();
FromDescr from = new FromDescr();
from.setDataSource(new MVELExprDescr(expression));
from.setResource(currentPattern.getResource());
currentPattern.setSource(from);
return result;
} else if (ctx.lhsPattern().size() > 1) {
OrDescr orDescr = new OrDescr();
currentConstructStack.peek().addDescr(orDescr);
currentConstructStack.push(orDescr);
try {
Object result = super.visitLhsPatternBind(ctx);
List<? extends BaseDescr> descrs = orDescr.getDescrs();
for (BaseDescr descr : descrs) {
PatternDescr patternDescr = (PatternDescr) descr;
if (ctx.label() != null) {
patternDescr.setIdentifier(ctx.label().IDENTIFIER().getText());
}
}
return result;
} finally {
currentConstructStack.pop();
}
currentConstructStack.peek().addDescr(currentPattern);
} else {
throw new IllegalStateException("ctx.lhsPattern().size() == 0 : " + ctx.getText());
}
}

@Override
public Object visitLhsPattern(DRLParser.LhsPatternContext ctx) {
currentPattern = new PatternDescr(ctx.objectType.getText());
if (ctx.patternSource() != null) {
String expression = ctx.patternSource().getText();
FromDescr from = new FromDescr();
from.setDataSource(new MVELExprDescr(expression));
from.setResource(currentPattern.getResource());
currentPattern.setSource(from);
}
Object result = super.visitLhsPatternBind(ctx);
Object result = super.visitLhsPattern(ctx);
currentConstructStack.peek().addDescr(currentPattern);
currentPattern = null;
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@
import java.nio.file.Paths;

import junit.framework.TestCase;
import org.assertj.core.api.Assertions;
import org.drools.drl.ast.descr.AndDescr;
import org.drools.drl.ast.descr.BaseDescr;
import org.drools.drl.ast.descr.FromDescr;
import org.drools.drl.ast.descr.FunctionImportDescr;
import org.drools.drl.ast.descr.GlobalDescr;
import org.drools.drl.ast.descr.ImportDescr;
import org.drools.drl.ast.descr.NotDescr;
import org.drools.drl.ast.descr.OrDescr;
import org.drools.drl.ast.descr.PackageDescr;
import org.drools.drl.ast.descr.PatternDescr;
import org.drools.drl.ast.descr.RuleDescr;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

/*
* This test class is being ported from org.drools.mvel.compiler.lang.RuleParserTest
*/
Expand Down Expand Up @@ -277,4 +283,118 @@ public void testFromComplexAcessor() throws Exception {
assertEquals("customerService.getCustomer(o.getCustomerId())",
((FromDescr) customer.getSource()).getDataSource().getText());
}

@Test
public void testFromWithInlineList() throws Exception {
String source = "rule XYZ \n" +
" when \n" +
" o: Order( ) \n" +
" not( Number( ) from [1, 2, 3] ) \n" +
" then \n" +
" System.err.println(\"Invalid customer id found!\"); \n" +
" o.addError(\"Invalid customer id\"); \n" +
"end \n";
PackageDescr pkg = parser.parse(source);
assertFalse(parser.getErrors().toString(),
parser.hasErrors());

RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
assertEquals("XYZ",
rule.getName());

PatternDescr number = (PatternDescr) ((NotDescr) rule.getLhs().getDescrs().get(1)).getDescrs().get(0);
assertThat(((FromDescr) number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1, 2, 3]");
}

@Test
public void testFromWithInlineListMethod() throws Exception {
String source = "rule XYZ \n" +
" when \n" +
" o: Order( ) \n" +
" Number( ) from [1, 2, 3].sublist(1, 2) \n" +
" then \n" +
" System.err.println(\"Invalid customer id found!\"); \n" +
" o.addError(\"Invalid customer id\"); \n" +
"end \n";
PackageDescr pkg = parser.parse(source);
assertFalse(parser.getErrors().toString(),
parser.hasErrors());

RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
assertEquals("XYZ",
rule.getName());

assertFalse(parser.hasErrors());
PatternDescr number = (PatternDescr) rule.getLhs().getDescrs().get(1);

assertThat(((FromDescr) number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1, 2, 3].sublist(1, 2)");
}

@Test
public void testFromWithInlineListIndex() throws Exception {
String source = "rule XYZ \n" +
" when \n" +
" o: Order( ) \n" +
" Number( ) from [1, 2, 3][1] \n" +
" then \n" +
" System.err.println(\"Invalid customer id found!\"); \n" +
" o.addError(\"Invalid customer id\"); \n" +
"end \n";
PackageDescr pkg = parser.parse(source);

assertFalse(parser.getErrors().toString(),
parser.hasErrors());

RuleDescr rule = (RuleDescr) pkg.getRules().get(0);
assertEquals("XYZ",
rule.getName());

assertFalse(parser.hasErrors());
PatternDescr number = (PatternDescr) rule.getLhs().getDescrs().get(1);
assertThat(((FromDescr) number.getSource()).getDataSource().toString()).isEqualToIgnoringWhitespace("[1, 2, 3][1]");
}

@Test
public void testRuleWithoutEnd() throws Exception {
String source = "rule \"Invalid customer id\" \n" +
" when \n" +
" o: Order( ) \n" +
" then \n" +
" System.err.println(\"Invalid customer id found!\"); \n";
parser.parse(source);
assertTrue(parser.hasErrors());
}

@Test
public void testOrWithSpecialBind() throws Exception {
String source = "rule \"A and (B or C or D)\" \n" +
" when \n" +
" pdo1 : ParametricDataObject( paramID == 101, stringValue == \"1000\" ) and \n" +
" pdo2 :(ParametricDataObject( paramID == 101, stringValue == \"1001\" ) or \n" +
" ParametricDataObject( paramID == 101, stringValue == \"1002\" ) or \n" +
" ParametricDataObject( paramID == 101, stringValue == \"1003\" )) \n" +
" then \n" +
" System.out.println( \"Rule: A and (B or C or D) Fired. pdo1: \" + pdo1 + \" pdo2: \"+ pdo2); \n" +
"end\n";
PackageDescr pkg = parser.parse(source);
assertFalse(parser.getErrors().toString(),
parser.hasErrors());

RuleDescr rule = pkg.getRules().get(0);
AndDescr lhs = rule.getLhs();
assertEquals(2,
lhs.getDescrs().size());

PatternDescr pdo1 = (PatternDescr) lhs.getDescrs().get(0);
assertEquals("pdo1",
pdo1.getIdentifier());

OrDescr or = (OrDescr) rule.getLhs().getDescrs().get(1);
assertEquals(3,
or.getDescrs().size());
for (BaseDescr pdo2 : or.getDescrs()) {
assertEquals("pdo2",
((PatternDescr) pdo2).getIdentifier());
}
}
}

0 comments on commit 37185cf

Please sign in to comment.