mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
Flatten builtin opcodes in vm
This commit is contained in:
+20
-19
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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")
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user