macro.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. package macro
  2. import (
  3. "fmt"
  4. "reflect"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. "unicode"
  9. )
  10. type (
  11. // ParamEvaluator is the signature for param type evaluator.
  12. // It accepts the param's value as string and returns
  13. // the <T> value (which its type is used for the input argument of the parameter functions, if any)
  14. // and a true value for passed, otherwise nil and false should be returned.
  15. ParamEvaluator func(paramValue string) (interface{}, bool)
  16. )
  17. var goodEvaluatorFuncs = []reflect.Type{
  18. reflect.TypeOf(func(string) (interface{}, bool) { return nil, false }),
  19. reflect.TypeOf(ParamEvaluator(func(string) (interface{}, bool) { return nil, false })),
  20. }
  21. func goodParamFunc(typ reflect.Type) bool {
  22. if typ.Kind() == reflect.Func { // it should be a func which returns a func (see below check).
  23. if typ.NumOut() == 1 {
  24. typOut := typ.Out(0)
  25. if typOut.Kind() != reflect.Func {
  26. return false
  27. }
  28. if typOut.NumOut() == 2 { // if it's a type of EvaluatorFunc, used for param evaluator.
  29. for _, fType := range goodEvaluatorFuncs {
  30. if typOut == fType {
  31. return true
  32. }
  33. }
  34. return false
  35. }
  36. if typOut.NumIn() == 1 && typOut.NumOut() == 1 { // if it's a type of func(paramValue [int,string...]) bool, used for param funcs.
  37. return typOut.Out(0).Kind() == reflect.Bool
  38. }
  39. }
  40. }
  41. return false
  42. }
  43. // Regexp accepts a regexp "expr" expression
  44. // and returns its MatchString.
  45. // The regexp is compiled before return.
  46. //
  47. // Returns a not-nil error on regexp compile failure.
  48. func Regexp(expr string) (func(string) bool, error) {
  49. if expr == "" {
  50. return nil, fmt.Errorf("empty regex expression")
  51. }
  52. // add the last $ if missing (and not wildcard(?))
  53. if i := expr[len(expr)-1]; i != '$' && i != '*' {
  54. expr += "$"
  55. }
  56. r, err := regexp.Compile(expr)
  57. if err != nil {
  58. return nil, err
  59. }
  60. return r.MatchString, nil
  61. }
  62. // MustRegexp same as Regexp
  63. // but it panics on the "expr" parse failure.
  64. func MustRegexp(expr string) func(string) bool {
  65. r, err := Regexp(expr)
  66. if err != nil {
  67. panic(err)
  68. }
  69. return r
  70. }
  71. // goodParamFuncName reports whether the function name is a valid identifier.
  72. func goodParamFuncName(name string) bool {
  73. if name == "" {
  74. return false
  75. }
  76. // valid names are only letters and _
  77. for _, r := range name {
  78. switch {
  79. case r == '_':
  80. case !unicode.IsLetter(r):
  81. return false
  82. }
  83. }
  84. return true
  85. }
  86. // the convertBuilderFunc return value is generating at boot time.
  87. // convertFunc converts an interface to a valid full param function.
  88. func convertBuilderFunc(fn interface{}) ParamFuncBuilder {
  89. typFn := reflect.TypeOf(fn)
  90. if !goodParamFunc(typFn) {
  91. // it's not a function which returns a function,
  92. // it's not a a func(compileArgs) func(requestDynamicParamValue) bool
  93. // but it's a func(requestDynamicParamValue) bool, such as regexp.Compile.MatchString
  94. if typFn.NumIn() == 1 && typFn.In(0).Kind() == reflect.String && typFn.NumOut() == 1 && typFn.Out(0).Kind() == reflect.Bool {
  95. fnV := reflect.ValueOf(fn)
  96. // let's convert it to a ParamFuncBuilder which its combile route arguments are empty and not used at all.
  97. // the below return function runs on each route that this param type function is used in order to validate the function,
  98. // if that param type function is used wrongly it will be panic like the rest,
  99. // indeed the only check is the len of arguments not > 0, no types of values or conversions,
  100. // so we return it as soon as possible.
  101. return func(args []string) reflect.Value {
  102. if n := len(args); n > 0 {
  103. panic(fmt.Sprintf("%T does not allow any input arguments from route but got [len=%d,values=%s]", fn, n, strings.Join(args, ", ")))
  104. }
  105. return fnV
  106. }
  107. }
  108. return nil
  109. }
  110. numFields := typFn.NumIn()
  111. panicIfErr := func(i int, err error) {
  112. if err != nil {
  113. panic(fmt.Sprintf("on field index: %d: %v", i, err))
  114. }
  115. }
  116. return func(args []string) reflect.Value {
  117. if len(args) != numFields {
  118. // no variadics support, for now.
  119. panic(fmt.Sprintf("args(len=%d) should be the same len as numFields(%d) for: %s", len(args), numFields, typFn))
  120. }
  121. var argValues []reflect.Value
  122. for i := 0; i < numFields; i++ {
  123. field := typFn.In(i)
  124. arg := args[i]
  125. // try to convert the string literal as we get it from the parser.
  126. var (
  127. val interface{}
  128. )
  129. // try to get the value based on the expected type.
  130. switch field.Kind() {
  131. case reflect.Int:
  132. v, err := strconv.Atoi(arg)
  133. panicIfErr(i, err)
  134. val = v
  135. case reflect.Int8:
  136. v, err := strconv.ParseInt(arg, 10, 8)
  137. panicIfErr(i, err)
  138. val = int8(v)
  139. case reflect.Int16:
  140. v, err := strconv.ParseInt(arg, 10, 16)
  141. panicIfErr(i, err)
  142. val = int16(v)
  143. case reflect.Int32:
  144. v, err := strconv.ParseInt(arg, 10, 32)
  145. panicIfErr(i, err)
  146. val = int32(v)
  147. case reflect.Int64:
  148. v, err := strconv.ParseInt(arg, 10, 64)
  149. panicIfErr(i, err)
  150. val = v
  151. case reflect.Uint:
  152. v, err := strconv.ParseUint(arg, 10, strconv.IntSize)
  153. panicIfErr(i, err)
  154. val = uint(v)
  155. case reflect.Uint8:
  156. v, err := strconv.ParseUint(arg, 10, 8)
  157. panicIfErr(i, err)
  158. val = uint8(v)
  159. case reflect.Uint16:
  160. v, err := strconv.ParseUint(arg, 10, 16)
  161. panicIfErr(i, err)
  162. val = uint16(v)
  163. case reflect.Uint32:
  164. v, err := strconv.ParseUint(arg, 10, 32)
  165. panicIfErr(i, err)
  166. val = uint32(v)
  167. case reflect.Uint64:
  168. v, err := strconv.ParseUint(arg, 10, 64)
  169. panicIfErr(i, err)
  170. val = v
  171. case reflect.Float32:
  172. v, err := strconv.ParseFloat(arg, 32)
  173. panicIfErr(i, err)
  174. val = float32(v)
  175. case reflect.Float64:
  176. v, err := strconv.ParseFloat(arg, 64)
  177. panicIfErr(i, err)
  178. val = v
  179. case reflect.Bool:
  180. v, err := strconv.ParseBool(arg)
  181. panicIfErr(i, err)
  182. val = v
  183. case reflect.Slice:
  184. if len(arg) > 1 {
  185. if arg[0] == '[' && arg[len(arg)-1] == ']' {
  186. // it is a single argument but as slice.
  187. val = strings.Split(arg[1:len(arg)-1], ",") // only string slices.
  188. }
  189. }
  190. default:
  191. val = arg
  192. }
  193. argValue := reflect.ValueOf(val)
  194. if expected, got := field.Kind(), argValue.Kind(); expected != got {
  195. panic(fmt.Sprintf("func's input arguments should have the same type: [%d] expected %s but got %s", i, expected, got))
  196. }
  197. argValues = append(argValues, argValue)
  198. }
  199. evalFn := reflect.ValueOf(fn).Call(argValues)[0]
  200. // var evaluator EvaluatorFunc
  201. // // check for typed and not typed
  202. // if _v, ok := evalFn.(EvaluatorFunc); ok {
  203. // evaluator = _v
  204. // } else if _v, ok = evalFn.(func(string) bool); ok {
  205. // evaluator = _v
  206. // }
  207. // return func(paramValue interface{}) bool {
  208. // return evaluator(paramValue)
  209. // }
  210. return evalFn
  211. }
  212. }
  213. type (
  214. // Macro represents the parsed macro,
  215. // which holds
  216. // the evaluator (param type's evaluator + param functions evaluators)
  217. // and its param functions.
  218. //
  219. // Any type contains its own macro
  220. // instance, so an String type
  221. // contains its type evaluator
  222. // which is the "Evaluator" field
  223. // and it can register param functions
  224. // to that macro which maps to a parameter type.
  225. Macro struct {
  226. indent string
  227. alias string
  228. master bool
  229. trailing bool
  230. Evaluator ParamEvaluator
  231. handleError interface{}
  232. funcs []ParamFunc
  233. }
  234. // ParamFuncBuilder is a func
  235. // which accepts a param function's arguments (values)
  236. // and returns a function as value, its job
  237. // is to make the macros to be registered
  238. // by user at the most generic possible way.
  239. ParamFuncBuilder func([]string) reflect.Value // the func(<T>) bool
  240. // ParamFunc represents the parsed
  241. // parameter function, it holds
  242. // the parameter's name
  243. // and the function which will build
  244. // the evaluator func.
  245. ParamFunc struct {
  246. Name string
  247. Func ParamFuncBuilder
  248. }
  249. )
  250. // NewMacro creates and returns a Macro that can be used as a registry for
  251. // a new customized parameter type and its functions.
  252. func NewMacro(indent, alias string, master, trailing bool, evaluator ParamEvaluator) *Macro {
  253. return &Macro{
  254. indent: indent,
  255. alias: alias,
  256. master: master,
  257. trailing: trailing,
  258. Evaluator: evaluator,
  259. }
  260. }
  261. // Indent returns the name of the parameter type.
  262. func (m *Macro) Indent() string {
  263. return m.indent
  264. }
  265. // Alias returns the alias of the parameter type, if any.
  266. func (m *Macro) Alias() string {
  267. return m.alias
  268. }
  269. // Master returns true if that macro's parameter type is the
  270. // default one if not :type is followed by a parameter type inside the route path.
  271. func (m *Macro) Master() bool {
  272. return m.master
  273. }
  274. // Trailing returns true if that macro's parameter type
  275. // is wildcard and can accept one or more path segments as one parameter value.
  276. // A wildcard should be registered in the last path segment only.
  277. func (m *Macro) Trailing() bool {
  278. return m.trailing
  279. }
  280. // HandleError registers a handler which will be executed
  281. // when a parameter evaluator returns false and a non nil value which is a type of `error`.
  282. // The "fnHandler" value MUST BE a type of `func(iris.Context, paramIndex int, err error)`,
  283. // otherwise the program will receive a panic before server startup.
  284. // The status code of the ErrCode (`else` literal) is set
  285. // before the error handler but it can be modified inside the handler itself.
  286. func (m *Macro) HandleError(fnHandler interface{}) *Macro { // See handler.MakeFilter.
  287. m.handleError = fnHandler
  288. return m
  289. }
  290. // func (m *Macro) SetParamResolver(fn func(memstore.Entry) interface{}) *Macro {
  291. // m.ParamResolver = fn
  292. // return m
  293. // }
  294. // RegisterFunc registers a parameter function
  295. // to that macro.
  296. // Accepts the func name ("range")
  297. // and the function body, which should return an EvaluatorFunc
  298. // a bool (it will be converted to EvaluatorFunc later on),
  299. // i.e RegisterFunc("min", func(minValue int) func(paramValue string) bool){})
  300. func (m *Macro) RegisterFunc(funcName string, fn interface{}) *Macro {
  301. fullFn := convertBuilderFunc(fn)
  302. // if it's not valid then not register it at all.
  303. if fullFn != nil {
  304. m.registerFunc(funcName, fullFn)
  305. }
  306. return m
  307. }
  308. func (m *Macro) registerFunc(funcName string, fullFn ParamFuncBuilder) {
  309. if !goodParamFuncName(funcName) {
  310. return
  311. }
  312. for _, fn := range m.funcs {
  313. if fn.Name == funcName {
  314. fn.Func = fullFn
  315. return
  316. }
  317. }
  318. m.funcs = append(m.funcs, ParamFunc{
  319. Name: funcName,
  320. Func: fullFn,
  321. })
  322. }
  323. func (m *Macro) getFunc(funcName string) ParamFuncBuilder {
  324. for _, fn := range m.funcs {
  325. if fn.Name == funcName {
  326. if fn.Func == nil {
  327. continue
  328. }
  329. return fn.Func
  330. }
  331. }
  332. return nil
  333. }