/internal/teaconfigs/agents/var_func.go

https://github.com/TeaWeb/build · Go · 249 lines · 219 code · 14 blank · 16 comment · 51 complexity · 4d7f5b91abdd2db09a30d070f634d44c MD5 · raw file

  1. package agents
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "github.com/TeaWeb/build/internal/teaconfigs/shared"
  7. "github.com/iwind/TeaGo/types"
  8. "math"
  9. "reflect"
  10. "strconv"
  11. "strings"
  12. )
  13. // func列表,code => type
  14. var funcMap = map[string]reflect.Value{
  15. "float": reflect.ValueOf(FuncFloat),
  16. "round": reflect.ValueOf(FuncRound),
  17. "ceil": reflect.ValueOf(FuncCeil),
  18. "floor": reflect.ValueOf(FuncFloor),
  19. "format": reflect.ValueOf(FuncFormat),
  20. "append": reflect.ValueOf(FuncAppend),
  21. }
  22. // 浮点数处理
  23. // float | float('%.2f')
  24. func FuncFloat(args ...interface{}) interface{} {
  25. if len(args) == 0 {
  26. return 0
  27. }
  28. if len(args) == 1 {
  29. return types.Float64(args[0])
  30. }
  31. args[0] = types.Float64(args[0])
  32. return FuncFormat(args...)
  33. }
  34. // 对数字四舍五入
  35. // round | round(2)
  36. func FuncRound(args ...interface{}) interface{} {
  37. if len(args) == 0 {
  38. return 0
  39. }
  40. if len(args) == 1 {
  41. return int64(math.Round(types.Float64(args[0])))
  42. }
  43. precision := types.Int64(args[1])
  44. if precision <= 0 {
  45. return int64(math.Round(types.Float64(args[0])))
  46. }
  47. return fmt.Sprintf("%."+strconv.FormatInt(precision, 10)+"f", types.Float64(args[0]))
  48. }
  49. // 对数字进行取不小于它的整数
  50. // ceil
  51. func FuncCeil(args ...interface{}) interface{} {
  52. if len(args) == 0 {
  53. return 0
  54. }
  55. return int64(math.Ceil(types.Float64(args[0])))
  56. }
  57. // 对数字进行取不大于它的整数
  58. // floor
  59. func FuncFloor(args ...interface{}) interface{} {
  60. if len(args) == 0 {
  61. return 0
  62. }
  63. return int64(math.Floor(types.Float64(args[0])))
  64. }
  65. // 格式化
  66. // format('%.2f')
  67. func FuncFormat(args ...interface{}) interface{} {
  68. if len(args) == 0 {
  69. return ""
  70. }
  71. if len(args) == 1 {
  72. return types.String(args[0])
  73. }
  74. format := types.String(args[1])
  75. if len(args) == 2 {
  76. return fmt.Sprintf(format, args[0])
  77. } else {
  78. return fmt.Sprintf(format, append([]interface{}{args[0]}, args[2:]...)...)
  79. }
  80. }
  81. // 附加字符串
  82. // append('a', 'b')
  83. func FuncAppend(args ...interface{}) interface{} {
  84. s := strings.Builder{}
  85. for _, arg := range args {
  86. s.WriteString(types.String(arg))
  87. }
  88. return s.String()
  89. }
  90. // 执行函数表达式
  91. func RunFuncExpr(value interface{}, expr []byte) (interface{}, error) {
  92. // 防止因nil参数导致panic
  93. if value == nil {
  94. value = ""
  95. }
  96. // 空表达式直接返回
  97. if len(expr) == 0 || len(bytes.TrimSpace(expr)) == 0 {
  98. return value, nil
  99. }
  100. identifier := []byte{}
  101. isInQuote := false
  102. isQuoted := false
  103. quoteByte := byte(0)
  104. funcCode := ""
  105. args := []interface{}{value}
  106. for index, b := range expr {
  107. switch b {
  108. case '|':
  109. if isInQuote {
  110. identifier = append(identifier, b)
  111. } else { // end function
  112. if len(funcCode) == 0 {
  113. funcCode = string(identifier)
  114. } else if len(identifier) > 0 {
  115. return value, errors.New("invalid identifier '" + string(identifier) + "'")
  116. }
  117. value, err := callFunc(funcCode, args)
  118. if err != nil {
  119. return value, err
  120. }
  121. return RunFuncExpr(value, expr[index+1:])
  122. }
  123. case '(':
  124. if isInQuote {
  125. identifier = append(identifier, b)
  126. } else {
  127. funcCode = string(identifier)
  128. identifier = []byte{}
  129. }
  130. case ',', ')':
  131. if isInQuote {
  132. identifier = append(identifier, b)
  133. } else {
  134. if isQuoted {
  135. isQuoted = false
  136. args = append(args, string(identifier))
  137. } else {
  138. arg, err := checkLiteral(string(identifier))
  139. if err != nil {
  140. return value, err
  141. }
  142. args = append(args, arg)
  143. }
  144. identifier = []byte{}
  145. }
  146. case '\\':
  147. if isInQuote && (index == len(expr)-1 || expr[index+1] != quoteByte) {
  148. identifier = append(identifier, b)
  149. } else {
  150. continue
  151. }
  152. case '\'', '"':
  153. if isInQuote {
  154. if quoteByte == b && expr[index-1] != '\\' {
  155. isInQuote = false
  156. break
  157. }
  158. } else if index == 0 || expr[index-1] != '\\' {
  159. isInQuote = true
  160. isQuoted = true
  161. quoteByte = b
  162. break
  163. }
  164. identifier = append(identifier, b)
  165. case ' ', '\t':
  166. if isInQuote {
  167. identifier = append(identifier, b)
  168. }
  169. default:
  170. identifier = append(identifier, b)
  171. }
  172. }
  173. if len(funcCode) == 0 {
  174. funcCode = string(identifier)
  175. } else if len(identifier) > 0 {
  176. return value, errors.New("invalid identifier '" + string(identifier) + "'")
  177. }
  178. return callFunc(funcCode, args)
  179. }
  180. // 注册一个函数
  181. func RegisterFunc(code string, f interface{}) {
  182. funcMap[code] = reflect.ValueOf(f)
  183. }
  184. // 调用一个函数
  185. func callFunc(funcCode string, args []interface{}) (value interface{}, err error) {
  186. fn, ok := funcMap[funcCode]
  187. if !ok {
  188. return value, errors.New("function '" + funcCode + "' not found")
  189. }
  190. argValues := []reflect.Value{}
  191. for _, arg := range args {
  192. argValues = append(argValues, reflect.ValueOf(arg))
  193. }
  194. result := fn.Call(argValues)
  195. if len(result) == 0 {
  196. value = nil
  197. } else {
  198. value = result[0].Interface()
  199. }
  200. return
  201. }
  202. // 检查字面量,支持true, false, null, nil和整数数字、浮点数数字(不支持e)
  203. func checkLiteral(identifier string) (result interface{}, err error) {
  204. if len(identifier) == 0 {
  205. return "", nil
  206. }
  207. switch strings.ToLower(identifier) {
  208. case "true":
  209. result = true
  210. return
  211. case "false":
  212. result = false
  213. return
  214. case "null", "nil":
  215. result = nil
  216. return
  217. default:
  218. if shared.RegexpAllDigitNumber.MatchString(identifier) {
  219. result = types.Int64(identifier)
  220. return
  221. }
  222. if shared.RegexpAllFloatNumber.MatchString(identifier) {
  223. result = types.Float64(identifier)
  224. return
  225. }
  226. }
  227. err = errors.New("undefined identifier '" + identifier + "'")
  228. return
  229. }