3131#include " compiler/cbi/model/CompilerBinder.h"
3232#include " compiler/lab/LabModule.h"
3333
34+ static void append_parts (Diag& diag, const std::vector<chem::string_view>& parts) {
35+ bool is_first = true ;
36+ for (auto & part : parts) {
37+ if (is_first) {
38+ is_first = false ;
39+ } else {
40+ diag << ' .' ;
41+ }
42+ diag << part;
43+ }
44+ }
45+
46+ inline static void append_alias (Diag& diag, const chem::string_view& alias) {
47+ if (!alias.empty ()) {
48+ diag << " as " ;
49+ diag << alias;
50+ }
51+ }
52+
53+ static void append_alias_and_part (Diag& d, const std::vector<chem::string_view>& parts, const chem::string_view& alias) {
54+ if (parts.size () > 1 ) {
55+ d << " part from '" ;
56+ append_parts (d, parts);
57+ d << " '" ;
58+ }
59+ append_alias (d, alias);
60+ }
61+
62+ // this checks for the import items too
63+ void declareChildren (SymbolResolver& linker, ChildrenMapNode* node, ImportStatement* stmt) {
64+ auto & import_items = stmt->getImportItems ();
65+ if (import_items.empty () && !stmt->is_force_empty_import_items ()) {
66+ linker.declare (stmt->getTopLevelAlias (), node);
67+ return ;
68+ } else {
69+ auto & symbols = node->symbols ;
70+ for (auto & item : import_items) {
71+ auto found = symbols.find (item.parts [0 ]);
72+ if (found == symbols.end ()) {
73+ auto & d = linker.error (stmt) << " couldn't find symbol '" << item.parts [0 ] << " '" ;
74+ append_alias_and_part (d, item.parts , item.alias );
75+ continue ;
76+ }
77+ if (item.parts .size () == 1 ) {
78+ // import { file as f } from std <-- single part (file), alias 'f' or 'file' (the first part)
79+ auto & name = item.alias .empty () ? item.parts [0 ] : item.alias ;
80+ linker.declare (name, node);
81+ continue ;
82+ }
83+ // import { file.change as c } from std <--- multiple parts, alias 'c' or 'change' (the last part)
84+ ASTNode* current = found->second ;
85+ auto start = item.parts .data () + 1 ;
86+ const auto end = item.parts .data () + item.parts .size ();
87+ while (start != end) {
88+ const auto child = current->child (*start);
89+ if (child == nullptr ) {
90+ auto & d = linker.error (stmt) << " couldn't find child symbol '" << *start << " '" ;
91+ append_alias_and_part (d, item.parts , item.alias );
92+ current = nullptr ;
93+ break ;
94+ }
95+ current = child;
96+ start++;
97+ }
98+ if (current) {
99+ linker.declare (item.alias .empty () ? *(end - 1 ) : item.alias , current);
100+ }
101+ }
102+ }
103+ }
104+
34105void TopLevelDeclSymDeclare::VisitImportStmt (ImportStatement* stmt) {
35- const auto & alias = stmt->getTopLevelAlias ();
36- if (alias.empty ()) return ;
106+ if (stmt->getTopLevelAlias ().empty ()) return ;
37107 switch (stmt->getResultKind ()) {
38108 case ImportResultKind::None:
39109 linker.error (stmt) << " couldn't import file/module '" << stmt->getSourcePath () << " ' because of missing result" ;
40110 return ;
41111 case ImportResultKind::File: {
112+ const auto res = stmt->getFileResult ();
113+ if (res->children != nullptr ) {
114+ declareChildren (linker, res->children , stmt);
115+ return ;
116+ }
117+
42118 // create a children map node for the given file
43119 const auto children = linker.ast_allocator ->allocate <ChildrenMapNode>();
44120 new (children) ChildrenMapNode (stmt->parent (), stmt->encoded_location ());
@@ -51,12 +127,19 @@ void TopLevelDeclSymDeclare::VisitImportStmt(ImportStatement* stmt) {
51127 declare_node (d, node, at_least_spec);
52128 }
53129
130+ // store it for caching
131+ res->children = children;
132+
54133 // declare the children map node so user can access symbols through it
55- linker. declare (alias , children);
134+ declareChildren (linker , children, stmt );
56135 return ;
57136 }
58137 case ImportResultKind::Module: {
59138 const auto module = stmt->getModuleResult ();
139+ if (module ->children != nullptr ) {
140+ declareChildren (linker, module ->children , stmt);
141+ return ;
142+ }
60143
61144 // create a children map node for the given file
62145 const auto children = linker.ast_allocator ->allocate <ChildrenMapNode>();
@@ -71,8 +154,11 @@ void TopLevelDeclSymDeclare::VisitImportStmt(ImportStatement* stmt) {
71154 }
72155 }
73156
157+ // store it for caching
158+ module ->children = children;
159+
74160 // declare the children map node so user can access symbols through it
75- linker. declare (alias , children);
161+ declareChildren (linker , children, stmt );
76162 return ;
77163 }
78164 }
0 commit comments