Skip to content

Commit 02b4800

Browse files
committed
Refactor builtins and func calls
1 parent c224b52 commit 02b4800

File tree

4 files changed

+72
-59
lines changed

4 files changed

+72
-59
lines changed

eval.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package expr
33
import (
44
"fmt"
55
"math"
6+
"reflect"
67
"regexp"
78
)
89

@@ -297,25 +298,51 @@ func (n methodNode) Eval(env interface{}) (interface{}, error) {
297298
return nil, err
298299
}
299300

300-
return call(n.method, method, n.arguments, env)
301-
}
301+
in := make([]reflect.Value, 0)
302302

303-
func (n builtinNode) Eval(env interface{}) (interface{}, error) {
304-
if len(n.arguments) == 0 {
305-
return nil, fmt.Errorf("missing argument to %v", n.name)
303+
for _, a := range n.arguments {
304+
i, err := a.Eval(env)
305+
if err != nil {
306+
return nil, err
307+
}
308+
in = append(in, reflect.ValueOf(i))
306309
}
307-
if len(n.arguments) > 1 {
308-
return nil, fmt.Errorf("too many arguments to %v: %v", n.name, n)
310+
311+
out := reflect.ValueOf(method).Call(in)
312+
313+
if len(out) == 0 {
314+
return nil, nil
315+
} else if len(out) > 1 {
316+
return nil, fmt.Errorf("method %q must return only one value", n.method)
309317
}
310318

311-
a, err := n.arguments[0].Eval(env)
312-
if err != nil {
313-
return nil, err
319+
if out[0].IsValid() && out[0].CanInterface() {
320+
return out[0].Interface(), nil
314321
}
315322

323+
return nil, nil
324+
}
325+
326+
func (n builtinNode) Eval(env interface{}) (interface{}, error) {
316327
switch n.name {
317328
case "len":
318-
return count(n.arguments[0], a)
329+
if len(n.arguments) == 0 {
330+
return nil, fmt.Errorf("missing argument: %v", n)
331+
}
332+
if len(n.arguments) > 1 {
333+
return nil, fmt.Errorf("too many arguments: %v", n)
334+
}
335+
336+
i, err := n.arguments[0].Eval(env)
337+
if err != nil {
338+
return nil, err
339+
}
340+
341+
switch reflect.TypeOf(i).Kind() {
342+
case reflect.Array, reflect.Slice, reflect.String:
343+
return float64(reflect.ValueOf(i).Len()), nil
344+
}
345+
return nil, fmt.Errorf("invalid argument %v (type %T)", n, i)
319346
}
320347

321348
return nil, fmt.Errorf("unknown %q builtin", n.name)
@@ -327,7 +354,29 @@ func (n functionNode) Eval(env interface{}) (interface{}, error) {
327354
return nil, err
328355
}
329356

330-
return call(n.name, fn, n.arguments, env)
357+
in := make([]reflect.Value, 0)
358+
359+
for _, a := range n.arguments {
360+
i, err := a.Eval(env)
361+
if err != nil {
362+
return nil, err
363+
}
364+
in = append(in, reflect.ValueOf(i))
365+
}
366+
367+
out := reflect.ValueOf(fn).Call(in)
368+
369+
if len(out) == 0 {
370+
return nil, nil
371+
} else if len(out) > 1 {
372+
return nil, fmt.Errorf("func %q must return only one value", n.name)
373+
}
374+
375+
if out[0].IsValid() && out[0].CanInterface() {
376+
return out[0].Interface(), nil
377+
}
378+
379+
return nil, nil
331380
}
332381

333382
func (n conditionalNode) Eval(env interface{}) (interface{}, error) {

eval_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -413,19 +413,19 @@ var evalErrorTests = []evalErrorTest{
413413
"operator in not defined on string",
414414
},
415415
{
416-
"len(1)",
416+
"len()",
417417
nil,
418-
"invalid argument 1 (type float64) for len",
418+
"missing argument: len()",
419419
},
420420
{
421-
"len(foo, bar)",
422-
map[string]interface{}{"foo": nil, "bar": nil},
423-
"too many arguments to len: len(foo, bar)",
421+
"len(1)",
422+
nil,
423+
"invalid argument len(1) (type float64)",
424424
},
425425
{
426-
"len()",
426+
"len(a, b)",
427427
nil,
428-
"missing argument to len",
428+
"too many arguments: len(a, b)",
429429
},
430430
}
431431

type.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ func (n builtinNode) Type(table typesTable) (Type, error) {
166166
return nil, err
167167
}
168168
}
169-
if _, ok := builtins[n.name]; ok {
170-
return interfaceType, nil
169+
switch n.name {
170+
case "len":
171+
// TODO: Add arguments type checks.
172+
return numberType, nil
171173
}
172174
return nil, fmt.Errorf("%v undefined", n)
173175
}

utils.go

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -112,41 +112,3 @@ func contains(needle interface{}, array interface{}) (bool, error) {
112112
}
113113
return false, nil
114114
}
115-
116-
func count(node Node, array interface{}) (float64, error) {
117-
if array != nil {
118-
value := reflect.ValueOf(array)
119-
switch reflect.TypeOf(array).Kind() {
120-
case reflect.Array, reflect.Slice:
121-
return float64(value.Len()), nil
122-
case reflect.String:
123-
return float64(value.Len()), nil
124-
}
125-
return 0, fmt.Errorf("invalid argument %v (type %T) for len", node, array)
126-
}
127-
128-
return 0, nil
129-
}
130-
131-
func call(name string, fn interface{}, arguments []Node, env interface{}) (interface{}, error) {
132-
in := make([]reflect.Value, 0)
133-
for _, arg := range arguments {
134-
a, err := Run(arg, env)
135-
if err != nil {
136-
return nil, err
137-
}
138-
in = append(in, reflect.ValueOf(a))
139-
}
140-
141-
out := reflect.ValueOf(fn).Call(in)
142-
if len(out) == 0 {
143-
return nil, nil
144-
} else if len(out) > 1 {
145-
return nil, fmt.Errorf("func %q must return only one value", name)
146-
}
147-
148-
if out[0].IsValid() && out[0].CanInterface() {
149-
return out[0].Interface(), nil
150-
}
151-
return nil, nil
152-
}

0 commit comments

Comments
 (0)