1
|
1
|
|
2 // Compiler implementation of the D programming language
|
|
3 // Copyright (c) 1999-2006 by Digital Mars
|
|
4 // All Rights Reserved
|
|
5 // written by Walter Bright
|
|
6 // http://www.digitalmars.com
|
|
7 // License for redistribution is by either the Artistic License
|
|
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
|
|
9 // See the included readme.txt for details.
|
|
10
|
|
11 #include <stdio.h>
|
|
12 #include <assert.h>
|
|
13
|
|
14 #include "id.h"
|
|
15 #include "init.h"
|
|
16 #include "declaration.h"
|
|
17 #include "identifier.h"
|
|
18 #include "expression.h"
|
|
19 #include "cond.h"
|
|
20 #include "module.h"
|
|
21 #include "template.h"
|
|
22 #include "lexer.h"
|
|
23 #ifdef _DH
|
|
24 #include "mtype.h"
|
|
25 #include "scope.h"
|
|
26 #endif
|
|
27
|
|
28 int findCondition(Array *ids, Identifier *ident)
|
|
29 {
|
|
30 if (ids)
|
|
31 {
|
|
32 for (int i = 0; i < ids->dim; i++)
|
|
33 {
|
|
34 char *id = (char *)ids->data[i];
|
|
35
|
|
36 if (strcmp(id, ident->toChars()) == 0)
|
|
37 return TRUE;
|
|
38 }
|
|
39 }
|
|
40
|
|
41 return FALSE;
|
|
42 }
|
|
43
|
|
44 /* ============================================================ */
|
|
45
|
|
46 Condition::Condition(Loc loc)
|
|
47 {
|
|
48 this->loc = loc;
|
|
49 inc = 0;
|
|
50 }
|
|
51
|
|
52 /* ============================================================ */
|
|
53
|
|
54 DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
|
|
55 : Condition(0)
|
|
56 {
|
|
57 this->mod = mod;
|
|
58 this->level = level;
|
|
59 this->ident = ident;
|
|
60 }
|
|
61
|
|
62 Condition *DVCondition::syntaxCopy()
|
|
63 {
|
|
64 return this; // don't need to copy
|
|
65 }
|
|
66
|
|
67 /* ============================================================ */
|
|
68
|
|
69 void DebugCondition::setGlobalLevel(unsigned level)
|
|
70 {
|
|
71 global.params.debuglevel = level;
|
|
72 }
|
|
73
|
|
74 void DebugCondition::addGlobalIdent(char *ident)
|
|
75 {
|
|
76 if (!global.params.debugids)
|
|
77 global.params.debugids = new Array();
|
|
78 global.params.debugids->push(ident);
|
|
79 }
|
|
80
|
|
81
|
|
82 DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
|
|
83 : DVCondition(mod, level, ident)
|
|
84 {
|
|
85 }
|
|
86
|
|
87 int DebugCondition::include(Scope *sc, ScopeDsymbol *s)
|
|
88 {
|
|
89 //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
|
|
90 if (inc == 0)
|
|
91 {
|
|
92 inc = 2;
|
|
93 if (ident)
|
|
94 {
|
|
95 if (findCondition(mod->debugids, ident))
|
|
96 inc = 1;
|
|
97 else if (findCondition(global.params.debugids, ident))
|
|
98 inc = 1;
|
|
99 else
|
|
100 { if (!mod->debugidsNot)
|
|
101 mod->debugidsNot = new Array();
|
|
102 mod->debugidsNot->push(ident->toChars());
|
|
103 }
|
|
104 }
|
|
105 else if (level <= global.params.debuglevel || level <= mod->debuglevel)
|
|
106 inc = 1;
|
|
107 }
|
|
108 return (inc == 1);
|
|
109 }
|
|
110
|
|
111 void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
|
112 {
|
|
113 if (ident)
|
|
114 buf->printf("debug (%s)", ident->toChars());
|
|
115 else
|
|
116 buf->printf("debug (%u)", level);
|
|
117 }
|
|
118
|
|
119 /* ============================================================ */
|
|
120
|
|
121 void VersionCondition::setGlobalLevel(unsigned level)
|
|
122 {
|
|
123 global.params.versionlevel = level;
|
|
124 }
|
|
125
|
|
126 void VersionCondition::checkPredefined(Loc loc, char *ident)
|
|
127 {
|
|
128 static char* reserved[] =
|
|
129 {
|
|
130 "DigitalMars", "X86", "X86_64",
|
|
131 "Windows", "Win32", "Win64",
|
|
132 "linux",
|
|
133 "LittleEndian", "BigEndian",
|
|
134 "all",
|
|
135 "none",
|
|
136 };
|
|
137
|
|
138 for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++)
|
|
139 {
|
|
140 if (strcmp(ident, reserved[i]) == 0)
|
|
141 goto Lerror;
|
|
142 }
|
|
143
|
|
144 if (ident[0] == 'D' && ident[1] == '_')
|
|
145 goto Lerror;
|
|
146
|
|
147 return;
|
|
148
|
|
149 Lerror:
|
|
150 error(loc, "version identifier '%s' is reserved and cannot be set", ident);
|
|
151 }
|
|
152
|
|
153 void VersionCondition::addGlobalIdent(char *ident)
|
|
154 {
|
|
155 checkPredefined(0, ident);
|
|
156 addPredefinedGlobalIdent(ident);
|
|
157 }
|
|
158
|
|
159 void VersionCondition::addPredefinedGlobalIdent(char *ident)
|
|
160 {
|
|
161 if (!global.params.versionids)
|
|
162 global.params.versionids = new Array();
|
|
163 global.params.versionids->push(ident);
|
|
164 }
|
|
165
|
|
166
|
|
167 VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
|
|
168 : DVCondition(mod, level, ident)
|
|
169 {
|
|
170 }
|
|
171
|
|
172 int VersionCondition::include(Scope *sc, ScopeDsymbol *s)
|
|
173 {
|
|
174 //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
|
|
175 //if (ident) printf("\tident = '%s'\n", ident->toChars());
|
|
176 if (inc == 0)
|
|
177 {
|
|
178 inc = 2;
|
|
179 if (ident)
|
|
180 {
|
|
181 if (findCondition(mod->versionids, ident))
|
|
182 inc = 1;
|
|
183 else if (findCondition(global.params.versionids, ident))
|
|
184 inc = 1;
|
|
185 else
|
|
186 {
|
|
187 if (!mod->versionidsNot)
|
|
188 mod->versionidsNot = new Array();
|
|
189 mod->versionidsNot->push(ident->toChars());
|
|
190 }
|
|
191 }
|
|
192 else if (level <= global.params.versionlevel || level <= mod->versionlevel)
|
|
193 inc = 1;
|
|
194 }
|
|
195 return (inc == 1);
|
|
196 }
|
|
197
|
|
198 void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
|
199 {
|
|
200 if (ident)
|
|
201 buf->printf("version (%s)", ident->toChars());
|
|
202 else
|
|
203 buf->printf("version (%u)", level);
|
|
204 }
|
|
205
|
|
206
|
|
207 /**************************** StaticIfCondition *******************************/
|
|
208
|
|
209 StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
|
|
210 : Condition(loc)
|
|
211 {
|
|
212 this->exp = exp;
|
|
213 }
|
|
214
|
|
215 Condition *StaticIfCondition::syntaxCopy()
|
|
216 {
|
|
217 return new StaticIfCondition(loc, exp->syntaxCopy());
|
|
218 }
|
|
219
|
|
220 int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s)
|
|
221 {
|
|
222 #if 0
|
|
223 printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s);
|
|
224 if (s)
|
|
225 {
|
|
226 printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind());
|
|
227 }
|
|
228 #endif
|
|
229 if (inc == 0)
|
|
230 {
|
|
231 if (!sc)
|
|
232 {
|
|
233 error(loc, "static if conditional cannot be at global scope");
|
|
234 inc = 2;
|
|
235 return 0;
|
|
236 }
|
|
237
|
|
238 sc = sc->push(sc->scopesym);
|
|
239 sc->sd = s; // s gets any addMember()
|
|
240 sc->flags |= SCOPEstaticif;
|
|
241 Expression *e = exp->semantic(sc);
|
|
242 sc->pop();
|
|
243 e = e->optimize(WANTvalue | WANTinterpret);
|
|
244 if (e->isBool(TRUE))
|
|
245 inc = 1;
|
|
246 else if (e->isBool(FALSE))
|
|
247 inc = 2;
|
|
248 else
|
|
249 {
|
|
250 e->error("expression %s is not constant or does not evaluate to a bool", e->toChars());
|
|
251 inc = 2;
|
|
252 }
|
|
253 }
|
|
254 return (inc == 1);
|
|
255 }
|
|
256
|
|
257 void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
|
258 {
|
|
259 buf->writestring("static if(");
|
|
260 exp->toCBuffer(buf, hgs);
|
|
261 buf->writeByte(')');
|
|
262 }
|
|
263
|
|
264
|
|
265 /**************************** IftypeCondition *******************************/
|
|
266
|
|
267 IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec)
|
|
268 : Condition(loc)
|
|
269 {
|
|
270 this->targ = targ;
|
|
271 this->id = id;
|
|
272 this->tok = tok;
|
|
273 this->tspec = tspec;
|
|
274 }
|
|
275
|
|
276 Condition *IftypeCondition::syntaxCopy()
|
|
277 {
|
|
278 return new IftypeCondition(loc,
|
|
279 targ->syntaxCopy(),
|
|
280 id,
|
|
281 tok,
|
|
282 tspec ? tspec->syntaxCopy() : NULL);
|
|
283 }
|
|
284
|
|
285 int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd)
|
|
286 {
|
|
287 //printf("IftypeCondition::include()\n");
|
|
288 if (inc == 0)
|
|
289 {
|
|
290 if (!sc)
|
|
291 {
|
|
292 error(loc, "iftype conditional cannot be at global scope");
|
|
293 inc = 2;
|
|
294 return 0;
|
|
295 }
|
|
296 unsigned errors = global.errors;
|
|
297 global.gag++; // suppress printing of error messages
|
|
298 targ = targ->semantic(loc, sc);
|
|
299 global.gag--;
|
|
300 if (errors != global.errors) // if any errors happened
|
|
301 { inc = 2; // then condition is false
|
|
302 global.errors = errors;
|
|
303 }
|
|
304 else if (id && tspec)
|
|
305 {
|
|
306 /* Evaluate to TRUE if targ matches tspec.
|
|
307 * If TRUE, declare id as an alias for the specialized type.
|
|
308 */
|
|
309
|
|
310 MATCH m;
|
|
311 TemplateTypeParameter tp(loc, id, NULL, NULL);
|
|
312
|
|
313 TemplateParameters parameters;
|
|
314 parameters.setDim(1);
|
|
315 parameters.data[0] = (void *)&tp;
|
|
316
|
|
317 Objects dedtypes;
|
|
318 dedtypes.setDim(1);
|
|
319
|
|
320 m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes);
|
|
321 if (m == MATCHnomatch ||
|
|
322 (m != MATCHexact && tok == TOKequal))
|
|
323 inc = 2;
|
|
324 else
|
|
325 {
|
|
326 inc = 1;
|
|
327 Type *tded = (Type *)dedtypes.data[0];
|
|
328 if (!tded)
|
|
329 tded = targ;
|
|
330 Dsymbol *s = new AliasDeclaration(loc, id, tded);
|
|
331 s->semantic(sc);
|
|
332 sc->insert(s);
|
|
333 if (sd)
|
|
334 s->addMember(sc, sd, 1);
|
|
335 }
|
|
336 }
|
|
337 else if (id)
|
|
338 {
|
|
339 /* Declare id as an alias for type targ. Evaluate to TRUE
|
|
340 */
|
|
341 Dsymbol *s = new AliasDeclaration(loc, id, targ);
|
|
342 s->semantic(sc);
|
|
343 sc->insert(s);
|
|
344 if (sd)
|
|
345 s->addMember(sc, sd, 1);
|
|
346 inc = 1;
|
|
347 }
|
|
348 else if (tspec)
|
|
349 {
|
|
350 /* Evaluate to TRUE if targ matches tspec
|
|
351 */
|
|
352 tspec = tspec->semantic(loc, sc);
|
|
353 //printf("targ = %s\n", targ->toChars());
|
|
354 //printf("tspec = %s\n", tspec->toChars());
|
|
355 if (tok == TOKcolon)
|
|
356 { if (targ->implicitConvTo(tspec))
|
|
357 inc = 1;
|
|
358 else
|
|
359 inc = 2;
|
|
360 }
|
|
361 else /* == */
|
|
362 { if (targ->equals(tspec))
|
|
363 inc = 1;
|
|
364 else
|
|
365 inc = 2;
|
|
366 }
|
|
367 }
|
|
368 else
|
|
369 inc = 1;
|
|
370 //printf("inc = %d\n", inc);
|
|
371 }
|
|
372 return (inc == 1);
|
|
373 }
|
|
374
|
|
375 void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
|
|
376 {
|
|
377 buf->writestring("iftype(");
|
|
378 targ->toCBuffer(buf, id, hgs);
|
|
379 if (tspec)
|
|
380 {
|
|
381 if (tok == TOKcolon)
|
|
382 buf->writestring(" : ");
|
|
383 else
|
|
384 buf->writestring(" == ");
|
|
385 tspec->toCBuffer(buf, NULL, hgs);
|
|
386 }
|
|
387 buf->writeByte(')');
|
|
388 }
|
|
389
|
|
390
|