- fixed a bug with building right-recursive trees iteratively
- moving scope handling into parser (simpler)
- snapshot of work today so far
R=r
OCL=22301
CL=22301
diff --git a/usr/gri/pretty/parser.go b/usr/gri/pretty/parser.go
index b77de14..fa59256 100644
--- a/usr/gri/pretty/parser.go
+++ b/usr/gri/pretty/parser.go
@@ -32,11 +32,34 @@
// Nesting levels
expr_lev int; // 0 = control clause level, 1 = expr inside ()'s
scope_lev int; // 0 = global scope, 1 = function scope of global functions, etc.
+
+ // Scopes
+ top_scope *Globals.Scope;
};
// ----------------------------------------------------------------------------
-// Support functions
+// Elementary support
+
+func unimplemented() {
+ panic("unimplemented");
+}
+
+
+func unreachable() {
+ panic("unreachable");
+}
+
+
+func assert(pred bool) {
+ if !pred {
+ panic("assertion failed");
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Parsing support
func (P *Parser) PrintIndent() {
for i := P.indent; i > 0; i-- {
@@ -128,6 +151,56 @@
// ----------------------------------------------------------------------------
+// Scopes
+
+func (P *Parser) OpenScope() {
+ P.top_scope = Globals.NewScope(P.top_scope);
+}
+
+
+func (P *Parser) CloseScope() {
+ P.top_scope = P.top_scope.parent;
+}
+
+
+func (P *Parser) Lookup(ident string) *Globals.Object {
+ for scope := P.top_scope; scope != nil; scope = scope.parent {
+ obj := scope.Lookup(ident);
+ if obj != nil {
+ return obj;
+ }
+ }
+ return nil;
+}
+
+
+func (P *Parser) DeclareInScope(scope *Globals.Scope, x *AST.Expr, kind int) {
+ if P.scope_lev < 0 {
+ panic("cannot declare objects in other packages");
+ }
+ obj := x.obj;
+ assert(x.tok == Scanner.IDENT && obj.kind == Object.NONE);
+ obj.kind = kind;
+ obj.pnolev = P.scope_lev;
+ if scope.Lookup(obj.ident) != nil {
+ P.Error(obj.pos, `"` + obj.ident + `" is declared already`);
+ return; // don't insert it into the scope
+ }
+ scope.Insert(obj);
+}
+
+
+// Declare a comma-separated list of idents or a single ident.
+func (P *Parser) Declare(p *AST.Expr, kind int) {
+ for p.tok == Scanner.COMMA {
+ P.DeclareInScope(P.top_scope, p.x, kind);
+ p = p.y;
+ }
+ P.DeclareInScope(P.top_scope, p, kind);
+}
+
+
+// ----------------------------------------------------------------------------
// AST support
func ExprType(x *AST.Expr) *AST.Type {
@@ -195,16 +268,18 @@
func (P *Parser) ParseIdentList() *AST.Expr {
P.Trace("IdentList");
+ var last *AST.Expr;
x := P.ParseIdent();
- for first := true; P.tok == Scanner.COMMA; {
+ for P.tok == Scanner.COMMA {
pos := P.pos;
P.Next();
y := P.ParseIdent();
- if first {
+ if last == nil {
x = P.NewExpr(pos, Scanner.COMMA, x, y);
- first = false;
+ last = x;
} else {
- x.y = P.NewExpr(pos, Scanner.COMMA, x.y, y);
+ last.y = P.NewExpr(pos, Scanner.COMMA, last.y, y);
+ last = last.y;
}
}
@@ -460,11 +535,17 @@
func (P *Parser) ParseFunctionType() *AST.Type {
P.Trace("FunctionType");
+ P.OpenScope();
+ P.scope_lev++;
+
t := AST.NewType(P.pos, Scanner.LPAREN);
t.list = P.ParseParameters(true).list; // TODO find better solution
t.end = P.pos;
t.elt = P.ParseResult();
+ P.scope_lev--;
+ P.CloseScope();
+
P.Ecart();
return t;
}
@@ -493,6 +574,9 @@
P.Expect(Scanner.INTERFACE);
if P.tok == Scanner.LBRACE {
P.Next();
+ P.OpenScope();
+ P.scope_lev++;
+
t.list = array.New(0);
for P.tok == Scanner.IDENT {
P.ParseMethodSpec(t.list);
@@ -501,6 +585,9 @@
}
}
t.end = P.pos;
+
+ P.scope_lev--;
+ P.CloseScope();
P.Expect(Scanner.RBRACE);
}
@@ -533,6 +620,9 @@
P.Expect(Scanner.STRUCT);
if P.tok == Scanner.LBRACE {
P.Next();
+ P.OpenScope();
+ P.scope_lev++;
+
t.list = array.New(0);
for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
P.ParseVarDeclList(t.list, false);
@@ -548,6 +638,9 @@
}
P.OptSemicolon();
t.end = P.pos;
+
+ P.scope_lev--;
+ P.CloseScope();
P.Expect(Scanner.RBRACE);
}
@@ -625,8 +718,12 @@
P.Trace("Block");
P.Expect(Scanner.LBRACE);
+ P.OpenScope();
+
slist = P.ParseStatementList();
end = P.pos;
+
+ P.CloseScope();
P.Expect(Scanner.RBRACE);
P.opt_semi = true;
@@ -832,7 +929,8 @@
singles = false;
}
- for first := true; P.tok != Scanner.RBRACE && P.tok != Scanner.EOF; {
+ var last *AST.Expr;
+ for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
y := P.ParseExpression(0);
if singles {
@@ -845,10 +943,12 @@
}
}
- if first {
+ if last == nil {
x = P.NewExpr(pos, Scanner.COMMA, x, y);
+ last = x;
} else {
- x.y = P.NewExpr(pos, Scanner.COMMA, x.y, y);
+ last.y = P.NewExpr(pos, Scanner.COMMA, last.y, y);
+ last = last.y;
}
if P.tok == Scanner.COMMA {
@@ -1143,6 +1243,7 @@
func (P *Parser) ParseIfStat() *AST.Stat {
P.Trace("IfStat");
+ P.OpenScope();
s := P.ParseControlClause(Scanner.IF);
s.block, s.end = P.ParseBlock();
if P.tok == Scanner.ELSE {
@@ -1169,6 +1270,7 @@
}
s.post = s1;
}
+ P.CloseScope();
P.Ecart();
return s;
@@ -1178,8 +1280,10 @@
func (P *Parser) ParseForStat() *AST.Stat {
P.Trace("ForStat");
+ P.OpenScope();
s := P.ParseControlClause(Scanner.FOR);
s.block, s.end = P.ParseBlock();
+ P.CloseScope();
P.Ecart();
return s;
@@ -1219,6 +1323,7 @@
func (P *Parser) ParseSwitchStat() *AST.Stat {
P.Trace("SwitchStat");
+ P.OpenScope();
s := P.ParseControlClause(Scanner.SWITCH);
s.block = array.New(0);
P.Expect(Scanner.LBRACE);
@@ -1228,6 +1333,7 @@
s.end = P.pos;
P.Expect(Scanner.RBRACE);
P.opt_semi = true;
+ P.CloseScope();
P.Ecart();
return s;
@@ -1382,6 +1488,10 @@
P.Expect(Scanner.STRING); // use Expect() error handling
}
+ if d.ident != nil {
+ P.Declare(d.ident, Object.PACKAGE);
+ }
+
P.Ecart();
return d;
}
@@ -1397,6 +1507,8 @@
P.Next();
d.val = P.ParseExpressionList();
}
+
+ P.Declare(d.ident, Object.CONST);
P.Ecart();
return d;
@@ -1432,6 +1544,8 @@
}
}
+ P.Declare(d.ident, Object.VAR);
+
P.Ecart();
return d;
}
@@ -1581,24 +1695,29 @@
func (P *Parser) ParseProgram() *AST.Program {
P.Trace("Program");
+ P.OpenScope();
p := AST.NewProgram(P.pos);
P.Expect(Scanner.PACKAGE);
p.ident = P.ParseIdent();
- p.decls = array.New(0);
- for P.tok == Scanner.IMPORT {
- p.decls.Push(P.ParseDecl(false, Scanner.IMPORT));
- P.OptSemicolon();
- }
-
- if !P.deps {
- for P.tok != Scanner.EOF {
- p.decls.Push(P.ParseDeclaration());
+ // package body
+ { P.OpenScope();
+ p.decls = array.New(0);
+ for P.tok == Scanner.IMPORT {
+ p.decls.Push(P.ParseDecl(false, Scanner.IMPORT));
P.OptSemicolon();
}
+ if !P.deps {
+ for P.tok != Scanner.EOF {
+ p.decls.Push(P.ParseDeclaration());
+ P.OptSemicolon();
+ }
+ }
+ P.CloseScope();
}
p.comments = P.comments;
+ P.CloseScope();
P.Ecart();
return p;
diff --git a/usr/gri/pretty/selftest2.go b/usr/gri/pretty/selftest2.go
index 9b63fd5..9f488f2 100644
--- a/usr/gri/pretty/selftest2.go
+++ b/usr/gri/pretty/selftest2.go
@@ -52,6 +52,17 @@
)
+func d0() {
+ var (
+ a string;
+ b, c string;
+ d, e, f string;
+ g, h, i, j string;
+ k, l, m, n, o string;
+ )
+}
+
+
func f0(a, b int) int {
if a < b {
a = a + 1; // estimate
diff --git a/usr/gri/pretty/typechecker.go b/usr/gri/pretty/typechecker.go
index 1b27942..b2e6ae6 100644
--- a/usr/gri/pretty/typechecker.go
+++ b/usr/gri/pretty/typechecker.go
@@ -17,10 +17,6 @@
type State struct {
// setup
err Scanner.ErrorHandler;
-
- // state
- level int;
- top_scope *Globals.Scope;
}
@@ -55,66 +51,6 @@
// ----------------------------------------------------------------------------
-// Scopes
-
-func (s *State) OpenScope() {
- s.top_scope = Globals.NewScope(s.top_scope);
-}
-
-
-func (s *State) CloseScope() {
- s.top_scope = s.top_scope.parent;
-}
-
-
-func (s *State) Lookup(ident string) *Globals.Object {
- for scope := s.top_scope; scope != nil; scope = scope.parent {
- obj := scope.Lookup(ident);
- if obj != nil {
- return obj;
- }
- }
- return nil;
-}
-
-
-func (s *State) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
- if s.level > 0 {
- panic("cannot declare objects in other packages");
- }
- obj.pnolev = s.level;
- if scope.Lookup(obj.ident) != nil {
- s.Error(obj.pos, `"` + obj.ident + `" is declared already`);
- return; // don't insert it into the scope
- }
- scope.Insert(obj);
-}
-
-
-func (s *State) Declare(obj *Globals.Object) {
- s.DeclareInScope(s.top_scope, obj);
-}
-
-
-// ----------------------------------------------------------------------------
-// Common productions
-
-func (s *State) DeclareIdent(ident *AST.Expr, kind int, typ *AST.Type) {
- // ident is either a comma-separated list or a single ident
- switch ident.tok {
- case Scanner.IDENT:
- obj := Globals.NewObject(ident.pos, kind, ident.obj.ident);
- s.Declare(obj);
- case Scanner.COMMA:
- s.DeclareIdent(ident.x, kind, typ);
- s.DeclareIdent(ident.y, kind, typ);
- default:
- unreachable();
- }
-}
-
-
-// ----------------------------------------------------------------------------
func (s *State) CheckType() {
}
@@ -131,48 +67,11 @@
// single declaration
switch d.tok {
case Scanner.IMPORT:
- assert(d.ident == nil || d.ident.tok == Scanner.IDENT);
- if d.ident != nil {
- s.DeclareIdent(d.ident, d.tok, d.typ);
- } else {
- }
-
case Scanner.EXPORT:
- // TODO
-
case Scanner.CONST:
- s.DeclareIdent(d.ident, d.tok, d.typ);
-
case Scanner.VAR:
- s.DeclareIdent(d.ident, d.tok, d.typ);
-
case Scanner.TYPE:
- assert(d.ident.tok == Scanner.IDENT);
- // types may be forward-declared
- obj := s.Lookup(d.ident.obj.ident);
- if obj != nil {
- // TODO check if proper forward-declaration
-
- } else {
- s.DeclareIdent(d.ident, d.tok, d.typ);
- }
-
case Scanner.FUNC:
- assert(d.ident.tok == Scanner.IDENT);
- if d.typ.key != nil {
- // method
- // TODO
- } else {
- // functions may be forward-declared
- obj := s.Lookup(d.ident.obj.ident);
- if obj != nil {
- // TODO check if proper forward-declaration
-
- } else {
- s.DeclareIdent(d.ident, d.tok, d.typ);
- }
- }
-
default:
unreachable();
}
@@ -181,16 +80,9 @@
func (s *State) CheckProgram(p *AST.Program) {
- s.OpenScope();
-
- { s.OpenScope();
- for i := 0; i < p.decls.Len(); i++ {
- s.CheckDeclaration(p.decls.At(i).(*AST.Decl));
- }
- s.CloseScope();
+ for i := 0; i < p.decls.Len(); i++ {
+ s.CheckDeclaration(p.decls.At(i).(*AST.Decl));
}
-
- s.CloseScope();
}