fix golint, ineffectassign issues and add some more tests

This commit is contained in:
Daniel Kang 2019-01-15 10:14:16 -08:00
parent 76a5c592aa
commit e1e0e0cb24
13 changed files with 217 additions and 40 deletions

View file

@ -9,10 +9,10 @@ import (
)
func errorTrace() []string {
pc := uintptr(0)
var pc uintptr
file := ""
line := 0
ok := false
var ok bool
name := ""
var callers []string

View file

@ -21,11 +21,7 @@ func (b *Bytecode) Decode(r io.Reader) error {
return err
}
if err := dec.Decode(&b.Constants); err != nil {
return err
}
return nil
return dec.Decode(&b.Constants)
}
// Encode writes Bytecode data to the writer.
@ -36,11 +32,7 @@ func (b *Bytecode) Encode(w io.Writer) error {
return err
}
if err := enc.Encode(b.Constants); err != nil {
return err
}
return nil
return enc.Encode(b.Constants)
}
func init() {

View file

@ -80,11 +80,7 @@ func (c *Compiler) Compile(node ast.Node) error {
}
case *ast.BinaryExpr:
if node.Token == token.LAnd || node.Token == token.LOr {
if err := c.compileLogical(node); err != nil {
return err
}
return nil
return c.compileLogical(node)
}
if node.Token == token.Less {

View file

@ -813,6 +813,25 @@ func() {
compiler.MakeInstruction(compiler.OpGetLocal, 0),
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
expect(t, `for i:=0; i<10; i++ {}`,
bytecode(
concat(
compiler.MakeInstruction(compiler.OpConstant, 0),
compiler.MakeInstruction(compiler.OpSetGlobal, 0),
compiler.MakeInstruction(compiler.OpConstant, 1),
compiler.MakeInstruction(compiler.OpGetGlobal, 0),
compiler.MakeInstruction(compiler.OpGreaterThan),
compiler.MakeInstruction(compiler.OpJumpFalsy, 29),
compiler.MakeInstruction(compiler.OpGetGlobal, 0),
compiler.MakeInstruction(compiler.OpConstant, 2),
compiler.MakeInstruction(compiler.OpAdd),
compiler.MakeInstruction(compiler.OpSetGlobal, 0),
compiler.MakeInstruction(compiler.OpJump, 6)),
objectsArray(
intObject(0),
intObject(10),
intObject(1))))
}
func concat(insts ...[]byte) []byte {

View file

@ -15,11 +15,6 @@ func (p *ErrorList) Add(pos source.FilePos, msg string) {
*p = append(*p, &Error{pos, msg})
}
// Reset clears the collection.
func (p *ErrorList) Reset() {
*p = (*p)[0:0]
}
// Len returns the number of elements in the collection.
func (p ErrorList) Len() int {
return len(p)

View file

@ -0,0 +1,18 @@
package parser_test
import (
"testing"
"github.com/d5/tengo/assert"
"github.com/d5/tengo/compiler/parser"
"github.com/d5/tengo/compiler/source"
)
func TestErrorList_Sort(t *testing.T) {
var list parser.ErrorList
list.Add(source.FilePos{Offset: 20, Line: 2, Column: 10}, "error 2")
list.Add(source.FilePos{Offset: 30, Line: 3, Column: 10}, "error 3")
list.Add(source.FilePos{Offset: 10, Line: 1, Column: 10}, "error 1")
list.Sort()
assert.Equal(t, "1:10: error 1 (and 2 more errors)", list.Error())
}

View file

@ -0,0 +1,14 @@
package parser_test
import (
"testing"
"github.com/d5/tengo/assert"
"github.com/d5/tengo/compiler/parser"
"github.com/d5/tengo/compiler/source"
)
func TestError_Error(t *testing.T) {
err := &parser.Error{Pos: source.FilePos{Offset: 10, Line: 1, Column: 10}, Msg: "test"}
assert.Equal(t, "1:10: test", err.Error())
}

View file

@ -98,19 +98,16 @@ func expectError(t *testing.T, input string) (ok bool) {
}
func expectString(t *testing.T, input, expected string) (ok bool) {
testFileSet := source.NewFileSet()
testFile := testFileSet.AddFile("", -1, len(input))
defer func() {
if !ok {
// print trace
tr := &tracer{}
_, _ = parser.ParseFile(testFile, []byte(input), tr)
_, _ = parser.ParseSource([]byte(input), tr)
t.Logf("Trace:\n%s", strings.Join(tr.out, ""))
}
}()
actual, err := parser.ParseFile(testFile, []byte(input), nil)
actual, err := parser.ParseSource([]byte(input), nil)
if !assert.NoError(t, err) {
return
}

View file

@ -267,8 +267,7 @@ func (s *Scanner) error(offset int, msg string) {
func (s *Scanner) scanComment() string {
// initial '/' already consumed; s.ch == '/' || s.ch == '*'
offs := s.offset - 1 // position of initial '/'
next := -1 // position immediately following the comment; < 0 means invalid comment
numCR := 0
var numCR int
if s.ch == '/' {
//-style comment
@ -280,11 +279,6 @@ func (s *Scanner) scanComment() string {
}
s.next()
}
// if we are at '\n', the position following the comment is afterwards
next = s.offset
if s.ch == '\n' {
next++
}
goto exit
}
@ -298,7 +292,6 @@ func (s *Scanner) scanComment() string {
s.next()
if ch == '*' && s.ch == '/' {
s.next()
next = s.offset
goto exit
}
}

60
objects/object_test.go Normal file
View file

@ -0,0 +1,60 @@
package objects_test
import (
"testing"
"github.com/d5/tengo/assert"
"github.com/d5/tengo/objects"
)
func TestObject_TypeName(t *testing.T) {
var o objects.Object
o = &objects.Int{}
assert.Equal(t, "int", o.TypeName())
o = &objects.Float{}
assert.Equal(t, "float", o.TypeName())
o = &objects.Char{}
assert.Equal(t, "char", o.TypeName())
o = &objects.String{}
assert.Equal(t, "string", o.TypeName())
o = &objects.Bool{}
assert.Equal(t, "bool", o.TypeName())
o = &objects.Array{}
assert.Equal(t, "array", o.TypeName())
o = &objects.Map{}
assert.Equal(t, "map", o.TypeName())
o = &objects.ArrayIterator{}
assert.Equal(t, "array-iterator", o.TypeName())
o = &objects.StringIterator{}
assert.Equal(t, "string-iterator", o.TypeName())
o = &objects.MapIterator{}
assert.Equal(t, "map-iterator", o.TypeName())
}
func TestObject_IsFalsy(t *testing.T) {
var o objects.Object
o = &objects.Int{Value: 0}
assert.True(t, o.IsFalsy())
o = &objects.Int{Value: 1}
assert.False(t, o.IsFalsy())
o = &objects.Float{Value: 0}
assert.False(t, o.IsFalsy())
o = &objects.Float{Value: 1}
assert.False(t, o.IsFalsy())
o = &objects.Char{Value: ' '}
assert.False(t, o.IsFalsy())
o = &objects.Char{Value: 'T'}
assert.False(t, o.IsFalsy())
o = &objects.String{Value: ""}
assert.True(t, o.IsFalsy())
o = &objects.String{Value: " "}
assert.False(t, o.IsFalsy())
o = &objects.Array{Value: nil}
assert.True(t, o.IsFalsy())
o = &objects.Array{Value: []objects.Object{nil}} // nil is not valid but still count as 1 element
assert.False(t, o.IsFalsy())
o = &objects.Map{Value: nil}
assert.True(t, o.IsFalsy())
o = &objects.Map{Value: map[string]objects.Object{"a": nil}} // nil is not valid but still count as 1 element
assert.False(t, o.IsFalsy())
}

View file

@ -26,3 +26,13 @@ func TestScript_Remove(t *testing.T) {
_, err = s.Compile() // should not compile because b is undefined
assert.Error(t, err)
}
func TestScript_Run(t *testing.T) {
s := script.New([]byte(`a := b`))
err := s.Add("b", 5)
assert.NoError(t, err)
c, err := s.Run()
assert.NoError(t, err)
assert.NotNil(t, c)
compiledGet(t, c, "a", int64(5))
}

View file

@ -12,6 +12,18 @@ type Variable struct {
value *objects.Object
}
func NewVariable(name string, value interface{}) (*Variable, error) {
obj, err := interfaceToObject(value)
if err != nil {
return nil, err
}
return &Variable{
name: name,
value: &obj,
}, nil
}
// Name returns the name of the variable.
func (v *Variable) Name() string {
return v.name
@ -35,22 +47,22 @@ func (v *Variable) Int() int {
// Int64 returns int64 value of the variable value.
// It returns 0 if the value is not convertible to int64.
func (v *Variable) Int64() int {
func (v *Variable) Int64() int64 {
switch val := (*v.value).(type) {
case *objects.Int:
return int(val.Value)
return val.Value
case *objects.Float:
return int(val.Value)
return int64(val.Value)
case *objects.Bool:
if val.Value {
return 1
}
return 0
case *objects.Char:
return int(val.Value)
return int64(val.Value)
case *objects.String:
n, _ := strconv.ParseInt(val.Value, 10, 64)
return int(n)
return n
}
return 0

71
script/variable_test.go Normal file
View file

@ -0,0 +1,71 @@
package script_test
import (
"testing"
"github.com/d5/tengo/assert"
"github.com/d5/tengo/objects"
"github.com/d5/tengo/script"
)
type VariableTest struct {
Name string
Value interface{}
ValueType string
IntValue int
Int64Value int64
FloatValue float64
CharValue rune
BoolValue bool
StringValue string
Object objects.Object
}
func TestVariable(t *testing.T) {
vars := []VariableTest{
{
Name: "a",
Value: int64(1),
ValueType: "int",
IntValue: 1,
Int64Value: 1,
FloatValue: 1.0,
StringValue: "1",
Object: &objects.Int{Value: 1},
},
{
Name: "b",
Value: "52.11",
ValueType: "string",
FloatValue: 52.11,
StringValue: "52.11",
Object: &objects.String{Value: "52.11"},
},
{
Name: "c",
Value: true,
ValueType: "bool",
IntValue: 1,
Int64Value: 1,
FloatValue: 1,
BoolValue: true,
StringValue: "true",
Object: &objects.Bool{Value: true},
},
}
for _, tc := range vars {
v, err := script.NewVariable(tc.Name, tc.Value)
assert.NoError(t, err)
assert.Equal(t, tc.Value, v.Value())
assert.Equal(t, tc.ValueType, v.ValueType())
assert.Equal(t, tc.IntValue, v.Int())
assert.Equal(t, tc.Int64Value, v.Int64())
assert.Equal(t, tc.FloatValue, v.Float())
assert.Equal(t, tc.CharValue, v.Char())
assert.Equal(t, tc.BoolValue, v.Bool())
assert.Equal(t, tc.StringValue, v.String())
assert.Equal(t, tc.Object, v.Object())
}
}