package compiler import ( "sync" "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(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 := map[string]*core.Function{} allStructs := map[string]*types.Struct{} for functions != nil || files != nil || errs != nil { select { case function, ok := <-functions: if !ok { functions = nil continue } function.Functions = allFunctions function.Structs = allStructs 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 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 } // CompileFunctions starts a goroutine for each function compilation and waits for completion. func CompileFunctions(functions map[string]*core.Function) { wg := sync.WaitGroup{} for _, function := range functions { wg.Add(1) go func() { defer wg.Done() function.Compile() }() } wg.Wait() }