-75d48ff977a2865d12b03857362ea48016a4b885
+6e0974fc6c9aa6ef19f72fbb5698e4b3734a4220
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
{ }
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
protected:
bool
// Import a boolean constant.
Expression*
-Boolean_expression::do_import(Import* imp, Location loc)
+Boolean_expression::do_import(Import_expression* imp, Location loc)
{
if (imp->peek_char() == 't')
{
// Import a string expression.
Expression*
-String_expression::do_import(Import* imp, Location loc)
+String_expression::do_import(Import_expression* imp, Location loc)
{
imp->require_c_string("\"");
std::string val;
{ mpz_init_set(this->val_, *val); }
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
// Write VAL to string dump.
static void
// all these types because they all start with digits.
Expression*
-Integer_expression::do_import(Import* imp, Location loc)
+Integer_expression::do_import(Import_expression* imp, Location loc)
{
std::string num = imp->read_identifier();
imp->require_c_string(" ");
{ }
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
protected:
bool
// Import a nil expression.
Expression*
-Nil_expression::do_import(Import* imp, Location loc)
+Nil_expression::do_import(Import_expression* imp, Location loc)
{
imp->require_c_string("nil");
return Expression::make_nil(loc);
// Import a type conversion or a struct construction.
Expression*
-Type_conversion_expression::do_import(Import* imp, Location loc)
+Type_conversion_expression::do_import(Import_expression* imp, Location loc)
{
imp->require_c_string("convert(");
Type* type = imp->read_type();
// Import a unary expression.
Expression*
-Unary_expression::do_import(Import* imp, Location loc)
+Unary_expression::do_import(Import_expression* imp, Location loc)
{
Operator op;
switch (imp->get_char())
// Import a binary expression.
Expression*
-Binary_expression::do_import(Import* imp, Location loc)
+Binary_expression::do_import(Import_expression* imp, Location loc)
{
imp->require_c_string("(");
// various class definitions.
Expression*
-Expression::import_expression(Import* imp, Location loc)
+Expression::import_expression(Import_expression* imp, Location loc)
{
int c = imp->peek_char();
if (imp->match_c_string("- ")
class Numeric_constant;
class Named_object;
class Export_function_body;
-class Import;
+class Import_expression;
class Temporary_statement;
class Label;
class Ast_dump_context;
// returned expression. Errors should be reported using the
// Import's location method.
static Expression*
- import_expression(Import*, Location);
+ import_expression(Import_expression*, Location);
// Return an expression which checks that VAL, of arbitrary integer type,
// is non-negative and is not more than the maximum integer value.
{ return this->val_; }
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
protected:
bool
// Import a type conversion expression.
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
protected:
int
Location, Numeric_constant* nc, bool *issued_error);
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
// Declare that this deref does or does not require an explicit nil check.
void
bool* result);
static Expression*
- do_import(Import*, Location);
+ do_import(Import_expression*, Location);
// Report an error if OP can not be applied to TYPE. Return whether
// it can. OTYPE is the type of the other operand.
return;
}
- Import imp(stream, location);
- imp.register_builtin_types(this);
- Package* package = imp.import(this, local_name, is_local_name_exported);
+ Import* imp = new Import(stream, location);
+ imp->register_builtin_types(this);
+ Package* package = imp->import(this, local_name, is_local_name_exported);
if (package != NULL)
{
if (package->pkgpath() == this->pkgpath())
this->imports_.insert(std::make_pair(filename, package));
}
+ imp->clear_stream();
delete stream;
+
+ // FIXME: we never delete imp; we may need it for inlinable functions.
}
Import_init *
const std::string& body(this->imported_body_);
go_assert(!body.empty());
- Location orig_loc = no->location();
-
// Read the "//FILE:LINE" comment starts the export data.
size_t indent = 1;
no = rtype->add_method(no->name(), fn);
}
- Import_function_body ifb(gogo, orig_loc, no, body, nl + 1, outer, indent);
+ Import_function_body ifb(gogo, this->imp_, no, body, nl + 1, outer, indent);
if (!Block::import_block(outer, &ifb, start_loc))
return;
// Record the imported body of this function.
void
- set_imported_body(const std::string& imported_body)
- { this->imported_body_ = imported_body; }
+ set_imported_body(Import* imp, const std::string& imported_body)
+ {
+ this->imp_ = imp;
+ this->imported_body_ = imported_body;
+ }
// Whether this declaration is on the list of inlinable functions.
bool
Bfunction* fndecl_;
// Pragmas for this function. This is a set of GOPRAGMA bits.
unsigned int pragmas_;
+ // Importer for function body if imported from a different package.
+ Import* imp_;
// Export data for function body if imported from a different package.
std::string imported_body_;
// Whether this declaration is already on the list of inlinable functions.
if (nointerface)
no->func_declaration_value()->set_nointerface();
if (!body.empty() && !no->func_declaration_value()->has_imported_body())
- no->func_declaration_value()->set_imported_body(body);
+ no->func_declaration_value()->set_imported_body(this, body);
return no;
}
if (c == '>')
{
// 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)
- : (static_cast<size_t>(index) >= this->types_.size()
- || this->types_[index] == NULL))
- {
- go_error_at(this->location_,
- "error in import data at %d: bad type index %d",
- stream->pos(), index);
- stream->set_saw_error();
- return Type::make_error_type();
- }
-
- return index < 0 ? this->builtin_types_[- index] : this->types_[index];
+ return this->type_for_index(index, "import data", stream->pos());
}
if (this->version_ >= EXPORT_FORMAT_V3)
return type;
}
+// Return the type given an index.
+
+Type*
+Import::type_for_index(int index, const std::string& input_name,
+ size_t input_offset)
+{
+ if (index >= 0 && !this->type_data_.empty())
+ {
+ if (static_cast<size_t>(index) >= this->type_offsets_.size())
+ {
+ go_error_at(this->location_,
+ "error in %s at %lu: bad type index %d >= %d",
+ input_name.c_str(),
+ static_cast<unsigned long>(input_offset),
+ index, static_cast<int>(this->type_offsets_.size()));
+ 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)
+ : (static_cast<size_t>(index) >= this->types_.size()
+ || this->types_[index] == NULL))
+ {
+ go_error_at(this->location_,
+ "error in %s at %lu: bad type index %d",
+ input_name.c_str(),
+ static_cast<unsigned long>(input_offset), index);
+ return Type::make_error_type();
+ }
+
+ return index < 0 ? this->builtin_types_[- index] : this->types_[index];
+}
+
// Read an escape note.
std::string
{
return this->named_object_->name();
}
+
+// Class Import_function_body.
+
+// Require that the next bytes match STR, issuing an error if not.
+// Advance past the string.
+
+void
+Import_function_body::require_c_string(const char* str)
+{
+ if (!this->match_c_string(str))
+ {
+ if (!this->saw_error_)
+ go_error_at(this->location(),
+ "invalid export data for %qs: expected %qs at %lu",
+ this->name().c_str(), str,
+ static_cast<unsigned long>(this->off_));
+ this->saw_error_ = true;
+ return;
+ }
+ this->advance(strlen(str));
+}
+
+// Read an identifier.
+
+std::string
+Import_function_body::read_identifier()
+{
+ size_t start = this->off_;
+ for (size_t i = start; i < this->body_.length(); i++)
+ {
+ int c = static_cast<unsigned char>(this->body_[i]);
+ if (c == ' ' || c == '\n' || c == ';')
+ {
+ this->off_ = i;
+ return this->body_.substr(start, i - start);
+ }
+ }
+ this->off_ = this->body_.length();
+ return this->body_.substr(start);
+}
+
+// Read a type.
+
+Type*
+Import_function_body::read_type()
+{
+ this->require_c_string("<type ");
+ size_t start = this->off_;
+ size_t i;
+ int c = '\0';
+ for (i = start; i < this->body_.length(); ++i)
+ {
+ c = static_cast<unsigned char>(this->body_[i]);
+ if (c != '-' && (c < '0' || c > '9'))
+ break;
+ }
+ this->off_ = i + 1;
+
+ char *end;
+ long val = strtol(this->body_.substr(start, i - start).c_str(), &end, 10);
+ if (*end != '\0' || i > 0x7fffffff)
+ {
+ if (!this->saw_error_)
+ go_error_at(this->location(),
+ "invalid export data for %qs: expected integer at %lu",
+ this->name().c_str(),
+ static_cast<unsigned long>(start));
+ this->saw_error_ = true;
+ return Type::make_error_type();
+ }
+
+ if (c != '>')
+ {
+ if (!this->saw_error_)
+ go_error_at(this->location(),
+ "invalid export data for %qs: expected %<>%> at %lu",
+ this->name().c_str(),
+ static_cast<unsigned long>(i));
+ this->saw_error_ = true;
+ return Type::make_error_type();
+ }
+
+ return this->imp_->type_for_index(static_cast<int>(val), this->name(),
+ static_cast<unsigned long>(start));
+}
class Named_object;
class Named_type;
class Expression;
+class Import_function_body;
+
+// Expressions can be imported either directly from import data (for
+// simple constant expressions that can appear in a const declaration
+// or as an array length in a type definition) or from an exported
+// function body (for an inlinable function). These two cases happen
+// at different points in the compilation and have different
+// requirements, so it's not easy to unify them. Import_expression is
+// an abstract interface that permits the expression import code to
+// work at either point. When importing expressions that only occur
+// for an inlinable function, the ifb method is available to get the
+// full Import_function_body.
+
+class Import_expression
+{
+ public:
+ // Return the import function body. This should only be called for
+ // expressions that can not appear outside of an inlinable function
+ // body.
+ virtual Import_function_body*
+ ifb() = 0;
+
+ // The location to report in an error message.
+ virtual Location
+ location() const = 0;
+
+ // Peek at the next character in the input, returning a value from 0
+ // to 0xff. Returns -1 at end of stream.
+ virtual int
+ peek_char() = 0;
+
+ // Return the next character and advance.
+ virtual int
+ get_char() = 0;
+
+ // Return true if the next bytes match STR.
+ virtual bool
+ match_c_string(const char* str) = 0;
+
+ // Require that the next bytes match STR.
+ virtual void
+ require_c_string(const char* str) = 0;
+
+ // Advance the stream SKIP bytes.
+ virtual void
+ advance(size_t skip) = 0;
+
+ // Read an identifier.
+ virtual std::string
+ read_identifier() = 0;
+
+ // Read a type.
+ virtual Type*
+ read_type() = 0;
+};
// This class manages importing Go declarations.
-class Import
+class Import : public Import_expression
{
public:
// The Stream class is an interface used to read the data. The
// Constructor.
Import(Stream*, Location);
+ virtual ~Import()
+ {}
+
// Register the builtin types.
void
register_builtin_types(Gogo*);
Type*
read_type();
+ // Return the type for a type index. INPUT_NAME and INPUT_OFFSET
+ // are only for error reporting.
+ Type*
+ type_for_index(int index, const std::string& input_name,
+ size_t input_offset);
+
// Read an escape note.
std::string
read_escape();
+ // Clear the stream when it is no longer accessible.
+ void
+ clear_stream()
+ { this->stream_ = NULL; }
+
+ // Just so that Import implements Import_expression.
+ Import_function_body*
+ ifb()
+ { return NULL; }
+
private:
static Stream*
try_package_in_directory(const std::string&, Location);
// Class to manage importing a function body. This is passed around
// to Statements and Expressions. It parses the function into the IR.
-class Import_function_body
+class Import_function_body : public Import_expression
{
public:
- Import_function_body(Gogo* gogo, Location loc, Named_object* named_object,
+ Import_function_body(Gogo* gogo, Import* imp, Named_object* named_object,
const std::string& body, size_t off, Block* block,
int indent)
- : gogo_(gogo), loc_(loc), named_object_(named_object), body_(body),
+ : gogo_(gogo), imp_(imp), named_object_(named_object), body_(body),
off_(off), block_(block), indent_(indent)
{ }
// The location to report in an error message.
Location
location() const
- { return this->loc_; }
+ { return this->imp_->location(); }
// A reference to the body we are reading.
const std::string&
set_off(size_t off)
{ this->off_ = off; }
+ // Advance the offset by SKIP bytes.
+ void
+ advance(size_t skip)
+ { this->off_ += skip; }
+
// The current block.
Block*
block()
const std::string&
name() const;
+ // Return the next character in the input stream, or -1 at the end.
+ int
+ peek_char()
+ {
+ if (this->body_.length() <= this->off_)
+ return -1;
+ return static_cast<unsigned char>(this->body_[this->off_]);
+ }
+
+ // Return the next character and advance.
+ int
+ get_char()
+ {
+ if (this->body_.length() <= this->off_)
+ return -1;
+ int c = static_cast<unsigned char>(this->body_[this->off_]);
+ this->off_++;
+ return c;
+ }
+
+ // Return whether the C string matches the current body position.
+ bool
+ match_c_string(const char* str)
+ {
+ size_t len = strlen(str);
+ return (this->body_.length() >= this->off_ + len
+ && this->body_.compare(this->off_, len, str) == 0);
+ }
+
+ // Give an error if the next bytes do not match STR. Advance the
+ // offset by the length of STR.
+ void
+ require_c_string(const char* str);
+
+ // Read an identifier.
+ std::string
+ read_identifier();
+
+ // Read a type.
+ Type*
+ read_type();
+
+ // Implement Import_expression.
+ Import_function_body*
+ ifb()
+ { return this; }
+
private:
// The IR.
Gogo* gogo_;
- // The location to report in an error message.
- Location loc_;
+ // The importer.
+ Import* imp_;
// The function we are parsing.
Named_object* named_object_;
// The exported data we are parsing. Note that this is a reference;
Block* block_;
// Current expected indentation level.
int indent_;
+ // Whether we've seen an error. Used to avoid reporting excess
+ // errors.
+ bool saw_error_;
};
#endif // !defined(GO_IMPORT_H)