summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2008-07-29 12:03:06 -0700
committerRobert Griesemer <gri@golang.org>2008-07-29 12:03:06 -0700
commitf38139599a7269b67a44a501db996dbd76368a68 (patch)
tree6d0a6c2d6dba1c9518e843b48a248b7e5f61812e
parentaf57763ce5e4be368ddb6203b09398f0ca4a8d42 (diff)
downloadgolang-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.go8
-rw-r--r--test/bugs/bug042.go8
-rwxr-xr-xusr/gri/gosrc/export.go10
-rw-r--r--usr/gri/gosrc/globals.go4
-rw-r--r--usr/gri/gosrc/parser.go165
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();
}