q/src/build/compiler.go

82 lines
2.0 KiB
Go

package build
import (
"fmt"
"git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/ast"
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/go/color/ansi"
)
// compiler is the data structure we embed in each function to preserve compilation state.
type compiler struct {
err error
definitions map[string]*Definition
variables map[string]*Variable
functions map[string]*Function
finished chan struct{}
assembler asm.Assembler
debug []debug
cpu cpu.CPU
count counter
sideEffects int
}
// counter stores how often a certain statement appeared so we can generate a unique label from it.
type counter struct {
loop int
}
// debug is used to look up the source code at the given position.
type debug struct {
source ast.Node
position int
}
// PrintInstructions shows the assembly instructions.
func (c *compiler) PrintInstructions() {
ansi.Dim.Println("╭──────────────────────────────────────╮")
for i, x := range c.assembler.Instructions {
instruction := c.sourceAt(i)
if instruction != nil {
ansi.Dim.Println("├──────────────────────────────────────┤")
}
ansi.Dim.Print("│ ")
if x.Mnemonic == asm.LABEL {
ansi.Yellow.Printf("%-36s", x.Data.String()+":")
} else {
ansi.Green.Printf("%-8s", x.Mnemonic.String())
if x.Data != nil {
fmt.Printf("%-28s", x.Data.String())
} else {
fmt.Printf("%-28s", "")
}
}
ansi.Dim.Print(" │\n")
}
ansi.Dim.Println("╰──────────────────────────────────────╯")
}
// sourceAt retrieves the source code at the given position or `nil`.
func (c *compiler) sourceAt(position int) ast.Node {
for _, record := range c.debug {
if record.position == position {
return record.source
}
if record.position > position {
return nil
}
}
return nil
}