From 6f542bfc3fa986937f523e1bc82cef725550dc9a Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 27 Jan 2025 19:25:34 +0100 Subject: [PATCH] continue build --- build/build.go | 158 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 1 deletion(-) diff --git a/build/build.go b/build/build.go index 3aebb50..edcd345 100644 --- a/build/build.go +++ b/build/build.go @@ -4,10 +4,19 @@ package build import ( "errors" "fmt" + "io" "os" "os/exec" + "path/filepath" + "strings" "robaertschi.xyz/robaertschi/tt/asm" + "robaertschi.xyz/robaertschi/tt/asm/amd64" + "robaertschi.xyz/robaertschi/tt/lexer" + "robaertschi.xyz/robaertschi/tt/parser" + "robaertschi.xyz/robaertschi/tt/token" + "robaertschi.xyz/robaertschi/tt/ttir" + "robaertschi.xyz/robaertschi/tt/typechecker" "robaertschi.xyz/robaertschi/tt/utils" ) @@ -71,6 +80,21 @@ func (rft *removeFileTask) Run(id int, doneChan chan taskResult) { } } +type funcTask struct { + f func() error +} + +func NewFuncTask(f func() error) task { + return &funcTask{f: f} +} + +func (rft *funcTask) Run(id int, doneChan chan taskResult) { + doneChan <- taskResult{ + Id: id, + Err: rft.f(), + } +} + type taskResult struct { Id int Err error @@ -132,12 +156,144 @@ func runTasks(nodes map[int]*node, rootNodes []int) { break } } + if allDone { + node := nodes[*node.next] + go node.task.Run(*node.next, doneChan) + running = append(running, *node.next) + } } } } } -func (sp *SourceProgram) Build(backend asm.Backend) { +func build(input string, output string) error { + file, err := os.Open(input) + if err != nil { + return fmt.Errorf("could not open file %q because: %v", input, err) + } + defer file.Close() + inputText, err := io.ReadAll(file) + if err != nil { + return fmt.Errorf("Could not read file %q because: %v", input, err) + } + + l, err := lexer.New(string(inputText), input) + if err != nil { + return fmt.Errorf("error while creating lexer: %v", err) + } + + l.WithErrorCallback(func(l token.Loc, s string, a ...any) { + fmt.Printf("%s:%d:%d: %s\n", l.File, l.Line, l.Col, fmt.Sprintf(s, a...)) + }) + + p := parser.New(l) + p.WithErrorCallback(func(t token.Token, s string, a ...any) { + loc := t.Loc + fmt.Printf("%s:%d:%d: %s\n", loc.File, loc.Line, loc.Col, fmt.Sprintf(s, a...)) + }) + + program := p.ParseProgram() + if p.Errors() > 0 { + return fmt.Errorf("parser encountered 1 or more errors") + } + + tprogram, err := typechecker.New().CheckProgram(program) + if err != nil { + return err + } + + ir := ttir.EmitProgram(tprogram) + asm := amd64.CgProgram(ir) + + asmOutput := asm.Emit() + + asmOutputFile, err := os.Create(output) + if err != nil { + return fmt.Errorf("failed to create/truncate asm file %q because: %v\n", output, err) + } + + _, err = asmOutputFile.WriteString(asmOutput) + asmOutputFile.Close() + if err != nil { + return fmt.Errorf("failed to write to file %q because: %v\n", output, err) + } + + return nil +} + +func (sp *SourceProgram) Build(backend asm.Backend) error { + var gasPath string + fasmPath, err := exec.LookPath("fasm") + if err != nil { + fasmPath, err = exec.LookPath("fasm2") + if err != nil { + return fmt.Errorf("could not find fasm or fasm2, please install any those two using your systems package manager or from https://flatassembler.net") + } + } + if backend == asm.Qbe { + gasPath, err = exec.LookPath("as") + if err != nil { + return fmt.Errorf("could not find as assembler, pleas install it") + } + } + + nodes := make(map[int]*node) + rootNodes := []int{} + id := 0 + + addRootNode := func(task task) int { + node := &node{task: task} + nodes[id] = node + rootNodes = append(rootNodes, id) + id += 1 + return id - 1 + } + + addNode := func(task task, deps ...int) int { + node := &node{task: task} + nodes[id] = node + + for _, dep := range deps { + nodeDep := nodes[dep] + if nodeDep.next != nil { + panic(fmt.Sprintf("dep %d already has an next", dep)) + } + newId := id + nodeDep.next = &newId + node.previous = append(node.previous, dep) + } + + rootNodes = append(rootNodes, id) + id += 1 + return id - 1 + } + + var mainFile int + switch backend { + case asm.Fasm: + mainAsmOutput := strings.TrimSuffix(sp.InputFile, filepath.Ext(sp.InputFile)) + ".asm" + sp.InputAssemblies = append(sp.InputAssemblies, mainAsmOutput) + mainFile = addRootNode(NewFuncTask(func() error { + return build(sp.InputFile, mainAsmOutput) + })) + case asm.Qbe: + panic("qbe support not finished") + } + + asmFiles := []int{} + for _, file := range sp.InputAssemblies { + output := strings.TrimSuffix(file, filepath.Ext(file)) + ".o" + if filepath.Ext(file) == ".asm" { + asmFiles = append(asmFiles, addNode( + NewProcessTask(id, fasmPath, file, output), mainFile, + )) + } else { + asmFiles = append(asmFiles, addNode(NewProcessTask(id, gasPath, file, "-o", output))) + } + sp.ObjectFiles = append(sp.ObjectFiles, output) + } + + return runTasks(nodes, rootNodes) }