1. govaluate
govaluate提供了简单的C类似的表达式的求值功能.
expression, err := govaluate.NewEvaluableExpression("10 > 0");
result, err := expression.Evaluate(nil);
// result is now set to "true", the bool value.
传参需要用个map[string]interface{}
来传递.
expression, err := govaluate.NewEvaluableExpression("(requests_made * requests_succeeded / 100) >= 90");
parameters := make(map[string]interface{}, 8)
parameters["requests_made"] = 100;
parameters["requests_succeeded"] = 80;
result, err := expression.Evaluate(parameters);
// result is now set to "false", the bool value.
除了返回bool, 也可以返回数字
expression, err := govaluate.NewEvaluableExpression("(mem_used / total_mem) * 100");
parameters := make(map[string]interface{}, 8)
parameters["total_mem"] = 1024;
parameters["mem_used"] = 512;
result, err := expression.Evaluate(parameters);
// result is now set to "50.0", the float64 value.
也可以预定义可以执行的函数, 用govaluate.NewEvaluableExpressionWithFunctions
注册
functions := map[string]govaluate.ExpressionFunction {
"strlen": func(args ...interface{}) (interface{}, error) {
length := len(args[0].(string))
return (float64)(length), nil
},
}
expString := "strlen('someReallyLongInputString') <= 16"
expression, _ := govaluate.NewEvaluableExpressionWithFunctions(expString, functions)
result, _ := expression.Evaluate(nil)
// result is now "false", the boolean value
1.1. parse阶段
func NewEvaluableExpression(expression string) (*EvaluableExpression, error) {
functions := make(map[string]ExpressionFunction)
return NewEvaluableExpressionWithFunctions(expression, functions)
//也要经过解析token
//在循环里逐个查看字符, 获得token的切片: []ExpressionToken -- 这里的token都不是一个ast
ret.tokens, err = parseTokens(expression, functions)
err = checkBalance(ret.tokens)
err = checkExpressionSyntax(ret.tokens)
//优化token slice.
ret.tokens, err = optimizeTokens(ret.tokens)
//planStages把token列表转为执行树
ret.evaluationStages, err = planStages(ret.tokens)
}
1.1.1. parseTokens
对input的每个字符都parse
func newLexerStream(source string) *lexerStream {
var ret *lexerStream
var runes []rune
for _, character := range source {
runes = append(runes, character)
}
ret = new(lexerStream)
ret.source = runes
ret.length = len(runes)
return ret
}
1.1.2. token类型
token是{Kind, Value}
type ExpressionToken struct {
//Kind是预定义的int标号
Kind TokenKind
//值就是万能interface
Value interface{}
}
type TokenKind int
const (
UNKNOWN TokenKind = iota
PREFIX
NUMERIC
BOOLEAN
STRING
PATTERN
TIME
VARIABLE
FUNCTION
SEPARATOR
ACCESSOR
COMPARATOR
LOGICALOP
MODIFIER
CLAUSE
CLAUSE_CLOSE
TERNARY
)
1.1.3. planStages
从token到执行树. 那么执行树里面有什么呢?
/*
Creates a `evaluationStageList` object which represents an execution plan (or tree)
which is used to completely evaluate a set of tokens at evaluation-time.
The three stages of evaluation can be thought of as parsing strings to tokens, then tokens to a stage list, then evaluation with parameters.
*/
func planStages(tokens []ExpressionToken) (*evaluationStage, error) {
stream := newTokenStream(tokens)
stage, err := planTokens(stream)
if err != nil {
return nil, err
}
// while we're now fully-planned, we now need to re-order same-precedence operators.
// this could probably be avoided with a different planning method
reorderStages(stage)
stage = elideLiterals(stage)
return stage, nil
}
1.1.4. operator
在plan执行树的时候, 所有最底层的操作都被定义为evaluationStage.operator
/*
A truly special precedence function, this handles all the "lowest-case" errata of the process, including literals, parmeters,
clauses, and prefixes.
*/
func planValue(stream *tokenStream) (*evaluationStage, error) {
...
//根据token的kind信息决定operator
switch token.Kind {
...
case VARIABLE:
operator = makeParameterStage(token.Value.(string))
case NUMERIC:
fallthrough
case STRING:
fallthrough
case PATTERN:
fallthrough
case BOOLEAN:
symbol = LITERAL
operator = makeLiteralStage(token.Value)
}
}
每个具体的操作都有对应的stage
func subtractStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) {
return left.(float64) - right.(float64), nil
}
func multiplyStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) {
return left.(float64) * right.(float64), nil
}
它们被放到一个map表里
var stageSymbolMap = map[OperatorSymbol]evaluationOperator{
EQ: equalStage,
NEQ: notEqualStage,
GT: gtStage,
LT: ltStage,
GTE: gteStage,
LTE: lteStage,
REQ: regexStage,
NREQ: notRegexStage,
AND: andStage,
OR: orStage,
IN: inStage,
BITWISE_OR: bitwiseOrStage,
BITWISE_AND: bitwiseAndStage,
BITWISE_XOR: bitwiseXORStage,
BITWISE_LSHIFT: leftShiftStage,
BITWISE_RSHIFT: rightShiftStage,
PLUS: addStage,
MINUS: subtractStage,
MULTIPLY: multiplyStage,
DIVIDE: divideStage,
MODULUS: modulusStage,
EXPONENT: exponentStage,
NEGATE: negateStage,
INVERT: invertStage,
BITWISE_NOT: bitwiseNotStage,
TERNARY_TRUE: ternaryIfStage,
TERNARY_FALSE: ternaryElseStage,
COALESCE: ternaryElseStage,
SEPARATE: separatorStage,
}
1.2. 执行阶段
/*
Same as `Eval`, but automatically wraps a map of parameters into a `govalute.Parameters` structure.
*/
func (this EvaluableExpression) Evaluate(parameters map[string]interface{}) (interface{}, error) {
if parameters == nil {
return this.Eval(nil)
}
/*
Runs the entire expression using the given [parameters].
e.g., If the expression contains a reference to the variable "foo", it will be taken from `parameters.Get("foo")`.
This function returns errors if the combination of expression and parameters cannot be run,
such as if a variable in the expression is not present in [parameters].
In all non-error circumstances, this returns the single value result of the expression and parameters given.
e.g., if the expression is "1 + 1", this will return 2.0.
e.g., if the expression is "foo + 1" and parameters contains "foo" = 2, this will return 3.0
*/
return this.Eval(MapParameters(parameters)) {
return this.evaluateStage(this.evaluationStages, parameters) {
//这里其实对应的是这个stage, 比如是multiplyStage, 执行
//left.(float64) * right.(float64), nil
return stage.operator(left, right, parameters)
}
}
}
1.3. 总结
这个库是个非常简化版的解释器. 也有标准的三步:
- token阶段, 对应ast
- planStage阶段, 每个基础操作都有个operaor, 对应执行树
- 执行阶段, 执行预定义好的动作operaor.