Improved closure context persistence. Now it is possibile to define counters like this func(base){func(){@base=base+1}}
This commit is contained in:
parent
3b641ac793
commit
e41ddc664c
@ -17,19 +17,31 @@ type exprFunctor struct {
|
||||
// }
|
||||
|
||||
func newExprFunctor(e Expr, params []ExprFuncParam, ctx ExprContext) *exprFunctor {
|
||||
return &exprFunctor{expr: e, params: params, defCtx: ctx}
|
||||
var defCtx ExprContext
|
||||
if ctx != nil {
|
||||
// if ctx.GetParent() != nil {
|
||||
// defCtx = ctx.Clone()
|
||||
// defCtx.SetParent(ctx)
|
||||
// } else {
|
||||
defCtx = ctx
|
||||
// }
|
||||
}
|
||||
return &exprFunctor{expr: e, params: params, defCtx: defCtx}
|
||||
}
|
||||
|
||||
func (functor *exprFunctor) GetDefinitionContext() ExprContext {
|
||||
return functor.defCtx
|
||||
}
|
||||
|
||||
func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
if functor.defCtx != nil {
|
||||
ctx.Merge(functor.defCtx)
|
||||
}
|
||||
// if functor.defCtx != nil {
|
||||
// ctx.Merge(functor.defCtx)
|
||||
// }
|
||||
|
||||
for i, p := range functor.params {
|
||||
if i < len(args) {
|
||||
arg := args[i]
|
||||
if funcArg, ok := arg.(Functor); ok {
|
||||
// ctx.RegisterFunc(p, functor, 0, -1)
|
||||
paramSpecs := funcArg.GetParams()
|
||||
ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs)
|
||||
} else {
|
||||
@ -42,17 +54,3 @@ func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (re
|
||||
result, err = functor.expr.Eval(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
// func CallExprFunction(parentCtx ExprContext, funcName string, params ...any) (v any, err error) {
|
||||
// ctx := cloneContext(parentCtx)
|
||||
// ctx.SetParent(parentCtx)
|
||||
|
||||
// if err == nil {
|
||||
// if err = checkFunctionCall(ctx, funcName, ¶ms); err == nil {
|
||||
// if v, err = ctx.Call(funcName, params); err == nil {
|
||||
// exportObjects(parentCtx, ctx)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
@ -10,6 +10,7 @@ type Functor interface {
|
||||
SetFunc(info ExprFunc)
|
||||
GetFunc() ExprFunc
|
||||
GetParams() []ExprFuncParam
|
||||
GetDefinitionContext() ExprContext
|
||||
}
|
||||
|
||||
// ---- Function Param Info
|
||||
@ -31,6 +32,8 @@ type ExprFunc interface {
|
||||
Functor() Functor
|
||||
Params() []ExprFuncParam
|
||||
ReturnType() string
|
||||
PrepareCall(parentCtx ExprContext, name string, varParams *[]any) (ctx ExprContext, err error)
|
||||
AllocContext(parentCtx ExprContext) (ctx ExprContext)
|
||||
}
|
||||
|
||||
// ----Expression Context
|
||||
|
71
function.go
71
function.go
@ -42,6 +42,10 @@ func (functor *baseFunctor) GetFunc() ExprFunc {
|
||||
return functor.info
|
||||
}
|
||||
|
||||
func (functor *baseFunctor) GetDefinitionContext() ExprContext {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---- Function Parameters
|
||||
type paramFlags uint16
|
||||
|
||||
@ -94,12 +98,14 @@ func (param *funcParamInfo) DefaultValue() any {
|
||||
}
|
||||
|
||||
// --- Functions
|
||||
|
||||
// funcInfo implements ExprFunc
|
||||
type funcInfo struct {
|
||||
name string
|
||||
minArgs int
|
||||
maxArgs int
|
||||
functor Functor
|
||||
params []ExprFuncParam
|
||||
formalParams []ExprFuncParam
|
||||
returnType string
|
||||
}
|
||||
|
||||
@ -126,7 +132,7 @@ func newFuncInfo(name string, functor Functor, returnType string, params []ExprF
|
||||
}
|
||||
}
|
||||
info = &funcInfo{
|
||||
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, params: params,
|
||||
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params,
|
||||
}
|
||||
functor.SetFunc(info)
|
||||
return info, nil
|
||||
@ -137,7 +143,7 @@ func newUnnamedFuncInfo(functor Functor, returnType string, params []ExprFuncPar
|
||||
}
|
||||
|
||||
func (info *funcInfo) Params() []ExprFuncParam {
|
||||
return info.params
|
||||
return info.formalParams
|
||||
}
|
||||
|
||||
func (info *funcInfo) ReturnType() string {
|
||||
@ -152,8 +158,8 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
|
||||
sb.WriteString(info.Name())
|
||||
}
|
||||
sb.WriteByte('(')
|
||||
if info.params != nil {
|
||||
for i, p := range info.params {
|
||||
if info.formalParams != nil {
|
||||
for i, p := range info.formalParams {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
@ -200,41 +206,52 @@ func (info *funcInfo) Functor() Functor {
|
||||
return info.functor
|
||||
}
|
||||
|
||||
// ----- Call a function ---
|
||||
func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) {
|
||||
if defCtx := info.functor.GetDefinitionContext(); defCtx != nil {
|
||||
ctx = defCtx.Clone()
|
||||
ctx.SetParent(defCtx)
|
||||
} else {
|
||||
ctx = parentCtx.Clone()
|
||||
ctx.SetParent(parentCtx)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) {
|
||||
if info, exists, owner := GetFuncInfo(ctx, name); exists {
|
||||
passedCount := len(*varParams)
|
||||
func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, varActualParams *[]any) (ctx ExprContext, err error) {
|
||||
passedCount := len(*varActualParams)
|
||||
if info.MinArgs() > passedCount {
|
||||
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
|
||||
}
|
||||
for i, p := range info.Params() {
|
||||
if i >= passedCount {
|
||||
|
||||
for i := passedCount; i < len(info.formalParams); i++ {
|
||||
p := info.formalParams[i]
|
||||
if !p.IsDefault() {
|
||||
break
|
||||
}
|
||||
*varParams = append(*varParams, p.DefaultValue())
|
||||
*varActualParams = append(*varActualParams, p.DefaultValue())
|
||||
}
|
||||
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varActualParams) {
|
||||
err = ErrTooMuchParams(name, info.MaxArgs(), len(*varActualParams))
|
||||
}
|
||||
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) {
|
||||
err = ErrTooMuchParams(name, info.MaxArgs(), len(*varParams))
|
||||
|
||||
if err == nil {
|
||||
ctx = info.AllocContext(parentCtx)
|
||||
}
|
||||
if err == nil && owner != ctx {
|
||||
ctx.RegisterFuncInfo(info)
|
||||
return
|
||||
}
|
||||
|
||||
// ----- Call a function ---
|
||||
|
||||
func CallFunction(parentCtx ExprContext, name string, actualParams []any) (result any, err error) {
|
||||
if info, exists, _ := GetFuncInfo(parentCtx, name); exists {
|
||||
var ctx ExprContext
|
||||
if ctx, err = info.PrepareCall(parentCtx, name, &actualParams); err == nil {
|
||||
functor := info.Functor()
|
||||
result, err = functor.Invoke(ctx, name, actualParams)
|
||||
exportObjectsToParent(ctx)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("unknown function %s()", name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CallFunction(parentCtx ExprContext, name string, params []any) (result any, err error) {
|
||||
ctx := cloneContext(parentCtx)
|
||||
ctx.SetParent(parentCtx)
|
||||
|
||||
if err = checkFunctionCall(ctx, name, ¶ms); err == nil {
|
||||
result, err = ctx.Call(name, params)
|
||||
exportObjectsToParent(ctx)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -36,10 +36,11 @@ func (ctx *SimpleStore) GetParent() ExprContext {
|
||||
}
|
||||
|
||||
func (ctx *SimpleStore) Clone() ExprContext {
|
||||
return &SimpleStore{
|
||||
clone := &SimpleStore{
|
||||
varStore: CloneFilteredMap(ctx.varStore, filterRefName),
|
||||
funcStore: CloneFilteredMap(ctx.funcStore, filterRefName),
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func (ctx *SimpleStore) Merge(src ExprContext) {
|
||||
|
Loading…
Reference in New Issue
Block a user