Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["expr_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"ast.go",
"check.go",
"eval.go",
"expr.go",
],
importpath = "go-common/app/service/live/zeus/expr",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,306 @@
package expr
import (
"bytes"
"fmt"
"strconv"
"strings"
"text/scanner"
"unicode"
)
const (
TokenEOF = -(iota + 1)
TokenIdent
TokenInt
TokenFloat
TokenString
TokenOperator
)
type lexer struct {
scan scanner.Scanner
token rune
text string
}
func (lex *lexer) getToken() rune {
return lex.token
}
func (lex *lexer) getText() string {
return lex.text
}
func (lex *lexer) next() {
token := lex.scan.Scan()
text := lex.scan.TokenText()
switch token {
case scanner.EOF:
lex.token = TokenEOF
lex.text = text
case scanner.Ident:
lex.token = TokenIdent
lex.text = text
case scanner.Int:
lex.token = TokenInt
lex.text = text
case scanner.Float:
lex.token = TokenFloat
lex.text = text
case scanner.RawString:
fallthrough
case scanner.String:
lex.token = TokenString
if len(text) >= 2 && ((text[0] == '`' && text[len(text)-1] == '`') || (text[0] == '"' && text[len(text)-1] == '"')) {
lex.text = text[1 : len(text)-1]
} else {
msg := fmt.Sprintf("got illegal string:%s", text)
panic(lexPanic(msg))
}
case '+', '-', '*', '/', '%', '~':
lex.token = TokenOperator
lex.text = text
case '&', '|', '=':
var buffer bytes.Buffer
lex.token = TokenOperator
buffer.WriteRune(token)
next := lex.scan.Peek()
if next == token {
buffer.WriteRune(next)
lex.scan.Scan()
}
lex.text = buffer.String()
case '>', '<', '!':
var buffer bytes.Buffer
lex.token = TokenOperator
buffer.WriteRune(token)
next := lex.scan.Peek()
if next == '=' {
buffer.WriteRune(next)
lex.scan.Scan()
}
lex.text = buffer.String()
default:
if token >= 0 {
lex.token = token
lex.text = text
} else {
msg := fmt.Sprintf("got unknown token:%d, text:%s", lex.token, lex.text)
panic(lexPanic(msg))
}
}
}
type lexPanic string
// describe returns a string describing the current token, for use in errors.
func (lex *lexer) describe() string {
switch lex.token {
case TokenEOF:
return "end of file"
case TokenIdent:
return fmt.Sprintf("identifier:%s", lex.getText())
case TokenInt, TokenFloat:
return fmt.Sprintf("number:%s", lex.getText())
case TokenString:
return fmt.Sprintf("string:%s", lex.getText())
}
return fmt.Sprintf("token:%d", rune(lex.getToken())) // any other rune
}
func precedence(token rune, text string) int {
if token == TokenOperator {
switch text {
case "~", "!":
return 9
case "*", "/", "%":
return 8
case "+", "-":
return 7
case ">", ">=", "<", "<=":
return 6
case "!=", "==", "=":
return 5
case "&":
return 4
case "|":
return 3
case "&&":
return 2
case "||":
return 1
default:
msg := fmt.Sprintf("unknown operator:%s", text)
panic(lexPanic(msg))
}
}
return 0
}
// ---- parser ----
type ExpressionParser struct {
expression Expr
variable map[string]struct{}
}
func NewExpressionParser() *ExpressionParser {
return &ExpressionParser{
expression: nil,
variable: make(map[string]struct{}),
}
}
// Parse parses the input string as an arithmetic expression.
//
// expr = num a literal number, e.g., 3.14159
// | id a variable name, e.g., x
// | id '(' expr ',' ... ')' a function call
// | '-' expr a unary operator ( + - ! )
// | expr '+' expr a binary operator ( + - * / && & || | == )
//
func (parser *ExpressionParser) Parse(input string) (err error) {
defer func() {
switch x := recover().(type) {
case nil:
// no panic
case lexPanic:
err = fmt.Errorf("%s", x)
default:
// unexpected panic: resume state of panic.
panic(x)
}
}()
lex := new(lexer)
lex.scan.Init(strings.NewReader(input))
lex.scan.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanRawStrings
lex.scan.IsIdentRune = parser.isIdentRune
lex.next() // initial lookahead
parser.expression = nil
parser.variable = make(map[string]struct{})
e := parser.parseExpr(lex)
if lex.token != scanner.EOF {
return fmt.Errorf("unexpected %s", lex.describe())
}
parser.expression = e
return nil
}
func (parser *ExpressionParser) GetExpr() Expr {
return parser.expression
}
func (parser *ExpressionParser) GetVariable() []string {
variable := make([]string, 0, len(parser.variable))
for v := range parser.variable {
if v != "true" && v != "false" {
variable = append(variable, v)
}
}
return variable
}
func (parser *ExpressionParser) isIdentRune(ch rune, i int) bool {
return ch == '$' || ch == '_' || ch == '?' || unicode.IsLetter(ch) || unicode.IsDigit(ch) && i > 0
}
func (parser *ExpressionParser) parseExpr(lex *lexer) Expr {
return parser.parseBinary(lex, 1)
}
// binary = unary ('+' binary)*
// parseBinary stops when it encounters an
// operator of lower precedence than prec1.
func (parser *ExpressionParser) parseBinary(lex *lexer, prec1 int) Expr {
lhs := parser.parseUnary(lex)
for prec := precedence(lex.getToken(), lex.getText()); prec >= prec1; prec-- {
for precedence(lex.getToken(), lex.getText()) == prec {
op := lex.getText()
lex.next() // consume operator
rhs := parser.parseBinary(lex, prec+1)
lhs = binary{op, lhs, rhs}
}
}
return lhs
}
// unary = '+' expr | primary
func (parser *ExpressionParser) parseUnary(lex *lexer) Expr {
if lex.getToken() == TokenOperator {
op := lex.getText()
if op == "+" || op == "-" || op == "~" || op == "!" {
lex.next()
return unary{op, parser.parseUnary(lex)}
} else {
msg := fmt.Sprintf("unary got unknown operator:%s", lex.getText())
panic(lexPanic(msg))
}
}
return parser.parsePrimary(lex)
}
// primary = id
// | id '(' expr ',' ... ',' expr ')'
// | num
// | '(' expr ')'
func (parser *ExpressionParser) parsePrimary(lex *lexer) Expr {
switch lex.token {
case TokenIdent:
id := lex.getText()
lex.next()
if lex.token != '(' {
parser.variable[id] = struct{}{}
return Var(id)
}
lex.next() // consume '('
var args []Expr
if lex.token != ')' {
for {
args = append(args, parser.parseExpr(lex))
if lex.token != ',' {
break
}
lex.next() // consume ','
}
if lex.token != ')' {
msg := fmt.Sprintf("got %q, want ')'", lex.token)
panic(lexPanic(msg))
}
}
lex.next() // consume ')'
return call{id, args}
case TokenFloat:
f, err := strconv.ParseFloat(lex.getText(), 64)
if err != nil {
panic(lexPanic(err.Error()))
}
lex.next()
return literal{value: f}
case TokenInt:
i, err := strconv.ParseInt(lex.getText(), 10, 64)
if err != nil {
panic(lexPanic(err.Error()))
}
lex.next()
return literal{value: i}
case TokenString:
s := lex.getText()
lex.next()
return literal{value: s}
case '(':
lex.next() // consume '('
e := parser.parseExpr(lex)
if lex.token != ')' {
msg := fmt.Sprintf("got %s, want ')'", lex.describe())
panic(lexPanic(msg))
}
lex.next() // consume ')'
return e
}
msg := fmt.Sprintf("unexpected %s", lex.describe())
panic(lexPanic(msg))
}

View File

@@ -0,0 +1,49 @@
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
package expr
import (
"fmt"
)
//!+Check
func (v Var) Check(vars map[Var]interface{}) error {
vars[v] = true
return nil
}
func (literal) Check(vars map[Var]interface{}) error {
return nil
}
func (u unary) Check(vars map[Var]interface{}) error {
return u.x.Check(vars)
}
func (b binary) Check(vars map[Var]interface{}) error {
if err := b.x.Check(vars); err != nil {
return err
}
return b.y.Check(vars)
}
func (c call) Check(vars map[Var]interface{}) error {
arity, ok := exprFuncParams[c.fn]
if !ok {
return fmt.Errorf("unknown function %q", c.fn)
}
if len(c.args) != arity {
return fmt.Errorf("call to %s has %d args, want %d",
c.fn, len(c.args), arity)
}
for _, arg := range c.args {
if err := arg.Check(vars); err != nil {
return err
}
}
return nil
}
//!-Check

View File

@@ -0,0 +1,602 @@
package expr
import (
"fmt"
"hash/crc32"
"math"
"math/rand"
"reflect"
"strings"
)
const kEpsilon = 1e-7
type Env map[Var]interface{}
type runtimePanic string
func EvalBool(expr Expr, env Env) (value bool, err error) {
defer func() {
switch x := recover().(type) {
case nil:
// no panic
case runtimePanic:
value = false
err = fmt.Errorf("%s", x)
default:
// unexpected panic: resume state of panic.
panic(x)
}
}()
if expr == nil {
return false, nil
}
value = ConvertToBool(expr.Eval(env))
return
}
func EvalInt(expr Expr, env Env) (value int64, err error) {
defer func() {
switch x := recover().(type) {
case nil:
// no panic
case runtimePanic:
value = 0
err = fmt.Errorf("%s", x)
default:
// unexpected panic: resume state of panic.
panic(x)
}
}()
if expr == nil {
return 0, nil
}
value = ConvertToInt(expr.Eval(env))
return
}
func (v Var) Eval(env Env) reflect.Value {
switch v {
case "true":
return reflect.ValueOf(true)
case "false":
return reflect.ValueOf(false)
default:
if i, ok := env[v]; ok {
return reflect.ValueOf(i)
}
panic(runtimePanic(fmt.Sprintf("undefined variable: %s", v)))
}
}
func (l literal) Eval(_ Env) reflect.Value {
return reflect.ValueOf(l.value)
}
func (u unary) Eval(env Env) reflect.Value {
switch u.op {
case "+":
return unaryPlus(u.x.Eval(env))
case "-":
return unaryMinus(u.x.Eval(env))
case "!":
return logicalNegation(u.x.Eval(env))
case "~":
return bitwiseComplement(u.x.Eval(env))
}
panic(runtimePanic(fmt.Sprintf("unsupported unary operator: %q", u.op)))
}
func (b binary) Eval(env Env) reflect.Value {
switch b.op {
case "+":
return addition(b.x.Eval(env), b.y.Eval(env))
case "-":
return subtraction(b.x.Eval(env), b.y.Eval(env))
case "*":
return multiplication(b.x.Eval(env), b.y.Eval(env))
case "/":
return division(b.x.Eval(env), b.y.Eval(env))
case "%":
return modulus(b.x.Eval(env), b.y.Eval(env))
case "&":
return bitwiseAnd(b.x.Eval(env), b.y.Eval(env))
case "&&":
return logicalAnd(b.x.Eval(env), b.y.Eval(env))
case "|":
return bitwiseOr(b.x.Eval(env), b.y.Eval(env))
case "||":
return logicalOr(b.x.Eval(env), b.y.Eval(env))
case "=", "==":
return comparisonEqual(b.x.Eval(env), b.y.Eval(env))
case ">":
return comparisonGreater(b.x.Eval(env), b.y.Eval(env))
case ">=":
return comparisonGreaterOrEqual(b.x.Eval(env), b.y.Eval(env))
case "<":
return comparisonLess(b.x.Eval(env), b.y.Eval(env))
case "<=":
return comparisonLessOrEqual(b.x.Eval(env), b.y.Eval(env))
case "!=":
return comparisonNotEqual(b.x.Eval(env), b.y.Eval(env))
}
panic(runtimePanic(fmt.Sprintf("unsupported binary operator: %q", b.op)))
}
func (c call) Eval(env Env) reflect.Value {
switch c.fn {
case "pow":
return reflect.ValueOf(math.Pow(ConvertToFloat(c.args[0].Eval(env)), ConvertToFloat(c.args[1].Eval(env))))
case "sin":
return reflect.ValueOf(math.Sin(ConvertToFloat(c.args[0].Eval(env))))
case "sqrt":
v := ConvertToFloat(c.args[0].Eval(env))
if v < 0 {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept normal number", c.fn)))
}
return reflect.ValueOf(math.Sqrt(v))
case "rand":
return reflect.ValueOf(rand.Float64())
case "log":
v := ConvertToFloat(c.args[0].Eval(env))
if v < 0 {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept normal number", c.fn)))
}
return reflect.ValueOf(math.Log10(v))
case "to_upper":
v := c.args[0].Eval(env)
if v.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept string", c.fn)))
}
return reflect.ValueOf(strings.ToUpper(v.String()))
case "to_lower":
v := c.args[0].Eval(env)
if v.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept string", c.fn)))
}
return reflect.ValueOf(strings.ToLower(v.String()))
case "crc32":
v := c.args[0].Eval(env)
if v.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept string", c.fn)))
}
return reflect.ValueOf(crc32.ChecksumIEEE([]byte(v.String())))
}
panic(runtimePanic(fmt.Sprintf("unsupported function call: %s", c.fn)))
}
func ConvertToBool(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() != 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return v.Uint() != 0
case reflect.Float32, reflect.Float64:
return v.Float() != 0
case reflect.String:
return v.String() != ""
default:
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to bool", v.Kind().String())))
}
}
func ConvertToInt(v reflect.Value) int64 {
switch v.Kind() {
case reflect.Bool:
if v.Bool() {
return 1
} else {
return 0
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return int64(v.Uint())
case reflect.Float32, reflect.Float64:
return int64(v.Float())
default:
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to int", v.Kind().String())))
}
}
func ConvertToUint(v reflect.Value) uint64 {
switch v.Kind() {
case reflect.Bool:
if v.Bool() {
return 1
} else {
return 0
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return uint64(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return v.Uint()
case reflect.Float32, reflect.Float64:
return uint64(v.Float())
default:
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to uint", v.Kind().String())))
}
}
func ConvertToFloat(v reflect.Value) float64 {
switch v.Kind() {
case reflect.Bool:
if v.Bool() {
return 1
} else {
return 0
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return float64(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return float64(v.Uint())
case reflect.Float32, reflect.Float64:
return v.Float()
default:
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to float", v.Kind().String())))
}
}
func unaryPlus(v reflect.Value) reflect.Value {
return v
}
func unaryMinus(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Bool:
return v
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return reflect.ValueOf(-v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return reflect.ValueOf(-v.Uint())
case reflect.Float32, reflect.Float64:
return reflect.ValueOf(-v.Float())
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) not support unary minus", v.Interface(), v.Kind().String())))
}
}
func logicalNegation(v reflect.Value) reflect.Value {
return reflect.ValueOf(!ConvertToBool(v))
}
func bitwiseComplement(v reflect.Value) reflect.Value {
switch v.Kind() {
case reflect.Bool:
return reflect.ValueOf(!v.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return reflect.ValueOf(^v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return reflect.ValueOf(^v.Uint())
case reflect.Float32, reflect.Float64:
panic(runtimePanic("cannot eval ~ for float"))
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) not support bitwise complement", v.Interface(), v.Kind().String())))
}
}
func typeLevel(k reflect.Kind) int {
switch k {
case reflect.String:
return 5
case reflect.Float32, reflect.Float64:
return 4
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return 3
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return 2
case reflect.Bool:
return 1
default:
return 0
}
}
func typeAscend(a reflect.Kind, b reflect.Kind) reflect.Kind {
if typeLevel(a) >= typeLevel(b) {
return a
} else {
return b
}
}
func addition(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) + ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) + ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) + ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) + ConvertToInt(right)
return reflect.ValueOf(r != 0)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support addition",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func subtraction(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) - ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) - ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) - ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) - ConvertToInt(right)
return reflect.ValueOf(r != 0)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support subtraction",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func multiplication(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) * ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) * ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) * ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) * ConvertToInt(right)
return reflect.ValueOf(r != 0)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support multiplication",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func division(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
lv := ConvertToFloat(left)
rv := ConvertToFloat(right)
if math.Abs(rv) < kEpsilon {
panic(runtimePanic(fmt.Sprintf("%f div %f, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv / rv)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
lv := ConvertToUint(left)
rv := ConvertToUint(right)
if rv == 0 {
panic(runtimePanic(fmt.Sprintf("%d div %d, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv / rv)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
lv := ConvertToInt(left)
rv := ConvertToInt(right)
if rv == 0 {
panic(runtimePanic(fmt.Sprintf("%d div %d, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv / rv)
case reflect.Bool:
lv := ConvertToInt(left)
rv := ConvertToInt(right)
if rv == 0 {
panic(runtimePanic(fmt.Sprintf("%d div %d, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv/rv != 0)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support division",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func modulus(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) % ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) % ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) % ConvertToInt(right)
return reflect.ValueOf(r != 0)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support division",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func bitwiseAnd(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) & ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) & ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToBool(left) && ConvertToBool(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support bitwise and",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func bitwiseOr(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) | ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) | ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToBool(left) || ConvertToBool(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support bitwise or",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func logicalAnd(left reflect.Value, right reflect.Value) reflect.Value {
r := ConvertToBool(left) && ConvertToBool(right)
return reflect.ValueOf(r)
}
func logicalOr(left reflect.Value, right reflect.Value) reflect.Value {
r := ConvertToBool(left) || ConvertToBool(right)
return reflect.ValueOf(r)
}
func comparisonEqual(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.String:
if left.Kind() != reflect.String || right.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support comparison equal",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
r := strings.Compare(left.String(), right.String()) == 0
return reflect.ValueOf(r)
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) == ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) == ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) == ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) == ConvertToInt(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support comparison equal",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func comparisonNotEqual(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.String:
if left.Kind() != reflect.String || right.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support comparison equal",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
r := strings.Compare(left.String(), right.String()) != 0
return reflect.ValueOf(r)
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) != ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) != ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) != ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) != ConvertToInt(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison not equal", left.Kind().String(), right.Kind().String())))
}
}
func comparisonGreater(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) > ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) > ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) > ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) > ConvertToInt(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison greater", left.Kind().String(), right.Kind().String())))
}
}
func comparisonGreaterOrEqual(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) >= ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) >= ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) >= ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) >= ConvertToInt(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison greater or equal", left.Kind().String(), right.Kind().String())))
}
}
func comparisonLess(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) < ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) < ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) < ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) < ConvertToInt(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison less", left.Kind().String(), right.Kind().String())))
}
}
func comparisonLessOrEqual(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.Float32, reflect.Float64:
r := ConvertToFloat(left) <= ConvertToFloat(right)
return reflect.ValueOf(r)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
r := ConvertToUint(left) <= ConvertToUint(right)
return reflect.ValueOf(r)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
r := ConvertToInt(left) <= ConvertToInt(right)
return reflect.ValueOf(r)
case reflect.Bool:
r := ConvertToInt(left) <= ConvertToInt(right)
return reflect.ValueOf(r)
default:
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison less or equal", left.Kind().String(), right.Kind().String())))
}
}

View File

@@ -0,0 +1,48 @@
package expr
import "reflect"
// A Var identifies a variable, e.g., x.
type Var string
// A literal is a numeric constant, e.g., 3.141.
type literal struct {
value interface{}
}
// An Expr is an arithmetic expression.
type Expr interface {
// Eval returns the value of this Expr in the environment env.
Eval(env Env) reflect.Value
// Check reports errors in this Expr and adds its Vars to the set.
Check(vars map[Var]interface{}) error
}
// A unary represents a unary operator expression, e.g., -x.
type unary struct {
op string // one of '+', '-', '!', '~'
x Expr
}
// A binary represents a binary operator expression, e.g., x+y.
type binary struct {
op string
x, y Expr
}
// A call represents a function call expression, e.g., sin(x).
type call struct {
fn string
args []Expr
}
var exprFuncParams = map[string]int{
"pow": 2,
"sin": 1,
"sqrt": 1,
"rand": 0,
"log": 1,
"to_upper": 1,
"to_lower": 1,
"crc32": 1,
}

View File

@@ -0,0 +1,60 @@
package expr
import (
"fmt"
"testing"
)
func TestExpr(t *testing.T) {
defer func() {
switch x := recover().(type) {
case nil:
// no panic
case runtimePanic:
fmt.Println(x)
panic(x)
default:
// unexpected panic: resume state of panic.
panic(x)
}
}()
tests := []struct {
expr string
env Env
want string
}{
{`$x == "android"`, Env{"$x": "android"}, "true"},
{"$x == `android`", Env{"$x": "android"}, "true"},
{"to_lower($x) == `android`", Env{"$x": "AnDroId"}, "true"},
{"to_lower($x) == `android`", Env{"$x": "iOS"}, "false"},
{"log($1 + 9 * $1)", Env{"$1": 100}, "3"},
{"$1 > 80 && $2 <9", Env{"$1": 100, "$2": 2}, "true"},
{"pow(x, false) + pow(y, false)", Env{"x": 12, "y": 1}, "2"},
{"pow(x, 3) + pow(y, 3)", Env{"x": 9, "y": 10}, "1729"},
{"9 * (F - 32)/5", Env{"F": -40}, "-129"},
{"-1 + -x", Env{"x": 1}, "-2"},
{"-1 - x", Env{"x": 1}, "-2"},
{"a >= 10", Env{"a": 15}, "true"},
{"b >= sin(10) && a < 1", Env{"a": 9, "b": 10}, "false"},
{"!!!true", Env{"a": 9, "b": 10}, "false"},
}
var prevExpr string
parser := NewExpressionParser()
for _, test := range tests {
// Print expr only when it changes.
if test.expr != prevExpr {
t.Logf("\n%s\n", test.expr)
prevExpr = test.expr
}
if err := parser.Parse(test.expr); err != nil {
t.Error(err) // parse error
continue
}
got := fmt.Sprintf("%v", parser.GetExpr().Eval(test.env))
t.Logf("%s\t%v => %s\n", test.expr, test.env, got)
if got != test.want {
t.Errorf("%s.Eval() in %v = %q, want %q\n",
test.expr, test.env, got, test.want)
}
}
}