Skip to content

Commit 56a274e

Browse files
committed
caching for symbol maps of imported files in build.lab files
1 parent 9688b93 commit 56a274e

File tree

4 files changed

+118
-4
lines changed

4 files changed

+118
-4
lines changed

ast/statements/Import.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,30 @@ enum class ImportResultKind : uint8_t {
3636
Module
3737
};
3838

39+
struct ImportStatementAttributes {
40+
41+
bool force_empty_import_items = false;
42+
43+
};
44+
3945
class ImportStatement final : public ASTNode {
4046
private:
4147

48+
/**
49+
* what kind of import statement is this
50+
*/
4251
ImportStatementKind import_kind;
4352

4453
/**
4554
* set once the import has been processed by the compiler
4655
*/
4756
ImportResultKind result_kind = ImportResultKind::None;
4857

58+
/**
59+
* the attributes on the import statement
60+
*/
61+
ImportStatementAttributes attrs;
62+
4963
// --- New Internal State ---
5064
chem::string_view m_sourcePath; // "std", "./local", or "org/repo"
5165
chem::string_view m_topLevelAlias; // the 'as' at the very end of the statement
@@ -95,6 +109,10 @@ class ImportStatement final : public ASTNode {
95109
import_kind = k;
96110
}
97111

112+
inline bool is_force_empty_import_items() {
113+
return attrs.force_empty_import_items;
114+
}
115+
98116
void setSourcePath(chem::string_view path) { m_sourcePath = path; }
99117
const chem::string_view& getSourcePath() const { return m_sourcePath; }
100118

compiler/lab/LabModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ struct LabModule {
9393
*/
9494
std::optional<bool> has_changed = std::nullopt;
9595

96+
/**
97+
* calculated once for caching purposes
98+
*/
99+
ChildrenMapNode* children = nullptr;
100+
96101
#ifdef LSP_BUILD
97102
/**
98103
* compiler interfaces strings are retained in lsp build, so they can

compiler/processor/ASTFileResult.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ struct ASTFileResult : ASTFileMetaData {
2020
*/
2121
ASTUnit unit;
2222

23+
/**
24+
* we calculate this once if import is present in build.lab
25+
*/
26+
ChildrenMapNode* children = nullptr;
27+
2328
/**
2429
* the compile unit
2530
*/

compiler/symres/DeclareTopLevel.cpp

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,90 @@
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+
34105
void 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

Comments
 (0)