Implemented compilation finished events

This commit is contained in:
Eduard Urbach 2024-06-30 11:41:59 +02:00
parent 3fe2cd1da2
commit 247b82b529
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
8 changed files with 72 additions and 50 deletions

View File

@ -51,7 +51,13 @@ q build examples/hello
q build examples/hello --dry q build examples/hello --dry
``` ```
To produce verbose output, add the `-v` flag which shows the generated assembly instructions: Adding the `-a` or `--assembler` flag shows the generated assembly instructions:
```shell
q build examples/hello -a
```
Adding the `-v` or `--verbose` flag shows verbose compiler information:
```shell ```shell
q build examples/hello -v q build examples/hello -v

44
src/build/Call.go Normal file
View File

@ -0,0 +1,44 @@
package build
import (
"git.akyoto.dev/cli/q/src/build/config"
"git.akyoto.dev/cli/q/src/build/expression"
)
// CompileFunctionCall executes a function call.
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
funcName := expr.Children[0].Token.Text()
if funcName == "syscall" {
return f.CompileSyscall(expr)
}
function := f.functions[funcName]
if function != f {
function.Wait()
}
parameters := expr.Children[1:]
registers := f.cpu.Call[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers)
if config.Verbose {
f.Logf("call: %s", funcName)
}
f.assembler.Call(funcName)
f.sideEffects += function.sideEffects
return err
}
// CompileSyscall executes a syscall.
func (f *Function) CompileSyscall(expr *expression.Expression) error {
parameters := expr.Children[1:]
registers := f.cpu.Syscall[:len(parameters)]
err := f.ExpressionsToRegisters(parameters, registers)
f.assembler.Syscall()
f.sideEffects++
return err
}

View File

@ -166,6 +166,10 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp
// ExpressionsToRegisters moves multiple expressions into the specified registers. // ExpressionsToRegisters moves multiple expressions into the specified registers.
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error { func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
for _, register := range registers {
f.SaveRegister(register)
}
for i := len(expressions) - 1; i >= 0; i-- { for i := len(expressions) - 1; i >= 0; i-- {
expression := expressions[i] expression := expressions[i]
register := registers[i] register := registers[i]

View File

@ -20,6 +20,7 @@ type Function struct {
// Compile turns a function into machine code. // Compile turns a function into machine code.
func (f *Function) Compile() { func (f *Function) Compile() {
defer close(f.finished)
f.assembler.Label(f.Name) f.assembler.Label(f.Name)
f.err = f.CompileTokens(f.Body) f.err = f.CompileTokens(f.Body)
f.assembler.Return() f.assembler.Return()
@ -124,6 +125,11 @@ func (f *Function) String() string {
return f.Name return f.Name
} }
// Wait will block until the compilation finishes.
func (f *Function) Wait() {
<-f.finished
}
// identifierExists returns true if the identifier has been defined. // identifierExists returns true if the identifier has been defined.
func (f *Function) identifierExists(name string) bool { func (f *Function) identifierExists(name string) bool {
_, exists := f.variables[name] _, exists := f.variables[name]

View File

@ -1,43 +0,0 @@
package build
import (
"git.akyoto.dev/cli/q/src/build/config"
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/expression"
)
// CompileFunctionCall executes a function call.
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
var (
funcName = expr.Children[0].Token.Text()
parameters = expr.Children[1:]
isSyscall = funcName == "syscall"
registers []cpu.Register
)
if isSyscall {
registers = f.cpu.Syscall
} else {
registers = f.cpu.Call
}
registers = registers[:len(parameters)]
for _, register := range registers {
f.SaveRegister(register)
}
err := f.ExpressionsToRegisters(parameters, registers)
if config.Verbose {
f.Logf("call: %s", funcName)
}
if isSyscall {
f.assembler.Syscall()
} else {
f.assembler.Call(funcName)
}
return err
}

View File

@ -27,6 +27,7 @@ func compile(functions <-chan *Function, errs <-chan error) (Result, error) {
continue continue
} }
function.functions = allFunctions
allFunctions[function.Name] = function allFunctions[function.Name] = function
} }
} }

View File

@ -11,12 +11,15 @@ import (
// compiler is the data structure we embed in each function to preserve compilation state. // compiler is the data structure we embed in each function to preserve compilation state.
type compiler struct { type compiler struct {
assembler asm.Assembler assembler asm.Assembler
count counter count counter
cpu cpu.CPU cpu cpu.CPU
debug []debug debug []debug
err error err error
variables map[string]*Variable variables map[string]*Variable
functions map[string]*Function
sideEffects int
finished chan struct{}
} }
// counter stores how often a certain statement appeared so we can generate a unique label from it. // counter stores how often a certain statement appeared so we can generate a unique label from it.

View File

@ -251,6 +251,7 @@ func scanFile(path string, functions chan<- *Function) error {
Return: x64.ReturnValueRegisters, Return: x64.ReturnValueRegisters,
}, },
variables: map[string]*Variable{}, variables: map[string]*Variable{},
finished: make(chan struct{}),
}, },
} }