go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/nodes/pkg/funcs/expression.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package funcs 9 10 import ( 11 "context" 12 "fmt" 13 14 "github.com/wcharczuk/go-incr" 15 "go.starlark.net/starlark" 16 17 "go.charczuk.com/sdk/errutil" 18 19 "go.charczuk.com/projects/nodes/pkg/incrutil" 20 ) 21 22 // Expression returns a function that evaluates a given expression. 23 func Expression[Input, Output any](expression string) func(context.Context, *incrutil.Inputs[Input]) (Output, error) { 24 return func(ctx context.Context, inputs *incrutil.Inputs[Input]) (output Output, err error) { 25 defer func() { 26 if r := recover(); r != nil { 27 err = errutil.New(r) 28 } 29 }() 30 31 inputFunc := createInputFunc(inputs) 32 var builtins = starlark.StringDict{ 33 "input": starlark.NewBuiltin("input", inputFunc), 34 } 35 for k, v := range defaultBuiltins { 36 builtins[k] = v 37 } 38 thread := new(starlark.Thread) 39 if tracer := incr.GetTracer(ctx); tracer != nil { 40 thread.Print = func(_ *starlark.Thread, msg string) { 41 tracer.Print("expression:", msg) 42 } 43 } 44 var sd starlark.StringDict 45 sd, err = starlark.ExecFileOptions(&expressionFileOptions, thread, "<expr>", expression, builtins) 46 if err != nil { 47 return 48 } 49 if sd == nil { 50 return 51 } 52 v, ok := sd["output"] 53 if !ok { 54 err = fmt.Errorf("expression: you must use the `output` global to set the output") 55 return 56 } 57 if v == nil { 58 return 59 } 60 switch typed := v.(type) { 61 case *starlark.Dict: 62 output, err = starlarkDictToOutput[Output](typed) 63 case *starlark.List: 64 output, err = starlarkListToOutput[Output](typed) 65 default: 66 output, err = starlarkScalarToOutput[Output](v) 67 } 68 return 69 } 70 }