Skip to content

Commit e73f3bc

Browse files
committed
Add compiler member fetch optimizations
1 parent e6b9fa9 commit e73f3bc

File tree

3 files changed

+64
-15
lines changed

3 files changed

+64
-15
lines changed

compiler/compiler.go

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import (
1515
)
1616

1717
func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err error) {
18-
//defer func() {
19-
// if r := recover(); r != nil {
20-
// err = fmt.Errorf("%v", r)
21-
// }
22-
//}()
18+
defer func() {
19+
if r := recover(); r != nil {
20+
err = fmt.Errorf("%v", r)
21+
}
22+
}()
2323

2424
c := &compiler{
2525
index: make(map[interface{}]uint16),
@@ -74,6 +74,14 @@ func (c *compiler) emit(op byte, b ...byte) int {
7474
return current
7575
}
7676

77+
func (c *compiler) emitLoc(node ast.Node, op byte, b ...byte) int {
78+
c.bytecode = append(c.bytecode, op)
79+
current := len(c.bytecode)
80+
c.bytecode = append(c.bytecode, b...)
81+
c.locations[current-1] = node.Location()
82+
return current
83+
}
84+
7785
func (c *compiler) emitPush(value interface{}) int {
7886
return c.emit(OpPush, c.makeConstant(value)...)
7987
}
@@ -418,21 +426,53 @@ func (c *compiler) ChainNode(node *ast.ChainNode) {
418426
}
419427

420428
func (c *compiler) MemberNode(node *ast.MemberNode) {
421-
c.compile(node.Node)
429+
op := OpFetch
430+
original := node
431+
index := node.Index
432+
path := node.Name
433+
base := node.Node
434+
if len(node.Index) > 0 {
435+
op = OpFetchField
436+
for !node.Optional {
437+
ident, ok := base.(*ast.IdentifierNode)
438+
if ok && len(ident.Index) > 0 {
439+
if ident.Deref {
440+
panic("IdentifierNode should not be dereferenced")
441+
}
442+
index = append(ident.Index, index...)
443+
path = ident.Value + "." + path
444+
op = OpFetchEnvField
445+
goto emit
446+
}
447+
member, ok := base.(*ast.MemberNode)
448+
if ok && len(member.Index) > 0 {
449+
if member.Deref {
450+
panic("MemberNode should not be dereferenced")
451+
}
452+
index = append(member.Index, index...)
453+
path = member.Name + "." + path
454+
node = member
455+
base = member.Node
456+
} else {
457+
break
458+
}
459+
}
460+
}
461+
462+
c.compile(base)
422463
if node.Optional {
423464
ph := c.emit(OpJumpIfNil, c.placeholder()...)
424465
c.chains[len(c.chains)-1] = append(c.chains[len(c.chains)-1], ph)
425466
}
426-
if len(node.Index) > 0 {
427-
c.emit(OpFetchField, c.makeConstant(&runtime.Field{
428-
Index: node.Index,
429-
Path: node.Name,
430-
})...)
431-
} else {
467+
468+
emit:
469+
if op == OpFetch {
432470
c.compile(node.Property)
433471
c.emit(OpFetch)
472+
} else {
473+
c.emitLoc(node, op, c.makeConstant(&runtime.Field{Index: index, Path: path})...)
434474
}
435-
if node.Deref {
475+
if original.Deref {
436476
c.emit(OpDeref)
437477
}
438478
}

vm/program.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package vm
33
import (
44
"encoding/binary"
55
"fmt"
6+
"github.com/antonmedv/expr/vm/runtime"
67
"regexp"
78

89
"github.com/antonmedv/expr/file"
@@ -55,7 +56,10 @@ func (program *Program) Disassemble() string {
5556
if r, ok := c.(*regexp.Regexp); ok {
5657
c = r.String()
5758
}
58-
out += fmt.Sprintf("%v\t%v\t%v\t%#v\n", pp, label, a, c)
59+
if field, ok := c.(*runtime.Field); ok {
60+
c = fmt.Sprintf("%v %v", field.Path, field.Index)
61+
}
62+
out += fmt.Sprintf("%v\t%v\t%v\t%v\n", pp, label, a, c)
5963
}
6064

6165
switch op {

vm/runtime/runtime.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ type Field struct {
7272
}
7373

7474
func FetchField(from interface{}, field *Field) interface{} {
75+
defer func() {
76+
if r := recover(); r != nil {
77+
panic(fmt.Sprintf("cannot get %v from %T", field.Path, from))
78+
}
79+
}()
7580
v := reflect.ValueOf(from)
7681
kind := v.Kind()
7782
if kind != reflect.Invalid {
@@ -86,7 +91,7 @@ func FetchField(from interface{}, field *Field) interface{} {
8691
}
8792
}
8893
}
89-
panic(fmt.Sprintf("cannot get %v from %T", field.Path, from))
94+
panic("why not")
9095
}
9196

9297
func Deref(i interface{}) interface{} {

0 commit comments

Comments
 (0)