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
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)

View File

@ -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]

View File

@ -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")
}

View File

@ -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)