- handling of pointer forward decls
- some comments added to bug cases
- added notes
R=r
OCL=13543
CL=13543
diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go
index 566e517..7d47427 100644
--- a/usr/gri/gosrc/parser.go
+++ b/usr/gri/gosrc/parser.go
@@ -29,6 +29,7 @@
// Semantic analysis
top_scope *Globals.Scope;
+ undef_types *Globals.List;
exports *Globals.List;
}
@@ -77,6 +78,7 @@
P.S = S;
P.Next();
P.top_scope = Universe.scope;
+ P.undef_types = Globals.NewList();
P.exports = Globals.NewList();
}
@@ -244,7 +246,7 @@
// ----------------------------------------------------------------------------
// Types
-func (P *Parser) ParseType() *Globals.Type{
+func (P *Parser) ParseType() *Globals.Type {
P.Trace("Type");
typ := P.TryType();
@@ -262,10 +264,11 @@
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 @@
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) 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 @@
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 @@
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) 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 @@
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) 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) 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 @@
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 @@
// ----------------------------------------------------------------------------
// 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 @@
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 @@
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 @@
P.Optional(Scanner.SEMICOLON);
}
+ P.ResolveUndefTypes();
P.MarkExports();
P.CloseScope();
}