-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy patheval.go
71 lines (59 loc) · 1.49 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
package gpath
import (
"errors"
"fmt"
"go/ast"
"go/constant"
"go/token"
)
func evalExpr(expr ast.Expr) (v constant.Value, rerr error) {
defer func() {
if r := recover(); r != nil {
v, rerr = constant.MakeUnknown(), fmt.Errorf("%v", r)
}
}()
switch e := expr.(type) {
case *ast.ParenExpr:
return evalExpr(e.X)
case *ast.BinaryExpr:
return evalBinaryExpr(e)
case *ast.UnaryExpr:
return evalUnaryExpr(e)
case *ast.BasicLit:
return constant.MakeFromLiteral(e.Value, e.Kind, 0), nil
case *ast.Ident:
return evalIdent(e)
}
return constant.MakeUnknown(), errors.New("unknown node")
}
func evalBinaryExpr(expr *ast.BinaryExpr) (constant.Value, error) {
x, err := evalExpr(expr.X)
if err != nil {
return constant.MakeUnknown(), err
}
y, err := evalExpr(expr.Y)
if err != nil {
return constant.MakeUnknown(), err
}
switch expr.Op {
case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
return constant.MakeBool(constant.Compare(x, expr.Op, y)), nil
}
return constant.BinaryOp(x, expr.Op, y), nil
}
func evalUnaryExpr(expr *ast.UnaryExpr) (constant.Value, error) {
x, err := evalExpr(expr.X)
if err != nil {
return constant.MakeUnknown(), err
}
return constant.UnaryOp(expr.Op, x, 0), nil
}
func evalIdent(expr *ast.Ident) (constant.Value, error) {
switch {
case expr.Name == "true":
return constant.MakeBool(true), nil
case expr.Name == "false":
return constant.MakeBool(false), nil
}
return constant.MakeUnknown(), errors.New("unknown ident")
}