/
eval.go
144 lines (135 loc) · 2.87 KB
/
eval.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package rete
import (
"go/ast"
"go/parser"
"go/token"
"strconv"
"reflect"
"errors"
"fmt"
"runtime/debug"
)
func EvalFromString(s string, env Env) (result []reflect.Value, err error) {
exp, err := parser.ParseExpr(s)
if err != nil {
return
}
return Eval(exp, env)
}
func Eval(exp ast.Expr, env Env) (result []reflect.Value, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(fmt.Sprintf("%s %s", e, debug.Stack()))
}
}()
switch exp := exp.(type) {
case *ast.BinaryExpr:
return EvalBinaryExpr(exp, env)
case *ast.BasicLit:
var r interface{}
switch exp.Kind {
case token.INT, token.FLOAT:
r, err = strconv.ParseFloat(exp.Value, 64)
case token.STRING:
r, err = strconv.Unquote(exp.Value)
}
if err != nil {
return
}
result = append(result, reflect.ValueOf(r))
return result, nil
case *ast.UnaryExpr:
switch exp.Op {
case token.ADD:
return Eval(exp.X, env)
case token.SUB:
result, err = Eval(exp.X, env)
if err != nil {
return
}
val := -result[0].Float()
result = []reflect.Value{reflect.ValueOf(val)}
return
}
case *ast.ParenExpr:
return Eval(exp.X, env)
case *ast.Ident:
return EvalIdent(exp, env)
case *ast.CallExpr:
return EvalCall(exp, env)
}
return
}
func EvalCall(exp *ast.CallExpr, env Env) (result []reflect.Value, err error) {
f_val, err := Eval(exp.Fun, env)
if err != nil {
return
}
var args_val []reflect.Value
for _, arg := range exp.Args {
arg_val, err := Eval(arg, env)
if err != nil {
return result, err
}
args_val = append(args_val, arg_val[0])
}
result = f_val[0].Call(args_val)
return
}
func EvalIdent(exp *ast.Ident, env Env) (result []reflect.Value, err error) {
v := env[exp.Name]
if v == nil {
err = errors.New(fmt.Sprintf("Ident `%s` undefined", exp))
} else {
result = append(result, reflect.ValueOf(v))
}
return
}
func EvalBinaryExpr(exp *ast.BinaryExpr, env map[string]interface{}) (result []reflect.Value, err error) {
left_result, err := Eval(exp.X, env)
if err != nil {
return
}
right_result, err := Eval(exp.Y, env)
if err != nil {
return
}
var r interface{}
left := value2float(left_result[0])
right := value2float(right_result[0])
switch exp.Op {
case token.GTR:
r = left > right
case token.LSS:
r = left < right
case token.GEQ:
r = left >= right
case token.LEQ:
r = left <= right
case token.EQL:
r = left == right
case token.ADD:
r = left + right
case token.SUB:
r = left - right
case token.MUL:
r = left * right
case token.QUO:
r = left / right
default:
err = errors.New(fmt.Sprintf("OP `%s` undefined", exp.Op))
return
}
result = append(result, reflect.ValueOf(r))
return result, nil
}
func value2float(v reflect.Value) float64 {
switch v.Kind() {
case reflect.Float64:
return v.Float()
case reflect.String:
r, _ := strconv.ParseFloat(v.String(), 64)
return r
}
return v.Float()
}