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 {
|
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) {
|
func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||||
if functor.defCtx != nil {
|
// if functor.defCtx != nil {
|
||||||
ctx.Merge(functor.defCtx)
|
// 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]
|
||||||
if funcArg, ok := arg.(Functor); ok {
|
if funcArg, ok := arg.(Functor); ok {
|
||||||
// ctx.RegisterFunc(p, functor, 0, -1)
|
|
||||||
paramSpecs := funcArg.GetParams()
|
paramSpecs := funcArg.GetParams()
|
||||||
ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs)
|
ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs)
|
||||||
} else {
|
} else {
|
||||||
@ -42,17 +54,3 @@ func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (re
|
|||||||
result, err = functor.expr.Eval(ctx)
|
result, err = functor.expr.Eval(ctx)
|
||||||
return
|
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)
|
SetFunc(info ExprFunc)
|
||||||
GetFunc() ExprFunc
|
GetFunc() ExprFunc
|
||||||
GetParams() []ExprFuncParam
|
GetParams() []ExprFuncParam
|
||||||
|
GetDefinitionContext() ExprContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Function Param Info
|
// ---- Function Param Info
|
||||||
@ -31,6 +32,8 @@ type ExprFunc interface {
|
|||||||
Functor() Functor
|
Functor() Functor
|
||||||
Params() []ExprFuncParam
|
Params() []ExprFuncParam
|
||||||
ReturnType() string
|
ReturnType() string
|
||||||
|
PrepareCall(parentCtx ExprContext, name string, varParams *[]any) (ctx ExprContext, err error)
|
||||||
|
AllocContext(parentCtx ExprContext) (ctx ExprContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----Expression Context
|
// ----Expression Context
|
||||||
|
101
function.go
101
function.go
@ -21,7 +21,7 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
|
|||||||
if functor.info != nil {
|
if functor.info != nil {
|
||||||
s = functor.info.ToString(opt)
|
s = functor.info.ToString(opt)
|
||||||
} else {
|
} else {
|
||||||
s = "func() {}"
|
s = "func(){}"
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -42,6 +42,10 @@ func (functor *baseFunctor) GetFunc() ExprFunc {
|
|||||||
return functor.info
|
return functor.info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (functor *baseFunctor) GetDefinitionContext() ExprContext {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Function Parameters
|
// ---- Function Parameters
|
||||||
type paramFlags uint16
|
type paramFlags uint16
|
||||||
|
|
||||||
@ -94,13 +98,15 @@ func (param *funcParamInfo) DefaultValue() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Functions
|
// --- Functions
|
||||||
|
|
||||||
|
// funcInfo implements ExprFunc
|
||||||
type funcInfo struct {
|
type funcInfo struct {
|
||||||
name string
|
name string
|
||||||
minArgs int
|
minArgs int
|
||||||
maxArgs int
|
maxArgs int
|
||||||
functor Functor
|
functor Functor
|
||||||
params []ExprFuncParam
|
formalParams []ExprFuncParam
|
||||||
returnType string
|
returnType string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
|
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{
|
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)
|
functor.SetFunc(info)
|
||||||
return info, nil
|
return info, nil
|
||||||
@ -137,7 +143,7 @@ func newUnnamedFuncInfo(functor Functor, returnType string, params []ExprFuncPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (info *funcInfo) Params() []ExprFuncParam {
|
func (info *funcInfo) Params() []ExprFuncParam {
|
||||||
return info.params
|
return info.formalParams
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *funcInfo) ReturnType() string {
|
func (info *funcInfo) ReturnType() string {
|
||||||
@ -152,8 +158,8 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
|
|||||||
sb.WriteString(info.Name())
|
sb.WriteString(info.Name())
|
||||||
}
|
}
|
||||||
sb.WriteByte('(')
|
sb.WriteByte('(')
|
||||||
if info.params != nil {
|
if info.formalParams != nil {
|
||||||
for i, p := range info.params {
|
for i, p := range info.formalParams {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
sb.WriteString(", ")
|
sb.WriteString(", ")
|
||||||
}
|
}
|
||||||
@ -180,7 +186,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
|
|||||||
} else {
|
} else {
|
||||||
sb.WriteString(TypeAny)
|
sb.WriteString(TypeAny)
|
||||||
}
|
}
|
||||||
sb.WriteString(" {}")
|
sb.WriteString("{}")
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,41 +206,52 @@ func (info *funcInfo) Functor() Functor {
|
|||||||
return info.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 ---
|
// ----- Call a function ---
|
||||||
|
|
||||||
func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err error) {
|
func CallFunction(parentCtx ExprContext, name string, actualParams []any) (result any, err error) {
|
||||||
if info, exists, owner := GetFuncInfo(ctx, name); exists {
|
if info, exists, _ := GetFuncInfo(parentCtx, name); exists {
|
||||||
passedCount := len(*varParams)
|
var ctx ExprContext
|
||||||
if info.MinArgs() > passedCount {
|
if ctx, err = info.PrepareCall(parentCtx, name, &actualParams); err == nil {
|
||||||
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
|
functor := info.Functor()
|
||||||
}
|
result, err = functor.Invoke(ctx, name, actualParams)
|
||||||
for i, p := range info.Params() {
|
exportObjectsToParent(ctx)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf("unknown function %s()", name)
|
err = fmt.Errorf("unknown function %s()", name)
|
||||||
}
|
}
|
||||||
return
|
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 {
|
func (ctx *SimpleStore) Clone() ExprContext {
|
||||||
return &SimpleStore{
|
clone := &SimpleStore{
|
||||||
varStore: CloneFilteredMap(ctx.varStore, filterRefName),
|
varStore: CloneFilteredMap(ctx.varStore, filterRefName),
|
||||||
funcStore: CloneFilteredMap(ctx.funcStore, filterRefName),
|
funcStore: CloneFilteredMap(ctx.funcStore, filterRefName),
|
||||||
}
|
}
|
||||||
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *SimpleStore) Merge(src ExprContext) {
|
func (ctx *SimpleStore) Merge(src ExprContext) {
|
||||||
|
@ -44,7 +44,7 @@ func dummy(ctx ExprContext, name string, args []any) (result any, err error) {
|
|||||||
|
|
||||||
func TestFunctionToStringSimple(t *testing.T) {
|
func TestFunctionToStringSimple(t *testing.T) {
|
||||||
source := NewGolangFunctor(dummy)
|
source := NewGolangFunctor(dummy)
|
||||||
want := "func() {}"
|
want := "func(){}"
|
||||||
got := source.ToString(0)
|
got := source.ToString(0)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want)
|
t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want)
|
||||||
|
Loading…
Reference in New Issue
Block a user