113 lines
2.4 KiB
Go
113 lines
2.4 KiB
Go
package compiler
|
|
|
|
import (
|
|
"git.akyoto.dev/cli/q/src/core"
|
|
"git.akyoto.dev/cli/q/src/errors"
|
|
"git.akyoto.dev/cli/q/src/fs"
|
|
"git.akyoto.dev/cli/q/src/types"
|
|
)
|
|
|
|
// Compile waits for the scan to finish and compiles all functions.
|
|
func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions <-chan *core.Function, structs <-chan *types.Struct, errs <-chan error) (Result, error) {
|
|
result := Result{}
|
|
allFiles := make([]*fs.File, 0, 8)
|
|
allFunctions := make(map[string]*core.Function, 32)
|
|
allStructs := make(map[string]*types.Struct, 8)
|
|
allConstants := make(map[string]*core.Constant, 8)
|
|
|
|
for constants != nil || files != nil || functions != nil || structs != nil || errs != nil {
|
|
select {
|
|
case function, ok := <-functions:
|
|
if !ok {
|
|
functions = nil
|
|
continue
|
|
}
|
|
|
|
function.Functions = allFunctions
|
|
function.Structs = allStructs
|
|
function.Constants = allConstants
|
|
allFunctions[function.UniqueName] = function
|
|
|
|
case structure, ok := <-structs:
|
|
if !ok {
|
|
structs = nil
|
|
continue
|
|
}
|
|
|
|
allStructs[structure.UniqueName] = structure
|
|
|
|
case file, ok := <-files:
|
|
if !ok {
|
|
files = nil
|
|
continue
|
|
}
|
|
|
|
allFiles = append(allFiles, file)
|
|
|
|
case constant, ok := <-constants:
|
|
if !ok {
|
|
constants = nil
|
|
continue
|
|
}
|
|
|
|
allConstants[constant.Name] = constant
|
|
|
|
case err, ok := <-errs:
|
|
if !ok {
|
|
errs = nil
|
|
continue
|
|
}
|
|
|
|
return result, err
|
|
}
|
|
}
|
|
|
|
// Calculate size of structs
|
|
for _, structure := range allStructs {
|
|
structure.Update(allStructs)
|
|
}
|
|
|
|
// Resolve the types
|
|
for _, function := range allFunctions {
|
|
err := function.ResolveTypes()
|
|
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
}
|
|
|
|
// Start parallel compilation
|
|
CompileFunctions(allFunctions)
|
|
|
|
// Report errors if any occurred
|
|
for _, function := range allFunctions {
|
|
if function.Err != nil {
|
|
return result, function.Err
|
|
}
|
|
|
|
result.InstructionCount += len(function.Assembler.Instructions)
|
|
result.DataCount += len(function.Assembler.Data)
|
|
}
|
|
|
|
// Check for unused imports in all files
|
|
for _, file := range allFiles {
|
|
for _, pkg := range file.Imports {
|
|
if !pkg.Used {
|
|
return result, errors.New(&errors.UnusedImport{Package: pkg.Path}, file, pkg.Position)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for existence of `main`
|
|
main, exists := allFunctions["main.main"]
|
|
|
|
if !exists {
|
|
return result, errors.MissingMainFunction
|
|
}
|
|
|
|
result.Main = main
|
|
result.Functions = allFunctions
|
|
result.finalize()
|
|
return result, nil
|
|
}
|