From db9a73d0dc7035e63ea0e2f7863743b9d42d56ae Mon Sep 17 00:00:00 2001 From: bhare Date: Fri, 12 Oct 2018 21:33:26 -0400 Subject: [PATCH] Added Meta tag to Tokens to store the baked-in function names. --- EvaluableExpression.go | 14 +++++--------- ExpressionToken.go | 1 + evaluationFailure_test.go | 19 ++++++++++++------- parsing.go | 27 +++++++++++++++++---------- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/EvaluableExpression.go b/EvaluableExpression.go index 7ba2e31..09ae0fd 100644 --- a/EvaluableExpression.go +++ b/EvaluableExpression.go @@ -265,20 +265,16 @@ func (this EvaluableExpression) String() string { var expressionText string for _, val := range this.Tokens() { switch val.Kind { - case CLAUSE: - expressionText += fmt.Sprintf("%+v", "(") - case CLAUSE_CLOSE: - expressionText += fmt.Sprintf("%+v", ")") case VARIABLE: - expressionText += fmt.Sprintf("[%+v]", val.Value) + expressionText += fmt.Sprintf("[%+v]", val.Meta) case STRING, TIME: - expressionText += fmt.Sprintf("'%+v'", val.Value) + expressionText += fmt.Sprintf("'%+v'", val.Meta) case COMPARATOR, LOGICALOP, MODIFIER, TERNARY: - expressionText += fmt.Sprintf(" %+v ", val.Value) + expressionText += fmt.Sprintf(" %+v ", val.Meta) case SEPARATOR: - expressionText += fmt.Sprintf("%+v ", val.Value) + expressionText += fmt.Sprintf("%+v ", val.Meta) default: - expressionText += fmt.Sprintf("%+v", val.Value) + expressionText += fmt.Sprintf("%+v", val.Meta) } } diff --git a/ExpressionToken.go b/ExpressionToken.go index f849f38..e559133 100644 --- a/ExpressionToken.go +++ b/ExpressionToken.go @@ -6,4 +6,5 @@ package govaluate type ExpressionToken struct { Kind TokenKind Value interface{} + Meta interface{} } diff --git a/evaluationFailure_test.go b/evaluationFailure_test.go index e551b5f..7f4f76a 100644 --- a/evaluationFailure_test.go +++ b/evaluationFailure_test.go @@ -46,14 +46,19 @@ var EVALUATION_FAILURE_PARAMETERS = map[string]interface{}{ } func TestFullCycle(test *testing.T) { - currentExpressionString := "2 > 1 &&" + - "'something' != 'nothing' || (1,2,3) != (3,2,1) ||" + - "'2014-01-20' < 'Wed Jul 8 23:07:35 MDT 2015' && " + - "[escapedVariable name with spaces] <= unescaped\\-variableName &&" + - "modifierTest + 1000 / 2 > (80 * 100 % 2) && true ? true : false" + currentExpressionString := "2 > 1 && " + + "'something' != 'nothing' || (1,2,3) != (3,2,1) || " + + "func1(1337,'leet',sawce) < 'Wed Jul 8 23:07:35 MDT 2015' && " + + "[escapedVariable name with spaces] <= unescaped\\-variableName && " + + "modifierTest + 0xa3a2b3 / 2 > (80 * 100 % 2) && true ? true : false" + extraFuncs := map[string]ExpressionFunction{ + "func1": func(args ...interface{}) (interface{}, error) { + return "2014-01-20", nil + }, + } var initialExpression, cycledExpression, finalExpression *EvaluableExpression - initialExpression, err := NewEvaluableExpression(currentExpressionString) + initialExpression, err := NewEvaluableExpressionWithFunctions(currentExpressionString, extraFuncs) if err != nil { test.Errorf("Failed to build expression from string... ERROR: %+v", err) } @@ -61,7 +66,7 @@ func TestFullCycle(test *testing.T) { if err != nil { test.Errorf("Failed to build expression from tokens, from string... ERROR: %+v", err) } - temp2, err := NewEvaluableExpression(cycledExpression.String()) + temp2, err := NewEvaluableExpressionWithFunctions(cycledExpression.String(), extraFuncs) if err != nil { test.Errorf("Failed to build expression from string, from tokens, from string... ERROR: %+v", err) } diff --git a/parsing.go b/parsing.go index 40c7ed2..bf080d3 100644 --- a/parsing.go +++ b/parsing.go @@ -64,6 +64,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre var found bool var completed bool var err error + var meta interface{} // numeric is 0-9, or . or 0x followed by digits // string starts with ' @@ -79,6 +80,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre continue } + meta = character kind = UNKNOWN // numeric constant @@ -96,6 +98,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre return ExpressionToken{}, errors.New(errorMsg), false } + meta = "0x" + tokenString kind = NUMERIC tokenValue = float64(tokenValueInt) break @@ -111,6 +114,8 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre errorMsg := fmt.Sprintf("Unable to parse numeric value '%v' to float64\n", tokenString) return ExpressionToken{}, errors.New(errorMsg), false } + + meta = tokenString kind = NUMERIC break } @@ -119,6 +124,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre if character == ',' { tokenValue = "," + meta = tokenValue kind = SEPARATOR break } @@ -127,6 +133,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre if character == '[' { tokenValue, completed = readUntilFalse(stream, true, false, true, isNotClosingBracket) + meta = tokenValue kind = VARIABLE if !completed { @@ -142,22 +149,15 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre if unicode.IsLetter(character) { tokenString = readTokenUntilFalse(stream, isVariableName) - + meta = tokenString tokenValue = tokenString kind = VARIABLE // boolean? - if tokenValue == "true" { + if tokenValue == "true" || tokenValue == "false" { kind = BOOLEAN - tokenValue = true - } else { - - if tokenValue == "false" { - - kind = BOOLEAN - tokenValue = false - } + tokenValue = tokenValue == "true" } // textual operator? @@ -205,6 +205,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre if !isNotQuote(character) { tokenValue, completed = readUntilFalse(stream, true, false, true, isNotQuote) + meta = tokenValue if !completed { return ExpressionToken{}, errors.New("Unclosed string literal"), false @@ -225,12 +226,16 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre } if character == '(' { + + meta = "(" tokenValue = character kind = CLAUSE break } if character == ')' { + + meta = ")" tokenValue = character kind = CLAUSE_CLOSE break @@ -238,6 +243,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre // must be a known symbol tokenString = readTokenUntilFalse(stream, isNotAlphanumeric) + meta = tokenString tokenValue = tokenString // quick hack for the case where "-" can mean "prefixed negation" or "minus", which are used @@ -284,6 +290,7 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre ret.Kind = kind ret.Value = tokenValue + ret.Meta = meta return ret, nil, (kind != UNKNOWN) }