-e32e9aaee598eeb43f9616cf6ca1d11acaa9d167
+0494dc5737f0c89ad6f45e04e8313e4161678861
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
// Current version magic string.
const char Export::cur_magic[Export::magic_len] =
{
- 'v', '2', ';', '\n'
+ 'v', '3', ';', '\n'
};
-// Magic string for previous version (still supported)
+// Magic strings for previous versions (still supported).
const char Export::v1_magic[Export::magic_len] =
{
'v', '1', ';', '\n'
};
+const char Export::v2_magic[Export::magic_len] =
+ {
+ 'v', '2', ';', '\n'
+ };
const int Export::checksum_len;
// The package name.
this->write_c_string("package ");
this->write_string(package_name);
- this->write_c_string(";\n");
+ this->write_c_string("\n");
// The prefix or package path, used for all global symbols.
if (prefix.empty())
this->write_c_string("prefix ");
this->write_string(prefix);
}
- this->write_c_string(";\n");
+ this->write_c_string("\n");
this->write_packages(packages);
dig = c & 0xf;
s += dig < 10 ? '0' + dig : 'A' + dig - 10;
}
- s += ";\n";
+ s += "\n";
this->stream_->write_checksum(s);
}
this->write_string((*p)->pkgpath());
this->write_c_string(" ");
this->write_string((*p)->pkgpath_symbol());
- this->write_c_string(";\n");
+ this->write_c_string("\n");
}
}
this->write_string(p->second->pkgpath());
this->write_c_string(" \"");
this->write_string(p->first);
- this->write_c_string("\";\n");
+ this->write_c_string("\"\n");
this->packages_.insert(p->second);
}
if (imported_init_fns.empty())
{
- this->write_c_string(";\n");
+ this->write_c_string("\n");
return;
}
it->second.push_back(ii->init_name());
}
}
- this->write_c_string(";\n");
+ this->write_c_string("\n");
// Create the init graph. Start by populating the graph with
// all the edges we inherited from imported packages.
this->write_unsigned(sink);
}
}
- this->write_c_string(";\n");
+ this->write_c_string("\n");
}
// Write a name to the export stream.
EXPORT_FORMAT_UNKNOWN = 0,
EXPORT_FORMAT_V1 = 1,
EXPORT_FORMAT_V2 = 2,
- EXPORT_FORMAT_CURRENT = EXPORT_FORMAT_V2
+ EXPORT_FORMAT_V3 = 3,
+ EXPORT_FORMAT_CURRENT = EXPORT_FORMAT_V3
};
// This class manages exporting Go declarations. It handles the main
// Size of export data magic string (which includes version number).
static const int magic_len = 4;
- // Magic strings (current version and older v1 version).
+ // Magic strings (current version and older versions).
static const char cur_magic[magic_len];
static const char v1_magic[magic_len];
+ static const char v2_magic[magic_len];
// The length of the checksum string.
static const int checksum_len = 20;
exp->write_c_string(")");
}
}
- exp->write_c_string(";\n");
+ exp->write_c_string("\n");
}
// Import a function.
imp->require_c_string(")");
}
}
- imp->require_c_string(";\n");
+ imp->require_semicolon_if_old_version();
+ imp->require_c_string("\n");
*presults = results;
}
exp->write_string(name);
exp->write_c_string(" ");
exp->write_type(this->type());
- exp->write_c_string(";\n");
+ exp->write_c_string("\n");
}
// Import a variable.
*pname = imp->read_identifier();
imp->require_c_string(" ");
*ptype = imp->read_type();
- imp->require_c_string(";\n");
+ imp->require_semicolon_if_old_version();
+ imp->require_c_string("\n");
}
// Convert a variable to the backend representation.
}
exp->write_c_string("= ");
this->expr()->export_expression(exp);
- exp->write_c_string(";\n");
+ exp->write_c_string("\n");
}
// Import a constant.
}
imp->require_c_string("= ");
*pexpr = Expression::import_expression(imp);
- imp->require_c_string(";\n");
+ imp->require_semicolon_if_old_version();
+ imp->require_c_string("\n");
}
// Get the backend representation.
return NULL;
// Check for a file containing nothing but Go export data.
- if (memcmp(buf, Export::cur_magic, Export::magic_len) == 0 ||
- memcmp(buf, Export::v1_magic, Export::magic_len) == 0)
+ if (memcmp(buf, Export::cur_magic, Export::magic_len) == 0
+ || memcmp(buf, Export::v1_magic, Export::magic_len) == 0
+ || memcmp(buf, Export::v2_magic, Export::magic_len) == 0)
return new Stream_from_file(fd);
// See if we can read this as an archive.
Export::magic_len);
this->version_ = EXPORT_FORMAT_V1;
}
+ else if (stream->match_bytes(Export::v2_magic, Export::magic_len))
+ {
+ stream->require_bytes(this->location_, Export::v2_magic,
+ Export::magic_len);
+ this->version_ = EXPORT_FORMAT_V2;
+ }
else
{
go_error_at(this->location_,
this->require_c_string("package ");
std::string package_name = this->read_identifier();
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
std::string pkgpath;
std::string pkgpath_symbol;
{
this->advance(7);
std::string unique_prefix = this->read_identifier();
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
pkgpath = unique_prefix + '.' + package_name;
pkgpath_symbol = (Gogo::pkgpath_for_symbol(unique_prefix) + '.'
+ Gogo::pkgpath_for_symbol(package_name));
{
this->require_c_string("pkgpath ");
pkgpath = this->read_identifier();
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
pkgpath_symbol = Gogo::pkgpath_for_symbol(pkgpath);
}
+ if (stream->saw_error())
+ return NULL;
+
this->package_ = gogo->add_imported_package(package_name, local_name,
is_local_name_exported,
pkgpath, pkgpath_symbol,
// load time.
this->require_c_string("checksum ");
stream->advance(Export::checksum_len * 2);
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
}
return this->package_;
std::string pkgpath = this->read_identifier();
this->require_c_string(" ");
std::string pkgpath_symbol = this->read_identifier();
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
Package* p = this->gogo_->register_package(pkgpath, pkgpath_symbol,
Linemap::unknown_location());
Stream* stream = this->stream_;
while (stream->peek_char() != '"')
stream->advance(1);
- this->require_c_string("\";\n");
+ this->require_c_string("\"");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
Package* p = this->gogo_->register_package(pkgpath, "",
Linemap::unknown_location());
// to read the init_graph section.
std::map<std::string, unsigned> init_idx;
- while (!this->match_c_string(";"))
+ while (!this->match_c_string("\n") && !this->match_c_string(";"))
{
int priority = -1;
unsigned idx = init_idx.size();
init_idx[init_name] = idx;
}
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
if (this->match_c_string("init_graph"))
{
//
// where src + sink are init functions indices.
- while (!this->match_c_string(";"))
+ while (!this->match_c_string("\n") && !this->match_c_string(";"))
{
this->require_c_string(" ");
std::string src_string = this->read_identifier();
ii_src->record_precursor_fcn(ii_sink->init_name());
}
- this->require_c_string(";\n");
+ this->require_semicolon_if_old_version();
+ this->require_c_string("\n");
}
}
while (true)
{
c = stream->peek_char();
- if (c == -1 || c == ' ' || c == ';')
+ if (c == -1 || c == ' ' || c == '\n' || c == ';')
break;
ret += c;
stream->advance(1);
advance(size_t skip)
{ this->stream_->advance(skip); }
+ // Skip a semicolon if using an older version.
+ void
+ require_semicolon_if_old_version()
+ {
+ if (this->version_ == EXPORT_FORMAT_V1
+ || this->version_ == EXPORT_FORMAT_V2)
+ this->require_c_string(";");
+ }
+
// Read an identifier.
std::string
read_identifier();
// be written by Export::write_type anyhow.
exp->write_c_string("type ");
exp->write_type(this);
- exp->write_c_string(";\n");
+ exp->write_c_string("\n");
}
// Import a named type.
Type *type = imp->read_type();
*ptype = type->named_type();
go_assert(*ptype != NULL);
- imp->require_c_string(";\n");
+ imp->require_semicolon_if_old_version();
+ imp->require_c_string("\n");
}
// Export the type when it is referenced by another type. In this
const (
gccgov1Magic = "v1;\n"
gccgov2Magic = "v2;\n"
+ gccgov3Magic = "v3;\n"
goimporterMagic = "\n$$ "
archiveMagic = "!<ar"
aixbigafMagic = "<big"
var objreader io.ReaderAt
switch string(magic[:]) {
- case gccgov1Magic, gccgov2Magic, goimporterMagic:
+ case gccgov1Magic, gccgov2Magic, gccgov3Magic, goimporterMagic:
// Raw export data.
reader = f
return
}
switch magics {
- case gccgov1Magic, gccgov2Magic:
+ case gccgov1Magic, gccgov2Magic, gccgov3Magic:
var p parser
p.init(fpath, reader, imports)
pkg = p.parsePackage()
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<<'\n' | 1<<' '
+ p.scanner.Whitespace = 1<<'\t' | 1<<' '
p.scanner.Filename = filename // for good error messages
p.next()
p.imports = imports
return lit
}
+func (p *parser) expectEOL() {
+ if p.version == "v1" || p.version == "v2" {
+ p.expect(';')
+ }
+ p.expect('\n')
+}
+
func (p *parser) expectKeyword(keyword string) {
lit := p.expect(scanner.Ident)
if lit != keyword {
buf.WriteString(p.scanner.TokenText())
// This loop needs to examine each character before deciding whether to consume it. If we see a semicolon,
// we need to let it be consumed by p.next().
- for ch := p.scanner.Peek(); ch != ';' && ch != scanner.EOF && p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
+ for ch := p.scanner.Peek(); ch != '\n' && ch != ';' && ch != scanner.EOF && p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
buf.WriteRune(ch)
p.scanner.Next()
}
nt.SetUnderlying(underlying.Underlying())
}
- // collect associated methods
- for p.tok == scanner.Ident {
- p.expectKeyword("func")
- p.expect('(')
- receiver, _ := p.parseParam(pkg)
- p.expect(')')
- name := p.parseName()
- params, isVariadic := p.parseParamList(pkg)
- results := p.parseResultList(pkg)
- p.expect(';')
-
- sig := types.NewSignature(receiver, params, results, isVariadic)
- nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+ if p.tok == '\n' {
+ p.next()
+ // collect associated methods
+ for p.tok == scanner.Ident {
+ p.expectKeyword("func")
+ p.expect('(')
+ receiver, _ := p.parseParam(pkg)
+ p.expect(')')
+ name := p.parseName()
+ params, isVariadic := p.parseParamList(pkg)
+ results := p.parseResultList(pkg)
+ p.expectEOL()
+
+ sig := types.NewSignature(receiver, params, results, isVariadic)
+ nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+ }
}
return nt
return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
}
-// Throw away tokens until we see a ';'. If we see a '<', attempt to parse as a type.
+// Throw away tokens until we see a newline or ';'.
+// If we see a '<', attempt to parse as a type.
func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) {
for {
switch p.tok {
- case ';':
+ case '\n', ';':
return
case '<':
p.parseType(pkg)
}
}
-// InitDataDirective = ( "v1" | "v2" ) ";" |
+// InitDataDirective = ( "v1" | "v2" | "v3" ) ";" |
// "priority" int ";" |
// "init" { PackageInit } ";" |
// "checksum" unquotedString ";" .
}
switch p.lit {
- case "v1", "v2":
+ case "v1", "v2", "v3":
p.version = p.lit
p.next()
p.expect(';')
+ p.expect('\n')
case "priority":
p.next()
p.initdata.Priority = int(p.parseInt())
- p.expect(';')
+ p.expectEOL()
case "init":
p.next()
- for p.tok != ';' && p.tok != scanner.EOF {
+ for p.tok != '\n' && p.tok != ';' && p.tok != scanner.EOF {
p.initdata.Inits = append(p.initdata.Inits, p.parsePackageInit())
}
- p.expect(';')
+ p.expectEOL()
case "init_graph":
p.next()
// The graph data is thrown away for now.
- for p.tok != ';' && p.tok != scanner.EOF {
+ for p.tok != '\n' && p.tok != ';' && p.tok != scanner.EOF {
p.parseInt()
p.parseInt()
}
- p.expect(';')
+ p.expectEOL()
case "checksum":
// Don't let the scanner try to parse the checksum as a number.
p.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats
p.next()
p.parseUnquotedString()
- p.expect(';')
+ p.expectEOL()
default:
p.errorf("unexpected identifier: %q", p.lit)
}
switch p.lit {
- case "v1", "v2", "priority", "init", "init_graph", "checksum":
+ case "v1", "v2", "v3", "priority", "init", "init_graph", "checksum":
p.parseInitDataDirective()
case "package":
p.next()
p.pkgname = p.parseUnquotedString()
p.maybeCreatePackage()
- if p.version == "v2" && p.tok != ';' {
+ if p.version != "v1" && p.tok != '\n' && p.tok != ';' {
p.parseUnquotedString()
p.parseUnquotedString()
}
- p.expect(';')
+ p.expectEOL()
case "pkgpath":
p.next()
p.pkgpath = p.parseUnquotedString()
p.maybeCreatePackage()
- p.expect(';')
+ p.expectEOL()
case "prefix":
p.next()
p.pkgpath = p.parseUnquotedString()
- p.expect(';')
+ p.expectEOL()
case "import":
p.next()
pkgpath := p.parseUnquotedString()
p.getPkg(pkgpath, pkgname)
p.parseString()
- p.expect(';')
+ p.expectEOL()
case "func":
p.next()
if fun != nil {
p.pkg.Scope().Insert(fun)
}
- p.expect(';')
+ p.expectEOL()
case "type":
p.next()
p.parseType(p.pkg)
- p.expect(';')
+ p.expectEOL()
case "var":
p.next()
v := p.parseVar(p.pkg)
p.pkg.Scope().Insert(v)
- p.expect(';')
+ p.expectEOL()
case "const":
p.next()
c := p.parseConst(p.pkg)
p.pkg.Scope().Insert(c)
- p.expect(';')
+ p.expectEOL()
default:
p.errorf("unexpected identifier: %q", p.lit)
{id: "foo", typ: "<type 1 *<type -19>>", want: "*error"},
{id: "foo", typ: "<type 1 *any>", want: "unsafe.Pointer"},
{id: "foo", typ: "<type 1 \"Bar\" <type 2 *<type 1>>>", want: "foo.Bar", underlying: "*foo.Bar"},
- {id: "foo", typ: "<type 1 \"bar.Foo\" \"bar\" <type -1> func (? <type 1>) M (); >", want: "bar.Foo", underlying: "int8", methods: "func (bar.Foo).M()"},
+ {id: "foo", typ: "<type 1 \"bar.Foo\" \"bar\" <type -1>\n func (? <type 1>) M ()\n>", want: "bar.Foo", underlying: "int8", methods: "func (bar.Foo).M()"},
{id: "foo", typ: "<type 1 \".bar.foo\" \"bar\" <type -1>>", want: "bar.foo", underlying: "int8"},
{id: "foo", typ: "<type 1 []<type -1>>", want: "[]int8"},
{id: "foo", typ: "<type 1 [42]<type -1>>", want: "[42]int8"},