Skip to content

Commit

Permalink
DROOLS-1701 Report compilation error as a runtime error (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
evacchi authored and mariofusco committed Jul 5, 2018
1 parent 9717dfe commit 7d7f3a0
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -415,4 +415,9 @@ private static Object[] toFunctionParams(Object params) {
}
return invocationParams;
}

public static Object notifyCompilationError(EvaluationContext feelExprCtx, String message) {
feelExprCtx.notifyEvt(() -> new ASTEventBase(Severity.ERROR, message, null));
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import org.kie.dmn.feel.runtime.UnaryTest;
import org.kie.dmn.feel.runtime.impl.RangeImpl;
import org.kie.dmn.feel.util.EvalHelper;
import org.kie.dmn.feel.util.Msg;

import static org.kie.dmn.feel.codegen.feel11.DirectCompilerResult.mergeFDs;

Expand Down Expand Up @@ -921,7 +922,7 @@ private DirectCompilerResult declareExternalFunction(FEEL_1_1Parser.FunctionDefi
String className = java.get("class");
String methodSignature = java.get("method signature");
if (className == null || methodSignature == null) {
throw new IllegalArgumentException("Invalid class name or method signature: " + className + "::" + methodSignature);
throw new FEELCompilationError(Msg.createMessage(Msg.UNABLE_TO_FIND_EXTERNAL_FUNCTION_AS_DEFINED_BY, methodSignature));
}
Expression methodCallExpr = FunctionDefs.asMethodCall(className, methodSignature, params);
DirectCompilerResult parameters = visit(ctx.formalParameters());
Expand All @@ -936,7 +937,7 @@ private DirectCompilerResult declareExternalFunction(FEEL_1_1Parser.FunctionDefi
return result;

} else {
throw new IllegalArgumentException("Invalid external declaration");
throw new FEELCompilationError(Msg.createMessage(Msg.UNABLE_TO_FIND_EXTERNAL_FUNCTION_AS_DEFINED_BY, null));
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.kie.dmn.feel.codegen.feel11;

public class FEELCompilationError extends Error {

public FEELCompilationError(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package org.kie.dmn.feel.lang;

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

import org.drools.javaparser.JavaParser;
import org.drools.javaparser.ast.NodeList;
Expand All @@ -13,10 +10,11 @@
import org.drools.javaparser.ast.expr.Expression;
import org.drools.javaparser.ast.expr.MethodCallExpr;
import org.drools.javaparser.ast.expr.NameExpr;
import org.drools.javaparser.ast.expr.NullLiteralExpr;
import org.drools.javaparser.ast.expr.StringLiteralExpr;
import org.drools.javaparser.ast.type.Type;
import org.kie.dmn.feel.codegen.feel11.FEELCompilationError;
import org.kie.dmn.feel.lang.ast.FunctionDefNode;
import org.kie.dmn.feel.util.Msg;

public class FunctionDefs {

Expand Down Expand Up @@ -61,7 +59,8 @@ public static Expression asMethodCall(
methodName,
new NodeList<>(paramExprs));
} else {
return new NullLiteralExpr();
throw new FEELCompilationError(
Msg.createMessage(Msg.ERROR_RESOLVING_EXTERNAL_FUNCTION_AS_DEFINED_BY, methodSignature));
}
} catch (Exception e) {
throw new IllegalArgumentException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@
import java.util.Set;

import org.antlr.v4.runtime.tree.ParseTree;
import org.drools.javaparser.ast.NodeList;
import org.drools.javaparser.ast.expr.Expression;
import org.drools.javaparser.ast.expr.MethodCallExpr;
import org.drools.javaparser.ast.expr.NameExpr;
import org.drools.javaparser.ast.expr.StringLiteralExpr;
import org.kie.dmn.api.feel.runtime.events.FEELEvent;
import org.kie.dmn.api.feel.runtime.events.FEELEventListener;
import org.kie.dmn.feel.FEEL;
import org.kie.dmn.feel.codegen.feel11.CompiledFEELExpression;
import org.kie.dmn.feel.codegen.feel11.CompilerBytecodeLoader;
import org.kie.dmn.feel.codegen.feel11.DirectCompilerResult;
import org.kie.dmn.feel.codegen.feel11.DirectCompilerVisitor;
import org.kie.dmn.feel.codegen.feel11.FEELCompilationError;
import org.kie.dmn.feel.lang.CompiledExpression;
import org.kie.dmn.feel.lang.CompilerContext;
import org.kie.dmn.feel.lang.EvaluationContext;
Expand Down Expand Up @@ -110,23 +116,53 @@ public CompilerContext newCompilerContext(Collection<FEELEventListener> contextL

@Override
public CompiledExpression compile(String expression, CompilerContext ctx) {
FEEL_1_1Parser parser = FEELParser.parse(getEventsManager(ctx.getListeners()), expression, ctx.getInputVariableTypes(), ctx.getInputVariables(), ctx.getFEELFunctions(), profiles);

Set<FEELEventListener> listeners = new HashSet<>(ctx.getListeners());
// add listener to syntax errors, and save them
CompilerErrorListener errorListener = new CompilerErrorListener();
listeners.add(errorListener);

FEEL_1_1Parser parser = FEELParser.parse(getEventsManager(listeners), expression, ctx.getInputVariableTypes(), ctx.getInputVariables(), ctx.getFEELFunctions(), profiles);
ParseTree tree = parser.compilation_unit();
if (!doCompile) {
ASTBuilderVisitor v = new ASTBuilderVisitor(ctx.getInputVariableTypes());
BaseNode expr = v.visit(tree);
CompiledExpression ce = new CompiledExpressionImpl(expr);
return ce;
} else {
DirectCompilerVisitor v = new DirectCompilerVisitor(ctx.getInputVariableTypes());
DirectCompilerResult directResult = v.visit(tree);
if (errorListener.evt != null) {
return compiledError(expression, errorListener.evt.getMessage());
}

try {
DirectCompilerVisitor v = new DirectCompilerVisitor(ctx.getInputVariableTypes());
DirectCompilerResult directResult = v.visit(tree);
Expression expr = directResult.getExpression();
return new CompilerBytecodeLoader()
.makeFromJPExpression(expression, expr, directResult.getFieldDeclarations());
} catch (FEELCompilationError e) {
return compiledError(expression, e.getMessage());
}

Expression expr = directResult.getExpression();
CompiledFEELExpression cu = new CompilerBytecodeLoader().makeFromJPExpression(expression, expr, directResult.getFieldDeclarations());
return cu;
}
}

/**
* Generates a compilable class that reports a (compile-time) error at runtime
*/
private CompiledFEELExpression compiledError(String expression, String msg) {
return new CompilerBytecodeLoader()
.makeFromJPExpression(
expression,
new MethodCallExpr(
new NameExpr("CompiledFEELSupport"),
"notifyCompilationError",
new NodeList<>(
new NameExpr("feelExprCtx"),
new StringLiteralExpr(msg))),
Collections.emptySet());
}

public CompiledExpression compileExpressionList(String expression, CompilerContext ctx) {
FEEL_1_1Parser parser = FEELParser.parse(getEventsManager(ctx.getListeners()), expression, ctx.getInputVariableTypes(), ctx.getInputVariables(), ctx.getFEELFunctions(), profiles);
ParseTree tree = parser.expressionList();
Expand Down Expand Up @@ -287,4 +323,16 @@ public FEELEventListenersManager getEventsManager(Collection<FEELEventListener>
return listenerMgr;
}

// thread-unsafe, but this is single-threaded so it's ok
private static class CompilerErrorListener implements FEELEventListener {
FEELEvent evt;
@Override
public void onEvent(FEELEvent feelEvent) {
if (feelEvent.getSeverity() == FEELEvent.Severity.ERROR) {
evt = feelEvent;
}
}
}


}

0 comments on commit 7d7f3a0

Please sign in to comment.