mirror of
https://github.com/golang/go
synced 2024-11-25 21:57:57 -07:00
- snapshot of state before trying yet another, hopefully better working
way to integrate comments into the generated output - various simplificatins and cleanups throughout R=r OCL=20062 CL=20062
This commit is contained in:
parent
d040d26863
commit
732b53a1fe
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,7 @@ func main() {
|
||||
return;
|
||||
}
|
||||
if !silent.BVal() && !flags.testmode {
|
||||
var P Printer.Printer;
|
||||
(&P).Program(prog);
|
||||
Printer.Print(prog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
// comments
|
||||
clist *array.Array;
|
||||
cindex int;
|
||||
cpos int;
|
||||
}
|
||||
|
||||
|
||||
func (P *Printer) Printf(fmt string, s ...) {
|
||||
Fmt.fprintf(P.writer, fmt, 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
|
||||
P.comments = comments;
|
||||
P.cindex = -1;
|
||||
P.NextComment();
|
||||
|
||||
// formatting control initialized correctly by default
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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);
|
||||
if ctext == "\n" {
|
||||
// found a newline in src
|
||||
src_nl++;
|
||||
|
||||
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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
at_line_begin = true;
|
||||
}
|
||||
|
||||
P.cindex++;
|
||||
if P.cindex < P.clist.Len() {
|
||||
P.cpos = P.clist.At(P.cindex).(*AST.Comment).pos;
|
||||
} else {
|
||||
P.cpos = 1000000000; // infinite
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
*/
|
||||
}
|
||||
|
||||
src_nl = 0;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
P.String(0, ""); // flush buffer
|
||||
|
||||
// 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.Program(prog);
|
||||
|
||||
// flush
|
||||
P.String(0, "");
|
||||
err := P.writer.Flush();
|
||||
if err != nil {
|
||||
panic("print error - exiting");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user