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
This commit is contained in:
parent
593570593e
commit
fc74d562de
7 changed files with 296 additions and 69 deletions
|
@ -1,4 +1,4 @@
|
|||
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)
|
||||
|
|
Loading…
Add table
Reference in a new issue