The function parameter model has been modified to support the passing of named parameters
This commit is contained in:
+97
-18
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user