Mercurial > projects > ldc
annotate dmd/cond.c @ 341:1bb99290e03a trunk
[svn r362] Started merging the old 'test' dir as well as the newer 'tangotests' dir into 'tests/mini' and 'tests/minicomplex'.
author | lindquist |
---|---|
date | Sun, 13 Jul 2008 02:51:19 +0200 |
parents | 665b81613475 |
children | cc40db549aea |
rev | line source |
---|---|
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 { | |
275
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
1
diff
changeset
|
130 "DigitalMars", "LLVM", "LLVMDC", |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
1
diff
changeset
|
131 "LLVM64", "LLVM_X86_FP80", |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
1
diff
changeset
|
132 "X86", "X86_64", "PPC", "PPC64", |
1 | 133 "Windows", "Win32", "Win64", |
134 "linux", | |
135 "LittleEndian", "BigEndian", | |
136 "all", | |
137 "none", | |
138 }; | |
139 | |
140 for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) | |
141 { | |
142 if (strcmp(ident, reserved[i]) == 0) | |
143 goto Lerror; | |
144 } | |
145 | |
146 if (ident[0] == 'D' && ident[1] == '_') | |
147 goto Lerror; | |
148 | |
149 return; | |
150 | |
151 Lerror: | |
152 error(loc, "version identifier '%s' is reserved and cannot be set", ident); | |
153 } | |
154 | |
155 void VersionCondition::addGlobalIdent(char *ident) | |
156 { | |
157 checkPredefined(0, ident); | |
158 addPredefinedGlobalIdent(ident); | |
159 } | |
160 | |
161 void VersionCondition::addPredefinedGlobalIdent(char *ident) | |
162 { | |
163 if (!global.params.versionids) | |
164 global.params.versionids = new Array(); | |
165 global.params.versionids->push(ident); | |
166 } | |
167 | |
168 | |
169 VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) | |
170 : DVCondition(mod, level, ident) | |
171 { | |
172 } | |
173 | |
174 int VersionCondition::include(Scope *sc, ScopeDsymbol *s) | |
175 { | |
176 //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); | |
177 //if (ident) printf("\tident = '%s'\n", ident->toChars()); | |
178 if (inc == 0) | |
179 { | |
180 inc = 2; | |
181 if (ident) | |
182 { | |
183 if (findCondition(mod->versionids, ident)) | |
184 inc = 1; | |
185 else if (findCondition(global.params.versionids, ident)) | |
186 inc = 1; | |
187 else | |
188 { | |
189 if (!mod->versionidsNot) | |
190 mod->versionidsNot = new Array(); | |
191 mod->versionidsNot->push(ident->toChars()); | |
192 } | |
193 } | |
194 else if (level <= global.params.versionlevel || level <= mod->versionlevel) | |
195 inc = 1; | |
196 } | |
197 return (inc == 1); | |
198 } | |
199 | |
200 void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
201 { | |
202 if (ident) | |
203 buf->printf("version (%s)", ident->toChars()); | |
204 else | |
205 buf->printf("version (%u)", level); | |
206 } | |
207 | |
208 | |
209 /**************************** StaticIfCondition *******************************/ | |
210 | |
211 StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) | |
212 : Condition(loc) | |
213 { | |
214 this->exp = exp; | |
215 } | |
216 | |
217 Condition *StaticIfCondition::syntaxCopy() | |
218 { | |
219 return new StaticIfCondition(loc, exp->syntaxCopy()); | |
220 } | |
221 | |
222 int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) | |
223 { | |
224 #if 0 | |
225 printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); | |
226 if (s) | |
227 { | |
228 printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); | |
229 } | |
230 #endif | |
231 if (inc == 0) | |
232 { | |
233 if (!sc) | |
234 { | |
235 error(loc, "static if conditional cannot be at global scope"); | |
236 inc = 2; | |
237 return 0; | |
238 } | |
239 | |
240 sc = sc->push(sc->scopesym); | |
241 sc->sd = s; // s gets any addMember() | |
242 sc->flags |= SCOPEstaticif; | |
243 Expression *e = exp->semantic(sc); | |
244 sc->pop(); | |
245 e = e->optimize(WANTvalue | WANTinterpret); | |
246 if (e->isBool(TRUE)) | |
247 inc = 1; | |
248 else if (e->isBool(FALSE)) | |
249 inc = 2; | |
250 else | |
251 { | |
252 e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); | |
253 inc = 2; | |
254 } | |
255 } | |
256 return (inc == 1); | |
257 } | |
258 | |
259 void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
260 { | |
261 buf->writestring("static if("); | |
262 exp->toCBuffer(buf, hgs); | |
263 buf->writeByte(')'); | |
264 } | |
265 | |
266 | |
267 /**************************** IftypeCondition *******************************/ | |
268 | |
269 IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) | |
270 : Condition(loc) | |
271 { | |
272 this->targ = targ; | |
273 this->id = id; | |
274 this->tok = tok; | |
275 this->tspec = tspec; | |
276 } | |
277 | |
278 Condition *IftypeCondition::syntaxCopy() | |
279 { | |
280 return new IftypeCondition(loc, | |
281 targ->syntaxCopy(), | |
282 id, | |
283 tok, | |
284 tspec ? tspec->syntaxCopy() : NULL); | |
285 } | |
286 | |
287 int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) | |
288 { | |
289 //printf("IftypeCondition::include()\n"); | |
290 if (inc == 0) | |
291 { | |
292 if (!sc) | |
293 { | |
294 error(loc, "iftype conditional cannot be at global scope"); | |
295 inc = 2; | |
296 return 0; | |
297 } | |
298 unsigned errors = global.errors; | |
299 global.gag++; // suppress printing of error messages | |
300 targ = targ->semantic(loc, sc); | |
301 global.gag--; | |
302 if (errors != global.errors) // if any errors happened | |
303 { inc = 2; // then condition is false | |
304 global.errors = errors; | |
305 } | |
306 else if (id && tspec) | |
307 { | |
308 /* Evaluate to TRUE if targ matches tspec. | |
309 * If TRUE, declare id as an alias for the specialized type. | |
310 */ | |
311 | |
312 MATCH m; | |
313 TemplateTypeParameter tp(loc, id, NULL, NULL); | |
314 | |
315 TemplateParameters parameters; | |
316 parameters.setDim(1); | |
317 parameters.data[0] = (void *)&tp; | |
318 | |
319 Objects dedtypes; | |
320 dedtypes.setDim(1); | |
321 | |
322 m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); | |
323 if (m == MATCHnomatch || | |
324 (m != MATCHexact && tok == TOKequal)) | |
325 inc = 2; | |
326 else | |
327 { | |
328 inc = 1; | |
329 Type *tded = (Type *)dedtypes.data[0]; | |
330 if (!tded) | |
331 tded = targ; | |
332 Dsymbol *s = new AliasDeclaration(loc, id, tded); | |
333 s->semantic(sc); | |
334 sc->insert(s); | |
335 if (sd) | |
336 s->addMember(sc, sd, 1); | |
337 } | |
338 } | |
339 else if (id) | |
340 { | |
341 /* Declare id as an alias for type targ. Evaluate to TRUE | |
342 */ | |
343 Dsymbol *s = new AliasDeclaration(loc, id, targ); | |
344 s->semantic(sc); | |
345 sc->insert(s); | |
346 if (sd) | |
347 s->addMember(sc, sd, 1); | |
348 inc = 1; | |
349 } | |
350 else if (tspec) | |
351 { | |
352 /* Evaluate to TRUE if targ matches tspec | |
353 */ | |
354 tspec = tspec->semantic(loc, sc); | |
355 //printf("targ = %s\n", targ->toChars()); | |
356 //printf("tspec = %s\n", tspec->toChars()); | |
357 if (tok == TOKcolon) | |
358 { if (targ->implicitConvTo(tspec)) | |
359 inc = 1; | |
360 else | |
361 inc = 2; | |
362 } | |
363 else /* == */ | |
364 { if (targ->equals(tspec)) | |
365 inc = 1; | |
366 else | |
367 inc = 2; | |
368 } | |
369 } | |
370 else | |
371 inc = 1; | |
372 //printf("inc = %d\n", inc); | |
373 } | |
374 return (inc == 1); | |
375 } | |
376 | |
377 void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
378 { | |
379 buf->writestring("iftype("); | |
380 targ->toCBuffer(buf, id, hgs); | |
381 if (tspec) | |
382 { | |
383 if (tok == TOKcolon) | |
384 buf->writestring(" : "); | |
385 else | |
386 buf->writestring(" == "); | |
387 tspec->toCBuffer(buf, NULL, hgs); | |
388 } | |
389 buf->writeByte(')'); | |
390 } | |
391 | |
392 |