From e1e0e0cb243028d7a2028bda9f0b27264205f766 Mon Sep 17 00:00:00 2001 From: Daniel Kang Date: Tue, 15 Jan 2019 10:14:16 -0800 Subject: [PATCH] fix golint, ineffectassign issues and add some more tests --- assert/trace.go | 4 +- compiler/bytecode.go | 12 +---- compiler/compiler.go | 6 +-- compiler/compiler_test.go | 19 ++++++++ compiler/parser/error_list.go | 5 --- compiler/parser/error_list_test.go | 18 ++++++++ compiler/parser/error_test.go | 14 ++++++ compiler/parser/parser_test.go | 7 +-- compiler/scanner/scanner.go | 9 +--- objects/object_test.go | 60 +++++++++++++++++++++++++ script/script_test.go | 10 +++++ script/variable.go | 22 ++++++--- script/variable_test.go | 71 ++++++++++++++++++++++++++++++ 13 files changed, 217 insertions(+), 40 deletions(-) create mode 100644 compiler/parser/error_list_test.go create mode 100644 compiler/parser/error_test.go create mode 100644 objects/object_test.go create mode 100644 script/variable_test.go diff --git a/assert/trace.go b/assert/trace.go index a5a32d9..5ba1390 100644 --- a/assert/trace.go +++ b/assert/trace.go @@ -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 diff --git a/compiler/bytecode.go b/compiler/bytecode.go index 234f277..04bd1db 100644 --- a/compiler/bytecode.go +++ b/compiler/bytecode.go @@ -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() { diff --git a/compiler/compiler.go b/compiler/compiler.go index b532587..d0ebfb9 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -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 { diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index c3ba2fc..f1d90dd 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -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 { diff --git a/compiler/parser/error_list.go b/compiler/parser/error_list.go index 7b804c7..599eaf7 100644 --- a/compiler/parser/error_list.go +++ b/compiler/parser/error_list.go @@ -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) diff --git a/compiler/parser/error_list_test.go b/compiler/parser/error_list_test.go new file mode 100644 index 0000000..205dbc2 --- /dev/null +++ b/compiler/parser/error_list_test.go @@ -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()) +} diff --git a/compiler/parser/error_test.go b/compiler/parser/error_test.go new file mode 100644 index 0000000..b8bf687 --- /dev/null +++ b/compiler/parser/error_test.go @@ -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()) +} diff --git a/compiler/parser/parser_test.go b/compiler/parser/parser_test.go index fa90904..d284b38 100644 --- a/compiler/parser/parser_test.go +++ b/compiler/parser/parser_test.go @@ -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 } diff --git a/compiler/scanner/scanner.go b/compiler/scanner/scanner.go index e4e86b6..5bc413d 100644 --- a/compiler/scanner/scanner.go +++ b/compiler/scanner/scanner.go @@ -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 } } diff --git a/objects/object_test.go b/objects/object_test.go new file mode 100644 index 0000000..c1eea8e --- /dev/null +++ b/objects/object_test.go @@ -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()) +} diff --git a/script/script_test.go b/script/script_test.go index 54bf936..be3ebac 100644 --- a/script/script_test.go +++ b/script/script_test.go @@ -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)) +} diff --git a/script/variable.go b/script/variable.go index 4229af3..41ded73 100644 --- a/script/variable.go +++ b/script/variable.go @@ -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 diff --git a/script/variable_test.go b/script/variable_test.go new file mode 100644 index 0000000..83a6908 --- /dev/null +++ b/script/variable_test.go @@ -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()) + } + +}