Skip to content

Commit

Permalink
CLI: Improve code for building a project
Browse files Browse the repository at this point in the history
  • Loading branch information
MineGame159 committed Jan 14, 2024
1 parent 9bff8af commit e0fb44b
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 128 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.vscode
.idea

build
example/build
tests/build

fireball
77 changes: 77 additions & 0 deletions cmd/build/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package build

import (
"fireball/core/codegen"
"fireball/core/ir"
"fireball/core/llvm"
"fireball/core/workspace"
"os"
"path/filepath"
"runtime"
"strings"
)

func Build(project *workspace.Project, entrypoint *ir.Module, optimizationLevel uint8, outputName string) (string, error) {
_ = os.Mkdir("build", 0750)

// Emit project IR
irPaths := make([]string, 0, len(project.Files))

for _, file := range project.Files {
path := strings.ReplaceAll(file.Path, "/", "-")
path = filepath.Join(project.Path, "build", path[:len(path)-3]+".ll")

irFile, err := os.Create(path)
if err != nil {
return "", err
}

module := codegen.Emit(file.AbsolutePath(), project.GetResolverFile(file.Ast), file.Ast)
llvm.WriteText(module, irFile)

_ = irFile.Close()

irPaths = append(irPaths, path)
}

// Emit entrypoint IR
entrypointPath := filepath.Join(project.Path, "build", "__entrypoint.ll")
irPaths = append(irPaths, entrypointPath)

entrypointFile, err := os.Create(entrypointPath)
if err != nil {
return "", err
}

llvm.WriteText(entrypoint, entrypointFile)
_ = entrypointFile.Close()

// Compile
c := Compiler{
OptimizationLevel: min(max(int(optimizationLevel), 0), 3),
}

for _, irPath := range irPaths {
c.AddInput(irPath)
}

if runtime.GOOS == "darwin" {
c.AddLibrary("System")
} else {
c.AddLibrary("m")
c.AddLibrary("c")
}

for _, library := range project.Config.LinkLibraries {
c.AddLibrary(library)
}

output := filepath.Join(project.Path, "build", outputName)

err = c.Compile(output)
if err != nil {
return "", err
}

return output, nil
}
69 changes: 69 additions & 0 deletions cmd/build/reporter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package build

import (
"fireball/core/utils"
"fireball/core/workspace"
"fmt"
"github.com/fatih/color"
"os"
"path/filepath"
)

func Report(project *workspace.Project) {
reporter := consoleReporter{
error: color.New(color.FgRed),
warning: color.New(color.FgYellow),
}

for _, file := range project.Files {
for _, diagnostic := range file.Diagnostics() {
reporter.Report(file, diagnostic)
}
}

if reporter.errorCount > 0 {
fmt.Println()
_, _ = color.New(color.FgRed).Print("Build failed")

if reporter.errorCount == 1 {
fmt.Printf(", with %d error\n", reporter.errorCount)
} else {
fmt.Printf(", with %d errors\n", reporter.errorCount)
}

os.Exit(1)
}

if reporter.hadDiagnostic {
fmt.Println()
}
}

type consoleReporter struct {
error *color.Color
warning *color.Color

hadDiagnostic bool
errorCount int
}

func (c *consoleReporter) Report(file *workspace.File, diag utils.Diagnostic) {
path, err := filepath.Rel(file.Project.Config.Src, file.Path)
if err != nil {
path = file.Path
}

msg := fmt.Sprintf("[%s:%d:%d] %s", path, diag.Range.Start.Line, diag.Range.Start.Column+1, diag.Message)

if diag.Kind == utils.ErrorKind {
_, _ = c.error.Fprint(os.Stderr, "ERROR ")
_, _ = fmt.Fprintln(os.Stderr, msg)

c.errorCount++
} else {
_, _ = c.warning.Print("WARNING ")
fmt.Println(msg)
}

c.hadDiagnostic = true
}
132 changes: 5 additions & 127 deletions cmd/cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@ package cmd
import (
"fireball/cmd/build"
"fireball/core/ast"
"fireball/core/codegen"
"fireball/core/ir"
"fireball/core/llvm"
"fireball/core/utils"
"fireball/core/workspace"
"fmt"
"github.com/fatih/color"
"github.com/spf13/cobra"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"time"
)

Expand Down Expand Up @@ -54,91 +47,17 @@ func buildProject() string {
}

// Report errors
reporter := consoleReporter{
error: color.New(color.FgRed),
warning: color.New(color.FgYellow),
}

for _, file := range project.Files {
for _, diagnostic := range file.Diagnostics() {
reporter.Report(file, diagnostic)
}
}

if reporter.errorCount > 0 {
fmt.Println()
_, _ = color.New(color.FgRed).Print("Build failed")

if reporter.errorCount == 1 {
fmt.Printf(", with %d error\n", reporter.errorCount)
} else {
fmt.Printf(", with %d errors\n", reporter.errorCount)
}

os.Exit(1)
}

// Emit LLVM IR
_ = os.Mkdir("build", 0750)

irPaths := make([]string, 0, len(project.Files))

for _, file := range project.Files {
path := strings.ReplaceAll(file.Path, "/", "-")
path = filepath.Join(project.Path, "build", path[:len(path)-3]+".ll")

irFile, _ := os.Create(path)

module := codegen.Emit(file.AbsolutePath(), project.GetResolverFile(file.Ast), file.Ast)
llvm.WriteText(module, irFile)

_ = irFile.Close()

irPaths = append(irPaths, path)
}

entrypointPath := filepath.Join(project.Path, "build", "__entrypoint.ll")
irPaths = append(irPaths, entrypointPath)

err = generateEntrypoint(project, entrypointPath)
if err != nil {
log.Fatalln(err.Error())
}

// Compile
c := build.Compiler{
OptimizationLevel: min(max(int(opt), 0), 3),
}

for _, irPath := range irPaths {
c.AddInput(irPath)
}

if runtime.GOOS == "darwin" {
c.AddLibrary("System")
} else {
c.AddLibrary("m")
c.AddLibrary("c")
}

for _, library := range project.Config.LinkLibraries {
c.AddLibrary(library)
}

output := filepath.Join(project.Path, "build", project.Config.Name)
err = c.Compile(output)
build.Report(project)

// Build
output, err := build.Build(project, generateEntrypoint(project), opt, project.Config.Name)
if err != nil {
log.Fatalln(err.Error())
}

// Print info
took := time.Now().Sub(start)

if reporter.hadDiagnostic {
fmt.Println()
}

_, _ = color.New(color.FgGreen).Print("Build successful")
fmt.Printf(", took %s\n", took)
fmt.Println()
Expand All @@ -147,8 +66,7 @@ func buildProject() string {
return output
}

func generateEntrypoint(project *workspace.Project, path string) error {
// Create module
func generateEntrypoint(project *workspace.Project) *ir.Module {
m := &ir.Module{Path: "__entrypoint"}

resolver := project.GetResolverName(project.Config.Namespace)
Expand All @@ -157,8 +75,6 @@ func generateEntrypoint(project *workspace.Project, path string) error {
main := m.Define("main", &ir.FuncType{Returns: ir.I32}, 0)
mainBlock := main.Block("")

// Flags

if function != nil {
var fbMain ir.Value

Expand Down Expand Up @@ -188,43 +104,5 @@ func generateEntrypoint(project *workspace.Project, path string) error {
}})
}

// Write module
file, err := os.Create(path)
if err != nil {
return err
}

llvm.WriteText(m, file)

_ = file.Close()
return nil
}

type consoleReporter struct {
error *color.Color
warning *color.Color

hadDiagnostic bool
errorCount int
}

func (c *consoleReporter) Report(file *workspace.File, diag utils.Diagnostic) {
path, err := filepath.Rel(file.Project.Config.Src, file.Path)
if err != nil {
path = file.Path
}

msg := fmt.Sprintf("[%s:%d:%d] %s", path, diag.Range.Start.Line, diag.Range.Start.Column+1, diag.Message)

if diag.Kind == utils.ErrorKind {
_, _ = c.error.Fprint(os.Stderr, "ERROR ")
_, _ = fmt.Fprintln(os.Stderr, msg)

c.errorCount++
} else {
_, _ = c.warning.Print("WARNING ")
fmt.Println(msg)
}

c.hadDiagnostic = true
return m
}

0 comments on commit e0fb44b

Please sign in to comment.