Skip to content

Commit

Permalink
fix: do not invert token.Less to token.Greater in compiler (#391)
Browse files Browse the repository at this point in the history
* fix: do not invert token.Less to token.Great in compiler

* unittest: do not invert token.Less to token.Great in compiler
  • Loading branch information
shiyuge authored Aug 29, 2022
1 parent 6fc8053 commit e338512
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 29 deletions.
24 changes: 5 additions & 19 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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:
Expand Down
20 changes: 10 additions & 10 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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(
Expand Down
62 changes: 62 additions & 0 deletions script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"math/rand"
"strconv"
"strings"
"sync"
"testing"
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit e338512

Please sign in to comment.