82 lines
2.0 KiB
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
|
|
}
|