diff --git a/bind-expr-functions.go b/bind-expr-functions.go index b621a46..f39d5fc 100644 --- a/bind-expr-functions.go +++ b/bind-expr-functions.go @@ -17,19 +17,31 @@ type exprFunctor struct { // } func newExprFunctor(e Expr, params []ExprFuncParam, ctx ExprContext) *exprFunctor { - return &exprFunctor{expr: e, params: params, defCtx: ctx} + var defCtx ExprContext + if ctx != nil { +// if ctx.GetParent() != nil { +// defCtx = ctx.Clone() +// defCtx.SetParent(ctx) +// } else { + defCtx = ctx +// } + } + return &exprFunctor{expr: e, params: params, defCtx: defCtx} +} + +func (functor *exprFunctor) GetDefinitionContext() ExprContext { + return functor.defCtx } func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) { - if functor.defCtx != nil { - ctx.Merge(functor.defCtx) - } + // if functor.defCtx != nil { + // ctx.Merge(functor.defCtx) + // } for i, p := range functor.params { if i < len(args) { arg := args[i] if funcArg, ok := arg.(Functor); ok { - // ctx.RegisterFunc(p, functor, 0, -1) paramSpecs := funcArg.GetParams() ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs) } else { @@ -42,17 +54,3 @@ func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (re result, err = functor.expr.Eval(ctx) return } - -// func CallExprFunction(parentCtx ExprContext, funcName string, params ...any) (v any, err error) { -// ctx := cloneContext(parentCtx) -// ctx.SetParent(parentCtx) - -// if err == nil { -// if err = checkFunctionCall(ctx, funcName, ¶ms); err == nil { -// if v, err = ctx.Call(funcName, params); err == nil { -// exportObjects(parentCtx, ctx) -// } -// } -// } -// return -// } diff --git a/context.go b/context.go index 20ae49b..c756f72 100644 --- a/context.go +++ b/context.go @@ -10,6 +10,7 @@ type Functor interface { SetFunc(info ExprFunc) GetFunc() ExprFunc GetParams() []ExprFuncParam + GetDefinitionContext() ExprContext } // ---- Function Param Info @@ -31,6 +32,8 @@ type ExprFunc interface { Functor() Functor Params() []ExprFuncParam ReturnType() string + PrepareCall(parentCtx ExprContext, name string, varParams *[]any) (ctx ExprContext, err error) + AllocContext(parentCtx ExprContext) (ctx ExprContext) } // ----Expression Context diff --git a/function.go b/function.go index 7c20ef6..8800abc 100644 --- a/function.go +++ b/function.go @@ -21,7 +21,7 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) { if functor.info != nil { s = functor.info.ToString(opt) } else { - s = "func() {}" + s = "func(){}" } return s } @@ -42,6 +42,10 @@ func (functor *baseFunctor) GetFunc() ExprFunc { return functor.info } +func (functor *baseFunctor) GetDefinitionContext() ExprContext { + return nil +} + // ---- Function Parameters type paramFlags uint16 @@ -94,13 +98,15 @@ func (param *funcParamInfo) DefaultValue() any { } // --- Functions + +// funcInfo implements ExprFunc type funcInfo struct { - name string - minArgs int - maxArgs int - functor Functor - params []ExprFuncParam - returnType string + name string + minArgs int + maxArgs int + functor Functor + formalParams []ExprFuncParam + returnType string } func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) { @@ -126,7 +132,7 @@ func newFuncInfo(name string, functor Functor, returnType string, params []ExprF } } info = &funcInfo{ - name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, params: params, + name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params, } functor.SetFunc(info) return info, nil @@ -137,7 +143,7 @@ func newUnnamedFuncInfo(functor Functor, returnType string, params []ExprFuncPar } func (info *funcInfo) Params() []ExprFuncParam { - return info.params + return info.formalParams } func (info *funcInfo) ReturnType() string { @@ -152,8 +158,8 @@ func (info *funcInfo) ToString(opt FmtOpt) string { sb.WriteString(info.Name()) } sb.WriteByte('(') - if info.params != nil { - for i, p := range info.params { + if info.formalParams != nil { + for i, p := range info.formalParams { if i > 0 { sb.WriteString(", ") } @@ -180,7 +186,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string { } else { sb.WriteString(TypeAny) } - sb.WriteString(" {}") + sb.WriteString("{}") return sb.String() } @@ -200,41 +206,52 @@ func (info *funcInfo) Functor() Functor { return info.functor } +func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) { + if defCtx := info.functor.GetDefinitionContext(); defCtx != nil { + ctx = defCtx.Clone() + ctx.SetParent(defCtx) + } else { + ctx = parentCtx.Clone() + ctx.SetParent(parentCtx) + } + return +} + +func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, varActualParams *[]any) (ctx ExprContext, err error) { + passedCount := len(*varActualParams) + if info.MinArgs() > passedCount { + err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) + } + + for i := passedCount; i < len(info.formalParams); i++ { + p := info.formalParams[i] + if !p.IsDefault() { + break + } + *varActualParams = append(*varActualParams, p.DefaultValue()) + } + if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varActualParams) { + err = ErrTooMuchParams(name, info.MaxArgs(), len(*varActualParams)) + } + + if err == nil { + ctx = info.AllocContext(parentCtx) + } + return +} + // ----- Call a function --- -func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) { - if info, exists, owner := GetFuncInfo(ctx, name); exists { - passedCount := len(*varParams) - if info.MinArgs() > passedCount { - err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) - } - for i, p := range info.Params() { - if i >= passedCount { - if !p.IsDefault() { - break - } - *varParams = append(*varParams, p.DefaultValue()) - } - } - if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) { - err = ErrTooMuchParams(name, info.MaxArgs(), len(*varParams)) - } - if err == nil && owner != ctx { - ctx.RegisterFuncInfo(info) +func CallFunction(parentCtx ExprContext, name string, actualParams []any) (result any, err error) { + if info, exists, _ := GetFuncInfo(parentCtx, name); exists { + var ctx ExprContext + if ctx, err = info.PrepareCall(parentCtx, name, &actualParams); err == nil { + functor := info.Functor() + result, err = functor.Invoke(ctx, name, actualParams) + exportObjectsToParent(ctx) } } else { err = fmt.Errorf("unknown function %s()", name) } return } - -func CallFunction(parentCtx ExprContext, name string, params []any) (result any, err error) { - ctx := cloneContext(parentCtx) - ctx.SetParent(parentCtx) - - if err = checkFunctionCall(ctx, name, ¶ms); err == nil { - result, err = ctx.Call(name, params) - exportObjectsToParent(ctx) - } - return -} diff --git a/simple-store.go b/simple-store.go index a626274..0153e91 100644 --- a/simple-store.go +++ b/simple-store.go @@ -36,10 +36,11 @@ func (ctx *SimpleStore) GetParent() ExprContext { } func (ctx *SimpleStore) Clone() ExprContext { - return &SimpleStore{ + clone := &SimpleStore{ varStore: CloneFilteredMap(ctx.varStore, filterRefName), funcStore: CloneFilteredMap(ctx.funcStore, filterRefName), } + return clone } func (ctx *SimpleStore) Merge(src ExprContext) { diff --git a/t_funcs_test.go b/t_funcs_test.go index af7da0c..c725dab 100644 --- a/t_funcs_test.go +++ b/t_funcs_test.go @@ -44,7 +44,7 @@ func dummy(ctx ExprContext, name string, args []any) (result any, err error) { func TestFunctionToStringSimple(t *testing.T) { source := NewGolangFunctor(dummy) - want := "func() {}" + want := "func(){}" got := source.ToString(0) if got != want { t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want)