Mercurial > projects > ddmd
annotate dmd/InterfaceDeclaration.d @ 187:b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
author | Abscissa |
---|---|
date | Tue, 07 Jun 2011 23:37:34 -0400 |
parents | e3afd1303184 |
children |
rev | line source |
---|---|
0 | 1 module dmd.InterfaceDeclaration; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.ClassDeclaration; |
5 import dmd.Loc; | |
6 import dmd.DsymbolTable; | |
7 import dmd.STC; | |
8 import dmd.Type; | |
9 import dmd.TY; | |
10 import dmd.LINK; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
125
diff
changeset
|
11 import dmd.Parameter; |
0 | 12 import dmd.Util; |
13 import dmd.TypeTuple; | |
14 import dmd.PROT; | |
15 import dmd.TypeClass; | |
16 import dmd.Identifier; | |
17 import dmd.ArrayTypes; | |
18 import dmd.Dsymbol; | |
19 import dmd.Scope; | |
20 import dmd.Global; | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
21 import dmd.Module; |
0 | 22 import dmd.BaseClass; |
23 import dmd.Id; | |
24 | |
25 import dmd.backend.Symbol; | |
26 import dmd.backend.TYM; | |
27 import dmd.backend.dt_t; | |
28 import dmd.backend.Util; | |
29 import dmd.codegen.Util; | |
30 import dmd.backend.SC; | |
31 import dmd.backend.FL; | |
32 import dmd.backend.LIST; | |
33 import dmd.backend.SFL; | |
34 | |
187
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
178
diff
changeset
|
35 import dmd.DDMDExtensions; |
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
178
diff
changeset
|
36 |
0 | 37 class InterfaceDeclaration : ClassDeclaration |
38 { | |
187
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
178
diff
changeset
|
39 mixin insertMemberExtension!(typeof(this)); |
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
178
diff
changeset
|
40 |
0 | 41 version (DMDV2) { |
42 bool cpp; // true if this is a C++ interface | |
43 } | |
44 this(Loc loc, Identifier id, BaseClasses baseclasses) | |
45 { | |
178 | 46 register(); |
0 | 47 super(loc, id, baseclasses); |
176 | 48 |
0 | 49 if (id is Id.IUnknown) // IUnknown is the root of all COM interfaces |
50 { | |
51 com = true; | |
52 cpp = true; // IUnknown is also a C++ interface | |
53 } | |
54 } | |
176 | 55 |
72 | 56 override Dsymbol syntaxCopy(Dsymbol s) |
0 | 57 { |
123 | 58 InterfaceDeclaration id; |
59 | |
60 if (s) | |
61 id = cast(InterfaceDeclaration)s; | |
62 else | |
63 id = new InterfaceDeclaration(loc, ident, null); | |
64 | |
65 ClassDeclaration.syntaxCopy(id); | |
66 return id; | |
0 | 67 } |
176 | 68 |
72 | 69 override void semantic(Scope sc) |
0 | 70 { |
71 //printf("InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); | |
72 if (inuse) | |
73 return; | |
74 | |
75 if (!sc) | |
76 sc = scope_; | |
77 if (!parent && sc.parent && !sc.parent.isModule()) | |
78 parent = sc.parent; | |
79 | |
80 type = type.semantic(loc, sc); | |
81 handle = type; | |
82 | |
83 if (!members) // if forward reference | |
176 | 84 { |
0 | 85 //printf("\tinterface '%s' is forward referenced\n", toChars()); |
86 return; | |
87 } | |
88 if (symtab) // if already done | |
176 | 89 { |
0 | 90 if (!scope_) |
91 return; | |
92 } | |
93 else | |
94 symtab = new DsymbolTable(); | |
95 | |
96 Scope scx = null; | |
97 if (scope_) | |
176 | 98 { |
0 | 99 sc = scope_; |
100 scx = scope_; // save so we don't make redundant copies | |
101 scope_ = null; | |
102 } | |
103 | |
104 if (sc.stc & STC.STCdeprecated) | |
105 { | |
106 isdeprecated = true; | |
107 } | |
108 | |
109 // Expand any tuples in baseclasses[] | |
89 | 110 for (size_t i = 0; i < baseclasses.dim; ) |
176 | 111 { |
125
767a01c2a272
BaseClasses -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
112 auto b = baseclasses[0]; |
0 | 113 b.type = b.type.semantic(loc, sc); |
114 Type tb = b.type.toBasetype(); | |
115 | |
116 if (tb.ty == TY.Ttuple) | |
117 { TypeTuple tup = cast(TypeTuple)tb; | |
118 PROT protection = b.protection; | |
119 baseclasses.remove(i); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
125
diff
changeset
|
120 size_t dim = Parameter.dim(tup.arguments); |
0 | 121 for (size_t j = 0; j < dim; j++) |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
125
diff
changeset
|
122 { auto arg = Parameter.getNth(tup.arguments, j); |
0 | 123 b = new BaseClass(arg.type, protection); |
125
767a01c2a272
BaseClasses -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
124 baseclasses.insert(i + j, b); |
0 | 125 } |
126 } | |
127 else | |
128 i++; | |
129 } | |
130 | |
131 if (!baseclasses.dim && sc.linkage == LINK.LINKcpp) | |
132 cpp = 1; | |
133 | |
134 // Check for errors, handle forward references | |
89 | 135 for (size_t i = 0; i < baseclasses.dim; ) |
176 | 136 { |
0 | 137 TypeClass tc; |
138 BaseClass b; | |
139 Type tb; | |
140 | |
125
767a01c2a272
BaseClasses -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
141 b = baseclasses[i]; |
0 | 142 b.type = b.type.semantic(loc, sc); |
143 tb = b.type.toBasetype(); | |
144 if (tb.ty == TY.Tclass) | |
145 tc = cast(TypeClass)tb; | |
146 else | |
147 tc = null; | |
148 if (!tc || !tc.sym.isInterfaceDeclaration()) | |
149 { | |
150 error("base type must be interface, not %s", b.type.toChars()); | |
151 baseclasses.remove(i); | |
152 continue; | |
153 } | |
154 else | |
155 { | |
156 // Check for duplicate interfaces | |
157 for (size_t j = 0; j < i; j++) | |
158 { | |
125
767a01c2a272
BaseClasses -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
159 auto b2 = baseclasses[j]; |
0 | 160 if (b2.base is tc.sym) |
161 error("inherits from duplicate interface %s", b2.base.toChars()); | |
162 } | |
163 | |
164 b.base = tc.sym; | |
165 if (b.base == this || isBaseOf2(b.base)) | |
166 { | |
167 error("circular inheritance of interface"); | |
168 baseclasses.remove(i); | |
169 continue; | |
170 } | |
171 if (!b.base.symtab) | |
176 | 172 { |
0 | 173 // Try to resolve forward reference |
174 if (sc.mustsemantic && b.base.scope_) | |
175 b.base.semantic(null); | |
176 } | |
177 if (!b.base.symtab || b.base.scope_ || b.base.inuse) | |
178 { | |
179 //error("forward reference of base class %s", baseClass.toChars()); | |
180 // Forward reference of base, try again later | |
181 //printf("\ttry later, forward reference of base %s\n", b.base.toChars()); | |
87
b17640f0e4e8
Fixed a bug with a Scope.this(Scope enclosing) being called instead of Scope.clone() method (as a copy ctor replacement)
korDen
parents:
77
diff
changeset
|
182 scope_ = scx ? scx : sc.clone(); |
0 | 183 scope_.setNoFree(); |
184 scope_.module_.addDeferredSemantic(this); | |
185 return; | |
186 } | |
187 } | |
188 static if (false) { | |
189 // Inherit const/invariant from base class | |
190 storage_class |= b.base.storage_class & STC.STC_TYPECTOR; | |
191 } | |
192 i++; | |
193 } | |
194 | |
195 interfaces_dim = baseclasses.dim; | |
125
767a01c2a272
BaseClasses -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
196 interfaces = baseclasses.ptr; |
0 | 197 |
198 interfaceSemantic(sc); | |
199 | |
200 if (vtblOffset()) | |
201 vtbl.push(cast(void*)this); // leave room at vtbl[0] for classinfo | |
202 | |
203 // Cat together the vtbl[]'s from base interfaces | |
89 | 204 for (size_t i = 0; i < interfaces_dim; i++) |
176 | 205 { |
0 | 206 BaseClass b = interfaces[i]; |
207 | |
208 // Skip if b has already appeared | |
209 for (int k = 0; k < i; k++) | |
210 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
125
diff
changeset
|
211 if (b == interfaces[k]) |
0 | 212 goto Lcontinue; |
213 } | |
214 | |
215 // Copy vtbl[] from base class | |
216 if (b.base.vtblOffset()) | |
217 { int d = b.base.vtbl.dim; | |
218 if (d > 1) | |
219 { | |
220 vtbl.reserve(d - 1); | |
221 for (int j = 1; j < d; j++) | |
222 vtbl.push(b.base.vtbl.data[j]); | |
223 } | |
224 } | |
225 else | |
226 { | |
227 vtbl.append(b.base.vtbl); | |
228 } | |
229 | |
230 Lcontinue: | |
231 ; | |
232 } | |
233 | |
234 protection = sc.protection; | |
235 storage_class |= sc.stc & STC.STC_TYPECTOR; | |
236 | |
77
ad4792a1cfd6
more D-ification container accessing
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
237 foreach(Dsymbol s; members) |
13 | 238 s.addMember(sc, this, true); |
0 | 239 |
240 sc = sc.push(this); | |
241 sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | | |
242 STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); | |
243 sc.stc |= storage_class & STC.STC_TYPECTOR; | |
244 sc.parent = this; | |
245 if (isCOMinterface()) | |
246 sc.linkage = LINK.LINKwindows; | |
247 else if (isCPPinterface()) | |
248 sc.linkage = LINK.LINKcpp; | |
249 sc.structalign = 8; | |
250 structalign = sc.structalign; | |
251 sc.offset = PTRSIZE * 2; | |
252 inuse++; | |
77
ad4792a1cfd6
more D-ification container accessing
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
253 foreach(Dsymbol s; members) |
0 | 254 s.semantic(sc); |
255 inuse--; | |
256 //members.print(); | |
257 sc.pop(); | |
258 //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); | |
259 } | |
176 | 260 |
72 | 261 override bool isBaseOf(ClassDeclaration cd, int* poffset) |
0 | 262 { |
263 uint j; | |
264 | |
265 //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars()); | |
266 assert(!baseClass); | |
267 for (j = 0; j < cd.interfaces_dim; j++) | |
268 { | |
269 BaseClass b = cd.interfaces[j]; | |
270 | |
271 //printf("\tbase %s\n", b.base.toChars()); | |
272 if (this == b.base) | |
273 { | |
274 //printf("\tfound at offset %d\n", b.offset); | |
275 if (poffset) | |
176 | 276 { |
0 | 277 *poffset = b.offset; |
278 if (j && cd.isInterfaceDeclaration()) | |
279 *poffset = OFFSET_RUNTIME; | |
280 } | |
281 return true; | |
282 } | |
283 if (isBaseOf(b, poffset)) | |
176 | 284 { |
0 | 285 if (j && poffset && cd.isInterfaceDeclaration()) |
286 *poffset = OFFSET_RUNTIME; | |
287 return true; | |
288 } | |
289 } | |
290 | |
291 if (cd.baseClass && isBaseOf(cd.baseClass, poffset)) | |
292 return true; | |
293 | |
294 if (poffset) | |
295 *poffset = 0; | |
296 return false; | |
297 } | |
176 | 298 |
0 | 299 bool isBaseOf(BaseClass bc, int* poffset) |
300 { | |
64 | 301 //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", toChars(), bc.base.toChars()); |
302 for (uint j = 0; j < bc.baseInterfaces.length; j++) | |
303 { | |
304 BaseClass b = bc.baseInterfaces[j]; | |
305 | |
306 if (this == b.base) | |
307 { | |
308 if (poffset) | |
176 | 309 { |
64 | 310 *poffset = b.offset; |
311 if (j && bc.base.isInterfaceDeclaration()) | |
312 *poffset = OFFSET_RUNTIME; | |
313 } | |
166
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
314 return true; |
64 | 315 } |
316 if (isBaseOf(b, poffset)) | |
176 | 317 { |
64 | 318 if (j && poffset && bc.base.isInterfaceDeclaration()) |
319 *poffset = OFFSET_RUNTIME; | |
166
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
320 return true; |
64 | 321 } |
322 } | |
323 if (poffset) | |
324 *poffset = 0; | |
166
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
325 return false; |
0 | 326 } |
176 | 327 |
72 | 328 override string kind() |
0 | 329 { |
330 assert(false); | |
331 } | |
176 | 332 |
0 | 333 /**************************************** |
334 * Determine if slot 0 of the vtbl[] is reserved for something else. | |
335 * For class objects, yes, this is where the ClassInfo ptr goes. | |
336 * For COM interfaces, no. | |
337 * For non-COM interfaces, yes, this is where the Interface ptr goes. | |
338 */ | |
72 | 339 override int vtblOffset() |
0 | 340 { |
341 if (isCOMinterface() || isCPPinterface()) | |
342 return 0; | |
343 return 1; | |
344 } | |
176 | 345 |
0 | 346 version (DMDV2) { |
72 | 347 override bool isCPPinterface() |
0 | 348 { |
349 return cpp; | |
350 } | |
351 } | |
72 | 352 override bool isCOMinterface() |
0 | 353 { |
354 return com; | |
355 } | |
356 | |
72 | 357 override void toObjFile(int multiobj) // compile to .obj file |
0 | 358 { |
359 uint offset; | |
360 Symbol* sinit; | |
361 SC scclass; | |
362 | |
363 //printf("InterfaceDeclaration.toObjFile('%s')\n", toChars()); | |
364 | |
365 if (!members) | |
366 return; | |
367 | |
368 if (global.params.symdebug) | |
369 toDebug(); | |
370 | |
371 scclass = SCglobal; | |
372 if (inTemplateInstance()) | |
373 scclass = SCcomdat; | |
374 | |
375 // Put out the members | |
77
ad4792a1cfd6
more D-ification container accessing
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
376 foreach(Dsymbol member; members) |
0 | 377 { |
378 if (!member.isFuncDeclaration()) | |
379 member.toObjFile(0); | |
380 } | |
381 | |
382 // Generate C symbols | |
383 toSymbol(); | |
384 | |
385 ////////////////////////////////////////////// | |
386 | |
387 // Put out the TypeInfo | |
388 type.getTypeInfo(null); | |
389 type.vtinfo.toObjFile(multiobj); | |
390 | |
391 ////////////////////////////////////////////// | |
392 | |
393 // Put out the ClassInfo | |
394 csym.Sclass = scclass; | |
395 csym.Sfl = FLdata; | |
396 | |
397 /* The layout is: | |
398 { | |
399 void **vptr; | |
400 monitor_t monitor; | |
401 byte[] initializer; // static initialization data | |
402 char[] name; // class name | |
403 void *[] vtbl; | |
404 Interface[] interfaces; | |
405 Object *base; // base class | |
406 void *destructor; | |
407 void *invariant; // class invariant | |
408 uint flags; | |
409 void *deallocator; | |
410 OffsetTypeInfo[] offTi; | |
411 void *defaultConstructor; | |
412 #if DMDV2 | |
413 const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function | |
414 #endif | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
125
diff
changeset
|
415 //TypeInfo typeinfo; |
0 | 416 } |
417 */ | |
418 dt_t *dt = null; | |
419 | |
166
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
420 if (global.classinfo) |
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
421 dtxoff(&dt, global.classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo |
0 | 422 else |
423 dtdword(&dt, 0); // BUG: should be an assert() | |
424 dtdword(&dt, 0); // monitor | |
425 | |
426 // initializer[] | |
427 dtdword(&dt, 0); // size | |
428 dtdword(&dt, 0); // initializer | |
429 | |
430 // name[] | |
431 string name = toPrettyChars(); | |
432 size_t namelen = name.length; | |
433 dtdword(&dt, namelen); | |
434 dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); | |
435 | |
436 // vtbl[] | |
437 dtdword(&dt, 0); | |
438 dtdword(&dt, 0); | |
439 | |
440 // vtblInterfaces.data[] | |
441 dtdword(&dt, vtblInterfaces.dim); | |
442 if (vtblInterfaces.dim) | |
443 { | |
166
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
444 if (global.classinfo) |
d8565fbd755c
Moved object and classinfo from ClassDeclaration to Global (as part of getting rid of the global state)
korDen
parents:
130
diff
changeset
|
445 assert(global.classinfo.structsize == CLASSINFO_SIZE); |
0 | 446 offset = CLASSINFO_SIZE; |
447 dtxoff(&dt, csym, offset, TYnptr); // (*) | |
448 } | |
449 else | |
450 dtdword(&dt, 0); | |
451 | |
452 // base | |
453 assert(!baseClass); | |
454 dtdword(&dt, 0); | |
455 | |
456 // dtor | |
457 dtdword(&dt, 0); | |
458 | |
459 // invariant | |
460 dtdword(&dt, 0); | |
461 | |
462 // flags | |
463 dtdword(&dt, 4 | isCOMinterface() | 32); | |
464 | |
465 // deallocator | |
466 dtdword(&dt, 0); | |
467 | |
468 // offTi[] | |
469 dtdword(&dt, 0); | |
470 dtdword(&dt, 0); // null for now, fix later | |
471 | |
472 // defaultConstructor | |
473 dtdword(&dt, 0); | |
474 | |
475 version (DMDV2) { | |
476 // xgetMembers | |
477 dtdword(&dt, 0); | |
478 } | |
479 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
125
diff
changeset
|
480 //dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo |
0 | 481 |
482 ////////////////////////////////////////////// | |
483 | |
484 // Put out vtblInterfaces.data[]. Must immediately follow csym, because | |
485 // of the fixup (*) | |
486 | |
487 offset += vtblInterfaces.dim * (4 * PTRSIZE); | |
125
767a01c2a272
BaseClasses -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
123
diff
changeset
|
488 foreach (b; vtblInterfaces) |
176 | 489 { |
0 | 490 ClassDeclaration id = b.base; |
491 | |
492 // ClassInfo | |
493 dtxoff(&dt, id.toSymbol(), 0, TYnptr); | |
494 | |
495 // vtbl[] | |
496 dtdword(&dt, 0); | |
497 dtdword(&dt, 0); | |
498 | |
499 // this offset | |
500 dtdword(&dt, b.offset); | |
501 } | |
502 | |
503 csym.Sdt = dt; | |
504 version (ELFOBJ) { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
505 csym.Sseg = Segment.CDATA; |
0 | 506 } |
507 version (MACHOBJ) { | |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
508 csym.Sseg = Segment.DATA; |
0 | 509 } |
510 outdata(csym); | |
511 if (isExport()) | |
512 obj_export(csym,0); | |
513 } | |
514 | |
515 /************************************* | |
516 * Create the "InterfaceInfo" symbol | |
517 */ | |
72 | 518 override Symbol* toSymbol() |
0 | 519 { |
520 if (!csym) | |
521 { | |
522 Symbol *s; | |
523 | |
176 | 524 s = toSymbolX("__Interface", SCextern, global.scc.Stype, "Z"); |
0 | 525 s.Sfl = FLextern; |
526 s.Sflags |= SFLnodebug; | |
527 csym = s; | |
528 slist_add(s); | |
529 } | |
530 return csym; | |
531 } | |
532 | |
72 | 533 override InterfaceDeclaration isInterfaceDeclaration() { return this; } |
22
fd4acc376c45
Implemented object file output and linking on linux.
Robert Clipsham <robert@octarineparrot.com>
parents:
0
diff
changeset
|
534 } |