Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions expression-src/main/api/Configuration.cls
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ global with sharing class Configuration {
global Boolean printAst = false;
global Map<String, Object> customContext = new Map<String, Object>();
public Boolean withDiagnostics = false;
global Boolean suppressErrors = false;

global Configuration respectSharing(Boolean respect) {
sharing = respect ? SharingMode.WITH : SharingMode.WITHOUT;
Expand All @@ -33,6 +34,11 @@ global with sharing class Configuration {
return this;
}

global Configuration suppressErrors() {
suppressErrors = true;
return this;
}

public void subscribe(EvaluatorEventNotifier notifier) {
// Always subscribe to the event that sets the sharing mode
// at the beginning of the evaluation regardless of configuration.
Expand Down
12 changes: 12 additions & 0 deletions expression-src/main/api/tests/ConfigurationTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,16 @@ private class ConfigurationTest {
Configuration config = new Configuration().withCustomContext(null);
Assert.isTrue(config.customContext.isEmpty());
}

@IsTest
static void suppressErrorsDefaultsToFalse() {
Configuration config = new Configuration();
Assert.isFalse(config.suppressErrors);
}

@IsTest
static void canEnableSuppressErrors() {
Configuration config = new Configuration().suppressErrors();
Assert.isTrue(config.suppressErrors);
}
}
32 changes: 32 additions & 0 deletions expression-src/main/api/tests/EvaluatorRetrieveRecordTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,36 @@ private class EvaluatorRetrieveRecordTest {
System.assertEquals(null, resultWithNullId, 'Should return null with null recordId');
Test.stopTest();
}

@IsTest
static void testSuppressErrorsReturnEmptyString() {
Test.startTest();
Object result = Evaluator.run('"a" & 1', new Configuration().suppressErrors());
Test.stopTest();

System.assertEquals('', result, 'Should return empty string when errors are suppressed');
}

@IsTest
static void testSuppressErrorsWithValidExpression() {
Test.startTest();
Object result = Evaluator.run('"Hello World"', new Configuration().suppressErrors());
Test.stopTest();

System.assertEquals('Hello World', result, 'Should return correct result when no errors occur');
}

@IsTest
static void testWithoutSuppressErrorsThrowsException() {
Test.startTest();
Boolean exceptionThrown = false;
try {
Evaluator.run('"a" & 1', new Configuration());
} catch (Exception e) {
exceptionThrown = true;
}
Test.stopTest();

System.assertTrue(exceptionThrown, 'Should throw exception when errors are not suppressed');
}
}
64 changes: 37 additions & 27 deletions expression-src/main/src/resolver/EvaluatorResolver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -77,36 +77,46 @@ public with sharing abstract class EvaluatorResolver {

eventNotifier.notify(new OnEvaluationStartEvent(config));

List<Token> tokens = this.scan(input);
List<Expr> parsedExpressions = this.parse(tokens);

eventNotifier.notify(new OnAfterParseEvent(parsedExpressions));

List<Expr> pipedExpressions = this.desugarPipe(parsedExpressions);

// This deals with the global environment, which is shared across all evaluations, so it
// it safe to call outside of the loop.
addCustomContextVariablesToGlobalEnvironment(config);
// We only care about the result of the last interpreted expression.
// We assume that the previous results are declarations.
Object result = null;
List<Expr.FunctionDeclaration> customFunctionDeclarations = new List<Expr.FunctionDeclaration>();
for (Expr pipedExpression : pipedExpressions) {
if (isFunctionDeclaration(pipedExpression)) {
// If we are dealing with a function declaration we do not need to interpret it.
Expr.FunctionDeclaration fnDeclaration = (Expr.FunctionDeclaration) pipedExpression;
Environment.addGlobalVariable(fnDeclaration.functionName, fnDeclaration);
customFunctionDeclarations.add(fnDeclaration);
continue;
}
try {
List<Token> tokens = this.scan(input);
List<Expr> parsedExpressions = this.parse(tokens);

eventNotifier.notify(new OnAfterParseEvent(parsedExpressions));

List<Expr> pipedExpressions = this.desugarPipe(parsedExpressions);

// This deals with the global environment, which is shared across all evaluations, so it
// it safe to call outside of the loop.
addCustomContextVariablesToGlobalEnvironment(config);
// We only care about the result of the last interpreted expression.
// We assume that the previous results are declarations.
Object result = null;
List<Expr.FunctionDeclaration> customFunctionDeclarations = new List<Expr.FunctionDeclaration>();
for (Expr pipedExpression : pipedExpressions) {
if (isFunctionDeclaration(pipedExpression)) {
// If we are dealing with a function declaration we do not need to interpret it.
Expr.FunctionDeclaration fnDeclaration = (Expr.FunctionDeclaration) pipedExpression;
Environment.addGlobalVariable(fnDeclaration.functionName, fnDeclaration);
customFunctionDeclarations.add(fnDeclaration);
continue;
}

Environment anEnvironment = this.prepareEnvironment(pipedExpression, customFunctionDeclarations);
result = this.interpret(anEnvironment, pipedExpression);
}
Environment anEnvironment = this.prepareEnvironment(pipedExpression, customFunctionDeclarations);
result = this.interpret(anEnvironment, pipedExpression);
}

eventNotifier.notify(new OnEvaluationEndEvent());
eventNotifier.notify(new OnEvaluationEndEvent());

return new EvaluationResult(result, additionalResultData);
return new EvaluationResult(result, additionalResultData);
} catch (Exception e) {
eventNotifier.notify(new OnEvaluationEndEvent());

if (config.suppressErrors) {
return new EvaluationResult('', additionalResultData);
} else {
throw e;
}
}
}

private static void addCustomContextVariablesToGlobalEnvironment(Configuration config) {
Expand Down