]> Cypherpunks repositories - gostls13.git/commitdiff
- snapshot of state before trying yet another, hopefully better working
authorRobert Griesemer <gri@golang.org>
Wed, 26 Nov 2008 21:23:26 +0000 (13:23 -0800)
committerRobert Griesemer <gri@golang.org>
Wed, 26 Nov 2008 21:23:26 +0000 (13:23 -0800)
way to integrate comments into the generated output
- various simplificatins and cleanups throughout

R=r
OCL=20062
CL=20062

usr/gri/pretty/ast.go
usr/gri/pretty/compilation.go
usr/gri/pretty/parser.go
usr/gri/pretty/pretty.go
usr/gri/pretty/printer.go
usr/gri/pretty/scanner.go

index 25a93377bf55ab8596cab9fd473a6f7187886fcd..d6ed78afc3a6e794180a511a05f1407eaac1a2ee 100644 (file)
@@ -180,14 +180,14 @@ export var BadDecl = NewDecl(0, Scanner.ILLEGAL, false);
 // Program
 
 export type Comment struct {
-       pos, tok int;
+       pos int;
        text string;
 }
 
 
-export func NewComment(pos, tok int, text string) *Comment {
+export func NewComment(pos int, text string) *Comment {
        c := new(Comment);
-       c.pos, c.tok, c.text = pos, tok, text;
+       c.pos, c.text = pos, text;
        return c;
 }
 
index 5c47d85f40d56bd3d4db5d9485c004b0d0dae972..9df221436ae160fc2db237f3f05980c367ac5a1f 100644 (file)
@@ -122,7 +122,7 @@ export func Compile(src_file string, flags *Flags) (*AST.Program, int) {
        err.Init(src_file, src, flags.columns);
 
        var scanner Scanner.Scanner;
-       scanner.Init(&err, src, flags.testmode);
+       scanner.Init(&err, src, true, flags.testmode);
 
        var tstream *<-chan *Scanner.Token;
        if flags.tokenchan {
index 2b942ac9a01e01a61788b909adcdd6f35210711d..573ea1a340ac9893f524dbba663146bbe3d192bb 100644 (file)
@@ -78,15 +78,8 @@ func (P *Parser) Next0() {
 
 
 func (P *Parser) Next() {
-       // TODO This is too expensive for every token - fix
-       for P.Next0();
-               P.tok == Scanner.COMMENT_WW ||
-               P.tok == Scanner.COMMENT_WB ||
-               P.tok == Scanner.COMMENT_BW ||
-               P.tok == Scanner.COMMENT_BB ;
-               P.Next0() 
-       {
-               P.comments.Push(AST.NewComment(P.pos, P.tok, P.val));
+       for P.Next0(); P.tok == Scanner.COMMENT; P.Next0() {
+               P.comments.Push(AST.NewComment(P.pos, P.val));
        }
 }
 
index 0c65bfc006a1b503490f7321cc224f969fa6f982..80edbfcc49a5cd2d13954c0f7dfd629274913fb0 100644 (file)
@@ -49,8 +49,7 @@ func main() {
                                return;
                        }
                        if !silent.BVal() && !flags.testmode {
-                               var P Printer.Printer;
-                               (&P).Program(prog);
+                               Printer.Print(prog);
                        }
                }
        }
index 6bb755b4b70a5b4afb5a5f5d86ad49b5dde44a31..0b9da34de549f31e771d4d595944496cd8bdb17e 100644 (file)
@@ -4,20 +4,20 @@
 
 package Printer
 
-import "array"
-import Strings "strings"
-import Scanner "scanner"
-import AST "ast"
-import Flag "flag"
-import Fmt "fmt"
-import IO "io"
-import OS "os"
-import TabWriter "tabwriter"
+import (
+       "os";
+       "array";
+       "tabwriter";
+       "flag";
+       "fmt";
+       Scanner "scanner";
+       AST "ast";
+)
 
 var (
-       tabwidth = Flag.Int("tabwidth", 4, nil, "tab width");
-       usetabs = Flag.Bool("usetabs", false, nil, "align with tabs instead of blanks");
-       comments = Flag.Bool("comments", false, nil, "enable printing of comments");
+       tabwidth = flag.Int("tabwidth", 4, nil, "tab width");
+       usetabs = flag.Bool("usetabs", true, nil, "align with tabs instead of blanks");
+       comments = flag.Bool("comments", false, nil, "enable printing of comments");
 )
 
 
@@ -34,25 +34,60 @@ func assert(p bool) {
 // ----------------------------------------------------------------------------
 // Printer
 
-export type Printer struct {
-       writer IO.Write;
+type Printer struct {
+       // output
+       writer *tabwriter.Writer;
        
+       // comments
+       comments *array.Array;
+       cindex int;
+       cpos int;
+
        // formatting control
        lastpos int;  // pos after last string
        level int;  // true scope level
        indent int;  // indentation level
        semi bool;  // pending ";"
        newl int;  // pending "\n"'s
+}
+
+
+func (P *Printer) NextComment() {
+       P.cindex++;
+       if P.comments != nil && P.cindex < P.comments.Len() {
+               P.cpos = P.comments.At(P.cindex).(*AST.Comment).pos;
+       } else {
+               P.cpos = 1<<30;  // infinite
+       }
+}
+
+
+func (P *Printer) Init(writer *tabwriter.Writer, comments *array.Array) {
+       // writer
+       padchar := byte(' ');
+       if usetabs.BVal() {
+               padchar = '\t';
+       }
+       P.writer = tabwriter.New(os.Stdout, int(tabwidth.IVal()), 1, padchar, true);
 
        // comments
-       clist *array.Array;
-       cindex int;
-       cpos int;
+       P.comments = comments;
+       P.cindex = -1;
+       P.NextComment();
+       
+       // formatting control initialized correctly by default
 }
 
 
-func (P *Printer) Printf(fmt string, s ...) {
-       Fmt.fprintf(P.writer, fmt, s);
+// ----------------------------------------------------------------------------
+// Printing support
+
+func (P *Printer) Printf(format string, s ...) {
+       n, err := fmt.fprintf(P.writer, format, s);
+       if err != nil {
+               panic("print error - exiting");
+       }
+       P.lastpos += n;
 }
 
 
@@ -60,6 +95,7 @@ func (P *Printer) String(pos int, s string) {
        if pos == 0 {
                pos = P.lastpos;  // estimate
        }
+       P.lastpos = pos;
 
        if P.semi && P.level > 0 {  // no semicolons at level 0
                P.Printf(";");
@@ -67,66 +103,78 @@ func (P *Printer) String(pos int, s string) {
 
        //print("--", pos, "[", s, "]\n");
        
+       src_nl := 0;
        at_line_begin := false;
        for comments.BVal() && P.cpos < pos {
                //print("cc", P.cpos, "\n");
                
-               // we have a comment that comes before s
-               comment := P.clist.At(P.cindex).(*AST.Comment);
-               text := comment.text;
-               assert(len(text) >= 3);  // classification char + "//" or "/*"
+               // we have a comment/newline that comes before s
+               comment := P.comments.At(P.cindex).(*AST.Comment);
+               ctext := comment.text;
                
-               // classify comment
-               switch comment.tok {
-               case Scanner.COMMENT_BB:
-                       // black space before and after comment on the same line
-                       // - print surrounded by blanks
-                       P.Printf(" %s ", text);
-
-               case Scanner.COMMENT_BW:
-                       // only white space after comment on the same line
-                       // - put into next cell
-                       P.Printf("\t%s", text);
-                       
-               case Scanner.COMMENT_WW, Scanner.COMMENT_WB:
-                       // only white space before comment on the same line
-                       // - indent
-                       /*
-                       if !P.buf.EmptyLine() {
-                               P.buf.Newline();
-                       }
-                       */
-                       for i := P.indent; i > 0; i-- {
-                               P.Printf("\t");
+               if ctext == "\n" {
+                       // found a newline in src
+                       src_nl++;
+
+               } else {
+                       // classify comment
+                       assert(len(ctext) >= 3);  // classification char + "//" or "/*"
+                       //-style comment
+                       if src_nl > 0 || P.cpos == 0 {
+                               // only white space before comment on this line
+                               // or file starts with comment
+                               // - indent
+                               P.Printf("\n");
+                               for i := P.indent; i > 0; i-- {
+                                       P.Printf("\t");
+                               }
+                               P.Printf("%s", ctext);
+                       } else {
+                               // black space before comment on this line
+                               if ctext[1] == '/' {
+                                       //-style comment
+                                       // - put in next cell
+                                       P.Printf("\t%s", ctext);
+                               } else {
+                                       /*-style comment */
+                                       // - print surrounded by blanks
+                                       P.Printf(" %s ", ctext);
+                               }
                        }
-                       P.Printf("%s", text);
 
-               default:
-                       panic("UNREACHABLE");
-               }
-               
-               if text[1] == '/' {
-                       // line comments must end in newline
-                       // TODO should we set P.newl instead?
-                       P.Printf("\n");
-                       for i := P.indent; i > 0; i-- {
-                               P.Printf("\t");
+                       if ctext[1] == '/' {
+                               //-style comments must end in newline
+                               if P.newl == 0 {
+                                       P.newl = 1;
+                               }
+                               /*
+                               // TODO should we set P.newl instead?
+                               P.Printf("\n");
+                               for i := P.indent; i > 0; i-- {
+                                       P.Printf("\t");
+                               }
+                               at_line_begin = true;
+                               */
                        }
-                       at_line_begin = true;
+                       
+                       src_nl = 0;
                }
 
-               P.cindex++;
-               if P.cindex < P.clist.Len() {
-                       P.cpos = P.clist.At(P.cindex).(*AST.Comment).pos;
-               } else {
-                       P.cpos = 1000000000;  // infinite
-               }
+               P.NextComment();
        }
 
        if at_line_begin && P.newl > 0 {
                P.newl--;
        }
        
+       if src_nl > P.newl {
+               P.newl = src_nl;
+       }
+
+       if P.newl > 2 {
+               P.newl = 2;
+       }
+
        if P.newl > 0 {
                P.Printf("\n");
                if P.newl > 1 {
@@ -141,7 +189,6 @@ func (P *Printer) String(pos int, s string) {
 
        P.Printf("%s", s);
 
-       P.lastpos = pos + len(s);
        P.semi, P.newl = false, 0;
 }
 
@@ -151,11 +198,6 @@ func (P *Printer) Blank() {
 }
 
 
-func (P *Printer) Tab() {
-       P.String(0, "\t");
-}
-
-
 func (P *Printer) Token(pos int, tok int) {
        P.String(pos, Scanner.TokenString(tok));
 }
@@ -225,7 +267,7 @@ func (P *Printer) Fields(list *array.Array) {
                                } else if prev == x.tok {
                                        P.String(0, ", ");
                                } else {
-                                       P.Tab();
+                                       P.String(0, "\t");
                                }
                        }
                        P.Expr(x);
@@ -565,7 +607,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
                }
 
                if d.val != nil {
-                       P.Tab();
+                       P.String(0, "\t");
                        if d.tok != Scanner.IMPORT {
                                P.String(0, "= ");
                        }
@@ -603,30 +645,37 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
 // Program
 
 func (P *Printer) Program(p *AST.Program) {
-       // TODO should initialize all fields?
-       padchar := byte(' ');
-       if usetabs.BVal() {
-               padchar = '\t';
-       }
-       P.writer = TabWriter.New(OS.Stdout, int(tabwidth.IVal()), 1, padchar, true);
-       
-       P.clist = p.comments;
-       P.cindex = 0;
-       if p.comments.Len() > 0 {
-               P.cpos = p.comments.At(0).(*AST.Comment).pos;
-       } else {
-               P.cpos = 1000000000;  // infinite
-       }
-
-       // Print package
        P.String(p.pos, "package ");
        P.Expr(p.ident);
        P.newl = 2;
        for i := 0; i < p.decls.Len(); i++ {
                P.Declaration(p.decls.At(i), false);
        }
-       P.newl = 2;     // TODO we should be able to do this with 1 instead of 2
-                               // but we are loosing the last buffer flush in that case
+       
+       // end program with '\n'
+       P.newl = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+// External interface
+
+export func Print(prog *AST.Program) {
+       // setup
+       padchar := byte(' ');
+       if usetabs.BVal() {
+               padchar = '\t';
+       }
+       writer := tabwriter.New(os.Stdout, int(tabwidth.IVal()), 1, padchar, true);
+       var P Printer;
+       P.Init(writer, prog.comments);
 
-       P.String(0, "");  // flush buffer
+       P.Program(prog);
+       
+       // flush
+       P.String(0, "");
+       err := P.writer.Flush();
+       if err != nil {
+               panic("print error - exiting");
+       }
 }
index b4df03f7e54d55c6f2759752c8381258bf6ded13..917acad382974efef0ea3bbb6598281479a8f536 100644 (file)
@@ -17,10 +17,7 @@ export const (
        STRING;
        EOF;
 
-       COMMENT_BB;
-       COMMENT_BW;
-       COMMENT_WB;
-       COMMENT_WW;
+       COMMENT;
 
        ADD;
        SUB;
@@ -124,10 +121,7 @@ export func TokenString(tok int) string {
        case STRING: return "STRING";
        case EOF: return "EOF";
 
-       case COMMENT_BB: return "COMMENT_BB";
-       case COMMENT_BW: return "COMMENT_BW";
-       case COMMENT_WB: return "COMMENT_WB";
-       case COMMENT_WW: return "COMMENT_WW";
+       case COMMENT: return "COMMENT";
 
        case ADD: return "+";
        case SUB: return "-";
@@ -285,10 +279,12 @@ export type ErrorHandler interface {
 
 
 export type Scanner struct {
+       // setup
        err ErrorHandler;
+       src string;  // source
+       scan_comments bool;
 
        // scanning
-       src string;  // source
        pos int;  // current reading position
        ch int;  // one char look-ahead
        chpos int;  // position of ch
@@ -341,10 +337,11 @@ func (S *Scanner) ExpectNoErrors() {
 }
 
 
-func (S *Scanner) Init(err ErrorHandler, src string, testmode bool) {
+func (S *Scanner) Init(err ErrorHandler, src string, scan_comments, testmode bool) {
        S.err = err;
-       
        S.src = src;
+       S.scan_comments = scan_comments;
+
        S.pos = 0;
        S.linepos = 0;
 
@@ -379,41 +376,43 @@ func (S *Scanner) Expect(ch int) {
 }
 
 
-// Returns true if a newline was seen, returns false otherwise.
-func (S *Scanner) SkipWhitespace() bool {
-       sawnl := S.chpos == 0;  // file beginning is always start of a new line
+func (S *Scanner) SkipWhitespace() {
        for {
                switch S.ch {
-               case '\t', '\r', ' ':  // nothing to do
-               case '\n': sawnl = true;
-               default: return sawnl;
+               case '\t', '\r', ' ':
+                       // nothing to do
+               case '\n':
+                       if S.scan_comments {
+                               return;
+                       }
+               default:
+                       return;
                }
                S.Next();
        }
        panic("UNREACHABLE");
-       return false;
 }
 
 
-func (S *Scanner) ScanComment(leading_ws bool) (tok int, val string) {
+func (S *Scanner) ScanComment() string {
        // first '/' already consumed
        pos := S.chpos - 1;
        
        if S.ch == '/' {
-               // comment
+               //-style comment
                S.Next();
                for S.ch >= 0 {
                        S.Next();
                        if S.ch == '\n' {
                                // '\n' terminates comment but we do not include
-                               // it in the comment (otherwise we cannot see the
+                               // it in the comment (otherwise we don't see the
                                // start of a newline in SkipWhitespace()).
                                goto exit;
                        }
                }
                
        } else {
-               /* comment */
+               /*-style comment */
                S.Expect('*');
                for S.ch >= 0 {
                        ch := S.ch;
@@ -430,12 +429,6 @@ func (S *Scanner) ScanComment(leading_ws bool) (tok int, val string) {
 exit:
        comment := S.src[pos : S.chpos];
 
-       // skip whitespace but stop at line end
-       for S.ch == '\t' || S.ch == '\r' || S.ch == ' ' {
-               S.Next();
-       }
-       trailing_ws := S.ch == '\n';
-
        if S.testmode {
                // interpret ERROR and SYNC comments
                oldpos := -1;
@@ -457,21 +450,7 @@ exit:
                }
        }
 
-       if leading_ws {
-               if trailing_ws {
-                       tok = COMMENT_WW;
-               } else {
-                       tok = COMMENT_WB;
-               }
-       } else {
-               if trailing_ws {
-                       tok = COMMENT_BW;
-               } else {
-                       tok = COMMENT_BB;
-               }
-       }
-
-       return tok, comment;
+       return comment;
 }
 
 
@@ -700,7 +679,7 @@ func (S *Scanner) Select4(tok0, tok1, ch2, tok2, tok3 int) int {
 
 
 func (S *Scanner) Scan() (pos, tok int, val string) {
-       sawnl := S.SkipWhitespace();
+L:     S.SkipWhitespace();
        
        pos, tok = S.chpos, ILLEGAL;
        
@@ -711,6 +690,7 @@ func (S *Scanner) Scan() (pos, tok int, val string) {
                S.Next();  // always make progress
                switch ch {
                case -1: tok = EOF;
+               case '\n': tok, val = COMMENT, "\n";
                case '"': tok, val = STRING, S.ScanString();
                case '\'': tok, val = INT, S.ScanChar();
                case '`': tok, val = STRING, S.ScanRawString();
@@ -740,7 +720,10 @@ func (S *Scanner) Scan() (pos, tok int, val string) {
                case '*': tok = S.Select2(MUL, MUL_ASSIGN);
                case '/':
                        if S.ch == '/' || S.ch == '*' {
-                               tok, val = S.ScanComment(sawnl);
+                               tok, val = COMMENT, S.ScanComment();
+                               if !S.scan_comments {
+                                       goto L;
+                               }
                        } else {
                                tok = S.Select2(QUO, QUO_ASSIGN);
                        }