package loader import ( "fmt" "github.com/marzeq/qk/codegen/irgen" "github.com/marzeq/qk/ir" "github.com/marzeq/qk/parser" "github.com/marzeq/qk/sema" "github.com/marzeq/qk/symbols" "github.com/marzeq/qk/types" ) func ComputeModuleOrder(mods map[string]*ModuleInfo, primaryModule string) ([]string, []error) { order, err := ModuleDependencyOrder(mods, primaryModule) if err != nil { return nil, []error{err} } return order, nil } func RunSemanticPipeline(mods map[string]*ModuleInfo, analyser *sema.Analyser, order []string, verbose, debug bool) (errors []error, warnings []error) { for _, name := range order { info := mods[name] analyser.DeclareModule(info.Root, name, info.TrustedStandardLibrary) if len(analyser.Errors()) > 0 { return analyser.Errors(), nil } analyser.AnalyseModuleBody(info.Root, name) if len(analyser.Errors()) > 0 { return analyser.Errors(), nil } } if verbose && debug { fmt.Println("completed analysis phase") } attributor := analyser.NewAttributor() for _, name := range order { info := mods[name] attributor.AttributeGenericTemplates(info.Root) } if len(analyser.Errors()) > 0 || len(attributor.Errors()) > 0 { errors := append([]error(nil), analyser.Errors()...) errors = append(errors, attributor.Errors()...) return errors, nil } templateValidator := analyser.NewValidator() for _, name := range order { info := mods[name] templateValidator.ValidateGenericTemplates(info.Root) } warnings = append(warnings, templateValidator.Warnings()...) if len(templateValidator.Errors()) > 0 { return templateValidator.Errors(), warnings } for _, name := range order { info := mods[name] attributor.AttributeModule(info.Root) } if len(analyser.Errors()) > 0 || len(attributor.Errors()) > 0 { errors := append([]error(nil), analyser.Errors()...) errors = append(errors, attributor.Errors()...) return errors, warnings } if verbose && debug { fmt.Println("completed attribution phase") } validator := analyser.NewValidator() for _, name := range order { info := mods[name] validator.ValidateModule(info.Root) } warnings = append(warnings, validator.Warnings()...) if len(validator.Errors()) > 0 { return validator.Errors(), warnings } if verbose && debug { fmt.Println("completed validation phase") } if debug { for _, name := range order { info := mods[name] analyser.DebugCheck(info.Root) } if verbose { fmt.Println("completed debug checks") } } return nil, warnings } // RunSemanticModule analyses one source-backed module after its dependencies // have been declared. func RunSemanticModule(info *ModuleInfo, analyser *sema.Analyser, verbose, debug bool) (errors []error, warnings []error) { analyser.DeclareModule(info.Root, info.Path, info.TrustedStandardLibrary) if len(analyser.Errors()) != 0 { return analyser.Errors(), nil } analyser.AnalyseModuleBody(info.Root, info.Path) if len(analyser.Errors()) != 0 { return analyser.Errors(), nil } attributor := analyser.NewAttributor() attributor.AttributeGenericTemplates(info.Root) if len(analyser.Errors()) != 0 || len(attributor.Errors()) != 0 { out := append([]error(nil), analyser.Errors()...) return append(out, attributor.Errors()...), nil } templateValidator := analyser.NewValidator() templateValidator.ValidateGenericTemplates(info.Root) warnings = append(warnings, templateValidator.Warnings()...) if len(templateValidator.Errors()) != 0 { return templateValidator.Errors(), warnings } attributor.AttributeModule(info.Root) if len(analyser.Errors()) != 0 || len(attributor.Errors()) != 0 { out := append([]error(nil), analyser.Errors()...) return append(out, attributor.Errors()...), warnings } validator := analyser.NewValidator() validator.ValidateModule(info.Root) warnings = append(warnings, validator.Warnings()...) if len(validator.Errors()) != 0 { return validator.Errors(), warnings } if debug { analyser.DebugCheck(info.Root) } if verbose && debug { fmt.Printf("completed semantic pipeline for module %s\n", info.Path) } return nil, warnings } // RunSemanticModuleBodies completes attribution and validation for modules // whose declarations and analysed bodies have already been installed. This // preserves the language's global structural-method declaration phase. func RunSemanticModuleBodies(mods map[string]*ModuleInfo, analyser *sema.Analyser, order []string, verbose, debug bool) (errors []error, warnings []error) { attributor := analyser.NewAttributor() for _, name := range order { attributor.AttributeGenericTemplates(mods[name].Root) } if len(analyser.Errors()) != 0 || len(attributor.Errors()) != 0 { out := append([]error(nil), analyser.Errors()...) return append(out, attributor.Errors()...), nil } templateValidator := analyser.NewValidator() for _, name := range order { templateValidator.ValidateGenericTemplates(mods[name].Root) } warnings = append(warnings, templateValidator.Warnings()...) if len(templateValidator.Errors()) != 0 { return templateValidator.Errors(), warnings } for _, name := range order { attributor.AttributeModule(mods[name].Root) } if len(analyser.Errors()) != 0 || len(attributor.Errors()) != 0 { out := append([]error(nil), analyser.Errors()...) return append(out, attributor.Errors()...), warnings } validator := analyser.NewValidator() for _, name := range order { validator.ValidateModule(mods[name].Root) } warnings = append(warnings, validator.Warnings()...) if len(validator.Errors()) != 0 { return validator.Errors(), warnings } if debug { for _, name := range order { analyser.DebugCheck(mods[name].Root) } } if verbose && debug { fmt.Println("completed incremental semantic body pipeline") } return nil, warnings } func GenerateIRModules(mods map[string]*ModuleInfo, mainModule string, order []string, verbose bool, debug bool) (map[string]*ir.Module, []error) { out := make(map[string]*ir.Module, len(order)) for _, name := range order { info := mods[name] dependencyInitializers := make([]string, 0, len(info.Imports)) for _, dependency := range info.Imports { if dependencyIR := out[dependency]; dependencyIR != nil && dependencyIR.Initializer != "" { dependencyInitializers = append(dependencyInitializers, dependencyIR.Initializer) } } gen := &irgen.Generator{ ModuleName: name, MainModule: mainModule, DependencyInitializers: dependencyInitializers, } modIR := gen.Generate(info.Root) deduplicateIRDeclarations(modIR) out[name] = modIR } if verbose && debug { fmt.Println("completed ir generation phase") } return out, nil } func GenerateIRModule(info *ModuleInfo, mainModule string, dependencyInitializers []string) *ir.Module { gen := &irgen.Generator{ ModuleName: info.Path, MainModule: mainModule, DependencyInitializers: append([]string(nil), dependencyInitializers...), } module := gen.Generate(info.Root) deduplicateIRDeclarations(module) return module } func GenerateModuleGenericTemplateIR(info *ModuleInfo) []ir.GenericTemplate { module := &ir.Module{} generator := &irgen.Generator{ModuleName: info.Path, Module: module} var result []ir.GenericTemplate for _, node := range info.Root.Body { function, ok := node.(*parser.FunctionDefNode) if !ok || !function.IsGeneric() || function.Body == nil { continue } if generated := generator.GenerateGenericTemplate(function); len(generated) != 0 { result = append(result, ir.GenericTemplate{ Module: info.Path, Name: function.Symbol.Name, Parameters: append([]types.TypeParameter(nil), function.Symbol.GenericParameters...), Functions: generated, }) } } return result } // PropagateSpecializationDemands carries constant-argument and fixed typed- // variadic demands through forwarding functions before their IR is generated. // The semantic validator records the forwarding relationships; this fixed- // point pass makes wrapper selection independent of module generation order. func PropagateSpecializationDemands(mods map[string]*ModuleInfo, order []string) { propagateSpecializationConstants(mods, order) propagateTypedVariadicArities(mods, order) } func GenerateGenericTemplateIR(mods map[string]*ModuleInfo, order []string) map[string][]ir.GenericTemplate { result := make(map[string][]ir.GenericTemplate) for _, name := range order { module := &ir.Module{} generator := &irgen.Generator{ModuleName: name, Module: module} for _, node := range mods[name].Root.Body { function, ok := node.(*parser.FunctionDefNode) if !ok || !function.IsGeneric() || function.Body == nil { continue } if generated := generator.GenerateGenericTemplate(function); len(generated) != 0 { result[name] = append(result[name], ir.GenericTemplate{ Module: name, Name: function.Symbol.Name, Parameters: append([]types.TypeParameter(nil), function.Symbol.GenericParameters...), Functions: generated, }) } } } return result } func propagateSpecializationConstants(mods map[string]*ModuleInfo, order []string) { var signatures []*symbols.FunctionSignature for _, name := range order { for _, node := range mods[name].Root.Body { if function, ok := node.(*parser.FunctionDefNode); ok && function.Symbol != nil && function.Symbol.Signature != nil { signatures = append(signatures, function.Symbol.Signature) } } } changed := true for changed { changed = false for _, signature := range signatures { for _, forward := range signature.ConstantForwards { for key, constant := range signature.ConstantArguments[forward.CallerParameter] { if forward.Callee.ConstantArguments == nil { forward.Callee.ConstantArguments = make(map[int]map[string]symbols.SpecializationConstant) } if forward.Callee.ConstantArguments[forward.CalleeParameter] == nil { forward.Callee.ConstantArguments[forward.CalleeParameter] = make(map[string]symbols.SpecializationConstant) } if _, exists := forward.Callee.ConstantArguments[forward.CalleeParameter][key]; !exists { forward.Callee.ConstantArguments[forward.CalleeParameter][key] = constant changed = true } } } } } } func propagateTypedVariadicArities(mods map[string]*ModuleInfo, order []string) { var signatures []*symbols.FunctionSignature for _, name := range order { for _, node := range mods[name].Root.Body { if function, ok := node.(*parser.FunctionDefNode); ok && function.Symbol != nil && function.Symbol.Signature != nil && function.Symbol.Signature.TypedVariadic { signatures = append(signatures, function.Symbol.Signature) } } } changed := true for changed { changed = false for _, signature := range signatures { for arity := range signature.TypedVariadicArities { for _, forwarded := range signature.TypedVariadicForwards { if forwarded.TypedVariadicArities == nil { forwarded.TypedVariadicArities = make(map[int]bool) } if !forwarded.TypedVariadicArities[arity] { forwarded.TypedVariadicArities[arity] = true changed = true } } } } } } func deduplicateIRDeclarations(module *ir.Module) { definedFunctions := make(map[string]bool, len(module.Functions)) for _, fn := range module.Functions { definedFunctions[fn.Name] = true } seenFunctions := make(map[string]bool) externs := module.Externs[:0] for _, extern := range module.Externs { name := extern.Name if extern.From != "" { name = extern.From } if definedFunctions[name] || seenFunctions[name] { continue } seenFunctions[name] = true externs = append(externs, extern) } module.Externs = externs definedGlobals := make(map[string]bool, len(module.Globals)) for _, global := range module.Globals { definedGlobals[global.Name] = true } seenGlobals := make(map[string]bool) externGlobals := module.ExternGlobals[:0] for _, global := range module.ExternGlobals { if definedGlobals[global.Name] || seenGlobals[global.Name] { continue } seenGlobals[global.Name] = true externGlobals = append(externGlobals, global) } module.ExternGlobals = externGlobals }