Flatten builtin opcodes in vm

This commit is contained in:
Anton Medvedev
2023-01-30 22:24:35 +01:00
parent 87d918e76d
commit 12a40c72cb
6 changed files with 47 additions and 40 deletions
+20 -19
View File
@@ -12,24 +12,25 @@ var (
)
type Function struct {
Name string
Func func(args ...interface{}) (interface{}, error)
Types []reflect.Type
Validate func(args []reflect.Type) (reflect.Type, error)
BuiltinId int
Name string
Func func(args ...interface{}) (interface{}, error)
Opcode byte
Types []reflect.Type
Validate func(args []reflect.Type) (reflect.Type, error)
}
const (
Len = iota + 1
Opcode byte = iota + 100
Len
Abs
Int
Float
)
var Builtins = []*Function{
{
Name: "len",
BuiltinId: Len,
var Builtins = map[byte]*Function{
Len: {
Name: "len",
Opcode: Len,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments for len (expected 1, got %d)", len(args))
@@ -41,9 +42,9 @@ var Builtins = []*Function{
return anyType, fmt.Errorf("invalid argument for len (type %s)", args[0])
},
},
{
Name: "abs",
BuiltinId: Abs,
Abs: {
Name: "abs",
Opcode: Abs,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments for abs (expected 1, got %d)", len(args))
@@ -55,9 +56,9 @@ var Builtins = []*Function{
return anyType, fmt.Errorf("invalid argument for abs (type %s)", args[0])
},
},
{
Name: "int",
BuiltinId: Int,
Int: {
Name: "int",
Opcode: Int,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments for int (expected 1, got %d)", len(args))
@@ -73,9 +74,9 @@ var Builtins = []*Function{
return anyType, fmt.Errorf("invalid argument for int (type %s)", args[0])
},
},
{
Name: "float",
BuiltinId: Float,
Float: {
Name: "float",
Opcode: Float,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments for float (expected 1, got %d)", len(args))
+2 -2
View File
@@ -527,8 +527,8 @@ func (c *compiler) CallNode(node *ast.CallNode) {
c.compile(arg)
}
if node.Func != nil {
if node.Func.BuiltinId > 0 {
c.emit(OpCallBuiltin, node.Func.BuiltinId)
if node.Func.Opcode > 0 {
c.emit(node.Func.Opcode)
return
}
switch len(node.Arguments) {
+2 -2
View File
@@ -31,8 +31,8 @@ func CreateNew() *Config {
Functions: make(map[string]*builtin.Function),
Optimize: true,
}
for _, builtin := range builtin.Builtins {
c.Functions[builtin.Name] = builtin
for _, f := range builtin.Builtins {
c.Functions[f.Name] = f
}
return c
}
+1 -2
View File
@@ -1,6 +1,6 @@
package vm
type Opcode byte
type Opcode = byte
const (
OpPush Opcode = iota
@@ -54,7 +54,6 @@ const (
OpCallN
OpCallFast
OpCallTyped
OpCallBuiltin
OpArray
OpMap
OpLen
+10 -3
View File
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/builtin"
"github.com/antonmedv/expr/file"
"github.com/antonmedv/expr/vm/runtime"
)
@@ -60,6 +61,15 @@ func (program *Program) Disassemble() string {
out += fmt.Sprintf("%v\t%v\t%v\t%v\n", pp, label, arg, c)
}
if op > builtin.Opcode {
f, ok := builtin.Builtins[op]
if !ok {
panic(fmt.Sprintf("unknown builtin %v", op))
}
out += fmt.Sprintf("%v\t%v\t%v\n", pp, "OpBuiltin", f.Name)
continue
}
switch op {
case OpPush:
constant("OpPush")
@@ -214,9 +224,6 @@ func (program *Program) Disassemble() string {
case OpCallTyped:
argument("OpCallTyped")
case OpCallBuiltin:
argument("OpCallBuiltin")
case OpArray:
code("OpArray")
+12 -12
View File
@@ -367,18 +367,6 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error)
out := vm.call(fn, arg)
vm.push(out)
case OpCallBuiltin:
switch arg {
case builtin.Len:
vm.push(runtime.Len(vm.pop()))
case builtin.Abs:
vm.push(runtime.Abs(vm.pop()))
case builtin.Int:
vm.push(runtime.ToInt(vm.pop()))
case builtin.Float:
vm.push(runtime.ToFloat64(vm.pop()))
}
case OpArray:
size := vm.pop().(int)
array := make([]interface{}, size)
@@ -454,6 +442,18 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error)
case OpEnd:
vm.scopes = vm.scopes[:len(vm.scopes)-1]
case builtin.Len:
vm.push(runtime.Len(vm.pop()))
case builtin.Abs:
vm.push(runtime.Abs(vm.pop()))
case builtin.Int:
vm.push(runtime.ToInt(vm.pop()))
case builtin.Float:
vm.push(runtime.ToFloat64(vm.pop()))
default:
panic(fmt.Sprintf("unknown bytecode %#x", op))
}