131 lines
2.4 KiB
Go
131 lines
2.4 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
|
|
Variables map[string]*Variable
|
|
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.Keyword {
|
|
switch line[0].Text() {
|
|
case "let":
|
|
name := line[1].Text()
|
|
value := line[3:]
|
|
fmt.Println("[variable]", name, value)
|
|
|
|
f.Variables[name] = &Variable{
|
|
Value: line[3:],
|
|
IsConst: true,
|
|
}
|
|
|
|
case "return":
|
|
f.Assembler.Return()
|
|
}
|
|
}
|
|
|
|
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 {
|
|
switch list[0].Kind {
|
|
case token.Identifier:
|
|
name := list[0].Text()
|
|
variable := f.Variables[name]
|
|
|
|
if !variable.IsConst {
|
|
panic("Not implemented yet")
|
|
}
|
|
|
|
n, _ := strconv.Atoi(variable.Value[0].Text())
|
|
f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n))
|
|
|
|
case token.Number:
|
|
value := list[0].Text()
|
|
n, _ := strconv.Atoi(value)
|
|
f.Assembler.MoveRegisterNumber(x64.SyscallArgs[i], uint64(n))
|
|
|
|
default:
|
|
panic("Unknown expression")
|
|
}
|
|
}
|
|
|
|
f.Assembler.Syscall()
|
|
}
|
|
}
|
|
|
|
f.Assembler.Return()
|
|
}
|
|
|
|
// 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
|
|
}
|