Skip to content

Commit

Permalink
Implemented AND/OR short-circuit
Browse files Browse the repository at this point in the history
  • Loading branch information
Knetic committed May 1, 2017
1 parent f9425c5 commit 9f400ba
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 2 deletions.
17 changes: 17 additions & 0 deletions EvaluableExpression.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ func (this EvaluableExpression) evaluateStage(stage *evaluationStage, parameters

var left, right interface{}
var err error
var shortResult bool

if stage.leftStage != nil {
left, err = this.evaluateStage(stage.leftStage, parameters)
Expand All @@ -170,6 +171,22 @@ func (this EvaluableExpression) evaluateStage(stage *evaluationStage, parameters
}
}

if stage.isShortCircuitable() && isBool(left) {

shortResult = left.(bool)

switch stage.symbol {
case AND:
if !shortResult {
return false, nil
}
case OR:
if shortResult {
return true, nil
}
}
}

if stage.rightStage != nil {
right, err = this.evaluateStage(stage.rightStage, parameters)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions evaluationFailure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ func TestLogicalOperatorTyping(test *testing.T) {
},
EvaluationFailureTest{

Name: "OR bool to string",
Input: "bool || string",
Name: "OR string to bool",
Input: "string || bool",
Expected: INVALID_LOGICALOP_TYPES,
},
}
Expand Down
18 changes: 18 additions & 0 deletions evaluationStage.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ func (this *evaluationStage) setToNonStage(other evaluationStage) {
this.typeErrorFormat = other.typeErrorFormat
}

func (this *evaluationStage) isShortCircuitable() bool {

switch this.symbol {
case AND:
fallthrough
case OR:
fallthrough
case TERNARY_TRUE:
fallthrough
case TERNARY_FALSE:
fallthrough
case COALESCE:
return true
}

return false
}

func noopStageRight(left interface{}, right interface{}, parameters Parameters) (interface{}, error) {
return right, nil
}
Expand Down
23 changes: 23 additions & 0 deletions evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"
"regexp"
"testing"
"errors"
)

/*
Expand Down Expand Up @@ -1227,6 +1228,28 @@ func TestParameterizedEvaluation(test *testing.T) {

Expected: "2awesome",
},
EvaluationTest{

Name: "Short-circuit OR",
Input: "true || fail()",
Functions: map[string]ExpressionFunction{
"fail": func(arguments ...interface{}) (interface{}, error) {
return nil, errors.New("Did not short-circuit")
},
},
Expected: true,
},
EvaluationTest{

Name: "Short-circuit AND",
Input: "false && fail()",
Functions: map[string]ExpressionFunction{
"fail": func(arguments ...interface{}) (interface{}, error) {
return nil, errors.New("Did not short-circuit")
},
},
Expected: false,
},
}

runEvaluationTests(evaluationTests, test)
Expand Down

0 comments on commit 9f400ba

Please sign in to comment.