Mercurial > projects > ldc
annotate dmd/module.c @ 650:aa6a0b7968f7
Added test case for bug #100
Removed dubious check for not emitting static private global in other modules without access. This should be handled properly somewhere else, it's causing unresolved global errors for stuff that should work (in MiniD)
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 05 Oct 2008 17:28:15 +0200 |
parents | 2a0bcf7f7b3d |
children | eef8ac26c66c |
rev | line source |
---|---|
336 | 1 |
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. | |
10 | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <assert.h> | |
14 | |
15 #if _MSC_VER || __MINGW32__ | |
16 #include <malloc.h> | |
17 #endif | |
18 | |
19 #if IN_GCC | |
20 #include "gdc_alloca.h" | |
21 #endif | |
22 | |
23 #include "mem.h" | |
24 | |
25 #include "mars.h" | |
26 #include "module.h" | |
27 #include "parse.h" | |
28 #include "scope.h" | |
29 #include "identifier.h" | |
30 #include "id.h" | |
31 #include "import.h" | |
32 #include "dsymbol.h" | |
33 #include "hdrgen.h" | |
34 #include "lexer.h" | |
35 | |
36 #define MARS 1 | |
37 #include "html.h" | |
38 | |
39 #ifdef IN_GCC | |
40 #include "d-dmd-gcc.h" | |
41 #endif | |
42 | |
43 ClassDeclaration *Module::moduleinfo; | |
44 | |
45 Module *Module::rootModule; | |
46 DsymbolTable *Module::modules; | |
47 Array Module::amodules; | |
48 | |
49 Array Module::deferred; // deferred Dsymbol's needing semantic() run on them | |
50 unsigned Module::dprogress; | |
51 | |
52 void Module::init() | |
53 { | |
54 modules = new DsymbolTable(); | |
55 } | |
56 | |
57 Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) | |
58 : Package(ident) | |
59 { | |
60 FileName *srcfilename; | |
61 | |
62 // printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); | |
63 this->arg = filename; | |
64 md = NULL; | |
65 errors = 0; | |
66 numlines = 0; | |
67 members = NULL; | |
68 isHtml = 0; | |
69 isDocFile = 0; | |
70 needmoduleinfo = 0; | |
71 #ifdef IN_GCC | |
72 strictlyneedmoduleinfo = 0; | |
73 #endif | |
74 insearch = 0; | |
75 searchCacheIdent = NULL; | |
76 searchCacheSymbol = NULL; | |
77 searchCacheFlags = 0; | |
78 semanticstarted = 0; | |
79 semanticdone = 0; | |
80 decldefs = NULL; | |
81 vmoduleinfo = NULL; | |
82 massert = NULL; | |
83 marray = NULL; | |
84 sictor = NULL; | |
85 sctor = NULL; | |
86 sdtor = NULL; | |
87 stest = NULL; | |
88 sfilename = NULL; | |
89 root = 0; | |
90 importedFrom = NULL; | |
91 srcfile = NULL; | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
92 objfile = NULL; |
336 | 93 docfile = NULL; |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
94 hdrfile = NULL; |
336 | 95 |
96 debuglevel = 0; | |
97 debugids = NULL; | |
98 debugidsNot = NULL; | |
99 versionlevel = 0; | |
100 versionids = NULL; | |
101 versionidsNot = NULL; | |
102 | |
103 macrotable = NULL; | |
104 escapetable = NULL; | |
105 doppelganger = 0; | |
106 cov = NULL; | |
107 covb = NULL; | |
108 | |
109 srcfilename = FileName::defaultExt(filename, global.mars_ext); | |
110 if (!srcfilename->equalsExt(global.mars_ext) && | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
486
diff
changeset
|
111 !srcfilename->equalsExt(global.hdr_ext) && |
336 | 112 !srcfilename->equalsExt("dd")) |
113 { | |
114 if (srcfilename->equalsExt("html") || | |
115 srcfilename->equalsExt("htm") || | |
116 srcfilename->equalsExt("xhtml")) | |
117 isHtml = 1; | |
118 else | |
119 { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); | |
120 fatal(); | |
121 } | |
122 } | |
123 srcfile = new File(srcfilename); | |
124 | |
486
a34078905d01
Added pragma(llvmdc, "string") for misc per-module compiler configuration, currently "string" can only be "verbose" which forces -vv for module it appears in.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
125 // LLVMDC |
a34078905d01
Added pragma(llvmdc, "string") for misc per-module compiler configuration, currently "string" can only be "verbose" which forces -vv for module it appears in.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
126 llvmForceLogging = false; |
604
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
127 this->doDocComment = doDocComment; |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
128 this->doHdrGen = doHdrGen; |
336 | 129 } |
130 | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
131 File* Module::buildFilePath(char* forcename, char* path, char* ext) |
336 | 132 { |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
133 char *argobj; |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
134 if (forcename) |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
135 argobj = forcename; |
336 | 136 else |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
137 { |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
138 if (global.params.preservePaths) |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
139 argobj = (char*)this->arg; |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
140 else |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
141 argobj = FileName::name((char*)this->arg); |
336 | 142 |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
143 if (global.params.fqnNames) |
643 | 144 { |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
145 if(md) |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
146 argobj = FileName::replaceName(argobj, md->toChars()); |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
147 else |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
148 argobj = FileName::replaceName(argobj, toChars()); |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
149 |
643 | 150 // add ext, otherwise forceExt will make nested.module into nested.bc |
151 size_t len = strlen(argobj); | |
152 size_t extlen = strlen(ext); | |
153 char* s = (char *)alloca(len + 1 + extlen + 1); | |
154 memcpy(s, argobj, len); | |
155 s[len] = '.'; | |
156 memcpy(s + len + 1, ext, extlen + 1); | |
157 s[len+1+extlen] = 0; | |
158 argobj = s; | |
159 } | |
336 | 160 } |
161 | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
162 if (!FileName::absolute(argobj)) |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
163 { |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
164 argobj = FileName::combine(path, argobj); |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
165 } |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
166 |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
167 FileName::ensurePathExists(FileName::path(argobj)); |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
168 |
597
8cc0c46064b1
Fix path handling, hopefully.
Christian Kamm <kamm incasoftware de>
parents:
595
diff
changeset
|
169 if (forcename) |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
170 return new File(argobj); |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
171 else |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
172 return new File(FileName::forceExt(argobj, ext)); |
336 | 173 } |
174 | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
175 void Module::buildTargetFiles() |
336 | 176 { |
604
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
177 if(objfile && |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
178 (!doDocComment || docfile) && |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
179 (!doHdrGen || hdrfile)) |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
180 return; |
336 | 181 |
604
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
182 if(!objfile) |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
183 objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
184 if(doDocComment && !docfile) |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
185 docfile = Module::buildFilePath(global.params.docname, global.params.docdir, global.doc_ext); |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
186 if(doHdrGen && !hdrfile) |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
187 hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); |
598
13ff06605226
To prevert source-overwriting in the future, forbit output files with the same
Christian Kamm <kamm incasoftware de>
parents:
597
diff
changeset
|
188 |
13ff06605226
To prevert source-overwriting in the future, forbit output files with the same
Christian Kamm <kamm incasoftware de>
parents:
597
diff
changeset
|
189 // safety check: never allow obj, doc or hdr file to have the source file's name |
604
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
190 if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
191 { |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
192 error("Output object files with the same name as the source file are forbidden"); |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
193 fatal(); |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
194 } |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
195 if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) |
598
13ff06605226
To prevert source-overwriting in the future, forbit output files with the same
Christian Kamm <kamm incasoftware de>
parents:
597
diff
changeset
|
196 { |
604
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
197 error("Output doc files with the same name as the source file are forbidden"); |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
198 fatal(); |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
199 } |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
200 if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
201 { |
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
202 error("Output header files with the same name as the source file are forbidden"); |
598
13ff06605226
To prevert source-overwriting in the future, forbit output files with the same
Christian Kamm <kamm incasoftware de>
parents:
597
diff
changeset
|
203 fatal(); |
13ff06605226
To prevert source-overwriting in the future, forbit output files with the same
Christian Kamm <kamm incasoftware de>
parents:
597
diff
changeset
|
204 } |
336 | 205 } |
206 | |
207 void Module::deleteObjFile() | |
208 { | |
209 if (global.params.obj) | |
210 objfile->remove(); | |
211 //if (global.params.llvmBC) | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
212 //bcfile->remove(); |
604
a30fc28e8f23
Make creating and deleting of doc and hdr files dependent on whether doc and
Christian Kamm <kamm incasoftware de>
parents:
598
diff
changeset
|
213 if (doDocComment && docfile) |
336 | 214 docfile->remove(); |
215 } | |
216 | |
217 Module::~Module() | |
218 { | |
219 } | |
220 | |
221 const char *Module::kind() | |
222 { | |
223 return "module"; | |
224 } | |
225 | |
226 Module *Module::load(Loc loc, Array *packages, Identifier *ident) | |
227 { Module *m; | |
228 char *filename; | |
229 | |
230 //printf("Module::load(ident = '%s')\n", ident->toChars()); | |
231 | |
232 // Build module filename by turning: | |
233 // foo.bar.baz | |
234 // into: | |
235 // foo\bar\baz | |
236 filename = ident->toChars(); | |
237 if (packages && packages->dim) | |
238 { | |
239 OutBuffer buf; | |
240 int i; | |
241 | |
242 for (i = 0; i < packages->dim; i++) | |
243 { Identifier *pid = (Identifier *)packages->data[i]; | |
244 | |
245 buf.writestring(pid->toChars()); | |
246 #if _WIN32 | |
247 buf.writeByte('\\'); | |
248 #else | |
249 buf.writeByte('/'); | |
250 #endif | |
251 } | |
252 buf.writestring(filename); | |
253 buf.writeByte(0); | |
254 filename = (char *)buf.extractData(); | |
255 } | |
256 | |
257 m = new Module(filename, ident, 0, 0); | |
258 m->loc = loc; | |
259 | |
260 /* Search along global.path for .di file, then .d file. | |
261 */ | |
262 char *result = NULL; | |
263 FileName *fdi = FileName::forceExt(filename, global.hdr_ext); | |
264 FileName *fd = FileName::forceExt(filename, global.mars_ext); | |
265 char *sdi = fdi->toChars(); | |
266 char *sd = fd->toChars(); | |
267 | |
268 if (FileName::exists(sdi)) | |
269 result = sdi; | |
270 else if (FileName::exists(sd)) | |
271 result = sd; | |
272 else if (FileName::absolute(filename)) | |
273 ; | |
274 else if (!global.path) | |
275 ; | |
276 else | |
277 { | |
278 for (size_t i = 0; i < global.path->dim; i++) | |
279 { | |
280 char *p = (char *)global.path->data[i]; | |
281 char *n = FileName::combine(p, sdi); | |
282 if (FileName::exists(n)) | |
283 { result = n; | |
284 break; | |
285 } | |
286 mem.free(n); | |
287 n = FileName::combine(p, sd); | |
288 if (FileName::exists(n)) | |
289 { result = n; | |
290 break; | |
291 } | |
292 mem.free(n); | |
293 } | |
294 } | |
295 if (result) | |
296 m->srcfile = new File(result); | |
297 | |
298 if (global.params.verbose) | |
299 { | |
300 printf("import "); | |
301 if (packages) | |
302 { | |
303 for (size_t i = 0; i < packages->dim; i++) | |
304 { Identifier *pid = (Identifier *)packages->data[i]; | |
305 printf("%s.", pid->toChars()); | |
306 } | |
307 } | |
308 printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); | |
309 } | |
310 | |
311 m->read(loc); | |
312 m->parse(); | |
313 | |
314 #ifdef IN_GCC | |
315 d_gcc_magic_module(m); | |
316 #endif | |
317 | |
318 return m; | |
319 } | |
320 | |
321 void Module::read(Loc loc) | |
322 { | |
323 //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars()); | |
324 if (srcfile->read()) | |
325 { error(loc, "cannot read file '%s'", srcfile->toChars()); | |
326 fatal(); | |
327 } | |
328 } | |
329 | |
330 inline unsigned readwordLE(unsigned short *p) | |
331 { | |
332 #if __I86__ | |
333 return *p; | |
334 #else | |
335 return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; | |
336 #endif | |
337 } | |
338 | |
339 inline unsigned readwordBE(unsigned short *p) | |
340 { | |
341 return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1]; | |
342 } | |
343 | |
344 inline unsigned readlongLE(unsigned *p) | |
345 { | |
346 #if __I86__ | |
347 return *p; | |
348 #else | |
349 return ((unsigned char *)p)[0] | | |
350 (((unsigned char *)p)[1] << 8) | | |
351 (((unsigned char *)p)[2] << 16) | | |
352 (((unsigned char *)p)[3] << 24); | |
353 #endif | |
354 } | |
355 | |
356 inline unsigned readlongBE(unsigned *p) | |
357 { | |
358 return ((unsigned char *)p)[3] | | |
359 (((unsigned char *)p)[2] << 8) | | |
360 (((unsigned char *)p)[1] << 16) | | |
361 (((unsigned char *)p)[0] << 24); | |
362 } | |
363 | |
364 #if IN_GCC | |
365 void Module::parse(bool dump_source) | |
366 #else | |
367 void Module::parse() | |
368 #endif | |
369 { char *srcname; | |
370 unsigned char *buf; | |
371 unsigned buflen; | |
372 unsigned le; | |
373 unsigned bom; | |
374 | |
375 //printf("Module::parse()\n"); | |
376 | |
377 srcname = srcfile->name->toChars(); | |
378 //printf("Module::parse(srcname = '%s')\n", srcname); | |
379 | |
380 buf = srcfile->buffer; | |
381 buflen = srcfile->len; | |
382 | |
383 if (buflen >= 2) | |
384 { | |
385 /* Convert all non-UTF-8 formats to UTF-8. | |
386 * BOM : http://www.unicode.org/faq/utf_bom.html | |
387 * 00 00 FE FF UTF-32BE, big-endian | |
388 * FF FE 00 00 UTF-32LE, little-endian | |
389 * FE FF UTF-16BE, big-endian | |
390 * FF FE UTF-16LE, little-endian | |
391 * EF BB BF UTF-8 | |
392 */ | |
393 | |
394 bom = 1; // assume there's a BOM | |
395 if (buf[0] == 0xFF && buf[1] == 0xFE) | |
396 { | |
397 if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) | |
398 { // UTF-32LE | |
399 le = 1; | |
400 | |
401 Lutf32: | |
402 OutBuffer dbuf; | |
403 unsigned *pu = (unsigned *)(buf); | |
404 unsigned *pumax = &pu[buflen / 4]; | |
405 | |
406 if (buflen & 3) | |
407 { error("odd length of UTF-32 char source %u", buflen); | |
408 fatal(); | |
409 } | |
410 | |
411 dbuf.reserve(buflen / 4); | |
412 for (pu += bom; pu < pumax; pu++) | |
413 { unsigned u; | |
414 | |
415 u = le ? readlongLE(pu) : readlongBE(pu); | |
416 if (u & ~0x7F) | |
417 { | |
418 if (u > 0x10FFFF) | |
419 { error("UTF-32 value %08x greater than 0x10FFFF", u); | |
420 fatal(); | |
421 } | |
422 dbuf.writeUTF8(u); | |
423 } | |
424 else | |
425 dbuf.writeByte(u); | |
426 } | |
427 dbuf.writeByte(0); // add 0 as sentinel for scanner | |
428 buflen = dbuf.offset - 1; // don't include sentinel in count | |
429 buf = (unsigned char *) dbuf.extractData(); | |
430 } | |
431 else | |
432 { // UTF-16LE (X86) | |
433 // Convert it to UTF-8 | |
434 le = 1; | |
435 | |
436 Lutf16: | |
437 OutBuffer dbuf; | |
438 unsigned short *pu = (unsigned short *)(buf); | |
439 unsigned short *pumax = &pu[buflen / 2]; | |
440 | |
441 if (buflen & 1) | |
442 { error("odd length of UTF-16 char source %u", buflen); | |
443 fatal(); | |
444 } | |
445 | |
446 dbuf.reserve(buflen / 2); | |
447 for (pu += bom; pu < pumax; pu++) | |
448 { unsigned u; | |
449 | |
450 u = le ? readwordLE(pu) : readwordBE(pu); | |
451 if (u & ~0x7F) | |
452 { if (u >= 0xD800 && u <= 0xDBFF) | |
453 { unsigned u2; | |
454 | |
455 if (++pu > pumax) | |
456 { error("surrogate UTF-16 high value %04x at EOF", u); | |
457 fatal(); | |
458 } | |
459 u2 = le ? readwordLE(pu) : readwordBE(pu); | |
460 if (u2 < 0xDC00 || u2 > 0xDFFF) | |
461 { error("surrogate UTF-16 low value %04x out of range", u2); | |
462 fatal(); | |
463 } | |
464 u = (u - 0xD7C0) << 10; | |
465 u |= (u2 - 0xDC00); | |
466 } | |
467 else if (u >= 0xDC00 && u <= 0xDFFF) | |
468 { error("unpaired surrogate UTF-16 value %04x", u); | |
469 fatal(); | |
470 } | |
471 else if (u == 0xFFFE || u == 0xFFFF) | |
472 { error("illegal UTF-16 value %04x", u); | |
473 fatal(); | |
474 } | |
475 dbuf.writeUTF8(u); | |
476 } | |
477 else | |
478 dbuf.writeByte(u); | |
479 } | |
480 dbuf.writeByte(0); // add 0 as sentinel for scanner | |
481 buflen = dbuf.offset - 1; // don't include sentinel in count | |
482 buf = (unsigned char *) dbuf.extractData(); | |
483 } | |
484 } | |
485 else if (buf[0] == 0xFE && buf[1] == 0xFF) | |
486 { // UTF-16BE | |
487 le = 0; | |
488 goto Lutf16; | |
489 } | |
490 else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) | |
491 { // UTF-32BE | |
492 le = 0; | |
493 goto Lutf32; | |
494 } | |
495 else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) | |
496 { // UTF-8 | |
497 | |
498 buf += 3; | |
499 buflen -= 3; | |
500 } | |
501 else | |
502 { | |
503 /* There is no BOM. Make use of Arcane Jill's insight that | |
504 * the first char of D source must be ASCII to | |
505 * figure out the encoding. | |
506 */ | |
507 | |
508 bom = 0; | |
509 if (buflen >= 4) | |
510 { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) | |
511 { // UTF-32LE | |
512 le = 1; | |
513 goto Lutf32; | |
514 } | |
515 else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) | |
516 { // UTF-32BE | |
517 le = 0; | |
518 goto Lutf32; | |
519 } | |
520 } | |
521 if (buflen >= 2) | |
522 { | |
523 if (buf[1] == 0) | |
524 { // UTF-16LE | |
525 le = 1; | |
526 goto Lutf16; | |
527 } | |
528 else if (buf[0] == 0) | |
529 { // UTF-16BE | |
530 le = 0; | |
531 goto Lutf16; | |
532 } | |
533 } | |
534 | |
535 // It's UTF-8 | |
536 if (buf[0] >= 0x80) | |
537 { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); | |
538 fatal(); | |
539 } | |
540 } | |
541 } | |
542 | |
543 #ifdef IN_GCC | |
544 // dump utf-8 encoded source | |
545 if (dump_source) | |
546 { // %% srcname could contain a path ... | |
547 d_gcc_dump_source(srcname, "utf-8", buf, buflen); | |
548 } | |
549 #endif | |
550 | |
551 /* If it starts with the string "Ddoc", then it's a documentation | |
552 * source file. | |
553 */ | |
554 if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) | |
555 { | |
556 comment = buf + 4; | |
557 isDocFile = 1; | |
558 return; | |
559 } | |
560 if (isHtml) | |
561 { | |
562 OutBuffer *dbuf = new OutBuffer(); | |
563 Html h(srcname, buf, buflen); | |
564 h.extractCode(dbuf); | |
565 buf = dbuf->data; | |
566 buflen = dbuf->offset; | |
567 #ifdef IN_GCC | |
568 // dump extracted source | |
569 if (dump_source) | |
570 d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); | |
571 #endif | |
572 } | |
573 Parser p(this, buf, buflen, docfile != NULL); | |
574 p.nextToken(); | |
575 members = p.parseModule(); | |
576 md = p.md; | |
577 numlines = p.loc.linnum; | |
578 | |
579 DsymbolTable *dst; | |
580 | |
581 if (md) | |
582 { this->ident = md->id; | |
583 dst = Package::resolve(md->packages, &this->parent, NULL); | |
584 } | |
585 else | |
586 { | |
587 dst = modules; | |
588 | |
589 /* Check to see if module name is a valid identifier | |
590 */ | |
591 if (!Lexer::isValidIdentifier(this->ident->toChars())) | |
592 error("has non-identifier characters in filename, use module declaration instead"); | |
593 } | |
594 | |
595 // Update global list of modules | |
596 if (!dst->insert(this)) | |
597 { | |
598 if (md) | |
599 error(loc, "is in multiple packages %s", md->toChars()); | |
600 else | |
601 error(loc, "is in multiple defined"); | |
602 } | |
603 else | |
604 { | |
605 amodules.push(this); | |
606 } | |
607 } | |
608 | |
609 void Module::semantic() | |
610 { int i; | |
611 | |
612 if (semanticstarted) | |
613 return; | |
614 | |
615 //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); | |
616 semanticstarted = 1; | |
617 | |
618 // Note that modules get their own scope, from scratch. | |
619 // This is so regardless of where in the syntax a module | |
620 // gets imported, it is unaffected by context. | |
621 Scope *sc = Scope::createGlobal(this); // create root scope | |
622 | |
623 //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); | |
624 | |
625 // Add import of "object" if this module isn't "object" | |
626 if (ident != Id::object) | |
627 { | |
628 Import *im = new Import(0, NULL, Id::object, NULL, 0); | |
629 members->shift(im); | |
630 } | |
631 | |
632 // Add all symbols into module's symbol table | |
633 symtab = new DsymbolTable(); | |
634 for (i = 0; i < members->dim; i++) | |
635 { Dsymbol *s; | |
636 | |
637 s = (Dsymbol *)members->data[i]; | |
638 s->addMember(NULL, sc->scopesym, 1); | |
639 } | |
640 | |
641 // Pass 1 semantic routines: do public side of the definition | |
642 for (i = 0; i < members->dim; i++) | |
643 { Dsymbol *s; | |
644 | |
645 s = (Dsymbol *)members->data[i]; | |
646 //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); | |
647 s->semantic(sc); | |
648 runDeferredSemantic(); | |
649 } | |
650 | |
651 sc = sc->pop(); | |
652 sc->pop(); | |
653 semanticdone = semanticstarted; | |
654 //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); | |
655 } | |
656 | |
657 void Module::semantic2() | |
658 { int i; | |
659 | |
660 if (deferred.dim) | |
661 { | |
662 for (int i = 0; i < deferred.dim; i++) | |
663 { | |
664 Dsymbol *sd = (Dsymbol *)deferred.data[i]; | |
665 | |
666 sd->error("unable to resolve forward reference in definition"); | |
667 } | |
668 return; | |
669 } | |
670 //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); | |
671 if (semanticstarted >= 2) | |
672 return; | |
673 assert(semanticstarted == 1); | |
674 semanticstarted = 2; | |
675 | |
676 // Note that modules get their own scope, from scratch. | |
677 // This is so regardless of where in the syntax a module | |
678 // gets imported, it is unaffected by context. | |
679 Scope *sc = Scope::createGlobal(this); // create root scope | |
680 //printf("Module = %p\n", sc.scopesym); | |
681 | |
682 // Pass 2 semantic routines: do initializers and function bodies | |
683 for (i = 0; i < members->dim; i++) | |
684 { Dsymbol *s; | |
685 | |
686 s = (Dsymbol *)members->data[i]; | |
687 s->semantic2(sc); | |
688 } | |
689 | |
690 sc = sc->pop(); | |
691 sc->pop(); | |
692 semanticdone = semanticstarted; | |
693 //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); | |
694 } | |
695 | |
696 void Module::semantic3() | |
697 { int i; | |
698 | |
699 //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); | |
700 if (semanticstarted >= 3) | |
701 return; | |
702 assert(semanticstarted == 2); | |
703 semanticstarted = 3; | |
704 | |
705 // Note that modules get their own scope, from scratch. | |
706 // This is so regardless of where in the syntax a module | |
707 // gets imported, it is unaffected by context. | |
708 Scope *sc = Scope::createGlobal(this); // create root scope | |
709 //printf("Module = %p\n", sc.scopesym); | |
710 | |
711 // Pass 3 semantic routines: do initializers and function bodies | |
712 for (i = 0; i < members->dim; i++) | |
713 { Dsymbol *s; | |
714 | |
715 s = (Dsymbol *)members->data[i]; | |
716 //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); | |
717 s->semantic3(sc); | |
718 } | |
719 | |
720 sc = sc->pop(); | |
721 sc->pop(); | |
722 semanticdone = semanticstarted; | |
723 } | |
724 | |
725 void Module::inlineScan() | |
726 { int i; | |
727 | |
728 if (semanticstarted >= 4) | |
729 return; | |
730 assert(semanticstarted == 3); | |
731 semanticstarted = 4; | |
732 | |
733 // Note that modules get their own scope, from scratch. | |
734 // This is so regardless of where in the syntax a module | |
735 // gets imported, it is unaffected by context. | |
736 //printf("Module = %p\n", sc.scopesym); | |
737 | |
738 for (i = 0; i < members->dim; i++) | |
739 { Dsymbol *s; | |
740 | |
741 s = (Dsymbol *)members->data[i]; | |
742 //if (global.params.verbose) | |
743 //printf("inline scan symbol %s\n", s->toChars()); | |
744 | |
745 s->inlineScan(); | |
746 } | |
747 semanticdone = semanticstarted; | |
748 } | |
749 | |
750 /**************************************************** | |
751 */ | |
752 | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
753 // is this used anywhere? |
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
754 /* |
336 | 755 void Module::gensymfile() |
756 { | |
757 OutBuffer buf; | |
758 HdrGenState hgs; | |
759 | |
760 //printf("Module::gensymfile()\n"); | |
761 | |
762 buf.printf("// Sym file generated from '%s'", srcfile->toChars()); | |
763 buf.writenl(); | |
764 | |
765 for (int i = 0; i < members->dim; i++) | |
766 { Dsymbol *s = (Dsymbol *)members->data[i]; | |
767 | |
768 s->toCBuffer(&buf, &hgs); | |
769 } | |
770 | |
771 // Transfer image to file | |
772 symfile->setbuffer(buf.data, buf.offset); | |
773 buf.data = NULL; | |
774 | |
775 symfile->writev(); | |
580
7824c21a58e3
Restructure path handling a bit. Fixes #66.
Christian Kamm <kamm incasoftware de>
parents:
550
diff
changeset
|
776 }*/ |
336 | 777 |
778 /********************************** | |
779 * Determine if we need to generate an instance of ModuleInfo | |
780 * for this Module. | |
781 */ | |
782 | |
783 int Module::needModuleInfo() | |
784 { | |
550
cbe08531430f
Removed unimplemented switches.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
510
diff
changeset
|
785 return needmoduleinfo; |
336 | 786 } |
787 | |
788 Dsymbol *Module::search(Loc loc, Identifier *ident, int flags) | |
789 { | |
790 /* Since modules can be circularly referenced, | |
791 * need to stop infinite recursive searches. | |
792 */ | |
793 | |
794 //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); | |
795 Dsymbol *s; | |
796 if (insearch) | |
797 s = NULL; | |
798 else if (searchCacheIdent == ident && searchCacheFlags == flags) | |
799 s = searchCacheSymbol; | |
800 else | |
801 { | |
802 insearch = 1; | |
803 s = ScopeDsymbol::search(loc, ident, flags); | |
804 insearch = 0; | |
805 | |
806 searchCacheIdent = ident; | |
807 searchCacheSymbol = s; | |
808 searchCacheFlags = flags; | |
809 } | |
810 return s; | |
811 } | |
812 | |
813 /******************************************* | |
814 * Can't run semantic on s now, try again later. | |
815 */ | |
816 | |
817 void Module::addDeferredSemantic(Dsymbol *s) | |
818 { | |
819 // Don't add it if it is already there | |
820 for (int i = 0; i < deferred.dim; i++) | |
821 { | |
822 Dsymbol *sd = (Dsymbol *)deferred.data[i]; | |
823 | |
824 if (sd == s) | |
825 return; | |
826 } | |
827 | |
828 //printf("Module::addDeferredSemantic('%s')\n", s->toChars()); | |
829 deferred.push(s); | |
830 } | |
831 | |
832 | |
833 /****************************************** | |
834 * Run semantic() on deferred symbols. | |
835 */ | |
836 | |
837 void Module::runDeferredSemantic() | |
838 { | |
839 size_t len; | |
840 | |
841 static int nested; | |
842 if (nested) | |
843 return; | |
844 //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); | |
845 nested++; | |
846 | |
847 do | |
848 { | |
849 dprogress = 0; | |
850 len = deferred.dim; | |
851 if (!len) | |
852 break; | |
853 | |
854 Dsymbol **todo; | |
855 Dsymbol *tmp; | |
856 if (len == 1) | |
857 { | |
858 todo = &tmp; | |
859 } | |
860 else | |
861 { | |
862 todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *)); | |
863 assert(todo); | |
864 } | |
865 memcpy(todo, deferred.data, len * sizeof(Dsymbol *)); | |
866 deferred.setDim(0); | |
867 | |
868 for (int i = 0; i < len; i++) | |
869 { | |
870 Dsymbol *s = todo[i]; | |
871 | |
872 s->semantic(NULL); | |
873 //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars()); | |
874 } | |
875 //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); | |
876 } while (deferred.dim < len || dprogress); // while making progress | |
877 nested--; | |
878 //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); | |
879 } | |
880 | |
881 /* =========================== ModuleDeclaration ===================== */ | |
882 | |
883 ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id) | |
884 { | |
885 this->packages = packages; | |
886 this->id = id; | |
887 } | |
888 | |
889 char *ModuleDeclaration::toChars() | |
890 { | |
891 OutBuffer buf; | |
892 int i; | |
893 | |
894 if (packages && packages->dim) | |
895 { | |
896 for (i = 0; i < packages->dim; i++) | |
897 { Identifier *pid = (Identifier *)packages->data[i]; | |
898 | |
899 buf.writestring(pid->toChars()); | |
900 buf.writeByte('.'); | |
901 } | |
902 } | |
903 buf.writestring(id->toChars()); | |
904 buf.writeByte(0); | |
905 return (char *)buf.extractData(); | |
906 } | |
907 | |
908 /* =========================== Package ===================== */ | |
909 | |
910 Package::Package(Identifier *ident) | |
911 : ScopeDsymbol(ident) | |
912 { | |
913 } | |
914 | |
915 | |
916 const char *Package::kind() | |
917 { | |
918 return "package"; | |
919 } | |
920 | |
921 | |
922 DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg) | |
923 { | |
924 DsymbolTable *dst = Module::modules; | |
925 Dsymbol *parent = NULL; | |
926 | |
927 //printf("Package::resolve()\n"); | |
928 if (ppkg) | |
929 *ppkg = NULL; | |
930 | |
931 if (packages) | |
932 { int i; | |
933 | |
934 for (i = 0; i < packages->dim; i++) | |
935 { Identifier *pid = (Identifier *)packages->data[i]; | |
936 Dsymbol *p; | |
937 | |
938 p = dst->lookup(pid); | |
939 if (!p) | |
940 { | |
941 p = new Package(pid); | |
942 dst->insert(p); | |
943 p->parent = parent; | |
944 ((ScopeDsymbol *)p)->symtab = new DsymbolTable(); | |
945 } | |
946 else | |
947 { | |
948 assert(p->isPackage()); | |
949 if (p->isModule()) | |
950 { p->error("module and package have the same name"); | |
951 fatal(); | |
952 break; | |
953 } | |
954 } | |
955 parent = p; | |
956 dst = ((Package *)p)->symtab; | |
957 if (ppkg && !*ppkg) | |
958 *ppkg = (Package *)p; | |
959 } | |
960 if (pparent) | |
961 { | |
962 *pparent = parent; | |
963 } | |
964 } | |
965 return dst; | |
966 } |