/
Expr.cpp
158 lines (114 loc) · 4.44 KB
/
Expr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "nixd/Expr.h"
#include <nix/nixexpr.hh>
namespace nixd {
std::map<const nix::Expr *, const nix::Expr *>
getParentMap(const nix::Expr *Root) {
decltype(getParentMap(nullptr)) Ret;
struct VisitorClass : RecursiveASTVisitor<VisitorClass> {
/// The parent before traverseExpr
const nix::Expr *ParentExpr;
decltype(Ret) *CapturedRet;
bool traverseExpr(const nix::Expr *E) {
CapturedRet->insert({E, ParentExpr});
const auto *OldParent = ParentExpr;
ParentExpr = E; // Set the parent into the visitor, it should be the
// parent when we are traversing child nodes.
if (!RecursiveASTVisitor<VisitorClass>::traverseExpr(E))
return false;
// After traversing on childrens finished, set parent expr to previous
// parent.
ParentExpr = OldParent;
return true;
}
} Visitor;
Visitor.ParentExpr = Root;
Visitor.CapturedRet = &Ret;
Visitor.traverseExpr(Root);
return Ret; // NRVO
}
nix::PosIdx getDisplOf(const nix::Expr *E, nix::Displacement Displ) {
if (const auto *CE = dynamic_cast<const nix::ExprAttrs *>(E))
return getDisplOf(CE, Displ);
if (const auto *CE = dynamic_cast<const nix::ExprLet *>(E))
return getDisplOf(CE, Displ);
if (const auto *CE = dynamic_cast<const nix::ExprLambda *>(E))
return getDisplOf(CE, Displ);
assert(false && "The requested expr is not an env creator");
return nix::noPos; // unreachable
}
nix::PosIdx getDisplOf(const nix::ExprAttrs *E, nix::Displacement Displ) {
assert(E->recursive && "Only recursive ExprAttr has displacement values");
auto DefIt = E->attrs.begin();
std::advance(DefIt, Displ);
return DefIt->second.pos;
}
nix::PosIdx getDisplOf(const nix::ExprLet *E, nix::Displacement Displ) {
auto DefIt = E->attrs->attrs.begin();
std::advance(DefIt, Displ);
return DefIt->second.pos;
}
nix::PosIdx getDisplOf(const nix::ExprLambda *E, nix::Displacement Displ) {
// this is broken because of:
// newEnv->sort();
// So we cannot now which position associated the Displ, *BEFORE* sorting.
return nix::noPos;
}
bool isEnvCreated(const nix::Expr *E, const nix::Expr *Child) {
// Line No. in the comment here is on NixOS/nix revision:
//
// 4539ab530ad23a8558512f784bd72c4cd0e72f13
//
// Custom, we need to check the relationship between parent & child
// ----------------------------------------------------------------
// src/libexpr/nixexpr.cc:507
if (const auto *CE = dynamic_cast<const nix::ExprAttrs *>(E))
return isEnvCreated(CE, Child);
// src/libexpr/nixexpr.cc:507
if (const auto *CE = dynamic_cast<const nix::ExprWith *>(E))
return isEnvCreated(CE, Child);
// Always true, these `Expr`s always created an Env.
// -------------------------------------------------
// src/libexpr/nixexpr.cc:435
if (const auto *CE = dynamic_cast<const nix::ExprLambda *>(E))
return true;
// src/libexpr/nixexpr.cc:472
if (const auto *CE = dynamic_cast<const nix::ExprLet *>(E))
return true;
return false; // Most `nix::Expr`s do not create a new Env.
}
bool isEnvCreated(const nix::ExprAttrs *E, const nix::Expr *) {
return E->recursive;
}
bool isEnvCreated(const nix::ExprWith *E, const nix::Expr *Child) {
// ExprWith creates a new env for it's body, not for it's "attrs"
return E->body == Child;
}
const nix::Expr *
searchEnvExpr(const nix::ExprVar *E,
const std::map<const nix::Expr *, const nix::Expr *> &ParentMap) {
assert(!E->fromWith && "This expression binds to 'with' expression!");
// For expressions not obtained from 'with' expression
// nix get it's value as:
// for (auto l = var.level; l; --l, env = env->up) // Search "levels" up
// Value = env->values[var.displ];
const nix::Expr *EnvExpr = E;
for (auto Level = E->level + 1; Level;) {
// So which expression is associated with 'Env->up'?
// Should be a parent nix::Expr that creates env.
const auto *ParentExpr = ParentMap.at(EnvExpr);
assert(ParentExpr != E &&
"Searched at the root of AST, but the Level still requested up");
if (isEnvCreated(ParentExpr, EnvExpr))
Level--;
EnvExpr = ParentExpr;
}
return EnvExpr;
}
nix::PosIdx searchDefinition(
const nix::ExprVar *E,
const std::map<const nix::Expr *, const nix::Expr *> &ParentMap) {
const auto *EnvExpr = searchEnvExpr(E, ParentMap);
assert(EnvExpr && "EnvExpr must be non-null!");
return getDisplOf(EnvExpr, E->displ);
}
} // namespace nixd