mirror of
https://github.com/TeaOSLab/EdgeCommon.git
synced 2025-11-04 05:00:24 +08:00
250 lines
5.5 KiB
Go
250 lines
5.5 KiB
Go
|
|
package vars
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"bytes"
|
|||
|
|
"errors"
|
|||
|
|
"fmt"
|
|||
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
|||
|
|
"github.com/iwind/TeaGo/types"
|
|||
|
|
"math"
|
|||
|
|
"reflect"
|
|||
|
|
"strconv"
|
|||
|
|
"strings"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// func列表,code => type
|
|||
|
|
var funcMap = map[string]reflect.Value{
|
|||
|
|
"float": reflect.ValueOf(FuncFloat),
|
|||
|
|
"round": reflect.ValueOf(FuncRound),
|
|||
|
|
"ceil": reflect.ValueOf(FuncCeil),
|
|||
|
|
"floor": reflect.ValueOf(FuncFloor),
|
|||
|
|
"format": reflect.ValueOf(FuncFormat),
|
|||
|
|
"append": reflect.ValueOf(FuncAppend),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FuncFloat 浮点数处理
|
|||
|
|
// float | float('%.2f')
|
|||
|
|
func FuncFloat(args ...interface{}) interface{} {
|
|||
|
|
if len(args) == 0 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
if len(args) == 1 {
|
|||
|
|
return types.Float64(args[0])
|
|||
|
|
}
|
|||
|
|
args[0] = types.Float64(args[0])
|
|||
|
|
return FuncFormat(args...)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FuncRound 对数字四舍五入
|
|||
|
|
// round | round(2)
|
|||
|
|
func FuncRound(args ...interface{}) interface{} {
|
|||
|
|
if len(args) == 0 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
if len(args) == 1 {
|
|||
|
|
return int64(math.Round(types.Float64(args[0])))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
precision := types.Int64(args[1])
|
|||
|
|
if precision <= 0 {
|
|||
|
|
return int64(math.Round(types.Float64(args[0])))
|
|||
|
|
}
|
|||
|
|
return fmt.Sprintf("%."+strconv.FormatInt(precision, 10)+"f", types.Float64(args[0]))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FuncCeil 对数字进行取不小于它的整数
|
|||
|
|
// ceil
|
|||
|
|
func FuncCeil(args ...interface{}) interface{} {
|
|||
|
|
if len(args) == 0 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
return int64(math.Ceil(types.Float64(args[0])))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FuncFloor 对数字进行取不大于它的整数
|
|||
|
|
// floor
|
|||
|
|
func FuncFloor(args ...interface{}) interface{} {
|
|||
|
|
if len(args) == 0 {
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
return int64(math.Floor(types.Float64(args[0])))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FuncFormat 格式化
|
|||
|
|
// format('%.2f')
|
|||
|
|
func FuncFormat(args ...interface{}) interface{} {
|
|||
|
|
if len(args) == 0 {
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
if len(args) == 1 {
|
|||
|
|
return types.String(args[0])
|
|||
|
|
}
|
|||
|
|
format := types.String(args[1])
|
|||
|
|
if len(args) == 2 {
|
|||
|
|
return fmt.Sprintf(format, args[0])
|
|||
|
|
} else {
|
|||
|
|
return fmt.Sprintf(format, append([]interface{}{args[0]}, args[2:]...)...)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FuncAppend 附加字符串
|
|||
|
|
// append('a', 'b')
|
|||
|
|
func FuncAppend(args ...interface{}) interface{} {
|
|||
|
|
s := strings.Builder{}
|
|||
|
|
for _, arg := range args {
|
|||
|
|
s.WriteString(types.String(arg))
|
|||
|
|
}
|
|||
|
|
return s.String()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RunFuncExpr 执行函数表达式
|
|||
|
|
func RunFuncExpr(value interface{}, expr []byte) (interface{}, error) {
|
|||
|
|
// 防止因nil参数导致panic
|
|||
|
|
if value == nil {
|
|||
|
|
value = ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 空表达式直接返回
|
|||
|
|
if len(expr) == 0 || len(bytes.TrimSpace(expr)) == 0 {
|
|||
|
|
return value, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
identifier := []byte{}
|
|||
|
|
|
|||
|
|
isInQuote := false
|
|||
|
|
isQuoted := false
|
|||
|
|
quoteByte := byte(0)
|
|||
|
|
funcCode := ""
|
|||
|
|
args := []interface{}{value}
|
|||
|
|
|
|||
|
|
for index, b := range expr {
|
|||
|
|
switch b {
|
|||
|
|
case '|':
|
|||
|
|
if isInQuote {
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
} else { // end function
|
|||
|
|
if len(funcCode) == 0 {
|
|||
|
|
funcCode = string(identifier)
|
|||
|
|
} else if len(identifier) > 0 {
|
|||
|
|
return value, errors.New("invalid identifier '" + string(identifier) + "'")
|
|||
|
|
}
|
|||
|
|
value, err := callFunc(funcCode, args)
|
|||
|
|
if err != nil {
|
|||
|
|
return value, err
|
|||
|
|
}
|
|||
|
|
return RunFuncExpr(value, expr[index+1:])
|
|||
|
|
}
|
|||
|
|
case '(':
|
|||
|
|
if isInQuote {
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
} else {
|
|||
|
|
funcCode = string(identifier)
|
|||
|
|
identifier = []byte{}
|
|||
|
|
}
|
|||
|
|
case ',', ')':
|
|||
|
|
if isInQuote {
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
} else {
|
|||
|
|
if isQuoted {
|
|||
|
|
isQuoted = false
|
|||
|
|
args = append(args, string(identifier))
|
|||
|
|
} else {
|
|||
|
|
arg, err := checkLiteral(string(identifier))
|
|||
|
|
if err != nil {
|
|||
|
|
return value, err
|
|||
|
|
}
|
|||
|
|
args = append(args, arg)
|
|||
|
|
}
|
|||
|
|
identifier = []byte{}
|
|||
|
|
}
|
|||
|
|
case '\\':
|
|||
|
|
if isInQuote && (index == len(expr)-1 || expr[index+1] != quoteByte) {
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
} else {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
case '\'', '"':
|
|||
|
|
if isInQuote {
|
|||
|
|
if quoteByte == b && expr[index-1] != '\\' {
|
|||
|
|
isInQuote = false
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
} else if index == 0 || expr[index-1] != '\\' {
|
|||
|
|
isInQuote = true
|
|||
|
|
isQuoted = true
|
|||
|
|
quoteByte = b
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
case ' ', '\t':
|
|||
|
|
if isInQuote {
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
}
|
|||
|
|
default:
|
|||
|
|
identifier = append(identifier, b)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if len(funcCode) == 0 {
|
|||
|
|
funcCode = string(identifier)
|
|||
|
|
} else if len(identifier) > 0 {
|
|||
|
|
return value, errors.New("invalid identifier '" + string(identifier) + "'")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return callFunc(funcCode, args)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RegisterFunc 注册一个函数
|
|||
|
|
func RegisterFunc(code string, f interface{}) {
|
|||
|
|
funcMap[code] = reflect.ValueOf(f)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用一个函数
|
|||
|
|
func callFunc(funcCode string, args []interface{}) (value interface{}, err error) {
|
|||
|
|
fn, ok := funcMap[funcCode]
|
|||
|
|
if !ok {
|
|||
|
|
return value, errors.New("function '" + funcCode + "' not found")
|
|||
|
|
}
|
|||
|
|
argValues := []reflect.Value{}
|
|||
|
|
for _, arg := range args {
|
|||
|
|
argValues = append(argValues, reflect.ValueOf(arg))
|
|||
|
|
}
|
|||
|
|
result := fn.Call(argValues)
|
|||
|
|
if len(result) == 0 {
|
|||
|
|
value = nil
|
|||
|
|
} else {
|
|||
|
|
value = result[0].Interface()
|
|||
|
|
}
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查字面量,支持true, false, null, nil和整数数字、浮点数数字(不支持e)
|
|||
|
|
func checkLiteral(identifier string) (result interface{}, err error) {
|
|||
|
|
if len(identifier) == 0 {
|
|||
|
|
return "", nil
|
|||
|
|
}
|
|||
|
|
switch strings.ToLower(identifier) {
|
|||
|
|
case "true":
|
|||
|
|
result = true
|
|||
|
|
return
|
|||
|
|
case "false":
|
|||
|
|
result = false
|
|||
|
|
return
|
|||
|
|
case "null", "nil":
|
|||
|
|
result = nil
|
|||
|
|
return
|
|||
|
|
default:
|
|||
|
|
if shared.RegexpAllDigitNumber.MatchString(identifier) {
|
|||
|
|
result = types.Int64(identifier)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
if shared.RegexpAllFloatNumber.MatchString(identifier) {
|
|||
|
|
result = types.Float64(identifier)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = errors.New("undefined identifier '" + identifier + "'")
|
|||
|
|
return
|
|||
|
|
}
|