Compare commits

...

1 Commits

Author SHA1 Message Date
camoroso f41ea96d17 Expr functions now act as closures 2024-05-30 07:13:26 +02:00
4 changed files with 29 additions and 16 deletions
+1
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)
+9 -4
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]
+1 -5
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")
} }
+18 -7
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)