fix golint, ineffectassign issues and add some more tests
This commit is contained in:
parent
76a5c592aa
commit
e1e0e0cb24
13 changed files with 217 additions and 40 deletions
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
18
compiler/parser/error_list_test.go
Normal file
18
compiler/parser/error_list_test.go
Normal 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())
|
||||
}
|
14
compiler/parser/error_test.go
Normal file
14
compiler/parser/error_test.go
Normal 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())
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
60
objects/object_test.go
Normal 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())
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
71
script/variable_test.go
Normal 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())
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue