96 lines
1.8 KiB
Go
96 lines
1.8 KiB
Go
package build
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"git.akyoto.dev/cli/q/src/build/arch/x64"
|
|
"git.akyoto.dev/cli/q/src/build/asm"
|
|
"git.akyoto.dev/cli/q/src/build/config"
|
|
"git.akyoto.dev/cli/q/src/build/token"
|
|
"git.akyoto.dev/go/color/ansi"
|
|
)
|
|
|
|
// Function represents a function.
|
|
type Function struct {
|
|
Name string
|
|
Head token.List
|
|
Body token.List
|
|
Assembler asm.Assembler
|
|
}
|
|
|
|
// Compile turns a function into machine code.
|
|
func (f *Function) Compile() {
|
|
if config.Verbose {
|
|
ansi.Underline.Println(f.Name)
|
|
}
|
|
|
|
for _, line := range f.Lines() {
|
|
if config.Verbose {
|
|
fmt.Println("[line]", line)
|
|
}
|
|
|
|
if len(line) == 0 {
|
|
continue
|
|
}
|
|
|
|
if line[0].Kind == token.Identifier && line[0].Text() == "syscall" {
|
|
paramTokens := line[2 : len(line)-1]
|
|
start := 0
|
|
i := 0
|
|
var parameters []token.List
|
|
|
|
for i < len(paramTokens) {
|
|
if paramTokens[i].Kind == token.Separator {
|
|
parameters = append(parameters, paramTokens[start:i])
|
|
start = i + 1
|
|
}
|
|
|
|
i++
|
|
}
|
|
|
|
if i != start {
|
|
parameters = append(parameters, paramTokens[start:i])
|
|
}
|
|
|
|
for i, list := range parameters {
|
|
if list[0].Kind == token.Number {
|
|
numAsText := list[0].Text()
|
|
n, _ := strconv.Atoi(numAsText)
|
|
f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n))
|
|
}
|
|
}
|
|
|
|
f.Assembler.Syscall()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lines returns the lines in the function body.
|
|
func (f *Function) Lines() []token.List {
|
|
var (
|
|
lines []token.List
|
|
start = 0
|
|
i = 0
|
|
)
|
|
|
|
for i < len(f.Body) {
|
|
if f.Body[i].Kind == token.NewLine {
|
|
lines = append(lines, f.Body[start:i])
|
|
start = i + 1
|
|
}
|
|
|
|
i++
|
|
}
|
|
|
|
if i != start {
|
|
lines = append(lines, f.Body[start:i])
|
|
}
|
|
|
|
return lines
|
|
}
|
|
|
|
// String returns the function name.
|
|
func (f *Function) String() string {
|
|
return f.Name
|
|
}
|