This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,249 @@
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
}

View File

@@ -0,0 +1,188 @@
package vars
import (
"github.com/iwind/TeaGo/assert"
"reflect"
"testing"
)
func TestFuncFloat(t *testing.T) {
a := assert.NewAssertion(t)
a.IsTrue(FuncFloat() == 0)
a.IsTrue(FuncFloat("123.456789") == 123.456789)
a.IsTrue(FuncFloat("123.456789", "%.2f") == "123.46")
}
func TestFuncFormat(t *testing.T) {
a := assert.NewAssertion(t)
t.Log(FuncFormat(123.456789, "%.2f"))
a.IsTrue(FuncFormat(123.456789, "%.2f") == "123.46")
a.IsTrue(FuncFormat(123.456123, "%.3f%s", "HELLO") == "123.456HELLO")
}
func TestFuncAppend(t *testing.T) {
a := assert.NewAssertion(t)
a.IsTrue(FuncAppend("a", "b", "c") == "abc")
}
func TestFuncCall(t *testing.T) {
{
funcType := reflect.ValueOf(FuncFloat)
values := funcType.Call([]reflect.Value{reflect.ValueOf("123.4567890123")})
for _, v := range values {
t.Log(v.Interface())
}
}
{
funcType := reflect.ValueOf(FuncAppend)
values := funcType.Call([]reflect.Value{reflect.ValueOf("a"), reflect.ValueOf("b"), reflect.ValueOf("c")})
for _, v := range values {
t.Log(v.Interface())
}
}
}
func TestRunFuncExpr(t *testing.T) {
a := assert.NewAssertion(t)
t.Log(RunFuncExpr(123.456789, []byte("float|format('%.3f%s,%s', 'a', 'b')|append('a1','b2','c3')")))
t.Log(RunFuncExpr(123.456, []byte("append('a', 'b2', 'c345\"', \"6789'10'\", '\\'Hello\\'\\\"')")))
t.Log(RunFuncExpr(123.456, []byte("append('78910')|float|format('%.6f')")))
t.Log(RunFuncExpr(123.456, []byte("format('%.2f') | append('a', 'b', 'c\td')")))
t.Log(RunFuncExpr(123.456, []byte("append(123.456, true, 'a')")))
t.Log(RunFuncExpr(123.456, []byte("")))
t.Log(RunFuncExpr(123.456, []byte(" ")))
{
v, err := RunFuncExpr(123.456, []byte(" format('%.2f')"))
if err != nil {
t.Fatal(err)
}
a.IsTrue(v == "123.46")
}
t.Log(RunFuncExpr(nil, []byte("float")))
{
v, err := RunFuncExpr("123.456", []byte("round"))
if err != nil {
t.Fatal(err)
}
t.Log(v)
a.IsTrue(v == int64(123))
}
{
v, err := RunFuncExpr("123.567", []byte("round"))
if err != nil {
t.Fatal(err)
}
t.Log(v)
a.IsTrue(v == int64(124))
}
{
v, err := RunFuncExpr("123.567", []byte("round(2)"))
if err != nil {
t.Fatal(err)
}
t.Log(v)
a.IsTrue(v == "123.57")
}
{
v, err := RunFuncExpr("123.4567123", []byte("round(4)"))
if err != nil {
t.Fatal(err)
}
t.Log(v)
a.IsTrue(v == "123.4567")
}
{
v, err := RunFuncExpr("123.567", []byte("ceil"))
if err != nil {
t.Fatal(err)
}
t.Log(v)
a.IsTrue(v == int64(124))
}
{
v, err := RunFuncExpr("123.567", []byte("floor"))
if err != nil {
t.Fatal(err)
}
t.Log(v)
a.IsTrue(v == int64(123))
}
}
func TestCheckLiteral(t *testing.T) {
a := assert.NewAssertion(t)
{
_, err := checkLiteral("abc")
a.IsNotNil(err)
t.Log(err)
}
{
result, err := checkLiteral("true")
a.IsNil(err)
a.IsTrue(result == true)
}
{
result, err := checkLiteral("false")
a.IsNil(err)
a.IsTrue(result == false)
}
{
result, err := checkLiteral("null")
a.IsNil(err)
a.IsTrue(result == nil)
}
{
result, err := checkLiteral("nil")
a.IsNil(err)
a.IsTrue(result == nil)
}
{
result, err := checkLiteral("123")
a.IsNil(err)
t.Log(result)
a.IsTrue(result == int64(123))
}
{
result, err := checkLiteral("+123")
a.IsNil(err)
t.Log(result)
a.IsTrue(result == int64(123))
}
{
result, err := checkLiteral("-123")
a.IsNil(err)
t.Log(result)
a.IsTrue(result == int64(-123))
}
{
result, err := checkLiteral("123.456")
a.IsNil(err)
t.Log(result)
a.IsTrue(result == 123.456)
}
{
result, err := checkLiteral("-123.456")
a.IsNil(err)
t.Log(result)
a.IsTrue(result == -123.456)
}
}