Skip to content

Commit

Permalink
EQL: Add AstBuilder to convert to QL tree (elastic#51558)
Browse files Browse the repository at this point in the history
* EQL: Add AstBuilder visitors
* EQL: Add tests for wildcards and sets
* EQL: Fix licensing
* EQL: Fix ExpressionTests.java license
* EQL: Cleanup imports
* EQL: PR feedback and remove LiteralBuilder
* EQL: Split off logical plan from expressions
* EQL: Remove stray import
* EQL: Add predicate handling for set checks
* EQL: Remove commented out dead code
* EQL: Remove wildcard test, wait until analyzer
  • Loading branch information
rw-access authored Feb 3, 2020
1 parent c0646ea commit a462700
Show file tree
Hide file tree
Showing 16 changed files with 949 additions and 545 deletions.
23 changes: 9 additions & 14 deletions x-pack/plugin/eql/src/main/antlr/EqlBase.g4
Original file line number Diff line number Diff line change
Expand Up @@ -73,32 +73,27 @@ expression
booleanExpression
: NOT booleanExpression #logicalNot
| relationship=IDENTIFIER OF subquery #processCheck
| predicated #booleanDefault
| valueExpression #booleanDefault
| left=booleanExpression operator=AND right=booleanExpression #logicalBinary
| left=booleanExpression operator=OR right=booleanExpression #logicalBinary
;

// workaround for:
// https://github.com/antlr/antlr4/issues/780
// https://github.com/antlr/antlr4/issues/781
predicated
: valueExpression predicate?
;

// dedicated calls for each branch are not used to reuse the NOT handling across them
// instead the property kind is used for differentiation
predicate
: NOT? kind=IN LP valueExpression (COMMA valueExpression)* RP
;

valueExpression
: primaryExpression #valueExpressionDefault
: primaryExpression predicate? #valueExpressionDefault
| operator=(MINUS | PLUS) valueExpression #arithmeticUnary
| left=valueExpression operator=(ASTERISK | SLASH | PERCENT) right=valueExpression #arithmeticBinary
| left=valueExpression operator=(PLUS | MINUS) right=valueExpression #arithmeticBinary
| left=valueExpression comparisonOperator right=valueExpression #comparison
;

// workaround for
// https://github.com/antlr/antlr4/issues/780
// https://github.com/antlr/antlr4/issues/781
predicate
: NOT? kind=IN LP expression (COMMA expression)* RP
;

primaryExpression
: constant #constantDefault
| functionExpression #function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
import org.elasticsearch.xpack.ql.tree.Location;
import org.elasticsearch.xpack.ql.tree.Source;
import org.elasticsearch.xpack.ql.util.Check;
Expand All @@ -25,6 +25,8 @@
*/
abstract class AbstractBuilder extends EqlBaseBaseVisitor<Object> {

private static final Pattern slashPattern = Pattern.compile("\\\\.");

@Override
public Object visit(ParseTree tree) {
Object result = super.visit(tree);
Expand All @@ -44,12 +46,12 @@ protected <T> T typedParsing(ParseTree ctx, Class<T> type) {
type.getSimpleName(), (result != null ? result.getClass().getSimpleName() : "null"));
}

protected Expression expression(ParseTree ctx) {
return typedParsing(ctx, Expression.class);
protected LogicalPlan plan(ParseTree ctx) {
return typedParsing(ctx, LogicalPlan.class);
}

protected List<Expression> expressions(List<? extends ParserRuleContext> ctxs) {
return visitList(ctxs, Expression.class);
protected List<LogicalPlan> plans(List<? extends ParserRuleContext> ctxs) {
return visitList(ctxs, LogicalPlan.class);
}

protected <T> List<T> visitList(List<? extends ParserRuleContext> contexts, Class<T> clazz) {
Expand Down Expand Up @@ -113,14 +115,7 @@ static String text(ParseTree node) {
return node == null ? null : node.getText();
}

/**
* Extracts the actual unescaped string (literal) value of a terminal node.
*/
static String string(TerminalNode node) {
return node == null ? null : unquoteString(node.getText());
}

static String unquoteString(String text) {
public static String unquoteString(String text) {
// remove leading and trailing ' for strings and also eliminate escaped single quotes
if (text == null) {
return null;
Expand All @@ -132,9 +127,8 @@ static String unquoteString(String text) {
}

text = text.substring(1, text.length() - 1);
Pattern regex = Pattern.compile("\\\\.");
StringBuffer resultString = new StringBuffer();
Matcher regexMatcher = regex.matcher(text);
Matcher regexMatcher = slashPattern.matcher(text);

while (regexMatcher.find()) {
String source = regexMatcher.group();
Expand Down Expand Up @@ -167,6 +161,7 @@ static String unquoteString(String text) {
replacement = "\\\\";
break;
default:
// unknown escape sequence, pass through as-is
replacement = source;
}

Expand All @@ -183,4 +178,5 @@ public Object visitTerminal(TerminalNode node) {
Source source = source(node);
throw new ParsingException(source, "Does not know how to handle {}", source.text());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
package org.elasticsearch.xpack.eql.parser;

import org.elasticsearch.xpack.eql.parser.EqlBaseParser.SingleStatementContext;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;

public class AstBuilder extends ExpressionBuilder {
public class AstBuilder extends LogicalPlanBuilder {

@Override
public Object visitSingleStatement(SingleStatementContext ctx) {
return expression(ctx.statement());
public LogicalPlan visitSingleStatement(SingleStatementContext ctx) {
return plan(ctx.statement());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,73 +232,61 @@ class EqlBaseBaseListener implements EqlBaseListener {
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterPredicated(EqlBaseParser.PredicatedContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitPredicated(EqlBaseParser.PredicatedContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterPredicate(EqlBaseParser.PredicateContext ctx) { }
@Override public void enterValueExpressionDefault(EqlBaseParser.ValueExpressionDefaultContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitPredicate(EqlBaseParser.PredicateContext ctx) { }
@Override public void exitValueExpressionDefault(EqlBaseParser.ValueExpressionDefaultContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterValueExpressionDefault(EqlBaseParser.ValueExpressionDefaultContext ctx) { }
@Override public void enterComparison(EqlBaseParser.ComparisonContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitValueExpressionDefault(EqlBaseParser.ValueExpressionDefaultContext ctx) { }
@Override public void exitComparison(EqlBaseParser.ComparisonContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterComparison(EqlBaseParser.ComparisonContext ctx) { }
@Override public void enterArithmeticBinary(EqlBaseParser.ArithmeticBinaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitComparison(EqlBaseParser.ComparisonContext ctx) { }
@Override public void exitArithmeticBinary(EqlBaseParser.ArithmeticBinaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterArithmeticBinary(EqlBaseParser.ArithmeticBinaryContext ctx) { }
@Override public void enterArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitArithmeticBinary(EqlBaseParser.ArithmeticBinaryContext ctx) { }
@Override public void exitArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx) { }
@Override public void enterPredicate(EqlBaseParser.PredicateContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx) { }
@Override public void exitPredicate(EqlBaseParser.PredicateContext ctx) { }
/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,42 +143,35 @@ class EqlBaseBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements EqlBa
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPredicated(EqlBaseParser.PredicatedContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPredicate(EqlBaseParser.PredicateContext ctx) { return visitChildren(ctx); }
@Override public T visitValueExpressionDefault(EqlBaseParser.ValueExpressionDefaultContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitValueExpressionDefault(EqlBaseParser.ValueExpressionDefaultContext ctx) { return visitChildren(ctx); }
@Override public T visitComparison(EqlBaseParser.ComparisonContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitComparison(EqlBaseParser.ComparisonContext ctx) { return visitChildren(ctx); }
@Override public T visitArithmeticBinary(EqlBaseParser.ArithmeticBinaryContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitArithmeticBinary(EqlBaseParser.ArithmeticBinaryContext ctx) { return visitChildren(ctx); }
@Override public T visitArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx) { return visitChildren(ctx); }
@Override public T visitPredicate(EqlBaseParser.PredicateContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,26 +195,6 @@ interface EqlBaseListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitLogicalBinary(EqlBaseParser.LogicalBinaryContext ctx);
/**
* Enter a parse tree produced by {@link EqlBaseParser#predicated}.
* @param ctx the parse tree
*/
void enterPredicated(EqlBaseParser.PredicatedContext ctx);
/**
* Exit a parse tree produced by {@link EqlBaseParser#predicated}.
* @param ctx the parse tree
*/
void exitPredicated(EqlBaseParser.PredicatedContext ctx);
/**
* Enter a parse tree produced by {@link EqlBaseParser#predicate}.
* @param ctx the parse tree
*/
void enterPredicate(EqlBaseParser.PredicateContext ctx);
/**
* Exit a parse tree produced by {@link EqlBaseParser#predicate}.
* @param ctx the parse tree
*/
void exitPredicate(EqlBaseParser.PredicateContext ctx);
/**
* Enter a parse tree produced by the {@code valueExpressionDefault}
* labeled alternative in {@link EqlBaseParser#valueExpression}.
Expand Down Expand Up @@ -263,6 +243,16 @@ interface EqlBaseListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitArithmeticUnary(EqlBaseParser.ArithmeticUnaryContext ctx);
/**
* Enter a parse tree produced by {@link EqlBaseParser#predicate}.
* @param ctx the parse tree
*/
void enterPredicate(EqlBaseParser.PredicateContext ctx);
/**
* Exit a parse tree produced by {@link EqlBaseParser#predicate}.
* @param ctx the parse tree
*/
void exitPredicate(EqlBaseParser.PredicateContext ctx);
/**
* Enter a parse tree produced by the {@code constantDefault}
* labeled alternative in {@link EqlBaseParser#primaryExpression}.
Expand Down
Loading

0 comments on commit a462700

Please sign in to comment.