the function call procedure now check the number of actual parameters against the numer of formal parameters

This commit is contained in:
Celestino Amoroso 2024-05-04 22:35:03 +02:00
parent 0fdd51049d
commit 1d8569d3a9
5 changed files with 32 additions and 8 deletions

2
ast.go
View File

@ -63,7 +63,7 @@ func (self *ast) addToken2(tk *Token) (t *term, err error) {
if t = newTerm(tk, nil); t != nil { if t = newTerm(tk, nil); t != nil {
err = self.addTerm(t) err = self.addTerm(t)
} else { } else {
err = tk.Errorf("No term constructor for token %q", tk.String()) err = tk.Errorf("unexpected token %q", tk.String())
} }
return return
} }

View File

@ -44,7 +44,7 @@ func TestAddTokensBad(t *testing.T) {
func TestAddUnknownTokens(t *testing.T) { func TestAddUnknownTokens(t *testing.T) {
tk0 := NewToken(0, 0, SymPercent, "%") tk0 := NewToken(0, 0, SymPercent, "%")
wantErr := errors.New(`No term constructor for token "%"`) wantErr := errors.New(`unexpected token "%"`)
tree := NewAst() tree := NewAst()
if gotErr := tree.addToken(tk0); gotErr != nil && gotErr.Error() != wantErr.Error() { if gotErr := tree.addToken(tk0); gotErr != nil && gotErr.Error() != wantErr.Error() {

View File

@ -6,6 +6,7 @@ package expr
import ( import (
"errors" "errors"
"fmt"
) )
// -------- function call term // -------- function call term
@ -21,6 +22,20 @@ func newFuncCallTerm(tk *Token, args []*term) *term {
} }
// -------- eval func call // -------- eval func call
func checkFunctionCall(ctx ExprContext, name string, params []any) (err error) {
if info, exists := ctx.GetFuncInfo(name); exists {
if info.MinArgs() > len(params) {
err = fmt.Errorf("too few params -- expected %d, got %d", info.MinArgs(), len(params))
}
if info.MaxArgs() >= 0 && info.MaxArgs() < len(params) {
err = fmt.Errorf("too much params -- expected %d, got %d", info.MaxArgs(), len(params))
}
} else {
err = fmt.Errorf("unknown function %s()", name)
}
return
}
func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) { func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
ctx := cloneContext(parentCtx) ctx := cloneContext(parentCtx)
name, _ := self.tk.Value.(string) name, _ := self.tk.Value.(string)
@ -34,19 +49,21 @@ func evalFuncCall(parentCtx ExprContext, self *term) (v any, err error) {
params[i] = param params[i] = param
} }
if err == nil { if err == nil {
if err = checkFunctionCall(ctx, name, params); err == nil {
if v, err = ctx.Call(name, params); err == nil { if v, err = ctx.Call(name, params); err == nil {
exportObjects(parentCtx, ctx) exportObjects(parentCtx, ctx)
} }
} }
}
return return
} }
// -------- function definition term // -------- function definition term
func newFuncDefTerm(tk *Token, args []*term) *term { func newFuncDefTerm(tk *Token, args []*term) *term {
return &term{ return &term{
tk: *tk, tk: *tk, // value is the expression body
parent: nil, parent: nil,
children: args, // arg[0]=formal-param-list, arg[1]=*ast children: args, // function params
position: posLeaf, position: posLeaf,
priority: priValue, priority: priValue,
evalFunc: evalFuncDef, evalFunc: evalFuncDef,

View File

@ -29,7 +29,14 @@ func evalAssign(ctx ExprContext, self *term) (v any, err error) {
if v, err = self.children[1].compute(ctx); err == nil { if v, err = self.children[1].compute(ctx); err == nil {
if functor, ok := v.(Functor); ok { if functor, ok := v.(Functor); ok {
ctx.RegisterFunc(leftTerm.source(), functor, 0, -1) var minArgs, maxArgs int = 0, 0
if funcDef, ok := functor.(*funcDefFunctor); ok {
l := len(funcDef.params)
minArgs = l
maxArgs = l
}
ctx.RegisterFunc(leftTerm.source(), functor, minArgs, maxArgs)
} else { } else {
ctx.setVar(leftTerm.source(), v) ctx.setVar(leftTerm.source(), v)
} }

View File

@ -160,7 +160,7 @@ func TestParser(t *testing.T) {
/* 138 */ {`nil`, nil, nil}, /* 138 */ {`nil`, nil, nil},
/* 139 */ {`null`, nil, errors.New(`undefined variable or function "null"`)}, /* 139 */ {`null`, nil, errors.New(`undefined variable or function "null"`)},
/* 140 */ {`{"key"}`, nil, errors.New(`[1:8] expected ":", got "}"`)}, /* 140 */ {`{"key"}`, nil, errors.New(`[1:8] expected ":", got "}"`)},
/* 141 */ {`{"key":}`, nil, errors.New(`[1:9] expected dictionary value, got "}"`)}, /* 141 */ {`{"key":}`, nil, errors.New(`[1:9] expected "dictionary-value", got "}"`)},
/* 142 */ {`{}`, map[any]any{}, nil}, /* 142 */ {`{}`, map[any]any{}, nil},
/* 143 */ {`1|2`, newFraction(1, 2), nil}, /* 143 */ {`1|2`, newFraction(1, 2), nil},
/* 144 */ {`1|2 + 1`, newFraction(3, 2), nil}, /* 144 */ {`1|2 + 1`, newFraction(3, 2), nil},