115 lines
2.4 KiB
Go
Raw Normal View History

2024-07-03 11:39:24 +02:00
package core
2024-06-10 15:51:39 +02:00
import (
2024-06-30 00:17:14 +02:00
"fmt"
2024-07-03 11:39:24 +02:00
"git.akyoto.dev/cli/q/src/build/arch/x64"
"git.akyoto.dev/cli/q/src/build/asm"
2024-06-30 22:54:59 +02:00
"git.akyoto.dev/cli/q/src/build/ast"
2024-07-03 11:39:24 +02:00
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/errors"
2024-06-15 18:42:31 +02:00
"git.akyoto.dev/cli/q/src/build/fs"
2024-06-10 15:51:39 +02:00
"git.akyoto.dev/cli/q/src/build/token"
)
2024-07-03 11:39:24 +02:00
// Function represents the smallest unit of code.
2024-06-10 15:51:39 +02:00
type Function struct {
2024-06-30 22:54:59 +02:00
Name string
2024-07-03 11:39:24 +02:00
File *fs.File
2024-06-29 11:49:32 +02:00
Body token.List
2024-07-03 11:39:24 +02:00
state
}
// NewFunction creates a new function.
func NewFunction(name string, file *fs.File, body token.List) *Function {
return &Function{
Name: name,
File: file,
Body: body,
state: state{
assembler: asm.Assembler{
Instructions: make([]asm.Instruction, 0, 32),
},
cpu: cpu.CPU{
2024-07-03 16:37:59 +02:00
Input: x64.CallRegisters,
2024-07-03 11:39:24 +02:00
General: x64.GeneralRegisters,
Syscall: x64.SyscallRegisters,
2024-07-03 16:37:59 +02:00
Output: x64.ReturnValueRegisters,
2024-07-03 11:39:24 +02:00
},
2024-07-06 15:20:52 +02:00
variables: map[string]*Variable{},
finished: make(chan struct{}),
2024-07-03 11:39:24 +02:00
},
}
2024-06-10 15:51:39 +02:00
}
// Compile turns a function into machine code.
func (f *Function) Compile() {
defer close(f.finished)
2024-06-29 11:49:32 +02:00
f.assembler.Label(f.Name)
f.err = f.CompileTokens(f.Body)
f.assembler.Return()
2024-06-24 00:03:26 +02:00
}
// CompileTokens compiles a token list.
2024-06-30 22:54:59 +02:00
func (f *Function) CompileTokens(tokens token.List) error {
tree, err := ast.Parse(tokens)
2024-06-30 22:54:59 +02:00
if err != nil {
err.(*errors.Error).File = f.File
2024-06-30 22:54:59 +02:00
return err
}
2024-06-15 14:46:44 +02:00
2024-06-30 22:54:59 +02:00
return f.CompileAST(tree)
}
2024-06-27 17:13:48 +02:00
2024-06-30 22:54:59 +02:00
// CompileAST compiles an abstract syntax tree.
func (f *Function) CompileAST(tree ast.AST) error {
for _, node := range tree {
2024-07-03 11:39:24 +02:00
err := f.CompileASTNode(node)
2024-06-15 14:46:44 +02:00
2024-06-30 22:54:59 +02:00
if err != nil {
return err
}
}
2024-06-15 14:46:44 +02:00
2024-06-30 22:54:59 +02:00
return nil
}
2024-06-15 14:46:44 +02:00
2024-07-03 11:39:24 +02:00
// CompileASTNode compiles a node in the AST.
func (f *Function) CompileASTNode(node ast.Node) error {
2024-06-30 22:54:59 +02:00
switch node := node.(type) {
2024-07-03 11:39:24 +02:00
case *ast.Assign:
return f.CompileAssign(node)
2024-06-30 22:54:59 +02:00
case *ast.Call:
2024-07-03 11:39:24 +02:00
return f.CompileCall(node.Expression)
2024-06-10 15:51:39 +02:00
2024-06-30 22:54:59 +02:00
case *ast.Define:
2024-07-03 11:39:24 +02:00
return f.CompileDefinition(node)
2024-06-24 00:03:26 +02:00
2024-06-30 22:54:59 +02:00
case *ast.Return:
return f.CompileReturn(node)
2024-06-24 00:03:26 +02:00
2024-06-30 22:54:59 +02:00
case *ast.Loop:
return f.CompileLoop(node)
2024-06-10 15:51:39 +02:00
2024-06-30 22:54:59 +02:00
default:
panic("Unknown AST type")
}
2024-06-15 18:42:31 +02:00
}
2024-06-15 14:46:44 +02:00
2024-06-30 00:17:14 +02:00
// Logf formats a message for verbose output.
func (f *Function) Logf(format string, data ...any) {
fmt.Printf("[%s @ %d] %s\n", f, len(f.assembler.Instructions), fmt.Sprintf(format, data...))
}
2024-06-10 15:51:39 +02:00
// String returns the function name.
func (f *Function) String() string {
return f.Name
}
2024-06-21 12:48:01 +02:00
// Wait will block until the compilation finishes.
func (f *Function) Wait() {
<-f.finished
}