Skip to content

Add OpCallSuper opcode #314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,17 @@ func Benchmark_callField(b *testing.B) {
}

func Benchmark_callFast(b *testing.B) {
program, err := expr.Compile(`FnFast()`, expr.Env(CallEnv{}))
if err != nil {
b.Fatal(err)
}

env := CallEnv{
FnFast: func(s ...interface{}) interface{} {
return "fn_fast"
},
}

program, err := expr.Compile(`FnFast()`, expr.Env(env))
if err != nil {
b.Fatal(err)
}

var out interface{}
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
Expand Down
27 changes: 24 additions & 3 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import (
"github.com/antonmedv/expr/vm/runtime"
)

const (
placeholder = 12345
)
const placeholder = 12345

func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err error) {
defer func() {
Expand All @@ -30,6 +28,7 @@ func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err erro
}

if config != nil {
c.env = config.Env
c.mapEnv = config.MapEnv
c.cast = config.Expect
}
Expand All @@ -52,6 +51,8 @@ func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err erro
Constants: c.constants,
Bytecode: c.bytecode,
Arguments: c.arguments,
Functions: c.functions,
Arity: c.arity,
}
return
}
Expand All @@ -61,11 +62,14 @@ type compiler struct {
constants []interface{}
bytecode []Opcode
index map[interface{}]int
env interface{}
mapEnv bool
cast reflect.Kind
nodes []ast.Node
chains [][]int
arguments []int
functions []FastFunc
arity []int
}

func (c *compiler) emitLocation(loc file.Location, op Opcode, arg int) int {
Expand Down Expand Up @@ -129,6 +133,12 @@ func (c *compiler) addConstant(constant interface{}) int {
return p
}

func (c *compiler) addFunction(fn FastFunc, arity int) int {
c.functions = append(c.functions, fn)
c.arity = append(c.arity, arity)
return len(c.functions) - 1
}

func (c *compiler) patchJump(placeholder int) {
offset := len(c.bytecode) - placeholder
c.arguments[placeholder-1] = offset
Expand Down Expand Up @@ -516,6 +526,17 @@ func (c *compiler) CallNode(node *ast.CallNode) {
for _, arg := range node.Arguments {
c.compile(arg)
}
ident, ok := node.Callee.(*ast.IdentifierNode)
if ok && node.Fast {
fn := runtime.Fetch(c.env, ident.Value)
if fn != nil {
c.emit(OpCallSuper, c.addFunction(
fn.(FastFunc),
len(node.Arguments),
))
return
}
}
c.compile(node.Callee)
if node.Typed > 0 {
c.emit(OpCallTyped, node.Typed)
Expand Down
1 change: 1 addition & 0 deletions vm/opcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
OpSlice
OpCall
OpCallFast
OpCallSuper
OpCallTyped
OpArray
OpMap
Expand Down
5 changes: 5 additions & 0 deletions vm/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type Program struct {
Constants []interface{}
Bytecode []Opcode
Arguments []int
Functions []FastFunc
Arity []int
}

func (program *Program) Disassemble() string {
Expand Down Expand Up @@ -195,6 +197,9 @@ func (program *Program) Disassemble() string {
case OpCallFast:
argument("OpCallFast")

case OpCallSuper:
argument("OpCallSuper")

case OpCallTyped:
argument("OpCallTyped")

Expand Down
11 changes: 11 additions & 0 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
var MemoryBudget int = 1e6
var errorType = reflect.TypeOf((*error)(nil)).Elem()

type FastFunc = func(params ...interface{}) interface{}

func Run(program *Program, env interface{}) (interface{}, error) {
if program == nil {
return nil, fmt.Errorf("program is nil")
Expand Down Expand Up @@ -315,6 +317,15 @@ func (vm *VM) Run(program *Program, env interface{}) (out interface{}, err error
}
vm.push(fn(in...))

case OpCallSuper:
fn := program.Functions[arg]
size := program.Arity[arg]
in := make([]interface{}, size)
for i := int(size) - 1; i >= 0; i-- {
in[i] = vm.pop()
}
vm.push(fn(in...))

case OpCallTyped:
fn := vm.pop()
out := vm.call(fn, arg)
Expand Down