mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-18 23:13:29 +00:00
build system mostly working
This commit is contained in:
parent
6f542bfc3f
commit
b175ee2bee
294
build/build.go
294
build/build.go
@ -2,22 +2,22 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"robaertschi.xyz/robaertschi/tt/asm"
|
"robaertschi.xyz/robaertschi/tt/asm"
|
||||||
"robaertschi.xyz/robaertschi/tt/asm/amd64"
|
)
|
||||||
"robaertschi.xyz/robaertschi/tt/lexer"
|
|
||||||
"robaertschi.xyz/robaertschi/tt/parser"
|
type ToPrintFlags int
|
||||||
"robaertschi.xyz/robaertschi/tt/token"
|
|
||||||
"robaertschi.xyz/robaertschi/tt/ttir"
|
const (
|
||||||
"robaertschi.xyz/robaertschi/tt/typechecker"
|
PrintAst ToPrintFlags = 1 << iota
|
||||||
"robaertschi.xyz/robaertschi/tt/utils"
|
PrintTAst
|
||||||
|
PrintIr
|
||||||
)
|
)
|
||||||
|
|
||||||
type SourceProgram struct {
|
type SourceProgram struct {
|
||||||
@ -29,221 +29,23 @@ type SourceProgram struct {
|
|||||||
InputAssemblies []string
|
InputAssemblies []string
|
||||||
// Additional object files, will also include the generated object files
|
// Additional object files, will also include the generated object files
|
||||||
ObjectFiles []string
|
ObjectFiles []string
|
||||||
// The linkded executable
|
// The linked executable
|
||||||
OutputFile string
|
OutputFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
type task interface {
|
func NewSourceProgram(inputFile string, outputFile string) *SourceProgram {
|
||||||
Run(id int, doneChan chan taskResult)
|
return &SourceProgram{InputFile: inputFile, OutputFile: outputFile}
|
||||||
}
|
}
|
||||||
|
|
||||||
type processTask struct {
|
func (sp *SourceProgram) Build(backend asm.Backend, emitAsmOnly bool, toPrint ToPrintFlags) error {
|
||||||
name string
|
l := log.New(os.Stderr, "[build] ", log.Lshortfile)
|
||||||
args []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProcessTask(id int, name string, args ...string) task {
|
|
||||||
return &processTask{
|
|
||||||
name: name,
|
|
||||||
args: args,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pt *processTask) Run(id int, doneChan chan taskResult) {
|
|
||||||
cmd := exec.Command(pt.name, pt.args...)
|
|
||||||
cmd.Stdout = utils.NewPrefixWriterString(os.Stdout, pt.name+" output: ")
|
|
||||||
cmd.Stderr = cmd.Stdout
|
|
||||||
|
|
||||||
err := cmd.Run()
|
|
||||||
var exitError error
|
|
||||||
if cmd.ProcessState.ExitCode() != 0 {
|
|
||||||
exitError = fmt.Errorf("command %q failed with exit code %d", pt.name, cmd.ProcessState.ExitCode())
|
|
||||||
}
|
|
||||||
doneChan <- taskResult{
|
|
||||||
Id: id,
|
|
||||||
Err: errors.Join(err, exitError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type removeFileTask struct {
|
|
||||||
file string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRemoveFileTask(file string) task {
|
|
||||||
return &removeFileTask{file: file}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rft *removeFileTask) Run(id int, doneChan chan taskResult) {
|
|
||||||
doneChan <- taskResult{
|
|
||||||
Id: id,
|
|
||||||
Err: os.Remove(rft.file),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type node struct {
|
|
||||||
next *int
|
|
||||||
previous []int
|
|
||||||
task task
|
|
||||||
}
|
|
||||||
|
|
||||||
func runTasks(nodes map[int]*node, rootNodes []int) {
|
|
||||||
done := make(map[int]bool)
|
|
||||||
running := []int{}
|
|
||||||
doneChan := make(chan taskResult)
|
|
||||||
|
|
||||||
for id, node := range nodes {
|
|
||||||
// Initalize map
|
|
||||||
done[id] = false
|
|
||||||
|
|
||||||
// because we are already going trough the whole map, we might as well
|
|
||||||
// check the relations
|
|
||||||
if node.next != nil {
|
|
||||||
if _, ok := nodes[*node.next]; !ok {
|
|
||||||
panic(fmt.Sprintf("task with id %d has a invalid next node", id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, prev := range node.previous {
|
|
||||||
if _, ok := nodes[prev]; !ok {
|
|
||||||
panic(fmt.Sprintf("task with id %d has a invalid prev node", id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rootNode := range rootNodes {
|
|
||||||
node := nodes[rootNode]
|
|
||||||
go node.task.Run(rootNode, doneChan)
|
|
||||||
running = append(running, rootNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case result := <-doneChan:
|
|
||||||
done[result.Id] = true
|
|
||||||
for i, id := range running {
|
|
||||||
if id == result.Id {
|
|
||||||
running = make([]int, len(running)-1)
|
|
||||||
running = append(running[:i], running[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node := nodes[result.Id]
|
|
||||||
if node.next != nil {
|
|
||||||
allDone := true
|
|
||||||
for _, prev := range node.previous {
|
|
||||||
if !done[prev] {
|
|
||||||
allDone = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if allDone {
|
|
||||||
node := nodes[*node.next]
|
|
||||||
go node.task.Run(*node.next, doneChan)
|
|
||||||
running = append(running, *node.next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
nodes := make(map[int]*node)
|
||||||
rootNodes := []int{}
|
rootNodes := []int{}
|
||||||
id := 0
|
id := 0
|
||||||
|
|
||||||
addRootNode := func(task task) int {
|
addRootNode := func(task task) int {
|
||||||
|
l.Printf("registering root task %d", id)
|
||||||
node := &node{task: task}
|
node := &node{task: task}
|
||||||
nodes[id] = node
|
nodes[id] = node
|
||||||
rootNodes = append(rootNodes, id)
|
rootNodes = append(rootNodes, id)
|
||||||
@ -252,48 +54,54 @@ func (sp *SourceProgram) Build(backend asm.Backend) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addNode := func(task task, deps ...int) int {
|
addNode := func(task task, deps ...int) int {
|
||||||
|
l.Printf("registering task %d", id)
|
||||||
|
if len(deps) <= 0 {
|
||||||
|
panic("node without dep is useless")
|
||||||
|
}
|
||||||
|
|
||||||
node := &node{task: task}
|
node := &node{task: task}
|
||||||
nodes[id] = node
|
nodes[id] = node
|
||||||
|
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
nodeDep := nodes[dep]
|
nodeDep := nodes[dep]
|
||||||
if nodeDep.next != nil {
|
nodeDep.next = append(nodeDep.next, id)
|
||||||
panic(fmt.Sprintf("dep %d already has an next", dep))
|
|
||||||
}
|
|
||||||
newId := id
|
|
||||||
nodeDep.next = &newId
|
|
||||||
node.previous = append(node.previous, dep)
|
node.previous = append(node.previous, dep)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootNodes = append(rootNodes, id)
|
|
||||||
id += 1
|
id += 1
|
||||||
return id - 1
|
return id - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var mainFile int
|
err := sp.buildFasm(addRootNode, addNode, emitAsmOnly, toPrint)
|
||||||
switch backend {
|
if err != nil {
|
||||||
case asm.Fasm:
|
return err
|
||||||
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{}
|
return runTasks(nodes, rootNodes, l)
|
||||||
for _, file := range sp.InputAssemblies {
|
}
|
||||||
output := strings.TrimSuffix(file, filepath.Ext(file)) + ".o"
|
|
||||||
if filepath.Ext(file) == ".asm" {
|
func (sp *SourceProgram) buildFasm(addRootNode func(task) int, addNode func(task, ...int) int, emitAsmOnly bool, toPrint ToPrintFlags) error {
|
||||||
asmFiles = append(asmFiles, addNode(
|
fasmPath, err := exec.LookPath("fasm")
|
||||||
NewProcessTask(id, fasmPath, file, output), mainFile,
|
if err != nil {
|
||||||
))
|
fasmPath, err = exec.LookPath("fasm2")
|
||||||
} else {
|
if err != nil {
|
||||||
asmFiles = append(asmFiles, addNode(NewProcessTask(id, gasPath, file, "-o", output)))
|
return fmt.Errorf("could not find fasm or fasm2, please install any those two using your systems package manager or from https://flatassembler.net")
|
||||||
}
|
}
|
||||||
sp.ObjectFiles = append(sp.ObjectFiles, output)
|
}
|
||||||
}
|
|
||||||
|
mainAsmOutput := strings.TrimSuffix(sp.InputFile, filepath.Ext(sp.InputFile)) + ".asm"
|
||||||
return runTasks(nodes, rootNodes)
|
|
||||||
|
asmFile := addRootNode(NewFuncTask(func() error {
|
||||||
|
return build(sp.InputFile, mainAsmOutput, toPrint)
|
||||||
|
}))
|
||||||
|
|
||||||
|
if !emitAsmOnly {
|
||||||
|
fasmTask := addNode(NewProcessTask(fasmPath, mainAsmOutput, sp.OutputFile), asmFile)
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
|
||||||
|
addNode(NewRemoveFileTask(mainAsmOutput), fasmTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
257
build/task.go
Normal file
257
build/task.go
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type task interface {
|
||||||
|
Run(id int, doneChan chan taskResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
type processTask struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProcessTask(name string, args ...string) task {
|
||||||
|
return &processTask{
|
||||||
|
name: name,
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *processTask) Run(id int, doneChan chan taskResult) {
|
||||||
|
cmd := exec.Command(pt.name, pt.args...)
|
||||||
|
cmd.Stdout = utils.NewPrefixWriterString(os.Stdout, pt.name+" output: ")
|
||||||
|
cmd.Stderr = cmd.Stdout
|
||||||
|
|
||||||
|
fmt.Printf("starting %q %v\n", pt.name, pt.args)
|
||||||
|
err := cmd.Run()
|
||||||
|
var exitError error
|
||||||
|
if cmd.ProcessState.ExitCode() != 0 {
|
||||||
|
exitError = fmt.Errorf("command %q failed with exit code %d", pt.name, cmd.ProcessState.ExitCode())
|
||||||
|
}
|
||||||
|
doneChan <- taskResult{
|
||||||
|
Id: id,
|
||||||
|
Err: errors.Join(err, exitError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type removeFileTask struct {
|
||||||
|
file string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRemoveFileTask(file string) task {
|
||||||
|
return &removeFileTask{file: file}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rft *removeFileTask) Run(id int, doneChan chan taskResult) {
|
||||||
|
err := os.Remove(rft.file)
|
||||||
|
doneChan <- taskResult{
|
||||||
|
Id: id,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func build(input string, output string, toPrint ToPrintFlags) 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")
|
||||||
|
}
|
||||||
|
if (toPrint & PrintAst) != 0 {
|
||||||
|
fmt.Printf("AST:\n%s\n%+#v\n", program.String(), program)
|
||||||
|
}
|
||||||
|
|
||||||
|
tprogram, err := typechecker.New().CheckProgram(program)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (toPrint & PrintTAst) != 0 {
|
||||||
|
fmt.Printf("TAST:\n%s\n%+#v\n", tprogram.String(), tprogram)
|
||||||
|
}
|
||||||
|
|
||||||
|
ir := ttir.EmitProgram(tprogram)
|
||||||
|
if (toPrint & PrintIr) != 0 {
|
||||||
|
fmt.Printf("TTIR:\n%s\n%+#v\n", ir.String(), ir)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type taskResult struct {
|
||||||
|
Id int
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
next []int
|
||||||
|
previous []int
|
||||||
|
task task
|
||||||
|
}
|
||||||
|
|
||||||
|
type executionState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
notStarted executionState = iota
|
||||||
|
executing
|
||||||
|
finished
|
||||||
|
failed
|
||||||
|
)
|
||||||
|
|
||||||
|
func runTasks(nodes map[int]*node, rootNodes []int, l *log.Logger) error {
|
||||||
|
|
||||||
|
done := make(map[int]executionState)
|
||||||
|
running := []int{}
|
||||||
|
doneChan := make(chan taskResult)
|
||||||
|
errs := []error{}
|
||||||
|
|
||||||
|
startTask := func(id int) {
|
||||||
|
if done[id] != notStarted {
|
||||||
|
panic(fmt.Sprintf("tried starting task %d twice", id))
|
||||||
|
}
|
||||||
|
// fmt.Printf("executing task %d\n", id)
|
||||||
|
node := nodes[id]
|
||||||
|
go node.task.Run(id, doneChan)
|
||||||
|
running = append(running, id)
|
||||||
|
done[id] = executing
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, node := range nodes {
|
||||||
|
// Initalize map
|
||||||
|
done[id] = notStarted
|
||||||
|
|
||||||
|
// because we are already going trough the whole map, we might as well
|
||||||
|
// check the relations
|
||||||
|
for _, next := range node.next {
|
||||||
|
if node.next != nil {
|
||||||
|
if _, ok := nodes[next]; !ok {
|
||||||
|
panic(fmt.Sprintf("task with id %d has a invalid next node", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, prev := range node.previous {
|
||||||
|
if _, ok := nodes[prev]; !ok {
|
||||||
|
panic(fmt.Sprintf("task with id %d has a invalid prev node", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("starting rootNodes %v\n", rootNodes)
|
||||||
|
for _, rootNode := range rootNodes {
|
||||||
|
startTask(rootNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
allFinished := false
|
||||||
|
|
||||||
|
for !allFinished {
|
||||||
|
select {
|
||||||
|
case result := <-doneChan:
|
||||||
|
// fmt.Printf("task %d is done with err: %v\n", result.Id, result.Err)
|
||||||
|
for i, id := range running {
|
||||||
|
if id == result.Id {
|
||||||
|
running = slices.Delete(running, i, i+1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Err != nil {
|
||||||
|
done[result.Id] = failed
|
||||||
|
errs = append(errs, result.Err)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
done[result.Id] = finished
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, next := range nodes[result.Id].next {
|
||||||
|
nextNode := nodes[next]
|
||||||
|
allDone := true
|
||||||
|
for _, prev := range nextNode.previous {
|
||||||
|
if done[prev] != finished {
|
||||||
|
allDone = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allDone {
|
||||||
|
startTask(next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if len(running) <= 0 {
|
||||||
|
allFinished = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
|
|
||||||
|
}
|
22
main.go
22
main.go
@ -3,11 +3,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"robaertschi.xyz/robaertschi/tt/cmd"
|
"robaertschi.xyz/robaertschi/tt/asm"
|
||||||
|
"robaertschi.xyz/robaertschi/tt/build"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -19,7 +21,7 @@ func main() {
|
|||||||
var output string
|
var output string
|
||||||
flag.StringVar(&output, "o", "", "Output a executable named `file`")
|
flag.StringVar(&output, "o", "", "Output a executable named `file`")
|
||||||
flag.StringVar(&output, "output", "", "Output a executable named `file`")
|
flag.StringVar(&output, "output", "", "Output a executable named `file`")
|
||||||
onlyEmitAsm := flag.Bool("S", false, "Only emit the asembly file and exit")
|
emitAsmOnly := flag.Bool("S", false, "Only emit the asembly file and exit")
|
||||||
|
|
||||||
printAst := flag.Bool("ast", false, "Print the AST out to stdout")
|
printAst := flag.Bool("ast", false, "Print the AST out to stdout")
|
||||||
printTAst := flag.Bool("tast", false, "Print the typed AST out to stdout")
|
printTAst := flag.Bool("tast", false, "Print the typed AST out to stdout")
|
||||||
@ -36,16 +38,22 @@ func main() {
|
|||||||
output = strings.TrimSuffix(input, filepath.Ext(input))
|
output = strings.TrimSuffix(input, filepath.Ext(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
var toPrint cmd.ToPrintFlags
|
var toPrint build.ToPrintFlags
|
||||||
if *printAst {
|
if *printAst {
|
||||||
toPrint |= cmd.PrintAst
|
toPrint |= build.PrintAst
|
||||||
}
|
}
|
||||||
if *printTAst {
|
if *printTAst {
|
||||||
toPrint |= cmd.PrintTAst
|
toPrint |= build.PrintTAst
|
||||||
}
|
}
|
||||||
if *printIr {
|
if *printIr {
|
||||||
toPrint |= cmd.PrintIr
|
toPrint |= build.PrintIr
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Compile(cmd.Arguments{Output: output, Input: input, OnlyEmitAsm: *onlyEmitAsm, ToPrint: toPrint})
|
logger := log.New(os.Stderr, "", log.Lshortfile)
|
||||||
|
|
||||||
|
err := build.NewSourceProgram(input, output).Build(asm.Fasm, *emitAsmOnly, build.ToPrintFlags(toPrint))
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalln(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user