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 {
|
func errorTrace() []string {
|
||||||
pc := uintptr(0)
|
var pc uintptr
|
||||||
file := ""
|
file := ""
|
||||||
line := 0
|
line := 0
|
||||||
ok := false
|
var ok bool
|
||||||
name := ""
|
name := ""
|
||||||
|
|
||||||
var callers []string
|
var callers []string
|
||||||
|
|
|
@ -21,11 +21,7 @@ func (b *Bytecode) Decode(r io.Reader) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dec.Decode(&b.Constants); err != nil {
|
return dec.Decode(&b.Constants)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode writes Bytecode data to the writer.
|
// Encode writes Bytecode data to the writer.
|
||||||
|
@ -36,11 +32,7 @@ func (b *Bytecode) Encode(w io.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := enc.Encode(b.Constants); err != nil {
|
return enc.Encode(b.Constants)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -80,11 +80,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
||||||
}
|
}
|
||||||
case *ast.BinaryExpr:
|
case *ast.BinaryExpr:
|
||||||
if node.Token == token.LAnd || node.Token == token.LOr {
|
if node.Token == token.LAnd || node.Token == token.LOr {
|
||||||
if err := c.compileLogical(node); err != nil {
|
return c.compileLogical(node)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.Token == token.Less {
|
if node.Token == token.Less {
|
||||||
|
|
|
@ -813,6 +813,25 @@ func() {
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
|
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 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 {
|
func concat(insts ...[]byte) []byte {
|
||||||
|
|
|
@ -15,11 +15,6 @@ func (p *ErrorList) Add(pos source.FilePos, msg string) {
|
||||||
*p = append(*p, &Error{pos, msg})
|
*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.
|
// Len returns the number of elements in the collection.
|
||||||
func (p ErrorList) Len() int {
|
func (p ErrorList) Len() int {
|
||||||
return len(p)
|
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) {
|
func expectString(t *testing.T, input, expected string) (ok bool) {
|
||||||
testFileSet := source.NewFileSet()
|
|
||||||
testFile := testFileSet.AddFile("", -1, len(input))
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if !ok {
|
if !ok {
|
||||||
// print trace
|
// print trace
|
||||||
tr := &tracer{}
|
tr := &tracer{}
|
||||||
_, _ = parser.ParseFile(testFile, []byte(input), tr)
|
_, _ = parser.ParseSource([]byte(input), tr)
|
||||||
t.Logf("Trace:\n%s", strings.Join(tr.out, ""))
|
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) {
|
if !assert.NoError(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,8 +267,7 @@ func (s *Scanner) error(offset int, msg string) {
|
||||||
func (s *Scanner) scanComment() string {
|
func (s *Scanner) scanComment() string {
|
||||||
// initial '/' already consumed; s.ch == '/' || s.ch == '*'
|
// initial '/' already consumed; s.ch == '/' || s.ch == '*'
|
||||||
offs := s.offset - 1 // position of initial '/'
|
offs := s.offset - 1 // position of initial '/'
|
||||||
next := -1 // position immediately following the comment; < 0 means invalid comment
|
var numCR int
|
||||||
numCR := 0
|
|
||||||
|
|
||||||
if s.ch == '/' {
|
if s.ch == '/' {
|
||||||
//-style comment
|
//-style comment
|
||||||
|
@ -280,11 +279,6 @@ func (s *Scanner) scanComment() string {
|
||||||
}
|
}
|
||||||
s.next()
|
s.next()
|
||||||
}
|
}
|
||||||
// if we are at '\n', the position following the comment is afterwards
|
|
||||||
next = s.offset
|
|
||||||
if s.ch == '\n' {
|
|
||||||
next++
|
|
||||||
}
|
|
||||||
goto exit
|
goto exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +292,6 @@ func (s *Scanner) scanComment() string {
|
||||||
s.next()
|
s.next()
|
||||||
if ch == '*' && s.ch == '/' {
|
if ch == '*' && s.ch == '/' {
|
||||||
s.next()
|
s.next()
|
||||||
next = s.offset
|
|
||||||
goto exit
|
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
|
_, err = s.Compile() // should not compile because b is undefined
|
||||||
assert.Error(t, err)
|
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
|
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.
|
// Name returns the name of the variable.
|
||||||
func (v *Variable) Name() string {
|
func (v *Variable) Name() string {
|
||||||
return v.name
|
return v.name
|
||||||
|
@ -35,22 +47,22 @@ func (v *Variable) Int() int {
|
||||||
|
|
||||||
// Int64 returns int64 value of the variable value.
|
// Int64 returns int64 value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to int64.
|
// 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) {
|
switch val := (*v.value).(type) {
|
||||||
case *objects.Int:
|
case *objects.Int:
|
||||||
return int(val.Value)
|
return val.Value
|
||||||
case *objects.Float:
|
case *objects.Float:
|
||||||
return int(val.Value)
|
return int64(val.Value)
|
||||||
case *objects.Bool:
|
case *objects.Bool:
|
||||||
if val.Value {
|
if val.Value {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
case *objects.Char:
|
case *objects.Char:
|
||||||
return int(val.Value)
|
return int64(val.Value)
|
||||||
case *objects.String:
|
case *objects.String:
|
||||||
n, _ := strconv.ParseInt(val.Value, 10, 64)
|
n, _ := strconv.ParseInt(val.Value, 10, 64)
|
||||||
return int(n)
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
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