Skip to content

Commit

Permalink
feat: support nil keyword
Browse files Browse the repository at this point in the history
Change-Id: I5e7155ae170853ce34f6492f9703915b5be70369
  • Loading branch information
andeya committed Jan 30, 2019
1 parent f3e8dcf commit b8f4bba
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 23 deletions.
11 changes: 5 additions & 6 deletions README.md
Expand Up @@ -105,11 +105,10 @@ NOTE: **The `exprName` under the same struct field cannot be the same!**

|Operator or Expression example|Explain|
|-----|---------|
|`true`|bool "true"|
|`false`|bool "false"|
|`1`|float64 "1"|
|`1.0`|float64 "1.0"|
|`'S'`|String "S"|
|`true` `false`|bool|
|`0` `0.0`|float64 "0"|
|`''`|String|
|`nil`|nil|
|`+`|Digital addition or string splicing|
|`-`|Digital subtraction or negative|
|`*`|Digital multiplication|
Expand Down Expand Up @@ -146,7 +145,7 @@ NOTE: **The `exprName` under the same struct field cannot be the same!**
|`>>`|Integer bitwise `shift right`| -->

Operator priority(high -> low):
* `()` `bool` `string` `float64` `!`
* `()` `bool` `string` `float64` `nil` `!`
* `*` `/` `%`
* `+` `-`
* `<` `<=` `>` `>=`
Expand Down
5 changes: 4 additions & 1 deletion expr.go
Expand Up @@ -66,6 +66,9 @@ func (p *Expr) parseOperand(expr *string) (e ExprNode) {
if e = readBoolExprNode(expr); e != nil {
return e
}
if e = readNilExprNode(expr); e != nil {
return e
}
return nil
}

Expand Down Expand Up @@ -176,7 +179,7 @@ func (p *Expr) checkSyntax() error {

/**
* Priority:
* () bool string float64 !
* () bool string float64 nil !
* * / %
* + -
* < <= > >=
Expand Down
22 changes: 20 additions & 2 deletions spec_operand.go
Expand Up @@ -69,7 +69,7 @@ type boolExprNode struct {
val bool
}

var boolRegexp = regexp.MustCompile(`^!*(true|false)([\|&!= \t]{1}|$)`)
var boolRegexp = regexp.MustCompile(`^!*(true|false)([\)\],\|&!= \t]{1}|$)`)

func readBoolExprNode(expr *string) ExprNode {
s := boolRegexp.FindString(*expr)
Expand Down Expand Up @@ -121,7 +121,7 @@ type digitalExprNode struct {
val float64
}

var digitalRegexp = regexp.MustCompile(`^[\+\-]?\d+(\.\d+)?([\+\-\*\/%><\|&!=\^ \t\\]|$)`)
var digitalRegexp = regexp.MustCompile(`^[\+\-]?\d+(\.\d+)?([\)\],\+\-\*\/%><\|&!=\^ \t\\]|$)`)

func readDigitalExprNode(expr *string) ExprNode {
s := digitalRegexp.FindString(*expr)
Expand Down Expand Up @@ -170,3 +170,21 @@ func readPairedSymbol(p *string, left, right rune) *string {
}
return nil
}

type nilExprNode struct {
exprBackground
}

var nilRegexp = regexp.MustCompile(`^nil([\)\],\|&!= \t]{1}|$)`)

func readNilExprNode(expr *string) ExprNode {
s := nilRegexp.FindString(*expr)
if s == "" {
return nil
}
*expr = (*expr)[3:]
e := &nilExprNode{}
return e
}

func (*nilExprNode) Run(currField string, tagExpr *TagExpr) interface{} { return nil }
2 changes: 2 additions & 0 deletions spec_operator.go
Expand Up @@ -108,6 +108,8 @@ func (ee *equalExprNode) Run(currField string, tagExpr *TagExpr) interface{} {
var r1 bool
r1, _ = v1.(bool)
return r == r1
case nil:
return v1 == nil
default:
return false
}
Expand Down
2 changes: 1 addition & 1 deletion spec_selector.go
Expand Up @@ -49,7 +49,7 @@ func (p *Expr) readSelectorExprNode(expr *string) ExprNode {
return operand
}

var selectorRegexp = regexp.MustCompile(`^(\!*)(\([ \t]*[A-Za-z_]+[A-Za-z0-9_\.]*[ \t]*\))?(\$)([\[\+\-\*\/%><\|&!=\^ \t\\]|$)`)
var selectorRegexp = regexp.MustCompile(`^(\!*)(\([ \t]*[A-Za-z_]+[A-Za-z0-9_\.]*[ \t]*\))?(\$)([\)\[\],\+\-\*\/%><\|&!=\^ \t\\]|$)`)

func findSelector(expr *string) (field string, name string, subSelector []string, boolPrefix *bool, found bool) {
raw := *expr
Expand Down
23 changes: 19 additions & 4 deletions tagexpr.go
Expand Up @@ -197,7 +197,11 @@ func (f *Field) setFloatGetter(kind reflect.Kind, ptrDeep int) {
}
} else {
f.valueGetter = func(ptr uintptr) interface{} {
return getFloat64(kind, f.newFrom(ptr, ptrDeep).UnsafeAddr())
v := f.newFrom(ptr, ptrDeep)
if v.CanAddr() {
return getFloat64(kind, v.UnsafeAddr())
}
return nil
}
}
}
Expand All @@ -209,7 +213,11 @@ func (f *Field) setBoolGetter(ptrDeep int) {
}
} else {
f.valueGetter = func(ptr uintptr) interface{} {
return f.newFrom(ptr, ptrDeep).Bool()
v := f.newFrom(ptr, ptrDeep)
if v.IsValid() {
return v.Bool()
}
return nil
}
}
}
Expand All @@ -221,7 +229,11 @@ func (f *Field) setStringGetter(ptrDeep int) {
}
} else {
f.valueGetter = func(ptr uintptr) interface{} {
return f.newFrom(ptr, ptrDeep).String()
v := f.newFrom(ptr, ptrDeep)
if v.IsValid() {
return v.String()
}
return nil
}
}
}
Expand Down Expand Up @@ -405,6 +417,9 @@ func (t *TagExpr) getValue(field string, subFields []interface{}) (v interface{}
return nil
}
v = f.valueGetter(t.ptr)
if v == nil {
return nil
}
if len(subFields) == 0 {
return v
}
Expand Down Expand Up @@ -439,7 +454,7 @@ func (t *TagExpr) getValue(field string, subFields []interface{}) (v interface{}
}
switch vv.Kind() {
default:
if vv.CanInterface() {
if !vv.IsNil() && vv.CanInterface() {
return vv.Interface()
}
return nil
Expand Down
17 changes: 14 additions & 3 deletions tagexpr_test.go
Expand Up @@ -83,6 +83,7 @@ func Test(t *testing.T) {
d := "ddd"
e := new(int)
*e = 3
type iface interface{}
var cases = []struct {
tagName string
structure interface{}
Expand All @@ -101,6 +102,8 @@ func Test(t *testing.T) {
g string `tagexpr:"{x:regexp('g\\d{3}$',$)}{y:regexp('g\\d{3}$')}"`
h []string `tagexpr:"{x:$[1]}{y:$[10]}"`
i map[string]int `tagexpr:"{x:$['a']}{y:$[0]}"`
j iface `tagexpr:"$==1"`
k *iface `tagexpr:"$"`
}{
A: 5.0,
A2: 5.0,
Expand Down Expand Up @@ -129,6 +132,8 @@ func Test(t *testing.T) {
"h@y": nil,
"i@x": 7.0,
"i@y": nil,
"j@": false,
"k@": nil,
},
},
{
Expand All @@ -150,9 +155,12 @@ func Test(t *testing.T) {
s []string
m map[string][]string
} `tagexpr:"$['h']"`
i string `tagexpr:"(g.s)$[0]+(g.m)$['0'][0]==$"`
j bool `tagexpr:"!$"`
k int `tagexpr:"!$"`
i string `tagexpr:"(g.s)$[0]+(g.m)$['0'][0]==$"`
j bool `tagexpr:"!$"`
k int `tagexpr:"!$"`
m *int `tagexpr:"$==nil"`
n *bool `tagexpr:"$==nil"`
p *string `tagexpr:"$"`
}{
A: 5.0,
b: "x",
Expand All @@ -177,6 +185,9 @@ func Test(t *testing.T) {
"i@": true,
"j@": true,
"k@": nil,
"m@": true,
"n@": true,
"p@": nil,
},
},
}
Expand Down
11 changes: 5 additions & 6 deletions validator/README.md
Expand Up @@ -105,11 +105,10 @@ type T struct {

|Operator or Expression example|Explain|
|-----|---------|
|`true`|bool "true"|
|`false`|bool "false"|
|`1`|float64 "1"|
|`1.0`|float64 "1.0"|
|`'S'`|String "S"|
|`true` `false`|bool|
|`0` `0.0`|float64 "0"|
|`''`|String|
|`nil`|nil|
|`+`|Digital addition or string splicing|
|`-`|Digital subtraction or negative|
|`*`|Digital multiplication|
Expand Down Expand Up @@ -146,7 +145,7 @@ type T struct {
|`>>`|Integer bitwise `shift right`| -->

Operator priority(high -> low):
* `()` `bool` `string` `float64` `!`
* `()` `bool` `string` `float64` `nil` `!`
* `*` `/` `%`
* `+` `-`
* `<` `<=` `>` `>=`
Expand Down

0 comments on commit b8f4bba

Please sign in to comment.