Refactor builtin.Function and move builtin funcs to builtin package

This commit is contained in:
Anton Medvedev
2023-08-14 11:50:42 +02:00
parent a7118a28c1
commit 8d959ea2fe
7 changed files with 183 additions and 145 deletions
+9 -17
View File
@@ -7,23 +7,15 @@ import (
type Function struct {
Name string
Id int
Func func(args ...interface{}) (interface{}, error)
Types []reflect.Type
Validate func(args []reflect.Type) (reflect.Type, error)
}
const (
Len = iota + 1
Abs
Int
Float
)
var Builtins = map[int]*Function{
Len: {
var Builtins = []*Function{
{
Name: "len",
Id: Len,
Func: 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))
@@ -35,9 +27,9 @@ var Builtins = map[int]*Function{
return anyType, fmt.Errorf("invalid argument for len (type %s)", args[0])
},
},
Abs: {
{
Name: "abs",
Id: Abs,
Func: 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))
@@ -49,9 +41,9 @@ var Builtins = map[int]*Function{
return anyType, fmt.Errorf("invalid argument for abs (type %s)", args[0])
},
},
Int: {
{
Name: "int",
Id: Int,
Func: 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))
@@ -67,9 +59,9 @@ var Builtins = map[int]*Function{
return anyType, fmt.Errorf("invalid argument for int (type %s)", args[0])
},
},
Float: {
{
Name: "float",
Id: Float,
Func: 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))
+173
View File
@@ -0,0 +1,173 @@
package builtin
import (
"fmt"
"reflect"
"strconv"
)
func Len(xs ...interface{}) (interface{}, error) {
x := xs[0]
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
return v.Len(), nil
default:
return nil, fmt.Errorf("invalid argument for len (type %T)", x)
}
}
func Abs(xs ...interface{}) (interface{}, error) {
x := xs[0]
switch x.(type) {
case float32:
if x.(float32) < 0 {
return -x.(float32), nil
} else {
return x, nil
}
case float64:
if x.(float64) < 0 {
return -x.(float64), nil
} else {
return x, nil
}
case int:
if x.(int) < 0 {
return -x.(int), nil
} else {
return x, nil
}
case int8:
if x.(int8) < 0 {
return -x.(int8), nil
} else {
return x, nil
}
case int16:
if x.(int16) < 0 {
return -x.(int16), nil
} else {
return x, nil
}
case int32:
if x.(int32) < 0 {
return -x.(int32), nil
} else {
return x, nil
}
case int64:
if x.(int64) < 0 {
return -x.(int64), nil
} else {
return x, nil
}
case uint:
if x.(uint) < 0 {
return -x.(uint), nil
} else {
return x, nil
}
case uint8:
if x.(uint8) < 0 {
return -x.(uint8), nil
} else {
return x, nil
}
case uint16:
if x.(uint16) < 0 {
return -x.(uint16), nil
} else {
return x, nil
}
case uint32:
if x.(uint32) < 0 {
return -x.(uint32), nil
} else {
return x, nil
}
case uint64:
if x.(uint64) < 0 {
return -x.(uint64), nil
} else {
return x, nil
}
}
return nil, fmt.Errorf("invalid argument for abs (type %T)", x)
}
func Int(xs ...interface{}) (interface{}, error) {
x := xs[0]
switch x := x.(type) {
case float32:
return int(x), nil
case float64:
return int(x), nil
case int:
return x, nil
case int8:
return int(x), nil
case int16:
return int(x), nil
case int32:
return int(x), nil
case int64:
return int(x), nil
case uint:
return int(x), nil
case uint8:
return int(x), nil
case uint16:
return int(x), nil
case uint32:
return int(x), nil
case uint64:
return int(x), nil
case string:
i, err := strconv.Atoi(x)
if err != nil {
return nil, fmt.Errorf("invalid operation: int(%s)", x)
}
return i, nil
default:
return nil, fmt.Errorf("invalid operation: int(%T)", x)
}
}
func Float(xs ...interface{}) (interface{}, error) {
x := xs[0]
switch x := x.(type) {
case float32:
return float64(x), nil
case float64:
return x, nil
case int:
return float64(x), nil
case int8:
return float64(x), nil
case int16:
return float64(x), nil
case int32:
return float64(x), nil
case int64:
return float64(x), nil
case uint:
return float64(x), nil
case uint8:
return float64(x), nil
case uint16:
return float64(x), nil
case uint32:
return float64(x), nil
case uint64:
return float64(x), nil
case string:
f, err := strconv.ParseFloat(x, 64)
if err != nil {
return nil, fmt.Errorf("invalid operation: float(%s)", x)
}
return f, nil
default:
return nil, fmt.Errorf("invalid operation: float(%T)", x)
}
}
-4
View File
@@ -563,10 +563,6 @@ func (c *compiler) CallNode(node *ast.CallNode) {
c.compile(arg)
}
if node.Func != nil {
if node.Func.Id > 0 {
c.emit(OpBuiltin, node.Func.Id)
return
}
switch len(node.Arguments) {
case 0:
c.emit(OpCall0, c.addFunction(node))
-1
View File
@@ -57,7 +57,6 @@ const (
OpCallN
OpCallFast
OpCallTyped
OpBuiltin
OpArray
OpMap
OpLen
-11
View File
@@ -9,7 +9,6 @@ import (
"text/tabwriter"
"github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/builtin"
"github.com/antonmedv/expr/file"
"github.com/antonmedv/expr/vm/runtime"
)
@@ -64,13 +63,6 @@ func (program *Program) Disassemble() string {
}
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t%v\n", pp, label, arg, c)
}
builtIn := func(label string) {
f, ok := builtin.Builtins[arg]
if !ok {
panic(fmt.Sprintf("unknown builtin %v", arg))
}
_, _ = fmt.Fprintf(w, "%v\t%v\t%v\n", pp, "OpBuiltin", f.Name)
}
switch op {
case OpInvalid:
@@ -236,9 +228,6 @@ func (program *Program) Disassemble() string {
signature := reflect.TypeOf(FuncTypes[arg]).Elem().String()
_, _ = fmt.Fprintf(w, "%v\t%v\t<%v>\t%v\n", pp, "OpCallTyped", arg, signature)
case OpBuiltin:
builtIn("OpBuiltin")
case OpArray:
code("OpArray")
-91
View File
@@ -6,7 +6,6 @@ import (
"fmt"
"math"
"reflect"
"strconv"
)
func Fetch(from, i interface{}) interface{} {
@@ -348,12 +347,6 @@ func ToInt(a interface{}) int {
return int(x)
case uint64:
return int(x)
case string:
i, err := strconv.Atoi(x)
if err != nil {
panic(fmt.Sprintf("invalid operation: int(%s)", x))
}
return i
default:
panic(fmt.Sprintf("invalid operation: int(%T)", x))
}
@@ -416,12 +409,6 @@ func ToFloat64(a interface{}) float64 {
return float64(x)
case uint64:
return float64(x)
case string:
f, err := strconv.ParseFloat(x, 64)
if err != nil {
panic(fmt.Sprintf("invalid operation: float(%s)", x))
}
return f
default:
panic(fmt.Sprintf("invalid operation: float(%T)", x))
}
@@ -439,81 +426,3 @@ func IsNil(v interface{}) bool {
return false
}
}
func Abs(x interface{}) interface{} {
switch x.(type) {
case float32:
if x.(float32) < 0 {
return -x.(float32)
} else {
return x
}
case float64:
if x.(float64) < 0 {
return -x.(float64)
} else {
return x
}
case int:
if x.(int) < 0 {
return -x.(int)
} else {
return x
}
case int8:
if x.(int8) < 0 {
return -x.(int8)
} else {
return x
}
case int16:
if x.(int16) < 0 {
return -x.(int16)
} else {
return x
}
case int32:
if x.(int32) < 0 {
return -x.(int32)
} else {
return x
}
case int64:
if x.(int64) < 0 {
return -x.(int64)
} else {
return x
}
case uint:
if x.(uint) < 0 {
return -x.(uint)
} else {
return x
}
case uint8:
if x.(uint8) < 0 {
return -x.(uint8)
} else {
return x
}
case uint16:
if x.(uint16) < 0 {
return -x.(uint16)
} else {
return x
}
case uint32:
if x.(uint32) < 0 {
return -x.(uint32)
} else {
return x
}
case uint64:
if x.(uint64) < 0 {
return -x.(uint64)
} else {
return x
}
}
panic(fmt.Sprintf("invalid argument for abs (type %T)", x))
}
+1 -21
View File
@@ -8,7 +8,6 @@ import (
"regexp"
"strings"
"github.com/antonmedv/expr/builtin"
"github.com/antonmedv/expr/file"
"github.com/antonmedv/expr/vm/runtime"
)
@@ -411,8 +410,7 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error)
vm.push(runtime.Len(vm.current()))
case OpCast:
t := arg
switch t {
switch arg {
case 0:
vm.push(runtime.ToInt(vm.pop()))
case 1:
@@ -456,24 +454,6 @@ func (vm *VM) Run(program *Program, env interface{}) (_ interface{}, err error)
case OpEnd:
vm.scopes = vm.scopes[:len(vm.scopes)-1]
case OpBuiltin:
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()))
default:
panic(fmt.Sprintf("unknown builtin %v", arg))
}
default:
panic(fmt.Sprintf("unknown bytecode %#x", op))
}