diff --git a/lang/funcs/structs/util.go b/lang/funcs/structs/util.go index a9ebd9e1b3..baedae1dcb 100644 --- a/lang/funcs/structs/util.go +++ b/lang/funcs/structs/util.go @@ -51,18 +51,9 @@ func SimpleFnToDirectFunc(name string, fv *types.FuncValue) interfaces.Func { // *full.FuncValue. func SimpleFnToFuncValue(name string, fv *types.FuncValue) *full.FuncValue { return &full.FuncValue{ - V: func(txn interfaces.Txn, args []interfaces.Func) (interfaces.Func, error) { - wrappedFunc := SimpleFnToDirectFunc(name, fv) - txn.AddVertex(wrappedFunc) - for i, arg := range args { - argName := fv.T.Ord[i] - txn.AddEdge(arg, wrappedFunc, &interfaces.FuncEdge{ - Args: []string{argName}, - }) - } - return wrappedFunc, nil - }, - T: fv.T, + Name: &name, + Timeless: fv, + T: fv.T, } } @@ -76,9 +67,10 @@ func SimpleFnToConstFunc(name string, fv *types.FuncValue) interfaces.Func { // FuncToFullFuncValue creates a *full.FuncValue which adds the given // interfaces.Func to the graph. Note that this means the *full.FuncValue // can only be called once. -func FuncToFullFuncValue(valueTransformingFunc interfaces.Func, typ *types.Type) *full.FuncValue { +func FuncToFullFuncValue(name string, valueTransformingFunc interfaces.Func, typ *types.Type) *full.FuncValue { return &full.FuncValue{ - V: func(txn interfaces.Txn, args []interfaces.Func) (interfaces.Func, error) { + Name: &name, + Timeful: func(txn interfaces.Txn, args []interfaces.Func) (interfaces.Func, error) { for i, arg := range args { argName := typ.Ord[i] txn.AddEdge(arg, valueTransformingFunc, &interfaces.FuncEdge{ @@ -90,3 +82,31 @@ func FuncToFullFuncValue(valueTransformingFunc interfaces.Func, typ *types.Type) T: typ, } } + +// Call calls the function with the provided txn and args. +func CallFuncValue(obj *full.FuncValue, txn interfaces.Txn, args []interfaces.Func) (interfaces.Func, error) { + if obj.Timeful != nil { + return obj.Timeful(txn, args) + } + + wrappedFunc := SimpleFnToDirectFunc(*obj.Name, obj.Timeless) + txn.AddVertex(wrappedFunc) + for i, arg := range args { + argName := obj.T.Ord[i] + txn.AddEdge(arg, wrappedFunc, &interfaces.FuncEdge{ + Args: []string{argName}, + }) + } + return wrappedFunc, nil +} + +// Speculatively call the function with the provided arguments. +// Only makes sense if the function is timeless (produces a single Value, not a +// stream of values). +func CallTimelessFuncValue(obj *full.FuncValue, args []types.Value) (types.Value, error) { + if obj.Timeless != nil { + return obj.Timeless.V(args) + } + + panic("cannot call CallIfTimeless on a Timeful function") +} diff --git a/lang/types/full/full.go b/lang/types/full/full.go index 66c96277b5..d28d032d9d 100644 --- a/lang/types/full/full.go +++ b/lang/types/full/full.go @@ -41,8 +41,10 @@ import ( // went horribly wrong. (Think, an internal panic.) type FuncValue struct { types.Base - V func(interfaces.Txn, []interfaces.Func) (interfaces.Func, error) - T *types.Type // contains ordered field types, arg names are a bonus part + Name *string + Timeful func(interfaces.Txn, []interfaces.Func) (interfaces.Func, error) + Timeless *types.FuncValue + T *types.Type // contains ordered field types, arg names are a bonus part } // String returns a visual representation of this value. @@ -111,8 +113,3 @@ func (obj *FuncValue) Value() interface{} { //val := reflect.MakeFunc(typ, fn) //return val.Interface() } - -// Call calls the function with the provided txn and args. -func (obj *FuncValue) Call(txn interfaces.Txn, args []interfaces.Func) (interfaces.Func, error) { - return obj.V(txn, args) -}