// MultiNode evaluator // // A IN (b,c,d) // func walkMulti(ctx expr.EvalContext, node *expr.MultiArgNode) (value.Value, bool) { a, aok := Eval(ctx, node.Args[0]) //u.Infof("multi: %T:%v %v", a, a, node.Operator) if !aok { u.Infof("Could not evaluate args, %#v", node.Args[0]) return value.BoolValueFalse, false } switch node.Operator.T { case lex.TokenIN: for i := 1; i < len(node.Args); i++ { v, ok := Eval(ctx, node.Args[i]) if ok { //u.Debugf("in? %v %v", a, v) if eq, err := value.Equal(a, v); eq && err == nil { return value.NewBoolValue(true), true } } else { u.Warnf("could not evaluate arg: %v", node.Args[i]) } } return value.NewBoolValue(false), true default: u.Warnf("tri node walk not implemented: %#v", node) } return value.NewNilValue(), false }
func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode) (value.Value, bool) { a, ok := Eval(ctx, node.Arg) if !ok { u.Infof("whoops, %#v", node) return a, false } switch node.Operator.T { case lex.TokenNegate: switch argVal := a.(type) { case value.BoolValue: //u.Infof("found urnary bool: res=%v expr=%v", !argVal.v, node.StringAST()) return value.NewBoolValue(!argVal.Val()), true default: //u.Errorf("urnary type not implementedUnknonwn node type: %T", argVal) panic(ErrUnknownNodeType) } case lex.TokenMinus: if an, aok := a.(value.NumericValue); aok { return value.NewNumberValue(-an.Float()), true } default: u.Warnf("urnary not implemented: %#v", node) } return value.NewNilValue(), false }
func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode) (value.Value, bool) { a, ok := Eval(ctx, node.Arg) if !ok { switch node.Operator.T { case lex.TokenExists: return value.NewBoolValue(false), true case lex.TokenNegate: return value.NewBoolValue(true), true } u.Debugf("unary could not evaluate for[ %s ] and %#v", node.String(), node) return a, false } switch node.Operator.T { case lex.TokenNegate: switch argVal := a.(type) { case value.BoolValue: //u.Debugf("found unary bool: res=%v expr=%v", !argVal.Val(), node) return value.NewBoolValue(!argVal.Val()), true case nil, value.NilValue: return value.NewBoolValue(false), false default: u.LogThrottle(u.WARN, 5, "unary type not implemented. Unknonwn node type: %T:%v node=%s", argVal, argVal, node.String()) return value.NewNilValue(), false } case lex.TokenMinus: if an, aok := a.(value.NumericValue); aok { return value.NewNumberValue(-an.Float()), true } case lex.TokenExists: switch a.(type) { case nil, value.NilValue: return value.NewBoolValue(false), true } if a.Nil() { return value.NewBoolValue(false), true } return value.NewBoolValue(true), true default: u.Warnf("urnary not implemented for type %s %#v", node.Operator.T.String(), node) } return value.NewNilValue(), false }
// TriNode evaluator // // A BETWEEN B AND C // func walkTri(ctx expr.EvalContext, node *expr.TriNode) (value.Value, bool) { a, aok := Eval(ctx, node.Args[0]) b, bok := Eval(ctx, node.Args[1]) c, c*k := Eval(ctx, node.Args[2]) //u.Infof("tri: %T:%v %v %T:%v %T:%v", a, a, node.Operator, b, b, c, c) if !aok { return value.BoolValueFalse, false } if !bok || !c*k { u.Debugf("Could not evaluate args, %#v", node.String()) return value.BoolValueFalse, false } if a == nil || b == nil || c == nil { return value.BoolValueFalse, false } switch node.Operator.T { case lex.TokenBetween: switch a.Type() { case value.IntType: //u.Infof("found tri: %v %v %v expr=%v", a, b, c, node.StringAST()) if aiv, ok := a.(value.IntValue); ok { if biv, ok := b.(value.IntValue); ok { if civ, ok := c.(value.IntValue); ok { if aiv.Int() > biv.Int() && aiv.Int() < civ.Int() { return value.NewBoolValue(true), true } else { return value.NewBoolValue(false), true } } } } return value.BoolValueFalse, false case value.NumberType: //u.Infof("found tri: %v %v %v expr=%v", a, b, c, node.StringAST()) if afv, ok := a.(value.NumberValue); ok { if bfv, ok := b.(value.NumberValue); ok { if cfv, ok := c.(value.NumberValue); ok { if afv.Float() > bfv.Float() && afv.Float() < cfv.Float() { return value.NewBoolValue(true), false } else { return value.NewBoolValue(false), true } } } } return value.BoolValueFalse, false default: u.Warnf("between not implemented for type %s %#v", a.Type().String(), node) } default: u.Warnf("tri node walk not implemented: %#v", node) } return value.NewNilValue(), false }
func Eval(ctx expr.EvalContext, arg expr.Node) (value.Value, bool) { //u.Debugf("Eval() node=%T %v", arg, arg) // can we switch to arg.Type() switch argVal := arg.(type) { case *expr.NumberNode: return numberNodeToValue(argVal) case *expr.BinaryNode: return walkBinary(ctx, argVal) case *expr.UnaryNode: return walkUnary(ctx, argVal) case *expr.TriNode: return walkTri(ctx, argVal) case *expr.ArrayNode: return walkArray(ctx, argVal) case *expr.FuncNode: return walkFunc(ctx, argVal) case *expr.IdentityNode: return walkIdentity(ctx, argVal) case *expr.StringNode: return value.NewStringValue(argVal.Text), true case nil: return nil, false case *expr.NullNode: // WHERE (`users.user_id` != NULL) return value.NewNilValue(), true case *expr.ValueNode: if argVal.Value == nil { return nil, false } switch val := argVal.Value.(type) { case *value.NilValue, value.NilValue: return nil, false case value.SliceValue: //u.Warnf("got slice? %#v", argVal) return val, true } u.Errorf("Unknonwn node type: %#v", argVal.Value) panic(ErrUnknownNodeType) default: u.Errorf("Unknonwn node type: %#v", arg) panic(ErrUnknownNodeType) } }
func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode) (value.Value, bool) { a, ok := Eval(ctx, node.Arg) if !ok { if node.Operator.T == lex.TokenExists { return value.NewBoolValue(false), true } u.Debugf("unary could not evaluate %#v", node) return a, false } switch node.Operator.T { case lex.TokenNegate: switch argVal := a.(type) { case value.BoolValue: //u.Infof("found unary bool: res=%v expr=%v", !argVal.v, node.StringAST()) return value.NewBoolValue(!argVal.Val()), true case nil, value.NilValue: return value.NewBoolValue(false), false default: u.Errorf("unary type not implemented. Unknonwn node type: %T:%v", argVal, argVal) panic(ErrUnknownNodeType) } case lex.TokenMinus: if an, aok := a.(value.NumericValue); aok { return value.NewNumberValue(-an.Float()), true } case lex.TokenExists: switch a.(type) { case nil, value.NilValue: return value.NewBoolValue(false), true } return value.NewBoolValue(true), true default: u.Warnf("urnary not implemented for type %s %#v", node.Operator.T.String(), node) } return value.NewNilValue(), false }
func walkFunc(ctx expr.EvalContext, node *expr.FuncNode) (value.Value, bool) { //u.Debugf("walkFunc node: %v", node.StringAST()) // we create a set of arguments to pass to the function, first arg // is this Context var ok bool funcArgs := make([]reflect.Value, 0) if ctx != nil { funcArgs = append(funcArgs, reflect.ValueOf(ctx)) } else { var nilArg expr.EvalContext funcArgs = append(funcArgs, reflect.ValueOf(&nilArg).Elem()) } for _, a := range node.Args { //u.Debugf("arg %v %T %v", a, a, a) var v interface{} switch t := a.(type) { case *expr.StringNode: // String Literal v = value.NewStringValue(t.Text) case *expr.IdentityNode: // Identity node = lookup in context if t.IsBooleanIdentity() { v = value.NewBoolValue(t.Bool()) } else { v, ok = ctx.Get(t.Text) //u.Infof("%#v", ctx.Row()) //u.Debugf("get '%s'? %T %v %v", t.String(), v, v, ok) if !ok { // nil arguments are valid v = value.NewNilValue() } } case *expr.NumberNode: v, ok = numberNodeToValue(t) case *expr.FuncNode: //u.Debugf("descending to %v()", t.Name) v, ok = walkFunc(ctx, t) if !ok { //return value.NewNilValue(), false // nil arguments are valid v = value.NewNilValue() } //u.Debugf("result of %v() = %v, %T", t.Name, v, v) case *expr.UnaryNode: v, ok = walkUnary(ctx, t) if !ok { // nil arguments are valid ?? v = value.NewNilValue() } case *expr.BinaryNode: v, ok = walkBinary(ctx, t) case *expr.ValueNode: v = t.Value default: panic(fmt.Errorf("expr: unknown func arg type")) } if v == nil { //u.Warnf("Nil vals? %v %T arg:%T", v, v, a) // What do we do with Nil Values? switch a.(type) { case *expr.StringNode: // String Literal u.Warnf("NOT IMPLEMENTED T:%T v:%v", a, a) case *expr.IdentityNode: // Identity node = lookup in context v = value.NewStringValue("") default: u.Warnf("un-handled type: %v %T", v, v) } funcArgs = append(funcArgs, reflect.ValueOf(v)) } else { //u.Debugf(`found func arg: "%v" %T arg:%T`, v, v, a) funcArgs = append(funcArgs, reflect.ValueOf(v)) } } // Get the result of calling our Function (Value,bool) //u.Debugf("Calling func:%v(%v) %v", node.F.Name, funcArgs, node.F.F) fnRet := node.F.F.Call(funcArgs) //u.Debugf("fnRet: %v ok?%v", fnRet, fnRet[1].Bool()) // check if has an error response? if len(fnRet) > 1 && !fnRet[1].Bool() { // What do we do if not ok? return value.EmptyStringValue, false } //u.Debugf("response %v %v %T", node.F.Name, fnRet[0].Interface(), fnRet[0].Interface()) return fnRet[0].Interface().(value.Value), true }