From aa5d758349c3e21124c1349e529880c63fc0fd05 Mon Sep 17 00:00:00 2001 From: "xielei.xielei" Date: Fri, 2 Aug 2024 15:38:09 +0800 Subject: [PATCH] fix as result not working with int32,int16,int8 --- checker/checker.go | 2 +- compiler/compiler.go | 14 ++++-- expr_test.go | 91 +++++++++++++++++++++++++++++++++++++ vm/runtime/runtime.go | 103 ++++++++++++++++++++++++++++++++++++++++++ vm/vm.go | 12 +++-- 5 files changed, 214 insertions(+), 8 deletions(-) diff --git a/checker/checker.go b/checker/checker.go index 0ad22f4e..c09b0245 100644 --- a/checker/checker.go +++ b/checker/checker.go @@ -79,7 +79,7 @@ func Check(tree *parser.Tree, config *conf.Config) (reflect.Type, error) { } switch v.config.Expect { - case reflect.Int, reflect.Int64, reflect.Float64: + case reflect.Int, reflect.Int64, reflect.Float64, reflect.Int32, reflect.Int16, reflect.Int8: if !isNumber(nt) { return nil, fmt.Errorf("expected %v, but got %v", v.config.Expect, nt) } diff --git a/compiler/compiler.go b/compiler/compiler.go index 68eae5ea..05b4bd33 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -40,12 +40,18 @@ func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err erro if c.config != nil { switch c.config.Expect { - case reflect.Int: - c.emit(OpCast, 0) + case reflect.Int8: + c.emit(OpCast, runtime.ResultAsTypInt8) + case reflect.Int16: + c.emit(OpCast, runtime.ResultAsTypInt16) + case reflect.Int32: + c.emit(OpCast, runtime.ResultAsTypInt32) case reflect.Int64: - c.emit(OpCast, 1) + c.emit(OpCast, runtime.ResultAsTypInt64) + case reflect.Int: + c.emit(OpCast, runtime.ResultAsTypInt) case reflect.Float64: - c.emit(OpCast, 2) + c.emit(OpCast, runtime.ResultAsTypFloat64) } if c.config.Optimize { c.optimize() diff --git a/expr_test.go b/expr_test.go index 4f2f829d..11e24a9d 100644 --- a/expr_test.go +++ b/expr_test.go @@ -210,6 +210,97 @@ func ExampleAsInt() { // Output: int(42) } +func ExampleAsInt32() { + program, err := expr.Compile("42", expr.AsKind(reflect.Int32)) + if err != nil { + fmt.Printf("%v", err) + return + } + + output, err := expr.Run(program, nil) + if err != nil { + fmt.Printf("%v", err) + return + } + + fmt.Printf("%T(%v)", output, output) + + // Output: int32(42) +} + +func TestAsResult(t *testing.T) { + type Case struct { + Name string + Want any + Code string + Opts []expr.Option + } + var cases = []Case{ + { + Name: "StrAsInt32", + Want: int32(42), + Code: "42", + Opts: []expr.Option{ + expr.AsKind(reflect.Int32), + }, + }, + { + Name: "FloatAsInt32", + Want: int32(42), + Code: "42.111", + Opts: []expr.Option{ + expr.AsKind(reflect.Int32), + }, + }, + { + Name: "StrAsInt16", + Want: int16(42), + Code: "42", + Opts: []expr.Option{ + expr.AsKind(reflect.Int16), + }, + }, + { + Name: "FloatAsInt16", + Want: int16(42), + Code: "42.111", + Opts: []expr.Option{ + expr.AsKind(reflect.Int16), + }, + }, + { + Name: "StrAsInt8", + Want: int8(42), + Code: "42", + Opts: []expr.Option{ + expr.AsKind(reflect.Int8), + }, + }, + { + Name: "FloatAsInt8", + Want: int8(42), + Code: "42.111", + Opts: []expr.Option{ + expr.AsKind(reflect.Int8), + }, + }, + } + for _, c := range cases { + t.Run(c.Name, func(t *testing.T) { + program, err := expr.Compile(c.Code, c.Opts...) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + output, err := expr.Run(program, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + assert.Equal(t, c.Want, output) + }) + } +} + func ExampleAsInt64() { env := map[string]any{ "rating": 5.5, diff --git a/vm/runtime/runtime.go b/vm/runtime/runtime.go index cd48a280..9c7a20b6 100644 --- a/vm/runtime/runtime.go +++ b/vm/runtime/runtime.go @@ -318,6 +318,99 @@ func ToInt(a any) int { } } +func ToInt8(a any) int8 { + switch x := a.(type) { + case float32: + return int8(x) + case float64: + return int8(x) + case int: + return int8(x) + case int8: + return int8(x) + case int16: + return int8(x) + case int32: + return int8(x) + case int64: + return int8(x) + case uint: + return int8(x) + case uint8: + return int8(x) + case uint16: + return int8(x) + case uint32: + return int8(x) + case uint64: + return int8(x) + default: + panic(fmt.Sprintf("invalid operation: int8(%T)", x)) + } +} + +func ToInt16(a any) int16 { + switch x := a.(type) { + case float32: + return int16(x) + case float64: + return int16(x) + case int: + return int16(x) + case int8: + return int16(x) + case int16: + return int16(x) + case int32: + return int16(x) + case int64: + return int16(x) + case uint: + return int16(x) + case uint8: + return int16(x) + case uint16: + return int16(x) + case uint32: + return int16(x) + case uint64: + return int16(x) + default: + panic(fmt.Sprintf("invalid operation: int16(%T)", x)) + } +} + +func ToInt32(a any) int32 { + switch x := a.(type) { + case float32: + return int32(x) + case float64: + return int32(x) + case int: + return int32(x) + case int8: + return int32(x) + case int16: + return int32(x) + case int32: + return x + case int64: + return int32(x) + case uint: + return int32(x) + case uint8: + return int32(x) + case uint16: + return int32(x) + case uint32: + return int32(x) + case uint64: + return int32(x) + default: + panic(fmt.Sprintf("invalid operation: int32(%T)", x)) + } +} + func ToInt64(a any) int64 { switch x := a.(type) { case float32: @@ -392,3 +485,13 @@ func IsNil(v any) bool { return false } } + +const ( + ResultAsTypUnknown int = iota + ResultAsTypInt8 + ResultAsTypInt16 + ResultAsTypInt32 + ResultAsTypInt64 + ResultAsTypInt + ResultAsTypFloat64 +) diff --git a/vm/vm.go b/vm/vm.go index fa1223b4..ed093534 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -447,11 +447,17 @@ func (vm *VM) Run(program *Program, env any) (_ any, err error) { case OpCast: switch arg { - case 0: + case runtime.ResultAsTypInt8: + vm.push(runtime.ToInt8(vm.pop())) + case runtime.ResultAsTypInt16: + vm.push(runtime.ToInt16(vm.pop())) + case runtime.ResultAsTypInt: vm.push(runtime.ToInt(vm.pop())) - case 1: + case runtime.ResultAsTypInt32: + vm.push(runtime.ToInt32(vm.pop())) + case runtime.ResultAsTypInt64: vm.push(runtime.ToInt64(vm.pop())) - case 2: + case runtime.ResultAsTypFloat64: vm.push(runtime.ToFloat64(vm.pop())) }