123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- package tengo_test
- import (
- "bytes"
- "testing"
- "time"
- "github.com/d5/tengo/v2"
- "github.com/d5/tengo/v2/parser"
- "github.com/d5/tengo/v2/require"
- )
- type srcfile struct {
- name string
- size int
- }
- func TestBytecode(t *testing.T) {
- testBytecodeSerialization(t, bytecode(concatInsts(), objectsArray()))
- testBytecodeSerialization(t, bytecode(
- concatInsts(), objectsArray(
- &tengo.Char{Value: 'y'},
- &tengo.Float{Value: 93.11},
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetGlobal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0)),
- &tengo.Float{Value: 39.2},
- &tengo.Int{Value: 192},
- &tengo.String{Value: "bar"})))
- testBytecodeSerialization(t, bytecodeFileSet(
- concatInsts(
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpSetGlobal, 0),
- tengo.MakeInstruction(parser.OpConstant, 6),
- tengo.MakeInstruction(parser.OpPop)),
- objectsArray(
- &tengo.Int{Value: 55},
- &tengo.Int{Value: 66},
- &tengo.Int{Value: 77},
- &tengo.Int{Value: 88},
- &tengo.ImmutableMap{
- Value: map[string]tengo.Object{
- "array": &tengo.ImmutableArray{
- Value: []tengo.Object{
- &tengo.Int{Value: 1},
- &tengo.Int{Value: 2},
- &tengo.Int{Value: 3},
- tengo.TrueValue,
- tengo.FalseValue,
- tengo.UndefinedValue,
- },
- },
- "true": tengo.TrueValue,
- "false": tengo.FalseValue,
- "bytes": &tengo.Bytes{Value: make([]byte, 16)},
- "char": &tengo.Char{Value: 'Y'},
- "error": &tengo.Error{Value: &tengo.String{
- Value: "some error",
- }},
- "float": &tengo.Float{Value: -19.84},
- "immutable_array": &tengo.ImmutableArray{
- Value: []tengo.Object{
- &tengo.Int{Value: 1},
- &tengo.Int{Value: 2},
- &tengo.Int{Value: 3},
- tengo.TrueValue,
- tengo.FalseValue,
- tengo.UndefinedValue,
- },
- },
- "immutable_map": &tengo.ImmutableMap{
- Value: map[string]tengo.Object{
- "a": &tengo.Int{Value: 1},
- "b": &tengo.Int{Value: 2},
- "c": &tengo.Int{Value: 3},
- "d": tengo.TrueValue,
- "e": tengo.FalseValue,
- "f": tengo.UndefinedValue,
- },
- },
- "int": &tengo.Int{Value: 91},
- "map": &tengo.Map{
- Value: map[string]tengo.Object{
- "a": &tengo.Int{Value: 1},
- "b": &tengo.Int{Value: 2},
- "c": &tengo.Int{Value: 3},
- "d": tengo.TrueValue,
- "e": tengo.FalseValue,
- "f": tengo.UndefinedValue,
- },
- },
- "string": &tengo.String{Value: "foo bar"},
- "time": &tengo.Time{Value: time.Now()},
- "undefined": tengo.UndefinedValue,
- },
- },
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetGlobal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0),
- tengo.MakeInstruction(parser.OpBinaryOp, 11),
- tengo.MakeInstruction(parser.OpGetFree, 1),
- tengo.MakeInstruction(parser.OpBinaryOp, 11),
- tengo.MakeInstruction(parser.OpGetLocal, 0),
- tengo.MakeInstruction(parser.OpBinaryOp, 11),
- tengo.MakeInstruction(parser.OpReturn, 1)),
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0),
- tengo.MakeInstruction(parser.OpGetLocal, 0),
- tengo.MakeInstruction(parser.OpClosure, 4, 2),
- tengo.MakeInstruction(parser.OpReturn, 1)),
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetLocal, 0),
- tengo.MakeInstruction(parser.OpClosure, 5, 1),
- tengo.MakeInstruction(parser.OpReturn, 1))),
- fileSet(srcfile{name: "file1", size: 100},
- srcfile{name: "file2", size: 200})))
- }
- func TestBytecode_RemoveDuplicates(t *testing.T) {
- testBytecodeRemoveDuplicates(t,
- bytecode(
- concatInsts(), objectsArray(
- &tengo.Char{Value: 'y'},
- &tengo.Float{Value: 93.11},
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetGlobal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0)),
- &tengo.Float{Value: 39.2},
- &tengo.Int{Value: 192},
- &tengo.String{Value: "bar"})),
- bytecode(
- concatInsts(), objectsArray(
- &tengo.Char{Value: 'y'},
- &tengo.Float{Value: 93.11},
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetGlobal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0)),
- &tengo.Float{Value: 39.2},
- &tengo.Int{Value: 192},
- &tengo.String{Value: "bar"})))
- testBytecodeRemoveDuplicates(t,
- bytecode(
- concatInsts(
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpConstant, 4),
- tengo.MakeInstruction(parser.OpConstant, 5),
- tengo.MakeInstruction(parser.OpConstant, 6),
- tengo.MakeInstruction(parser.OpConstant, 7),
- tengo.MakeInstruction(parser.OpConstant, 8),
- tengo.MakeInstruction(parser.OpClosure, 4, 1)),
- objectsArray(
- &tengo.Int{Value: 1},
- &tengo.Float{Value: 2.0},
- &tengo.Char{Value: '3'},
- &tengo.String{Value: "four"},
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpConstant, 7),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetGlobal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0)),
- &tengo.Int{Value: 1},
- &tengo.Float{Value: 2.0},
- &tengo.Char{Value: '3'},
- &tengo.String{Value: "four"})),
- bytecode(
- concatInsts(
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpConstant, 4),
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpClosure, 4, 1)),
- objectsArray(
- &tengo.Int{Value: 1},
- &tengo.Float{Value: 2.0},
- &tengo.Char{Value: '3'},
- &tengo.String{Value: "four"},
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpSetLocal, 0),
- tengo.MakeInstruction(parser.OpGetGlobal, 0),
- tengo.MakeInstruction(parser.OpGetFree, 0)))))
- testBytecodeRemoveDuplicates(t,
- bytecode(
- concatInsts(
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpConstant, 4)),
- objectsArray(
- &tengo.Int{Value: 1},
- &tengo.Int{Value: 2},
- &tengo.Int{Value: 3},
- &tengo.Int{Value: 1},
- &tengo.Int{Value: 3})),
- bytecode(
- concatInsts(
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpConstant, 0),
- tengo.MakeInstruction(parser.OpConstant, 2)),
- objectsArray(
- &tengo.Int{Value: 1},
- &tengo.Int{Value: 2},
- &tengo.Int{Value: 3})))
- }
- func TestBytecode_CountObjects(t *testing.T) {
- b := bytecode(
- concatInsts(),
- objectsArray(
- &tengo.Int{Value: 55},
- &tengo.Int{Value: 66},
- &tengo.Int{Value: 77},
- &tengo.Int{Value: 88},
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 3),
- tengo.MakeInstruction(parser.OpReturn, 1)),
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 2),
- tengo.MakeInstruction(parser.OpReturn, 1)),
- compiledFunction(1, 0,
- tengo.MakeInstruction(parser.OpConstant, 1),
- tengo.MakeInstruction(parser.OpReturn, 1))))
- require.Equal(t, 7, b.CountObjects())
- }
- func fileSet(files ...srcfile) *parser.SourceFileSet {
- fileSet := parser.NewFileSet()
- for _, f := range files {
- fileSet.AddFile(f.name, -1, f.size)
- }
- return fileSet
- }
- func bytecodeFileSet(
- instructions []byte,
- constants []tengo.Object,
- fileSet *parser.SourceFileSet,
- ) *tengo.Bytecode {
- return &tengo.Bytecode{
- FileSet: fileSet,
- MainFunction: &tengo.CompiledFunction{Instructions: instructions},
- Constants: constants,
- }
- }
- func testBytecodeRemoveDuplicates(
- t *testing.T,
- input, expected *tengo.Bytecode,
- ) {
- input.RemoveDuplicates()
- require.Equal(t, expected.FileSet, input.FileSet)
- require.Equal(t, expected.MainFunction, input.MainFunction)
- require.Equal(t, expected.Constants, input.Constants)
- }
- func testBytecodeSerialization(t *testing.T, b *tengo.Bytecode) {
- var buf bytes.Buffer
- err := b.Encode(&buf)
- require.NoError(t, err)
- r := &tengo.Bytecode{}
- err = r.Decode(bytes.NewReader(buf.Bytes()), nil)
- require.NoError(t, err)
- require.Equal(t, b.FileSet, r.FileSet)
- require.Equal(t, b.MainFunction, r.MainFunction)
- require.Equal(t, b.Constants, r.Constants)
- }
|