Skip to content

Commit

Permalink
Enhance test/grammar coverage. matches, single quoted string, escape (#9
Browse files Browse the repository at this point in the history
)

- Introduced drlExpression, drlPrimary, drlLiteral, DRL_STRING_LITERAL
  • Loading branch information
tkobayas committed Oct 11, 2024
1 parent db5da0b commit 19eccd9
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ EXISTS : 'exists';
NOT : 'not';
IN : 'in';
FROM : 'from';
MATCHES : 'matches';

SALIENCE : 'salience';
ENABLED : 'enabled';
Expand Down Expand Up @@ -69,6 +70,10 @@ TIME_INTERVAL
| (('0'..'9')+ 'ms')
;

DRL_STRING_LITERAL
: ('"' ( DrlEscapeSequence | ~('\\'|'"') )* '"')
| ('\'' ( DrlEscapeSequence | ~('\\'|'\'') )* '\'') { setText( normalizeString( getText() ) ); }
;

/////////////////
// SYMBOLS
Expand All @@ -80,3 +85,28 @@ NULL_SAFE_DOT : '!.' ;
QUESTION_DIV : '?/' ;

MISC : '\'' | '\\' | '$' ;

/////////////////
// Fragment
/////////////////
fragment
DrlEscapeSequence
: '\\' ('b'|'B'|'t'|'n'|'f'|'r'|'"'|'\''|'\\'|'.'|'o'|
'x'|'a'|'e'|'c'|'d'|'D'|'s'|'S'|'w'|'W'|'p'|'A'|
'G'|'Z'|'z'|'Q'|'E'|'*'|'['|']'|'('|')'|'$'|'^'|
'{'|'}'|'?'|'+'|'-'|'&'|'|')
| DrlUnicodeEscape
| DrlOctalEscape
;

fragment
DrlOctalEscape
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
| '\\' ('0'..'7') ('0'..'7')
| '\\' ('0'..'7')
;

fragment
DrlUnicodeEscape
: '\\' 'u' HexDigit HexDigit HexDigit HexDigit
;
Original file line number Diff line number Diff line change
Expand Up @@ -58,32 +58,83 @@ 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 : shiftExpression, additiveExpression, multiplicativeExpression, unaryExpression, unaryExpressionNotPlusMinus, ..., primary
relationalExpression : drlExpression? ;

/* extending JavaParser expression */
drlExpression
: drlPrimary
| drlExpression bop=DOT
(
identifier
| methodCall
| THIS
| NEW nonWildcardTypeArguments? innerCreator
| SUPER superSuffix
| explicitGenericInvocation
)
| drlExpression LBRACK drlExpression RBRACK
| methodCall
| NEW creator
| LPAREN annotation* typeType (BITAND typeType)* RPAREN drlExpression
| drlExpression postfix=(INC | DEC)
| prefix=(ADD|SUB|INC|DEC) drlExpression
| prefix=(TILDE|BANG) 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 bop=INSTANCEOF (typeType | pattern)
| drlExpression bop=MATCHES drlExpression
| drlExpression bop=(EQUAL | NOTEQUAL) drlExpression
| drlExpression bop=BITAND drlExpression
| drlExpression bop=CARET drlExpression
| drlExpression bop=BITOR drlExpression
| drlExpression bop=AND drlExpression
| drlExpression bop=OR drlExpression
| <assoc=right> drlExpression bop=QUESTION drlExpression COLON drlExpression
| <assoc=right> drlExpression
bop=(ASSIGN | ADD_ASSIGN | SUB_ASSIGN | MUL_ASSIGN | DIV_ASSIGN | AND_ASSIGN | OR_ASSIGN | XOR_ASSIGN | RSHIFT_ASSIGN | URSHIFT_ASSIGN | LSHIFT_ASSIGN | MOD_ASSIGN)
drlExpression
| lambdaExpression // Java8
| switchExpression // Java17

// Java 8 methodReference
| drlExpression COLONCOLON typeArguments? identifier
| typeType COLONCOLON (typeArguments? identifier | NEW)
| classType COLONCOLON typeArguments? NEW
;

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

/* extending JavaParser literal */
drlLiteral
: integerLiteral
| floatLiteral
| CHAR_LITERAL
| DRL_STRING_LITERAL
| BOOL_LITERAL
| NULL_LITERAL
| TEXT_BLOCK // Java17
;

inlineListExpression
: LBRACK expressionList? RBRACK
;

expressionList
: expression (COMMA expression)*
: drlExpression (COMMA drlExpression)*
;

drlExpression : conditionalExpression ( op=assignmentOperator right=drlExpression )? ;
conditionalExpression : left=conditionalOrExpression ternaryExpression? ;
ternaryExpression : QUESTION ts=drlExpression COLON fs=drlExpression ;

/*
patternSource := FROM
( fromAccumulate
Expand Down Expand Up @@ -112,9 +163,9 @@ lhsExists : EXISTS lhsPatternBind ;
*/
lhsNot : NOT lhsPatternBind ;

rhs : blockStatement+ ;
rhs : blockStatement* ;

stringId : ( IDENTIFIER | STRING_LITERAL ) ;
stringId : ( IDENTIFIER | DRL_STRING_LITERAL ) ;

type : IDENTIFIER typeArguments? ( DOT IDENTIFIER typeArguments? )* (LBRACK RBRACK)* ;

Expand All @@ -129,8 +180,8 @@ drlAnnotation : AT name=qualifiedName drlArguments? ;
attributes : attribute ( COMMA? attribute )* ;
attribute : ( 'salience' DECIMAL_LITERAL )
| ( 'enabled' | 'no-loop' | 'auto-focus' | 'lock-on-active' | 'refract' | 'direct' ) BOOL_LITERAL?
| ( 'agenda-group' | 'activation-group' | 'ruleflow-group' | 'date-effective' | 'date-expires' | 'dialect' ) STRING_LITERAL
| 'calendars' STRING_LITERAL ( COMMA STRING_LITERAL )*
| ( 'agenda-group' | 'activation-group' | 'ruleflow-group' | 'date-effective' | 'date-expires' | 'dialect' ) DRL_STRING_LITERAL
| 'calendars' DRL_STRING_LITERAL ( COMMA DRL_STRING_LITERAL )*
| 'timer' ( DECIMAL_LITERAL | TEXT )
| 'duration' ( DECIMAL_LITERAL | TEXT ) ;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,16 @@ public Object visitConstraint(DRLParser.ConstraintContext ctx) {
}

@Override
public Object visitExpression(DRLParser.ExpressionContext ctx) {
public Object visitDrlExpression(DRLParser.DrlExpressionContext ctx) {
return ctx.children.stream()
.map(c -> c instanceof TerminalNode ? c : c.accept(this))
.filter(Objects::nonNull)
.map(Object::toString)
.collect(Collectors.joining(" "));
}

@Override
public Object visitDrlPrimary(DRLParser.DrlPrimaryContext ctx) {
return ctx.children.stream()
.map(c -> c instanceof TerminalNode ? c : c.accept(this))
.filter(Objects::nonNull)
Expand All @@ -163,14 +172,14 @@ public Object visitIdentifier(DRLParser.IdentifierContext ctx) {
}

@Override
public Object visitLiteral(DRLParser.LiteralContext ctx) {
public Object visitDrlLiteral(DRLParser.DrlLiteralContext ctx) {
ParseTree node = ctx;
while (true) {
if (node instanceof TerminalNode) {
return node.toString();
}
if (node.getChildCount() != 1) {
return super.visitLiteral(ctx);
return super.visitDrlLiteral(ctx);
}
node = node.getChild(0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
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.ExprConstraintDescr;
import org.drools.drl.ast.descr.FromDescr;
import org.drools.drl.ast.descr.FunctionImportDescr;
import org.drools.drl.ast.descr.GlobalDescr;
Expand Down Expand Up @@ -397,4 +398,64 @@ public void testOrWithSpecialBind() throws Exception {
((PatternDescr) pdo2).getIdentifier());
}
}

@Test
public void testCompatibleRestriction() throws Exception {
String source = "package com.sample rule test when Test( ( text == null || text2 matches \"\" ) ) then end";
PackageDescr pkg = parser.parse(source);

assertEquals( "com.sample",
pkg.getName() );
RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
assertEquals( "test",
rule.getName() );
ExprConstraintDescr expr = (ExprConstraintDescr) ((PatternDescr) rule.getLhs().getDescrs().get(0 )).getDescrs().get(0 );
assertEquals( "( text == null || text2 matches \"\" )",
expr.getText() );
}

@Test
public void testSimpleConstraint() throws Exception {
String source = "package com.sample rule test when Cheese( type == 'stilton', price > 10 ) then end";
PackageDescr pkg = parser.parse(source);

assertEquals( "com.sample",
pkg.getName() );
RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
assertEquals( "test",
rule.getName() );

assertEquals( 1,
rule.getLhs().getDescrs().size() );
PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 );

AndDescr constraint = (AndDescr) pattern.getConstraint();
assertEquals( 2,
constraint.getDescrs().size() );
assertEquals( "type == \"stilton\"",
constraint.getDescrs().get( 0 ).toString() );
assertEquals( "price > 10",
constraint.getDescrs().get( 1 ).toString() );
}

@Test
public void testStringEscapes() throws Exception {
String source = "package com.sample rule test when Cheese( type matches \"\\..*\\\\.\" ) then end";
PackageDescr pkg = parser.parse(source);
assertEquals( "com.sample",
pkg.getName() );
RuleDescr rule = (RuleDescr) pkg.getRules().get( 0 );
assertEquals( "test",
rule.getName() );

assertEquals( 1,
rule.getLhs().getDescrs().size() );
PatternDescr pattern = (PatternDescr) rule.getLhs().getDescrs().get( 0 );

AndDescr constraint = (AndDescr) pattern.getConstraint();
assertEquals( 1,
constraint.getDescrs().size() );
assertEquals( "type matches \"\\..*\\\\.\"",
constraint.getDescrs().get( 0 ).toString() );
}
}

0 comments on commit 19eccd9

Please sign in to comment.