Warn about "assert X,Y"
[delight/core.git] / dmd2 / traits.c
blob877c317786830b9fe7b00da8a10f05fe999b4b7a
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 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.
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include <assert.h>
15 #include <complex.h>
16 #include <math.h>
18 #if IN_GCC
19 // Issues with using -include total.h (defines integer_t) and then complex.h fails...
20 #undef integer_t
21 #endif
23 #ifdef __APPLE__
24 #define integer_t dmd_integer_t
25 #endif
27 #if IN_GCC
28 #include "mem.h"
29 #elif _WIN32
30 #include "..\root\mem.h"
31 #elif linux
32 #include "../root/mem.h"
33 #endif
35 //#include "port.h"
36 #include "mtype.h"
37 #include "init.h"
38 #include "expression.h"
39 #include "template.h"
40 #include "utf.h"
41 #include "enum.h"
42 #include "scope.h"
43 #include "statement.h"
44 #include "declaration.h"
45 #include "aggregate.h"
46 #include "import.h"
47 #include "id.h"
48 #include "dsymbol.h"
49 #include "module.h"
50 #include "attrib.h"
51 #include "hdrgen.h"
52 #include "parse.h"
54 #define LOGSEMANTIC 0
56 /************************************************
57 * Delegate to be passed to overloadApply() that looks
58 * for virtual functions.
61 struct Pvirtuals
63 Expression *e1;
64 Expressions *exps;
67 static int fpvirtuals(void *param, FuncDeclaration *f)
68 { Pvirtuals *p = (Pvirtuals *)param;
70 if (f->isVirtual())
71 { Expression *e;
73 if (p->e1->op == TOKdotvar)
74 { DotVarExp *dve = (DotVarExp *)p->e1;
75 e = new DotVarExp(0, dve->e1, f);
77 else
78 e = new DsymbolExp(0, f);
79 p->exps->push(e);
81 return 0;
84 /************************ TraitsExp ************************************/
86 Expression *TraitsExp::semantic(Scope *sc)
88 #if LOGSEMANTIC
89 printf("TraitsExp::semantic() %s\n", toChars());
90 #endif
91 if (ident != Id::compiles && ident != Id::isSame)
92 TemplateInstance::semanticTiargs(loc, sc, args, 1);
93 size_t dim = args ? args->dim : 0;
94 Object *o;
95 FuncDeclaration *f;
97 #define ISTYPE(cond) \
98 for (size_t i = 0; i < dim; i++) \
99 { Type *t = getType((Object *)args->data[i]); \
100 if (!t) \
101 goto Lfalse; \
102 if (!(cond)) \
103 goto Lfalse; \
105 if (!dim) \
106 goto Lfalse; \
107 goto Ltrue;
109 #define ISDSYMBOL(cond) \
110 for (size_t i = 0; i < dim; i++) \
111 { Dsymbol *s = getDsymbol((Object *)args->data[i]); \
112 if (!s) \
113 goto Lfalse; \
114 if (!(cond)) \
115 goto Lfalse; \
117 if (!dim) \
118 goto Lfalse; \
119 goto Ltrue;
123 if (ident == Id::isArithmetic)
125 ISTYPE(t->isintegral() || t->isfloating())
127 else if (ident == Id::isFloating)
129 ISTYPE(t->isfloating())
131 else if (ident == Id::isIntegral)
133 ISTYPE(t->isintegral())
135 else if (ident == Id::isScalar)
137 ISTYPE(t->isscalar())
139 else if (ident == Id::isUnsigned)
141 ISTYPE(t->isunsigned())
143 else if (ident == Id::isAssociativeArray)
145 ISTYPE(t->toBasetype()->ty == Taarray)
147 else if (ident == Id::isStaticArray)
149 ISTYPE(t->toBasetype()->ty == Tsarray)
151 else if (ident == Id::isAbstractClass)
153 ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract())
155 else if (ident == Id::isFinalClass)
157 ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal)
159 else if (ident == Id::isAbstractFunction)
161 ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract())
163 else if (ident == Id::isVirtualFunction)
165 ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual())
167 else if (ident == Id::isFinalFunction)
169 ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal())
171 else if (ident == Id::hasMember ||
172 ident == Id::getMember ||
173 ident == Id::getVirtualFunctions)
175 if (dim != 2)
176 goto Ldimerror;
177 Object *o = (Object *)args->data[0];
178 Expression *e = isExpression((Object *)args->data[1]);
179 if (!e)
180 { error("expression expected as second argument of __traits %s", ident->toChars());
181 goto Lfalse;
183 e = e->optimize(WANTvalue | WANTinterpret);
184 if (e->op != TOKstring)
185 { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars());
186 goto Lfalse;
188 StringExp *se = (StringExp *)e;
189 se = se->toUTF8(sc);
190 if (se->sz != 1)
191 { error("string must be chars");
192 goto Lfalse;
194 Identifier *id = Lexer::idPool((char *)se->string);
196 Type *t = isType(o);
197 e = isExpression(o);
198 Dsymbol *s = isDsymbol(o);
199 if (t)
200 e = new TypeDotIdExp(loc, t, id);
201 else if (e)
202 e = new DotIdExp(loc, e, id);
203 else if (s)
204 { e = new DsymbolExp(loc, s);
205 e = new DotIdExp(loc, e, id);
207 else
208 { error("invalid first argument");
209 goto Lfalse;
212 if (ident == Id::hasMember)
213 { /* Take any errors as meaning it wasn't found
215 unsigned errors = global.errors;
216 global.gag++;
217 e = e->semantic(sc);
218 global.gag--;
219 if (errors != global.errors)
220 { if (global.gag == 0)
221 global.errors = errors;
222 goto Lfalse;
224 else
225 goto Ltrue;
227 else if (ident == Id::getMember)
229 e = e->semantic(sc);
230 return e;
232 else if (ident == Id::getVirtualFunctions)
234 unsigned errors = global.errors;
235 Expression *ex = e;
236 e = e->semantic(sc);
237 if (errors < global.errors)
238 error("%s cannot be resolved", ex->toChars());
240 /* Create tuple of virtual function overloads of e
242 //e->dump(0);
243 Expressions *exps = new Expressions();
244 FuncDeclaration *f;
245 if (e->op == TOKvar)
246 { VarExp *ve = (VarExp *)e;
247 f = ve->var->isFuncDeclaration();
249 else if (e->op == TOKdotvar)
250 { DotVarExp *dve = (DotVarExp *)e;
251 f = dve->var->isFuncDeclaration();
253 else
254 f = NULL;
255 Pvirtuals p;
256 p.exps = exps;
257 p.e1 = e;
258 overloadApply(f, fpvirtuals, &p);
260 TupleExp *tup = new TupleExp(loc, exps);
261 return tup->semantic(sc);
263 else
264 assert(0);
266 else if (ident == Id::classInstanceSize)
268 if (dim != 1)
269 goto Ldimerror;
270 Object *o = (Object *)args->data[0];
271 Dsymbol *s = getDsymbol(o);
272 ClassDeclaration *cd;
273 if (!s || (cd = s->isClassDeclaration()) == NULL)
275 error("first argument is not a class");
276 goto Lfalse;
278 return new IntegerExp(loc, cd->structsize, Type::tsize_t);
280 else if (ident == Id::allMembers || ident == Id::derivedMembers)
282 if (dim != 1)
283 goto Ldimerror;
284 Object *o = (Object *)args->data[0];
285 Dsymbol *s = getDsymbol(o);
286 ScopeDsymbol *sd;
287 if (!s)
289 error("argument has no members");
290 goto Lfalse;
292 if ((sd = s->isScopeDsymbol()) == NULL)
294 error("%s %s has no members", s->kind(), s->toChars());
295 goto Lfalse;
297 Expressions *exps = new Expressions;
298 while (1)
299 { size_t dim = ScopeDsymbol::dim(sd->members);
300 for (size_t i = 0; i < dim; i++)
302 Dsymbol *sm = ScopeDsymbol::getNth(sd->members, i);
303 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
304 if (sm->ident)
306 //printf("\t%s\n", sm->ident->toChars());
307 char *str = sm->ident->toChars();
309 /* Skip if already present in exps[]
311 for (size_t j = 0; j < exps->dim; j++)
312 { StringExp *se2 = (StringExp *)exps->data[j];
313 if (strcmp(str, (char *)se2->string) == 0)
314 goto Lnext;
317 StringExp *se = new StringExp(loc, str);
318 exps->push(se);
320 Lnext:
323 ClassDeclaration *cd = sd->isClassDeclaration();
324 if (cd && cd->baseClass && ident == Id::allMembers)
325 sd = cd->baseClass; // do again with base class
326 else
327 break;
329 Expression *e = new ArrayLiteralExp(loc, exps);
330 e = e->semantic(sc);
331 return e;
333 else if (ident == Id::compiles)
335 /* Determine if all the objects - types, expressions, or symbols -
336 * compile without error
338 if (!dim)
339 goto Lfalse;
341 for (size_t i = 0; i < dim; i++)
342 { Object *o = (Object *)args->data[i];
343 Type *t;
344 Expression *e;
345 Dsymbol *s;
347 unsigned errors = global.errors;
348 global.gag++;
350 t = isType(o);
351 if (t)
352 { t->resolve(loc, sc, &e, &t, &s);
353 if (t)
354 t->semantic(loc, sc);
355 else if (e)
356 e->semantic(sc);
358 else
359 { e = isExpression(o);
360 if (e)
361 e->semantic(sc);
364 global.gag--;
365 if (errors != global.errors)
366 { if (global.gag == 0)
367 global.errors = errors;
368 goto Lfalse;
371 goto Ltrue;
373 else if (ident == Id::isSame)
374 { /* Determine if two symbols are the same
376 if (dim != 2)
377 goto Ldimerror;
378 TemplateInstance::semanticTiargs(loc, sc, args, 0);
379 Object *o1 = (Object *)args->data[0];
380 Object *o2 = (Object *)args->data[1];
381 Dsymbol *s1 = getDsymbol(o1);
382 Dsymbol *s2 = getDsymbol(o2);
384 #if 0
385 printf("o1: %p\n", o1);
386 printf("o2: %p\n", o2);
387 if (!s1)
388 { Expression *ea = isExpression(o1);
389 if (ea)
390 printf("%s\n", ea->toChars());
391 Type *ta = isType(o1);
392 if (ta)
393 printf("%s\n", ta->toChars());
394 goto Lfalse;
396 else
397 printf("%s %s\n", s1->kind(), s1->toChars());
398 #endif
399 if (!s1 && !s2)
400 { Expression *ea1 = isExpression(o1);
401 Expression *ea2 = isExpression(o2);
402 if (ea1 && ea2 && ea1->equals(ea2))
403 goto Ltrue;
406 if (!s1 || !s2)
407 goto Lfalse;
409 s1 = s1->toAlias();
410 s2 = s2->toAlias();
412 if (s1 == s2)
413 goto Ltrue;
414 else
415 goto Lfalse;
417 else
418 { error("unrecognized trait %s", ident->toChars());
419 goto Lfalse;
422 return NULL;
424 Lnottype:
425 error("%s is not a type", o->toChars());
426 goto Lfalse;
428 Ldimerror:
429 error("wrong number of arguments %d", dim);
430 goto Lfalse;
433 Lfalse:
434 return new IntegerExp(loc, 0, Type::tbool);
436 Ltrue:
437 return new IntegerExp(loc, 1, Type::tbool);