|
4 | 4 | #include "nixf/Basic/Nodes/Lambda.h" |
5 | 5 | #include "nixf/Sema/PrimOpInfo.h" |
6 | 6 |
|
| 7 | +#include <set> |
| 8 | + |
7 | 9 | using namespace nixf; |
8 | 10 |
|
9 | 11 | namespace { |
10 | 12 |
|
| 13 | +std::set<std::string> Constants{ |
| 14 | + "builtins", |
| 15 | + // This is an undocumented keyword actually. |
| 16 | + "__curPos", |
| 17 | + |
| 18 | + "true", |
| 19 | + "false", |
| 20 | + "null", |
| 21 | + "__currentTime", |
| 22 | + "__currentSystem", |
| 23 | + "__nixVersion", |
| 24 | + "__storeDir", |
| 25 | + "__langVersion", |
| 26 | + "__importNative", |
| 27 | + "__traceVerbose", |
| 28 | + "__nixPath", |
| 29 | + "derivation", |
| 30 | +}; |
| 31 | + |
11 | 32 | /// Builder a map of definitions. If there are something overlapped, maybe issue |
12 | 33 | /// a diagnostic. |
13 | 34 | class DefBuilder { |
14 | 35 | EnvNode::DefMap Def; |
| 36 | + std::vector<Diagnostic> &Diags; |
| 37 | + |
| 38 | + std::shared_ptr<Definition> addSimple(std::string Name, const Node *Entry, |
| 39 | + Definition::DefinitionSource Source) { |
| 40 | + assert(!Def.contains(Name)); |
| 41 | + auto NewDef = std::make_shared<Definition>(Entry, Source); |
| 42 | + Def.insert({std::move(Name), NewDef}); |
| 43 | + return NewDef; |
| 44 | + } |
15 | 45 |
|
16 | 46 | public: |
| 47 | + DefBuilder(std::vector<Diagnostic> &Diags) : Diags(Diags) {} |
| 48 | + |
17 | 49 | void addBuiltin(std::string Name) { |
18 | 50 | // Don't need to record def map for builtins. |
19 | | - auto _ = add(std::move(Name), nullptr, Definition::DS_Builtin); |
| 51 | + auto _ = addSimple(std::move(Name), nullptr, Definition::DS_Builtin); |
20 | 52 | } |
21 | 53 |
|
22 | 54 | [[nodiscard("Record ToDef Map!")]] std::shared_ptr<Definition> |
23 | 55 | add(std::string Name, const Node *Entry, |
24 | 56 | Definition::DefinitionSource Source) { |
25 | | - assert(!Def.contains(Name)); |
26 | | - auto NewDef = std::make_shared<Definition>(Entry, Source); |
27 | | - Def.insert({std::move(Name), NewDef}); |
28 | | - return NewDef; |
| 57 | + auto PrimOpLookup = lookupGlobalPrimOpInfo(Name); |
| 58 | + if (PrimOpLookup != PrimopLookupResult::NotFound) { |
| 59 | + // Overriding a builtin primop is discouraged. |
| 60 | + Diagnostic &D = |
| 61 | + Diags.emplace_back(Diagnostic::DK_PrimOpOverridden, Entry->range()); |
| 62 | + D << Name; |
| 63 | + } |
| 64 | + |
| 65 | + // Lookup constants |
| 66 | + if (Constants.contains(Name)) { |
| 67 | + Diagnostic &D = |
| 68 | + Diags.emplace_back(Diagnostic::DK_ConstantOverridden, Entry->range()); |
| 69 | + D << Name; |
| 70 | + } |
| 71 | + |
| 72 | + return addSimple(std::move(Name), Entry, Source); |
29 | 73 | } |
30 | 74 |
|
31 | 75 | EnvNode::DefMap finish() { return std::move(Def); } |
@@ -141,7 +185,7 @@ void VariableLookupAnalysis::dfs(const ExprLambda &Lambda, |
141 | 185 | return; |
142 | 186 |
|
143 | 187 | // Create a new EnvNode, as lambdas may have formal & arg. |
144 | | - DefBuilder DBuilder; |
| 188 | + DefBuilder DBuilder(Diags); |
145 | 189 | assert(Lambda.arg()); |
146 | 190 | const LambdaArg &Arg = *Lambda.arg(); |
147 | 191 |
|
@@ -212,7 +256,7 @@ std::shared_ptr<EnvNode> VariableLookupAnalysis::dfsAttrs( |
212 | 256 | const Node *Syntax, Definition::DefinitionSource Source) { |
213 | 257 | if (SA.isRecursive()) { |
214 | 258 | // rec { }, or let ... in ... |
215 | | - DefBuilder DB; |
| 259 | + DefBuilder DB(Diags); |
216 | 260 | // For each static names, create a name binding. |
217 | 261 | for (const auto &[Name, Attr] : SA.staticAttrs()) |
218 | 262 | ToDef.insert_or_assign(&Attr.key(), DB.add(Name, &Attr.key(), Source)); |
@@ -413,21 +457,16 @@ void VariableLookupAnalysis::dfs(const Node &Root, |
413 | 457 |
|
414 | 458 | void VariableLookupAnalysis::runOnAST(const Node &Root) { |
415 | 459 | // Create a basic env |
416 | | - DefBuilder DB; |
417 | | - std::vector<std::string> BaseEnv{ |
418 | | - "builtins", |
419 | | - // This is an undocumented keyword actually. |
420 | | - "__curPos", |
421 | | - }; |
| 460 | + DefBuilder DB(Diags); |
422 | 461 |
|
423 | 462 | for (const auto &[Name, Info] : PrimOpsInfo) { |
424 | 463 | if (!Info.Internal && !Name.starts_with("__")) { |
425 | 464 | // Only add non-internal primops without "__" prefix. |
426 | | - BaseEnv.push_back(Name); |
| 465 | + DB.addBuiltin(Name); |
427 | 466 | } |
428 | 467 | } |
429 | 468 |
|
430 | | - for (const auto &Builtin : BaseEnv) |
| 469 | + for (const auto &Builtin : Constants) |
431 | 470 | DB.addBuiltin(Builtin); |
432 | 471 |
|
433 | 472 | auto Env = std::make_shared<EnvNode>(nullptr, DB.finish(), nullptr); |
|
0 commit comments