1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-24 05:17:03 +00:00

Conversion once at macros and their functions, internal changes required

Former-commit-id: 7b778cccfb7c0e30ca5e8106017ada065993aba5
This commit is contained in:
Gerasimos (Makis) Maropoulos
2018-09-27 03:17:45 +03:00
parent dc3c38b189
commit d6d27b2605
11 changed files with 338 additions and 279 deletions

View File

@@ -12,14 +12,51 @@ import (
// EvaluatorFunc is the signature for both param types and param funcs.
// It should accepts the param's value as string
// and return true if validated otherwise false.
type EvaluatorFunc func(paramValue string) bool
// type EvaluatorFunc func(paramValue string) bool
// type BinderFunc func(paramValue string) interface{}
// NewEvaluatorFromRegexp accepts a regexp "expr" expression
// and returns an EvaluatorFunc based on that regexp.
// the regexp is compiled before return.
type (
ParamEvaluator func(paramValue string) (interface{}, bool)
// FuncEvaluator interface{} // i.e func(paramValue int) bool
)
var goodEvaluatorFuncs = []reflect.Type{
reflect.TypeOf(func(string) (interface{}, bool) { return nil, false }),
reflect.TypeOf(ParamEvaluator(func(string) (interface{}, bool) { return nil, false })),
}
func goodParamFunc(typ reflect.Type) bool {
if typ.Kind() == reflect.Func { // it should be a func which returns a func (see below check).
if typ.NumOut() == 1 {
typOut := typ.Out(0)
if typOut.Kind() != reflect.Func {
return false
}
if typOut.NumOut() == 2 { // if it's a type of EvaluatorFunc, used for param evaluator.
for _, fType := range goodEvaluatorFuncs {
if typOut == fType {
return true
}
}
return false
}
if typOut.NumIn() == 1 && typOut.NumOut() == 1 { // if it's a type of func(paramValue [int,string...]) bool, used for param funcs.
return typOut.Out(0).Kind() == reflect.Bool
}
}
}
return false
}
// Regexp accepts a regexp "expr" expression
// and returns its MatchString.
// The regexp is compiled before return.
//
// Returns a not-nil error on regexp compile failure.
func NewEvaluatorFromRegexp(expr string) (EvaluatorFunc, error) {
func Regexp(expr string) (func(string) bool, error) {
if expr == "" {
return nil, fmt.Errorf("empty regex expression")
}
@@ -37,36 +74,16 @@ func NewEvaluatorFromRegexp(expr string) (EvaluatorFunc, error) {
return r.MatchString, nil
}
// MustNewEvaluatorFromRegexp same as NewEvaluatorFromRegexp
// MustRegexp same as Regexp
// but it panics on the "expr" parse failure.
func MustNewEvaluatorFromRegexp(expr string) EvaluatorFunc {
r, err := NewEvaluatorFromRegexp(expr)
func MustRegexp(expr string) func(string) bool {
r, err := Regexp(expr)
if err != nil {
panic(err)
}
return r
}
var (
goodParamFuncReturnType = reflect.TypeOf(func(string) bool { return false })
goodParamFuncReturnType2 = reflect.TypeOf(EvaluatorFunc(func(string) bool { return false }))
)
func goodParamFunc(typ reflect.Type) bool {
// should be a func
// which returns a func(string) bool
if typ.Kind() == reflect.Func {
if typ.NumOut() == 1 {
typOut := typ.Out(0)
if typOut == goodParamFuncReturnType || typOut == goodParamFuncReturnType2 {
return true
}
}
}
return false
}
// goodParamFuncName reports whether the function name is a valid identifier.
func goodParamFuncName(name string) bool {
if name == "" {
@@ -85,7 +102,7 @@ func goodParamFuncName(name string) bool {
// the convertBuilderFunc return value is generating at boot time.
// convertFunc converts an interface to a valid full param function.
func convertBuilderFunc(fn interface{}) ParamEvaluatorBuilder {
func convertBuilderFunc(fn interface{}) ParamFuncBuilder {
typFn := reflect.TypeOf(fn)
if !goodParamFunc(typFn) {
@@ -94,7 +111,7 @@ func convertBuilderFunc(fn interface{}) ParamEvaluatorBuilder {
numFields := typFn.NumIn()
return func(args []string) EvaluatorFunc {
return func(args []string) reflect.Value {
if len(args) != numFields {
// no variadics support, for now.
panic("args should be the same len as numFields")
@@ -179,24 +196,25 @@ func convertBuilderFunc(fn interface{}) ParamEvaluatorBuilder {
argValue := reflect.ValueOf(val)
if expected, got := field.Kind(), argValue.Kind(); expected != got {
panic(fmt.Sprintf("fields should have the same type: [%d] expected %s but got %s", i, expected, got))
panic(fmt.Sprintf("func's input arguments should have the same type: [%d] expected %s but got %s", i, expected, got))
}
argValues = append(argValues, argValue)
}
evalFn := reflect.ValueOf(fn).Call(argValues)[0].Interface()
evalFn := reflect.ValueOf(fn).Call(argValues)[0]
var evaluator EvaluatorFunc
// check for typed and not typed
if _v, ok := evalFn.(EvaluatorFunc); ok {
evaluator = _v
} else if _v, ok = evalFn.(func(string) bool); ok {
evaluator = _v
}
return func(paramValue string) bool {
return evaluator(paramValue)
}
// var evaluator EvaluatorFunc
// // check for typed and not typed
// if _v, ok := evalFn.(EvaluatorFunc); ok {
// evaluator = _v
// } else if _v, ok = evalFn.(func(string) bool); ok {
// evaluator = _v
// }
// return func(paramValue interface{}) bool {
// return evaluator(paramValue)
// }
return evalFn
}
}
@@ -218,16 +236,16 @@ type (
master bool
trailing bool
Evaluator EvaluatorFunc
Evaluator ParamEvaluator
funcs []ParamFunc
}
// ParamEvaluatorBuilder is a func
// ParamFuncBuilder is a func
// which accepts a param function's arguments (values)
// and returns an EvaluatorFunc, its job
// and returns a function as value, its job
// is to make the macros to be registered
// by user at the most generic possible way.
ParamEvaluatorBuilder func([]string) EvaluatorFunc
ParamFuncBuilder func([]string) reflect.Value // the func
// ParamFunc represents the parsed
// parameter function, it holds
@@ -236,13 +254,13 @@ type (
// the evaluator func.
ParamFunc struct {
Name string
Func ParamEvaluatorBuilder
Func ParamFuncBuilder
}
)
// NewMacro creates and returns a Macro that can be used as a registry for
// a new customized parameter type and its functions.
func NewMacro(indent, alias string, master, trailing bool, evaluator EvaluatorFunc) *Macro {
func NewMacro(indent, alias string, master, trailing bool, evaluator ParamEvaluator) *Macro {
return &Macro{
indent: indent,
alias: alias,
@@ -287,7 +305,7 @@ func (m *Macro) RegisterFunc(funcName string, fn interface{}) *Macro {
return m
}
func (m *Macro) registerFunc(funcName string, fullFn ParamEvaluatorBuilder) {
func (m *Macro) registerFunc(funcName string, fullFn ParamFuncBuilder) {
if !goodParamFuncName(funcName) {
return
}
@@ -305,7 +323,7 @@ func (m *Macro) registerFunc(funcName string, fullFn ParamEvaluatorBuilder) {
})
}
func (m *Macro) getFunc(funcName string) ParamEvaluatorBuilder {
func (m *Macro) getFunc(funcName string) ParamFuncBuilder {
for _, fn := range m.funcs {
if fn.Name == funcName {
if fn.Func == nil {

View File

@@ -2,6 +2,7 @@ package macro
import (
"reflect"
"strconv"
"testing"
)
@@ -64,9 +65,25 @@ func TestGoodParamFuncName(t *testing.T) {
}
}
func testEvaluatorRaw(t *testing.T, macroEvaluator *Macro, input string, pass bool, i int) {
if got := macroEvaluator.Evaluator(input); pass != got {
t.Fatalf("%s - tests[%d] - expecting %v but got %v", t.Name(), i, pass, got)
func testEvaluatorRaw(t *testing.T, macroEvaluator *Macro, input string, expectedType reflect.Kind, pass bool, i int) {
if macroEvaluator.Evaluator == nil && pass {
return // if not evaluator defined then it should allow everything.
}
value, passed := macroEvaluator.Evaluator(input)
if pass != passed {
t.Fatalf("%s - tests[%d] - expecting[pass] %v but got %v", t.Name(), i, pass, passed)
}
if !passed {
return
}
if value == nil && expectedType != reflect.Invalid {
t.Fatalf("%s - tests[%d] - expecting[value] to not be nil", t.Name(), i)
}
if v := reflect.ValueOf(value); v.Kind() != expectedType {
t.Fatalf("%s - tests[%d] - expecting[value.Kind] %v but got %v", t.Name(), i, expectedType, v.Kind())
}
}
@@ -84,30 +101,32 @@ func TestStringEvaluatorRaw(t *testing.T) {
} // 0
for i, tt := range tests {
testEvaluatorRaw(t, String, tt.input, tt.pass, i)
testEvaluatorRaw(t, String, tt.input, reflect.String, tt.pass, i)
}
}
func TestNumberEvaluatorRaw(t *testing.T) {
func TestIntEvaluatorRaw(t *testing.T) {
x64 := strconv.IntSize == 64
tests := []struct {
pass bool
input string
}{
{false, "astring"}, // 0
{false, "astringwith_numb3rS_and_symbol$"}, // 1
{true, "32321"}, // 2
{true, "18446744073709551615"}, // 3
{true, "-18446744073709551615"}, // 4
{true, "-18446744073709553213213213213213121615"}, // 5
{false, "42 18446744073709551615"}, // 6
{false, "--42"}, // 7
{false, "+42"}, // 8
{false, "main.css"}, // 9
{false, "/assets/main.css"}, // 10
{false, "astring"}, // 0
{false, "astringwith_numb3rS_and_symbol$"}, // 1
{true, "32321"}, // 2
{x64, "9223372036854775807" /*max int64*/}, // 3
{x64, "-9223372036854775808" /*min int64 */}, // 4
{false, "-18446744073709553213213213213213121615"}, // 5
{false, "42 18446744073709551615"}, // 6
{false, "--42"}, // 7
{false, "+42"}, // 8
{false, "main.css"}, // 9
{false, "/assets/main.css"}, // 10
}
for i, tt := range tests {
testEvaluatorRaw(t, Number, tt.input, tt.pass, i)
testEvaluatorRaw(t, Int, tt.input, reflect.Int, tt.pass, i)
}
}
@@ -132,7 +151,7 @@ func TestInt64EvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(t, Int64, tt.input, tt.pass, i)
testEvaluatorRaw(t, Int64, tt.input, reflect.Int64, tt.pass, i)
}
}
@@ -161,7 +180,7 @@ func TestUint8EvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(t, Uint8, tt.input, tt.pass, i)
testEvaluatorRaw(t, Uint8, tt.input, reflect.Uint8, tt.pass, i)
}
}
@@ -186,7 +205,7 @@ func TestUint64EvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(t, Uint64, tt.input, tt.pass, i)
testEvaluatorRaw(t, Uint64, tt.input, reflect.Uint64, tt.pass, i)
}
}
@@ -203,7 +222,7 @@ func TestAlphabeticalEvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(t, Alphabetical, tt.input, tt.pass, i)
testEvaluatorRaw(t, Alphabetical, tt.input, reflect.String, tt.pass, i)
}
}
@@ -220,7 +239,7 @@ func TestFileEvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(t, File, tt.input, tt.pass, i)
testEvaluatorRaw(t, File, tt.input, reflect.String, tt.pass, i)
}
}
@@ -238,7 +257,7 @@ func TestPathEvaluatorRaw(t *testing.T) {
}
for i, tt := range pathTests {
testEvaluatorRaw(t, Path, tt.input, tt.pass, i)
testEvaluatorRaw(t, Path, tt.input, reflect.String, tt.pass, i)
}
}
@@ -270,8 +289,7 @@ func TestConvertBuilderFunc(t *testing.T) {
}
evalFunc := convertBuilderFunc(fn)
if !evalFunc([]string{"1", "[name1,name2]"})("ok") {
if !evalFunc([]string{"1", "[name1,name2]"}).Call([]reflect.Value{reflect.ValueOf("ok")})[0].Interface().(bool) {
t.Fatalf("failed, it should fail already")
}
}

View File

@@ -10,233 +10,205 @@ import (
var (
// String type
// Allows anything (single path segment, as everything except the `Path`).
String = NewMacro("string", "", true, false, func(string) bool { return true }).
RegisterFunc("regexp", func(expr string) EvaluatorFunc {
return MustNewEvaluatorFromRegexp(expr)
String = NewMacro("string", "", true, false, nil). // if nil allows everything.
RegisterFunc("regexp", func(expr string) func(string) bool {
return MustRegexp(expr)
}).
// checks if param value starts with the 'prefix' arg
RegisterFunc("prefix", func(prefix string) EvaluatorFunc {
RegisterFunc("prefix", func(prefix string) func(string) bool {
return func(paramValue string) bool {
return strings.HasPrefix(paramValue, prefix)
}
}).
// checks if param value ends with the 'suffix' arg
RegisterFunc("suffix", func(suffix string) EvaluatorFunc {
RegisterFunc("suffix", func(suffix string) func(string) bool {
return func(paramValue string) bool {
return strings.HasSuffix(paramValue, suffix)
}
}).
// checks if param value contains the 's' arg
RegisterFunc("contains", func(s string) EvaluatorFunc {
RegisterFunc("contains", func(s string) func(string) bool {
return func(paramValue string) bool {
return strings.Contains(paramValue, s)
}
}).
// checks if param value's length is at least 'min'
RegisterFunc("min", func(min int) EvaluatorFunc {
RegisterFunc("min", func(min int) func(string) bool {
return func(paramValue string) bool {
return len(paramValue) >= min
}
}).
// checks if param value's length is not bigger than 'max'
RegisterFunc("max", func(max int) EvaluatorFunc {
RegisterFunc("max", func(max int) func(string) bool {
return func(paramValue string) bool {
return max >= len(paramValue)
}
})
simpleNumberEvalutator = MustNewEvaluatorFromRegexp("^-?[0-9]+$")
// Number or int type
// both positive and negative numbers, any number of digits.
Number = NewMacro("number", "int", false, false, simpleNumberEvalutator).
simpleNumberEval = MustRegexp("^-?[0-9]+$")
// Int or int type
// both positive and negative numbers, actual value can be min-max int64 or min-max int32 depends on the arch.
Int = NewMacro("int", "number", false, false, func(paramValue string) (interface{}, bool) {
if !simpleNumberEval(paramValue) {
return nil, false
}
v, err := strconv.Atoi(paramValue)
if err != nil {
return nil, false
}
return v, true
}).
// checks if the param value's int representation is
// bigger or equal than 'min'
RegisterFunc("min", func(min int) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.Atoi(paramValue)
if err != nil {
return false
}
return n >= min
RegisterFunc("min", func(min int) func(int) bool {
return func(paramValue int) bool {
return paramValue >= min
}
}).
// checks if the param value's int representation is
// smaller or equal than 'max'.
RegisterFunc("max", func(max int) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.Atoi(paramValue)
if err != nil {
return false
}
return n <= max
RegisterFunc("max", func(max int) func(int) bool {
return func(paramValue int) bool {
return paramValue <= max
}
}).
// checks if the param value's int representation is
// between min and max, including 'min' and 'max'.
RegisterFunc("range", func(min, max int) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.Atoi(paramValue)
if err != nil {
return false
}
if n < min || n > max {
return false
}
return true
RegisterFunc("range", func(min, max int) func(int) bool {
return func(paramValue int) bool {
return !(paramValue < min || paramValue > max)
}
})
// Int64 as int64 type
// -9223372036854775808 to 9223372036854775807.
Int64 = NewMacro("int64", "long", false, false, func(paramValue string) bool {
if !simpleNumberEvalutator(paramValue) {
return false
Int64 = NewMacro("int64", "long", false, false, func(paramValue string) (interface{}, bool) {
if !simpleNumberEval(paramValue) {
return nil, false
}
_, err := strconv.ParseInt(paramValue, 10, 64)
// if err == strconv.ErrRange...
return err == nil
v, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil { // if err == strconv.ErrRange...
return nil, false
}
return v, true
}).
// checks if the param value's int64 representation is
// bigger or equal than 'min'.
RegisterFunc("min", func(min int64) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return false
}
return n >= min
RegisterFunc("min", func(min int64) func(int64) bool {
return func(paramValue int64) bool {
return paramValue >= min
}
}).
// checks if the param value's int64 representation is
// smaller or equal than 'max'.
RegisterFunc("max", func(max int64) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return false
}
return n <= max
RegisterFunc("max", func(max int64) func(int64) bool {
return func(paramValue int64) bool {
return paramValue <= max
}
}).
// checks if the param value's int64 representation is
// between min and max, including 'min' and 'max'.
RegisterFunc("range", func(min, max int64) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return false
}
if n < min || n > max {
return false
}
return true
RegisterFunc("range", func(min, max int64) func(int64) bool {
return func(paramValue int64) bool {
return !(paramValue < min || paramValue > max)
}
})
uint8Eval = MustRegexp("^([0-9]|[1-8][0-9]|9[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
// Uint8 as uint8 type
// 0 to 255.
Uint8 = NewMacro("uint8", "", false, false, MustNewEvaluatorFromRegexp("^([0-9]|[1-8][0-9]|9[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")).
Uint8 = NewMacro("uint8", "", false, false, func(paramValue string) (interface{}, bool) {
if !uint8Eval(paramValue) {
return nil, false
}
v, err := strconv.ParseUint(paramValue, 10, 8)
if err != nil {
return nil, false
}
return uint8(v), true
}).
// checks if the param value's uint8 representation is
// bigger or equal than 'min'.
RegisterFunc("min", func(min uint8) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 8)
if err != nil {
return false
}
return uint8(n) >= min
RegisterFunc("min", func(min uint8) func(uint8) bool {
return func(paramValue uint8) bool {
return paramValue >= min
}
}).
// checks if the param value's uint8 representation is
// smaller or equal than 'max'.
RegisterFunc("max", func(max uint8) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 8)
if err != nil {
return false
}
return uint8(n) <= max
RegisterFunc("max", func(max uint8) func(uint8) bool {
return func(paramValue uint8) bool {
return paramValue <= max
}
}).
// checks if the param value's uint8 representation is
// between min and max, including 'min' and 'max'.
RegisterFunc("range", func(min, max uint8) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 8)
if err != nil {
return false
}
if v := uint8(n); v < min || v > max {
return false
}
return true
RegisterFunc("range", func(min, max uint8) func(uint8) bool {
return func(paramValue uint8) bool {
return !(paramValue < min || paramValue > max)
}
})
// Uint64 as uint64 type
// 0 to 18446744073709551615.
Uint64 = NewMacro("uint64", "", false, false, func(paramValue string) bool {
if !simpleNumberEvalutator(paramValue) {
return false
Uint64 = NewMacro("uint64", "", false, false, func(paramValue string) (interface{}, bool) {
if !simpleNumberEval(paramValue) {
return nil, false
}
_, err := strconv.ParseUint(paramValue, 10, 64)
return err == nil
v, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return nil, false
}
return v, true
}).
// checks if the param value's uint64 representation is
// bigger or equal than 'min'.
RegisterFunc("min", func(min uint64) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return false
}
return n >= min
RegisterFunc("min", func(min uint64) func(uint64) bool {
return func(paramValue uint64) bool {
return paramValue >= min
}
}).
// checks if the param value's uint64 representation is
// smaller or equal than 'max'.
RegisterFunc("max", func(max uint64) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return false
}
return n <= max
RegisterFunc("max", func(max uint64) func(uint64) bool {
return func(paramValue uint64) bool {
return paramValue <= max
}
}).
// checks if the param value's uint64 representation is
// between min and max, including 'min' and 'max'.
RegisterFunc("range", func(min, max uint64) EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return false
}
if n < min || n > max {
return false
}
return true
RegisterFunc("range", func(min, max uint64) func(uint64) bool {
return func(paramValue uint64) bool {
return !(paramValue < min || paramValue > max)
}
})
// Bool or boolean as bool type
// a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
Bool = NewMacro("bool", "boolean", false, false, func(paramValue string) bool {
Bool = NewMacro("bool", "boolean", false, false, func(paramValue string) (interface{}, bool) {
// a simple if statement is faster than regex ^(true|false|True|False|t|0|f|FALSE|TRUE)$
// in this case.
_, err := strconv.ParseBool(paramValue)
return err == nil
v, err := strconv.ParseBool(paramValue)
if err != nil {
return nil, false
}
return v, true
})
alphabeticalEval = MustRegexp("^[a-zA-Z ]+$")
// Alphabetical letter type
// letters only (upper or lowercase)
Alphabetical = NewMacro("alphabetical", "", false, false, MustNewEvaluatorFromRegexp("^[a-zA-Z ]+$"))
Alphabetical = NewMacro("alphabetical", "", false, false, func(paramValue string) (interface{}, bool) {
if !alphabeticalEval(paramValue) {
return nil, false
}
return paramValue, true
})
fileEval = MustRegexp("^[a-zA-Z0-9_.-]*$")
// File type
// letters (upper or lowercase)
// numbers (0-9)
@@ -244,7 +216,12 @@ var (
// dash (-)
// point (.)
// no spaces! or other character
File = NewMacro("file", "", false, false, MustNewEvaluatorFromRegexp("^[a-zA-Z0-9_.-]*$"))
File = NewMacro("file", "", false, false, func(paramValue string) (interface{}, bool) {
if !fileEval(paramValue) {
return nil, false
}
return paramValue, true
})
// Path type
// anything, should be the last part
//
@@ -252,11 +229,11 @@ var (
// types because I want to give the opportunity to the user
// to organise the macro functions based on wildcard or single dynamic named path parameter.
// Should be living in the latest path segment of a route path.
Path = NewMacro("path", "", false, true, func(string) bool { return true })
Path = NewMacro("path", "", false, true, nil)
Defaults = &Macros{
String,
Number,
Int,
Int64,
Uint8,
Uint64,
@@ -268,7 +245,7 @@ var (
type Macros []*Macro
func (ms *Macros) Register(indent, alias string, isMaster, isTrailing bool, evaluator EvaluatorFunc) *Macro {
func (ms *Macros) Register(indent, alias string, isMaster, isTrailing bool, evaluator ParamEvaluator) *Macro {
macro := NewMacro(indent, alias, isMaster, isTrailing, evaluator)
if ms.register(macro) {
return macro

View File

@@ -1,6 +1,8 @@
package macro
import (
"reflect"
"github.com/kataras/iris/core/router/macro/interpreter/ast"
"github.com/kataras/iris/core/router/macro/interpreter/parser"
)
@@ -27,8 +29,8 @@ type TemplateParam struct {
Name string `json:"name"`
Index int `json:"index"`
ErrCode int `json:"errCode"`
TypeEvaluator EvaluatorFunc `json:"-"`
Funcs []EvaluatorFunc `json:"-"`
TypeEvaluator ParamEvaluator `json:"-"`
Funcs []reflect.Value `json:"-"`
}
// Parse takes a full route path and a macro map (macro map contains the macro types with their registered param functions)
@@ -74,7 +76,7 @@ func Parse(src string, macros Macros) (*Template, error) {
}
evalFn := tmplFn(paramfn.Args)
if evalFn == nil {
if evalFn.IsNil() || !evalFn.IsValid() || evalFn.Kind() != reflect.Func {
continue
}
tmplParam.Funcs = append(tmplParam.Funcs, evalFn)