Skip to content

Commit 7c1d2ee

Browse files
authored
Add better error message for OpFetchField on missing field (#276)
1 parent d7b43b9 commit 7c1d2ee

File tree

4 files changed

+21
-20
lines changed

4 files changed

+21
-20
lines changed

compiler/compiler.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func (c *compiler) IdentifierNode(node *ast.IdentifierNode) {
200200
} else if len(node.FieldIndex) > 0 {
201201
c.emit(OpFetchEnvField, c.addConstant(&runtime.Field{
202202
Index: node.FieldIndex,
203-
Path: node.Value,
203+
Path: []string{node.Value},
204204
}))
205205
} else if node.Method {
206206
c.emit(OpMethodEnv, c.addConstant(&runtime.Method{
@@ -449,7 +449,7 @@ func (c *compiler) MemberNode(node *ast.MemberNode) {
449449
op := OpFetch
450450
original := node
451451
index := node.FieldIndex
452-
path := node.Name
452+
path := []string{node.Name}
453453
base := node.Node
454454
if len(node.FieldIndex) > 0 {
455455
op = OpFetchField
@@ -460,7 +460,7 @@ func (c *compiler) MemberNode(node *ast.MemberNode) {
460460
panic("IdentifierNode should not be dereferenced")
461461
}
462462
index = append(ident.FieldIndex, index...)
463-
path = ident.Value + "." + path
463+
path = append([]string{ident.Value}, path...)
464464
c.emitLocation(ident.Location(), OpFetchEnvField, c.addConstant(
465465
&runtime.Field{Index: index, Path: path},
466466
))
@@ -472,7 +472,7 @@ func (c *compiler) MemberNode(node *ast.MemberNode) {
472472
panic("MemberNode should not be dereferenced")
473473
}
474474
index = append(member.FieldIndex, index...)
475-
path = member.Name + "." + path
475+
path = append([]string{member.Name}, path...)
476476
node = member
477477
base = member.Node
478478
} else {

compiler/compiler_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func TestCompile(t *testing.T) {
159159
Constants: []interface{}{
160160
&runtime.Field{
161161
Index: []int{0, 1, 2, 3},
162-
Path: "A.B.C.D",
162+
Path: []string{"A", "B", "C", "D"},
163163
},
164164
},
165165
Bytecode: []vm.Opcode{
@@ -174,11 +174,11 @@ func TestCompile(t *testing.T) {
174174
Constants: []interface{}{
175175
&runtime.Field{
176176
Index: []int{0},
177-
Path: "A",
177+
Path: []string{"A"},
178178
},
179179
&runtime.Field{
180180
Index: []int{1, 2, 3},
181-
Path: "B.C.D",
181+
Path: []string{"B", "C", "D"},
182182
},
183183
},
184184
Bytecode: []vm.Opcode{
@@ -195,11 +195,11 @@ func TestCompile(t *testing.T) {
195195
Constants: []interface{}{
196196
&runtime.Field{
197197
Index: []int{0, 1},
198-
Path: "A.B",
198+
Path: []string{"A", "B"},
199199
},
200200
&runtime.Field{
201201
Index: []int{2, 3},
202-
Path: "C.D",
202+
Path: []string{"C", "D"},
203203
},
204204
},
205205
Bytecode: []vm.Opcode{
@@ -216,12 +216,12 @@ func TestCompile(t *testing.T) {
216216
Constants: []interface{}{
217217
&runtime.Field{
218218
Index: []int{0, 2},
219-
Path: "A.Map",
219+
Path: []string{"A", "Map"},
220220
},
221221
"B",
222222
&runtime.Field{
223223
Index: []int{2, 3},
224-
Path: "C.D",
224+
Path: []string{"C", "D"},
225225
},
226226
},
227227
Bytecode: []vm.Opcode{

vm/program.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package vm
33
import (
44
"fmt"
55
"regexp"
6+
"strings"
67

78
"github.com/antonmedv/expr/ast"
89
"github.com/antonmedv/expr/file"
@@ -50,7 +51,7 @@ func (program *Program) Disassemble() string {
5051
c = r.String()
5152
}
5253
if field, ok := c.(*runtime.Field); ok {
53-
c = fmt.Sprintf("{%v %v}", field.Path, field.Index)
54+
c = fmt.Sprintf("{%v %v}", strings.Join(field.Path, "."), field.Index)
5455
}
5556
if method, ok := c.(*runtime.Method); ok {
5657
c = fmt.Sprintf("{%v %v}", method.Name, method.Index)

vm/runtime/runtime.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func Fetch(from, i interface{}) interface{} {
6666

6767
type Field struct {
6868
Index []int
69-
Path string
69+
Path []string
7070
}
7171

7272
func FetchField(from interface{}, field *Field) interface{} {
@@ -83,23 +83,23 @@ func FetchField(from interface{}, field *Field) interface{} {
8383
// Also, our fieldByIndex() function is slightly faster than the
8484
// v.FieldByIndex() function as we don't need to verify what a field
8585
// is a struct as we already did it on compilation step.
86-
value := fieldByIndex(v, field.Index)
86+
value := fieldByIndex(v, field)
8787
if value.IsValid() {
8888
return value.Interface()
8989
}
9090
}
91-
panic(fmt.Sprintf("cannot get %v from %T", field.Path, from))
91+
panic(fmt.Sprintf("cannot get %v from %T", field.Path[0], from))
9292
}
9393

94-
func fieldByIndex(v reflect.Value, index []int) reflect.Value {
95-
if len(index) == 1 {
96-
return v.Field(index[0])
94+
func fieldByIndex(v reflect.Value, field *Field) reflect.Value {
95+
if len(field.Index) == 1 {
96+
return v.Field(field.Index[0])
9797
}
98-
for i, x := range index {
98+
for i, x := range field.Index {
9999
if i > 0 {
100100
if v.Kind() == reflect.Ptr {
101101
if v.IsNil() {
102-
return reflect.Value{}
102+
panic(fmt.Sprintf("cannot get %v from %v", field.Path[i], field.Path[i-1]))
103103
}
104104
v = v.Elem()
105105
}

0 commit comments

Comments
 (0)