Expr functions now act as closures

This commit is contained in:
Celestino Amoroso 2024-05-30 07:13:26 +02:00
parent d84e690ef3
commit f41ea96d17
4 changed files with 29 additions and 16 deletions

View File

@ -34,6 +34,7 @@ type ExprFunc interface {
// ----Expression Context // ----Expression Context
type ExprContext interface { type ExprContext interface {
Clone() ExprContext Clone() ExprContext
Merge(ctx ExprContext)
GetVar(varName string) (value any, exists bool) GetVar(varName string) (value any, exists bool)
SetVar(varName string, value any) SetVar(varName string, value any)
UnsafeSetVar(varName string, value any) UnsafeSetVar(varName string, value any)

View File

@ -34,7 +34,7 @@ func (functor *baseFunctor) GetFunc() ExprFunc {
return functor.info return functor.info
} }
// ---- Linking with the functions of Go // ---- Linking with Go functions
type golangFunctor struct { type golangFunctor struct {
baseFunctor baseFunctor
f FuncTemplate f FuncTemplate
@ -48,18 +48,23 @@ func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) (
return functor.f(ctx, name, args) return functor.f(ctx, name, args)
} }
// ---- Linking with the functions of Expr // ---- Linking with Expr functions
type exprFunctor struct { type exprFunctor struct {
baseFunctor baseFunctor
params []string params []string
expr Expr expr Expr
defCtx ExprContext
} }
func newExprFunctor(e Expr, params []string) *exprFunctor { func newExprFunctor(e Expr, params []string, ctx ExprContext) *exprFunctor {
return &exprFunctor{expr: e, params: params} return &exprFunctor{expr: e, params: params, defCtx: ctx}
} }
func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) { 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 { for i, p := range functor.params {
if i < len(args) { if i < len(args) {
arg := args[i] arg := args[i]

View File

@ -108,11 +108,7 @@ func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
for _, param := range self.children { for _, param := range self.children {
paramList = append(paramList, param.source()) paramList = append(paramList, param.source())
} }
v = newExprFunctor(expr, paramList) v = newExprFunctor(expr, paramList, ctx)
// v = &funcDefFunctor{
// params: paramList,
// expr: expr,
// }
} else { } else {
err = errors.New("invalid function definition: the body specification must be an expression") err = errors.New("invalid function definition: the body specification must be an expression")
} }

View File

@ -12,29 +12,40 @@ import (
type SimpleStore struct { type SimpleStore struct {
varStore map[string]any varStore map[string]any
funcStore map[string]*funcInfo funcStore map[string]ExprFunc
} }
func NewSimpleStore() *SimpleStore { func NewSimpleStore() *SimpleStore {
ctx := &SimpleStore{ ctx := &SimpleStore{
varStore: make(map[string]any), varStore: make(map[string]any),
funcStore: make(map[string]*funcInfo), funcStore: make(map[string]ExprFunc),
} }
//ImportBuiltinsFuncs(ctx)
return ctx return ctx
} }
func filterRefName(name string) bool { return name[0] != '@' }
func filterPrivName(name string) bool { return name[0] != '_' }
func (ctx *SimpleStore) Clone() ExprContext { func (ctx *SimpleStore) Clone() ExprContext {
return &SimpleStore{ return &SimpleStore{
varStore: CloneFilteredMap(ctx.varStore, func(name string) bool { return name[0] != '@' }), varStore: CloneFilteredMap(ctx.varStore, filterRefName),
funcStore: CloneFilteredMap(ctx.funcStore, func(name string) bool { return name[0] != '@' }), 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) { func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
sb.WriteString("vars: {\n") sb.WriteString("vars: {\n")
first := true first := true
for _, name := range ctx.EnumVars(func(name string) bool { return name[0] != '_' }) { for _, name := range ctx.EnumVars(filterPrivName) {
if first { if first {
first = false first = false
} else { } 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) { func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) {
if info, exists := ctx.funcStore[name]; exists { if info, exists := ctx.funcStore[name]; exists {
functor := info.functor functor := info.Functor()
result, err = functor.Invoke(ctx, name, args) result, err = functor.Invoke(ctx, name, args)
} else { } else {
err = fmt.Errorf("unknown function %s()", name) err = fmt.Errorf("unknown function %s()", name)