/
eval.go
122 lines (94 loc) · 2.46 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
package gslang
import (
"fmt"
"github.com/gsrpc/gslang/ast"
"github.com/gsrpc/gslang/lexer"
"github.com/gsdocker/gslogger"
)
// Eval compile time eval
type Eval interface {
EvalInt(expr ast.Expr) int64
EvalString(expr ast.Expr) string
EvalEnumConstant(name string, constant string) int32
GetType(name string) (ast.Type, bool)
}
type _Eval struct {
gslogger.Log //Mixin logger
module *ast.Module // module
errorHandler ErrorHandler // error handlers
}
func newEval(errorHandler ErrorHandler, module *ast.Module) Eval {
return &_Eval{
Log: gslogger.Get("eval"),
module: module,
errorHandler: errorHandler,
}
}
func (eval *_Eval) errorf(err error, node ast.Node, fmtstr string, args ...interface{}) {
var start lexer.Position
var end lexer.Position
if node != nil {
start, end = Pos(node)
}
errinfo := &Error{
Stage: StageSemParing,
Orignal: err,
Start: start,
End: end,
Text: fmt.Sprintf(fmtstr, args...),
}
eval.errorHandler.HandleError(errinfo)
}
func (eval *_Eval) EvalString(expr ast.Expr) string {
stringConstant, ok := expr.(*ast.String)
if !ok {
eval.errorf(ErrEval, expr, "can't eval expr(%s) as string ", expr)
}
return stringConstant.Name()
}
func (eval *_Eval) EvalEnumConstant(name string, constantName string) int32 {
target, ok := eval.GetType(name)
if !ok {
eval.errorf(ErrEval, nil, "unknown type(%s)", name)
return 0
}
enum, ok := target.(*ast.Enum)
if !ok {
eval.errorf(ErrEval, nil, "target type(%s) is not enum", name)
return 0
}
constant, ok := enum.Constant(constantName)
if !ok {
eval.errorf(ErrEval, nil, "enum constant %s#%s -- not found", enum, constantName)
return 0
}
return constant.Value
}
func (eval *_Eval) EvalInt(expr ast.Expr) int64 {
switch expr.(type) {
case *ast.ConstantRef:
return eval.EvalInt(expr.(*ast.ConstantRef).Value)
case *ast.EnumConstant:
return int64(expr.(*ast.EnumConstant).Value)
case *ast.BinaryOp:
binary := expr.(*ast.BinaryOp)
lhs := eval.EvalInt(binary.LHS)
rhs := eval.EvalInt(binary.RHS)
switch binary.Token {
case lexer.OpBitOr:
return lhs | rhs
case lexer.OpBitAnd:
return lhs & rhs
default:
eval.errorf(ErrEval, expr, "can't eval expr(%s) as int64 : unsupport op", expr)
return 0
}
default:
eval.errorf(ErrEval, expr, "can't eval expr(%s) as int64", expr)
return 0
}
}
func (eval *_Eval) GetType(name string) (t ast.Type, ok bool) {
t, ok = eval.module.Types[name]
return
}