Skip to content

Commit 9a27b44

Browse files
committed
fix(selector): The field selector in the expression supports relative path instead of absolute path
Change-Id: I54f9cce753afec6837f24b8c4e4e4557cc798aaa
1 parent 2e51b7c commit 9a27b44

File tree

2 files changed

+93
-22
lines changed

2 files changed

+93
-22
lines changed

tagexpr.go

+66-22
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ type fieldVM struct {
5050
elemType reflect.Type
5151
elemKind reflect.Kind
5252
zeroValue interface{}
53-
host *structVM
53+
origin *structVM
5454
valueGetter func(uintptr) interface{}
5555
reflectValueGetter func(uintptr) reflect.Value
5656
}
@@ -157,6 +157,7 @@ func (vm *VM) registerStructLocked(structType reflect.Type) (*structVM, error) {
157157
if err != nil {
158158
return nil, err
159159
}
160+
field.origin = sub
160161
s.copySubFields(field, sub)
161162
case reflect.Interface:
162163
s.setIfaceTagExprGetter(field)
@@ -188,7 +189,7 @@ func (vm *VM) newStructVM() *structVM {
188189
func (s *structVM) newFieldVM(structField reflect.StructField) (*fieldVM, error) {
189190
f := &fieldVM{
190191
StructField: structField,
191-
host: s,
192+
origin: s,
192193
}
193194
err := f.parseExprs(structField.Tag.Get(s.vm.tagName))
194195
if err != nil {
@@ -219,7 +220,7 @@ func (s *structVM) copySubFields(field *fieldVM, sub *structVM) {
219220
reflectValueGetter := v.reflectValueGetter
220221
f := &fieldVM{
221222
StructField: v.StructField,
222-
host: v.host,
223+
origin: v.origin,
223224
}
224225
if valueGetter != nil {
225226
if ptrDeep == 0 {
@@ -262,16 +263,20 @@ func (s *structVM) copySubFields(field *fieldVM, sub *structVM) {
262263
}
263264
}
264265

266+
func (f *fieldVM) elemPtr(ptr uintptr) uintptr {
267+
ptr = ptr + f.Offset
268+
for i := f.ptrDeep; i > 0; i-- {
269+
ptr = uintptrElem(ptr)
270+
}
271+
return ptr
272+
}
273+
265274
func (f *fieldVM) packRawFrom(ptr uintptr) reflect.Value {
266275
return reflect.NewAt(f.Type, unsafe.Pointer(ptr+f.Offset)).Elem()
267276
}
268277

269278
func (f *fieldVM) packElemFrom(ptr uintptr) reflect.Value {
270-
v := f.packRawFrom(ptr)
271-
for i := 0; i < f.ptrDeep; i++ {
272-
v = v.Elem()
273-
}
274-
return v
279+
return reflect.NewAt(f.elemType, unsafe.Pointer(f.elemPtr(ptr))).Elem()
275280
}
276281

277282
func (s *structVM) setIfaceTagExprGetter(f *fieldVM) {
@@ -400,8 +405,8 @@ func (f *fieldVM) parseExprs(tag string) error {
400405
return err
401406
}
402407
selector := f.Name
403-
f.host.exprs[selector] = expr
404-
f.host.selectorList = append(f.host.selectorList, selector)
408+
f.origin.exprs[selector] = expr
409+
f.origin.selectorList = append(f.origin.selectorList, selector)
405410
return nil
406411
}
407412
var subtag *string
@@ -421,14 +426,14 @@ func (f *fieldVM) parseExprs(tag string) error {
421426
default:
422427
selector = f.Name + "@" + selector
423428
}
424-
if _, had := f.host.exprs[selector]; had {
429+
if _, had := f.origin.exprs[selector]; had {
425430
return fmt.Errorf("duplicate expression name: %s", selector)
426431
}
427432
exprStr = strings.TrimSpace((*subtag)[idx+1:])
428433
if exprStr != "" {
429434
if expr, err := parseExpr(exprStr); err == nil {
430-
f.host.exprs[selector] = expr
431-
f.host.selectorList = append(f.host.selectorList, selector)
435+
f.origin.exprs[selector] = expr
436+
f.origin.selectorList = append(f.origin.selectorList, selector)
432437
} else {
433438
return err
434439
}
@@ -459,6 +464,7 @@ func (s *structVM) newTagExpr(ptr uintptr) *TagExpr {
459464
te := &TagExpr{
460465
s: s,
461466
ptr: ptr,
467+
sub: make(map[string]*TagExpr, 8),
462468
}
463469
return te
464470
}
@@ -467,6 +473,7 @@ func (s *structVM) newTagExpr(ptr uintptr) *TagExpr {
467473
type TagExpr struct {
468474
s *structVM
469475
ptr uintptr
476+
sub map[string]*TagExpr
470477
}
471478

472479
// EvalFloat evaluate the value of the struct tag expression by the selector expression.
@@ -527,7 +534,12 @@ func (t *TagExpr) Eval(exprSelector string) interface{} {
527534
return nil
528535
}
529536
}
530-
return expr.run(getFieldSelector(exprSelector), t)
537+
dir, base := splitFieldSelector(exprSelector)
538+
targetTagExpr, err := t.checkout(dir)
539+
if err != nil {
540+
return nil
541+
}
542+
return expr.run(base, targetTagExpr)
531543
}
532544

533545
// Range loop through each tag expression
@@ -538,7 +550,12 @@ func (t *TagExpr) Range(fn func(exprSelector string, eval func() interface{}) bo
538550
exprs := t.s.exprs
539551
for _, exprSelector := range list {
540552
if !fn(exprSelector, func() interface{} {
541-
return exprs[exprSelector].run(getFieldSelector(exprSelector), t)
553+
dir, base := splitFieldSelector(exprSelector)
554+
targetTagExpr, err := t.checkout(dir)
555+
if err != nil {
556+
return nil
557+
}
558+
return exprs[exprSelector].run(base, targetTagExpr)
542559
}) {
543560
return
544561
}
@@ -574,9 +591,28 @@ func (t *TagExpr) Field(fieldSelector string) interface{} {
574591
return nil
575592
}
576593

577-
func (t *TagExpr) getValue(field string, subFields []interface{}) (v interface{}) {
578-
f, ok := t.s.fields[field]
594+
var errFieldSelector = errors.New("field selector does not exist")
595+
596+
func (t *TagExpr) checkout(fs string) (*TagExpr, error) {
597+
if fs == "" {
598+
return t, nil
599+
}
600+
subTagExpr, ok := t.sub[fs]
601+
if ok {
602+
return subTagExpr, nil
603+
}
604+
f, ok := t.s.fields[fs]
579605
if !ok {
606+
return nil, errFieldSelector
607+
}
608+
subTagExpr = f.origin.newTagExpr(f.elemPtr(t.ptr))
609+
t.sub[fs] = subTagExpr
610+
return subTagExpr, nil
611+
}
612+
613+
func (t *TagExpr) getValue(fieldSelector string, subFields []interface{}) (v interface{}) {
614+
f := t.s.fields[fieldSelector]
615+
if f == nil {
580616
return nil
581617
}
582618
if f.valueGetter == nil {
@@ -649,12 +685,16 @@ func safeConvert(v reflect.Value, t reflect.Type) reflect.Value {
649685

650686
var float64Type = reflect.TypeOf(float64(0))
651687

652-
func getFieldSelector(selector string) string {
653-
idx := strings.Index(selector, "@")
654-
if idx == -1 {
655-
return selector
688+
func splitFieldSelector(selector string) (dir, base string) {
689+
idx := strings.LastIndex(selector, "@")
690+
if idx != -1 {
691+
selector = selector[:idx]
692+
}
693+
idx = strings.LastIndex(selector, ".")
694+
if idx != -1 {
695+
return selector[:idx], selector[idx+1:]
656696
}
657-
return selector[:idx]
697+
return "", selector
658698
}
659699

660700
func getFloat64(kind reflect.Kind, ptr uintptr) interface{} {
@@ -732,3 +772,7 @@ func safeIsNil(v reflect.Value) bool {
732772
}
733773
return false
734774
}
775+
776+
func uintptrElem(ptr uintptr) uintptr {
777+
return *(*uintptr)(unsafe.Pointer(ptr))
778+
}

tagexpr_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -449,3 +449,30 @@ func TestOperator(t *testing.T) {
449449
}
450450

451451
}
452+
453+
func TestStruct(t *testing.T) {
454+
type A struct {
455+
B struct {
456+
C struct {
457+
D struct {
458+
X string `vd:"$"`
459+
}
460+
} `vd:"{@:$['D']['X']}"`
461+
C2 string `vd:"{@:(C)$['D']['X']}"`
462+
C3 string `vd:"{@:(C.D.X)$}"`
463+
}
464+
}
465+
a := new(A)
466+
a.B.C.D.X = "xxx"
467+
vm := New("vd")
468+
expr := vm.MustRun(a)
469+
if expr.EvalString("B.C2") != "xxx" {
470+
t.FailNow()
471+
}
472+
if expr.EvalString("B.C3") != "xxx" {
473+
t.FailNow()
474+
}
475+
if expr.EvalString("B.C") != "xxx" {
476+
t.FailNow()
477+
}
478+
}

0 commit comments

Comments
 (0)