q/src/build/compiler.go

78 lines
1.9 KiB
Go

package build
import (
"fmt"
"git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/go/color/ansi"
)
// compiler is the data structure we embed in each function to preserve compilation state.
type compiler struct {
assembler asm.Assembler
count counter
cpu cpu.CPU
debug []debug
err error
variables map[string]*Variable
}
// 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 {
position int
source token.List
}
// 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) token.List {
for _, record := range c.debug {
if record.position == position {
return record.source
}
if record.position > position {
return nil
}
}
return nil
}