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 }