Skip to content

Commit b387e61

Browse files
committed
add function eval to evaluate a string to an expression
1 parent 90ee173 commit b387e61

5 files changed

+45
-6
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ This is container `Value`. It can contain zero or any number of `Value`'s. Curre
152152
* Types: String, Number, Bool, MultiValue
153153
* Associativity with parentheses: `(` and `)`
154154
* Functions:
155-
* Built-in: pi, cos, floor, sin, sqrt, trunc, and more (see `function.go`: `Eval()`)
155+
* Built-in: pi, cos, floor, sin, sqrt, trunc, **eval**, and more (see `function.go`: `Eval()`)
156156
* User-defined, injected via `WithFunctions()`
157157
* Variables, defined as `:variable_name:` and injected via `WithVariables()`
158158

function.go

+15
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ var builtInFunctions = map[string]FunctionalValue{
6464
"trunc": Trunc,
6565
"ln": Ln,
6666
"log": Log,
67+
"eval": Eval,
6768
}
6869

6970
// BuiltInFunction returns a built-in function body if known.
@@ -241,3 +242,17 @@ func Trunc(args ...Value) Value {
241242

242243
return NewUndefinedWithReasonf("trunc(): invalid argument #1 '%s'", argVal.String())
243244
}
245+
246+
func Eval(args ...Value) Value {
247+
if len(args) != 1 {
248+
return NewUndefinedWithReasonf("eval() requires 1 argument1, got %d: '%v'", len(args), args)
249+
}
250+
251+
argVal := args[0]
252+
253+
if v, ok := argVal.(Evaler); ok {
254+
return v.Eval()
255+
}
256+
257+
return argVal
258+
}

function_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/seborama/gal/v8"
88

99
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
1011
)
1112

1213
func TestPi(t *testing.T) {
@@ -76,3 +77,11 @@ func TestLog(t *testing.T) {
7677
val = gal.Log(gal.NewNumber(10_000_000), gal.NewNumber(0))
7778
assert.Equal(t, "7", val.String())
7879
}
80+
81+
func TestFunctionEval(t *testing.T) {
82+
expr := `eval("7+22")*2`
83+
tree, err := gal.NewTreeBuilder().FromExpr(expr)
84+
require.NoError(t, err)
85+
86+
assert.Equal(t, "58", tree.Eval().String())
87+
}

tree_builder_test.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package gal_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/google/go-cmp/cmp"
@@ -10,24 +11,24 @@ import (
1011
)
1112

1213
func TestTreeBuilder_FromExpr_VariousOperators(t *testing.T) {
13-
expr := `-1 + 2 * 3 / 2 + 3 ** 2 -8`
14+
expr := `-10 + 2 * 7 / 2 + 5 ** 4 -8`
1415
tree, err := gal.NewTreeBuilder().FromExpr(expr)
1516
require.NoError(t, err)
1617

1718
expectedTree := gal.Tree{
1819
gal.NewNumber(-1),
1920
gal.Multiply,
20-
gal.NewNumber(1),
21+
gal.NewNumber(10),
2122
gal.Plus,
2223
gal.NewNumber(2),
2324
gal.Multiply,
24-
gal.NewNumber(3),
25+
gal.NewNumber(7),
2526
gal.Divide,
2627
gal.NewNumber(2),
2728
gal.Plus,
28-
gal.NewNumber(3),
29+
gal.NewNumber(5),
2930
gal.Power,
30-
gal.NewNumber(2),
31+
gal.NewNumber(4),
3132
gal.Minus,
3233
gal.NewNumber(8),
3334
}
@@ -41,6 +42,7 @@ func TestTreeBuilder_FromExpr_PlusMinus_String(t *testing.T) {
4142
expr := `"-3 + -4" + -3 --4 / ( 1 + 2+3+4) +tan(10)`
4243
tree, err := gal.NewTreeBuilder().FromExpr(expr)
4344
require.NoError(t, err)
45+
fmt.Println(tree.Eval())
4446

4547
expectedTree := gal.Tree{
4648
gal.NewString(`-3 + -4`),

value.go

+13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ type Booler interface {
2121
Bool() Bool
2222
}
2323

24+
type Evaler interface {
25+
Eval() Value
26+
}
27+
2428
// TODO: we may also want to create ToString() and ToBool()
2529
func ToNumber(val Value) Number {
2630
// TODO: we could also try to convert Bool to Number since we could add NewNumberFromBool() to deal with Bool's
@@ -191,6 +195,15 @@ func (s String) Number() Number {
191195
return n
192196
}
193197

198+
func (s String) Eval() Value {
199+
tree, err := NewTreeBuilder().FromExpr(s.value)
200+
if err != nil {
201+
return s
202+
}
203+
204+
return tree.Eval()
205+
}
206+
194207
type Number struct {
195208
Undefined
196209
value decimal.Decimal

0 commit comments

Comments
 (0)