Expr functions now act as closures
This commit is contained in:
parent
d84e690ef3
commit
f41ea96d17
@ -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)
|
||||||
|
13
function.go
13
function.go
@ -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]
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user