package loader import ( "fmt" "github.com/marzeq/qk/parser" ) type PartialModuleInfo struct { Name string Imports []string Root *parser.RootNode } func CollectModuleInfo(root *parser.RootNode) (*PartialModuleInfo, error) { name := "main" imports := []string{} seenModule := false for i, node := range root.Body { switch n := node.(type) { case *parser.ModuleNode: if i != 0 { return nil, fmt.Errorf("module declaration must be first statement") } if seenModule { return nil, fmt.Errorf("multiple module declarations") } seenModule = true name = n.Name case *parser.ImportNode: imports = append(imports, n.Modules...) default: return &PartialModuleInfo{ Name: name, Imports: imports, Root: root, }, nil } } return &PartialModuleInfo{ Name: name, Imports: imports, Root: root, }, nil } type ModuleInfo struct { Name string Imports []string Roots []*parser.RootNode } func BuildModules(partials []*PartialModuleInfo) (map[string]*ModuleInfo, error) { modules := map[string]*ModuleInfo{} for _, p := range partials { if existing, ok := modules[p.Name]; ok { existing.Roots = append(existing.Roots, p.Root) existing.Imports = mergeImports(existing.Imports, p.Imports) } else { modules[p.Name] = &ModuleInfo{ Name: p.Name, Imports: unique(p.Imports), Roots: []*parser.RootNode{p.Root}, } } } return modules, nil } func mergeImports(a, b []string) []string { return unique(append(a, b...)) } func unique(in []string) []string { seen := map[string]struct{}{} var out []string for _, v := range in { if _, ok := seen[v]; !ok { seen[v] = struct{}{} out = append(out, v) } } return out }