Commit fc74d562 by Ian Lance Taylor

compiler: change expression importing to use Import_expression

    
    Change expression importing to use a new abstract interface class
    Import_expression, so that we can more easily import expressions from
    inlinable function bodies.  This is a refactoring with no affect on
    compiler behavior.
    
    Reviewed-on: https://go-review.googlesource.com/c/150065

From-SVN: r266526
parent 59357059
75d48ff977a2865d12b03857362ea48016a4b885
6e0974fc6c9aa6ef19f72fbb5698e4b3734a4220
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
......@@ -1583,7 +1583,7 @@ class Boolean_expression : public Expression
{ }
static Expression*
do_import(Import*, Location);
do_import(Import_expression*, Location);
protected:
bool
......@@ -1649,7 +1649,7 @@ Boolean_expression::do_determine_type(const Type_context* context)
// 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')
{
......@@ -1768,7 +1768,7 @@ String_expression::do_export(Export_function_body* efb) const
// 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;
......@@ -1944,7 +1944,7 @@ class Integer_expression : public Expression
{ mpz_init_set(this->val_, *val); }
static Expression*
do_import(Import*, Location);
do_import(Import_expression*, Location);
// Write VAL to string dump.
static void
......@@ -2151,7 +2151,7 @@ Integer_expression::do_export(Export_function_body* efb) const
// 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(" ");
......@@ -3133,7 +3133,7 @@ class Nil_expression : public Expression
{ }
static Expression*
do_import(Import*, Location);
do_import(Import_expression*, Location);
protected:
bool
......@@ -3172,7 +3172,7 @@ class Nil_expression : public Expression
// 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);
......@@ -3623,7 +3623,7 @@ Type_conversion_expression::do_export(Export_function_body* efb) const
// 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();
......@@ -4634,7 +4634,7 @@ Unary_expression::do_export(Export_function_body* efb) const
// 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())
......@@ -6403,7 +6403,7 @@ Binary_expression::do_export(Export_function_body* efb) const
// 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("(");
......@@ -16138,7 +16138,7 @@ Expression::make_backend(Bexpression* bexpr, Type* type, Location location)
// 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("- ")
......
......@@ -66,7 +66,7 @@ class Compound_expression;
class Numeric_constant;
class Named_object;
class Export_function_body;
class Import;
class Import_expression;
class Temporary_statement;
class Label;
class Ast_dump_context;
......@@ -1018,7 +1018,7 @@ class Expression
// 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.
......@@ -1567,7 +1567,7 @@ class String_expression : public Expression
{ return this->val_; }
static Expression*
do_import(Import*, Location);
do_import(Import_expression*, Location);
protected:
bool
......@@ -1646,7 +1646,7 @@ class Type_conversion_expression : public Expression
// Import a type conversion expression.
static Expression*
do_import(Import*, Location);
do_import(Import_expression*, Location);
protected:
int
......@@ -1817,7 +1817,7 @@ class Unary_expression : public Expression
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
......@@ -1966,7 +1966,7 @@ class Binary_expression : public Expression
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.
......
......@@ -527,9 +527,9 @@ Gogo::import_package(const std::string& filename,
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())
......@@ -540,7 +540,10 @@ Gogo::import_package(const std::string& filename,
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 *
......@@ -6763,8 +6766,6 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no)
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;
......@@ -6877,7 +6878,7 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no)
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;
......
......@@ -1691,8 +1691,11 @@ class Function_declaration
// 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
......@@ -1756,6 +1759,8 @@ class Function_declaration
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.
......
......@@ -790,7 +790,7 @@ Import::import_func(Package* package)
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;
}
......@@ -886,41 +886,7 @@ Import::read_type()
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)
......@@ -1126,6 +1092,47 @@ Import::read_named_type(int index)
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
......@@ -1408,3 +1415,88 @@ Import_function_body::name() const
{
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));
}
......@@ -17,10 +17,65 @@ class Type;
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
......@@ -138,6 +193,9 @@ class Import
// Constructor.
Import(Stream*, Location);
virtual ~Import()
{}
// Register the builtin types.
void
register_builtin_types(Gogo*);
......@@ -217,10 +275,26 @@ class Import
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);
......@@ -468,13 +542,13 @@ class Stream_from_string_ref : public Import::Stream
// 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)
{ }
......@@ -486,7 +560,7 @@ class Import_function_body
// 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&
......@@ -503,6 +577,11 @@ class Import_function_body
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()
......@@ -517,11 +596,58 @@ class Import_function_body
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;
......@@ -533,6 +659,9 @@ class Import_function_body
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment