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
|
package main
import (
"errors"
"go/ast"
"go/constant"
"go/parser"
"strconv"
)
// Vars is a map for LTSV's label and value.
type Vars map[string]string
// ExprRunner is an expression runner for Go code.
type ExprRunner struct {
expr ast.Expr
}
// ExprContext is a context for ExprRunner.
type ExprContext struct {
vars Vars
}
func parseExpr(e string) (ast.Expr, error) {
expr, err := parser.ParseExpr(e)
if err != nil {
return nil, err
}
return expr, nil
}
func evalExpr(expr ast.Expr, ctx *ExprContext) (constant.Value, error) {
switch e := expr.(type) {
case *ast.BasicLit:
return evalBasicLit(e, ctx)
case *ast.BinaryExpr:
return evalBinaryExpr(e, ctx)
case *ast.Ident:
return evalIdent(e, ctx)
case *ast.ParenExpr:
return evalExpr(e.X, ctx)
}
return constant.MakeUnknown(), errors.New("unknown expr")
}
func evalBasicLit(expr *ast.BasicLit, ctx *ExprContext) (constant.Value, error) {
return constant.MakeFromLiteral(expr.Value, expr.Kind, 0), nil
}
func evalBinaryExpr(expr *ast.BinaryExpr, ctx *ExprContext) (constant.Value, error) {
x, err := evalExpr(expr.X, ctx)
if err != nil {
return constant.MakeUnknown(), err
}
y, err := evalExpr(expr.Y, ctx)
if err != nil {
return constant.MakeUnknown(), err
}
return constant.BinaryOp(x, expr.Op, y), nil
}
func evalIdent(expr *ast.Ident, ctx *ExprContext) (constant.Value, error) {
name, ok := ctx.vars[expr.Name]
if !ok {
return constant.MakeUnknown(), errors.New("unknown variable name")
}
n, err := strconv.ParseFloat(name, 64)
if err != nil {
return constant.MakeUnknown(), errors.New("variable type must be numeric")
}
return constant.MakeFloat64(n), nil
}
|