aboutsummaryrefslogtreecommitdiff
path: root/pkg/lang/vm/text
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang/vm/text')
-rw-r--r--pkg/lang/vm/text/compiler.go55
-rw-r--r--pkg/lang/vm/text/compiler_test.go152
2 files changed, 101 insertions, 106 deletions
diff --git a/pkg/lang/vm/text/compiler.go b/pkg/lang/vm/text/compiler.go
index 1480171..68889eb 100644
--- a/pkg/lang/vm/text/compiler.go
+++ b/pkg/lang/vm/text/compiler.go
@@ -1,11 +1,9 @@
package text
import (
- "encoding/binary"
"io"
"jinx/pkg/lang/vm/code"
"jinx/pkg/libs/source"
- "math"
"strconv"
"strings"
"unicode"
@@ -30,8 +28,7 @@ func NewCompiler(src io.Reader) *Compiler {
}
func (cpl *Compiler) Compile() (code.Code, error) {
- res := []byte{}
- info := code.NewDebugInfo("unknown file")
+ builder := code.NewBuilder()
for {
_, eof, err := cpl.src.Peek()
@@ -50,22 +47,22 @@ func (cpl *Compiler) Compile() (code.Code, error) {
cpl.codePos += len(line)
- if line != nil {
- info.AppendLine(cpl.codePos-1, cpl.src.Loc().Row-1)
- }
+ builder.AppendRaw(line)
- res = append(res, line...)
+ if len(line) > 0 {
+ builder.AppendLine(cpl.src.Loc().Row - 1)
+ }
}
- if err := cpl.linkLabels(res); err != nil {
+ if err := cpl.linkLabels(&builder); err != nil {
return code.Code{}, err
}
- return code.New(res, info), nil
+ return builder.Build(), nil
}
-func (cpl *Compiler) compileLine() ([]byte, error) {
- res := []byte{}
+func (cpl *Compiler) compileLine() (code.Raw, error) {
+ builder := code.NewBuilder()
start, value, err := cpl.splitLine()
if err != nil || start == "" {
@@ -93,7 +90,7 @@ func (cpl *Compiler) compileLine() ([]byte, error) {
return nil, err
}
- res = append(res, byte(op))
+ builder.AppendOp(op)
// Find the value, of which there is at most one.
if value != "" {
@@ -102,10 +99,10 @@ func (cpl *Compiler) compileLine() ([]byte, error) {
return nil, err
}
- res = append(res, val...)
+ builder.AppendRaw(val)
}
- return res, nil
+ return builder.Code(), nil
}
func (cpl *Compiler) compileOp(str string) (code.Op, error) {
@@ -117,8 +114,8 @@ func (cpl *Compiler) compileOp(str string) (code.Op, error) {
return op, nil
}
-func (cpl *Compiler) compileValue(str string) ([]byte, error) {
- res := make([]byte, 8)
+func (cpl *Compiler) compileValue(str string) (code.Raw, error) {
+ builder := code.NewBuilder()
// Save label reference.
if str[0] == '@' {
@@ -127,38 +124,38 @@ func (cpl *Compiler) compileValue(str string) ([]byte, error) {
label: label,
at: cpl.codePos + 1, // +1 to skip the opcode.
})
- return res, nil
+ builder.AppendInt(0)
+ return builder.Code(), nil
}
if unicode.IsDigit(rune(str[0])) || str[0] == '-' {
if strings.Contains(str, ".") {
val, err := strconv.ParseFloat(str, 64)
if err != nil {
- return res, err
+ return nil, err
}
- binary.LittleEndian.PutUint64(res, math.Float64bits(val))
+ builder.AppendFloat(val)
} else {
val, err := strconv.ParseInt(str, 10, 64)
if err != nil {
- return res, err
+ return nil, err
}
- binary.LittleEndian.PutUint64(res, uint64(val))
+ builder.AppendInt(val)
}
- return res, nil
+ return builder.Code(), nil
}
if str[0] == '"' {
str = strings.Trim(str, "\"")
- res = []byte(str)
- res = append(res, 0)
+ builder.AppendString(str)
- return res, nil
+ return builder.Code(), nil
}
- return res, ErrInvalidValue{str}
+ return nil, ErrInvalidValue{str}
}
func (cpl *Compiler) splitLine() (string, string, error) {
@@ -195,14 +192,14 @@ type labelReference struct {
at int
}
-func (cpl *Compiler) linkLabels(code []byte) error {
+func (cpl *Compiler) linkLabels(builder *code.Builder) error {
for _, ref := range cpl.labelReferences {
pos, ok := cpl.labelPositions[ref.label]
if !ok {
return ErrUnkonwnLabel{ref.label}
}
- binary.LittleEndian.PutUint64(code[ref.at:], uint64(pos))
+ builder.SetInt(ref.at, int64(pos))
}
return nil
}
diff --git a/pkg/lang/vm/text/compiler_test.go b/pkg/lang/vm/text/compiler_test.go
index 56b886d..c9e3fa1 100644
--- a/pkg/lang/vm/text/compiler_test.go
+++ b/pkg/lang/vm/text/compiler_test.go
@@ -1,10 +1,8 @@
package text_test
import (
- "encoding/binary"
"jinx/pkg/lang/vm/code"
"jinx/pkg/lang/vm/text"
- "math"
"strings"
"testing"
@@ -22,13 +20,13 @@ func TestSimple(t *testing.T) {
res, err := c.Compile()
require.NoError(t, err)
- parts := [][]byte{
- opBin(code.OpAdd),
- opBin(code.OpSub),
- opBin(code.OpRet),
- }
+ exp := code.NewBuilder()
- require.Equal(t, joinSlices(parts), res.Code())
+ exp.AppendOp(code.OpAdd)
+ exp.AppendOp(code.OpSub)
+ exp.AppendOp(code.OpRet)
+
+ require.Equal(t, exp.Code(), res.Code())
}
func TestInt(t *testing.T) {
@@ -43,16 +41,16 @@ func TestInt(t *testing.T) {
res, err := c.Compile()
require.NoError(t, err)
- parts := [][]byte{
- opBin(code.OpPushInt),
- uintBin(1),
- opBin(code.OpPushInt),
- uintBin(2),
- opBin(code.OpAdd),
- opBin(code.OpRet),
- }
+ exp := code.NewBuilder()
+
+ exp.AppendOp(code.OpPushInt)
+ exp.AppendInt(1)
+ exp.AppendOp(code.OpPushInt)
+ exp.AppendInt(2)
+ exp.AppendOp(code.OpAdd)
+ exp.AppendOp(code.OpRet)
- require.Equal(t, joinSlices(parts), res.Code())
+ require.Equal(t, exp.Code(), res.Code())
}
func TestFloat(t *testing.T) {
@@ -65,14 +63,14 @@ func TestFloat(t *testing.T) {
res, err := c.Compile()
require.NoError(t, err)
- parts := [][]byte{
- opBin(code.OpPushFloat),
- floatBin(3.1415),
- opBin(code.OpPushFloat),
- floatBin(-2.71828),
- }
+ exp := code.NewBuilder()
+
+ exp.AppendOp(code.OpPushFloat)
+ exp.AppendFloat(3.1415)
+ exp.AppendOp(code.OpPushFloat)
+ exp.AppendFloat(-2.71828)
- require.Equal(t, joinSlices(parts), res.Code())
+ require.Equal(t, exp.Code(), res.Code())
}
func TestString(t *testing.T) {
@@ -86,15 +84,15 @@ func TestString(t *testing.T) {
res, err := c.Compile()
require.NoError(t, err)
- parts := [][]byte{
- opBin(code.OpPushString),
- stringBin("Hello, "),
- opBin(code.OpPushString),
- stringBin("world!"),
- opBin(code.OpAdd),
- }
+ exp := code.NewBuilder()
- require.Equal(t, joinSlices(parts), res.Code())
+ exp.AppendOp(code.OpPushString)
+ exp.AppendString("Hello, ")
+ exp.AppendOp(code.OpPushString)
+ exp.AppendString("world!")
+ exp.AppendOp(code.OpAdd)
+
+ require.Equal(t, exp.Code(), res.Code())
}
func TestLabels(t *testing.T) {
@@ -114,19 +112,19 @@ func TestLabels(t *testing.T) {
res, err := c.Compile()
require.NoError(t, err)
- parts := [][]byte{
- opBin(code.OpNop),
- opBin(code.OpNop),
- opBin(code.OpNop),
- opBin(code.OpJmp),
- uintBin(0),
- opBin(code.OpJmp),
- uintBin(1),
- opBin(code.OpJmp),
- uintBin(2),
- }
+ exp := code.NewBuilder()
+
+ exp.AppendOp(code.OpNop)
+ exp.AppendOp(code.OpNop)
+ exp.AppendOp(code.OpNop)
+ exp.AppendOp(code.OpJmp)
+ exp.AppendInt(0)
+ exp.AppendOp(code.OpJmp)
+ exp.AppendInt(1)
+ exp.AppendOp(code.OpJmp)
+ exp.AppendInt(2)
- require.Equal(t, joinSlices(parts), res.Code())
+ require.Equal(t, exp.Code(), res.Code())
}
func TestDebugInfo(t *testing.T) {
@@ -146,46 +144,46 @@ func TestDebugInfo(t *testing.T) {
res, err := c.Compile()
require.NoError(t, err)
- expected := code.NewDebugInfo("unknown file")
+ exp := code.NewDebugInfo("unknown file")
- expected.AppendLine(8, 1)
- expected.AppendLine(17, 2)
- expected.AppendLine(18, 4)
- expected.AppendLine(19, 5)
- expected.AppendLine(20, 8)
- expected.AppendLine(21, 9)
+ exp.AppendLine(8, 1)
+ exp.AppendLine(17, 2)
+ exp.AppendLine(18, 4)
+ exp.AppendLine(19, 5)
+ exp.AppendLine(20, 8)
+ exp.AppendLine(21, 9)
- require.Equal(t, expected, *res.Debug())
+ require.Equal(t, exp, *res.Debug())
}
-func opBin(op code.Op) []byte {
- return []byte{byte(op)}
-}
+// func opBin(op code.Op) []byte {
+// return []byte{byte(op)}
+// }
-func uintBin(x uint64) []byte {
- res := make([]byte, 8)
- binary.LittleEndian.PutUint64(res, x)
- return res
-}
+// func uintBin(x uint64) []byte {
+// res := make([]byte, 8)
+// binary.LittleEndian.PutUint64(res, x)
+// return res
+// }
-func floatBin(x float64) []byte {
- res := make([]byte, 8)
- binary.LittleEndian.PutUint64(res, math.Float64bits(x))
- return res
-}
+// func floatBin(x float64) []byte {
+// res := make([]byte, 8)
+// binary.LittleEndian.PutUint64(res, math.Float64bits(x))
+// return res
+// }
-func stringBin(x string) []byte {
- res := []byte(x)
- res = append(res, 0)
- return res
-}
+// func stringBin(x string) []byte {
+// res := []byte(x)
+// res = append(res, 0)
+// return res
+// }
-func joinSlices[T any](slices [][]T) []T {
- res := []T{}
+// func joinSlices[T any](slices [][]T) []T {
+// res := []T{}
- for _, slice := range slices {
- res = append(res, slice...)
- }
+// for _, slice := range slices {
+// res = append(res, slice...)
+// }
- return res
-}
+// return res
+// }