-e1dc92a6037a3f81ea1b8ea8fb6207af33505f0c
+6db7e35d3bcd75ab3cb15296a5ddc5178038c9c1
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
// Constructor.
Export::Export(Stream* stream)
- : stream_(stream), type_refs_(), type_index_(1), packages_()
+ : stream_(stream), type_index_(1), packages_()
{
go_assert(Export::checksum_len == Go_sha1_helper::checksum_len);
}
+// Type hash table operations, treating aliases as distinct.
+
+class Type_hash_alias_identical
+{
+ public:
+ unsigned int
+ operator()(const Type* type) const
+ {
+ return type->hash_for_method(NULL,
+ (Type::COMPARE_ERRORS
+ | Type::COMPARE_TAGS
+ | Type::COMPARE_ALIASES));
+ }
+};
+
+class Type_alias_identical
+{
+ public:
+ bool
+ operator()(const Type* t1, const Type* t2) const
+ {
+ return Type::are_identical(t1, t2,
+ (Type::COMPARE_ERRORS
+ | Type::COMPARE_TAGS
+ | Type::COMPARE_ALIASES),
+ NULL);
+ }
+};
+
+// Mapping from Type objects to a constant index. This would be nicer
+// as a field in Export, but then export.h would have to #include
+// types.h.
+
+typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical,
+ Type_alias_identical) Type_refs;
+
+static Type_refs type_refs;
+
// A functor to sort Named_object pointers by name.
struct Sort_bindings
std::sort(exports.begin(), exports.end(), Sort_bindings());
- // Find all packages not explicitly imported but mentioned by types.
+ // Assign indexes to all exported types and types referenced by
+ // exported types, and collect all packages mentioned.
Unordered_set(const Package*) type_imports;
- this->prepare_types(&exports, &type_imports);
+ int unexported_type_index = this->prepare_types(&exports, &type_imports);
// Although the export data is readable, at least this version is,
// it is conceptually a binary format. Start with a four byte
// and ABI being used, although ideally any problems in that area
// would be caught by the linker.
+ // Write out all the types, both exported and not.
+ this->write_types(unexported_type_index);
+
+ // Write out the non-type export data.
for (std::vector<Named_object*>::const_iterator p = exports.begin();
p != exports.end();
++p)
- (*p)->export_named_object(this);
+ {
+ if (!(*p)->is_type())
+ (*p)->export_named_object(this);
+ }
std::string checksum = this->stream_->checksum();
std::string s = "checksum ";
class Find_types_to_prepare : public Traverse
{
public:
- Find_types_to_prepare(Unordered_set(const Package*)* imports)
+ Find_types_to_prepare(Export* exp,
+ Unordered_set(const Package*)* imports)
: Traverse(traverse_types),
- imports_(imports)
+ exp_(exp), imports_(imports)
{ }
int
traverse_named_type(Named_type*);
private:
+ // Exporters.
+ Export* exp_;
// List of packages we are building.
Unordered_set(const Package*)* imports_;
};
-// Traverse a type.
+// Set type index of referenced type, record package imports, and make
+// sure we traverse methods of named types.
int
Find_types_to_prepare::type(Type* type)
{
- // Skip forwarders.
+ // Skip forwarders; don't try to give them a type index.
if (type->forward_declaration_type() != NULL)
return TRAVERSE_CONTINUE;
+ // Skip the void type, which we'll see when exporting
+ // unsafe.Pointer. The void type is not itself exported, because
+ // Pointer_type::do_export checks for it.
+ if (type->is_void_type())
+ return TRAVERSE_SKIP_COMPONENTS;
+
+ if (!this->exp_->set_type_index(type))
+ {
+ // We've already seen this type.
+ return TRAVERSE_SKIP_COMPONENTS;
+ }
+
// At this stage of compilation traversing interface types traverses
// the final list of methods, but we export the locally defined
// methods. If there is an embedded interface type we need to make
}
// Traverse the types in a function type. We don't need the function
-// type tself, just the receiver, parameter, and result types.
+// type itself, just the receiver, parameter, and result types.
void
Find_types_to_prepare::traverse_function(Function_type* type)
}
}
-// Collect all the pacakges we see in types, so that if we refer to
-// any types from indirectly importe packages we can tell the importer
-// about the package.
+// Prepare to export types by assigning a type index to every exported
+// type and every type referenced by an exported type. Also collect
+// all the packages we see in types, so that if we refer to any types
+// from indirectly imported packages we can tell the importer about
+// the package. This returns the number of exported types.
-void
+int
Export::prepare_types(const std::vector<Named_object*>* exports,
Unordered_set(const Package*)* imports)
{
- // Use a single index of the traversal class because traversal
+ // Assign indexes to all the exported types.
+ for (std::vector<Named_object*>::const_iterator p = exports->begin();
+ p != exports->end();
+ ++p)
+ {
+ if (!(*p)->is_type())
+ continue;
+ this->set_type_index((*p)->type_value());
+ }
+
+ int ret = this->type_index_;
+
+ // Use a single instance of the traversal class because traversal
// classes keep track of which types they've already seen. That
// lets us avoid type reference loops.
- Find_types_to_prepare find(imports);
+ Find_types_to_prepare find(this, imports);
- // Traverse all the exported objects.
+ // Traverse all the exported objects and assign indexes to all types.
for (std::vector<Named_object*>::const_iterator p = exports->begin();
p != exports->end();
++p)
break;
case Named_object::NAMED_OBJECT_TYPE:
- Type::traverse(no->type_value(), &find);
+ Type::traverse(no->type_value()->real_type(), &find);
+ find.traverse_named_type(no->type_value());
break;
case Named_object::NAMED_OBJECT_VAR:
break;
}
}
+
+ return ret;
+}
+
+// Give a type an index if it doesn't already have one. Return true
+// if we set the type index, false if it was already known.
+
+bool
+Export::set_type_index(Type* type)
+{
+ type = type->forwarded();
+
+ std::pair<Type_refs::iterator, bool> ins =
+ type_refs.insert(std::make_pair(type, 0));
+ if (!ins.second)
+ {
+ // We've already seen this type.
+ return false;
+ }
+
+ int index = this->type_index_;
+ ++this->type_index_;
+ ins.first->second = index;
+
+ return true;
}
// Sort packages.
this->write_c_string("\n");
}
+// Write the types to the export stream.
+
+void
+Export::write_types(int unexported_type_index)
+{
+ // Map from type index to type.
+ std::vector<const Type*> types(static_cast<size_t>(this->type_index_));
+ for (Type_refs::const_iterator p = type_refs.begin();
+ p != type_refs.end();
+ ++p)
+ {
+ if (p->second >= 0)
+ types.at(p->second) = p->first;
+ }
+
+ // Write the type information to a buffer.
+ Stream_to_string type_data;
+ Export::Stream* orig_stream = this->stream_;
+ this->stream_ = &type_data;
+
+ std::vector<size_t> type_sizes(static_cast<size_t>(this->type_index_));
+ type_sizes[0] = 0;
+
+ // Start at 1 because type index 0 is not used.
+ size_t start_size = 0;
+ for (int i = 1; i < this->type_index_; ++i)
+ {
+ this->write_type_definition(types[i], i);
+
+ size_t cur_size = type_data.string().size();
+ type_sizes[i] = cur_size - start_size;
+ start_size = cur_size;
+ }
+
+ // Back to original stream.
+ this->stream_ = orig_stream;
+
+ // The line "types MAXP1 EXPORTEDP1 SIZES..." appears before the
+ // types. MAXP1 is one more than the maximum type index used; that
+ // is, it is the size of the array we need to allocate to hold all
+ // the values. Indexes 1 up to but not including EXPORTEDP1 are the
+ // exported types. The other types are not exported. SIZES... is a
+ // list of MAXP1-1 entries listing the size of the type definition
+ // for each type, starting at index 1.
+ char buf[100];
+ snprintf(buf, sizeof buf, "types %d %d", this->type_index_,
+ unexported_type_index);
+ this->write_c_string(buf);
+
+ // Start at 1 because type index 0 is not used.
+ for (int i = 1; i < this->type_index_; ++i)
+ {
+ snprintf(buf, sizeof buf, " %lu",
+ static_cast<unsigned long>(type_sizes[i]));
+ this->write_c_string(buf);
+ }
+ this->write_c_string("\n");
+ this->write_string(type_data.string());
+}
+
+// Write a single type to the export stream.
+
+void
+Export::write_type_definition(const Type* type, int index)
+{
+ this->write_c_string("type ");
+
+ char buf[30];
+ snprintf(buf, sizeof buf, "%d ", index);
+ this->write_c_string(buf);
+
+ const Named_type* nt = type->named_type();
+ if (nt != NULL)
+ {
+ const Named_object* no = nt->named_object();
+ const Package* package = no->package();
+
+ this->write_c_string("\"");
+ if (package != NULL && !Gogo::is_hidden_name(no->name()))
+ {
+ this->write_string(package->pkgpath());
+ this->write_c_string(".");
+ }
+ this->write_string(nt->named_object()->name());
+ this->write_c_string("\" ");
+
+ if (nt->is_alias())
+ this->write_c_string("= ");
+ }
+
+ type->export_type(this);
+
+ // Type::export_type will print a newline for a named type, but not
+ // otherwise.
+ if (nt == NULL)
+ this->write_c_string("\n");
+}
+
// Write a name to the export stream.
void
this->write_c_string(buf);
}
-// Export a type. We have to ensure that on import we create a single
-// Named_type node for each named type. We do this by keeping a hash
-// table mapping named types to reference numbers. The first time we
-// see a named type we assign it a reference number by making an entry
-// in the hash table. If we see it again, we just refer to the
-// reference number.
-
-// Named types are, of course, associated with packages. Note that we
-// may see a named type when importing one package, and then later see
-// the same named type when importing a different package. The home
-// package may or may not be imported during this compilation. The
-// reference number scheme has to get this all right. Basic approach
-// taken from "On the Linearization of Graphs and Writing Symbol
-// Files" by Robert Griesemer.
+// Export a type.
void
Export::write_type(const Type* type)
{
- // We don't want to assign a reference number to a forward
- // declaration to a type which was defined later.
type = type->forwarded();
-
- Type_refs::const_iterator p = this->type_refs_.find(type);
- if (p != this->type_refs_.end())
- {
- // This type was already in the table.
- int index = p->second;
- go_assert(index != 0);
- char buf[30];
- snprintf(buf, sizeof buf, "<type %d>", index);
- this->write_c_string(buf);
- return;
- }
-
- const Named_type* named_type = type->named_type();
- const Forward_declaration_type* forward = type->forward_declaration_type();
-
- int index = this->type_index_;
- ++this->type_index_;
-
+ Type_refs::const_iterator p = type_refs.find(type);
+ go_assert(p != type_refs.end());
+ int index = p->second;
+ go_assert(index != 0);
char buf[30];
- snprintf(buf, sizeof buf, "<type %d ", index);
+ snprintf(buf, sizeof buf, "<type %d>", index);
this->write_c_string(buf);
-
- if (named_type != NULL || forward != NULL)
- {
- const Named_object* named_object;
- if (named_type != NULL)
- {
- // The builtin types should have been predefined.
- go_assert(!Linemap::is_predeclared_location(named_type->location())
- || (named_type->named_object()->package()->package_name()
- == "unsafe"));
- named_object = named_type->named_object();
- }
- else
- named_object = forward->named_object();
-
- const Package* package = named_object->package();
-
- std::string s = "\"";
- if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
- {
- s += package->pkgpath();
- s += '.';
- }
- s += named_object->name();
- s += "\" ";
- this->write_string(s);
-
- // We must add a named type to the table now, since the
- // definition of the type may refer to the named type via a
- // pointer.
- this->type_refs_[type] = index;
-
- if (named_type != NULL && named_type->is_alias())
- this->write_c_string("= ");
- }
-
- type->export_type(this);
-
- this->write_c_string(">");
-
- if (named_type == NULL)
- this->type_refs_[type] = index;
}
// Export escape note.
Named_object* named_object = gogo->lookup_global(name);
go_assert(named_object != NULL && named_object->is_type());
std::pair<Type_refs::iterator, bool> ins =
- this->type_refs_.insert(std::make_pair(named_object->type_value(), code));
+ type_refs.insert(std::make_pair(named_object->type_value(), code));
go_assert(ins.second);
// We also insert the underlying type. We can see the underlying
- // type at least for string and bool. We skip the type aliases byte
- // and rune here.
- if (code != BUILTIN_BYTE && code != BUILTIN_RUNE)
- {
- Type* real_type = named_object->type_value()->real_type();
- ins = this->type_refs_.insert(std::make_pair(real_type, code));
- go_assert(ins.second);
- }
+ // type at least for string and bool. It's OK if this insert
+ // fails--we expect duplications here, and it doesn't matter when
+ // they occur.
+ Type* real_type = named_object->type_value()->real_type();
+ type_refs.insert(std::make_pair(real_type, code));
}
// Class Export::Stream.
class Go_sha1_helper;
class Gogo;
+class Named_object;
class Import_init;
class Named_object;
class Bindings;
const Import_init_set& imported_init_fns,
const Bindings* bindings);
+ // Set the index of a type.
+ bool
+ set_type_index(Type*);
+
// Write a string to the export stream.
void
write_string(const std::string& s)
Export& operator=(const Export&);
// Prepare types for exporting.
- void
+ int
prepare_types(const std::vector<Named_object*>* exports,
Unordered_set(const Package*)* imports);
write_imported_init_fns(const std::string& package_name,
const std::string&, const Import_init_set&);
+ // Write out all types.
+ void
+ write_types(int unexported_type_index);
+
+ // Write out one type definition.
+ void
+ write_type_definition(const Type* type, int index);
+
// Register one builtin type.
void
register_builtin_type(Gogo*, const char* name, Builtin_code);
- // Mapping from Type objects to a constant index.
- typedef Unordered_map(const Type*, int) Type_refs;
-
// The stream to which we are writing data.
Stream* stream_;
- // Type mappings.
- Type_refs type_refs_;
// Index number of next type.
int type_index_;
// Packages we have written out.
Unordered_set(const Package*) packages_;
};
-// An export streamer which puts the export stream in a named section.
+// An export streamer that puts the export stream in a named section.
class Stream_to_section : public Export::Stream
{
Backend* backend_;
};
+// An export streamer that puts the export stream in a string.
+
+class Stream_to_string : public Export::Stream
+{
+ public:
+ Stream_to_string()
+ : string_()
+ {}
+
+ const std::string&
+ string() const
+ { return this->string_; }
+
+ protected:
+ void
+ do_write(const char* s, size_t len)
+ { this->string_.append(s, len); }
+
+ private:
+ std::string string_;
+};
+
#endif // !defined(GO_EXPORT_H)
break;
case NAMED_OBJECT_TYPE:
- this->type_value()->export_named_type(exp, this->name_);
- break;
+ // Types are handled by export::write_types.
+ go_unreachable();
case NAMED_OBJECT_TYPE_DECLARATION:
go_error_at(this->type_declaration_value()->location(),
class Traverse;
class Statement_inserter;
class Type;
-class Type_hash_identical;
class Type_equal;
-class Type_identical;
class Typed_identifier;
class Typed_identifier_list;
class Function_type;
}
char buf[len];
- ssize_t c = read(fd, buf, len);
+ ssize_t c = ::read(fd, buf, len);
if (c < len)
return NULL;
Import::Import(Stream* stream, Location location)
: gogo_(NULL), stream_(stream), location_(location), package_(NULL),
- add_to_globals_(false),
+ add_to_globals_(false), type_data_(), type_pos_(0), type_offsets_(),
builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
types_(), version_(EXPORT_FORMAT_UNKNOWN)
{
if (stream->match_c_string("init"))
this->read_import_init_fns(gogo);
+ if (stream->match_c_string("types "))
+ {
+ if (!this->read_types())
+ return NULL;
+ }
+
// Loop over all the input data for this package.
while (!stream->saw_error())
{
}
}
+// Import the types. Starting in export format version 3 all the
+// types are listed first.
+
+bool
+Import::read_types()
+{
+ this->require_c_string("types ");
+ std::string str = this->read_identifier();
+ int maxp1;
+ if (!this->string_to_int(str, false, &maxp1))
+ return false;
+
+ this->require_c_string(" ");
+ str = this->read_identifier();
+ int exportedp1;
+ if (!this->string_to_int(str, false, &exportedp1))
+ return false;
+
+ this->type_offsets_.resize(maxp1, std::make_pair<size_t, size_t>(0, 0));
+ size_t total_type_size = 0;
+ // Start at 1 because type index 0 not used.
+ for (int i = 1; i < maxp1; i++)
+ {
+ this->require_c_string(" ");
+ str = this->read_identifier();
+ int v;
+ if (!this->string_to_int(str, false, &v))
+ return false;
+ size_t vs = static_cast<size_t>(v);
+ this->type_offsets_[i] = std::make_pair(total_type_size, vs);
+ total_type_size += vs;
+ }
+
+ this->require_c_string("\n");
+
+ // Types can refer to each other in an unpredictable order. Read
+ // all the type data into type_data_. The type_offsets_ vector we
+ // just initialized provides indexes into type_data_.
+
+ this->type_pos_ = this->stream_->pos();
+ const char* type_data;
+ if (!this->stream_->peek(total_type_size, &type_data))
+ return false;
+ this->type_data_ = std::string(type_data, total_type_size);
+ this->advance(total_type_size);
+
+ this->types_.resize(maxp1, NULL);
+
+ // Parse all the exported types now, so that the names are properly
+ // bound and visible to the parser. Parse unexported types lazily.
+
+ // Start at 1 because there is no type 0.
+ for (int i = 1; i < exportedp1; i++)
+ {
+ // We may have already parsed this type when we parsed an
+ // earlier type.
+ Type* type = this->types_[i];
+ if (type == NULL)
+ {
+ if (!this->parse_type(i))
+ return false;
+ type = this->types_[i];
+ go_assert(type != NULL);
+ }
+ Named_type* nt = type->named_type();
+ if (nt == NULL)
+ {
+ go_error_at(this->location_,
+ "error in import data: exported unnamed type %d",
+ i);
+ return false;
+ }
+ nt->set_is_visible();
+ if (this->add_to_globals_)
+ this->gogo_->add_named_type(nt);
+ }
+
+ return true;
+}
+
// Import a constant.
void
void
Import::import_type()
{
+ if (this->version_ >= EXPORT_FORMAT_V3)
+ {
+ if (!this->stream_->saw_error())
+ {
+ go_error_at(this->location_,
+ "error in import data at %d: old type syntax",
+ this->stream_->pos());
+ this->stream_->set_saw_error();
+ }
+ return;
+ }
+
Named_type* type;
Named_type::import_named_type(this, &type);
return no;
}
+// Read a type definition and initialize the entry in this->types_.
+// This parses the type definition saved by read_types earlier. This
+// returns true on success, false on failure.
+
+bool
+Import::parse_type(int i)
+{
+ go_assert(i >= 0 && static_cast<size_t>(i) < this->types_.size());
+ go_assert(this->types_[i] == NULL);
+ size_t offset = this->type_offsets_[i].first;
+ size_t len = this->type_offsets_[i].second;
+
+ Stream* orig_stream = this->stream_;
+
+ Stream_from_string_ref stream(this->type_data_, offset, len);
+ stream.set_pos(this->type_pos_ + offset);
+ this->stream_ = &stream;
+
+ this->require_c_string("type ");
+ std::string str = this->read_identifier();
+ int id;
+ if (!this->string_to_int(str, false, &id))
+ {
+ this->stream_ = orig_stream;
+ return false;
+ }
+ if (i != id)
+ {
+ go_error_at(this->location_,
+ ("error in import data at %d: "
+ "type ID mismatch: got %d, want %d"),
+ stream.pos(), id, i);
+ this->stream_ = orig_stream;
+ return false;
+ }
+
+ this->require_c_string(" ");
+ if (stream.peek_char() == '"')
+ {
+ stream.advance(1);
+ Type* type = this->read_named_type(i);
+ if (type->is_error_type())
+ {
+ this->stream_ = orig_stream;
+ return false;
+ }
+ }
+ else
+ {
+ Type* type = Type::import_type(this);
+ if (type->is_error_type())
+ {
+ this->stream_ = orig_stream;
+ return false;
+ }
+ this->types_[i] = type;
+
+ this->require_c_string("\n");
+ }
+
+ this->stream_ = orig_stream;
+ return true;
+}
+
// Read a type in the import stream. This records the type by the
-// type index. If the type is named, it registers the name, but marks
-// it as invisible.
+// type index. If the type is named (which can only happen with older
+// export formats), it registers the name, but marks it as invisible.
Type*
Import::read_type()
if (c == '>')
{
- // This type was already defined.
+ // A reference to a type defined earlier.
+
+ if (index >= 0 && !this->type_data_.empty())
+ {
+ if (static_cast<size_t>(index) >= this->type_offsets_.size())
+ {
+ go_error_at(this->location_,
+ ("error in import data at %d: "
+ "bad type index %d >= %d"),
+ stream->pos(), index,
+ static_cast<int>(this->type_offsets_.size()));
+ stream->set_saw_error();
+ return Type::make_error_type();
+ }
+
+ if (this->types_[index] == NULL)
+ {
+ if (!this->parse_type(index))
+ return Type::make_error_type();
+ }
+ }
+
if (index < 0
? (static_cast<size_t>(- index) >= this->builtin_types_.size()
|| this->builtin_types_[- index] == NULL)
return index < 0 ? this->builtin_types_[- index] : this->types_[index];
}
+ if (this->version_ >= EXPORT_FORMAT_V3)
+ {
+ if (!stream->saw_error())
+ go_error_at(this->location_,
+ "error in import data at %d: expected %<>%>",
+ stream->pos());
+ stream->set_saw_error();
+ return Type::make_error_type();
+ }
+
if (c != ' ')
{
if (!stream->saw_error())
go_error_at(this->location_,
- "error in import data at %d: expect %< %> or %<>%>'",
+ "error in import data at %d: expected %< %> or %<>%>'",
stream->pos());
stream->set_saw_error();
stream->advance(1);
return type;
}
- // This type has a name.
-
stream->advance(1);
+
+ Type* type = this->read_named_type(index);
+
+ this->require_c_string(">");
+
+ return type;
+}
+
+// Read a named type from the import stream and store it in
+// this->types_[index]. The stream should be positioned immediately
+// after the '"' that starts the name.
+
+Type*
+Import::read_named_type(int index)
+{
+ Stream* stream = this->stream_;
std::string type_name;
+ int c;
while ((c = stream->get_char()) != '"')
type_name += c;
// If there is no type definition, then this is just a forward
// declaration of a type defined in some other file.
Type* type;
- if (this->match_c_string(">"))
+ if (this->match_c_string(">") || this->match_c_string("\n"))
type = this->types_[index];
else
{
}
}
- this->require_c_string(">");
-
return type;
}
*bytes = this->data_.data();
return true;
}
- // Don't bother to handle the general case, since we don't need it.
- go_assert(length < 64);
- char buf[64];
- ssize_t got = read(this->fd_, buf, length);
+
+ this->data_.resize(length);
+ ssize_t got = ::read(this->fd_, &this->data_[0], length);
if (got < 0)
{
if (static_cast<size_t>(got) < length)
return false;
- this->data_.assign(buf, got);
-
*bytes = this->data_.data();
return true;
}
Stream();
virtual ~Stream();
+ // Set the position, for error messages.
+ void
+ set_pos(int pos)
+ { this->pos_ = pos; }
+
// Return whether we have seen an error.
bool
saw_error() const
void
read_import_init_fns(Gogo*);
+ // Read the types.
+ bool
+ read_types();
+
// Import a constant.
void
import_const();
Named_object*
import_func(Package*);
+ // Parse a type definition.
+ bool
+ parse_type(int index);
+
+ // Read a named type and store it at this->type_[index].
+ Type*
+ read_named_type(int index);
+
// Register a single builtin type.
void
register_builtin_type(Gogo*, const char* name, Builtin_code);
// Whether to add new objects to the global scope, rather than to a
// package scope.
bool add_to_globals_;
+ // All type data.
+ std::string type_data_;
+ // Position of type data in the stream.
+ int type_pos_;
+ // Mapping from type code to offset/length in type_data_.
+ std::vector<std::pair<size_t, size_t> > type_offsets_;
// Mapping from negated builtin type codes to Type structures.
std::vector<Named_type*> builtin_types_;
// Mapping from exported type codes to Type structures.
std::string data_;
};
+// Read import data from an offset into a std::string. This uses a
+// reference to the string, to avoid copying, so the string must be
+// kept alive through some other mechanism.
+
+class Stream_from_string_ref : public Import::Stream
+{
+ public:
+ Stream_from_string_ref(const std::string& str, size_t offset, size_t length)
+ : str_(str), pos_(offset), end_(offset + length)
+ { }
+
+ ~Stream_from_string_ref()
+ {}
+
+ protected:
+ bool
+ do_peek(size_t length, const char** bytes)
+ {
+ if (this->pos_ + length > this->end_)
+ return false;
+ *bytes = &this->str_[this->pos_];
+ return true;
+ }
+
+ void
+ do_advance(size_t length)
+ { this->pos_ += length; }
+
+ private:
+ // A reference to the string we are reading from.
+ const std::string& str_;
+ // The current offset into the string.
+ size_t pos_;
+ // The index after the last byte we can read.
+ size_t end_;
+};
+
#endif // !defined(GO_IMPORT_H)
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
}
-// Export the type. This is called to export a global type.
-
-void
-Named_type::export_named_type(Export* exp, const std::string&) const
-{
- // We don't need to write the name of the type here, because it will
- // be written by Export::write_type anyhow.
- exp->write_c_string("type ");
- exp->write_type(this);
- exp->write_c_string("\n");
-}
-
-// Import a named type.
+// Import a named type. This is only used for export format versions
+// before version 3.
void
Named_type::import_named_type(Import* imp, Named_type** ptype)
}
// Export the type when it is referenced by another type. In this
-// case Export::export_type will already have issued the name.
+// case Export::export_type will already have issued the name. The
+// output always ends with a newline, since that is convenient if
+// there are methods.
void
Named_type::do_export(Export* exp) const
{
exp->write_type(this->type_);
+ exp->write_c_string("\n");
// To save space, we only export the methods directly attached to
// this type.
if (methods == NULL)
return;
- exp->write_c_string("\n");
for (Bindings::const_definitions_iterator p = methods->begin_definitions();
p != methods->end_definitions();
++p)
void
append_mangled_type_name(Gogo*, bool use_alias, std::string*) const;
- // Export the type.
- void
- export_named_type(Export*, const std::string& name) const;
-
// Import a named type.
static void
import_named_type(Import*, Named_type**);
)
type parser struct {
- scanner scanner.Scanner
+ scanner *scanner.Scanner
version string // format version
tok rune // current token
lit string // literal string; only valid for Ident, Int, String tokens
pkg *types.Package // reference to imported package
imports map[string]*types.Package // package path -> package object
typeMap map[int]types.Type // type number -> type
+ typeData []string // unparsed type data
initdata InitData // package init priority data
}
func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
+ p.scanner = new(scanner.Scanner)
+ p.initScanner(filename, src)
+ p.imports = imports
+ p.typeMap = make(map[int]types.Type)
+}
+
+func (p *parser) initScanner(filename string, src io.Reader) {
p.scanner.Init(src)
p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
p.scanner.Whitespace = 1<<'\t' | 1<<' '
p.scanner.Filename = filename // for good error messages
p.next()
- p.imports = imports
- p.typeMap = make(map[int]types.Type)
}
type importError struct {
n := p.parseInt()
if p.tok == '>' {
+ if len(p.typeData) > 0 && p.typeMap[int(n)] == nil {
+ p.parseSavedType(pkg, int(n))
+ }
t = p.typeMap[int(n)]
} else {
t = p.parseTypeDefinition(pkg, int(n))
return
}
+// Types = "types" maxp1 exportedp1 (offset length)* .
+func (p *parser) parseTypes(pkg *types.Package) {
+ maxp1 := p.parseInt()
+ exportedp1 := p.parseInt()
+
+ type typeOffset struct {
+ offset int
+ length int
+ }
+ var typeOffsets []typeOffset
+
+ total := 0
+ for i := 1; i < int(maxp1); i++ {
+ len := int(p.parseInt())
+ typeOffsets = append(typeOffsets, typeOffset{total, len})
+ total += len
+ }
+
+ // We should now have p.tok pointing to the final newline.
+ // The next runes from the scanner should be the type data.
+
+ var sb strings.Builder
+ for sb.Len() < total {
+ r := p.scanner.Next()
+ if r == scanner.EOF {
+ p.error("unexpected EOF")
+ }
+ sb.WriteRune(r)
+ }
+ allTypeData := sb.String()
+
+ p.typeData = []string{""} // type 0, unused
+ for _, to := range typeOffsets {
+ p.typeData = append(p.typeData, allTypeData[to.offset:to.offset+to.length])
+ }
+
+ for i := 1; i < int(exportedp1); i++ {
+ p.parseSavedType(pkg, i)
+ }
+}
+
+// parseSavedType parses one saved type definition.
+func (p *parser) parseSavedType(pkg *types.Package, i int) {
+ defer func(s *scanner.Scanner, tok rune, lit string) {
+ p.scanner = s
+ p.tok = tok
+ p.lit = lit
+ }(p.scanner, p.tok, p.lit)
+
+ p.scanner = new(scanner.Scanner)
+ p.initScanner(p.scanner.Filename, strings.NewReader(p.typeData[i]))
+ p.expectKeyword("type")
+ id := int(p.parseInt())
+ if id != i {
+ p.errorf("type ID mismatch: got %d, want %d", id, i)
+ }
+ if p.typeMap[i] == nil {
+ p.typeMap[i] = p.parseTypeDefinition(pkg, i)
+ }
+}
+
// PackageInit = unquotedString unquotedString int .
func (p *parser) parsePackageInit() PackageInit {
name := p.parseUnquotedString()
p.getPkg(pkgpath, pkgname)
p.expectEOL()
+ case "types":
+ p.next()
+ p.parseTypes(p.pkg)
+ p.expectEOL()
+
case "func":
p.next()
fun := p.parseFunc(p.pkg)