Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EQL: Add AstBuilder to convert to QL tree #51558

Merged
merged 11 commits into from
Feb 3, 2020
15 changes: 2 additions & 13 deletions x-pack/plugin/eql/src/main/antlr/EqlBase.g4
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,15 @@ 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:
costin marked this conversation as resolved.
Show resolved Hide resolved
// 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 NOT? IN LP expression (COMMA expression)* RP #containsExpression
| operator=(MINUS | PLUS) valueExpression #arithmeticUnary
| left=valueExpression operator=(ASTERISK | SLASH | PERCENT) right=valueExpression #arithmeticBinary
| left=valueExpression operator=(PLUS | MINUS) right=valueExpression #arithmeticBinary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@
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.tree.Location;
import org.elasticsearch.xpack.ql.tree.Source;
import org.elasticsearch.xpack.ql.util.Check;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Base parsing visitor class offering utility methods.
Expand All @@ -44,14 +41,6 @@ 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 List<Expression> expressions(List<? extends ParserRuleContext> ctxs) {
return visitList(ctxs, Expression.class);
}

protected <T> List<T> visitList(List<? extends ParserRuleContext> contexts, Class<T> clazz) {
List<T> results = new ArrayList<>(contexts.size());
for (ParserRuleContext context : contexts) {
Expand Down Expand Up @@ -113,71 +102,6 @@ static String text(ParseTree node) {
return node == null ? null : node.getText();
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can keep the comment.

* 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) {
// remove leading and trailing ' for strings and also eliminate escaped single quotes
if (text == null) {
return null;
}

// unescaped strings can be interpreted directly
if (text.startsWith("?")) {
return text.substring(2, text.length() - 1);
}

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

while (regexMatcher.find()) {
String source = regexMatcher.group();
String replacement;

switch (source) {
case "\\t":
replacement = "\t";
break;
case "\\b":
replacement = "\b";
break;
case "\\f":
replacement = "\f";
break;
case "\\n":
replacement = "\n";
break;
case "\\r":
replacement = "\r";
break;
case "\\\"":
replacement = "\"";
break;
case "\\'":
replacement = "'";
break;
case "\\\\":
// will be interpreted as regex, so we have to escape it
replacement = "\\\\";
break;
default:
replacement = source;
}

regexMatcher.appendReplacement(resultString, replacement);

}
regexMatcher.appendTail(resultString);

return resultString.toString();
}

@Override
public Object visitTerminal(TerminalNode node) {
Source source = source(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

import org.elasticsearch.xpack.eql.parser.EqlBaseParser.SingleStatementContext;

public class AstBuilder extends ExpressionBuilder {
public class AstBuilder extends QueryBuilder {

@Override
public Object visitSingleStatement(SingleStatementContext ctx) {
return expression(ctx.statement());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,49 +232,37 @@ 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 enterContainsExpression(EqlBaseParser.ContainsExpressionContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitComparison(EqlBaseParser.ComparisonContext ctx) { }
@Override public void exitContainsExpression(EqlBaseParser.ContainsExpressionContext ctx) { }
/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,28 +143,21 @@ 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 visitContainsExpression(EqlBaseParser.ContainsExpressionContext 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 All @@ -239,6 +219,18 @@ interface EqlBaseListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitComparison(EqlBaseParser.ComparisonContext ctx);
/**
* Enter a parse tree produced by the {@code containsExpression}
* labeled alternative in {@link EqlBaseParser#valueExpression}.
* @param ctx the parse tree
*/
void enterContainsExpression(EqlBaseParser.ContainsExpressionContext ctx);
/**
* Exit a parse tree produced by the {@code containsExpression}
* labeled alternative in {@link EqlBaseParser#valueExpression}.
* @param ctx the parse tree
*/
void exitContainsExpression(EqlBaseParser.ContainsExpressionContext ctx);
/**
* Enter a parse tree produced by the {@code arithmeticBinary}
* labeled alternative in {@link EqlBaseParser#valueExpression}.
Expand Down
Loading