Improved closure context persistence. Now it is possibile to define counters like this func(base){func(){@base=base+1}}

This commit is contained in:
2024-06-24 07:20:17 +02:00
parent 3b641ac793
commit e41ddc664c
5 changed files with 82 additions and 63 deletions
+59 -42
View File
@@ -21,7 +21,7 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
if functor.info != nil {
s = functor.info.ToString(opt)
} else {
s = "func() {}"
s = "func(){}"
}
return s
}
@@ -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,13 +98,15 @@ func (param *funcParamInfo) DefaultValue() any {
}
// --- Functions
// funcInfo implements ExprFunc
type funcInfo struct {
name string
minArgs int
maxArgs int
functor Functor
params []ExprFuncParam
returnType string
name string
minArgs int
maxArgs int
functor Functor
formalParams []ExprFuncParam
returnType string
}
func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
@@ -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(", ")
}
@@ -180,7 +186,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
} else {
sb.WriteString(TypeAny)
}
sb.WriteString(" {}")
sb.WriteString("{}")
return sb.String()
}
@@ -200,41 +206,52 @@ func (info *funcInfo) Functor() Functor {
return info.functor
}
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 (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 := passedCount; i < len(info.formalParams); i++ {
p := info.formalParams[i]
if !p.IsDefault() {
break
}
*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 {
ctx = info.AllocContext(parentCtx)
}
return
}
// ----- Call a function ---
func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) {
if info, exists, owner := GetFuncInfo(ctx, name); exists {
passedCount := len(*varParams)
if info.MinArgs() > passedCount {
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
}
for i, p := range info.Params() {
if i >= passedCount {
if !p.IsDefault() {
break
}
*varParams = append(*varParams, p.DefaultValue())
}
}
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) {
err = ErrTooMuchParams(name, info.MaxArgs(), len(*varParams))
}
if err == nil && owner != ctx {
ctx.RegisterFuncInfo(info)
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, &params); err == nil {
result, err = ctx.Call(name, params)
exportObjectsToParent(ctx)
}
return
}