func (v *evalOutput) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { // The expressions should all be on the stack in reverse // order. So pop them off, reverse their order, and concatenate. nodes := make([]*ast.LiteralNode, 0, len(v.Exprs)) for range v.Exprs { nodes = append(nodes, stack.Pop().(*ast.LiteralNode)) } // Special case the single list and map if len(nodes) == 1 { switch t := nodes[0].Typex; t { case ast.TypeList: fallthrough case ast.TypeMap: fallthrough case ast.TypeUnknown: return nodes[0].Value, t, nil } } // Otherwise concatenate the strings var buf bytes.Buffer for i := len(nodes) - 1; i >= 0; i-- { buf.WriteString(nodes[i].Value.(string)) } return buf.String(), ast.TypeString, nil }
func (v *evalConditional) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { // On the stack we have literal nodes representing the resulting values // of the condition, true and false expressions, but they are in reverse // order. falseLit := stack.Pop().(*ast.LiteralNode) trueLit := stack.Pop().(*ast.LiteralNode) condLit := stack.Pop().(*ast.LiteralNode) if condLit.Value.(bool) { return trueLit.Value, trueLit.Typex, nil } else { return falseLit.Value, trueLit.Typex, nil } }
func (v *evalConcat) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { // The expressions should all be on the stack in reverse // order. So pop them off, reverse their order, and concatenate. nodes := make([]*ast.LiteralNode, 0, len(v.Exprs)) for range v.Exprs { nodes = append(nodes, stack.Pop().(*ast.LiteralNode)) } var buf bytes.Buffer for i := len(nodes) - 1; i >= 0; i-- { buf.WriteString(nodes[i].Value.(string)) } return buf.String(), ast.TypeString, nil }
func (v *evalIndex) Eval(scope ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { key := stack.Pop().(*ast.LiteralNode) target := stack.Pop().(*ast.LiteralNode) variableName := v.Index.Target.(*ast.VariableAccess).Name switch target.Typex { case ast.TypeList: return v.evalListIndex(variableName, target.Value, key.Value) case ast.TypeMap: return v.evalMapIndex(variableName, target.Value, key.Value) default: return nil, ast.TypeInvalid, fmt.Errorf( "target %q for indexing must be ast.TypeList or ast.TypeMap, is %s", variableName, target.Typex) } }
func (v *evalCall) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { // Look up the function in the map function, ok := s.LookupFunc(v.Func) if !ok { return nil, ast.TypeInvalid, fmt.Errorf( "unknown function called: %s", v.Func) } // The arguments are on the stack in reverse order, so pop them off. args := make([]interface{}, len(v.Args)) for i, _ := range v.Args { node := stack.Pop().(*ast.LiteralNode) args[len(v.Args)-1-i] = node.Value } // Call the function result, err := function.Callback(args) if err != nil { return nil, ast.TypeInvalid, fmt.Errorf("%s: %s", v.Func, err) } return result, function.ReturnType, nil }