| 909 | } |
| 910 | |
| 911 | func (a *Analyzer) checkExprArity(arg ast.BaseTerm) error { |
| 912 | switch x := arg.(type) { |
| 913 | case ast.Constant: |
| 914 | return nil |
| 915 | case ast.Variable: |
| 916 | return nil |
| 917 | case ast.ApplyFn: |
| 918 | for _, arg := range x.Args { |
| 919 | if err := a.checkExprArity(arg); err != nil { |
| 920 | return err |
| 921 | } |
| 922 | } |
| 923 | sym := x.Function |
| 924 | lookup := func(sym ast.FunctionSym) (bool, bool) { |
| 925 | _, builtinFun := builtin.Functions[sym] |
| 926 | if builtinFun { |
| 927 | return true, false |
| 928 | } |
| 929 | var extra bool |
| 930 | if a.extraFunctions != nil { |
| 931 | _, extra = a.extraFunctions[sym] |
| 932 | } |
| 933 | return false, extra |
| 934 | } |
| 935 | // Variable number of arguments. |
| 936 | isBuiltinVar, isExtraVar := lookup(ast.FunctionSym{sym.Symbol, -1}) |
| 937 | if isExtraVar { |
| 938 | return nil |
| 939 | } |
| 940 | if isBuiltinVar { |
| 941 | // For var-arity reducer functions (e.g. fn:collect), check we have at least one argument. |
| 942 | if _, ok := builtin.ReducerFunctions[ast.FunctionSym{sym.Symbol, -1}]; ok && len(x.Args) == 0 { |
| 943 | return fmt.Errorf("reducer function %v expects at least one argument", sym.Symbol) |
| 944 | } |
| 945 | if sym.Symbol == symbols.Struct.Symbol && len(x.Args)%2 != 0 { |
| 946 | // What if we are in a type expression? remove optional and repeated. |
| 947 | return fmt.Errorf("expect even number of arguments for %s - use { /key: value, ... } syntax for structs", x) |
| 948 | } |
| 949 | if sym.Symbol == symbols.Map.Symbol && len(x.Args)%2 != 0 { |
| 950 | return fmt.Errorf("expect even number of arguments for %s - use [ key: value, ... ] syntax for maps", x) |
| 951 | } |
| 952 | return nil |
| 953 | } |
| 954 | if isBuiltin, isExtra := lookup(sym); isBuiltin || isExtra { |
| 955 | if sym.Arity == len(x.Args) { |
| 956 | return nil |
| 957 | } |
| 958 | return fmt.Errorf("function %v expects %d arguments, provided: %v", sym.Symbol, sym.Arity, x.Args) |
| 959 | } |
| 960 | // Arity mismatch. Look for a symbol with the same name. |
| 961 | for fn := range builtin.Functions { |
| 962 | if fn.Symbol == sym.Symbol { |
| 963 | return fmt.Errorf("wrong arity for function %v got %v (%d args) want %d args", fn, x.Args, len(x.Args), fn.Arity) |
| 964 | } |
| 965 | } |
| 966 | if len(a.extraFunctions) > 0 { |
| 967 | for fn := range a.extraFunctions { |
| 968 | if fn.Symbol == sym.Symbol { |