165 lines
3.5 KiB
Go
165 lines
3.5 KiB
Go
// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
// All rights reserved.
|
|
|
|
// func-info.go
|
|
package kern
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// --- Functions
|
|
|
|
// FuncInfo implements expr.ExprFunc
|
|
type FuncInfo struct {
|
|
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) {
|
|
var minArgs = 0
|
|
var maxArgs = 0
|
|
for _, p := range params {
|
|
if maxArgs == -1 {
|
|
return nil, fmt.Errorf("no more params can be specified after the ellipsis symbol: %q", p.Name())
|
|
}
|
|
if p.IsDefault() || p.IsOptional() {
|
|
maxArgs++
|
|
} else if maxArgs == minArgs {
|
|
minArgs++
|
|
maxArgs++
|
|
} else {
|
|
return nil, fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name())
|
|
}
|
|
if p.IsRepeat() {
|
|
minArgs--
|
|
maxArgs = -1
|
|
}
|
|
}
|
|
|
|
info = &FuncInfo{
|
|
name: name, minArgs: minArgs, maxArgs: maxArgs, functor: functor, returnType: returnType, formalParams: params,
|
|
}
|
|
functor.SetFunc(info)
|
|
return info, nil
|
|
}
|
|
|
|
func (info *FuncInfo) Params() []ExprFuncParam {
|
|
return info.formalParams
|
|
}
|
|
|
|
func (info *FuncInfo) ReturnType() string {
|
|
return info.returnType
|
|
}
|
|
|
|
func (info *FuncInfo) ToString(opt FmtOpt) string {
|
|
var sb strings.Builder
|
|
if len(info.Name()) == 0 {
|
|
sb.WriteString("func")
|
|
} else {
|
|
sb.WriteString(info.Name())
|
|
}
|
|
sb.WriteByte('(')
|
|
if info.formalParams != nil {
|
|
for i, p := range info.formalParams {
|
|
if i > 0 {
|
|
sb.WriteString(", ")
|
|
}
|
|
sb.WriteString(p.Name())
|
|
|
|
if p.IsDefault() {
|
|
sb.WriteByte('=')
|
|
if s, ok := p.DefaultValue().(string); ok {
|
|
sb.WriteByte('"')
|
|
sb.WriteString(s)
|
|
sb.WriteByte('"')
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v", p.DefaultValue()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if info.maxArgs < 0 {
|
|
sb.WriteString(" ...")
|
|
}
|
|
sb.WriteString("):")
|
|
if len(info.returnType) > 0 {
|
|
sb.WriteString(info.returnType)
|
|
} else {
|
|
sb.WriteString(TypeAny)
|
|
}
|
|
sb.WriteString("{}")
|
|
return sb.String()
|
|
}
|
|
|
|
func (info *FuncInfo) Name() string {
|
|
return info.name
|
|
}
|
|
|
|
func (info *FuncInfo) MinArgs() int {
|
|
return info.minArgs
|
|
}
|
|
|
|
func (info *FuncInfo) MaxArgs() int {
|
|
return info.maxArgs
|
|
}
|
|
|
|
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) ParamSpec(paramName string) ExprFuncParam {
|
|
for _, spec := range info.formalParams {
|
|
if spec.Name() == paramName {
|
|
return spec
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (info *FuncInfo) PrepareCall(name string, actualParams map[string]any) (err error) {
|
|
passedCount := len(actualParams)
|
|
if info.MinArgs() > passedCount {
|
|
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
|
|
return
|
|
}
|
|
|
|
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()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) {
|
|
err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams))
|
|
}
|
|
return
|
|
}
|