refactor how repl works
This commit is contained in:
147
internal/compiler/bytecode.go
Normal file
147
internal/compiler/bytecode.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"monkey/internal/code"
|
||||
"monkey/internal/object"
|
||||
)
|
||||
|
||||
type Bytecode struct {
|
||||
Instructions code.Instructions
|
||||
Constants []object.Object
|
||||
}
|
||||
|
||||
type encoder struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (e *encoder) Write(b []byte) (err error) {
|
||||
_, err = e.Buffer.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (e *encoder) WriteString(s string) (err error) {
|
||||
_, err = e.Buffer.WriteString(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (e *encoder) WriteValue(data any) error {
|
||||
return binary.Write(&e.Buffer, binary.BigEndian, data)
|
||||
}
|
||||
|
||||
func (e *encoder) WriteObjects(objs ...object.Object) (err error) {
|
||||
for _, obj := range objs {
|
||||
err = errors.Join(err, e.WriteValue(len(string(obj.Type()))))
|
||||
err = errors.Join(err, e.WriteString(string(obj.Type())))
|
||||
|
||||
switch o := obj.(type) {
|
||||
case *object.Null:
|
||||
break
|
||||
case *object.Boolean:
|
||||
err = errors.Join(err, e.WriteValue(o.Value))
|
||||
case *object.Integer:
|
||||
err = errors.Join(err, e.WriteValue(o.Value))
|
||||
case *object.String:
|
||||
err = errors.Join(err, e.WriteValue(len(o.Value)))
|
||||
err = errors.Join(err, e.WriteValue(o.Value))
|
||||
case *object.CompiledFunction:
|
||||
err = errors.Join(err, e.WriteValue(o.NumParameters))
|
||||
err = errors.Join(err, e.WriteValue(o.NumLocals))
|
||||
err = errors.Join(err, e.WriteValue(len(o.Instructions)))
|
||||
err = errors.Join(err, e.Write(o.Instructions))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b Bytecode) Encode() (data []byte, err error) {
|
||||
var e encoder
|
||||
|
||||
err = errors.Join(err, e.WriteValue(len(b.Instructions)))
|
||||
err = errors.Join(err, e.Write(b.Instructions))
|
||||
err = errors.Join(err, e.WriteValue(len(b.Constants)))
|
||||
err = errors.Join(err, e.WriteObjects(b.Constants...))
|
||||
return e.Bytes(), err
|
||||
}
|
||||
|
||||
type decoder struct {
|
||||
pos int
|
||||
b []byte
|
||||
}
|
||||
|
||||
func (d *decoder) Byte() (b byte) {
|
||||
b = d.b[d.pos]
|
||||
d.pos++
|
||||
return
|
||||
}
|
||||
|
||||
func (d *decoder) Int() (i int) {
|
||||
i = int(binary.BigEndian.Uint32(d.b[d.pos:]))
|
||||
d.pos += 4
|
||||
return
|
||||
}
|
||||
|
||||
func (d *decoder) Uint64() (i uint64) {
|
||||
i = binary.BigEndian.Uint64(d.b[d.pos:])
|
||||
d.pos += 8
|
||||
return
|
||||
}
|
||||
|
||||
func (d *decoder) Int64() (i int64) {
|
||||
return int64(d.Uint64())
|
||||
}
|
||||
|
||||
func (d *decoder) Float64() (f float64) {
|
||||
return math.Float64frombits(d.Uint64())
|
||||
}
|
||||
|
||||
func (d *decoder) Bytes(len int) (b []byte) {
|
||||
b = d.b[d.pos : d.pos+len]
|
||||
d.pos += len
|
||||
return
|
||||
}
|
||||
|
||||
func (d *decoder) String(len int) (s string) {
|
||||
s = string(d.b[d.pos : d.pos+len])
|
||||
d.pos += len
|
||||
return
|
||||
}
|
||||
|
||||
func (d *decoder) Objects(len int) (o []object.Object) {
|
||||
for i := 0; i < len; i++ {
|
||||
switch t := d.String(d.Int()); t {
|
||||
case object.NULL_OBJ:
|
||||
o = append(o, &object.Null{})
|
||||
case object.BOOLEAN_OBJ:
|
||||
o = append(o, &object.Boolean{Value: d.Byte() == 1})
|
||||
case object.INTEGER_OBJ:
|
||||
o = append(o, &object.Integer{Value: d.Int64()})
|
||||
case object.STRING_OBJ:
|
||||
o = append(o, &object.String{Value: d.String(d.Int())})
|
||||
case object.COMPILED_FUNCTION_OBJ:
|
||||
// The order of the fields has to reflect the data layout in the encoded bytecode.
|
||||
o = append(o, &object.CompiledFunction{
|
||||
NumParameters: d.Int(),
|
||||
NumLocals: d.Int(),
|
||||
Instructions: d.Bytes(d.Int()),
|
||||
})
|
||||
default:
|
||||
panic(fmt.Sprintf("decoder: unsupported decoding for type %s", t))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Decode(b []byte) *Bytecode {
|
||||
var d = decoder{b: b}
|
||||
|
||||
// The order of the fields has to reflect the data layout in the encoded bytecode.
|
||||
return &Bytecode{
|
||||
Instructions: d.Bytes(d.Int()),
|
||||
Constants: d.Objects(d.Int()),
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,11 @@ type CompilationScope struct {
|
||||
type Compiler struct {
|
||||
Debug bool
|
||||
|
||||
fn string
|
||||
input string
|
||||
|
||||
l int
|
||||
constants []object.Object
|
||||
constants *[]object.Object
|
||||
|
||||
symbolTable *SymbolTable
|
||||
|
||||
@@ -48,7 +51,7 @@ func New() *Compiler {
|
||||
}
|
||||
|
||||
return &Compiler{
|
||||
constants: []object.Object{},
|
||||
constants: &[]object.Object{},
|
||||
symbolTable: symbolTable,
|
||||
scopes: []CompilationScope{mainScope},
|
||||
scopeIndex: 0,
|
||||
@@ -59,7 +62,7 @@ func (c *Compiler) currentInstructions() code.Instructions {
|
||||
return c.scopes[c.scopeIndex].instructions
|
||||
}
|
||||
|
||||
func NewWithState(s *SymbolTable, constants []object.Object) *Compiler {
|
||||
func NewWithState(s *SymbolTable, constants *[]object.Object) *Compiler {
|
||||
compiler := New()
|
||||
compiler.symbolTable = s
|
||||
compiler.constants = constants
|
||||
@@ -442,7 +445,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
||||
}
|
||||
|
||||
freeSymbols := c.symbolTable.FreeSymbols
|
||||
numLocals := c.symbolTable.numDefinitions
|
||||
numLocals := c.symbolTable.NumDefinitions
|
||||
instructions := c.leaveScope()
|
||||
|
||||
for _, s := range freeSymbols {
|
||||
@@ -529,8 +532,8 @@ func (c *Compiler) Compile(node ast.Node) error {
|
||||
}
|
||||
|
||||
func (c *Compiler) addConstant(obj object.Object) int {
|
||||
c.constants = append(c.constants, obj)
|
||||
return len(c.constants) - 1
|
||||
*c.constants = append(*c.constants, obj)
|
||||
return len(*c.constants) - 1
|
||||
}
|
||||
|
||||
func (c *Compiler) emit(op code.Opcode, operands ...int) int {
|
||||
@@ -542,6 +545,11 @@ func (c *Compiler) emit(op code.Opcode, operands ...int) int {
|
||||
return pos
|
||||
}
|
||||
|
||||
func (c *Compiler) SetFileInfo(fn, input string) {
|
||||
c.fn = fn
|
||||
c.input = input
|
||||
}
|
||||
|
||||
func (c *Compiler) setLastInstruction(op code.Opcode, pos int) {
|
||||
previous := c.scopes[c.scopeIndex].lastInstruction
|
||||
last := EmittedInstruction{Opcode: op, Position: pos}
|
||||
@@ -553,7 +561,7 @@ func (c *Compiler) setLastInstruction(op code.Opcode, pos int) {
|
||||
func (c *Compiler) Bytecode() *Bytecode {
|
||||
return &Bytecode{
|
||||
Instructions: c.currentInstructions(),
|
||||
Constants: c.constants,
|
||||
Constants: *c.constants,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,11 +638,6 @@ func (c *Compiler) replaceLastPopWithReturn() {
|
||||
c.scopes[c.scopeIndex].lastInstruction.Opcode = code.OpReturn
|
||||
}
|
||||
|
||||
type Bytecode struct {
|
||||
Instructions code.Instructions
|
||||
Constants []object.Object
|
||||
}
|
||||
|
||||
func (c *Compiler) loadSymbol(s Symbol) {
|
||||
switch s.Scope {
|
||||
case GlobalScope:
|
||||
|
||||
@@ -1090,7 +1090,7 @@ func runCompilerTests2(t *testing.T, tests []compilerTestCase2) {
|
||||
|
||||
func parse(input string) *ast.Program {
|
||||
l := lexer.New(input)
|
||||
p := parser.New(l)
|
||||
p := parser.New("<text", l)
|
||||
return p.ParseProgram()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ type SymbolTable struct {
|
||||
Outer *SymbolTable
|
||||
|
||||
Store map[string]Symbol
|
||||
numDefinitions int
|
||||
NumDefinitions int
|
||||
|
||||
FreeSymbols []Symbol
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func NewSymbolTable() *SymbolTable {
|
||||
}
|
||||
|
||||
func (s *SymbolTable) Define(name string) Symbol {
|
||||
symbol := Symbol{Name: name, Index: s.numDefinitions}
|
||||
symbol := Symbol{Name: name, Index: s.NumDefinitions}
|
||||
if s.Outer == nil {
|
||||
symbol.Scope = GlobalScope
|
||||
} else {
|
||||
@@ -46,7 +46,7 @@ func (s *SymbolTable) Define(name string) Symbol {
|
||||
}
|
||||
|
||||
s.Store[name] = symbol
|
||||
s.numDefinitions++
|
||||
s.NumDefinitions++
|
||||
return symbol
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user