fix: do not invert token.Less to token.Greater in compiler (#391)
* fix: do not invert token.Less to token.Great in compiler * unittest: do not invert token.Less to token.Great in compiler
This commit is contained in:
parent
6fc8053992
commit
e338512259
3 changed files with 77 additions and 29 deletions
24
compiler.go
24
compiler.go
|
@ -141,25 +141,7 @@ func (c *Compiler) Compile(node parser.Node) error {
|
|||
if node.Token == token.LAnd || node.Token == token.LOr {
|
||||
return c.compileLogical(node)
|
||||
}
|
||||
if node.Token == token.Less {
|
||||
if err := c.Compile(node.RHS); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Compile(node.LHS); err != nil {
|
||||
return err
|
||||
}
|
||||
c.emit(node, parser.OpBinaryOp, int(token.Greater))
|
||||
return nil
|
||||
} else if node.Token == token.LessEq {
|
||||
if err := c.Compile(node.RHS); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Compile(node.LHS); err != nil {
|
||||
return err
|
||||
}
|
||||
c.emit(node, parser.OpBinaryOp, int(token.GreaterEq))
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.Compile(node.LHS); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -182,6 +164,10 @@ func (c *Compiler) Compile(node parser.Node) error {
|
|||
c.emit(node, parser.OpBinaryOp, int(token.Greater))
|
||||
case token.GreaterEq:
|
||||
c.emit(node, parser.OpBinaryOp, int(token.GreaterEq))
|
||||
case token.Less:
|
||||
c.emit(node, parser.OpBinaryOp, int(token.Less))
|
||||
case token.LessEq:
|
||||
c.emit(node, parser.OpBinaryOp, int(token.LessEq))
|
||||
case token.Equal:
|
||||
c.emit(node, parser.OpEqual)
|
||||
case token.NotEqual:
|
||||
|
|
|
@ -107,12 +107,12 @@ func TestCompiler_Compile(t *testing.T) {
|
|||
concatInsts(
|
||||
tengo.MakeInstruction(parser.OpConstant, 0),
|
||||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 39),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 38),
|
||||
tengo.MakeInstruction(parser.OpPop),
|
||||
tengo.MakeInstruction(parser.OpSuspend)),
|
||||
objectsArray(
|
||||
intObject(2),
|
||||
intObject(1))))
|
||||
intObject(1),
|
||||
intObject(2))))
|
||||
|
||||
expectCompile(t, `1 >= 2`,
|
||||
bytecode(
|
||||
|
@ -131,12 +131,12 @@ func TestCompiler_Compile(t *testing.T) {
|
|||
concatInsts(
|
||||
tengo.MakeInstruction(parser.OpConstant, 0),
|
||||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 44),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 43),
|
||||
tengo.MakeInstruction(parser.OpPop),
|
||||
tengo.MakeInstruction(parser.OpSuspend)),
|
||||
objectsArray(
|
||||
intObject(2),
|
||||
intObject(1))))
|
||||
intObject(1),
|
||||
intObject(2))))
|
||||
|
||||
expectCompile(t, `1 == 2`,
|
||||
bytecode(
|
||||
|
@ -929,9 +929,9 @@ func() {
|
|||
concatInsts(
|
||||
tengo.MakeInstruction(parser.OpConstant, 0),
|
||||
tengo.MakeInstruction(parser.OpSetGlobal, 0),
|
||||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpGetGlobal, 0),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 39),
|
||||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 38),
|
||||
tengo.MakeInstruction(parser.OpJumpFalsy, 31),
|
||||
tengo.MakeInstruction(parser.OpGetGlobal, 0),
|
||||
tengo.MakeInstruction(parser.OpConstant, 2),
|
||||
|
@ -978,9 +978,9 @@ func() {
|
|||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpNotEqual),
|
||||
tengo.MakeInstruction(parser.OpOrJump, 34),
|
||||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpGetGlobal, 0),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 39),
|
||||
tengo.MakeInstruction(parser.OpConstant, 1),
|
||||
tengo.MakeInstruction(parser.OpBinaryOp, 38),
|
||||
tengo.MakeInstruction(parser.OpPop),
|
||||
tengo.MakeInstruction(parser.OpSuspend)),
|
||||
objectsArray(
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
@ -479,6 +480,67 @@ func TestCompiled_RunContext(t *testing.T) {
|
|||
require.Equal(t, context.DeadlineExceeded, err)
|
||||
}
|
||||
|
||||
func TestCompiled_CustomObject(t *testing.T) {
|
||||
c := compile(t, `r := (t<130)`, M{"t": &customNumber{value: 123}})
|
||||
compiledRun(t, c)
|
||||
compiledGet(t, c, "r", true)
|
||||
|
||||
c = compile(t, `r := (t>13)`, M{"t": &customNumber{value: 123}})
|
||||
compiledRun(t, c)
|
||||
compiledGet(t, c, "r", true)
|
||||
}
|
||||
|
||||
// customNumber is a user defined object that can compare to tengo.Int
|
||||
// very shitty implementation, just to test that token.Less and token.Greater in BinaryOp works
|
||||
type customNumber struct {
|
||||
tengo.ObjectImpl
|
||||
value int64
|
||||
}
|
||||
|
||||
func (n *customNumber) TypeName() string {
|
||||
return "Number"
|
||||
}
|
||||
|
||||
func (n *customNumber) String() string {
|
||||
return strconv.FormatInt(n.value, 10)
|
||||
}
|
||||
|
||||
func (n *customNumber) BinaryOp(op token.Token, rhs tengo.Object) (tengo.Object, error) {
|
||||
tengoInt, ok := rhs.(*tengo.Int)
|
||||
if !ok {
|
||||
return nil, tengo.ErrInvalidOperator
|
||||
}
|
||||
return n.binaryOpInt(op, tengoInt)
|
||||
}
|
||||
|
||||
func (n *customNumber) binaryOpInt(op token.Token, rhs *tengo.Int) (tengo.Object, error) {
|
||||
i := n.value
|
||||
|
||||
switch op {
|
||||
case token.Less:
|
||||
if i < rhs.Value {
|
||||
return tengo.TrueValue, nil
|
||||
}
|
||||
return tengo.FalseValue, nil
|
||||
case token.Greater:
|
||||
if i > rhs.Value {
|
||||
return tengo.TrueValue, nil
|
||||
}
|
||||
return tengo.FalseValue, nil
|
||||
case token.LessEq:
|
||||
if i <= rhs.Value {
|
||||
return tengo.TrueValue, nil
|
||||
}
|
||||
return tengo.FalseValue, nil
|
||||
case token.GreaterEq:
|
||||
if i >= rhs.Value {
|
||||
return tengo.TrueValue, nil
|
||||
}
|
||||
return tengo.FalseValue, nil
|
||||
}
|
||||
return nil, tengo.ErrInvalidOperator
|
||||
}
|
||||
|
||||
func compile(t *testing.T, input string, vars M) *tengo.Compiled {
|
||||
s := tengo.NewScript([]byte(input))
|
||||
for vn, vv := range vars {
|
||||
|
|
Loading…
Reference in a new issue