123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package govaluate
- import (
- "errors"
- "fmt"
- )
- const isoDateFormat string = "2006-01-02T15:04:05.999999999Z0700"
- const shortCircuitHolder int = -1
- var DUMMY_PARAMETERS = MapParameters(map[string]interface{}{})
- type EvaluableExpression struct {
-
- QueryDateFormat string
-
- ChecksTypes bool
- tokens []ExpressionToken
- evaluationStages *evaluationStage
- inputExpression string
- }
- func NewEvaluableExpression(expression string) (*EvaluableExpression, error) {
- functions := make(map[string]ExpressionFunction)
- return NewEvaluableExpressionWithFunctions(expression, functions)
- }
- func NewEvaluableExpressionFromTokens(tokens []ExpressionToken) (*EvaluableExpression, error) {
- var ret *EvaluableExpression
- var err error
- ret = new(EvaluableExpression)
- ret.QueryDateFormat = isoDateFormat
- err = checkBalance(tokens)
- if err != nil {
- return nil, err
- }
- err = checkExpressionSyntax(tokens)
- if err != nil {
- return nil, err
- }
- ret.tokens, err = optimizeTokens(tokens)
- if err != nil {
- return nil, err
- }
- ret.evaluationStages, err = planStages(ret.tokens)
- if err != nil {
- return nil, err
- }
- ret.ChecksTypes = true
- return ret, nil
- }
- func NewEvaluableExpressionWithFunctions(expression string, functions map[string]ExpressionFunction) (*EvaluableExpression, error) {
- var ret *EvaluableExpression
- var err error
- ret = new(EvaluableExpression)
- ret.QueryDateFormat = isoDateFormat
- ret.inputExpression = expression
- ret.tokens, err = parseTokens(expression, functions)
- if err != nil {
- return nil, err
- }
- err = checkBalance(ret.tokens)
- if err != nil {
- return nil, err
- }
- err = checkExpressionSyntax(ret.tokens)
- if err != nil {
- return nil, err
- }
- ret.tokens, err = optimizeTokens(ret.tokens)
- if err != nil {
- return nil, err
- }
- ret.evaluationStages, err = planStages(ret.tokens)
- if err != nil {
- return nil, err
- }
- ret.ChecksTypes = true
- return ret, nil
- }
- func (this EvaluableExpression) Evaluate(parameters map[string]interface{}) (interface{}, error) {
- if parameters == nil {
- return this.Eval(nil)
- }
- return this.Eval(MapParameters(parameters))
- }
- func (this EvaluableExpression) Eval(parameters Parameters) (interface{}, error) {
- if this.evaluationStages == nil {
- return nil, nil
- }
- if parameters != nil {
- parameters = &sanitizedParameters{parameters}
- }
- return this.evaluateStage(this.evaluationStages, parameters)
- }
- func (this EvaluableExpression) evaluateStage(stage *evaluationStage, parameters Parameters) (interface{}, error) {
- var left, right interface{}
- var err error
- if stage.leftStage != nil {
- left, err = this.evaluateStage(stage.leftStage, parameters)
- if err != nil {
- return nil, err
- }
- }
- if stage.isShortCircuitable() {
- switch stage.symbol {
- case AND:
- if left == false {
- return false, nil
- }
- case OR:
- if left == true {
- return true, nil
- }
- case COALESCE:
- if left != nil {
- return left, nil
- }
-
- case TERNARY_TRUE:
- if left == false {
- right = shortCircuitHolder
- }
- case TERNARY_FALSE:
- if left != nil {
- right = shortCircuitHolder
- }
- }
- }
- if right != shortCircuitHolder && stage.rightStage != nil {
- right, err = this.evaluateStage(stage.rightStage, parameters)
- if err != nil {
- return nil, err
- }
- }
- if this.ChecksTypes {
- if stage.typeCheck == nil {
- err = typeCheck(stage.leftTypeCheck, left, stage.symbol, stage.typeErrorFormat)
- if err != nil {
- return nil, err
- }
- err = typeCheck(stage.rightTypeCheck, right, stage.symbol, stage.typeErrorFormat)
- if err != nil {
- return nil, err
- }
- } else {
-
- if !stage.typeCheck(left, right) {
- errorMsg := fmt.Sprintf(stage.typeErrorFormat, left, stage.symbol.String())
- return nil, errors.New(errorMsg)
- }
- }
- }
- return stage.operator(left, right, parameters)
- }
- func typeCheck(check stageTypeCheck, value interface{}, symbol OperatorSymbol, format string) error {
- if check == nil {
- return nil
- }
- if check(value) {
- return nil
- }
- errorMsg := fmt.Sprintf(format, value, symbol.String())
- return errors.New(errorMsg)
- }
- func (this EvaluableExpression) Tokens() []ExpressionToken {
- return this.tokens
- }
- func (this EvaluableExpression) String() string {
- return this.inputExpression
- }
- func (this EvaluableExpression) Vars() []string {
- var varlist []string
- for _, val := range this.Tokens() {
- if val.Kind == VARIABLE {
- varlist = append(varlist, val.Value.(string))
- }
- }
- return varlist
- }
|