aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/vm/sqlvm/cmd/gen-op-test/main.go21
-rw-r--r--core/vm/sqlvm/common/context.go7
-rw-r--r--core/vm/sqlvm/common/decimal/decimal.go5
-rw-r--r--core/vm/sqlvm/errors/errors.go8
-rw-r--r--core/vm/sqlvm/runtime/instructions.go1526
-rw-r--r--core/vm/sqlvm/runtime/instructions_op_test.go3110
-rw-r--r--core/vm/sqlvm/runtime/instructions_test.go61
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl.go82
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl_data.go2934
-rw-r--r--core/vm/sqlvm/runtime/jumptable.go26
-rw-r--r--core/vm/sqlvm/runtime/opcodes.go95
-rw-r--r--core/vm/sqlvm/runtime/runtime.go25
12 files changed, 7784 insertions, 116 deletions
diff --git a/core/vm/sqlvm/cmd/gen-op-test/main.go b/core/vm/sqlvm/cmd/gen-op-test/main.go
new file mode 100644
index 000000000..60387dddf
--- /dev/null
+++ b/core/vm/sqlvm/cmd/gen-op-test/main.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "flag"
+
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/runtime"
+)
+
+func main() {
+ var output string
+ flag.StringVar(
+ &output, "o", "./runtime/instructions_op_test.go",
+ "the output path of generated testcases",
+ )
+ flag.Parse()
+
+ err := runtime.RenderOpTest(output)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/core/vm/sqlvm/common/context.go b/core/vm/sqlvm/common/context.go
index 1985473fa..56ad89ded 100644
--- a/core/vm/sqlvm/common/context.go
+++ b/core/vm/sqlvm/common/context.go
@@ -2,10 +2,17 @@ package common
import "github.com/dexon-foundation/dexon/core/vm"
+// Option is collection of SQL options.
+type Option struct {
+ SafeMath bool
+}
+
// Context holds SQL VM required params.
type Context struct {
vm.Context
Storage Storage
Contract *vm.Contract
+
+ Opt Option
}
diff --git a/core/vm/sqlvm/common/decimal/decimal.go b/core/vm/sqlvm/common/decimal/decimal.go
index 445256cf5..2b9993b02 100644
--- a/core/vm/sqlvm/common/decimal/decimal.go
+++ b/core/vm/sqlvm/common/decimal/decimal.go
@@ -6,4 +6,9 @@ import "github.com/dexon-foundation/decimal"
var (
False = decimal.New(0, 0)
True = decimal.New(1, 0)
+
+ Int64Max = decimal.New(1, 63).Sub(decimal.One)
+ Int64Min = decimal.New(1, 63).Neg()
+
+ UInt16Max = decimal.New(1, 16).Sub(decimal.One)
)
diff --git a/core/vm/sqlvm/errors/errors.go b/core/vm/sqlvm/errors/errors.go
index ad00e5bb0..9a22bf453 100644
--- a/core/vm/sqlvm/errors/errors.go
+++ b/core/vm/sqlvm/errors/errors.go
@@ -116,6 +116,7 @@ const (
// Planner Error
ErrorCodePlanner
// Runtime Error
+ ErrorCodeInvalidOperandNum
ErrorCodeInvalidDataType
ErrorCodeOverflow
ErrorCodeUnderflow
@@ -123,6 +124,9 @@ const (
ErrorCodeInvalidCastType
ErrorCodeDividedByZero
ErrorCodeNegDecimalToUint64
+ ErrorCodeDataLengthNotMatch
+ ErrorCodeMultipleEscapeByte
+ ErrorCodePendingEscapeByte
)
var errorCodeMap = [...]string{
@@ -149,6 +153,7 @@ var errorCodeMap = [...]string{
// Planner Error
ErrorCodePlanner: "planner failure", // TODO: fix the message.
// Runtime Error
+ ErrorCodeInvalidOperandNum: "invalid operand number",
ErrorCodeInvalidDataType: "invalid data type",
ErrorCodeOverflow: "overflow",
ErrorCodeUnderflow: "underflow",
@@ -156,6 +161,9 @@ var errorCodeMap = [...]string{
ErrorCodeInvalidCastType: "invalid cast type",
ErrorCodeDividedByZero: "divide by zero",
ErrorCodeNegDecimalToUint64: "negative deciaml to uint64",
+ ErrorCodeDataLengthNotMatch: "data length not match",
+ ErrorCodeMultipleEscapeByte: "multiple escape byte",
+ ErrorCodePendingEscapeByte: "pending escape byte",
}
func (c ErrorCode) Error() string {
diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go
index d1bfa8a17..bb0e8a425 100644
--- a/core/vm/sqlvm/runtime/instructions.go
+++ b/core/vm/sqlvm/runtime/instructions.go
@@ -1,7 +1,11 @@
package runtime
import (
+ "bytes"
+ "errors"
"fmt"
+ "regexp"
+ "sort"
"strings"
"github.com/dexon-foundation/decimal"
@@ -9,21 +13,31 @@ import (
dexCommon "github.com/dexon-foundation/dexon/common"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/common"
- "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
+ dec "github.com/dexon-foundation/dexon/core/vm/sqlvm/common/decimal"
+ se "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
)
-var tupleJoin = "|"
+var (
+ byteLikeP = byte('%')
+ byteLikeU = byte('_')
+ byteDot = byte('.')
+ bytesLikeReg = []byte{'.', '*', '?'}
+ bytesStart = []byte{'^'}
+ bytesEnd = []byte{'$'}
+
+ tupleJoin = "|"
+)
// OpFunction type
// data could be fields Fields, pattern []byte, order Orders
-type OpFunction func(ctx *common.Context, ops []*Operand, registers []*Operand, output int) error
+type OpFunction func(ctx *common.Context, ops, registers []*Operand, output uint) error
// Instruction represents single instruction with essential information
// collection.
type Instruction struct {
Op OpCode
Input []*Operand
- Output int
+ Output uint
Position uint32 // ast tree position
}
@@ -46,7 +60,7 @@ func (t Tuple) String() string {
for i := 0; i < len(t); i++ {
rawStr = append(rawStr, t[i].String())
}
- return strings.Join(rawStr, tupleJoin)
+ return fmt.Sprintf("\n%v\n", strings.Join(rawStr, tupleJoin))
}
// Operand would be array-based value associated with meta to describe type of
@@ -58,9 +72,9 @@ type Operand struct {
RegisterIndex uint
}
-func (o *Operand) toUint64() (result []uint64, err error) {
- result = make([]uint64, len(o.Data))
- for i, tuple := range o.Data {
+func (op *Operand) toUint64() (result []uint64, err error) {
+ result = make([]uint64, len(op.Data))
+ for i, tuple := range op.Data {
result[i], err = ast.DecimalToUint64(tuple[0].Value)
if err != nil {
return
@@ -69,9 +83,9 @@ func (o *Operand) toUint64() (result []uint64, err error) {
return
}
-func (o *Operand) toUint8() ([]uint8, error) {
- result := make([]uint8, len(o.Data))
- for i, tuple := range o.Data {
+func (op *Operand) toUint8() ([]uint8, error) {
+ result := make([]uint8, len(op.Data))
+ for i, tuple := range op.Data {
u, err := ast.DecimalToUint64(tuple[0].Value)
if err != nil {
return nil, err
@@ -81,10 +95,10 @@ func (o *Operand) toUint8() ([]uint8, error) {
return result, nil
}
-func opLoad(ctx *common.Context, input []*Operand, registers []*Operand, output int) error {
+func opLoad(ctx *common.Context, input []*Operand, registers []*Operand, output uint) error {
tableIdx := input[0].Data[0][0].Value.IntPart()
if tableIdx >= int64(len(ctx.Storage.Schema)) {
- return errors.ErrorCodeIndexOutOfRange
+ return se.ErrorCodeIndexOutOfRange
}
table := ctx.Storage.Schema[tableIdx]
@@ -164,3 +178,1489 @@ func decode(ctx *common.Context, dt ast.DataType, slot dexCommon.Hash, bytes []b
}
return rVal, nil
}
+
+func (op *Operand) clone(metaOnly bool) (op2 *Operand) {
+ op2 = &Operand{
+ Meta: op.cloneMeta(),
+ // skip RegisterIndex since is only used when loading
+ // skip IsImmediate flag since is only set by codegen
+ }
+
+ if metaOnly {
+ return
+ }
+
+ op2.Data = make([]Tuple, len(op.Data))
+ for i := 0; i < len(op.Data); i++ {
+ op2.Data[i] = append(Tuple{}, op.Data[i]...)
+ }
+ return
+}
+
+func (op *Operand) cloneMeta() (meta []ast.DataType) {
+ meta = make([]ast.DataType, len(op.Meta))
+ copy(meta, op.Meta)
+ return
+}
+
+// Equal compares underlying data level-by-level.
+func (op *Operand) Equal(op2 *Operand) (equal bool) {
+ if op2 == nil {
+ return
+ }
+
+ equal = op.IsImmediate == op2.IsImmediate
+ if !equal {
+ return
+ }
+
+ equal = metaAllEq(op, op2)
+ if !equal {
+ return
+ }
+
+ equal = len(op.Data) == len(op2.Data)
+ if !equal {
+ return
+ }
+
+ for i := 0; i < len(op.Data); i++ {
+ equal = op.Data[i].Equal(op2.Data[i], op.Meta)
+ if !equal {
+ return
+ }
+ }
+ return
+}
+
+// Equal compares tuple values one by one.
+func (t Tuple) Equal(t2 Tuple, meta []ast.DataType) (equal bool) {
+ equal = len(t) == len(t2)
+ if !equal {
+ return
+ }
+
+ for i := 0; i < len(t); i++ {
+ equal = t[i].Equal(t2[i], meta[i])
+ if !equal {
+ return
+ }
+ }
+ return
+}
+
+// Equal compares raw by type.
+func (r *Raw) Equal(r2 *Raw, dType ast.DataType) (equal bool) {
+ major, _ := ast.DecomposeDataType(dType)
+ switch major {
+ case ast.DataTypeMajorDynamicBytes,
+ ast.DataTypeMajorFixedBytes,
+ ast.DataTypeMajorAddress:
+ equal = bytes.Equal(r.Bytes, r2.Bytes)
+ default:
+ equal = r.Value.Cmp(r2.Value) == 0
+ }
+ return
+}
+
+var (
+ rawFalse = &Raw{Value: dec.False}
+ rawTrue = &Raw{Value: dec.True}
+)
+
+func metaAllEq(op1, op2 *Operand) bool {
+ if len(op1.Meta) != len(op2.Meta) {
+ return false
+ }
+
+ for i := 0; i < len(op1.Meta); i++ {
+ if op1.Meta[i] != op2.Meta[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func metaAll(op *Operand, fn func(ast.DataType) bool) bool {
+ for i := 0; i < len(op.Meta); i++ {
+ if !fn(op.Meta[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func metaBool(dType ast.DataType) bool {
+ dMajor, _ := ast.DecomposeDataType(dType)
+ return dMajor == ast.DataTypeMajorBool
+}
+
+func metaAllBool(op *Operand) bool { return metaAll(op, metaBool) }
+
+func metaArith(dType ast.DataType) bool {
+ major, _ := ast.DecomposeDataType(dType)
+ if major == ast.DataTypeMajorInt ||
+ major == ast.DataTypeMajorUint {
+ return true
+ }
+ return false
+}
+
+func metaAllArith(op *Operand) bool { return metaAll(op, metaArith) }
+
+func findMaxDataLength(ops []*Operand) (l int, err error) {
+ l = -1
+
+ for i := 0; i < len(ops); i++ {
+ if ops[i].IsImmediate {
+ continue
+ }
+
+ if l == -1 {
+ l = len(ops[i].Data)
+ }
+
+ if len(ops[i].Data) != l {
+ err = se.ErrorCodeDataLengthNotMatch
+ return
+ }
+ }
+
+ if l == -1 {
+ l = 1
+ }
+ return
+}
+
+func bool2Raw(b bool) (r *Raw) {
+ if b {
+ r = rawTrue
+ } else {
+ r = rawFalse
+ }
+ return
+}
+
+func value2ColIdx(v decimal.Decimal) (idx uint16) {
+ if v.GreaterThan(dec.UInt16Max) {
+ panic(errors.New("field index greater than uint16 max"))
+ } else if v.LessThan(decimal.Zero) {
+ panic(errors.New("field index less than 0"))
+ }
+
+ idx = uint16(v.IntPart())
+ return
+}
+
+func flowCheck(ctx *common.Context, v decimal.Decimal, dType ast.DataType) (err error) {
+ if !ctx.Opt.SafeMath {
+ return
+ }
+
+ min, max, ok := dType.GetMinMax()
+ if !ok {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ if v.Cmp(max) > 0 {
+ err = se.ErrorCodeOverflow
+ } else if v.Cmp(min) < 0 {
+ err = se.ErrorCodeUnderflow
+ }
+ return
+}
+
+func opAdd(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) || !metaAllArith(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+
+ raw, iErr := op1.Data[j].add(ctx, op2.Data[k], op1.Meta)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+ data[i] = raw
+ }
+
+ registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
+ return
+}
+
+func (t Tuple) add(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ raw := t[i].add(t2[i])
+ err = flowCheck(ctx, raw.Value, meta[i])
+ if err != nil {
+ return
+ }
+ t3[i] = raw
+ }
+ return
+}
+
+func (r *Raw) add(r2 *Raw) (r3 *Raw) {
+ r3 = &Raw{Value: r.Value.Add(r2.Value)}
+ return
+}
+
+func opMul(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) || !metaAllArith(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+
+ raw, iErr := op1.Data[j].mul(ctx, op2.Data[k], op1.Meta)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+ data[i] = raw
+ }
+
+ registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
+ return
+}
+
+func (t Tuple) mul(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ raw := t[i].mul(t2[i])
+ err = flowCheck(ctx, raw.Value, meta[i])
+ if err != nil {
+ return
+ }
+
+ t3[i] = raw
+ }
+ return
+}
+
+func (r *Raw) mul(r2 *Raw) (r3 *Raw) {
+ r3 = &Raw{Value: r.Value.Mul(r2.Value)}
+ return
+}
+
+func opSub(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) || !metaAllArith(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+
+ raw, iErr := op1.Data[j].sub(ctx, op2.Data[k], op1.Meta)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+ data[i] = raw
+ }
+
+ registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
+ return
+}
+
+func (t Tuple) sub(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ raw := t[i].sub(t2[i])
+ err = flowCheck(ctx, raw.Value, meta[i])
+ if err != nil {
+ return
+ }
+
+ t3[i] = raw
+ }
+ return
+}
+
+func (r *Raw) sub(r2 *Raw) (r3 *Raw) {
+ r3 = &Raw{Value: r.Value.Sub(r2.Value)}
+ return
+}
+
+func opDiv(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) || !metaAllArith(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ raw, iErr := op1.Data[j].div(ctx, op2.Data[k], op1.Meta)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+ data[i] = raw
+ }
+
+ registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
+ return
+}
+
+func (t Tuple) div(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ raw, iErr := t[i].div(t2[i])
+ if iErr != nil {
+ err = iErr
+ return
+ }
+
+ iErr = flowCheck(ctx, raw.Value, meta[i])
+ if iErr != nil {
+ err = iErr
+ return
+ }
+
+ t3[i] = raw
+ }
+ return
+}
+
+func (r *Raw) div(r2 *Raw) (r3 *Raw, err error) {
+ if r2.Value.IsZero() {
+ err = se.ErrorCodeDividedByZero
+ return
+ }
+
+ q, _ := r.Value.QuoRem(r2.Value, 0)
+
+ r3 = &Raw{Value: q}
+ return
+}
+
+func opMod(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) || !metaAllArith(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ raw, iErr := op1.Data[j].mod(ctx, op2.Data[k], op1.Meta)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+ data[i] = raw
+ }
+
+ registers[output] = &Operand{Meta: op1.cloneMeta(), Data: data}
+ return
+}
+
+func (t Tuple) mod(ctx *common.Context, t2 Tuple, meta []ast.DataType) (t3 Tuple, err error) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ raw, iErr := t[i].mod(t2[i])
+ if iErr != nil {
+ err = iErr
+ return
+
+ }
+ t3[i] = raw
+ }
+ return
+}
+
+func (r *Raw) mod(r2 *Raw) (r3 *Raw, err error) {
+ if r2.Value.IsZero() {
+ err = se.ErrorCodeDividedByZero
+ return
+ }
+
+ _, qr := r.Value.QuoRem(r2.Value, 0)
+
+ r3 = &Raw{Value: qr}
+ return
+}
+
+func opLt(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ data[i] = op1.Data[j].lt(op2.Data[k])
+ }
+
+ boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
+ meta := make([]ast.DataType, len(op1.Meta))
+ for i := 0; i < len(op1.Meta); i++ {
+ meta[i] = boolType
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+func (t Tuple) lt(t2 Tuple) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = bool2Raw(t[i].lt(t2[i]))
+ }
+ return
+}
+
+func (r *Raw) lt(r2 *Raw) (lt bool) {
+ if r.Bytes == nil {
+ lt = r.Value.Cmp(r2.Value) < 0
+ } else {
+ lt = bytes.Compare(r.Bytes, r2.Bytes) < 0
+ }
+ return
+}
+
+func opGt(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ data[i] = op1.Data[j].gt(op2.Data[k])
+ }
+
+ boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
+ meta := make([]ast.DataType, len(op1.Meta))
+ for i := 0; i < len(op1.Meta); i++ {
+ meta[i] = boolType
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+func (t Tuple) gt(t2 Tuple) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = bool2Raw(t[i].gt(t2[i]))
+ }
+ return
+}
+
+func (r *Raw) gt(r2 *Raw) (gt bool) {
+ if r.Bytes == nil {
+ gt = r.Value.Cmp(r2.Value) > 0
+ } else {
+ gt = bytes.Compare(r.Bytes, r2.Bytes) > 0
+ }
+ return
+}
+
+func opEq(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ data[i] = op1.Data[j].eq(op2.Data[k], op1.Meta)
+ }
+
+ boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
+ meta := make([]ast.DataType, len(op1.Meta))
+ for i := 0; i < len(op1.Meta); i++ {
+ meta[i] = boolType
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+func (t Tuple) eq(t2 Tuple, meta []ast.DataType) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = bool2Raw(t[i].Equal(t2[i], meta[i]))
+ }
+ return
+}
+
+func opAnd(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ if !metaAllBool(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ data[i] = op1.Data[j].and(op2.Data[k])
+ }
+
+ boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
+ meta := make([]ast.DataType, l)
+ for i := 0; i < l; i++ {
+ meta[i] = boolType
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+func (t Tuple) and(t2 Tuple) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = t[i].and(t2[i])
+ }
+ return
+}
+
+func (r *Raw) and(r2 *Raw) (r3 *Raw) {
+ r3 = bool2Raw(r.Value.Equal(dec.True) && r2.Value.Equal(dec.True))
+ return
+}
+
+func opOr(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ if !metaAllBool(op1) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ data := make([]Tuple, l)
+ for i, j, k := 0, 0, 0; i < l; i, j, k = i+1, j+1, k+1 {
+ if op1.IsImmediate {
+ j = 0
+ }
+ if op2.IsImmediate {
+ k = 0
+ }
+ data[i] = op1.Data[j].or(op2.Data[k])
+ }
+
+ boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
+ meta := make([]ast.DataType, l)
+ for i := 0; i < l; i++ {
+ meta[i] = boolType
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+func (t Tuple) or(t2 Tuple) (t3 Tuple) {
+ t3 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t3[i] = t[i].or(t2[i])
+ }
+ return
+}
+
+func (r *Raw) or(r2 *Raw) (r3 *Raw) {
+ r3 = bool2Raw(r.Value.Equal(dec.True) || r2.Value.Equal(dec.True))
+ return
+}
+
+func opNot(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 1 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op := ops[0]
+
+ if !metaAllBool(op) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ data := make([]Tuple, len(op.Data))
+ for i := 0; i < len(op.Data); i++ {
+ data[i] = op.Data[i].not()
+ }
+
+ registers[output] = &Operand{Meta: op.cloneMeta(), Data: data}
+ return
+}
+
+func (t Tuple) not() (t2 Tuple) {
+ t2 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t2[i] = t[i].not()
+ }
+ return
+}
+
+func (r *Raw) not() (r2 *Raw) {
+ r2 = bool2Raw(r.Value.IsZero())
+ return
+}
+
+func opUnion(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ if len(op1.Data) > len(op2.Data) {
+ op1, op2 = op2, op1
+ }
+
+ tmpMap := make(map[string]struct{})
+ for i := 0; i < len(op1.Data); i++ {
+ tmpMap[op1.Data[i].String()] = struct{}{}
+ }
+
+ op3 := op1.clone(false)
+
+ for i := 0; i < len(op2.Data); i++ {
+ if _, ok := tmpMap[op2.Data[i].String()]; !ok {
+ op3.Data = append(op3.Data, append(Tuple{}, op2.Data[i]...))
+ }
+ }
+
+ orders := make([]sortOption, len(op3.Meta))
+ for i := 0; i < len(orders); i++ {
+ orders[i] = sortOption{Asc: true, Field: uint(i)}
+ }
+
+ sort.SliceStable(
+ op3.Data,
+ func(i, j int) bool { return op3.Data[i].less(op3.Data[j], orders) },
+ )
+
+ registers[output] = op3
+ return
+}
+
+func opIntxn(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op1, op2 := ops[0], ops[1]
+
+ if !metaAllEq(op1, op2) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ if len(op1.Data) > len(op2.Data) {
+ op1, op2 = op2, op1
+ }
+
+ tmpMap := make(map[string]struct{})
+ for i := 0; i < len(op1.Data); i++ {
+ tmpMap[op1.Data[i].String()] = struct{}{}
+ }
+
+ op3 := &Operand{Meta: op1.cloneMeta(), Data: []Tuple{}}
+
+ for i := 0; i < len(op2.Data); i++ {
+ if _, ok := tmpMap[op2.Data[i].String()]; ok {
+ op3.Data = append(op3.Data, append(Tuple{}, op2.Data[i]...))
+ }
+ }
+
+ orders := make([]sortOption, len(op3.Meta))
+ for i := 0; i < len(orders); i++ {
+ orders[i] = sortOption{Asc: true, Field: uint(i)}
+ }
+
+ sort.SliceStable(
+ op3.Data,
+ func(i, j int) bool { return op3.Data[i].less(op3.Data[j], orders) },
+ )
+
+ registers[output] = op3
+ return
+}
+
+func opLike(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 && len(ops) != 3 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op, pattern := ops[0], ops[1]
+
+ var escape *Operand
+ if len(ops) > 2 {
+ escape = ops[2]
+ }
+
+ var cReg *regexp.Regexp
+
+ matchWithI := pattern.IsImmediate && (escape == nil || escape.IsImmediate)
+ if matchWithI {
+ var escapeBytes []byte
+ if escape != nil && len(escape.Data) > 0 {
+ escapeBytes = escape.Data[0][0].Bytes
+ }
+
+ if len(escapeBytes) > 1 {
+ err = se.ErrorCodeMultipleEscapeByte
+ return
+ }
+
+ cReg, err = like2regexp(pattern.Data[0][0].Bytes, escapeBytes)
+ if err != nil {
+ return
+ }
+
+ }
+
+ data := make([]Tuple, len(op.Data))
+ if matchWithI {
+ for i := 0; i < len(op.Data); i++ {
+ raw, iErr := op.Data[i].like(cReg)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+ data[i] = raw
+ }
+ } else {
+ var (
+ pat []byte
+ esc []byte
+ )
+
+ for i := 0; i < len(op.Data); i++ {
+ if pattern.IsImmediate {
+ pat = pattern.Data[0][0].Bytes
+ } else {
+ pat = pattern.Data[i][0].Bytes
+ }
+
+ if escape != nil {
+ if escape.IsImmediate {
+ esc = escape.Data[0][0].Bytes
+ } else {
+ esc = escape.Data[i][0].Bytes
+ }
+ } else {
+ esc = []byte{}
+ }
+
+ if len(esc) > 1 {
+ err = se.ErrorCodeMultipleEscapeByte
+ return
+ }
+
+ reg, iErr := like2regexp(pat, esc)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+
+ raw, iErr := op.Data[i].like(reg)
+ if iErr != nil {
+ err = iErr
+ return
+ }
+
+ data[i] = raw
+ }
+ }
+
+ boolType := ast.ComposeDataType(ast.DataTypeMajorBool, 0)
+ meta := make([]ast.DataType, len(op.Meta))
+ for i := 0; i < len(meta); i++ {
+ meta[i] = boolType
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+// check parser/parser.go comment for string encoding
+func encB(b []byte) []byte {
+ encBuf := bytes.Buffer{}
+ for _, c := range b {
+ encBuf.WriteRune(rune(c))
+ }
+ return encBuf.Bytes()
+}
+
+func writeC2Buf(buf *bytes.Buffer, c byte) {
+ if c < 0x80 {
+ // quote for valid ascii
+ buf.WriteString(regexp.QuoteMeta(string(c)))
+ } else {
+ buf.WriteRune(rune(c))
+ }
+}
+
+func like2regexp(pattern []byte, escape []byte) (reg *regexp.Regexp, err error) {
+ var (
+ buf = &bytes.Buffer{}
+ escMode = len(escape) > 0
+ isEsc = false
+ c byte
+ )
+
+ for i := 0; i < len(pattern); i++ {
+ c = pattern[i]
+
+ if escMode && !isEsc && c == escape[0] {
+ isEsc = true
+ continue
+ }
+
+ if escMode && isEsc {
+ isEsc = false
+ writeC2Buf(buf, c)
+ continue
+ }
+
+ switch c {
+ case byteLikeP:
+ buf.Write(bytesLikeReg)
+ case byteLikeU:
+ buf.WriteByte(byteDot)
+ default:
+ writeC2Buf(buf, c)
+ }
+ }
+
+ if isEsc {
+ err = se.ErrorCodePendingEscapeByte
+ return
+ }
+
+ rPattern := buf.Bytes()
+
+ if !bytes.HasPrefix(rPattern, bytesLikeReg) {
+ rPattern = append(bytesStart, rPattern...)
+ }
+
+ if !bytes.HasSuffix(rPattern, bytesLikeReg) {
+ rPattern = append(rPattern, bytesEnd...)
+ }
+
+ reg, err = regexp.Compile(string(rPattern))
+ return
+}
+
+func (t Tuple) like(reg *regexp.Regexp) (t2 Tuple, err error) {
+ t2 = make(Tuple, len(t))
+ for i := 0; i < len(t); i++ {
+ t2[i] = t[i].like(reg)
+ }
+ return
+}
+
+func (r *Raw) like(reg *regexp.Regexp) (r2 *Raw) {
+ r2 = bool2Raw(reg.Match(encB(r.Bytes)))
+ return
+}
+
+func opZip(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ l, err := findMaxDataLength(ops)
+ if err != nil {
+ return
+ }
+
+ op3 := &Operand{Meta: make([]ast.DataType, 0), Data: make([]Tuple, l)}
+
+ for i := 0; i < len(ops); i++ {
+ op3.Meta = append(op3.Meta, ops[i].Meta...)
+ }
+
+ for i := 0; i < l; i++ {
+ if ops[0].IsImmediate {
+ op3.Data[i] = append(Tuple{}, ops[0].Data[0]...)
+ } else {
+ op3.Data[i] = append(Tuple{}, ops[0].Data[i]...)
+ }
+
+ for j := 1; j < len(ops); j++ {
+ if ops[j].IsImmediate {
+ op3.Data[i] = append(op3.Data[i], ops[j].Data[0]...)
+ } else {
+ op3.Data[i] = append(op3.Data[i], ops[j].Data[i]...)
+ }
+ }
+ }
+
+ registers[output] = op3
+ return
+}
+
+func opField(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op, fields := ops[0], ops[1].Data[0]
+ fLen := len(fields)
+
+ var fieldIdx uint16
+ meta, fieldIdxs := make([]ast.DataType, fLen), make([]uint16, fLen)
+ for i := 0; i < fLen; i++ {
+ fieldIdx = value2ColIdx(fields[i].Value)
+ if len(op.Meta) <= int(fieldIdx) {
+ err = se.ErrorCodeIndexOutOfRange
+ return
+ }
+ meta[i], fieldIdxs[i] = op.Meta[fieldIdx], fieldIdx
+ }
+
+ data := make([]Tuple, len(op.Data))
+ for i := 0; i < len(op.Data); i++ {
+ tuple := make(Tuple, fLen)
+ for j := 0; j < fLen; j++ {
+ tuple[j] = op.Data[i][fieldIdxs[j]]
+ }
+ data[i] = tuple
+ }
+
+ registers[output] = &Operand{Meta: meta, Data: data}
+ return
+}
+
+// in-place Op
+func opPrune(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op, fields := ops[0], ops[1].Data[0]
+ fLen := len(fields)
+
+ var fieldIdx uint16
+ fieldIdxs := make([]int, fLen)
+ for i := 0; i < fLen; i++ {
+ fieldIdx = value2ColIdx(fields[i].Value)
+ if len(op.Meta) <= int(fieldIdx) {
+ err = se.ErrorCodeIndexOutOfRange
+ return
+ }
+ fieldIdxs[i] = int(fieldIdx)
+ }
+
+ op.Meta = pruneMeta(op.Meta, fieldIdxs)
+
+ for i := 0; i < len(op.Data); i++ {
+ op.Data[i] = pruneTuple(op.Data[i], fieldIdxs)
+ }
+ return
+}
+
+func pruneMeta(meta []ast.DataType, idxs []int) (meta2 []ast.DataType) {
+ for c, idx := range idxs {
+ end := len(meta) - 1
+ if c+1 < len(idxs) {
+ end = idxs[c+1]
+ }
+
+ for i := idx; i < end; i++ {
+ meta[i-c] = meta[i+1]
+ }
+ }
+ meta2 = meta[:len(meta)-len(idxs)]
+ return
+}
+
+func pruneTuple(t Tuple, idxs []int) (t2 Tuple) {
+ for c, idx := range idxs {
+ end := len(t) - 1
+ if c+1 < len(idxs) {
+ end = idxs[c+1]
+ }
+
+ for i := idx; i < end; i++ {
+ t[i-c] = t[i+1]
+ }
+ }
+ t2 = t[:len(t)-len(idxs)]
+ return
+}
+
+// in-place Op
+func opSort(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op := ops[0]
+
+ // orders (ascending bool, field)
+ orders := make([]sortOption, len(ops[1].Data))
+ for i, o := range ops[1].Data {
+ orders[i] = sortOption{
+ Asc: o[0].cmp(rawTrue) == 0,
+ Field: uint(value2ColIdx(o[1].Value)),
+ }
+ }
+
+ sort.SliceStable(
+ op.Data,
+ func(i, j int) bool { return op.Data[i].less(op.Data[j], orders) },
+ )
+ return
+}
+
+type sortOption struct {
+ Asc bool
+ Field uint
+}
+
+func (t Tuple) less(t2 Tuple, orders []sortOption) bool {
+ var r int
+
+ for _, o := range orders {
+ r = 0
+
+ if o.Asc {
+ r = t[o.Field].cmp(t2[o.Field])
+ } else {
+ r = t2[o.Field].cmp(t[o.Field])
+ }
+
+ switch r {
+ case -1:
+ return true
+ case 1:
+ return false
+ }
+ }
+ return false
+}
+
+func (r *Raw) cmp(r2 *Raw) (v int) {
+ if r.Bytes != nil {
+ v = bytes.Compare(r.Bytes, r2.Bytes)
+ } else {
+ v = r.Value.Cmp(r2.Value)
+ }
+ return
+}
+
+func opFilter(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op, filters := ops[0], ops[1]
+
+ op2 := &Operand{Meta: op.cloneMeta(), Data: make([]Tuple, 0)}
+
+ for i := 0; i < len(filters.Data); i++ {
+ if filters.Data[i][0].cmp(rawTrue) == 0 {
+ op2.Data = append(op2.Data, append(Tuple{}, op.Data[i]...))
+ }
+ }
+
+ registers[output] = op2
+ return
+}
+
+// Type check will ensure all cast is valid
+func opCast(ctx *common.Context, ops, registers []*Operand, output uint) (err error) {
+ if len(ops) != 2 {
+ err = se.ErrorCodeInvalidOperandNum
+ return
+ }
+ op := ops[0]
+ dTypes := ops[1].Meta
+
+ if len(dTypes) != len(op.Meta) {
+ err = se.ErrorCodeInvalidDataType
+ return
+ }
+
+ op2 := &Operand{Meta: ops[1].cloneMeta(), Data: make([]Tuple, len(op.Data))}
+ for i := 0; i < len(op.Data); i++ {
+ op2.Data[i] = append(Tuple{}, op.Data[i]...)
+
+ for j, dType := range dTypes {
+ if op.Meta[j] == dType {
+ continue
+ }
+
+ err = op2.Data[i][j].cast(ctx, op.Meta[j], dType)
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ registers[output] = op2
+ return
+}
+
+func (r *Raw) cast(ctx *common.Context, origin, target ast.DataType) (err error) {
+ oMajor, _ := ast.DecomposeDataType(origin)
+
+ // conversion table
+ switch oMajor {
+ case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
+ err = r.castInt(ctx, origin, target)
+ case ast.DataTypeMajorFixedBytes:
+ err = r.castFixedBytes(ctx, origin, target)
+ case ast.DataTypeMajorAddress:
+ err = r.castAddress(ctx, origin, target)
+ case ast.DataTypeMajorBool:
+ err = r.castBool(origin, target)
+ case ast.DataTypeMajorDynamicBytes:
+ err = r.castDynBytes(origin, target)
+ default:
+ err = se.ErrorCodeInvalidCastType
+ }
+ return
+}
+
+func (r *Raw) castValue(
+ ctx *common.Context,
+ origin, target ast.DataType,
+ l int, signed, rPadding bool) (err error) {
+ oBytes, err := ast.DecimalEncode(origin, r.Value)
+ if err != nil {
+ return
+ }
+
+ bytes2 := r.shiftBytes(oBytes, l, signed, rPadding)
+
+ r.Value, err = ast.DecimalDecode(target, bytes2)
+ if err != nil {
+ return
+ }
+
+ err = flowCheck(ctx, r.Value, target)
+ return
+}
+
+func (r *Raw) castInt(ctx *common.Context, origin, target ast.DataType) (err error) {
+ oMajor, oMinor := ast.DecomposeDataType(origin)
+ tMajor, tMinor := ast.DecomposeDataType(target)
+ signed := oMajor == ast.DataTypeMajorInt
+
+ switch tMajor {
+ case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
+ err = r.castValue(ctx, origin, target, int(tMinor)+1, signed, false)
+ case ast.DataTypeMajorAddress:
+ r.Bytes, err = ast.DecimalEncode(origin, r.Value)
+ if err != nil {
+ return
+ }
+
+ if len(r.Bytes) > dexCommon.AddressLength {
+ if r.Bytes[0]&0x80 != 0 {
+ err = se.ErrorCodeUnderflow
+ } else {
+ err = se.ErrorCodeOverflow
+ }
+ return
+ }
+
+ r.Bytes = r.shiftBytes(r.Bytes, dexCommon.AddressLength, signed, false)
+ r.Value = decimal.Zero
+ case ast.DataTypeMajorFixedBytes:
+ if tMinor != oMinor {
+ err = se.ErrorCodeInvalidCastType
+ return
+ }
+ r.Bytes, err = ast.DecimalEncode(origin, r.Value)
+ if err != nil {
+ return
+ }
+ r.Value = decimal.Zero
+ case ast.DataTypeMajorBool:
+ r.Value = bool2Raw(!r.Value.IsZero()).Value
+ default:
+ err = se.ErrorCodeInvalidCastType
+ }
+ return
+}
+
+func (r *Raw) castFixedBytes(ctx *common.Context, origin, target ast.DataType) (err error) {
+ _, oMinor := ast.DecomposeDataType(origin)
+ tMajor, tMinor := ast.DecomposeDataType(target)
+ switch tMajor {
+ case ast.DataTypeMajorDynamicBytes:
+ case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
+ if tMinor != oMinor {
+ err = se.ErrorCodeInvalidCastType
+ return
+ }
+ r.Value, err = ast.DecimalDecode(target, r.Bytes)
+ if err != nil {
+ return
+ }
+ r.Bytes = nil
+ case ast.DataTypeMajorFixedBytes:
+ r.Bytes = r.shiftBytes(r.Bytes, int(tMinor)+1, false, true)
+ case ast.DataTypeMajorAddress:
+ if oMinor != (dexCommon.AddressLength - 1) {
+ err = se.ErrorCodeInvalidCastType
+ return
+ }
+ default:
+ err = se.ErrorCodeInvalidCastType
+ }
+ return
+}
+
+func (r *Raw) castAddress(ctx *common.Context, origin, target ast.DataType) (err error) {
+ tMajor, tMinor := ast.DecomposeDataType(target)
+
+ switch tMajor {
+ case ast.DataTypeMajorAddress:
+ case ast.DataTypeMajorInt, ast.DataTypeMajorUint:
+ r.Value, err = ast.DecimalDecode(
+ target,
+ r.shiftBytes(r.Bytes, int(tMinor)+1, false, false),
+ )
+ if err != nil {
+ return
+ }
+ err = flowCheck(ctx, r.Value, target)
+ if err != nil {
+ return
+ }
+ r.Bytes = nil
+ case ast.DataTypeMajorFixedBytes:
+ if tMinor != (dexCommon.AddressLength - 1) {
+ err = se.ErrorCodeInvalidCastType
+ return
+ }
+ default:
+ err = se.ErrorCodeInvalidCastType
+ }
+ return
+}
+
+func (r *Raw) castBool(origin, target ast.DataType) (err error) {
+ tMajor, _ := ast.DecomposeDataType(target)
+ switch tMajor {
+ case ast.DataTypeMajorBool, ast.DataTypeMajorInt, ast.DataTypeMajorUint:
+ default:
+ err = se.ErrorCodeInvalidCastType
+ }
+ return
+}
+
+func (r *Raw) castDynBytes(origin, target ast.DataType) (err error) {
+ tMajor, tMinor := ast.DecomposeDataType(target)
+ switch tMajor {
+ case ast.DataTypeMajorDynamicBytes:
+ case ast.DataTypeMajorFixedBytes:
+ r.Bytes = r.shiftBytes(r.Bytes, int(tMinor)+1, false, true)
+ default:
+ err = se.ErrorCodeInvalidCastType
+ }
+ return
+}
+
+func (r *Raw) shiftBytes(src []byte, l int, signed, rPadding bool) (tgr []byte) {
+ if len(src) >= l {
+ if rPadding {
+ tgr = src[:l]
+ } else {
+ tgr = src[len(src)-l:]
+ }
+ return
+ }
+
+ tgr = make([]byte, l)
+
+ if rPadding {
+ copy(tgr, src)
+ return
+ }
+
+ copy(tgr[l-len(src):], src)
+
+ if signed && src[0]&0x80 != 0 {
+ for i := 0; i < l-len(src); i++ {
+ tgr[i] = 0xff
+ }
+ }
+ return
+}
diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go
new file mode 100644
index 000000000..f18fb0181
--- /dev/null
+++ b/core/vm/sqlvm/runtime/instructions_op_test.go
@@ -0,0 +1,3110 @@
+// Code generated - DO NOT EDIT.
+
+package runtime
+
+import (
+ "github.com/dexon-foundation/decimal"
+
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
+)
+
+func (s *instructionSuite) TestOpAdd() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(3)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(4)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(20)}},
+ {&Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(13)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(11)}, &Raw{Value: decimal.NewFromFloat(8)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-12)}, &Raw{Value: decimal.NewFromFloat(-20)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate 2",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(11)}, &Raw{Value: decimal.NewFromFloat(8)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-12)}, &Raw{Value: decimal.NewFromFloat(-20)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Overflow - Immediate",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(127)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Overflow None Immediate",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(126)}},
+ {&Raw{Value: decimal.NewFromFloat(126)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Underflow - Immediate",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-128)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeUnderflow,
+ },
+ {
+ "Underflow None Immediate",
+ Instruction{
+ Op: ADD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-127)}},
+ {&Raw{Value: decimal.NewFromFloat(-127)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeUnderflow,
+ },
+ }
+
+ s.run(testcases, opAdd)
+}
+
+func (s *instructionSuite) TestOpSub() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(3)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-4)}},
+ {&Raw{Value: decimal.NewFromFloat(20)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(7)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(9)}, &Raw{Value: decimal.NewFromFloat(12)}, &Raw{Value: decimal.NewFromFloat(20)}},
+ {&Raw{Value: decimal.NewFromFloat(-11)}, &Raw{Value: decimal.NewFromFloat(-8)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(4)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate 2",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-12)}, &Raw{Value: decimal.NewFromFloat(-20)}},
+ {&Raw{Value: decimal.NewFromFloat(11)}, &Raw{Value: decimal.NewFromFloat(8)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-4)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Overflow - Immediate",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(127)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Overflow None Immediate",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(126)}},
+ {&Raw{Value: decimal.NewFromFloat(126)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Underflow - Immediate",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-128)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeUnderflow,
+ },
+ {
+ "Underflow None Immediate",
+ Instruction{
+ Op: SUB,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-127)}},
+ {&Raw{Value: decimal.NewFromFloat(-127)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeUnderflow,
+ },
+ }
+
+ s.run(testcases, opSub)
+}
+
+func (s *instructionSuite) TestOpMul() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(4)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-4)}, &Raw{Value: decimal.NewFromFloat(-100)}},
+ {&Raw{Value: decimal.NewFromFloat(100)}, &Raw{Value: decimal.NewFromFloat(100)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(20)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate - 2",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(20)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Overflow - Immediate",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(127)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Overflow None Immediate",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(126)}},
+ {&Raw{Value: decimal.NewFromFloat(126)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Underflow - Immediate",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-128)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeUnderflow,
+ },
+ {
+ "Underflow None Immediate",
+ Instruction{
+ Op: MUL,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-127)}},
+ {&Raw{Value: decimal.NewFromFloat(-127)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeUnderflow,
+ },
+ }
+
+ s.run(testcases, opMul)
+}
+
+func (s *instructionSuite) TestOpDiv() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(13)}, &Raw{Value: decimal.NewFromFloat(13)}},
+ {&Raw{Value: decimal.NewFromFloat(-13)}, &Raw{Value: decimal.NewFromFloat(-13)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}},
+ {&Raw{Value: decimal.NewFromFloat(-5)}, &Raw{Value: decimal.NewFromFloat(5)}},
+ {&Raw{Value: decimal.NewFromFloat(6)}, &Raw{Value: decimal.NewFromFloat(-6)}},
+ {&Raw{Value: decimal.NewFromFloat(-6)}, &Raw{Value: decimal.NewFromFloat(6)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate 2",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(50)}, &Raw{Value: decimal.NewFromFloat(-50)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(9)}, &Raw{Value: decimal.NewFromFloat(9)}},
+ {&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-9)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}},
+ {&Raw{Value: decimal.NewFromFloat(-5)}, &Raw{Value: decimal.NewFromFloat(5)}},
+ {&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}},
+ {&Raw{Value: decimal.NewFromFloat(-5)}, &Raw{Value: decimal.NewFromFloat(5)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "DivideByZero Immediate",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeDividedByZero,
+ },
+ {
+ "DivideByZero None Immediate",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeDividedByZero,
+ },
+ {
+ "Overflow - Immediate",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(-128)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ {
+ "Overflow None Immediate",
+ Instruction{
+ Op: DIV,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-128)}},
+ {&Raw{Value: decimal.NewFromFloat(-128)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(-2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeOverflow,
+ },
+ }
+
+ s.run(testcases, opDiv)
+}
+
+func (s *instructionSuite) TestOpMod() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: MOD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(3)}},
+ {&Raw{Value: decimal.NewFromFloat(-3)}, &Raw{Value: decimal.NewFromFloat(-3)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ {&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: MOD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(13)}, &Raw{Value: decimal.NewFromFloat(13)}},
+ {&Raw{Value: decimal.NewFromFloat(-13)}, &Raw{Value: decimal.NewFromFloat(-13)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(-3)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate - 2",
+ Instruction{
+ Op: MOD,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(31)}, &Raw{Value: decimal.NewFromFloat(-31)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}},
+ {&Raw{Value: decimal.NewFromFloat(13)}, &Raw{Value: decimal.NewFromFloat(13)}},
+ {&Raw{Value: decimal.NewFromFloat(-13)}, &Raw{Value: decimal.NewFromFloat(-13)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}},
+ {&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "ModideByZero Immediate",
+ Instruction{
+ Op: MOD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeDividedByZero,
+ },
+ {
+ "ModideByZero None Immediate",
+ Instruction{
+ Op: MOD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ {&Raw{Value: decimal.NewFromFloat(10)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeDividedByZero,
+ },
+ }
+
+ s.run(testcases, opMod)
+}
+
+func (s *instructionSuite) TestOpLt() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: LT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawTrue, rawTrue},
+ {rawFalse, rawFalse, rawTrue},
+ {rawFalse, rawFalse, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: LT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawFalse, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate - 2",
+ Instruction{
+ Op: LT,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opLt)
+}
+
+func (s *instructionSuite) TestOpGt() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: GT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawFalse, rawFalse},
+ {rawTrue, rawFalse, rawFalse},
+ {rawTrue, rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: GT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate - 2",
+ Instruction{
+ Op: GT,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawFalse, rawTrue},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opGt)
+}
+
+func (s *instructionSuite) TestOpEq() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: EQ,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue, rawTrue},
+ {rawTrue, rawFalse, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: EQ,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue, rawTrue},
+ {rawTrue, rawFalse, rawFalse},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opEq)
+}
+
+func (s *instructionSuite) TestOpAnd() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: AND,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: AND,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate - 2",
+ Instruction{
+ Op: AND,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Invalid Data Type",
+ Instruction{
+ Op: AND,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeInvalidDataType,
+ },
+ }
+
+ s.run(testcases, opAnd)
+}
+
+func (s *instructionSuite) TestOpOr() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: OR,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawFalse, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate",
+ Instruction{
+ Op: OR,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawTrue, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Immediate - 2",
+ Instruction{
+ Op: OR,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawTrue, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Invalid Data Type",
+ Instruction{
+ Op: OR,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeInvalidDataType,
+ },
+ }
+
+ s.run(testcases, opOr)
+}
+
+func (s *instructionSuite) TestOpNot() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: NOT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawTrue},
+ {rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Errors Invalid Data Type",
+ Instruction{
+ Op: NOT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeInvalidDataType,
+ },
+ }
+
+ s.run(testcases, opNot)
+}
+
+func (s *instructionSuite) TestOpUnion() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: UNION,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawFalse},
+ {rawFalse, rawTrue},
+ {rawTrue, rawFalse},
+ {rawTrue, rawTrue},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opUnion)
+}
+
+func (s *instructionSuite) TestOpIntxn() {
+ testcases := []opTestcase{
+ {
+ "None Immediate",
+ Instruction{
+ Op: INTXN,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawFalse, rawFalse},
+ {rawTrue, rawTrue},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opIntxn)
+}
+
+func (s *instructionSuite) TestOpLike() {
+ testcases := []opTestcase{
+ {
+ "Like %\\%b% escape \\",
+ Instruction{
+ Op: LIKE,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("a%bcdefg")}, &Raw{Bytes: []byte("gfedcba")}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("%\\%b%")}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("\\")}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Like t1 escape t2",
+ Instruction{
+ Op: LIKE,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("a%bcdefg")}},
+ {&Raw{Bytes: []byte("gfedcba")}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("%\\%b%")}},
+ {&Raw{Bytes: []byte("_fed%")}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("\\")}},
+ {&Raw{Bytes: []byte("")}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue},
+ {rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Like with valid and invalid UTF8",
+ Instruction{
+ Op: LIKE,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{226, 40, 161, 228, 189, 160, 229, 165, 189}}, &Raw{Bytes: []byte("gfedcba")}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{37, 228, 189, 160, 37}}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opLike)
+}
+
+func (s *instructionSuite) TestOpZip() {
+ testcases := []opTestcase{
+ {
+ "Zip two array",
+ Instruction{
+ Op: ZIP,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}},
+ {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "Zip immediate",
+ Instruction{
+ Op: ZIP,
+ Input: []*Operand{
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opZip)
+}
+
+func (s *instructionSuite) TestOpField() {
+ testcases := []opTestcase{
+ {
+ "Retrieve 2nd,3rd column",
+ Instruction{
+ Op: FIELD,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opField)
+}
+
+func (s *instructionSuite) TestOpPrune() {
+ testcases := []opTestcase{
+ {
+ "Prune 2nd,4th,5th column",
+ Instruction{
+ Op: PRUNE,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse, rawTrue},
+ {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue, rawFalse},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(4)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Value: decimal.NewFromFloat(1)}},
+ {&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opPrune)
+}
+
+func (s *instructionSuite) TestOpFilter() {
+ testcases := []opTestcase{
+ {
+ "Filter first 2 rows",
+ Instruction{
+ Op: FILTER,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue},
+ {rawTrue},
+ {rawFalse},
+ {rawFalse},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ {rawFalse, rawTrue},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opFilter)
+}
+
+func (s *instructionSuite) TestOpCast() {
+ testcases := []opTestcase{
+ {
+ "None Immediate - int",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(4, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(127)}, &Raw{Value: decimal.NewFromFloat(127)}},
+ {&Raw{Value: decimal.NewFromFloat(-128)}, &Raw{Value: decimal.NewFromFloat(-128)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 2),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 0), ast.ComposeDataType(4, 2),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(127)}, &Raw{Value: decimal.NewFromFloat(127)}},
+ {&Raw{Value: decimal.NewFromFloat(-128)}, &Raw{Value: decimal.NewFromFloat(-128)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - int2",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(4, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(-32768)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(32768)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - int3",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(4, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(-32768)}},
+ {&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawTrue},
+ {rawFalse, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - int4",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(4, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(-32768)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1), ast.ComposeDataType(3, 0),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1), ast.ComposeDataType(3, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0x7f, 0xff}}, &Raw{Bytes: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0x80, 0x00}}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - uint",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(128)}, &Raw{Value: decimal.NewFromFloat(128)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(5, 0), ast.ComposeDataType(5, 2),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 0), ast.ComposeDataType(5, 2),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(128)}, &Raw{Value: decimal.NewFromFloat(128)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - uint2",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(32768)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(6, 1),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(6, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Bytes: []byte{0x80, 0x00}}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - uint3",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue, rawFalse},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - uint4",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1), ast.ComposeDataType(6, 1),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1), ast.ComposeDataType(6, 1),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0x7f, 0xff}}, &Raw{Bytes: []byte{0x00, 0x00}}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - uint5",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(3, 1),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(3, 1),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7f, 0xff}}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - bytes",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1), ast.ComposeDataType(6, 1),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0xff, 0xff}}, &Raw{Bytes: []byte{0xff, 0xff}}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(6, 0), ast.ComposeDataType(6, 2),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(6, 0), ast.ComposeDataType(6, 2),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0xff}}, &Raw{Bytes: []byte{0xff, 0xff, 0x00}}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - bytes2",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1), ast.ComposeDataType(6, 1),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0x7f, 0xff}}, &Raw{Bytes: []byte{0x80, 0x00}}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 1), ast.ComposeDataType(5, 1),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(32768)}},
+ },
+ ),
+ nil,
+ },
+ {
+ "None Immediate - bytes3",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(6, 1),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0x7f, 0xff}}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(7, 1),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 1),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte{0x7f, 0xff}}},
+ },
+ ),
+ nil,
+ },
+ {
+ "Same type",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Error Invalid Type",
+ Instruction{
+ Op: CAST,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(4, 2),
+ },
+ []Tuple{
+ {&Raw{Value: decimal.NewFromFloat(-32768)}},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0),
+ },
+ []Tuple{},
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{},
+ []Tuple{},
+ ),
+ errors.ErrorCodeInvalidCastType,
+ },
+ }
+
+ s.run(testcases, opCast)
+}
+
+func (s *instructionSuite) TestOpSort() {
+ testcases := []opTestcase{
+ {
+ "Multi-column sorting",
+ Instruction{
+ Op: SORT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {rawFalse, &Raw{Value: decimal.NewFromFloat(1)}},
+ {rawTrue, &Raw{Value: decimal.NewFromFloat(2)}},
+ {rawFalse, &Raw{Value: decimal.NewFromFloat(0)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse},
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ },
+ ),
+ nil,
+ },
+ {
+ "Multi-column sorting - 2",
+ Instruction{
+ Op: SORT,
+ Input: []*Operand{
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ },
+ ),
+ makeOperand(
+ true,
+ []ast.DataType{
+ ast.ComposeDataType(2, 0), ast.ComposeDataType(4, 0),
+ },
+ []Tuple{
+ {rawTrue, &Raw{Value: decimal.NewFromFloat(0)}},
+ {rawTrue, &Raw{Value: decimal.NewFromFloat(1)}},
+ {rawFalse, &Raw{Value: decimal.NewFromFloat(2)}},
+ },
+ ),
+ },
+ Output: 0,
+ },
+ makeOperand(
+ false,
+ []ast.DataType{
+ ast.ComposeDataType(7, 0), ast.ComposeDataType(4, 0), ast.ComposeDataType(2, 0),
+ },
+ []Tuple{
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue},
+ {&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse},
+ {&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue},
+ {&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse},
+ },
+ ),
+ nil,
+ },
+ }
+
+ s.run(testcases, opSort)
+}
diff --git a/core/vm/sqlvm/runtime/instructions_test.go b/core/vm/sqlvm/runtime/instructions_test.go
index 7c6bb2c5b..b679c366f 100644
--- a/core/vm/sqlvm/runtime/instructions_test.go
+++ b/core/vm/sqlvm/runtime/instructions_test.go
@@ -191,7 +191,7 @@ type decodeTestCase struct {
type opLoadTestCase struct {
title string
- outputIdx int
+ outputIdx uint
expectedOutput *Operand
expectedErr error
ids []uint64
@@ -410,3 +410,62 @@ func (s *opLoadSuite) TestOpLoad() {
func TestOpLoad(t *testing.T) {
suite.Run(t, new(opLoadSuite))
}
+
+func TestInstructions(t *testing.T) {
+ suite.Run(t, new(instructionSuite))
+}
+
+func makeOperand(im bool, meta []ast.DataType, pTuple []Tuple) (op *Operand) {
+ op = &Operand{IsImmediate: im, Meta: meta, Data: pTuple}
+ return
+}
+
+func loadRegister(input, registers []*Operand) {
+ for i, operand := range input {
+ if operand != nil && !operand.IsImmediate {
+ input[i] = registers[operand.RegisterIndex]
+ }
+ }
+}
+
+type opTestcase struct {
+ Name string
+ In Instruction
+ Output *Operand
+ Err error
+}
+
+type instructionSuite struct {
+ suite.Suite
+}
+
+func (s *instructionSuite) run(testcases []opTestcase, opfunc OpFunction) {
+ for idx, c := range testcases {
+ registers := make([]*Operand, len(c.In.Input))
+
+ for i, j := 0, 0; i < len(c.In.Input); i++ {
+ if !c.In.Input[i].IsImmediate {
+ registers[j] = c.In.Input[i]
+ j++
+ }
+ }
+ err := opfunc(
+ &common.Context{Opt: common.Option{SafeMath: true}},
+ c.In.Input, registers, c.In.Output)
+ s.Require().Equal(
+ c.Err, err,
+ "idx: %v, op: %v, case: %v\nerror not equal: %v != %v",
+ idx, c.In.Op, c.Name, c.Err, err,
+ )
+ if c.Err != nil {
+ continue
+ }
+
+ result := registers[0]
+ s.Require().True(
+ c.Output.Equal(result),
+ "idx: %v, op: %v, case: %v\noutput not equal.\nExpect: %v\nResult: %v\n",
+ idx, c.In.Op, c.Name, c.Output, result,
+ )
+ }
+}
diff --git a/core/vm/sqlvm/runtime/instructions_tmpl.go b/core/vm/sqlvm/runtime/instructions_tmpl.go
new file mode 100644
index 000000000..22c6bef88
--- /dev/null
+++ b/core/vm/sqlvm/runtime/instructions_tmpl.go
@@ -0,0 +1,82 @@
+package runtime
+
+import "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+
+type tmplData struct {
+ BinOpCollections []tmplTestCollection
+}
+
+type tmplTestCollection struct {
+ TestName string
+ Cases []tmplTestCase
+ OpFunc string
+}
+
+type tmplTestCase struct {
+ Name string
+ OpCode string
+ Inputs []tmplOp
+ Output tmplOp
+ Error string
+}
+
+type tmplOp struct {
+ Im bool
+ Metas []tmplOpMeta
+ Data []string
+}
+
+type tmplOpMeta struct {
+ Major ast.DataTypeMajor
+ Minor ast.DataTypeMinor
+}
+
+const binOpTmplStr = `
+// Code generated - DO NOT EDIT.
+
+package runtime
+
+import (
+ "github.com/dexon-foundation/decimal"
+
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
+)
+
+{{range .BinOpCollections}}
+func (s *instructionSuite) Test{{.TestName}}() {
+ testcases := []opTestcase{ {{range .Cases}}
+ {
+ "{{.Name}}",
+ Instruction{
+ Op: {{.OpCode}},
+ Input: []*Operand{ {{range .Inputs}}
+ makeOperand(
+ {{.Im}},
+ []ast.DataType{
+ {{range .Metas}}ast.ComposeDataType({{.Major}}, {{.Minor}}),{{end}}
+ },
+ []Tuple{ {{range .Data}}
+ {{.}},{{end}}
+ },
+ ),{{end}}
+ },
+ Output: 0,
+ },
+ makeOperand(
+ {{.Output.Im}},
+ []ast.DataType{
+ {{range .Output.Metas}}ast.ComposeDataType({{.Major}}, {{.Minor}}),{{end}}
+ },
+ []Tuple{ {{range .Output.Data}}
+ {{.}},{{end}}
+ },
+ ),
+ {{.Error}},
+ },{{end}}
+ }
+
+ s.run(testcases, {{.OpFunc}})
+}
+{{end}}
+`
diff --git a/core/vm/sqlvm/runtime/instructions_tmpl_data.go b/core/vm/sqlvm/runtime/instructions_tmpl_data.go
new file mode 100644
index 000000000..345d200ec
--- /dev/null
+++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go
@@ -0,0 +1,2934 @@
+package runtime
+
+import (
+ "bytes"
+ "go/format"
+ "os"
+ "text/template"
+
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+)
+
+// RenderOpTest render op test to test file.
+func RenderOpTest(output string) (err error) {
+ binOpT, err := template.New("binOp").Parse(binOpTmplStr)
+ if err != nil {
+ return
+ }
+
+ b := new(bytes.Buffer)
+
+ err = binOpT.Execute(b, testData)
+ if err != nil {
+ return
+ }
+
+ src, err := format.Source(b.Bytes())
+ if err != nil {
+ return
+ }
+
+ f, err := os.Create(output)
+ if err != nil {
+ return
+ }
+ defer f.Close()
+
+ _, err = f.Write(src)
+ return
+}
+
+var testData = tmplData{
+ BinOpCollections: []tmplTestCollection{
+ {
+ TestName: "OpAdd", OpFunc: "opAdd",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(3)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(4)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(20)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(13)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(11)}, &Raw{Value: decimal.NewFromFloat(8)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-12)}, &Raw{Value: decimal.NewFromFloat(-20)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate 2",
+ Error: "nil", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(11)}, &Raw{Value: decimal.NewFromFloat(8)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-12)}, &Raw{Value: decimal.NewFromFloat(-20)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ {
+ Name: "Overflow - Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Overflow None Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(126)}}",
+ "{&Raw{Value: decimal.NewFromFloat(126)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Underflow - Immediate",
+ Error: "errors.ErrorCodeUnderflow", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-128)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Underflow None Immediate",
+ Error: "errors.ErrorCodeUnderflow", OpCode: "ADD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-127)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of ADD
+ {
+ TestName: "OpSub", OpFunc: "opSub",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(3)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-4)}}",
+ "{&Raw{Value: decimal.NewFromFloat(20)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(7)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(9)}, &Raw{Value: decimal.NewFromFloat(12)}, &Raw{Value: decimal.NewFromFloat(20)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-11)}, &Raw{Value: decimal.NewFromFloat(-8)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(4)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate 2",
+ Error: "nil", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-12)}, &Raw{Value: decimal.NewFromFloat(-20)}}",
+ "{&Raw{Value: decimal.NewFromFloat(11)}, &Raw{Value: decimal.NewFromFloat(8)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-4)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ {
+ Name: "Overflow - Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Overflow None Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(126)}}",
+ "{&Raw{Value: decimal.NewFromFloat(126)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Underflow - Immediate",
+ Error: "errors.ErrorCodeUnderflow", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-128)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Underflow None Immediate",
+ Error: "errors.ErrorCodeUnderflow", OpCode: "SUB",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-127)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of SUB
+ {
+ TestName: "OpMul", OpFunc: "opMul",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(4)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-4)}, &Raw{Value: decimal.NewFromFloat(-100)}}",
+ "{&Raw{Value: decimal.NewFromFloat(100)}, &Raw{Value: decimal.NewFromFloat(100)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(20)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate - 2",
+ Error: "nil", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-20)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(20)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ {
+ Name: "Overflow - Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Overflow None Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(126)}}",
+ "{&Raw{Value: decimal.NewFromFloat(126)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Underflow - Immediate",
+ Error: "errors.ErrorCodeUnderflow", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-128)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Underflow None Immediate",
+ Error: "errors.ErrorCodeUnderflow", OpCode: "MUL",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-127)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of MUL
+ {
+ TestName: "OpDiv", OpFunc: "opDiv",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(13)}, &Raw{Value: decimal.NewFromFloat(13)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-13)}, &Raw{Value: decimal.NewFromFloat(-13)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-5)}, &Raw{Value: decimal.NewFromFloat(5)}}",
+ "{&Raw{Value: decimal.NewFromFloat(6)}, &Raw{Value: decimal.NewFromFloat(-6)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-6)}, &Raw{Value: decimal.NewFromFloat(6)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate 2",
+ Error: "nil", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(50)}, &Raw{Value: decimal.NewFromFloat(-50)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(9)}, &Raw{Value: decimal.NewFromFloat(9)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-9)}, &Raw{Value: decimal.NewFromFloat(-9)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-5)}, &Raw{Value: decimal.NewFromFloat(5)}}",
+ "{&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-5)}, &Raw{Value: decimal.NewFromFloat(5)}}",
+ },
+ },
+ },
+ {
+ Name: "DivideByZero Immediate",
+ Error: "errors.ErrorCodeDividedByZero", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "DivideByZero None Immediate",
+ Error: "errors.ErrorCodeDividedByZero", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Overflow - Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-128)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "Overflow None Immediate",
+ Error: "errors.ErrorCodeOverflow", OpCode: "DIV",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-128)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-128)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-2)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of DIV
+ {
+ TestName: "OpMod", OpFunc: "opMod",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "MOD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(3)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-3)}, &Raw{Value: decimal.NewFromFloat(-3)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, &Raw{Value: decimal.NewFromFloat(-2)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "MOD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(13)}, &Raw{Value: decimal.NewFromFloat(13)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-13)}, &Raw{Value: decimal.NewFromFloat(-13)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(-3)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ {
+ Name: "Immediate - 2",
+ Error: "nil", OpCode: "MOD",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(31)}, &Raw{Value: decimal.NewFromFloat(-31)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}, &Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-10)}, &Raw{Value: decimal.NewFromFloat(-10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(13)}, &Raw{Value: decimal.NewFromFloat(13)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-13)}, &Raw{Value: decimal.NewFromFloat(-13)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}}",
+ "{&Raw{Value: decimal.NewFromFloat(5)}, &Raw{Value: decimal.NewFromFloat(-5)}}",
+ },
+ },
+ },
+ {
+ Name: "ModideByZero Immediate",
+ Error: "errors.ErrorCodeDividedByZero", OpCode: "MOD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ {
+ Name: "ModideByZero None Immediate",
+ Error: "errors.ErrorCodeDividedByZero", OpCode: "MOD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ "{&Raw{Value: decimal.NewFromFloat(10)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of MOD
+ {
+ TestName: "OpLt", OpFunc: "opLt",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "LT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawTrue, rawTrue}",
+ "{rawFalse, rawFalse, rawTrue}",
+ "{rawFalse, rawFalse, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "LT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawFalse, rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Immediate - 2",
+ Error: "nil", OpCode: "LT",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawTrue, rawFalse}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of LT
+ {
+ TestName: "OpGt", OpFunc: "opGt",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "GT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawFalse, rawFalse}",
+ "{rawTrue, rawFalse, rawFalse}",
+ "{rawTrue, rawTrue, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "GT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawTrue, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "Immediate - 2",
+ Error: "nil", OpCode: "GT",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawFalse, rawTrue}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of GT
+ {
+ TestName: "OpEq", OpFunc: "opEq",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "EQ",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue, rawTrue}",
+ "{rawTrue, rawFalse, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "EQ",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(-1)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue, rawTrue}",
+ "{rawTrue, rawFalse, rawFalse}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of EQ
+ {
+ TestName: "OpAnd", OpFunc: "opAnd",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "AND",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "AND",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Immediate - 2",
+ Error: "nil", OpCode: "AND",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Invalid Data Type",
+ Error: "errors.ErrorCodeInvalidDataType", OpCode: "AND",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of AND
+ {
+ TestName: "OpOr", OpFunc: "opOr",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "OR",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Immediate",
+ Error: "nil", OpCode: "OR",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawTrue, rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Immediate - 2",
+ Error: "nil", OpCode: "OR",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawTrue, rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Invalid Data Type",
+ Error: "errors.ErrorCodeInvalidDataType", OpCode: "OR",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of OR
+ {
+ TestName: "OpNot", OpFunc: "opNot",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "NOT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawTrue}",
+ "{rawTrue, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "Errors Invalid Data Type",
+ Error: "errors.ErrorCodeInvalidDataType", OpCode: "NOT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}}",
+ },
+ },
+ },
+ Output: tmplOp{},
+ },
+ },
+ },
+ // -- end of NOT
+ {
+ TestName: "OpUnion", OpFunc: "opUnion",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "UNION",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawFalse}",
+ "{rawFalse, rawTrue}",
+ "{rawTrue, rawFalse}",
+ "{rawTrue, rawTrue}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of UNION
+ {
+ TestName: "OpIntxn", OpFunc: "opIntxn",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate",
+ Error: "nil", OpCode: "INTXN",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, rawFalse}",
+ "{rawTrue, rawTrue}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of INTXN
+ {
+ TestName: "OpLike", OpFunc: "opLike",
+ Cases: []tmplTestCase{
+ {
+ Name: `Like %\\%b% escape \\`, // \\ is raw string escape for \
+ Error: "nil", OpCode: "LIKE",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("a%bcdefg")}, &Raw{Bytes: []byte("gfedcba")}}`,
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{`{&Raw{Bytes: []byte("%\\%b%")}}`},
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{`{&Raw{Bytes: []byte("\\")}}`},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: `Like t1 escape t2`,
+ Error: "nil", OpCode: "LIKE",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("a%bcdefg")}}`,
+ `{&Raw{Bytes: []byte("gfedcba")}}`,
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("%\\%b%")}}`,
+ `{&Raw{Bytes: []byte("_fed%")}}`,
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("\\")}}`,
+ `{&Raw{Bytes: []byte("")}}`,
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue}",
+ "{rawTrue}",
+ },
+ },
+ },
+ {
+ Name: `Like with valid and invalid UTF8`,
+ Error: "nil", OpCode: "LIKE",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte{226, 40, 161, 228, 189, 160, 229, 165, 189}}, &Raw{Bytes: []byte("gfedcba")}}`,
+ // "\xe2(\xa1你好"
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte{37, 228, 189, 160, 37}}}`,
+ // "%你%"
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of LIKE
+ {
+ TestName: "OpZip", OpFunc: "opZip",
+ Cases: []tmplTestCase{
+ {
+ Name: "Zip two array",
+ Error: "nil", OpCode: "ZIP",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}}`,
+ `{&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}}`,
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, rawTrue}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ },
+ },
+ },
+ {
+ Name: "Zip immediate",
+ Error: "nil", OpCode: "ZIP",
+ Inputs: []tmplOp{
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}}`,
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, rawTrue}",
+ "{&Raw{Value: decimal.NewFromFloat(2)}, rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ },
+ },
+ },
+ },
+ },
+ // -- end of ZIP
+ {
+ TestName: "OpField", OpFunc: "opField",
+ Cases: []tmplTestCase{
+ {
+ Name: "Retrieve 2nd,3rd column",
+ Error: "nil", OpCode: "FIELD",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}}`,
+ `{&Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}}`,
+ },
+ },
+ },
+ },
+ },
+ // -- end of FIELD
+ {
+ TestName: "OpPrune", OpFunc: "opPrune",
+ Cases: []tmplTestCase{
+ {
+ Name: "Prune 2nd,4th,5th column",
+ Error: "nil", OpCode: "PRUNE",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Bytes: []byte("gfedcba-1")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse, rawTrue}`,
+ `{&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Bytes: []byte("gfedcba-2")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue, rawFalse}`,
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(3)}, &Raw{Value: decimal.NewFromFloat(4)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("abcdefg-1")}, &Raw{Value: decimal.NewFromFloat(1)}}`,
+ `{&Raw{Bytes: []byte("abcdefg-2")}, &Raw{Value: decimal.NewFromFloat(2)}}`,
+ },
+ },
+ },
+ },
+ },
+ // -- end of PRUNE
+ {
+ TestName: "OpFilter", OpFunc: "opFilter",
+ Cases: []tmplTestCase{
+ {
+ Name: "Filter first 2 rows",
+ Error: "nil", OpCode: "FILTER",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ "{rawTrue, rawTrue}",
+ "{rawFalse, rawFalse}",
+ },
+ },
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue}",
+ "{rawTrue}",
+ "{rawFalse}",
+ "{rawFalse}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ "{rawFalse, rawTrue}",
+ },
+ },
+ },
+ },
+ },
+ // -- end of FILTER
+ {
+ TestName: "OpCast", OpFunc: "opCast",
+ Cases: []tmplTestCase{
+ {
+ Name: "None Immediate - int",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> int8
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> int24
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(127)}, &Raw{Value: decimal.NewFromFloat(127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-128)}, &Raw{Value: decimal.NewFromFloat(-128)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 2},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 2},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(127)}, &Raw{Value: decimal.NewFromFloat(127)}}",
+ "{&Raw{Value: decimal.NewFromFloat(-128)}, &Raw{Value: decimal.NewFromFloat(-128)}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - int2",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> uint16
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> uint16
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(-32768)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1},
+ {Major: ast.DataTypeMajorUint, Minor: 1},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1},
+ {Major: ast.DataTypeMajorUint, Minor: 1},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(32768)}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - int3",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> bool
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> bool
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(-32768)}}",
+ "{&Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawTrue}", "{rawFalse, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - int4",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> bytes16
+ {Major: ast.DataTypeMajorInt, Minor: 1}, // int16 -> address
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(-32768)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ {Major: ast.DataTypeMajorAddress, Minor: 0},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ {Major: ast.DataTypeMajorAddress, Minor: 0},
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0x7f, 0xff}}, &Raw{Bytes: []byte{255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0x80,0x00}}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - uint",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> uint8
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> uint24
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(128)}, &Raw{Value: decimal.NewFromFloat(128)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 0},
+ {Major: ast.DataTypeMajorUint, Minor: 2},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 0},
+ {Major: ast.DataTypeMajorUint, Minor: 2},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(128)}, &Raw{Value: decimal.NewFromFloat(128)}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - uint2",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> int16
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> byte16
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(32768)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1},
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1},
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Bytes: []byte{0x80,0x00}}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - uint3",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> bool
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> bool
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, rawFalse}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - uint4",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> bytes
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> bytes
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1},
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0x7f, 0xff}}, &Raw{Bytes: []byte{0x00, 0x00}}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - uint5",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorUint, Minor: 1}, // uint16 -> address
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorAddress, Minor: 1},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorAddress, Minor: 1},
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7f,0xff}}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - bytes",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1}, // byte16 -> byte8
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1}, // byte16 -> byte24
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0xff, 0xff}}, &Raw{Bytes: []byte{0xff, 0xff}}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 0},
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 2},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 0},
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 2},
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0xff}}, &Raw{Bytes: []byte{0xff, 0xff, 0x00}}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - bytes2",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1}, // byte16 -> int16
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1}, // byte16 -> uint16
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0x7f, 0xff}}, &Raw{Bytes: []byte{0x80, 0x00}}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1},
+ {Major: ast.DataTypeMajorUint, Minor: 1},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 1},
+ {Major: ast.DataTypeMajorUint, Minor: 1},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(32767)}, &Raw{Value: decimal.NewFromFloat(32768)}}",
+ },
+ },
+ },
+ {
+ Name: "None Immediate - bytes3",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorFixedBytes, Minor: 1}, // byte16 -> dyn
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0x7f, 0xff}}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 1},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 1},
+ },
+ Data: []string{
+ "{&Raw{Bytes: []byte{0x7f, 0xff}}}",
+ },
+ },
+ },
+ {
+ Name: "Same type",
+ Error: "nil", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue}",
+ },
+ },
+ },
+ {
+ Name: "Error Invalid Type",
+ Error: "errors.ErrorCodeInvalidCastType", OpCode: "CAST",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorInt, Minor: 2},
+ },
+ Data: []string{
+ "{&Raw{Value: decimal.NewFromFloat(-32768)}}",
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ },
+ Data: []string{},
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{},
+ Data: []string{},
+ },
+ },
+ },
+ },
+ // -- end of CAST
+ {
+ TestName: "OpSort", OpFunc: "opSort",
+ Cases: []tmplTestCase{
+ {
+ Name: "Multi-column sorting",
+ Error: "nil", OpCode: "SORT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{rawFalse, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{rawTrue, &Raw{Value: decimal.NewFromFloat(2)}}",
+ "{rawFalse, &Raw{Value: decimal.NewFromFloat(0)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ },
+ },
+ },
+ {
+ Name: "Multi-column sorting - 2",
+ Error: "nil", OpCode: "SORT",
+ Inputs: []tmplOp{
+ {
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ },
+ },
+ {
+ Im: true,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ },
+ Data: []string{
+ "{rawTrue, &Raw{Value: decimal.NewFromFloat(0)}}",
+ "{rawTrue, &Raw{Value: decimal.NewFromFloat(1)}}",
+ "{rawFalse, &Raw{Value: decimal.NewFromFloat(2)}}",
+ },
+ },
+ },
+ Output: tmplOp{
+ Im: false,
+ Metas: []tmplOpMeta{
+ {Major: ast.DataTypeMajorDynamicBytes, Minor: 0},
+ {Major: ast.DataTypeMajorInt, Minor: 0},
+ {Major: ast.DataTypeMajorBool, Minor: 0},
+ },
+ Data: []string{
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(1)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("a")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(2)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("b")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(1)}, rawTrue}`,
+ `{&Raw{Bytes: []byte("c")}, &Raw{Value: decimal.NewFromFloat(3)}, rawFalse}`,
+ },
+ },
+ },
+ },
+ },
+ // -- end of SORT
+ },
+}
diff --git a/core/vm/sqlvm/runtime/jumptable.go b/core/vm/sqlvm/runtime/jumptable.go
index 5ce6d9a8a..415a4e62b 100644
--- a/core/vm/sqlvm/runtime/jumptable.go
+++ b/core/vm/sqlvm/runtime/jumptable.go
@@ -1,6 +1,32 @@
package runtime
var jumpTable = [256]OpFunction{
+ // 0x10
+ ADD: opAdd,
+ MUL: opMul,
+ SUB: opSub,
+ DIV: opDiv,
+ MOD: opMod,
+
+ // 0x20
+ LT: opLt,
+ GT: opGt,
+ EQ: opEq,
+ AND: opAnd,
+ OR: opOr,
+ NOT: opNot,
+ UNION: opUnion,
+ INTXN: opIntxn,
+ LIKE: opLike,
+
+ // 0x40
+ ZIP: opZip,
+ FIELD: opField,
+ PRUNE: opPrune,
+ SORT: opSort,
+ FILTER: opFilter,
+ CAST: opCast,
+
// 0x60
LOAD: opLoad,
}
diff --git a/core/vm/sqlvm/runtime/opcodes.go b/core/vm/sqlvm/runtime/opcodes.go
index 22628b28e..88bc039e1 100644
--- a/core/vm/sqlvm/runtime/opcodes.go
+++ b/core/vm/sqlvm/runtime/opcodes.go
@@ -3,133 +3,54 @@ package runtime
// OpCode type
type OpCode byte
+// 0x00 range - higher order ops.
+const (
+ NOP OpCode = iota
+)
+
// 0x10 range - arithmetic ops. (array-based)
const (
ADD OpCode = iota + 0x10
- // ADD(t1, t2) res
- // res = t1 + t2 = [1, 2] + [2, 3] = [3, 5]
MUL
- // MUL(t1, t2) res
- // res = t1 * t2 = [1, 2] * [2, 3] = [2, 6]
SUB
- // SUB(t1, t2) res
- // res = t1 - t2 = [1, 2] - [2, 3] = [-1, -1]
DIV
- // DIV(t1, t2) res
- // res = t1 / t2 = [1, 2] / [2, 3] = [0, 0]
MOD
- // MOD(t1, t2) res
- // res = t1 % t2 = [1, 2] % [2, 3] = [1, 2]
-
)
// 0x20 range - comparison ops.
const (
LT OpCode = iota + 0x20
- // LT(t1, t2) res
- // res = t1 < t2 = [1, 2] < [2, 3] = [true, true]
GT
- // GT(t1, t2) res
- // res = t1 > t2 = [1, 2] > [2, 3] = [false, false]
EQ
- // EQ(t1, t2) res
- // res = t1 == t2 = [1, 2] == [2, 3] = [false, false]
AND
- // AND(t1, t2) res
- // res = t1 && t2 = [true, true] && [true, false] = [true, false]
OR
- // OR(t1, t2) res
- // res = t1 || t2 = [false, false] || [true, false] = [true, false]
NOT
- // NOT(t1) res
- // res = !t1 = ![false, true] = [true, false]
UNION
- // UNION(t1, t2) res
- // res = t1 ∪ t2 = [1, 2] ∪ [2, 3] = [1, 2, 3]
INTXN
- // INTXN(t1, t2) res
- // res = t1 ∩ t2 = [1, 2] ∩ [2, 3] = [2]
LIKE
- // LIKE(t1, pattern) res
- // res = t1 like '%abc%' =
- // ['_abc_', '123'] like '%abc%' = [true, false]
)
// 0x30 range - pk/index/field meta ops
const (
REPEATPK OpCode = iota + 0x30
- // REPEATPK(pk) res res = [id1, id2, id3, ...]
- // REPEATPK([tables, table_id, primary]) = [1, 2, 3, 5, 6, 7, ...]
REPEATIDX
- // Scan given index value(s)
- // REPEATIDX(base, idxv) res res = [id2, id4, id5, id6]
- // REPEATIDX(
- // [tables, table_id, indices, name_idx],
- // [val1, val3]
- // ) = [5, 6, 7, 10, 11, ... ]
REPEATIDXV
- // Get possible values from index value meta
- // REPEATIDXV(idx) res res = [val1, val2, val3, ...]
- // REPEATIDXV(
- // [tables, table_id, indices, name_idx]
- // ) = ["alice", "bob", "foo", "bar", ... ]
)
// 0x40 range - format/output ops
const (
ZIP OpCode = iota + 0x40
- // ZIP(tgr, new) = res
- // ZIP([f1, f2, f3], [c1, c2, c3]) = [(f1, c1), (f2, c2), (f3, c3)]
- // ZIP(
- // [(f1, c1), (f2, c2), (f3, c3)],
- // [(x1, (y1)), (x2, (y2)), (x3, (y3))]
- // ) = [(f1, c1, x1, (y1)), (f2, c2, x2, (y2)), (f3, c3, x2, (y2))]
FIELD
- // (src, fields) = res
- // (
- // [(r1f1, r1f2, r1f3), (r2f1, r2f2, r2f3),...], [2,3]
- // ) = [(r1f2, r1f3), (r2f2, r2f3), ...]
+ PRUNE
SORT
- // SORT(src, [(field, order, null order)] ) = res
- // SORT(
- // [(a1, a2, a3), (b1, a2, null), (a1, b2, null), ...],
- // [(1, asc, null_first), (2, desc, null_last), (3, asc, null_last)]
- // ) = [(a1, a2, a3), (a1, b2, null), (b1, a2, null), ...]
FILTER
- // FILTER(src, cond) = res
- // FILTER([1, 2, 3, 4, 5], [true, false, true, false, false]) = [1, 3]
CAST
- // CAST(t1, types) t2
)
// 0x60 range - storage ops
const (
- STOREPK OpCode = iota + 0x60
- // STOREPK(pk, [uint256, uint256, ...])
- LOADPK
- // LOADPK(pk) array array = [uint256, uint256, ...]
- STORE
- // STORE(base, ids, values, fields, idxes)
- // STORE(
- // [tables, table_id, primary],
- // [],
- // [field1, field2, [field3.1, field3.2]],
- // []
- // )
- // STORE(
- // [tables, table_id, primary],
- // [1, 2],
- // [updated_field1, updated_field2],
- // [1, 2]
- // )
+ INSERT = iota + 0x60
+ UPDATE
LOAD
- // LOAD(base, ids, fields) array
- // LOAD(
- // [tables, table_id, primary], [1], []
- // ) = [(field1, field2, [field3.1, field3.2])]
- // LOAD(
- // [tables, table_id, primary, [1], [1,3]
- // ) =[(field1, [field3.1, field3.2])]
DELETE
- // DELETE(base, ids, idxes)
)
diff --git a/core/vm/sqlvm/runtime/runtime.go b/core/vm/sqlvm/runtime/runtime.go
index 8c3a105ac..3b6d49a72 100644
--- a/core/vm/sqlvm/runtime/runtime.go
+++ b/core/vm/sqlvm/runtime/runtime.go
@@ -3,20 +3,23 @@ package runtime
import (
"github.com/dexon-foundation/dexon/core/vm"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/common"
- "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
+ se "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
)
// Run is runtime entrypoint.
func Run(stateDB vm.StateDB, ins []Instruction, registers []*Operand) (ret []byte, err error) {
for _, in := range ins {
- opFunc := jumpTable[in.Op]
- loadRegister(in.Input, registers)
- errCode := opFunc(&common.Context{}, in.Input, registers, in.Output)
+ for i := 0; i < len(in.Input); i++ {
+ if !in.Input[i].IsImmediate {
+ in.Input[i] = registers[in.Input[i].RegisterIndex]
+ }
+ }
+ errCode := jumpTable[in.Op](&common.Context{}, in.Input, registers, in.Output)
if errCode != nil {
- err = errors.Error{
+ err = se.Error{
Position: in.Position,
- Code: errCode.(errors.ErrorCode),
- Category: errors.ErrorCategoryRuntime,
+ Code: errCode.(se.ErrorCode),
+ Category: se.ErrorCategoryRuntime,
}
return nil, err
}
@@ -24,11 +27,3 @@ func Run(stateDB vm.StateDB, ins []Instruction, registers []*Operand) (ret []byt
// TODO: ret = ABIEncode(ins[len(ins)-1].Output)
return
}
-
-func loadRegister(input, registers []*Operand) {
- for i, operand := range input {
- if operand != nil && !operand.IsImmediate {
- input[i] = registers[operand.RegisterIndex]
- }
- }
-}