diff options
author | Robert Griesemer <gri@golang.org> | 2008-07-29 12:03:06 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2008-07-29 12:03:06 -0700 |
commit | f38139599a7269b67a44a501db996dbd76368a68 (patch) | |
tree | 6d0a6c2d6dba1c9518e843b48a248b7e5f61812e | |
parent | af57763ce5e4be368ddb6203b09398f0ca4a8d42 (diff) | |
download | golang-f38139599a7269b67a44a501db996dbd76368a68.tar.gz |
- handling of pointer forward decls
- some comments added to bug cases
- added notes
R=r
OCL=13543
CL=13543
-rw-r--r-- | test/bugs/bug041.go | 8 | ||||
-rw-r--r-- | test/bugs/bug042.go | 8 | ||||
-rwxr-xr-x | usr/gri/gosrc/export.go | 10 | ||||
-rw-r--r-- | usr/gri/gosrc/globals.go | 4 | ||||
-rw-r--r-- | usr/gri/gosrc/parser.go | 165 |
5 files changed, 117 insertions, 78 deletions
diff --git a/test/bugs/bug041.go b/test/bugs/bug041.go index 1a6e0dde8..709b774d0 100644 --- a/test/bugs/bug041.go +++ b/test/bugs/bug041.go @@ -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. +*/ diff --git a/test/bugs/bug042.go b/test/bugs/bug042.go index 37a2bfd69..9c873abfc 100644 --- a/test/bugs/bug042.go +++ b/test/bugs/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). +*/ diff --git a/usr/gri/gosrc/export.go b/usr/gri/gosrc/export.go index 57c49ba6d..0ab3b0792 100755 --- a/usr/gri/gosrc/export.go +++ b/usr/gri/gosrc/export.go @@ -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); } } diff --git a/usr/gri/gosrc/globals.go b/usr/gri/gosrc/globals.go index 31dc1a351..c98624124 100644 --- a/usr/gri/gosrc/globals.go +++ b/usr/gri/gosrc/globals.go @@ -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; diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go index 566e5176a..7d474275e 100644 --- a/usr/gri/gosrc/parser.go +++ b/usr/gri/gosrc/parser.go @@ -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(); } |