package core import ( "git.akyoto.dev/cli/q/src/build/arch/x64" "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/cli/q/src/build/errors" "git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/token" ) // Function represents the smallest unit of code. type Function struct { Name string File *fs.File Body token.List 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), Data: map[string][]byte{}, }, cpu: cpu.CPU{ All: x64.AllRegisters, Input: x64.CallRegisters, General: x64.GeneralRegisters, Syscall: x64.SyscallRegisters, Output: x64.ReturnValueRegisters, }, scopes: []Scope{{}}, finished: make(chan struct{}), }, } } // Compile turns a function into machine code. func (f *Function) Compile() { defer close(f.finished) f.AddLabel(f.Name) f.err = f.CompileTokens(f.Body) f.Return() } // CompileTokens compiles a token list. func (f *Function) CompileTokens(tokens token.List) error { tree, err := ast.Parse(tokens) if err != nil { err.(*errors.Error).File = f.File return err } return f.CompileAST(tree) } // CompileAST compiles an abstract syntax tree. func (f *Function) CompileAST(tree ast.AST) error { for _, node := range tree { err := f.CompileASTNode(node) if err != nil { return err } } return nil } // CompileASTNode compiles a node in the AST. func (f *Function) CompileASTNode(node ast.Node) error { switch node := node.(type) { case *ast.Assign: return f.CompileAssign(node) case *ast.Call: return f.CompileCall(node.Expression) case *ast.Define: return f.CompileDefinition(node) case *ast.Return: return f.CompileReturn(node) case *ast.If: return f.CompileIf(node) case *ast.Loop: return f.CompileLoop(node) default: panic("Unknown AST type") } } // String returns the function name. func (f *Function) String() string { return f.Name } // Wait will block until the compilation finishes. func (f *Function) Wait() { <-f.finished }