Mercurial > projects > ldc
annotate dmd/cond.c @ 314:8d98e42ece93 trunk
[svn r335] The basics of exception handling are in place.
Still need to make sure calls are turned into invokes everywhere. (NewExpression for instance)
Still some rough edges and corner cases to figure out.
Needs testing!
author | ChristianK |
---|---|
date | Wed, 02 Jul 2008 22:20:18 +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 |