diff --git a/context.go b/context.go index 51e03b1..6c2df5f 100644 --- a/context.go +++ b/context.go @@ -34,6 +34,7 @@ type ExprFunc interface { // ----Expression Context type ExprContext interface { Clone() ExprContext + Merge(ctx ExprContext) GetVar(varName string) (value any, exists bool) SetVar(varName string, value any) UnsafeSetVar(varName string, value any) diff --git a/function.go b/function.go index c09028c..4605798 100644 --- a/function.go +++ b/function.go @@ -34,7 +34,7 @@ func (functor *baseFunctor) GetFunc() ExprFunc { return functor.info } -// ---- Linking with the functions of Go +// ---- Linking with Go functions type golangFunctor struct { baseFunctor f FuncTemplate @@ -48,18 +48,23 @@ func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) ( return functor.f(ctx, name, args) } -// ---- Linking with the functions of Expr +// ---- Linking with Expr functions type exprFunctor struct { baseFunctor params []string expr Expr + defCtx ExprContext } -func newExprFunctor(e Expr, params []string) *exprFunctor { - return &exprFunctor{expr: e, params: params} +func newExprFunctor(e Expr, params []string, ctx ExprContext) *exprFunctor { + return &exprFunctor{expr: e, params: params, defCtx: ctx} } func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) { + if functor.defCtx != nil { + ctx.Merge(functor.defCtx) + } + for i, p := range functor.params { if i < len(args) { arg := args[i] diff --git a/operand-func.go b/operand-func.go index 4bafbad..f2b9b0a 100644 --- a/operand-func.go +++ b/operand-func.go @@ -108,11 +108,7 @@ func evalFuncDef(ctx ExprContext, self *term) (v any, err error) { for _, param := range self.children { paramList = append(paramList, param.source()) } - v = newExprFunctor(expr, paramList) - // v = &funcDefFunctor{ - // params: paramList, - // expr: expr, - // } + v = newExprFunctor(expr, paramList, ctx) } else { err = errors.New("invalid function definition: the body specification must be an expression") } diff --git a/simple-store.go b/simple-store.go index 850be75..73e5805 100644 --- a/simple-store.go +++ b/simple-store.go @@ -12,29 +12,40 @@ import ( type SimpleStore struct { varStore map[string]any - funcStore map[string]*funcInfo + funcStore map[string]ExprFunc } func NewSimpleStore() *SimpleStore { ctx := &SimpleStore{ varStore: make(map[string]any), - funcStore: make(map[string]*funcInfo), + funcStore: make(map[string]ExprFunc), } - //ImportBuiltinsFuncs(ctx) return ctx } +func filterRefName(name string) bool { return name[0] != '@' } +func filterPrivName(name string) bool { return name[0] != '_' } + func (ctx *SimpleStore) Clone() ExprContext { return &SimpleStore{ - varStore: CloneFilteredMap(ctx.varStore, func(name string) bool { return name[0] != '@' }), - funcStore: CloneFilteredMap(ctx.funcStore, func(name string) bool { return name[0] != '@' }), + varStore: CloneFilteredMap(ctx.varStore, filterRefName), + funcStore: CloneFilteredMap(ctx.funcStore, filterRefName), + } +} + +func (ctx *SimpleStore) Merge(src ExprContext) { + for _, name := range src.EnumVars(filterRefName) { + ctx.varStore[name], _ = src.GetVar(name) + } + for _, name := range src.EnumFuncs(filterRefName) { + ctx.funcStore[name], _ = src.GetFuncInfo(name) } } func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) { sb.WriteString("vars: {\n") first := true - for _, name := range ctx.EnumVars(func(name string) bool { return name[0] != '_' }) { + for _, name := range ctx.EnumVars(filterPrivName) { if first { first = false } else { @@ -164,7 +175,7 @@ func (ctx *SimpleStore) EnumFuncs(acceptor func(name string) (accept bool)) (fun func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) { if info, exists := ctx.funcStore[name]; exists { - functor := info.functor + functor := info.Functor() result, err = functor.Invoke(ctx, name, args) } else { err = fmt.Errorf("unknown function %s()", name)