mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
Refactor builtin.Function and move builtin funcs to builtin package
This commit is contained in:
+9
-17
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -57,7 +57,6 @@ const (
|
||||
OpCallN
|
||||
OpCallFast
|
||||
OpCallTyped
|
||||
OpBuiltin
|
||||
OpArray
|
||||
OpMap
|
||||
OpLen
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user