]>
Commit | Line | Data |
---|---|---|
e440a328 | 1 | // import.cc -- Go frontend import declarations. |
2 | ||
3 | // Copyright 2009 The Go Authors. All rights reserved. | |
4 | // Use of this source code is governed by a BSD-style | |
5 | // license that can be found in the LICENSE file. | |
6 | ||
7 | #include "go-system.h" | |
8 | ||
9 | #include "filenames.h" | |
e440a328 | 10 | |
11 | #include "go-c.h" | |
631d5788 | 12 | #include "go-diagnostics.h" |
e440a328 | 13 | #include "gogo.h" |
68883531 | 14 | #include "lex.h" |
e440a328 | 15 | #include "types.h" |
16 | #include "export.h" | |
17 | #include "import.h" | |
18 | ||
19 | #ifndef O_BINARY | |
20 | #define O_BINARY 0 | |
21 | #endif | |
22 | ||
23 | // The list of paths we search for import files. | |
24 | ||
25 | static std::vector<std::string> search_path; | |
26 | ||
27 | // Add a directory to the search path. This is called from the option | |
28 | // handling language hook. | |
29 | ||
30 | GO_EXTERN_C | |
31 | void | |
32 | go_add_search_path(const char* path) | |
33 | { | |
34 | search_path.push_back(std::string(path)); | |
35 | } | |
36 | ||
e440a328 | 37 | // Find import data. This searches the file system for FILENAME and |
38 | // returns a pointer to a Stream object to read the data that it | |
39 | // exports. If the file is not found, it returns NULL. | |
40 | ||
487ecfe9 | 41 | // When FILENAME is not an absolute path and does not start with ./ or |
42 | // ../, we use the search path provided by -I and -L options. | |
e440a328 | 43 | |
0b1e172c | 44 | // When FILENAME does start with ./ or ../, we use |
45 | // RELATIVE_IMPORT_PATH as a prefix. | |
46 | ||
e440a328 | 47 | // When FILENAME does not exist, we try modifying FILENAME to find the |
48 | // file. We use the first of these which exists: | |
49 | // * We append ".gox". | |
50 | // * We turn the base of FILENAME into libFILENAME.so. | |
51 | // * We turn the base of FILENAME into libFILENAME.a. | |
52 | // * We append ".o". | |
53 | ||
54 | // When using a search path, we apply each of these transformations at | |
55 | // each entry on the search path before moving on to the next entry. | |
56 | // If the file exists, but does not contain any Go export data, we | |
57 | // stop; we do not keep looking for another file with the same name | |
58 | // later in the search path. | |
59 | ||
60 | Import::Stream* | |
0b1e172c | 61 | Import::open_package(const std::string& filename, Location location, |
62 | const std::string& relative_import_path) | |
e440a328 | 63 | { |
487ecfe9 | 64 | bool is_local; |
65 | if (IS_ABSOLUTE_PATH(filename)) | |
66 | is_local = true; | |
0b1e172c | 67 | else if (filename[0] == '.' |
68 | && (filename[1] == '\0' || IS_DIR_SEPARATOR(filename[1]))) | |
487ecfe9 | 69 | is_local = true; |
70 | else if (filename[0] == '.' | |
71 | && filename[1] == '.' | |
0b1e172c | 72 | && (filename[2] == '\0' || IS_DIR_SEPARATOR(filename[2]))) |
487ecfe9 | 73 | is_local = true; |
74 | else | |
75 | is_local = false; | |
0b1e172c | 76 | |
77 | std::string fn = filename; | |
78 | if (is_local && !IS_ABSOLUTE_PATH(filename) && !relative_import_path.empty()) | |
79 | { | |
80 | if (fn == ".") | |
81 | { | |
82 | // A special case. | |
83 | fn = relative_import_path; | |
84 | } | |
382819b3 | 85 | else if (fn[0] == '.' && fn[1] == '.' |
86 | && (fn[2] == '\0' || IS_DIR_SEPARATOR(fn[2]))) | |
87 | { | |
88 | // We are going to join relative_import_path and fn, and it | |
89 | // will look like DIR/../PATH. But DIR does not necessarily | |
90 | // exist in this case, and if it doesn't the use of .. will | |
91 | // fail although it shouldn't. The gc compiler uses | |
92 | // path.Join here, which cleans up the .., so we need to do | |
93 | // the same. | |
94 | size_t index; | |
95 | for (index = relative_import_path.length() - 1; | |
96 | index > 0 && !IS_DIR_SEPARATOR(relative_import_path[index]); | |
97 | index--) | |
98 | ; | |
99 | if (index > 0) | |
100 | fn = relative_import_path.substr(0, index) + fn.substr(2); | |
101 | else | |
102 | fn = relative_import_path + '/' + fn; | |
103 | } | |
0b1e172c | 104 | else |
105 | fn = relative_import_path + '/' + fn; | |
106 | is_local = false; | |
107 | } | |
108 | ||
487ecfe9 | 109 | if (!is_local) |
e440a328 | 110 | { |
111 | for (std::vector<std::string>::const_iterator p = search_path.begin(); | |
112 | p != search_path.end(); | |
113 | ++p) | |
114 | { | |
115 | std::string indir = *p; | |
116 | if (!indir.empty() && indir[indir.size() - 1] != '/') | |
117 | indir += '/'; | |
0b1e172c | 118 | indir += fn; |
e440a328 | 119 | Stream* s = Import::try_package_in_directory(indir, location); |
120 | if (s != NULL) | |
121 | return s; | |
122 | } | |
123 | } | |
124 | ||
0b1e172c | 125 | Stream* s = Import::try_package_in_directory(fn, location); |
e440a328 | 126 | if (s != NULL) |
127 | return s; | |
128 | ||
129 | return NULL; | |
130 | } | |
131 | ||
132 | // Try to find the export data for FILENAME. | |
133 | ||
134 | Import::Stream* | |
135 | Import::try_package_in_directory(const std::string& filename, | |
b13c66cd | 136 | Location location) |
e440a328 | 137 | { |
138 | std::string found_filename = filename; | |
139 | int fd = open(found_filename.c_str(), O_RDONLY | O_BINARY); | |
140 | ||
141 | if (fd >= 0) | |
142 | { | |
143 | struct stat s; | |
144 | if (fstat(fd, &s) >= 0 && S_ISDIR(s.st_mode)) | |
145 | { | |
146 | close(fd); | |
147 | fd = -1; | |
148 | errno = EISDIR; | |
149 | } | |
150 | } | |
151 | ||
152 | if (fd < 0) | |
153 | { | |
154 | if (errno != ENOENT && errno != EISDIR) | |
631d5788 | 155 | go_warning_at(location, 0, "%s: %m", filename.c_str()); |
e440a328 | 156 | |
157 | fd = Import::try_suffixes(&found_filename); | |
158 | if (fd < 0) | |
159 | return NULL; | |
160 | } | |
161 | ||
162 | // The export data may not be in this file. | |
163 | Stream* s = Import::find_export_data(found_filename, fd, location); | |
164 | if (s != NULL) | |
165 | return s; | |
166 | ||
167 | close(fd); | |
168 | ||
631d5788 | 169 | go_error_at(location, "%s exists but does not contain any Go export data", |
170 | found_filename.c_str()); | |
e440a328 | 171 | |
172 | return NULL; | |
173 | } | |
174 | ||
175 | // Given import "*PFILENAME", where *PFILENAME does not exist, try | |
176 | // various suffixes. If we find one, set *PFILENAME to the one we | |
177 | // found. Return the open file descriptor. | |
178 | ||
179 | int | |
180 | Import::try_suffixes(std::string* pfilename) | |
181 | { | |
182 | std::string filename = *pfilename + ".gox"; | |
183 | int fd = open(filename.c_str(), O_RDONLY | O_BINARY); | |
184 | if (fd >= 0) | |
185 | { | |
186 | *pfilename = filename; | |
187 | return fd; | |
188 | } | |
189 | ||
190 | const char* basename = lbasename(pfilename->c_str()); | |
191 | size_t basename_pos = basename - pfilename->c_str(); | |
192 | filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".so"; | |
193 | fd = open(filename.c_str(), O_RDONLY | O_BINARY); | |
194 | if (fd >= 0) | |
195 | { | |
196 | *pfilename = filename; | |
197 | return fd; | |
198 | } | |
199 | ||
200 | filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".a"; | |
201 | fd = open(filename.c_str(), O_RDONLY | O_BINARY); | |
202 | if (fd >= 0) | |
203 | { | |
204 | *pfilename = filename; | |
205 | return fd; | |
206 | } | |
207 | ||
208 | filename = *pfilename + ".o"; | |
209 | fd = open(filename.c_str(), O_RDONLY | O_BINARY); | |
210 | if (fd >= 0) | |
211 | { | |
212 | *pfilename = filename; | |
213 | return fd; | |
214 | } | |
215 | ||
216 | return -1; | |
217 | } | |
218 | ||
219 | // Look for export data in the file descriptor FD. | |
220 | ||
221 | Import::Stream* | |
8d7cfce1 | 222 | Import::find_export_data(const std::string& filename, int fd, Location location) |
e440a328 | 223 | { |
224 | // See if we can read this as an object file. | |
225 | Import::Stream* stream = Import::find_object_export_data(filename, fd, 0, | |
226 | location); | |
227 | if (stream != NULL) | |
228 | return stream; | |
229 | ||
8d7cfce1 | 230 | const int len = MAX(Export::magic_len, Import::archive_magic_len); |
e440a328 | 231 | |
232 | if (lseek(fd, 0, SEEK_SET) < 0) | |
233 | { | |
631d5788 | 234 | go_error_at(location, "lseek %s failed: %m", filename.c_str()); |
e440a328 | 235 | return NULL; |
236 | } | |
237 | ||
238 | char buf[len]; | |
80526a7d | 239 | ssize_t c = ::read(fd, buf, len); |
e440a328 | 240 | if (c < len) |
241 | return NULL; | |
242 | ||
243 | // Check for a file containing nothing but Go export data. | |
8f260102 | 244 | if (memcmp(buf, Export::cur_magic, Export::magic_len) == 0 |
245 | || memcmp(buf, Export::v1_magic, Export::magic_len) == 0 | |
246 | || memcmp(buf, Export::v2_magic, Export::magic_len) == 0) | |
e440a328 | 247 | return new Stream_from_file(fd); |
248 | ||
249 | // See if we can read this as an archive. | |
250 | if (Import::is_archive_magic(buf)) | |
251 | return Import::find_archive_export_data(filename, fd, location); | |
252 | ||
253 | return NULL; | |
254 | } | |
255 | ||
4b3412be | 256 | // Look for export data in an object file. |
e440a328 | 257 | |
258 | Import::Stream* | |
259 | Import::find_object_export_data(const std::string& filename, | |
260 | int fd, | |
261 | off_t offset, | |
b13c66cd | 262 | Location location) |
e440a328 | 263 | { |
612cc2ea | 264 | char *buf; |
265 | size_t len; | |
e440a328 | 266 | int err; |
612cc2ea | 267 | const char *errmsg = go_read_export_data(fd, offset, &buf, &len, &err); |
268 | if (errmsg != NULL) | |
e440a328 | 269 | { |
612cc2ea | 270 | if (err == 0) |
631d5788 | 271 | go_error_at(location, "%s: %s", filename.c_str(), errmsg); |
612cc2ea | 272 | else |
631d5788 | 273 | go_error_at(location, "%s: %s: %s", filename.c_str(), errmsg, |
274 | xstrerror(err)); | |
e440a328 | 275 | return NULL; |
276 | } | |
277 | ||
612cc2ea | 278 | if (buf == NULL) |
279 | return NULL; | |
e440a328 | 280 | |
612cc2ea | 281 | return new Stream_from_buffer(buf, len); |
e440a328 | 282 | } |
283 | ||
284 | // Class Import. | |
285 | ||
286 | // Construct an Import object. We make the builtin_types_ vector | |
287 | // large enough to hold all the builtin types. | |
288 | ||
b13c66cd | 289 | Import::Import(Stream* stream, Location location) |
e440a328 | 290 | : gogo_(NULL), stream_(stream), location_(location), package_(NULL), |
80526a7d | 291 | add_to_globals_(false), type_data_(), type_pos_(0), type_offsets_(), |
e440a328 | 292 | builtin_types_((- SMALLEST_BUILTIN_CODE) + 1), |
8d7cfce1 | 293 | types_(), version_(EXPORT_FORMAT_UNKNOWN) |
e440a328 | 294 | { |
295 | } | |
296 | ||
297 | // Import the data in the associated stream. | |
298 | ||
299 | Package* | |
300 | Import::import(Gogo* gogo, const std::string& local_name, | |
301 | bool is_local_name_exported) | |
302 | { | |
303 | // Hold on to the Gogo structure. Otherwise we need to pass it | |
304 | // through all the import functions, because we need it when reading | |
305 | // a type. | |
306 | this->gogo_ = gogo; | |
307 | ||
308 | // A stream of export data can include data from more than one input | |
309 | // file. Here we loop over each input file. | |
310 | Stream* stream = this->stream_; | |
311 | while (!stream->at_eof() && !stream->saw_error()) | |
312 | { | |
313 | // The vector of types is package specific. | |
314 | this->types_.clear(); | |
315 | ||
8d7cfce1 | 316 | // Check magic string / version number. |
317 | if (stream->match_bytes(Export::cur_magic, Export::magic_len)) | |
318 | { | |
319 | stream->require_bytes(this->location_, Export::cur_magic, | |
320 | Export::magic_len); | |
321 | this->version_ = EXPORT_FORMAT_CURRENT; | |
322 | } | |
323 | else if (stream->match_bytes(Export::v1_magic, Export::magic_len)) | |
324 | { | |
325 | stream->require_bytes(this->location_, Export::v1_magic, | |
326 | Export::magic_len); | |
327 | this->version_ = EXPORT_FORMAT_V1; | |
328 | } | |
8f260102 | 329 | else if (stream->match_bytes(Export::v2_magic, Export::magic_len)) |
330 | { | |
331 | stream->require_bytes(this->location_, Export::v2_magic, | |
332 | Export::magic_len); | |
333 | this->version_ = EXPORT_FORMAT_V2; | |
334 | } | |
8d7cfce1 | 335 | else |
336 | { | |
631d5788 | 337 | go_error_at(this->location_, |
338 | ("error in import data at %d: invalid magic string"), | |
339 | stream->pos()); | |
8d7cfce1 | 340 | return NULL; |
341 | } | |
e440a328 | 342 | |
343 | this->require_c_string("package "); | |
344 | std::string package_name = this->read_identifier(); | |
8f260102 | 345 | this->require_semicolon_if_old_version(); |
346 | this->require_c_string("\n"); | |
e440a328 | 347 | |
2a2647e2 | 348 | std::string pkgpath; |
26197037 | 349 | std::string pkgpath_symbol; |
2a2647e2 | 350 | if (this->match_c_string("prefix ")) |
351 | { | |
352 | this->advance(7); | |
353 | std::string unique_prefix = this->read_identifier(); | |
8f260102 | 354 | this->require_semicolon_if_old_version(); |
355 | this->require_c_string("\n"); | |
2a2647e2 | 356 | pkgpath = unique_prefix + '.' + package_name; |
26197037 | 357 | pkgpath_symbol = (Gogo::pkgpath_for_symbol(unique_prefix) + '.' |
358 | + Gogo::pkgpath_for_symbol(package_name)); | |
2a2647e2 | 359 | } |
360 | else | |
361 | { | |
362 | this->require_c_string("pkgpath "); | |
363 | pkgpath = this->read_identifier(); | |
8f260102 | 364 | this->require_semicolon_if_old_version(); |
365 | this->require_c_string("\n"); | |
26197037 | 366 | pkgpath_symbol = Gogo::pkgpath_for_symbol(pkgpath); |
2a2647e2 | 367 | } |
e440a328 | 368 | |
8f260102 | 369 | if (stream->saw_error()) |
370 | return NULL; | |
371 | ||
e440a328 | 372 | this->package_ = gogo->add_imported_package(package_name, local_name, |
373 | is_local_name_exported, | |
26197037 | 374 | pkgpath, pkgpath_symbol, |
e440a328 | 375 | this->location_, |
376 | &this->add_to_globals_); | |
377 | if (this->package_ == NULL) | |
378 | { | |
379 | stream->set_saw_error(); | |
380 | return NULL; | |
381 | } | |
382 | ||
8d7cfce1 | 383 | // Read and discard priority if older V1 export data format. |
384 | if (version() == EXPORT_FORMAT_V1) | |
385 | { | |
386 | this->require_c_string("priority "); | |
387 | std::string priority_string = this->read_identifier(); | |
388 | int prio; | |
389 | if (!this->string_to_int(priority_string, false, &prio)) | |
390 | return NULL; | |
391 | this->require_c_string(";\n"); | |
392 | } | |
e440a328 | 393 | |
1a38587a | 394 | while (stream->match_c_string("package")) |
395 | this->read_one_package(); | |
396 | ||
18d835b9 | 397 | while (stream->match_c_string("import")) |
398 | this->read_one_import(); | |
399 | ||
fc194964 | 400 | while (stream->match_c_string("indirectimport")) |
401 | this->read_one_indirect_import(); | |
402 | ||
18d835b9 | 403 | if (stream->match_c_string("init")) |
e440a328 | 404 | this->read_import_init_fns(gogo); |
405 | ||
80526a7d | 406 | if (stream->match_c_string("types ")) |
407 | { | |
408 | if (!this->read_types()) | |
409 | return NULL; | |
410 | } | |
411 | ||
e440a328 | 412 | // Loop over all the input data for this package. |
413 | while (!stream->saw_error()) | |
414 | { | |
415 | if (stream->match_c_string("const ")) | |
416 | this->import_const(); | |
417 | else if (stream->match_c_string("type ")) | |
418 | this->import_type(); | |
419 | else if (stream->match_c_string("var ")) | |
420 | this->import_var(); | |
421 | else if (stream->match_c_string("func ")) | |
422 | this->import_func(this->package_); | |
423 | else if (stream->match_c_string("checksum ")) | |
424 | break; | |
425 | else | |
426 | { | |
631d5788 | 427 | go_error_at(this->location_, |
428 | ("error in import data at %d: " | |
429 | "expected %<const%>, %<type%>, %<var%>, " | |
430 | "%<func%>, or %<checksum%>"), | |
431 | stream->pos()); | |
e440a328 | 432 | stream->set_saw_error(); |
433 | return NULL; | |
434 | } | |
435 | } | |
436 | ||
437 | // We currently ignore the checksum. In the future we could | |
438 | // store the checksum somewhere in the generated object and then | |
439 | // verify that the checksum matches at link time or at dynamic | |
440 | // load time. | |
441 | this->require_c_string("checksum "); | |
8d7cfce1 | 442 | stream->advance(Export::checksum_len * 2); |
8f260102 | 443 | this->require_semicolon_if_old_version(); |
444 | this->require_c_string("\n"); | |
e440a328 | 445 | } |
446 | ||
447 | return this->package_; | |
448 | } | |
449 | ||
1a38587a | 450 | // Read a package line. This let us reliably determine the pkgpath |
451 | // symbol, even if the package was compiled with a -fgo-prefix option. | |
452 | ||
453 | void | |
454 | Import::read_one_package() | |
455 | { | |
456 | this->require_c_string("package "); | |
457 | std::string package_name = this->read_identifier(); | |
458 | this->require_c_string(" "); | |
459 | std::string pkgpath = this->read_identifier(); | |
460 | this->require_c_string(" "); | |
461 | std::string pkgpath_symbol = this->read_identifier(); | |
8f260102 | 462 | this->require_semicolon_if_old_version(); |
463 | this->require_c_string("\n"); | |
1a38587a | 464 | |
465 | Package* p = this->gogo_->register_package(pkgpath, pkgpath_symbol, | |
466 | Linemap::unknown_location()); | |
467 | p->set_package_name(package_name, this->location()); | |
468 | } | |
469 | ||
fc194964 | 470 | // Read an import line. |
18d835b9 | 471 | |
472 | void | |
473 | Import::read_one_import() | |
474 | { | |
475 | this->require_c_string("import "); | |
2a2647e2 | 476 | std::string package_name = this->read_identifier(); |
477 | this->require_c_string(" "); | |
478 | std::string pkgpath = this->read_identifier(); | |
479 | this->require_c_string(" \""); | |
18d835b9 | 480 | Stream* stream = this->stream_; |
2a2647e2 | 481 | while (stream->peek_char() != '"') |
18d835b9 | 482 | stream->advance(1); |
8f260102 | 483 | this->require_c_string("\""); |
484 | this->require_semicolon_if_old_version(); | |
485 | this->require_c_string("\n"); | |
2a2647e2 | 486 | |
26197037 | 487 | Package* p = this->gogo_->register_package(pkgpath, "", |
2a2647e2 | 488 | Linemap::unknown_location()); |
489 | p->set_package_name(package_name, this->location()); | |
18d835b9 | 490 | } |
491 | ||
fc194964 | 492 | // Read an indirectimport line. |
493 | ||
494 | void | |
495 | Import::read_one_indirect_import() | |
496 | { | |
497 | this->require_c_string("indirectimport "); | |
498 | std::string package_name = this->read_identifier(); | |
499 | this->require_c_string(" "); | |
500 | std::string pkgpath = this->read_identifier(); | |
501 | this->require_c_string("\n"); | |
502 | ||
503 | Package* p = this->gogo_->register_package(pkgpath, "", | |
504 | Linemap::unknown_location()); | |
505 | p->set_package_name(package_name, this->location()); | |
506 | } | |
507 | ||
8d7cfce1 | 508 | // Read the list of import control functions and/or init graph. |
e440a328 | 509 | |
510 | void | |
511 | Import::read_import_init_fns(Gogo* gogo) | |
512 | { | |
18d835b9 | 513 | this->require_c_string("init"); |
8d7cfce1 | 514 | |
515 | // Maps init function to index in the "init" clause; needed | |
516 | // to read the init_graph section. | |
517 | std::map<std::string, unsigned> init_idx; | |
518 | ||
8f260102 | 519 | while (!this->match_c_string("\n") && !this->match_c_string(";")) |
e440a328 | 520 | { |
8d7cfce1 | 521 | int priority = -1; |
522 | ||
e440a328 | 523 | this->require_c_string(" "); |
524 | std::string package_name = this->read_identifier(); | |
525 | this->require_c_string(" "); | |
526 | std::string init_name = this->read_identifier(); | |
8d7cfce1 | 527 | if (this->version_ == EXPORT_FORMAT_V1) |
528 | { | |
529 | // Older version 1 init fcn export data format is: | |
530 | // | |
531 | // <packname> <fcn> <priority> | |
532 | this->require_c_string(" "); | |
533 | std::string prio_string = this->read_identifier(); | |
534 | if (!this->string_to_int(prio_string, false, &priority)) | |
535 | return; | |
536 | } | |
537 | gogo->add_import_init_fn(package_name, init_name, priority); | |
538 | ||
539 | // Record the index of this init fcn so that we can look it | |
540 | // up by index in the subsequent init_graph section. | |
541 | unsigned idx = init_idx.size(); | |
542 | init_idx[init_name] = idx; | |
e440a328 | 543 | } |
8f260102 | 544 | this->require_semicolon_if_old_version(); |
545 | this->require_c_string("\n"); | |
8d7cfce1 | 546 | |
547 | if (this->match_c_string("init_graph")) | |
548 | { | |
549 | this->require_c_string("init_graph"); | |
550 | ||
551 | // Build a vector mapping init fcn slot to Import_init pointer. | |
552 | go_assert(init_idx.size() > 0); | |
553 | std::vector<Import_init*> import_initvec; | |
554 | import_initvec.resize(init_idx.size()); | |
555 | for (std::map<std::string, unsigned>::const_iterator it = | |
556 | init_idx.begin(); | |
557 | it != init_idx.end(); ++it) | |
558 | { | |
559 | const std::string& init_name = it->first; | |
560 | Import_init* ii = gogo->lookup_init(init_name); | |
561 | import_initvec[it->second] = ii; | |
562 | } | |
563 | ||
564 | // Init graph format is: | |
565 | // | |
566 | // init_graph <src1> <sink1> <src2> <sink2> ... ; | |
567 | // | |
568 | // where src + sink are init functions indices. | |
569 | ||
8f260102 | 570 | while (!this->match_c_string("\n") && !this->match_c_string(";")) |
8d7cfce1 | 571 | { |
572 | this->require_c_string(" "); | |
573 | std::string src_string = this->read_identifier(); | |
574 | unsigned src; | |
575 | if (!this->string_to_unsigned(src_string, &src)) return; | |
576 | ||
577 | this->require_c_string(" "); | |
578 | std::string sink_string = this->read_identifier(); | |
579 | unsigned sink; | |
580 | if (!this->string_to_unsigned(sink_string, &sink)) return; | |
581 | ||
582 | go_assert(src < import_initvec.size()); | |
583 | Import_init* ii_src = import_initvec[src]; | |
584 | go_assert(sink < import_initvec.size()); | |
585 | Import_init* ii_sink = import_initvec[sink]; | |
586 | ||
587 | ii_src->record_precursor_fcn(ii_sink->init_name()); | |
588 | } | |
8f260102 | 589 | this->require_semicolon_if_old_version(); |
590 | this->require_c_string("\n"); | |
8d7cfce1 | 591 | } |
e440a328 | 592 | } |
593 | ||
80526a7d | 594 | // Import the types. Starting in export format version 3 all the |
595 | // types are listed first. | |
596 | ||
597 | bool | |
598 | Import::read_types() | |
599 | { | |
600 | this->require_c_string("types "); | |
601 | std::string str = this->read_identifier(); | |
602 | int maxp1; | |
603 | if (!this->string_to_int(str, false, &maxp1)) | |
604 | return false; | |
605 | ||
606 | this->require_c_string(" "); | |
607 | str = this->read_identifier(); | |
608 | int exportedp1; | |
609 | if (!this->string_to_int(str, false, &exportedp1)) | |
610 | return false; | |
611 | ||
612 | this->type_offsets_.resize(maxp1, std::make_pair<size_t, size_t>(0, 0)); | |
613 | size_t total_type_size = 0; | |
614 | // Start at 1 because type index 0 not used. | |
615 | for (int i = 1; i < maxp1; i++) | |
616 | { | |
617 | this->require_c_string(" "); | |
618 | str = this->read_identifier(); | |
619 | int v; | |
620 | if (!this->string_to_int(str, false, &v)) | |
621 | return false; | |
622 | size_t vs = static_cast<size_t>(v); | |
623 | this->type_offsets_[i] = std::make_pair(total_type_size, vs); | |
624 | total_type_size += vs; | |
625 | } | |
626 | ||
627 | this->require_c_string("\n"); | |
628 | ||
629 | // Types can refer to each other in an unpredictable order. Read | |
630 | // all the type data into type_data_. The type_offsets_ vector we | |
631 | // just initialized provides indexes into type_data_. | |
632 | ||
633 | this->type_pos_ = this->stream_->pos(); | |
634 | const char* type_data; | |
635 | if (!this->stream_->peek(total_type_size, &type_data)) | |
636 | return false; | |
637 | this->type_data_ = std::string(type_data, total_type_size); | |
638 | this->advance(total_type_size); | |
639 | ||
640 | this->types_.resize(maxp1, NULL); | |
641 | ||
642 | // Parse all the exported types now, so that the names are properly | |
643 | // bound and visible to the parser. Parse unexported types lazily. | |
644 | ||
645 | // Start at 1 because there is no type 0. | |
646 | for (int i = 1; i < exportedp1; i++) | |
647 | { | |
648 | // We may have already parsed this type when we parsed an | |
649 | // earlier type. | |
650 | Type* type = this->types_[i]; | |
651 | if (type == NULL) | |
652 | { | |
653 | if (!this->parse_type(i)) | |
654 | return false; | |
655 | type = this->types_[i]; | |
656 | go_assert(type != NULL); | |
657 | } | |
658 | Named_type* nt = type->named_type(); | |
659 | if (nt == NULL) | |
660 | { | |
661 | go_error_at(this->location_, | |
662 | "error in import data: exported unnamed type %d", | |
663 | i); | |
664 | return false; | |
665 | } | |
666 | nt->set_is_visible(); | |
667 | if (this->add_to_globals_) | |
668 | this->gogo_->add_named_type(nt); | |
669 | } | |
670 | ||
671 | return true; | |
672 | } | |
673 | ||
e440a328 | 674 | // Import a constant. |
675 | ||
676 | void | |
677 | Import::import_const() | |
678 | { | |
679 | std::string name; | |
680 | Type* type; | |
681 | Expression* expr; | |
682 | Named_constant::import_const(this, &name, &type, &expr); | |
683 | Typed_identifier tid(name, type, this->location_); | |
684 | Named_object* no = this->package_->add_constant(tid, expr); | |
685 | if (this->add_to_globals_) | |
105f4b3f | 686 | this->gogo_->add_dot_import_object(no); |
e440a328 | 687 | } |
688 | ||
689 | // Import a type. | |
690 | ||
691 | void | |
692 | Import::import_type() | |
693 | { | |
80526a7d | 694 | if (this->version_ >= EXPORT_FORMAT_V3) |
695 | { | |
696 | if (!this->stream_->saw_error()) | |
697 | { | |
698 | go_error_at(this->location_, | |
699 | "error in import data at %d: old type syntax", | |
700 | this->stream_->pos()); | |
701 | this->stream_->set_saw_error(); | |
702 | } | |
703 | return; | |
704 | } | |
705 | ||
e440a328 | 706 | Named_type* type; |
707 | Named_type::import_named_type(this, &type); | |
708 | ||
709 | // The named type has been added to the package by the type import | |
710 | // process. Here we need to make it visible to the parser, and it | |
711 | // to the global bindings if necessary. | |
712 | type->set_is_visible(); | |
713 | ||
714 | if (this->add_to_globals_) | |
715 | this->gogo_->add_named_type(type); | |
716 | } | |
717 | ||
718 | // Import a variable. | |
719 | ||
720 | void | |
721 | Import::import_var() | |
722 | { | |
723 | std::string name; | |
724 | Type* type; | |
725 | Variable::import_var(this, &name, &type); | |
726 | Variable* var = new Variable(type, NULL, true, false, false, | |
727 | this->location_); | |
728 | Named_object* no; | |
729 | no = this->package_->add_variable(name, var); | |
730 | if (this->add_to_globals_) | |
105f4b3f | 731 | this->gogo_->add_dot_import_object(no); |
e440a328 | 732 | } |
733 | ||
734 | // Import a function into PACKAGE. PACKAGE is normally | |
735 | // THIS->PACKAGE_, but it will be different for a method associated | |
736 | // with a type defined in a different package. | |
737 | ||
738 | Named_object* | |
739 | Import::import_func(Package* package) | |
740 | { | |
741 | std::string name; | |
742 | Typed_identifier* receiver; | |
743 | Typed_identifier_list* parameters; | |
744 | Typed_identifier_list* results; | |
745 | bool is_varargs; | |
3568b8dc | 746 | bool nointerface; |
81affb1d | 747 | std::string body; |
748 | Function::import_func(this, &name, &receiver, ¶meters, &results, | |
749 | &is_varargs, &nointerface, &body); | |
e440a328 | 750 | Function_type *fntype = Type::make_function_type(receiver, parameters, |
751 | results, this->location_); | |
752 | if (is_varargs) | |
753 | fntype->set_is_varargs(); | |
754 | ||
b13c66cd | 755 | Location loc = this->location_; |
e440a328 | 756 | Named_object* no; |
757 | if (fntype->is_method()) | |
758 | { | |
0873e18e | 759 | Type* rtype = receiver->type(); |
760 | ||
761 | // We may still be reading the definition of RTYPE, so we have | |
762 | // to be careful to avoid calling base or convert. If RTYPE is | |
763 | // a named type or a forward declaration, then we know that it | |
764 | // is not a pointer, because we are reading a method on RTYPE | |
765 | // and named pointers can't have methods. | |
766 | ||
767 | if (rtype->classification() == Type::TYPE_POINTER) | |
768 | rtype = rtype->points_to(); | |
769 | ||
e440a328 | 770 | if (rtype->is_error_type()) |
771 | return NULL; | |
0873e18e | 772 | else if (rtype->named_type() != NULL) |
773 | no = rtype->named_type()->add_method_declaration(name, package, fntype, | |
774 | loc); | |
775 | else if (rtype->forward_declaration_type() != NULL) | |
776 | no = rtype->forward_declaration_type()->add_method_declaration(name, | |
777 | package, | |
778 | fntype, | |
779 | loc); | |
780 | else | |
781 | go_unreachable(); | |
e440a328 | 782 | } |
783 | else | |
784 | { | |
785 | no = package->add_function_declaration(name, fntype, loc); | |
786 | if (this->add_to_globals_) | |
105f4b3f | 787 | this->gogo_->add_dot_import_object(no); |
e440a328 | 788 | } |
3568b8dc | 789 | |
790 | if (nointerface) | |
791 | no->func_declaration_value()->set_nointerface(); | |
81affb1d | 792 | if (!body.empty() && !no->func_declaration_value()->has_imported_body()) |
bc8e2ef4 | 793 | no->func_declaration_value()->set_imported_body(this, body); |
3568b8dc | 794 | |
e440a328 | 795 | return no; |
796 | } | |
797 | ||
80526a7d | 798 | // Read a type definition and initialize the entry in this->types_. |
799 | // This parses the type definition saved by read_types earlier. This | |
800 | // returns true on success, false on failure. | |
801 | ||
802 | bool | |
803 | Import::parse_type(int i) | |
804 | { | |
805 | go_assert(i >= 0 && static_cast<size_t>(i) < this->types_.size()); | |
806 | go_assert(this->types_[i] == NULL); | |
807 | size_t offset = this->type_offsets_[i].first; | |
808 | size_t len = this->type_offsets_[i].second; | |
809 | ||
810 | Stream* orig_stream = this->stream_; | |
811 | ||
812 | Stream_from_string_ref stream(this->type_data_, offset, len); | |
813 | stream.set_pos(this->type_pos_ + offset); | |
814 | this->stream_ = &stream; | |
815 | ||
816 | this->require_c_string("type "); | |
817 | std::string str = this->read_identifier(); | |
818 | int id; | |
819 | if (!this->string_to_int(str, false, &id)) | |
820 | { | |
821 | this->stream_ = orig_stream; | |
822 | return false; | |
823 | } | |
824 | if (i != id) | |
825 | { | |
826 | go_error_at(this->location_, | |
827 | ("error in import data at %d: " | |
828 | "type ID mismatch: got %d, want %d"), | |
829 | stream.pos(), id, i); | |
830 | this->stream_ = orig_stream; | |
831 | return false; | |
832 | } | |
833 | ||
834 | this->require_c_string(" "); | |
835 | if (stream.peek_char() == '"') | |
836 | { | |
837 | stream.advance(1); | |
838 | Type* type = this->read_named_type(i); | |
839 | if (type->is_error_type()) | |
840 | { | |
841 | this->stream_ = orig_stream; | |
842 | return false; | |
843 | } | |
844 | } | |
845 | else | |
846 | { | |
847 | Type* type = Type::import_type(this); | |
848 | if (type->is_error_type()) | |
849 | { | |
850 | this->stream_ = orig_stream; | |
851 | return false; | |
852 | } | |
853 | this->types_[i] = type; | |
854 | ||
855 | this->require_c_string("\n"); | |
856 | } | |
857 | ||
858 | this->stream_ = orig_stream; | |
859 | return true; | |
860 | } | |
861 | ||
e440a328 | 862 | // Read a type in the import stream. This records the type by the |
80526a7d | 863 | // type index. If the type is named (which can only happen with older |
864 | // export formats), it registers the name, but marks it as invisible. | |
e440a328 | 865 | |
866 | Type* | |
867 | Import::read_type() | |
868 | { | |
869 | Stream* stream = this->stream_; | |
870 | this->require_c_string("<type "); | |
871 | ||
872 | std::string number; | |
873 | int c; | |
874 | while (true) | |
875 | { | |
876 | c = stream->get_char(); | |
877 | if (c != '-' && (c < '0' || c > '9')) | |
878 | break; | |
879 | number += c; | |
880 | } | |
881 | ||
882 | int index; | |
883 | if (!this->string_to_int(number, true, &index)) | |
884 | return Type::make_error_type(); | |
885 | ||
886 | if (c == '>') | |
887 | { | |
80526a7d | 888 | // A reference to a type defined earlier. |
eb75d23a | 889 | bool parsed; |
890 | return this->type_for_index(index, "import data", stream->pos(), | |
891 | &parsed); | |
e440a328 | 892 | } |
893 | ||
80526a7d | 894 | if (this->version_ >= EXPORT_FORMAT_V3) |
895 | { | |
896 | if (!stream->saw_error()) | |
897 | go_error_at(this->location_, | |
898 | "error in import data at %d: expected %<>%>", | |
899 | stream->pos()); | |
900 | stream->set_saw_error(); | |
901 | return Type::make_error_type(); | |
902 | } | |
903 | ||
e440a328 | 904 | if (c != ' ') |
905 | { | |
906 | if (!stream->saw_error()) | |
631d5788 | 907 | go_error_at(this->location_, |
80526a7d | 908 | "error in import data at %d: expected %< %> or %<>%>'", |
631d5788 | 909 | stream->pos()); |
e440a328 | 910 | stream->set_saw_error(); |
911 | stream->advance(1); | |
912 | return Type::make_error_type(); | |
913 | } | |
914 | ||
915 | if (index <= 0 | |
916 | || (static_cast<size_t>(index) < this->types_.size() | |
917 | && this->types_[index] != NULL)) | |
918 | { | |
631d5788 | 919 | go_error_at(this->location_, |
920 | "error in import data at %d: type index already defined", | |
921 | stream->pos()); | |
e440a328 | 922 | stream->set_saw_error(); |
923 | return Type::make_error_type(); | |
924 | } | |
925 | ||
926 | if (static_cast<size_t>(index) >= this->types_.size()) | |
927 | { | |
928 | int newsize = std::max(static_cast<size_t>(index) + 1, | |
929 | this->types_.size() * 2); | |
930 | this->types_.resize(newsize, NULL); | |
931 | } | |
932 | ||
933 | if (stream->peek_char() != '"') | |
934 | { | |
935 | Type* type = Type::import_type(this); | |
936 | this->require_c_string(">"); | |
937 | this->types_[index] = type; | |
938 | return type; | |
939 | } | |
940 | ||
e440a328 | 941 | stream->advance(1); |
80526a7d | 942 | |
943 | Type* type = this->read_named_type(index); | |
944 | ||
945 | this->require_c_string(">"); | |
946 | ||
947 | return type; | |
948 | } | |
949 | ||
950 | // Read a named type from the import stream and store it in | |
951 | // this->types_[index]. The stream should be positioned immediately | |
952 | // after the '"' that starts the name. | |
953 | ||
954 | Type* | |
955 | Import::read_named_type(int index) | |
956 | { | |
957 | Stream* stream = this->stream_; | |
e440a328 | 958 | std::string type_name; |
80526a7d | 959 | int c; |
e440a328 | 960 | while ((c = stream->get_char()) != '"') |
961 | type_name += c; | |
962 | ||
2a2647e2 | 963 | // If this type is in the package we are currently importing, the |
964 | // name will be .PKGPATH.NAME or simply NAME with no dots. | |
965 | // Otherwise, a non-hidden symbol will be PKGPATH.NAME and a hidden | |
966 | // symbol will be .PKGPATH.NAME. | |
967 | std::string pkgpath; | |
e440a328 | 968 | if (type_name.find('.') != std::string::npos) |
969 | { | |
e440a328 | 970 | size_t start = 0; |
971 | if (type_name[0] == '.') | |
2a2647e2 | 972 | start = 1; |
973 | size_t dot = type_name.rfind('.'); | |
974 | pkgpath = type_name.substr(start, dot - start); | |
975 | if (type_name[0] != '.') | |
976 | type_name.erase(0, dot + 1); | |
e440a328 | 977 | } |
978 | ||
979 | this->require_c_string(" "); | |
980 | ||
2a2647e2 | 981 | // The package name may follow. This is the name of the package in |
982 | // the package clause of that package. The type name will include | |
983 | // the pkgpath, which may be different. | |
984 | std::string package_name; | |
985 | if (stream->peek_char() == '"') | |
986 | { | |
987 | stream->advance(1); | |
988 | while ((c = stream->get_char()) != '"') | |
989 | package_name += c; | |
990 | this->require_c_string(" "); | |
991 | } | |
992 | ||
46cb4905 | 993 | bool is_alias = false; |
994 | if (this->match_c_string("= ")) | |
995 | { | |
996 | stream->advance(2); | |
997 | is_alias = true; | |
998 | } | |
999 | ||
e440a328 | 1000 | // Declare the type in the appropriate package. If we haven't seen |
1001 | // it before, mark it as invisible. We declare it before we read | |
1002 | // the actual definition of the type, since the definition may refer | |
1003 | // to the type itself. | |
1004 | Package* package; | |
2a2647e2 | 1005 | if (pkgpath.empty() || pkgpath == this->gogo_->pkgpath()) |
e440a328 | 1006 | package = this->package_; |
1007 | else | |
2a2647e2 | 1008 | { |
26197037 | 1009 | package = this->gogo_->register_package(pkgpath, "", |
2a2647e2 | 1010 | Linemap::unknown_location()); |
1011 | if (!package_name.empty()) | |
1012 | package->set_package_name(package_name, this->location()); | |
1013 | } | |
e440a328 | 1014 | |
1015 | Named_object* no = package->bindings()->lookup(type_name); | |
1016 | if (no == NULL) | |
1017 | no = package->add_type_declaration(type_name, this->location_); | |
1018 | else if (!no->is_type_declaration() && !no->is_type()) | |
1019 | { | |
631d5788 | 1020 | go_error_at(this->location_, "imported %<%s.%s%> both type and non-type", |
1021 | pkgpath.c_str(), Gogo::message_name(type_name).c_str()); | |
e440a328 | 1022 | stream->set_saw_error(); |
1023 | return Type::make_error_type(); | |
1024 | } | |
1025 | else | |
c484d925 | 1026 | go_assert(no->package() == package); |
e440a328 | 1027 | |
1028 | if (this->types_[index] == NULL) | |
1029 | { | |
1030 | if (no->is_type_declaration()) | |
1031 | { | |
1032 | // FIXME: It's silly to make a forward declaration every time. | |
1033 | this->types_[index] = Type::make_forward_declaration(no); | |
1034 | } | |
1035 | else | |
1036 | { | |
c484d925 | 1037 | go_assert(no->is_type()); |
e440a328 | 1038 | this->types_[index] = no->type_value(); |
1039 | } | |
1040 | } | |
1041 | ||
1042 | // If there is no type definition, then this is just a forward | |
1043 | // declaration of a type defined in some other file. | |
1044 | Type* type; | |
80526a7d | 1045 | if (this->match_c_string(">") || this->match_c_string("\n")) |
e440a328 | 1046 | type = this->types_[index]; |
1047 | else | |
1048 | { | |
1049 | type = this->read_type(); | |
1050 | ||
1051 | if (no->is_type_declaration()) | |
1052 | { | |
1053 | // We can define the type now. | |
1054 | ||
1055 | no = package->add_type(type_name, type, this->location_); | |
1056 | Named_type* ntype = no->type_value(); | |
1057 | ||
1058 | // This type has not yet been imported. | |
1059 | ntype->clear_is_visible(); | |
1060 | ||
9c164db9 | 1061 | if (is_alias) |
1062 | ntype->set_is_alias(); | |
1063 | ||
6914ada6 | 1064 | if (!type->is_undefined() && type->interface_type() != NULL) |
1065 | this->gogo_->record_interface_type(type->interface_type()); | |
1066 | ||
e440a328 | 1067 | type = ntype; |
1068 | } | |
1069 | else if (no->is_type()) | |
1070 | { | |
1071 | // We have seen this type before. FIXME: it would be a good | |
1072 | // idea to check that the two imported types are identical, | |
0873e18e | 1073 | // but we have not finalized the methods yet, which means |
1074 | // that we can not reliably compare interface types. | |
e440a328 | 1075 | type = no->type_value(); |
1076 | ||
1077 | // Don't change the visibility of the existing type. | |
1078 | } | |
1079 | ||
1080 | this->types_[index] = type; | |
1081 | ||
1082 | // Read the type methods. | |
1083 | if (this->match_c_string("\n")) | |
1084 | { | |
1085 | this->advance(1); | |
1086 | while (this->match_c_string(" func")) | |
1087 | { | |
1088 | this->advance(1); | |
1089 | this->import_func(package); | |
1090 | } | |
1091 | } | |
1092 | } | |
1093 | ||
e440a328 | 1094 | return type; |
1095 | } | |
1096 | ||
eb75d23a | 1097 | // Return the type given an index. Set *PARSED if we parsed it here. |
bc8e2ef4 | 1098 | |
1099 | Type* | |
1100 | Import::type_for_index(int index, const std::string& input_name, | |
eb75d23a | 1101 | size_t input_offset, bool* parsed) |
bc8e2ef4 | 1102 | { |
eb75d23a | 1103 | *parsed = false; |
bc8e2ef4 | 1104 | if (index >= 0 && !this->type_data_.empty()) |
1105 | { | |
1106 | if (static_cast<size_t>(index) >= this->type_offsets_.size()) | |
1107 | { | |
1108 | go_error_at(this->location_, | |
1109 | "error in %s at %lu: bad type index %d >= %d", | |
1110 | input_name.c_str(), | |
1111 | static_cast<unsigned long>(input_offset), | |
1112 | index, static_cast<int>(this->type_offsets_.size())); | |
1113 | return Type::make_error_type(); | |
1114 | } | |
1115 | ||
1116 | if (this->types_[index] == NULL) | |
1117 | { | |
1118 | if (!this->parse_type(index)) | |
1119 | return Type::make_error_type(); | |
eb75d23a | 1120 | *parsed = true; |
bc8e2ef4 | 1121 | } |
1122 | } | |
1123 | ||
1124 | if (index < 0 | |
1125 | ? (static_cast<size_t>(- index) >= this->builtin_types_.size() | |
1126 | || this->builtin_types_[- index] == NULL) | |
1127 | : (static_cast<size_t>(index) >= this->types_.size() | |
1128 | || this->types_[index] == NULL)) | |
1129 | { | |
1130 | go_error_at(this->location_, | |
1131 | "error in %s at %lu: bad type index %d", | |
1132 | input_name.c_str(), | |
1133 | static_cast<unsigned long>(input_offset), index); | |
1134 | return Type::make_error_type(); | |
1135 | } | |
1136 | ||
1137 | return index < 0 ? this->builtin_types_[- index] : this->types_[index]; | |
1138 | } | |
1139 | ||
ffa607ae | 1140 | // Read an escape note. |
1141 | ||
1142 | std::string | |
1143 | Import::read_escape() | |
1144 | { | |
1145 | if (this->match_c_string(" <esc:")) | |
1146 | { | |
1147 | Stream* stream = this->stream_; | |
1148 | this->require_c_string(" <esc:"); | |
1149 | ||
1150 | std::string escape = "esc:"; | |
1151 | int c; | |
1152 | while (true) | |
1153 | { | |
1154 | c = stream->get_char(); | |
1155 | if (c != 'x' && !ISXDIGIT(c)) | |
1156 | break; | |
1157 | escape += c; | |
1158 | } | |
1159 | ||
1160 | if (c != '>') | |
1161 | { | |
631d5788 | 1162 | go_error_at(this->location(), |
1163 | ("error in import data at %d: " | |
1164 | "expect %< %> or %<>%>, got %c"), | |
1165 | stream->pos(), c); | |
ffa607ae | 1166 | stream->set_saw_error(); |
1167 | stream->advance(1); | |
1168 | escape = Escape_note::make_tag(Node::ESCAPE_UNKNOWN); | |
1169 | } | |
1170 | return escape; | |
1171 | } | |
1172 | else | |
1173 | return Escape_note::make_tag(Node::ESCAPE_UNKNOWN); | |
1174 | } | |
1175 | ||
1176 | ||
e440a328 | 1177 | // Register the builtin types. |
1178 | ||
1179 | void | |
1180 | Import::register_builtin_types(Gogo* gogo) | |
1181 | { | |
1182 | this->register_builtin_type(gogo, "int8", BUILTIN_INT8); | |
1183 | this->register_builtin_type(gogo, "int16", BUILTIN_INT16); | |
1184 | this->register_builtin_type(gogo, "int32", BUILTIN_INT32); | |
1185 | this->register_builtin_type(gogo, "int64", BUILTIN_INT64); | |
1186 | this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8); | |
1187 | this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16); | |
1188 | this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32); | |
1189 | this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64); | |
1190 | this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32); | |
1191 | this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64); | |
1192 | this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64); | |
1193 | this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128); | |
1194 | this->register_builtin_type(gogo, "int", BUILTIN_INT); | |
1195 | this->register_builtin_type(gogo, "uint", BUILTIN_UINT); | |
1196 | this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR); | |
e440a328 | 1197 | this->register_builtin_type(gogo, "bool", BUILTIN_BOOL); |
1198 | this->register_builtin_type(gogo, "string", BUILTIN_STRING); | |
385c438b | 1199 | this->register_builtin_type(gogo, "error", BUILTIN_ERROR); |
5d4b8566 | 1200 | this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); |
1201 | this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); | |
e440a328 | 1202 | } |
1203 | ||
1204 | // Register a single builtin type. | |
1205 | ||
1206 | void | |
1207 | Import::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code) | |
1208 | { | |
1209 | Named_object* named_object = gogo->lookup_global(name); | |
c484d925 | 1210 | go_assert(named_object != NULL && named_object->is_type()); |
e440a328 | 1211 | int index = - static_cast<int>(code); |
c484d925 | 1212 | go_assert(index > 0 |
e440a328 | 1213 | && static_cast<size_t>(index) < this->builtin_types_.size()); |
1214 | this->builtin_types_[index] = named_object->type_value(); | |
1215 | } | |
1216 | ||
1217 | // Read an identifier from the stream. | |
1218 | ||
1219 | std::string | |
1220 | Import::read_identifier() | |
1221 | { | |
1222 | std::string ret; | |
1223 | Stream* stream = this->stream_; | |
1224 | int c; | |
1225 | while (true) | |
1226 | { | |
1227 | c = stream->peek_char(); | |
98386435 | 1228 | if (c == -1 || c == ' ' || c == '\n' || c == ';' || c == ')') |
e440a328 | 1229 | break; |
1230 | ret += c; | |
1231 | stream->advance(1); | |
1232 | } | |
1233 | return ret; | |
1234 | } | |
1235 | ||
68883531 | 1236 | // Read a name from the stream. |
1237 | ||
1238 | std::string | |
1239 | Import::read_name() | |
1240 | { | |
1241 | std::string ret = this->read_identifier(); | |
1242 | if (ret == "?") | |
1243 | ret.clear(); | |
68883531 | 1244 | return ret; |
1245 | } | |
1246 | ||
9890f25f | 1247 | // Read LENGTH bytes from the stream. |
1248 | ||
1249 | std::string | |
1250 | Import::read(size_t length) | |
1251 | { | |
1252 | const char* data; | |
1253 | if (!this->stream_->peek(length, &data)) | |
1254 | { | |
1255 | if (!this->stream_->saw_error()) | |
1256 | go_error_at(this->location_, "import error at %d: expected %d bytes", | |
1257 | this->stream_->pos(), static_cast<int>(length)); | |
1258 | this->stream_->set_saw_error(); | |
1259 | return ""; | |
1260 | } | |
1261 | this->advance(length); | |
1262 | return std::string(data, length); | |
1263 | } | |
1264 | ||
e440a328 | 1265 | // Turn a string into a integer with appropriate error handling. |
1266 | ||
1267 | bool | |
1268 | Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret) | |
1269 | { | |
1270 | char* end; | |
1271 | long prio = strtol(s.c_str(), &end, 10); | |
1272 | if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok)) | |
1273 | { | |
631d5788 | 1274 | go_error_at(this->location_, "invalid integer in import data at %d", |
1275 | this->stream_->pos()); | |
e440a328 | 1276 | this->stream_->set_saw_error(); |
1277 | return false; | |
1278 | } | |
1279 | *ret = prio; | |
1280 | return true; | |
1281 | } | |
1282 | ||
1283 | // Class Import::Stream. | |
1284 | ||
1285 | Import::Stream::Stream() | |
1286 | : pos_(0), saw_error_(false) | |
1287 | { | |
1288 | } | |
1289 | ||
1290 | Import::Stream::~Stream() | |
1291 | { | |
1292 | } | |
1293 | ||
1294 | // Return the next character to come from the stream. | |
1295 | ||
1296 | int | |
1297 | Import::Stream::peek_char() | |
1298 | { | |
1299 | const char* read; | |
1300 | if (!this->do_peek(1, &read)) | |
1301 | return -1; | |
1302 | // Make sure we return an unsigned char, so that we don't get | |
1303 | // confused by \xff. | |
1304 | unsigned char ret = *read; | |
1305 | return ret; | |
1306 | } | |
1307 | ||
1308 | // Return true if the next LENGTH characters from the stream match | |
1309 | // BYTES | |
1310 | ||
1311 | bool | |
1312 | Import::Stream::match_bytes(const char* bytes, size_t length) | |
1313 | { | |
1314 | const char* read; | |
1315 | if (!this->do_peek(length, &read)) | |
1316 | return false; | |
1317 | return memcmp(bytes, read, length) == 0; | |
1318 | } | |
1319 | ||
1320 | // Require that the next LENGTH bytes from the stream match BYTES. | |
1321 | ||
1322 | void | |
b13c66cd | 1323 | Import::Stream::require_bytes(Location location, const char* bytes, |
e440a328 | 1324 | size_t length) |
1325 | { | |
1326 | const char* read; | |
1327 | if (!this->do_peek(length, &read) | |
1328 | || memcmp(bytes, read, length) != 0) | |
1329 | { | |
1330 | if (!this->saw_error_) | |
631d5788 | 1331 | go_error_at(location, "import error at %d: expected %<%.*s%>", |
1332 | this->pos(), static_cast<int>(length), bytes); | |
e440a328 | 1333 | this->saw_error_ = true; |
1334 | return; | |
1335 | } | |
1336 | this->advance(length); | |
1337 | } | |
1338 | ||
1339 | // Class Stream_from_file. | |
1340 | ||
1341 | Stream_from_file::Stream_from_file(int fd) | |
1342 | : fd_(fd), data_() | |
1343 | { | |
1344 | if (lseek(fd, 0, SEEK_SET) != 0) | |
1345 | { | |
631d5788 | 1346 | go_fatal_error(Linemap::unknown_location(), "lseek failed: %m"); |
e440a328 | 1347 | this->set_saw_error(); |
1348 | } | |
1349 | } | |
1350 | ||
1351 | Stream_from_file::~Stream_from_file() | |
1352 | { | |
1353 | close(this->fd_); | |
1354 | } | |
1355 | ||
1356 | // Read next bytes. | |
1357 | ||
1358 | bool | |
1359 | Stream_from_file::do_peek(size_t length, const char** bytes) | |
1360 | { | |
1361 | if (this->data_.length() <= length) | |
1362 | { | |
1363 | *bytes = this->data_.data(); | |
1364 | return true; | |
1365 | } | |
80526a7d | 1366 | |
1367 | this->data_.resize(length); | |
1368 | ssize_t got = ::read(this->fd_, &this->data_[0], length); | |
e440a328 | 1369 | |
1370 | if (got < 0) | |
1371 | { | |
1372 | if (!this->saw_error()) | |
631d5788 | 1373 | go_fatal_error(Linemap::unknown_location(), "read failed: %m"); |
e440a328 | 1374 | this->set_saw_error(); |
1375 | return false; | |
1376 | } | |
1377 | ||
1378 | if (lseek(this->fd_, - got, SEEK_CUR) != 0) | |
1379 | { | |
1380 | if (!this->saw_error()) | |
631d5788 | 1381 | go_fatal_error(Linemap::unknown_location(), "lseek failed: %m"); |
e440a328 | 1382 | this->set_saw_error(); |
1383 | return false; | |
1384 | } | |
1385 | ||
1386 | if (static_cast<size_t>(got) < length) | |
1387 | return false; | |
1388 | ||
e440a328 | 1389 | *bytes = this->data_.data(); |
1390 | return true; | |
1391 | } | |
1392 | ||
1393 | // Advance. | |
1394 | ||
1395 | void | |
1396 | Stream_from_file::do_advance(size_t skip) | |
1397 | { | |
1398 | if (lseek(this->fd_, skip, SEEK_CUR) != 0) | |
1399 | { | |
1400 | if (!this->saw_error()) | |
631d5788 | 1401 | go_fatal_error(Linemap::unknown_location(), "lseek failed: %m"); |
e440a328 | 1402 | this->set_saw_error(); |
1403 | } | |
1404 | if (!this->data_.empty()) | |
1405 | { | |
1406 | if (this->data_.length() < skip) | |
1407 | this->data_.erase(0, skip); | |
1408 | else | |
1409 | this->data_.clear(); | |
1410 | } | |
1411 | } | |
81affb1d | 1412 | |
1413 | // Class Import_function_body. | |
1414 | ||
1415 | // The name of the function we are parsing. | |
1416 | ||
1417 | const std::string& | |
1418 | Import_function_body::name() const | |
1419 | { | |
1420 | return this->named_object_->name(); | |
1421 | } | |
bc8e2ef4 | 1422 | |
1423 | // Class Import_function_body. | |
1424 | ||
1425 | // Require that the next bytes match STR, issuing an error if not. | |
1426 | // Advance past the string. | |
1427 | ||
1428 | void | |
1429 | Import_function_body::require_c_string(const char* str) | |
1430 | { | |
1431 | if (!this->match_c_string(str)) | |
1432 | { | |
1433 | if (!this->saw_error_) | |
1434 | go_error_at(this->location(), | |
1435 | "invalid export data for %qs: expected %qs at %lu", | |
1436 | this->name().c_str(), str, | |
1437 | static_cast<unsigned long>(this->off_)); | |
1438 | this->saw_error_ = true; | |
1439 | return; | |
1440 | } | |
1441 | this->advance(strlen(str)); | |
1442 | } | |
1443 | ||
1444 | // Read an identifier. | |
1445 | ||
1446 | std::string | |
1447 | Import_function_body::read_identifier() | |
1448 | { | |
1449 | size_t start = this->off_; | |
1450 | for (size_t i = start; i < this->body_.length(); i++) | |
1451 | { | |
1452 | int c = static_cast<unsigned char>(this->body_[i]); | |
98386435 | 1453 | if (c == ' ' || c == '\n' || c == ';' || c == ')') |
bc8e2ef4 | 1454 | { |
1455 | this->off_ = i; | |
1456 | return this->body_.substr(start, i - start); | |
1457 | } | |
1458 | } | |
1459 | this->off_ = this->body_.length(); | |
1460 | return this->body_.substr(start); | |
1461 | } | |
1462 | ||
1463 | // Read a type. | |
1464 | ||
1465 | Type* | |
1466 | Import_function_body::read_type() | |
1467 | { | |
1468 | this->require_c_string("<type "); | |
1469 | size_t start = this->off_; | |
1470 | size_t i; | |
1471 | int c = '\0'; | |
1472 | for (i = start; i < this->body_.length(); ++i) | |
1473 | { | |
1474 | c = static_cast<unsigned char>(this->body_[i]); | |
1475 | if (c != '-' && (c < '0' || c > '9')) | |
1476 | break; | |
1477 | } | |
1478 | this->off_ = i + 1; | |
1479 | ||
1480 | char *end; | |
07f6bc25 | 1481 | std::string num = this->body_.substr(start, i - start); |
1482 | long val = strtol(num.c_str(), &end, 10); | |
1483 | if (*end != '\0' || val > 0x7fffffff) | |
bc8e2ef4 | 1484 | { |
1485 | if (!this->saw_error_) | |
1486 | go_error_at(this->location(), | |
1487 | "invalid export data for %qs: expected integer at %lu", | |
1488 | this->name().c_str(), | |
1489 | static_cast<unsigned long>(start)); | |
1490 | this->saw_error_ = true; | |
1491 | return Type::make_error_type(); | |
1492 | } | |
1493 | ||
1494 | if (c != '>') | |
1495 | { | |
1496 | if (!this->saw_error_) | |
1497 | go_error_at(this->location(), | |
1498 | "invalid export data for %qs: expected %<>%> at %lu", | |
1499 | this->name().c_str(), | |
1500 | static_cast<unsigned long>(i)); | |
1501 | this->saw_error_ = true; | |
1502 | return Type::make_error_type(); | |
1503 | } | |
1504 | ||
eb75d23a | 1505 | bool parsed; |
1506 | Type* type = this->imp_->type_for_index(static_cast<int>(val), this->name(), | |
1507 | static_cast<unsigned long>(start), | |
1508 | &parsed); | |
1509 | ||
1510 | // If we just read this type's information, its methods will not | |
1511 | // have been finalized. Do that now. | |
1512 | if (parsed) | |
1513 | this->gogo_->finalize_methods_for_type(type); | |
1514 | ||
1515 | return type; | |
bc8e2ef4 | 1516 | } |