Skip to content

Commit

Permalink
[CESQL] Constant folding (#392)
Browse files Browse the repository at this point in the history
* Added visitor for the expressions

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* First constant folding draft

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Constant folding for unary expressions

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* More testing
Constant folding for exists expression

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Little mistake

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* Added a ParserBuilder

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
  • Loading branch information
slinkydeveloper committed Jun 4, 2021
1 parent 687e03b commit a0b0835
Show file tree
Hide file tree
Showing 33 changed files with 431 additions and 89 deletions.
17 changes: 14 additions & 3 deletions sql/src/main/java/io/cloudevents/sql/ParseException.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
public class ParseException extends RuntimeException {

public enum ErrorKind {
RECOGNITION_ERROR,
PARSE_VALUE
RECOGNITION,
PARSE_VALUE,
CONSTANT_EXPRESSION_EVALUATION,
}

private final ErrorKind errorKind;
Expand Down Expand Up @@ -49,12 +50,22 @@ public static ParseException cannotParseValue(ParseTree node, Type target, Throw

public static ParseException recognitionError(RecognitionException e, String msg) {
return new ParseException(
ErrorKind.RECOGNITION_ERROR,
ErrorKind.RECOGNITION,
new Interval(e.getOffendingToken().getStartIndex(), e.getOffendingToken().getStopIndex()),
e.getOffendingToken().getText(),
"Cannot parse: " + msg,
e
);
}

public static ParseException cannotEvaluateConstantExpression(EvaluationException exception) {
return new ParseException(
ErrorKind.CONSTANT_EXPRESSION_EVALUATION,
exception.getExpressionInterval(),
exception.getExpressionText(),
"Cannot evaluate the constant expression: " + exception.getExpressionText(),
exception
);
}

}
15 changes: 15 additions & 0 deletions sql/src/main/java/io/cloudevents/sql/Parser.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.cloudevents.sql;

import io.cloudevents.sql.impl.ParserBuilder;
import io.cloudevents.sql.impl.ParserImpl;

public interface Parser {
Expand All @@ -24,4 +25,18 @@ static Expression parseDefault(String inputExpression) throws ParseException {
return ParserImpl.getInstance().parse(inputExpression);
}

/**
* @return the default instance of the parser
*/
static Parser getDefault() {
return ParserImpl.getInstance();
}

/**
* @return a new {@link ParserBuilder}, to create a customized parser instance
*/
static ParserBuilder builder() {
return new ParserBuilder();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.cloudevents.sql.impl;

import io.cloudevents.SpecVersion;
import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.impl.expressions.*;

public class ConstantFoldingExpressionVisitor implements ExpressionInternalVisitor<ExpressionInternal> {

@Override
public ExpressionInternal visitExpressionInternal(ExpressionInternal expressionInternal) {
return expressionInternal;
}

@Override
public ExpressionInternal visitBaseBinaryExpression(BaseBinaryExpression baseBinaryExpression) {
ExpressionInternal left = baseBinaryExpression.getLeftOperand().visit(this);
ExpressionInternal right = baseBinaryExpression.getRightOperand().visit(this);

if (left instanceof ValueExpression && right instanceof ValueExpression) {
// I can do constant folding!
return new ValueExpression(
baseBinaryExpression.expressionInterval(),
baseBinaryExpression.expressionText(),
baseBinaryExpression.evaluate(
EvaluationRuntime.getDefault(),
((ValueExpression) left).getValue(),
((ValueExpression) right).getValue(),
FailFastExceptionThrower.getInstance()
)
);
}

baseBinaryExpression.setLeftOperand(left);
baseBinaryExpression.setRightOperand(right);
return baseBinaryExpression;
}

@Override
public ExpressionInternal visitExistsExpression(ExistsExpression existsExpression) {
if (SpecVersion.V1.getMandatoryAttributes().contains(existsExpression.getKey())) {
// If the attribute is a mandatory attribute of the spec, there's no need to check it
return new ValueExpression(existsExpression.expressionInterval(), existsExpression.expressionText(), true);
}
return existsExpression;
}

@Override
public ExpressionInternal visitBaseUnaryExpression(BaseUnaryExpression baseUnaryExpression) {
ExpressionInternal inner = baseUnaryExpression.getOperand().visit(this);

if (inner instanceof ValueExpression) {
return new ValueExpression(
baseUnaryExpression.expressionInterval(),
baseUnaryExpression.expressionText(),
baseUnaryExpression.evaluate(EvaluationRuntime.getDefault(), ((ValueExpression) inner).getValue(), FailFastExceptionThrower.getInstance())
);
}

baseUnaryExpression.setOperand(inner);
return baseUnaryExpression;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import java.util.ArrayList;
import java.util.List;

class ExceptionsStore implements ExceptionThrower {
class ExceptionStore implements ExceptionThrower {

private List<EvaluationException> exceptions;

ExceptionsStore() {
ExceptionStore() {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.Expression;
import io.cloudevents.sql.Result;
import io.cloudevents.sql.impl.expressions.ExpressionInternal;

public class ExpressionImpl implements Expression {

Expand All @@ -16,7 +17,7 @@ public ExpressionImpl(ExpressionInternal expressionInternal) {

@Override
public Result evaluate(EvaluationRuntime evaluationRuntime, CloudEvent event) {
ExceptionsStore exceptions = new ExceptionsStore();
ExceptionStore exceptions = new ExceptionStore();
Object value = this.expressionInternal.evaluate(evaluationRuntime, event, exceptions);
return new EvaluationResult(value, exceptions.getExceptions());
}
Expand All @@ -25,4 +26,8 @@ public Result evaluate(EvaluationRuntime evaluationRuntime, CloudEvent event) {
public Object tryEvaluate(EvaluationRuntime evaluationRuntime, CloudEvent event) throws EvaluationException {
return this.expressionInternal.evaluate(evaluationRuntime, event, FailFastExceptionThrower.getInstance());
}

protected ExpressionInternal getExpressionInternal() {
return expressionInternal;
}
}
30 changes: 30 additions & 0 deletions sql/src/main/java/io/cloudevents/sql/impl/ParserBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.cloudevents.sql.impl;

import io.cloudevents.sql.Parser;

public class ParserBuilder {

private boolean constantFolding;

public ParserBuilder() {
this.constantFolding = true;
}

/**
* Disable constant folding when parsing.
*
* @return this
*/
public ParserBuilder disableConstantFolding() {
this.constantFolding = false;
return this;
}

/**
* @return the new {@link Parser}
*/
public Parser build() {
return new ParserImpl(this.constantFolding);
}

}
19 changes: 16 additions & 3 deletions sql/src/main/java/io/cloudevents/sql/impl/ParserImpl.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.cloudevents.sql.impl;

import io.cloudevents.sql.EvaluationException;
import io.cloudevents.sql.Expression;
import io.cloudevents.sql.ParseException;
import io.cloudevents.sql.Parser;
import io.cloudevents.sql.generated.CESQLParserLexer;
import io.cloudevents.sql.generated.CESQLParserParser;
import io.cloudevents.sql.impl.expressions.ExpressionInternal;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
Expand All @@ -17,17 +19,20 @@
public class ParserImpl implements Parser {

private static class SingletonContainer {
private final static ParserImpl INSTANCE = new ParserImpl();
private final static ParserImpl INSTANCE = new ParserImpl(true);
}

/**
* @return instance of {@link ParserImpl}
* @return default instance of {@link ParserImpl}
*/
public static Parser getInstance() {
return ParserImpl.SingletonContainer.INSTANCE;
}

public ParserImpl() {
private final boolean constantFolding;

ParserImpl(boolean constantFolding) {
this.constantFolding = constantFolding;
}

@Override
Expand Down Expand Up @@ -72,6 +77,14 @@ public void reportContextSensitivity(org.antlr.v4.runtime.Parser recognizer, DFA

ExpressionInternal internal = new ExpressionTranslatorVisitor().visit(tree);

if (this.constantFolding) {
try {
internal = internal.visit(new ConstantFoldingExpressionVisitor());
} catch (EvaluationException e) {
throw ParseException.cannotEvaluateConstantExpression(e);
}
}

return new ExpressionImpl(internal);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ public Object evaluate(EvaluationRuntime runtime, CloudEvent event, ExceptionThr
return CloudEventUtils.accessContextAttribute(thrower, expressionInterval(), expressionText(), event, key);
}

@Override
public <T> T visit(ExpressionInternalVisitor<T> visitor) {
return visitor.visitAccessAttributeExpression(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.impl.ExceptionThrower;
import io.cloudevents.sql.impl.ExpressionInternal;
import org.antlr.v4.runtime.misc.Interval;

public class AndExpression extends BaseBinaryExpression {
Expand All @@ -12,7 +11,7 @@ public AndExpression(Interval expressionInterval, String expressionText, Express
}

@Override
Object evaluate(EvaluationRuntime runtime, Object left, Object right, ExceptionThrower exceptions) {
public Object evaluate(EvaluationRuntime runtime, Object left, Object right, ExceptionThrower exceptions) {
boolean x = castToBoolean(runtime, exceptions, left);
if (!x) {
// Short circuit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,48 @@
import io.cloudevents.CloudEvent;
import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.impl.ExceptionThrower;
import io.cloudevents.sql.impl.ExpressionInternal;
import org.antlr.v4.runtime.misc.Interval;

public abstract class BaseBinaryExpression extends BaseExpression {

protected final ExpressionInternal leftOperand;
protected final ExpressionInternal rightOperand;
protected ExpressionInternal leftOperand;
protected ExpressionInternal rightOperand;

protected BaseBinaryExpression(Interval expressionInterval, String expressionText, ExpressionInternal leftOperand, ExpressionInternal rightOperand) {
super(expressionInterval, expressionText);
this.leftOperand = leftOperand;
this.rightOperand = rightOperand;
}

abstract Object evaluate(EvaluationRuntime runtime, Object left, Object right, ExceptionThrower exceptions);
public abstract Object evaluate(EvaluationRuntime runtime, Object left, Object right, ExceptionThrower exceptions);

@Override
public Object evaluate(EvaluationRuntime runtime, CloudEvent event, ExceptionThrower thrower) {
Object left = leftOperand.evaluate(runtime, event, thrower);
Object right = rightOperand.evaluate(runtime, event, thrower);
return evaluate(runtime, left, right, thrower);
}

@Override
public <T> T visit(ExpressionInternalVisitor<T> visitor) {
return visitor.visitBaseBinaryExpression(this);
}

public ExpressionInternal getLeftOperand() {
return leftOperand;
}

public ExpressionInternal getRightOperand() {
return rightOperand;
}

public BaseBinaryExpression setLeftOperand(ExpressionInternal leftOperand) {
this.leftOperand = leftOperand;
return this;
}

public BaseBinaryExpression setRightOperand(ExpressionInternal rightOperand) {
this.rightOperand = rightOperand;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import io.cloudevents.sql.Type;
import io.cloudevents.sql.impl.EvaluationContextImpl;
import io.cloudevents.sql.impl.ExceptionThrower;
import io.cloudevents.sql.impl.ExpressionInternal;
import org.antlr.v4.runtime.misc.Interval;

public abstract class BaseExpression implements ExpressionInternal {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.impl.ExceptionThrower;
import io.cloudevents.sql.impl.ExpressionInternal;
import org.antlr.v4.runtime.misc.Interval;

public abstract class BaseIntegerBinaryExpression extends BaseBinaryExpression {
Expand All @@ -14,7 +13,7 @@ public BaseIntegerBinaryExpression(Interval expressionInterval, String expressio
abstract Object evaluate(EvaluationRuntime runtime, int left, int right, ExceptionThrower exceptions);

@Override
Object evaluate(EvaluationRuntime runtime, Object left, Object right, ExceptionThrower exceptions) {
public Object evaluate(EvaluationRuntime runtime, Object left, Object right, ExceptionThrower exceptions) {
return this.evaluate(
runtime,
castToInteger(runtime, exceptions, left).intValue(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.cloudevents.sql.impl.expressions;

import io.cloudevents.CloudEvent;
import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.impl.ExceptionThrower;
import org.antlr.v4.runtime.misc.Interval;

public abstract class BaseUnaryExpression extends BaseExpression {

protected ExpressionInternal internal;

public BaseUnaryExpression(Interval expressionInterval, String expressionText, ExpressionInternal internal) {
super(expressionInterval, expressionText);
this.internal = internal;
}

public abstract Object evaluate(EvaluationRuntime runtime, Object value, ExceptionThrower exceptions);

@Override
public Object evaluate(EvaluationRuntime runtime, CloudEvent event, ExceptionThrower thrower) {
return evaluate(runtime, internal.evaluate(runtime, event, thrower), thrower);
}

@Override
public <T> T visit(ExpressionInternalVisitor<T> visitor) {
return visitor.visitBaseUnaryExpression(this);
}

public ExpressionInternal getOperand() {
return internal;
}

public BaseUnaryExpression setOperand(ExpressionInternal internal) {
this.internal = internal;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.impl.ExceptionThrower;
import io.cloudevents.sql.impl.ExpressionInternal;
import org.antlr.v4.runtime.misc.Interval;

public class DifferenceExpression extends BaseIntegerBinaryExpression {
Expand Down
Loading

0 comments on commit a0b0835

Please sign in to comment.