Commit fce91186 authored by Robert Griesemer's avatar Robert Griesemer

- handling of pointer forward decls

- some comments added to bug cases
- added notes

R=r
OCL=13543
CL=13543
parent f436ade2
......@@ -13,3 +13,11 @@ type S struct {
func main() {
var s S;
}
/*
Another problem with implicit forward declarations (as in this program on line 6)
is that it is not clear in which scope the type (here "T") should be declared.
This is the main reason why we should not allow implicit forward declarations at all,
and instead have an explicit type forward declaration. For more on this subject
see bug042.go.
*/
......@@ -18,3 +18,11 @@ type T struct {
func main() {
var s S;
}
/*
Per discussion w/ Ken, some time ago, we came to the conclusion that explicit
forward declarations (as on line 5 in this program) are preferrable over
implicit forward declarations because they make it explicit in which scope a
type is to be declared fully, eventually. As an aside, the machinery for it is
almost free in the compiler (one extra 'if' as far as I can tell).
*/
......@@ -115,7 +115,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
// determine number of objects to export
n := 0;
for p := scope.entries.first; p != nil; p = p.next {
if p.obj.mark {
if p.obj.exported {
n++;
}
}
......@@ -123,7 +123,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
// export the objects, if any
if n > 0 {
for p := scope.entries.first; p != nil; p = p.next {
if p.obj.mark {
if p.obj.exported {
E.WriteObject(p.obj);
}
}
......@@ -136,8 +136,8 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
func (E *Exporter) WriteObject(obj *Globals.Object) {
if obj == nil || !obj.mark {
panic "obj == nil || !obj.mark";
if obj == nil || !obj.exported {
panic "obj == nil || !obj.exported";
}
if obj.kind == Object.TYPE && obj.typ.obj == obj {
......@@ -274,7 +274,7 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
pkg := comp.pkgs[0];
E.WritePackage(pkg);
for p := pkg.scope.entries.first; p != nil; p = p.next {
if p.obj.mark {
if p.obj.exported {
E.WriteObject(p.obj);
}
}
......
......@@ -15,7 +15,7 @@ package Globals
export Object
type Object struct {
mark bool; // mark => object marked for export
exported bool;
pos int; // source position
kind int;
ident string;
......@@ -89,7 +89,7 @@ type Compilation struct {
export NewObject
func NewObject(pos, kind int, ident string) *Object {
obj := new(Object);
obj.mark = false;
obj.exported = false;
obj.pos = pos;
obj.kind = kind;
obj.ident = ident;
......
......@@ -29,6 +29,7 @@ type Parser struct {
// Semantic analysis
top_scope *Globals.Scope;
undef_types *Globals.List;
exports *Globals.List;
}
......@@ -77,6 +78,7 @@ func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, verbose int
P.S = S;
P.Next();
P.top_scope = Universe.scope;
P.undef_types = Globals.NewList();
P.exports = Globals.NewList();
}
......@@ -244,7 +246,7 @@ func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
// ----------------------------------------------------------------------------
// Types
func (P *Parser) ParseType() *Globals.Type{
func (P *Parser) ParseType() *Globals.Type {
P.Trace("Type");
typ := P.TryType();
......@@ -262,10 +264,11 @@ func (P *Parser) ParseTypeName() *Globals.Type {
P.Trace("TypeName");
if EnableSemanticTests {
pos := P.pos;
obj := P.ParseQualifiedIdent(-1, "");
typ := obj.typ;
if obj.kind != Object.TYPE {
P.Error(obj.pos, `"` + obj.ident + `" is not a type`);
P.Error(pos, "qualified identifier does not denote a type");
typ = Universe.bad_t;
}
P.Ecart();
......@@ -571,16 +574,42 @@ func (P *Parser) ParsePointerType() *Globals.Type {
P.Trace("PointerType");
P.Expect(Scanner.MUL);
typ := Universe.undef_t;
if (EnableSemanticTests && P.tok == Scanner.IDENT && P.Lookup(P.val) == nil) {
// forward declaration
panic "UNIMPLEMENTED *forward_declared_type";
typ := Globals.NewType(Type.POINTER);
if EnableSemanticTests {
if P.tok == Scanner.IDENT {
if P.Lookup(P.val) == nil {
// implicit forward declaration
// TODO very problematic: in which scope should the
// type object be declared? It's different if this
// is inside a struct or say in a var declaration.
// This code is only here for "compatibility" with 6g.
pos := P.pos;
obj := Globals.NewObject(pos, Object.TYPE, P.ParseIdent());
obj.typ = Globals.NewType(Type.UNDEF);
obj.typ.obj = obj; // primary type object
typ.elt = obj.typ;
// TODO obj should be declared, but scope is not clear
} else {
// type name
// (ParseType() doesn't permit incomplete types,
// so call ParseTypeName() here)
typ.elt = P.ParseTypeName();
}
} else {
typ.elt = P.ParseType();
}
// collect undefined pointer types
if typ.elt.form == Type.UNDEF {
P.undef_types.AddTyp(typ);
}
} else {
typ = Globals.NewType(Type.POINTER);
typ.elt = P.ParseType();
}
P.Ecart();
P.Ecart();
return typ;
}
......@@ -589,6 +618,7 @@ func (P *Parser) ParsePointerType() *Globals.Type {
func (P *Parser) TryType() *Globals.Type {
P.Trace("Type (try)");
pos := P.pos;
var typ *Globals.Type = nil;
switch P.tok {
case Scanner.IDENT: typ = P.ParseTypeName();
......@@ -601,6 +631,10 @@ func (P *Parser) TryType() *Globals.Type {
case Scanner.MUL: typ = P.ParsePointerType();
}
if typ != nil && typ.form == Type.UNDEF {
P.Error(pos, "incomplete type");
}
P.Ecart();
return typ;
}
......@@ -1464,7 +1498,7 @@ func (P *Parser) ParseConstSpec(exported bool) {
typ := P.TryType();
if typ != nil {
for p := list.first; p != nil; p = p.next {
p.obj.mark = exported;
p.obj.exported = exported;
p.obj.typ = typ; // TODO should use/have set_type()!
}
}
......@@ -1477,27 +1511,6 @@ func (P *Parser) ParseConstSpec(exported bool) {
}
func (P *Parser) ParseConstDecl(exported bool) {
P.Trace("ConstDecl");
P.Expect(Scanner.CONST);
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok == Scanner.IDENT {
P.ParseConstSpec(exported);
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
}
}
P.Next();
} else {
P.ParseConstSpec(exported);
}
P.Ecart();
}
func (P *Parser) ParseTypeSpec(exported bool) {
P.Trace("TypeSpec");
......@@ -1505,22 +1518,23 @@ func (P *Parser) ParseTypeSpec(exported bool) {
ident := P.ParseIdent();
obj := P.top_scope.Lookup(ident); // only lookup in top scope!
if obj != nil {
// ok if forward declared type
// name already declared - ok if forward declared type
if obj.kind != Object.TYPE || obj.typ.form != Type.UNDEF {
// TODO use obj.pos to refer to decl pos in error msg!
P.Error(pos, `"` + ident + `" is declared already`);
}
} else {
obj = Globals.NewObject(pos, Object.TYPE, ident);
obj.mark = exported;
obj.typ = Universe.undef_t; // TODO fix this
P.top_scope.Insert(obj);
obj.exported = exported;
obj.typ = Globals.NewType(Type.UNDEF);
obj.typ.obj = obj; // primary type object
P.Declare(obj);
}
typ := P.TryType(); // no type if we have a forward decl
typ := P.TryType(); // nil if we have an explicit forward declaration
if typ != nil {
// TODO what about the name of incomplete types?
obj.typ = typ; // TODO should use/have set_typ()!
obj.typ = typ;
if typ.obj == nil {
typ.obj = obj; // primary type object
}
......@@ -1530,27 +1544,6 @@ func (P *Parser) ParseTypeSpec(exported bool) {
}
func (P *Parser) ParseTypeDecl(exported bool) {
P.Trace("TypeDecl");
P.Expect(Scanner.TYPE);
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok == Scanner.IDENT {
P.ParseTypeSpec(exported);
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
}
}
P.Next();
} else {
P.ParseTypeSpec(exported);
}
P.Ecart();
}
func (P *Parser) ParseVarSpec(exported bool) {
P.Trace("VarSpec");
......@@ -1573,21 +1566,32 @@ func (P *Parser) ParseVarSpec(exported bool) {
}
func (P *Parser) ParseVarDecl(exported bool) {
P.Trace("VarDecl");
// TODO With method variables, we wouldn't need this dispatch function.
func (P *Parser) ParseSpec(exported bool, keyword int) {
switch keyword {
case Scanner.CONST: P.ParseConstSpec(exported);
case Scanner.TYPE: P.ParseTypeSpec(exported);
case Scanner.VAR: P.ParseVarSpec(exported);
default: panic "UNREACHABLE";
}
}
func (P *Parser) ParseDecl(exported bool, keyword int) {
P.Trace("Decl");
P.Expect(Scanner.VAR);
P.Expect(keyword);
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok == Scanner.IDENT {
P.ParseVarSpec(exported);
P.ParseSpec(exported, keyword);
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
}
}
P.Next();
} else {
P.ParseVarSpec(exported);
P.ParseSpec(exported, keyword);
}
P.Ecart();
......@@ -1643,12 +1647,8 @@ func (P *Parser) ParseDeclaration() {
exported = true;
}
switch P.tok {
case Scanner.CONST:
P.ParseConstDecl(exported);
case Scanner.TYPE:
P.ParseTypeDecl(exported);
case Scanner.VAR:
P.ParseVarDecl(exported);
case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
P.ParseDecl(exported, P.tok);
case Scanner.FUNC:
P.ParseFuncDecl(exported);
case Scanner.EXPORT:
......@@ -1676,6 +1676,28 @@ func (P *Parser) ParseDeclaration() {
// ----------------------------------------------------------------------------
// Program
func (P *Parser) ResolveUndefTypes() {
if !EnableSemanticTests {
return;
}
for p := P.undef_types.first; p != nil; p = p.next {
typ := p.typ;
if typ.form != Type.POINTER {
panic "unresolved types should be pointers only";
}
if typ.elt.form != Type.UNDEF {
panic "unresolved pointer should point to undefined type";
}
obj := typ.elt.obj;
typ.elt = obj.typ;
if typ.elt.form == Type.UNDEF {
P.Error(obj.pos, `"` + obj.ident + `" is not declared`);
}
}
}
func (P *Parser) MarkExports() {
if !EnableSemanticTests {
return;
......@@ -1685,7 +1707,7 @@ func (P *Parser) MarkExports() {
for p := P.exports.first; p != nil; p = p.next {
obj := scope.Lookup(p.str);
if obj != nil {
obj.mark = true;
obj.exported = true;
// For now we export deep
// TODO this should change eventually - we need selective export
if obj.kind == Object.TYPE {
......@@ -1693,7 +1715,7 @@ func (P *Parser) MarkExports() {
if typ.form == Type.STRUCT || typ.form == Type.INTERFACE {
scope := typ.scope;
for p := scope.entries.first; p != nil; p = p.next {
p.obj.mark = true;
p.obj.exported = true;
}
}
}
......@@ -1726,6 +1748,7 @@ func (P *Parser) ParseProgram() {
P.Optional(Scanner.SEMICOLON);
}
P.ResolveUndefTypes();
P.MarkExports();
P.CloseScope();
}
......
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