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) { all := core.Environment{ Files: make([]*fs.File, 0, 8), Functions: make(map[string]*core.Function, 32), Structs: make(map[string]*types.Struct, 8), Constants: make(map[string]*core.Constant, 8), } result := Result{} for constants != nil || files != nil || functions != nil || structs != nil || errs != nil { select { case function, ok := <-functions: if !ok { functions = nil continue } function.All = &all all.Functions[function.UniqueName] = function case structure, ok := <-structs: if !ok { structs = nil continue } all.Structs[structure.UniqueName] = structure case file, ok := <-files: if !ok { files = nil continue } all.Files = append(all.Files, file) case constant, ok := <-constants: if !ok { constants = nil continue } all.Constants[constant.Name] = constant case err, ok := <-errs: if !ok { errs = nil continue } return result, err } } // Calculate size of structs for _, structure := range all.Structs { structure.Update(all.Structs) } // Resolve the types for _, function := range all.Functions { err := function.ResolveTypes() if err != nil { return result, err } } // Start parallel compilation CompileFunctions(all.Functions) // Report errors if any occurred for _, function := range all.Functions { 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 all.Files { for _, pkg := range file.Imports { if !pkg.Used { return result, errors.New(&errors.UnusedImport{Package: pkg.Path}, file, pkg.Position) } } } // Check for existence of `init` init, exists := all.Functions["core.init"] if !exists { return result, errors.MissingInitFunction } // Check for existence of `main` main, exists := all.Functions["main.main"] if !exists { return result, errors.MissingMainFunction } result.Init = init result.Main = main result.Functions = all.Functions result.finalize() return result, nil }