]> Cypherpunks repositories - gostls13.git/commitdiff
snapshot of pretty printer:
authorRobert Griesemer <gri@golang.org>
Thu, 16 Oct 2008 00:06:28 +0000 (17:06 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 16 Oct 2008 00:06:28 +0000 (17:06 -0700)
- almost there, receivers, labels, composites, comments are not yet printed
- runs through 18KLOC of Go code and prints it again

R=r
OCL=17237
CL=17237

usr/gri/pretty/Makefile
usr/gri/pretty/node.go
usr/gri/pretty/parser.go
usr/gri/pretty/printer.go

index 8fd88a0ce99944b8ca18ee288ac94d7d89a6b1a8..ae49902ea1f2539c84f69d6d52a2792fbd8cebc7 100644 (file)
@@ -36,18 +36,26 @@ test: pretty
 testnoisy: pretty
        pretty *.go
        pretty ../gosrc/*.go
+       #pretty $(GOROOT)/test/*.go  # contains incorrect programs
        pretty $(GOROOT)/test/235.go
        pretty $(GOROOT)/test/args.go
        pretty $(GOROOT)/test/bufiolib.go
        pretty $(GOROOT)/test/char_lit.go
-       pretty $(GOROOT)/test/sieve.go
+       pretty $(GOROOT)/test/complit.go
+       pretty $(GOROOT)/test/const.go
+       pretty $(GOROOT)/test/dialgoogle.go
+       pretty $(GOROOT)/test/empty.go
+       pretty $(GOROOT)/test/env.go
+       pretty $(GOROOT)/test/float_lit.go
+       pretty $(GOROOT)/test/fmt_test.go
+       pretty $(GOROOT)/test/for.go
+       pretty $(GOROOT)/test/func.go
+       pretty $(GOROOT)/test/func1.go
+       pretty $(GOROOT)/test/func2.go
        pretty $(GOROOT)/src/pkg/*.go
-       pretty $(GOROOT)/src/lib/flag.go
-       pretty $(GOROOT)/src/lib/fmt.go
-       pretty $(GOROOT)/src/lib/rand.go
-       pretty $(GOROOT)/src/lib/math/*.go
-       pretty $(GOROOT)/src/lib/container/*.go
-       pretty $(GOROOT)/src/lib/syscall/*.go
+       pretty $(GOROOT)/src/lib/*.go
+       pretty $(GOROOT)/src/lib/*/*.go
+       pretty $(GOROOT)/usr/r/*/*.go
        echo "DONE"
 
 # These tests don't work yet
index 51ea1e68136a7e09e251f49fdee39775f86d0aca..8f81af83871b904cf2fc723beb028d669ac2b792 100644 (file)
@@ -38,6 +38,11 @@ func (p *List) at(i int) Node {
 }
 
 
+func (p *List) set(i int, x Node) {
+       p.a[i] = x;
+}
+
+
 func (p *List) Add (x Node) {
        a := p.a;
        n := len(a);
@@ -100,7 +105,7 @@ export type Expr struct {
        pos, tok int;
        x, y *Expr;  // binary (x, y) and unary (y) expressions
        s string;  // identifiers and literals
-       t *Type;  // declarations and composite literals
+       t *Type;  // operands that are types
 }
 
 
@@ -130,6 +135,13 @@ export func NewLit(pos, tok int, s string) *Expr {
 }
 
 
+export func NewTypeExpr(pos int, t *Type) *Expr {
+       e := new(Expr);
+       e.pos, e.tok, e.t = pos, Scanner.TYPE, t;
+       return e;
+}
+
+
 // ----------------------------------------------------------------------------
 // Statements
 
index a51683d678b2a36aa69e87837092050fdf1a803f..a4b4d56854f4699747a3647bee64c2f42aa71e78 100644 (file)
@@ -238,10 +238,10 @@ func (P *Parser) ParseChannelType() *Node.Type {
 }
 
 
-func (P *Parser) ParseVarDeclList() {
+func (P *Parser) ParseVarDeclList(list *Node.List) {
        P.Trace("VarDeclList");
 
-       list := Node.NewList();
+       i0 := list.len();
        list.Add(P.ParseType());
        for P.tok == Scanner.COMMA {
                P.Next();
@@ -251,19 +251,31 @@ func (P *Parser) ParseVarDeclList() {
        typ := P.TryType();
 
        if typ != nil {
-               // all list entries must be identifiers;
-               // convert the list into an expression list of identifiers
-               for i, n := 0, list.len(); i < n; i++ {
+               // all list entries must be identifiers
+               // convert the type entries into identifiers
+               for i, n := i0, list.len(); i < n; i++ {
                        t := list.at(i).(*Node.Type);
                        if t.tok == Scanner.IDENT && t.expr.tok == Scanner.IDENT {
-                               x := t.expr;
+                               list.set(i, t.expr);
                        } else {
+                               list.set(i, Node.NewLit(t.pos, Scanner.IDENT, "bad"));
                                P.Error(t.pos, "identifier expected");
                        }
                }
+               // add type
+               list.Add(Node.NewTypeExpr(typ.pos, typ));
+
        } else {
                // all list entries are types
+               // convert all type entries into type expressions
+               for i, n := i0, list.len(); i < n; i++ {
+                       t := list.at(i).(*Node.Type);
+                       list.set(i, Node.NewTypeExpr(t.pos, t));
+               }
                
+               if P.tok == Scanner.COMMA {
+                       panic("internal parser error");
+               }
        }
        
        P.Ecart();
@@ -274,10 +286,10 @@ func (P *Parser) ParseParameterList() *Node.List {
        P.Trace("ParameterList");
        
        list := Node.NewList();
-       P.ParseVarDeclList();
+       P.ParseVarDeclList(list);
        for P.tok == Scanner.COMMA {
                P.Next();
-               P.ParseVarDeclList();
+               P.ParseVarDeclList(list);
        }
        
        P.Ecart();
@@ -285,18 +297,18 @@ func (P *Parser) ParseParameterList() *Node.List {
 }
 
 
-func (P *Parser) ParseParameters() *Node.List {
+func (P *Parser) ParseParameters() *Node.Type {
        P.Trace("Parameters");
        
-       var list *Node.List;
+       t := Node.NewType(P.pos, Scanner.STRUCT);
        P.Expect(Scanner.LPAREN);
        if P.tok != Scanner.RPAREN {
-               list = P.ParseParameterList();
+               t.list = P.ParseParameterList();
        }
        P.Expect(Scanner.RPAREN);
        
        P.Ecart();
-       return list;
+       return t;
 }
 
 
@@ -316,18 +328,23 @@ func (P *Parser) ParseResultList() {
 }
 
 
-func (P *Parser) ParseResult() *Node.List {
+func (P *Parser) ParseResult() *Node.Type {
        P.Trace("Result");
        
-       var list *Node.List;
+       var t *Node.Type;
        if P.tok == Scanner.LPAREN {
-               list = P.ParseParameters();
+               t = P.ParseParameters();
        } else {
                typ := P.TryType();
+               if typ != nil {
+                       t = Node.NewType(P.pos, Scanner.STRUCT);
+                       t.list = Node.NewList();
+                       t.list.Add(Node.NewTypeExpr(typ.pos, typ));
+               }
        }
 
        P.Ecart();
-       return list;
+       return t;
 }
 
 
@@ -341,8 +358,8 @@ func (P *Parser) ParseFunctionType() *Node.Type {
        P.Trace("FunctionType");
        
        t := Node.NewType(P.pos, Scanner.LPAREN);
-       t.list = P.ParseParameters();
-       P.ParseResult();
+       t.list = P.ParseParameters().list;  // TODO find better solution
+       t.elt = P.ParseResult();
        
        P.Ecart();
        return t;
@@ -405,7 +422,7 @@ func (P *Parser) ParseStructType() *Node.Type {
                P.Next();
                t.list = Node.NewList();
                for P.tok == Scanner.IDENT {
-                       P.ParseVarDeclList();
+                       P.ParseVarDeclList(t.list);
                        if P.tok != Scanner.RBRACE {
                                P.Expect(Scanner.SEMICOLON);
                        }
@@ -521,7 +538,7 @@ func (P *Parser) ParseFunctionLit() *Node.Expr {
        P.scope_lev--;
        
        P.Ecart();
-       return nil;
+       return Node.NewLit(P.pos, Scanner.INT, "0");  // "null" expr
 }
 
 
@@ -550,16 +567,17 @@ func (P *Parser) ParseOperand() *Node.Expr {
                }
 
        case Scanner.FUNC:
-               P.ParseFunctionLit();
+               x = P.ParseFunctionLit();
                
        default:
-               typ := P.TryType();
-               if typ != nil {
-                       break;
+               t := P.TryType();
+               if t != nil {
+                       x = Node.NewTypeExpr(t.pos, t);
+               } else {
+                       P.Error(P.pos, "operand expected");
+                       P.Next();  // make progress
+                       x = Node.NewLit(P.pos, Scanner.INT, "0");  // "null" expr
                }
-
-               P.Error(P.pos, "operand expected");
-               P.Next();  // make progress
        }
 
        P.Ecart();
@@ -635,7 +653,7 @@ func (P *Parser) ParseCall(x *Node.Expr) *Node.Expr {
 }
 
 
-func (P *Parser) ParseCompositeLit() {
+func (P *Parser) ParseCompositeLit(t *Node.Type) *Node.Expr {
        P.Trace("CompositeLit");
 
        mode := 0;
@@ -659,6 +677,7 @@ func (P *Parser) ParseCompositeLit() {
        P.Expect(Scanner.RBRACE);
        
        P.Ecart();
+       return Node.NewLit(P.pos, Scanner.INT, "0");  // "null" expr
 }
 
 
@@ -673,8 +692,19 @@ func (P *Parser) ParsePrimaryExpr() *Node.Expr {
                case Scanner.LPAREN: x = P.ParseCall(x);
                case Scanner.LBRACE:
                        if P.expr_lev > 0 {
-                               P.ParseCompositeLit();
+                               var t *Node.Type;
+                               if x.tok == Scanner.TYPE {
+                                       t = x.t;
+                               } else if x.tok == Scanner.IDENT {
+                                       // assume a type name
+                                       t = Node.NewType(x.pos, Scanner.IDENT);
+                                       t.expr = x;
+                               } else {
+                                       P.Error(x.pos, "type expected for composite literal");
+                               }
+                               x = P.ParseCompositeLit(t);
                        } else {
+                               // composites inside control clauses must be parenthesized
                                goto exit;
                        }
                default: goto exit;
@@ -1100,6 +1130,7 @@ func (P *Parser) ParseImportSpec() *Node.Decl {
        
        if P.tok == Scanner.STRING {
                // TODO eventually the scanner should strip the quotes
+               d.val = Node.NewLit(P.pos, Scanner.STRING, P.val);
                P.Next();
        } else {
                P.Expect(Scanner.STRING);  // use Expect() error handling
@@ -1218,15 +1249,11 @@ func (P *Parser) ParseFunctionDecl(exported bool) *Node.Decl {
        P.Expect(Scanner.FUNC);
        if P.tok == Scanner.LPAREN {
                pos := P.pos;
-               P.ParseParameters();
-               /*
-               if tmp.len() > 0 {
-                       //recv = tmp.at(0);
-               }
-               */
+               recv := P.ParseParameters();
+               // TODO: fix this
                /*
-               if recv.idents.len() != 1 {
-                       //P.Error(pos, "must have exactly one receiver");
+               if recv.list.len() != 1 {
+                       P.Error(pos, "must have exactly one receiver");
                }
                */
        }
index 76b9dd9dce4792d326433b4c21fee6e139837a69..2b5e70da1734ec86d323e72a8e6ba20b3365aacb 100644 (file)
@@ -16,7 +16,7 @@ export type Printer struct {
 }
 
 
-func (P *Printer) String(s string) {
+func (P *Printer) String(pos int, s string) {
        if P.semi && P.level > 0 {  // no semicolons at level 0
                print(";");
        }
@@ -31,8 +31,13 @@ func (P *Printer) String(s string) {
 }
 
 
-func (P *Printer) Token(tok int) {
-       P.String(Scanner.TokenString(tok));
+func (P *Printer) Blank() {
+       P.String(0, " ");
+}
+
+
+func (P *Printer) Token(pos int, tok int) {
+       P.String(pos, Scanner.TokenString(tok));
 }
 
 
@@ -44,7 +49,7 @@ func (P *Printer) NewLine() {  // explicit "\n"
 
 func (P *Printer) OpenScope(paren string) {
        P.semi, P.newl = false, false;
-       P.String(paren);
+       P.String(0, paren);
        P.level++;
        P.indent++;
        P.newl = true;
@@ -54,7 +59,7 @@ func (P *Printer) OpenScope(paren string) {
 func (P *Printer) CloseScope(paren string) {
        P.indent--;
        P.semi = false;
-       P.String(paren);
+       P.String(0, paren);
        P.level--;
        P.semi, P.newl = false, true;
 }
@@ -63,50 +68,91 @@ func (P *Printer) CloseScope(paren string) {
 // ----------------------------------------------------------------------------
 // Types
 
+func (P *Printer) Type(t *Node.Type)
 func (P *Printer) Expr(x *Node.Expr)
 
+func (P *Printer) Parameters(list *Node.List) {
+       var prev int;
+       for i, n := 0, list.len(); i < n; i++ {
+               x := list.at(i).(*Node.Expr);
+               if i > 0 {
+                       if prev == x.tok || prev == Scanner.TYPE {
+                               P.String(0, ", ");
+                       } else {
+                               P.Blank();
+                       }
+               }
+               P.Expr(x);
+               prev = x.tok;
+       }
+}
+
+
+func (P *Printer) Fields(list *Node.List) {
+       var prev int;
+       for i, n := 0, list.len(); i < n; i++ {
+               x := list.at(i).(*Node.Expr);
+               if i > 0 {
+                       if prev == Scanner.TYPE {
+                               P.String(0, ";");
+                               P.newl = true;
+                       } else if prev == x.tok {
+                               P.String(0, ", ");
+                       } else {
+                               P.Blank();
+                       }
+               }
+               P.Expr(x);
+               prev = x.tok;
+       }
+       P.newl = true;
+}
+
+
 func (P *Printer) Type(t *Node.Type) {
+       if t == nil {  // TODO remove this check
+               P.String(0, "<nil type>");
+               return;
+       }
+
        switch t.tok {
        case Scanner.IDENT:
                P.Expr(t.expr);
 
        case Scanner.LBRACK:
-               P.String("[");
+               P.String(t.pos, "[");
                if t.expr != nil {
                        P.Expr(t.expr);
                }
-               P.String("] ");
+               P.String(0, "] ");
                P.Type(t.elt);
 
        case Scanner.STRUCT:
-               P.String("struct");
+               P.String(t.pos, "struct");
                if t.list != nil {
                        P.OpenScope(" {");
-                       /*
-                       for i := 0; i < x.fields.len(); i++ {
-                               P.Print(x.fields.at(i));
-                               P.newl, P.semi = true, true;
-                       }
-                       */
+                       P.Fields(t.list);
                        P.CloseScope("}");
                }
 
        case Scanner.MAP:
-               P.String("[");
+               P.String(t.pos, "[");
                P.Type(t.key);
-               P.String("] ");
+               P.String(0, "] ");
                P.Type(t.elt);
 
        case Scanner.CHAN:
+               var m string;
                switch t.mode {
-               case Node.FULL: P.String("chan ");
-               case Node.RECV: P.String("<-chan ");
-               case Node.SEND: P.String("chan <- ");
+               case Node.FULL: m = "chan ";
+               case Node.RECV: m = "<-chan ";
+               case Node.SEND: m = "chan <- ";
                }
+               P.String(t.pos, m);
                P.Type(t.elt);
 
        case Scanner.INTERFACE:
-               P.String("interface");
+               P.String(t.pos, "interface");
                if t.list != nil {
                        P.OpenScope(" {");
                        /*
@@ -119,20 +165,18 @@ func (P *Printer) Type(t *Node.Type) {
                }
 
        case Scanner.MUL:
-               P.String("*");
+               P.String(t.pos, "*");
                P.Type(t.elt);
 
        case Scanner.LPAREN:
-               P.String("(");
-               //P.PrintList(x.params);
-               P.String(")");
-               /*
-               if x.result != nil {
-                       P.String(" (");
-                       P.PrintList(x.result);
-                       P.String(")");
+               P.String(t.pos, "(");
+               P.Parameters(t.list);
+               P.String(0, ")");
+               if t.elt != nil {
+                       P.String(0, " (");
+                       P.Parameters(t.elt.list);
+                       P.String(0, ")");
                }
-               */
 
        default:
                panic("UNREACHABLE");
@@ -149,49 +193,55 @@ func (P *Printer) Expr1(x *Node.Expr, prec1 int) {
        }
 
        switch x.tok {
+       case Scanner.VAR:
+               panic("UNIMPLEMENTED (VAR)");
+               
+       case Scanner.TYPE:
+               P.Type(x.t);
+
        case Scanner.IDENT, Scanner.INT, Scanner.STRING, Scanner.FLOAT:
-               P.String(x.s);
+               P.String(x.pos, x.s);
 
        case Scanner.COMMA:
                P.Expr1(x.x, 0);
-               P.String(", ");
+               P.String(x.pos, ", ");
                P.Expr1(x.y, 0);
 
        case Scanner.PERIOD:
-               P.Expr1(x.x, 8);
-               P.String(".");
+               P.Expr1(x.x, 8);  // 8 == highest precedence
+               P.String(x.pos, ".");
                P.Expr1(x.y, 8);
                
        case Scanner.LBRACK:
                P.Expr1(x.x, 8);
-               P.String("[");
+               P.String(x.pos, "[");
                P.Expr1(x.y, 0);
-               P.String("]");
+               P.String(0, "]");
 
        case Scanner.LPAREN:
                P.Expr1(x.x, 8);
-               P.String("(");
+               P.String(x.pos, "(");
                P.Expr1(x.y, 0);
-               P.String(")");
+               P.String(0, ")");
                
        default:
                if x.x == nil {
                        // unary expression
-                       P.Token(x.tok);
-                       P.Expr1(x.y, 7);
+                       P.Token(x.pos, x.tok);
+                       P.Expr1(x.y, 7);  // 7 == unary operator precedence
                } else {
                        // binary expression: print ()'s if necessary
                        prec := Scanner.Precedence(x.tok);
                        if prec < prec1 {
-                               print("(");
+                               P.String(0, "(");
                        }
                        P.Expr1(x.x, prec);
-                       P.String(" ");
-                       P.Token(x.tok);
-                       P.String(" ");
+                       P.Blank();
+                       P.Token(x.pos, x.tok);
+                       P.Blank();
                        P.Expr1(x.y, prec);
                        if prec < prec1 {
-                               print(")");
+                               P.String(0, ")");
                        }
                }
        }
@@ -231,31 +281,30 @@ func (P *Printer) Block(list *Node.List, indent bool) {
 
 func (P *Printer) ControlClause(s *Node.Stat) {
        if s.init != nil {
-               P.String(" ");
+               P.Blank();
                P.Stat(s.init);
                P.semi = true;
-               P.String("");
        }
        if s.expr != nil {
-               P.String(" ");
+               P.Blank();
                P.Expr(s.expr);
                P.semi = false;
        }
        if s.tok == Scanner.FOR && s.post != nil {
                P.semi = true;
-               P.String(" ");
+               P.Blank();
                P.Stat(s.post);
                P.semi = false;
        }
-       P.String(" ");
+       P.Blank();
 }
 
 
-func (P *Printer) Declaration(d *Node.Decl);
+func (P *Printer) Declaration(d *Node.Decl, parenthesized bool);
 
 func (P *Printer) Stat(s *Node.Stat) {
        if s == nil {  // TODO remove this check
-               P.String("<nil stat>");
+               P.String(0, "<nil stat>");
                return;
        }
 
@@ -265,66 +314,66 @@ func (P *Printer) Stat(s *Node.Stat) {
                P.semi = true;
 
        case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
-               P.Declaration(s.decl);
+               P.Declaration(s.decl, false);
 
        case Scanner.DEFINE, Scanner.ASSIGN, Scanner.ADD_ASSIGN,
                Scanner.SUB_ASSIGN, Scanner.MUL_ASSIGN, Scanner.QUO_ASSIGN,
                Scanner.REM_ASSIGN, Scanner.AND_ASSIGN, Scanner.OR_ASSIGN,
                Scanner.XOR_ASSIGN, Scanner.SHL_ASSIGN, Scanner.SHR_ASSIGN:
                P.Expr(s.lhs);
-               P.String(" ");
-               P.Token(s.tok);
-               P.String(" ");
+               P.Blank();
+               P.Token(s.pos, s.tok);
+               P.Blank();
                P.Expr(s.expr);
                P.semi = true;
 
        case Scanner.INC, Scanner.DEC:
                P.Expr(s.expr);
-               P.Token(s.tok);
+               P.Token(s.pos, s.tok);
                P.semi = true;
 
        case Scanner.LBRACE:
                P.Block(s.block, true);
 
        case Scanner.IF:
-               P.String("if");
+               P.String(s.pos, "if");
                P.ControlClause(s);
                P.Block(s.block, true);
                if s.post != nil {
                        P.newl = false;
-                       P.String(" else ");
+                       P.String(0, " else ");
                        P.Stat(s.post);
                }
 
        case Scanner.FOR:
-               P.String("for");
+               P.String(s.pos, "for");
                P.ControlClause(s);
                P.Block(s.block, true);
 
        case Scanner.SWITCH, Scanner.SELECT:
-               P.Token(s.tok);
+               P.Token(s.pos, s.tok);
                P.ControlClause(s);
                P.Block(s.block, false);
 
        case Scanner.CASE, Scanner.DEFAULT:
-               P.Token(s.tok);
+               P.Token(s.pos, s.tok);
                if s.expr != nil {
-                       P.String(" ");
+                       P.Blank();
                        P.Expr(s.expr);
                }
-               P.String(":");
+               P.String(0, ":");
                P.OpenScope("");
                P.StatementList(s.block);
                P.CloseScope("");
 
        case Scanner.GO, Scanner.RETURN, Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
-               P.Token(s.tok);
-               P.String(" ");
+               P.Token(s.pos, s.tok);
+               P.Blank();
                P.Expr(s.expr);
                P.semi = true;
 
        default:
-               P.String("<stat>");
+               P.String(s.pos, "<stat>");
                P.semi = true;
        }
 }
@@ -363,45 +412,47 @@ func (P *Printer) DoMethodDecl(x *AST.MethodDecl) {
 */
 
 
-func (P *Printer) Declaration(d *Node.Decl) {
-       if d.tok == Scanner.FUNC || d.ident == nil {
+func (P *Printer) Declaration(d *Node.Decl, parenthesized bool) {
+       if d == nil {  // TODO remove this check
+               P.String(0, "<nil decl>");
+               return;
+       }
+
+       if !parenthesized {
                if d.exported {
-                       P.String("export ");
+                       P.String(0, "export ");
                }
-               P.Token(d.tok);
-               P.String(" ");
+               P.Token(d.pos, d.tok);
+               P.Blank();
        }
 
        if d.ident == nil {
-               switch d.list.len() {
-               case 0:
-                       P.String("()");
-               case 1:
-                       P.Declaration(d.list.at(0).(*Node.Decl));
-               default:
-                       P.OpenScope("(");
-                       for i := 0; i < d.list.len(); i++ {
-                               P.Declaration(d.list.at(i).(*Node.Decl));
-                               P.newl, P.semi = true, true;
-                       }
-                       P.CloseScope(")");
+               P.OpenScope("(");
+               for i := 0; i < d.list.len(); i++ {
+                       P.Declaration(d.list.at(i).(*Node.Decl), true);
+                       P.newl, P.semi = true, true;
                }
+               P.CloseScope(")");
 
        } else {
                P.Expr(d.ident);
                if d.typ != nil {
-                       P.String(" ");
+                       P.Blank();
                        P.Type(d.typ);
                }
                if d.val != nil {
-                       P.String(" = ");
+                       if d.tok == Scanner.IMPORT {
+                               P.Blank();
+                       } else {
+                               P.String(0, " = ");
+                       }
                        P.Expr(d.val);
                }
                if d.list != nil {
                        if d.tok != Scanner.FUNC {
                                panic("must be a func declaration");
                        }
-                       P.String(" ");
+                       P.Blank();
                        P.Block(d.list, true);
                }
        }
@@ -419,12 +470,12 @@ func (P *Printer) Declaration(d *Node.Decl) {
 // Program
 
 func (P *Printer) Program(p *Node.Program) {
-       P.String("package ");
+       P.String(p.pos, "package ");
        P.Expr(p.ident);
        P.NewLine();
        for i := 0; i < p.decls.len(); i++ {
-               P.Declaration(p.decls.at(i));
+               P.Declaration(p.decls.at(i), false);
        }
        P.newl = true;
-       P.String("");
+       P.String(0, "");  // flush
 }