1 : #include "nixexpr.hh"
2 : #include "storeexpr.hh"
3 :
4 :
5 : #include "nixexpr-ast.hh"
6 : #include "nixexpr-ast.cc"
7 :
8 :
9 : ATermMap::ATermMap(unsigned int initialSize, unsigned int maxLoadPct)
10 115 : {
11 115 : this->maxLoadPct = maxLoadPct;
12 115 : table = ATtableCreate(initialSize, maxLoadPct);
13 115 : if (!table) throw Error("cannot create ATerm table");
14 : }
15 :
16 :
17 : ATermMap::ATermMap(const ATermMap & map)
18 48 : : table(0)
19 48 : {
20 48 : ATermList keys = map.keys();
21 :
22 : /* !!! adjust allocation for load pct */
23 48 : maxLoadPct = map.maxLoadPct;
24 48 : table = ATtableCreate(ATgetLength(keys), maxLoadPct);
25 48 : if (!table) throw Error("cannot create ATerm table");
26 :
27 48 : add(map, keys);
28 : }
29 :
30 :
31 : ATermMap::~ATermMap()
32 326 : {
33 163 : if (table) ATtableDestroy(table);
34 : }
35 :
36 :
37 : void ATermMap::set(ATerm key, ATerm value)
38 1632 : {
39 1632 : return ATtablePut(table, key, value);
40 : }
41 :
42 :
43 : void ATermMap::set(const string & key, ATerm value)
44 299 : {
45 299 : set(toATerm(key), value);
46 : }
47 :
48 :
49 : ATerm ATermMap::get(ATerm key) const
50 1533 : {
51 1533 : return ATtableGet(table, key);
52 : }
53 :
54 :
55 : ATerm ATermMap::get(const string & key) const
56 121 : {
57 121 : return get(toATerm(key));
58 : }
59 :
60 :
61 : void ATermMap::remove(ATerm key)
62 29 : {
63 29 : ATtableRemove(table, key);
64 : }
65 :
66 :
67 : void ATermMap::remove(const string & key)
68 0 : {
69 0 : remove(toATerm(key));
70 : }
71 :
72 :
73 : ATermList ATermMap::keys() const
74 108 : {
75 108 : ATermList keys = ATtableKeys(table);
76 108 : if (!keys) throw Error("cannot query aterm map keys");
77 108 : return keys;
78 : }
79 :
80 :
81 : void ATermMap::add(const ATermMap & map)
82 0 : {
83 0 : ATermList keys = map.keys();
84 0 : add(map, keys);
85 : }
86 :
87 :
88 : void ATermMap::add(const ATermMap & map, ATermList & keys)
89 48 : {
90 348 : for (ATermIterator i(keys); i; ++i)
91 300 : set(*i, map.get(*i));
92 : }
93 :
94 :
95 : void ATermMap::reset()
96 0 : {
97 0 : ATtableReset(table);
98 : }
99 :
100 :
101 : string showPos(ATerm pos)
102 3 : {
103 3 : ATerm path;
104 3 : int line, column;
105 3 : if (matchNoPos(pos)) return "undefined position";
106 3 : if (!matchPos(pos, path, line, column))
107 0 : throw badTerm("position expected", pos);
108 3 : return (format("`%1%', line %2%") % aterm2String(path) % line).str();
109 : }
110 :
111 :
112 : ATerm bottomupRewrite(TermFun & f, ATerm e)
113 0 : {
114 0 : checkInterrupt();
115 :
116 0 : if (ATgetType(e) == AT_APPL) {
117 0 : AFun fun = ATgetAFun(e);
118 0 : int arity = ATgetArity(fun);
119 0 : ATermList args = ATempty;
120 :
121 0 : for (int i = arity - 1; i >= 0; i--)
122 0 : args = ATinsert(args, bottomupRewrite(f, ATgetArgument(e, i)));
123 :
124 0 : e = (ATerm) ATmakeApplList(fun, args);
125 : }
126 :
127 0 : else if (ATgetType(e) == AT_LIST) {
128 0 : ATermList in = (ATermList) e;
129 0 : ATermList out = ATempty;
130 :
131 0 : for (ATermIterator i(in); i; ++i)
132 0 : out = ATinsert(out, bottomupRewrite(f, *i));
133 :
134 0 : e = (ATerm) ATreverse(out);
135 : }
136 :
137 0 : return f(e);
138 : }
139 :
140 :
141 : void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos)
142 26 : {
143 26 : ATermList bnds;
144 26 : if (!matchAttrs(e, bnds))
145 0 : throw Error("attribute set expected");
146 :
147 150 : for (ATermIterator i(bnds); i; ++i) {
148 124 : ATerm name;
149 124 : Expr e;
150 124 : ATerm pos;
151 124 : if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
152 124 : attrs.set(name, withPos ? makeAttrRHS(e, pos) : e);
153 : }
154 : }
155 :
156 :
157 : Expr queryAttr(Expr e, const string & name)
158 86 : {
159 86 : ATerm dummy;
160 86 : return queryAttr(e, name, dummy);
161 : }
162 :
163 :
164 : Expr queryAttr(Expr e, const string & name, ATerm & pos)
165 117 : {
166 117 : ATermList bnds;
167 117 : if (!matchAttrs(e, bnds))
168 0 : throw Error("attribute set expected");
169 :
170 292 : for (ATermIterator i(bnds); i; ++i) {
171 292 : ATerm name2, pos2;
172 292 : Expr e;
173 292 : if (!matchBind(*i, name2, e, pos2))
174 0 : abort(); /* can't happen */
175 292 : if (aterm2String(name2) == name) {
176 117 : pos = pos2;
177 117 : return e;
178 : }
179 : }
180 :
181 0 : return 0;
182 : }
183 :
184 :
185 : Expr makeAttrs(const ATermMap & attrs)
186 31 : {
187 31 : ATermList bnds = ATempty;
188 274 : for (ATermIterator i(attrs.keys()); i; ++i) {
189 243 : Expr e;
190 243 : ATerm pos;
191 243 : if (!matchAttrRHS(attrs.get(*i), e, pos))
192 0 : abort(); /* can't happen */
193 243 : bnds = ATinsert(bnds, makeBind(*i, e, pos));
194 : }
195 31 : return makeAttrs(ATreverse(bnds));
196 : }
197 :
198 :
199 : Expr substitute(const ATermMap & subs, Expr e)
200 1853 : {
201 1853 : checkInterrupt();
202 :
203 1853 : ATerm name, pos, e2;
204 :
205 : /* As an optimisation, don't substitute in subterms known to be
206 : closed. */
207 1853 : if (matchClosed(e, e2)) return e;
208 :
209 1842 : if (matchVar(e, name)) {
210 106 : Expr sub = subs.get(name);
211 106 : return sub ? makeClosed(sub) : e;
212 : }
213 :
214 : /* In case of a function, filter out all variables bound by this
215 : function. */
216 1736 : ATermList formals;
217 1736 : ATerm body, def;
218 1736 : if (matchFunction(e, formals, body, pos)) {
219 3 : ATermMap subs2(subs);
220 6 : for (ATermIterator i(formals); i; ++i) {
221 3 : if (!matchNoDefFormal(*i, name) &&
222 : !matchDefFormal(*i, name, def))
223 0 : abort();
224 3 : subs2.remove(name);
225 : }
226 3 : return makeFunction(
227 : (ATermList) substitute(subs, (ATerm) formals),
228 : substitute(subs2, body), pos);
229 : }
230 :
231 1733 : if (matchFunction1(e, name, body, pos)) {
232 16 : ATermMap subs2(subs);
233 16 : subs2.remove(name);
234 16 : return makeFunction1(name, substitute(subs2, body), pos);
235 : }
236 :
237 : /* Idem for a mutually recursive attribute set. */
238 1717 : ATermList rbnds, nrbnds;
239 1717 : if (matchRec(e, rbnds, nrbnds)) {
240 5 : ATermMap subs2(subs);
241 12 : for (ATermIterator i(rbnds); i; ++i)
242 7 : if (matchBind(*i, name, e2, pos)) subs2.remove(name);
243 0 : else abort(); /* can't happen */
244 8 : for (ATermIterator i(nrbnds); i; ++i)
245 3 : if (matchBind(*i, name, e2, pos)) subs2.remove(name);
246 0 : else abort(); /* can't happen */
247 5 : return makeRec(
248 : (ATermList) substitute(subs2, (ATerm) rbnds),
249 : (ATermList) substitute(subs, (ATerm) nrbnds));
250 : }
251 :
252 1712 : if (ATgetType(e) == AT_APPL) {
253 1256 : AFun fun = ATgetAFun(e);
254 1256 : int arity = ATgetArity(fun);
255 1256 : ATermList args = ATempty;
256 :
257 2737 : for (int i = arity - 1; i >= 0; i--)
258 1481 : args = ATinsert(args, substitute(subs, ATgetArgument(e, i)));
259 :
260 1256 : return (ATerm) ATmakeApplList(fun, args);
261 : }
262 :
263 456 : if (ATgetType(e) == AT_LIST) {
264 81 : ATermList out = ATempty;
265 365 : for (ATermIterator i((ATermList) e); i; ++i)
266 284 : out = ATinsert(out, substitute(subs, *i));
267 81 : return (ATerm) ATreverse(out);
268 : }
269 :
270 375 : return e;
271 : }
272 :
273 :
274 : void checkVarDefs(const ATermMap & defs, Expr e)
275 1472 : {
276 1472 : ATerm name, pos, value;
277 1472 : ATermList formals;
278 1472 : ATerm with, body;
279 1472 : ATermList rbnds, nrbnds;
280 :
281 1472 : if (matchVar(e, name)) {
282 134 : if (!defs.get(name))
283 1 : throw Error(format("undefined variable `%1%'")
284 : % aterm2String(name));
285 : }
286 :
287 1338 : else if (matchFunction(e, formals, body, pos)) {
288 6 : ATermMap defs2(defs);
289 28 : for (ATermIterator i(formals); i; ++i) {
290 22 : Expr deflt;
291 22 : if (!matchNoDefFormal(*i, name))
292 11 : if (matchDefFormal(*i, name, deflt))
293 11 : checkVarDefs(defs, deflt);
294 : else
295 0 : abort();
296 22 : defs2.set(name, (ATerm) ATempty);
297 : }
298 6 : checkVarDefs(defs2, body);
299 : }
300 :
301 1332 : else if (matchFunction1(e, name, body, pos)) {
302 10 : ATermMap defs2(defs);
303 10 : defs2.set(name, (ATerm) ATempty);
304 10 : checkVarDefs(defs2, body);
305 : }
306 :
307 1322 : else if (matchRec(e, rbnds, nrbnds)) {
308 8 : checkVarDefs(defs, (ATerm) nrbnds);
309 8 : ATermMap defs2(defs);
310 37 : for (ATermIterator i(rbnds); i; ++i) {
311 29 : if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */
312 29 : defs2.set(name, (ATerm) ATempty);
313 : }
314 9 : for (ATermIterator i(nrbnds); i; ++i) {
315 1 : if (!matchBind(*i, name, value, pos)) abort(); /* can't happen */
316 1 : defs2.set(name, (ATerm) ATempty);
317 : }
318 8 : checkVarDefs(defs2, (ATerm) rbnds);
319 : }
320 :
321 1314 : else if (matchWith(e, with, body, pos)) {
322 : /* We can't check the body without evaluating the definitions
323 : (which is an arbitrary expression), so we don't do that
324 : here but only when actually evaluating the `with'. */
325 0 : checkVarDefs(defs, with);
326 : }
327 :
328 1314 : else if (ATgetType(e) == AT_APPL) {
329 966 : int arity = ATgetArity(ATgetAFun(e));
330 2177 : for (int i = 0; i < arity; ++i)
331 1211 : checkVarDefs(defs, ATgetArgument(e, i));
332 : }
333 :
334 348 : else if (ATgetType(e) == AT_LIST)
335 264 : for (ATermIterator i((ATermList) e); i; ++i)
336 195 : checkVarDefs(defs, *i);
337 : }
338 :
339 :
340 : Expr makeBool(bool b)
341 0 : {
342 0 : return b ? eTrue : eFalse;
343 23 : }
|