The function parameter model has been modified to support the passing of named parameters

This commit is contained in:
2024-07-28 18:49:08 +02:00
parent ab06702e5e
commit 9070b5c9cc
34 changed files with 520 additions and 347 deletions
+97 -18
View File
@@ -10,7 +10,7 @@ import (
)
// ---- Function template
type FuncTemplate func(ctx ExprContext, name string, args []any) (result any, err error)
type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (result any, err error)
// ---- Common functor definition
type baseFunctor struct {
@@ -137,10 +137,6 @@ func newFuncInfo(name string, functor Functor, returnType string, params []ExprF
return info, nil
}
// func newUnnamedFuncInfo(functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) {
// return newFuncInfo("unnamed", functor, returnType, params)
// }
func (info *funcInfo) Params() []ExprFuncParam {
return info.formalParams
}
@@ -216,21 +212,96 @@ func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) {
return
}
func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, varActualParams *[]any) (ctx ExprContext, err error) {
passedCount := len(*varActualParams)
func (info *funcInfo) checkExistingParam(paramName string) (exists bool) {
exists = false
for _, spec := range info.formalParams {
if spec.Name() == paramName {
exists = true
break
}
}
return
}
func (info *funcInfo) initActualParams(ctx ExprContext, name string, callTerm *term) (params map[string]any, err error) {
var varArgs []any
var varName string
namedParamsStarted := false
actualParams := make(map[string]any, len(info.formalParams))
for i, tree := range callTerm.children {
var paramValue any
paramCtx := ctx.Clone()
if paramValue, err = tree.compute(paramCtx); err != nil {
break
}
if paramName, namedParam := getAssignVarName(tree); namedParam {
if !info.checkExistingParam(paramName) {
err = fmt.Errorf("%s(): unknown param %q", name, paramName)
break
}
actualParams[paramName] = paramValue
namedParamsStarted = true
} else if !namedParamsStarted {
if varArgs != nil {
varArgs = append(varArgs, paramValue)
} else if i < len(info.formalParams) {
spec := info.formalParams[i]
if spec.IsRepeat() {
varArgs = make([]any, 0, len(callTerm.children)-i)
varArgs = append(varArgs, paramValue)
varName = spec.Name()
} else {
actualParams[spec.Name()] = paramValue
}
} else {
err = ErrTooManyParams(name, len(info.formalParams), len(callTerm.children))
break
}
} else {
err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", name, i+1)
break
}
}
if err == nil {
if varArgs != nil {
actualParams[varName] = varArgs
}
params = actualParams
}
return
}
func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, callTerm *term) (ctx ExprContext, actualParams map[string]any, err error) {
if actualParams, err = info.initActualParams(parentCtx, name, callTerm); err != nil {
return
}
passedCount := len(actualParams)
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
if passedCount < len(info.formalParams) {
for _, p := range info.formalParams {
if _, exists := actualParams[p.Name()]; !exists {
if !p.IsDefault() {
break
}
if p.IsRepeat() {
varArgs := make([]any, 1)
varArgs[0] = p.DefaultValue()
actualParams[p.Name()] = varArgs
} else {
actualParams[p.Name()] = 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(actualParams) {
err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
}
if err == nil {
@@ -241,12 +312,20 @@ func (info *funcInfo) PrepareCall(parentCtx ExprContext, name string, varActualP
// ----- Call a function ---
func CallFunction(parentCtx ExprContext, name string, actualParams []any) (result any, err error) {
if info, exists, _ := GetFuncInfo(parentCtx, name); exists {
func getAssignVarName(t *term) (name string, ok bool) {
if ok = t.symbol() == SymEqual; ok {
name = t.children[0].source()
}
return
}
func CallFunction3(parentCtx ExprContext, name string, callTerm *term) (result any, err error) {
var actualParams map[string]any
if info, exists := GetFuncInfo(parentCtx, name); exists {
var ctx ExprContext
if ctx, err = info.PrepareCall(parentCtx, name, &actualParams); err == nil {
if ctx, actualParams, err = info.PrepareCall(parentCtx, name, callTerm); err == nil {
functor := info.Functor()
result, err = functor.Invoke(ctx, name, actualParams)
result, err = functor.InvokeNamed(ctx, name, actualParams)
exportObjectsToParent(ctx)
}
} else {