From a893db8767e0857fffe3d8ae64d2b4b2dd2c22fe Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 15 Jun 2009 16:23:16 -0700 Subject: [PATCH] gofmt (final resting place TBD): - replacement for pretty; app to format a single .go file printer.go (pkg/go/printer): - replacement for astprinter.go; implements AST printing - also replaces pkg/go/ast/format.go for now cleanups: - removed/saved away old code R=r,rsc,iant DELTA=2833 (1183 added, 1628 deleted, 22 changed) OCL=30226 CL=30306 --- src/pkg/Make.deps | 3 +- src/pkg/Makefile | 1 + src/pkg/go/ast/Makefile | 10 +- src/pkg/go/ast/format.go | 123 ---- src/pkg/go/printer/Makefile | 60 ++ src/pkg/go/printer/printer.go | 1019 ++++++++++++++++++++++++++ usr/gri/pretty/Makefile | 24 +- usr/gri/pretty/astprinter.go | 1269 --------------------------------- usr/gri/pretty/godoc.go | 58 +- usr/gri/pretty/gofmt.go | 107 +++ usr/gri/pretty/pretty.go | 123 ---- usr/gri/pretty/test.sh | 4 +- usr/gri/pretty/untab.go | 58 -- 13 files changed, 1211 insertions(+), 1648 deletions(-) delete mode 100644 src/pkg/go/ast/format.go create mode 100644 src/pkg/go/printer/Makefile create mode 100644 src/pkg/go/printer/printer.go delete mode 100644 usr/gri/pretty/astprinter.go create mode 100644 usr/gri/pretty/gofmt.go delete mode 100644 usr/gri/pretty/pretty.go delete mode 100644 usr/gri/pretty/untab.go diff --git a/src/pkg/Make.deps b/src/pkg/Make.deps index dd83e8b1cb..d710c59e35 100644 --- a/src/pkg/Make.deps +++ b/src/pkg/Make.deps @@ -16,9 +16,10 @@ exec.install: os.install strings.install exvar.install: fmt.install http.install io.install log.install strconv.install sync.install flag.install: fmt.install os.install strconv.install fmt.install: io.install os.install reflect.install strconv.install utf8.install -go/ast.install: datafmt.install go/token.install io.install os.install unicode.install utf8.install +go/ast.install: go/token.install unicode.install utf8.install go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install go/parser.install: container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install +go/printer.install: fmt.install go/ast.install go/token.install io.install os.install reflect.install go/scanner.install: go/token.install strconv.install unicode.install utf8.install go/token.install: strconv.install hash.install: io.install diff --git a/src/pkg/Makefile b/src/pkg/Makefile index 036a82e38b..3339a9d369 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -33,6 +33,7 @@ DIRS=\ go/ast\ go/doc\ go/parser\ + go/printer\ go/scanner\ go/token\ hash\ diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile index 1fd22ae71f..ead35dead1 100644 --- a/src/pkg/go/ast/Makefile +++ b/src/pkg/go/ast/Makefile @@ -34,21 +34,14 @@ coverage: packages O1=\ ast.$O\ -O2=\ - format.$O\ - -phases: a1 a2 +phases: a1 _obj$D/ast.a: phases a1: $(O1) $(AR) grc _obj$D/ast.a ast.$O rm -f $(O1) -a2: $(O2) - $(AR) grc _obj$D/ast.a format.$O - rm -f $(O2) - newpkg: clean mkdir -p _obj$D @@ -56,7 +49,6 @@ newpkg: clean $(O1): newpkg $(O2): a1 -$(O3): a2 nuke: clean rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a diff --git a/src/pkg/go/ast/format.go b/src/pkg/go/ast/format.go deleted file mode 100644 index caeca19aa6..0000000000 --- a/src/pkg/go/ast/format.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ast - -import ( - "datafmt"; - "go/ast"; - "go/token"; - "io"; - "os"; -) - - -// Format is a customized datafmt.Format for printing of ASTs. -type Format datafmt.Format; - - -// ---------------------------------------------------------------------------- -// Custom formatters - -// The AST-specific formatting state is maintained by a state variable. -type state struct { - // for now we have very little state - // TODO maintain list of unassociated comments - optSemi bool -} - - -func (s *state) Copy() datafmt.Environment { - copy := *s; - return © -} - - -func isValidPos(s *datafmt.State, value interface{}, ruleName string) bool { - pos := value.(token.Position); - return pos.IsValid(); -} - - -func isSend(s *datafmt.State, value interface{}, ruleName string) bool { - return value.(ast.ChanDir) & ast.SEND != 0; -} - - -func isRecv(s *datafmt.State, value interface{}, ruleName string) bool { - return value.(ast.ChanDir) & ast.RECV != 0; -} - - -func isMultiLineComment(s *datafmt.State, value interface{}, ruleName string) bool { - return value.([]byte)[1] == '*'; -} - - -func clearOptSemi(s *datafmt.State, value interface{}, ruleName string) bool { - s.Env().(*state).optSemi = false; - return true; -} - - -func setOptSemi(s *datafmt.State, value interface{}, ruleName string) bool { - s.Env().(*state).optSemi = true; - return true; -} - - -func optSemi(s *datafmt.State, value interface{}, ruleName string) bool { - if !s.Env().(*state).optSemi { - s.Write([]byte{';'}); - } - return true; -} - - -var fmap = datafmt.FormatterMap { - "isValidPos": isValidPos, - "isSend": isSend, - "isRecv": isRecv, - "isMultiLineComment": isMultiLineComment, - "/": clearOptSemi, - "clearOptSemi": clearOptSemi, - "setOptSemi": setOptSemi, - "optSemi": optSemi, -} - - -// ---------------------------------------------------------------------------- -// Printing - -// NewFormat parses a datafmt format specification from a file -// and adds AST-specific custom formatter rules. The result is -// the customized format or an os.Error, if any. -// -func NewFormat(filename string) (Format, os.Error) { - src, err := io.ReadFile(filename); - if err != nil { - return nil, err; - } - f, err := datafmt.Parse(src, fmap); - return Format(f), err; -} - - -// Fprint formats each AST node provided as argument according to the -// format f and writes to standard output. The result is the total number -// of bytes written and an os.Error, if any. -// -func (f Format) Fprint(w io.Writer, nodes ...) (int, os.Error) { - var s state; - return datafmt.Format(f).Fprint(w, &s, nodes); -} - - -// Fprint formats each AST node provided as argument according to the -// format f and writes to w. The result is the total number of bytes -// written and an os.Error, if any. -// -func (f Format) Print(nodes ...) (int, os.Error) { - return f.Fprint(os.Stdout, nodes); -} diff --git a/src/pkg/go/printer/Makefile b/src/pkg/go/printer/Makefile new file mode 100644 index 0000000000..0b0b5a77c6 --- /dev/null +++ b/src/pkg/go/printer/Makefile @@ -0,0 +1,60 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/go/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + printer.$O\ + + +phases: a1 +_obj$D/printer.a: phases + +a1: $(O1) + $(AR) grc _obj$D/printer.a printer.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/printer.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/printer.a + +packages: _obj$D/printer.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/printer.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/printer.a diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go new file mode 100644 index 0000000000..74318b0cd0 --- /dev/null +++ b/src/pkg/go/printer/printer.go @@ -0,0 +1,1019 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The printer package implements printing of AST nodes. +package printer + +import ( + "fmt"; + "go/ast"; + "go/token"; + "io"; + "os"; + "reflect"; +) + + +// Printing is controlled with these flags supplied +// to Fprint via the mode parameter. +// +const ( + ExportsOnly uint = 1 << iota; // print exported code only + DocComments; // print documentation comments + OptCommas; // print optional commas + OptSemis; // print optional semicolons +) + + +type printer struct { + // configuration (does not change after initialization) + output io.Writer; + mode uint; + errors chan os.Error; + comments ast.Comments; // list of unassociated comments; or nil + + // current state (changes during printing) + written int; // number of bytes written + level int; // function nesting level; 0 = package scope, 1 = top-level function scope, etc. + indent int; // indent level + pos token.Position; // output position (possibly estimated) in "AST space" + + // comments + cindex int; // the current comment index + cpos token.Position; // the position of the next comment +} + + +func (p *printer) hasComment(pos token.Position) bool { + return p.cpos.Offset < pos.Offset; +} + + +func (p *printer) nextComment() { + p.cindex++; + if p.comments != nil && p.cindex < len(p.comments) && p.comments[p.cindex] != nil { + p.cpos = p.comments[p.cindex].Pos(); + } else { + p.cpos = token.Position{1<<30, 1<<30, 1}; // infinite + } +} + + +func (p *printer) setComments(comments ast.Comments) { + p.comments = comments; + p.cindex = -1; + p.nextComment(); +} + + +func (p *printer) init(output io.Writer, mode uint) { + p.output = output; + p.mode = mode; + p.errors = make(chan os.Error); + p.setComments(nil); +} + + +var ( + blank = []byte{' '}; + tab = []byte{'\t'}; + newline = []byte{'\n'}; + formfeed = []byte{'\f'}; +) + + +// Writing to p.output is done with write0 which also handles errors. +// It should only be called by write. +// +func (p *printer) write0(data []byte) { + n, err := p.output.Write(data); + p.written += n; + if err != nil { + p.errors <- err; + } +} + + +func (p *printer) write(data []byte) { + i0 := 0; + for i, b := range data { + if b == '\n' || b == '\f' { + // write segment ending in a newline/formfeed followed by indentation + // TODO should convert '\f' into '\n' if the output is not going through + // tabwriter + p.write0(data[i0 : i+1]); + for j := p.indent; j > 0; j-- { + p.write0(tab); + } + i0 = i+1; + + // update p.pos + p.pos.Offset += i+1 - i0 + p.indent; + p.pos.Line++; + p.pos.Column = p.indent + 1; + } + } + + // write remaining segment + p.write0(data[i0 : len(data)]); + + // update p.pos + n := len(data) - i0; + p.pos.Offset += n; + p.pos.Column += n; +} + + +// Reduce contiguous sequences of '\t' in a []byte to a single '\t'. +func untabify(src []byte) []byte { + dst := make([]byte, len(src)); + j := 0; + for i, c := range src { + if c != '\t' || i == 0 || src[i-1] != '\t' { + dst[j] = c; + j++; + } + } + return dst[0 : j]; +} + + +func (p *printer) adjustSpacingAndMergeComments() { + for ; p.hasComment(p.pos); p.nextComment() { + // we have a comment that comes before the current position + comment := p.comments[p.cindex]; + p.write(untabify(comment.Text)); + // TODO + // - classify comment and provide better formatting + // - add extra newlines if so indicated by source positions + } +} + + +func (p *printer) print(args ...) { + v := reflect.NewValue(args).(reflect.StructValue); + for i := 0; i < v.Len(); i++ { + p.adjustSpacingAndMergeComments(); + f := v.Field(i); + switch x := f.Interface().(type) { + case int: + // indentation delta + p.indent += x; + if p.indent < 0 { + panic("print: negative indentation"); + } + case []byte: + p.write(x); + case string: + p.write(io.StringBytes(x)); + case token.Token: + p.write(io.StringBytes(x.String())); + case token.Position: + // set current position + p.pos = x; + default: + panicln("print: unsupported argument type", f.Type().String()); + } + } +} + + +// ---------------------------------------------------------------------------- +// Predicates + +func (p *printer) optSemis() bool { + return p.mode & OptSemis != 0; +} + + +func (p *printer) exportsOnly() bool { + return p.mode & ExportsOnly != 0; +} + + +// The isVisibleX predicates return true if X should produce any output +// given the printing mode and depending on whether X contains exported +// names. + +func (p *printer) isVisibleIdent(x *ast.Ident) bool { + // identifiers in local scopes (p.level > 0) are always visible + // if the surrounding code is printed in the first place + return !p.exportsOnly() || x.IsExported() || p.level > 0; +} + + +func (p *printer) isVisibleIdentList(list []*ast.Ident) bool { + for _, x := range list { + if p.isVisibleIdent(x) { + return true; + } + } + return false; +} + + +func (p *printer) isVisibleFieldList(list []*ast.Field) bool { + for _, f := range list { + if len(f.Names) == 0 { + // anonymous field + // TODO should only return true if the anonymous field + // type is visible (for now be conservative and + // print it so that the generated code is valid) + return true; + } + if p.isVisibleIdentList(f.Names) { + return true; + } + } + return false; +} + + +func (p *printer) isVisibleSpec(spec ast.Spec) bool { + switch s := spec.(type) { + case *ast.ImportSpec: + return !p.exportsOnly(); + case *ast.ValueSpec: + return p.isVisibleIdentList(s.Names); + case *ast.TypeSpec: + return p.isVisibleIdent(s.Name); + } + panic("unreachable"); + return false; +} + + +func (p *printer) isVisibleSpecList(list []ast.Spec) bool { + for _, s := range list { + if p.isVisibleSpec(s) { + return true; + } + } + return false; +} + + +func (p *printer) isVisibleDecl(decl ast.Decl) bool { + switch d := decl.(type) { + case *ast.BadDecl: + return false; + case *ast.GenDecl: + return p.isVisibleSpecList(d.Specs); + case *ast.FuncDecl: + return p.isVisibleIdent(d.Name); + } + panic("unreachable"); + return false; +} + + +// ---------------------------------------------------------------------------- +// Printing of common AST nodes. + +func (p *printer) comment(c *ast.Comment) { + if c != nil { + text := c.Text; + if text[1] == '/' { + // //-style comment - dont print the '\n' + // TODO scanner should probably not include the '\n' in this case + text = text[0 : len(text)-1]; + } + p.print(tab, c.Pos(), text); // tab-separated trailing comment + } +} + + +func (p *printer) doc(d ast.Comments) { + if p.mode & DocComments != 0 { + for _, c := range d { + p.print(c.Pos(), c.Text); + } + } +} + + +func (p *printer) expr(x ast.Expr) bool + +func (p *printer) identList(list []*ast.Ident) { + needsComma := false; + for i, x := range list { + if p.isVisibleIdent(x) { + if needsComma { + p.print(token.COMMA, blank); + } + p.expr(x); + needsComma = true; + } + } +} + + +func (p *printer) exprList(list []ast.Expr) { + for i, x := range list { + if i > 0 { + p.print(token.COMMA, blank); + } + p.expr(x); + } +} + + +func (p *printer) parameters(list []*ast.Field) { + p.print(token.LPAREN); + if len(list) > 0 { + for i, par := range list { + if i > 0 { + p.print(token.COMMA, blank); + } + p.identList(par.Names); // p.level > 0; all identifiers will be printed + if len(par.Names) > 0 { + // at least one identifier + p.print(blank); + }; + p.expr(par.Type); + } + } + p.print(token.RPAREN); +} + + +func (p *printer) signature(params, result []*ast.Field) { + p.parameters(params); + if result != nil { + p.print(blank); + + if len(result) == 1 && result[0].Names == nil { + // single anonymous result; no ()'s unless it's a function type + f := result[0]; + if _, isFtyp := f.Type.(*ast.FuncType); !isFtyp { + p.expr(f.Type); + return; + } + } + + p.parameters(result); + } +} + + +// Returns true if the field list ends in a closing brace. +func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isInterface bool) bool { + hasBody := p.isVisibleFieldList(list); + if !lbrace.IsValid() || p.exportsOnly() && !hasBody { + // forward declaration without {}'s or no visible exported fields + // (in all other cases, the {}'s must be printed even if there are + // no fields, otherwise the type is incorrect) + return false; // no {}'s + } + + p.print(blank, lbrace, token.LBRACE); + + if hasBody { + p.print(+1, newline); + + var needsSemi bool; + var lastWasAnon bool; // true if the previous line was an anonymous field + var lastComment *ast.Comment; // the comment from the previous line + for _, f := range list { + hasNames := p.isVisibleIdentList(f.Names); + isAnon := len(f.Names) == 0; + + if hasNames || isAnon { + // at least one visible identifier or anonymous field + // TODO this is conservative - see isVisibleFieldList + if needsSemi { + p.print(token.SEMICOLON); + p.comment(lastComment); + if lastWasAnon == isAnon { + // previous and current line have same structure; + // continue with existing columns + p.print(newline); + } else { + // previous and current line have different structure; + // flush tabwriter and start new columns (the "type + // column" on a line with named fields may line up + // with the "trailing comment column" on a line with + // an anonymous field, leading to bad alignment) + p.print(formfeed); + } + } + + p.doc(f.Doc); + if hasNames { + p.identList(f.Names); + p.print(tab); + } + + if isInterface { + if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { + // methods + p.signature(ftyp.Params, ftyp.Results); + } else { + // embedded interface + p.expr(f.Type); + } + } else { + p.expr(f.Type); + if f.Tag != nil && !p.exportsOnly() { + p.print(tab); + p.expr(&ast.StringList{f.Tag}); + } + } + + needsSemi = true; + lastWasAnon = isAnon; + lastComment = f.Comment; + } + } + + if p.optSemis() { + p.print(token.SEMICOLON); + } + + p.comment(lastComment); + p.print(-1, newline); + } + + p.print(rbrace, token.RBRACE); + return true; // field list with {}'s +} + + +// ---------------------------------------------------------------------------- +// Expressions + +func (p *printer) stmt(s ast.Stmt) (optSemi bool) + +// Returns true if a separating semicolon is optional. +func (p *printer) expr1(expr ast.Expr, prec1 int) (optSemi bool) { + p.print(expr.Pos()); + + switch x := expr.(type) { + case *ast.BadExpr: + p.print("BadExpr"); + + case *ast.Ident: + p.print(x.Value); + + case *ast.BinaryExpr: + prec := x.Op.Precedence(); + if prec < prec1 { + p.print(token.LPAREN); + } + p.expr1(x.X, prec); + p.print(blank, x.OpPos, x.Op, blank); + p.expr1(x.Y, prec); + if prec < prec1 { + p.print(token.RPAREN); + } + + case *ast.KeyValueExpr: + p.expr(x.Key); + p.print(blank, x.Colon, token.COLON, blank); + p.expr(x.Value); + + case *ast.StarExpr: + p.print(token.MUL); + p.expr(x.X); + + case *ast.UnaryExpr: + prec := token.UnaryPrec; + if prec < prec1 { + p.print(token.LPAREN); + } + p.print(x.Op); + if x.Op == token.RANGE { + p.print(blank); + } + p.expr1(x.X, prec); + if prec < prec1 { + p.print(token.RPAREN); + } + + case *ast.IntLit: + p.print(x.Value); + + case *ast.FloatLit: + p.print(x.Value); + + case *ast.CharLit: + p.print(x.Value); + + case *ast.StringLit: + p.print(x.Value); + + case *ast.StringList: + for i, x := range x.Strings { + if i > 0 { + p.print(blank); + } + p.expr(x); + } + + case *ast.FuncLit: + p.level++; + p.expr(x.Type); + p.print(blank); + p.stmt(x.Body); + p.level--; + + case *ast.ParenExpr: + p.print(token.LPAREN); + p.expr(x.X); + p.print(x.Rparen, token.RPAREN); + + case *ast.SelectorExpr: + p.expr1(x.X, token.HighestPrec); + p.print(token.PERIOD); + p.expr1(x.Sel, token.HighestPrec); + + case *ast.TypeAssertExpr: + p.expr1(x.X, token.HighestPrec); + p.print(token.PERIOD, token.LPAREN); + p.expr(x.Type); + p.print(token.RPAREN); + + case *ast.IndexExpr: + p.expr1(x.X, token.HighestPrec); + p.print(token.LBRACK); + p.expr(x.Index); + if x.End != nil { + p.print(blank, token.COLON, blank); + p.expr(x.End); + } + p.print(token.RBRACK); + + case *ast.CallExpr: + p.expr1(x.Fun, token.HighestPrec); + p.print(x.Lparen, token.LPAREN); + p.exprList(x.Args); + p.print(x.Rparen, token.RPAREN); + + case *ast.CompositeLit: + p.expr1(x.Type, token.HighestPrec); + p.print(x.Lbrace, token.LBRACE); + p.exprList(x.Elts); + if p.mode & OptCommas != 0 { + p.print(token.COMMA); + } + p.print(x.Rbrace, token.RBRACE); + + case *ast.Ellipsis: + p.print(token.ELLIPSIS); + + case *ast.ArrayType: + p.print(token.LBRACK); + if x.Len != nil { + p.expr(x.Len); + } + p.print(token.RBRACK); + p.expr(x.Elt); + + case *ast.StructType: + p.print(token.STRUCT); + optSemi = p.fieldList(x.Lbrace, x.Fields, x.Rbrace, false); + + case *ast.FuncType: + p.print(token.FUNC); + p.signature(x.Params, x.Results); + + case *ast.InterfaceType: + p.print(token.INTERFACE); + optSemi = p.fieldList(x.Lbrace, x.Methods, x.Rbrace, true); + + case *ast.MapType: + p.print(token.MAP, blank, token.LBRACK); + p.expr(x.Key); + p.print(token.RBRACK); + p.expr(x.Value); + + case *ast.ChanType: + switch x.Dir { + case ast.SEND | ast.RECV: + p.print(token.CHAN); + case ast.RECV: + p.print(token.ARROW, token.CHAN); + case ast.SEND: + p.print(token.CHAN, blank, token.ARROW); + } + p.print(blank); + p.expr(x.Value); + + default: + panic("unreachable"); + } + + return optSemi; +} + + +// Returns true if a separating semicolon is optional. +func (p *printer) expr(x ast.Expr) bool { + return p.expr1(x, token.LowestPrec); +} + + +// ---------------------------------------------------------------------------- +// Statements + +func (p *printer) decl(decl ast.Decl) (optSemi bool) + +// Print the statement list indented, but without a newline after the last statement. +func (p *printer) stmtList(list []ast.Stmt) { + if len(list) > 0 { + p.print(+1, newline); + optSemi := false; + for i, s := range list { + if i > 0 { + if !optSemi || p.optSemis() { + // semicolon is required + p.print(token.SEMICOLON); + } + p.print(newline); + } + optSemi = p.stmt(s); + } + if p.optSemis() { + p.print(token.SEMICOLON); + } + p.print(-1); + } +} + + +func (p *printer) block(s *ast.BlockStmt) { + p.print(s.Pos(), token.LBRACE); + if len(s.List) > 0 { + p.stmtList(s.List); + p.print(newline); + } + p.print(s.Rbrace, token.RBRACE); +} + + +func (p *printer) switchBlock(s *ast.BlockStmt) { + p.print(s.Pos(), token.LBRACE); + if len(s.List) > 0 { + for i, s := range s.List { + // s is one of *ast.CaseClause, *ast.TypeCaseClause, *ast.CommClause; + p.print(newline); + p.stmt(s); + } + p.print(newline); + } + p.print(s.Rbrace, token.RBRACE); +} + + +func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) { + if init == nil && post == nil { + // no semicolons required + if expr != nil { + p.print(blank); + p.expr(expr); + } + } else { + // all semicolons required + // (they are not separators, print them explicitly) + p.print(blank); + if init != nil { + p.stmt(init); + } + p.print(token.SEMICOLON, blank); + if expr != nil { + p.expr(expr); + } + if isForStmt { + p.print(token.SEMICOLON, blank); + if post != nil { + p.stmt(post); + } + } + } +} + + +// Returns true if a separating semicolon is optional. +func (p *printer) stmt(stmt ast.Stmt) (optSemi bool) { + p.print(stmt.Pos()); + + switch s := stmt.(type) { + case *ast.BadStmt: + p.print("BadStmt"); + + case *ast.DeclStmt: + optSemi = p.decl(s.Decl); + + case *ast.EmptyStmt: + // nothing to do + + case *ast.LabeledStmt: + p.print(-1, newline); + p.expr(s.Label); + p.print(token.COLON, tab, +1); + optSemi = p.stmt(s.Stmt); + + case *ast.ExprStmt: + p.expr(s.X); + + case *ast.IncDecStmt: + p.expr(s.X); + p.print(s.Tok); + + case *ast.AssignStmt: + p.exprList(s.Lhs); + p.print(blank, s.TokPos, s.Tok, blank); + p.exprList(s.Rhs); + + case *ast.GoStmt: + p.print(token.GO, blank); + p.expr(s.Call); + + case *ast.DeferStmt: + p.print(token.DEFER, blank); + p.expr(s.Call); + + case *ast.ReturnStmt: + p.print(token.RETURN); + if s.Results != nil { + p.print(blank); + p.exprList(s.Results); + } + + case *ast.BranchStmt: + p.print(s.Tok); + if s.Label != nil { + p.print(blank); + p.expr(s.Label); + } + + case *ast.BlockStmt: + p.block(s); + optSemi = true; + + case *ast.IfStmt: + p.print(token.IF); + p.controlClause(false, s.Init, s.Cond, nil); + p.print(blank); + p.block(s.Body); + optSemi = true; + if s.Else != nil { + p.print(blank, token.ELSE, blank); + optSemi = p.stmt(s.Else); + } + + case *ast.CaseClause: + if s.Values != nil { + p.print(token.CASE, blank); + p.exprList(s.Values); + } else { + p.print(token.DEFAULT); + } + p.print(s.Colon, token.COLON); + p.stmtList(s.Body); + + case *ast.SwitchStmt: + p.print(token.SWITCH); + p.controlClause(false, s.Init, s.Tag, nil); + p.print(blank); + p.switchBlock(s.Body); + optSemi = true; + + case *ast.TypeCaseClause: + if s.Type != nil { + p.print(token.CASE, blank); + p.expr(s.Type); + } else { + p.print(token.DEFAULT); + } + p.print(s.Colon, token.COLON); + p.stmtList(s.Body); + + case *ast.TypeSwitchStmt: + p.print(token.SWITCH); + if s.Init != nil { + p.print(blank); + p.stmt(s.Init); + p.print(token.SEMICOLON); + } + p.print(blank); + p.stmt(s.Assign); + p.print(blank); + p.switchBlock(s.Body); + optSemi = true; + + case *ast.CommClause: + if s.Rhs != nil { + p.print(token.CASE, blank); + if s.Lhs != nil { + p.expr(s.Lhs); + p.print(blank, s.Tok, blank); + } + p.expr(s.Rhs); + } else { + p.print(token.DEFAULT); + } + p.print(s.Colon, token.COLON); + p.stmtList(s.Body); + + case *ast.SelectStmt: + p.print(token.SELECT, blank); + p.switchBlock(s.Body); + optSemi = true; + + case *ast.ForStmt: + p.print(token.FOR); + p.controlClause(true, s.Init, s.Cond, s.Post); + p.print(blank); + p.block(s.Body); + optSemi = true; + + case *ast.RangeStmt: + p.print(token.FOR, blank); + p.expr(s.Key); + if s.Value != nil { + p.print(token.COMMA, blank); + p.expr(s.Value); + } + p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank); + p.expr(s.X); + p.print(blank); + p.block(s.Body); + optSemi = true; + + default: + panic("unreachable"); + } + + return optSemi; +} + + +// ---------------------------------------------------------------------------- +// Declarations + +// Returns true if a separating semicolon is optional. +func (p *printer) spec(spec ast.Spec) (optSemi bool) { + switch s := spec.(type) { + case *ast.ImportSpec: + p.doc(s.Doc); + if s.Name != nil { + p.expr(s.Name); + } + // TODO fix for longer package names + p.print(tab, s.Path[0].Pos(), s.Path[0].Value); + + case *ast.ValueSpec: + p.doc(s.Doc); + p.identList(s.Names); + if s.Type != nil { + p.print(blank); // TODO switch to tab? (indent problem with structs) + p.expr(s.Type); + } + if s.Values != nil { + p.print(tab, token.ASSIGN, blank); + p.exprList(s.Values); + } + + case *ast.TypeSpec: + p.doc(s.Doc); + p.expr(s.Name); + p.print(blank); // TODO switch to tab? (but indent problem with structs) + optSemi = p.expr(s.Type); + + default: + panic("unreachable"); + } + + return optSemi; +} + + +// Returns true if a separating semicolon is optional. +func (p *printer) decl(decl ast.Decl) (optSemi bool) { + switch d := decl.(type) { + case *ast.BadDecl: + p.print(d.Pos(), "BadDecl"); + + case *ast.GenDecl: + p.doc(d.Doc); + p.print(d.Pos(), d.Tok, blank); + + if d.Lparen.IsValid() { + // group of parenthesized declarations + p.print(d.Lparen, token.LPAREN); + if p.isVisibleSpecList(d.Specs) { + p.print(+1, newline); + semi := false; + for _, s := range d.Specs { + if p.isVisibleSpec(s) { + if semi { + p.print(token.SEMICOLON, newline); + } + p.spec(s); + semi = true; + } + } + if p.optSemis() { + p.print(token.SEMICOLON); + } + p.print(-1, newline); + } + p.print(d.Rparen, token.RPAREN); + optSemi = true; + + } else { + // single declaration + optSemi = p.spec(d.Specs[0]); + } + + case *ast.FuncDecl: + p.level++; + p.doc(d.Doc); + p.print(d.Pos(), token.FUNC, blank); + if recv := d.Recv; recv != nil { + // method: print receiver + p.print(token.LPAREN); + if len(recv.Names) > 0 { + p.expr(recv.Names[0]); + p.print(blank); + } + p.expr(recv.Type); + p.print(token.RPAREN, blank); + } + p.expr(d.Name); + p.signature(d.Type.Params, d.Type.Results); + if !p.exportsOnly() && d.Body != nil { + p.print(blank); + p.stmt(d.Body); + } + p.level--; + + default: + panic("unreachable"); + } + + return optSemi; +} + + +// ---------------------------------------------------------------------------- +// Programs + +func (p *printer) program(prog *ast.Program) { + // set unassociated comments if all code is printed + if !p.exportsOnly() { + // TODO enable this once comments are properly interspersed + //p.setComments(prog.Comments); + } + + p.doc(prog.Doc); + p.print(prog.Pos(), token.PACKAGE, blank); + p.expr(prog.Name); + + for _, d := range prog.Decls { + if p.isVisibleDecl(d) { + p.print(newline, newline); + p.decl(d); + if p.optSemis() { + p.print(token.SEMICOLON); + } + } + } +} + + +// ---------------------------------------------------------------------------- +// Public interface + +// Fprint "pretty-prints" an AST node to output and returns the number of +// bytes written, and an error, if any. The node type must be *ast.Program, +// or assignment-compatible to ast.Expr, ast.Decl, or ast.Stmt. Printing is +// controlled by the mode parameter. For best results, the output should be +// a tabwriter.Writer. +// +func Fprint(output io.Writer, node interface{}, mode uint) (int, os.Error) { + var p printer; + p.init(output, mode); + + go func() { + switch n := node.(type) { + case ast.Expr: + p.expr(n); + case ast.Stmt: + p.stmt(n); + case ast.Decl: + p.decl(n); + case *ast.Program: + p.program(n); + default: + p.errors <- os.NewError("unsupported node type"); + } + p.print(newline); + p.errors <- nil; // no errors + }(); + err := <-p.errors; // wait for completion of goroutine + + return p.written, err; +} diff --git a/usr/gri/pretty/Makefile b/usr/gri/pretty/Makefile index 96f1184b95..3171a087a5 100644 --- a/usr/gri/pretty/Makefile +++ b/usr/gri/pretty/Makefile @@ -4,34 +4,26 @@ include $(GOROOT)/src/Make.$(GOARCH) -all: untab godoc pretty - -untab: untab.$O - $(LD) -o untab untab.$O +all: godoc gofmt godoc: godoc.$O $(LD) -o godoc godoc.$O -pretty: pretty.$O - $(LD) -o pretty pretty.$O +gofmt: gofmt.$O + $(LD) -o gofmt gofmt.$O -test: pretty +test: gofmt ./test.sh -smoketest: pretty - ./test.sh astprinter.go +smoketest: gofmt + ./test.sh $(GOROOT)/src/pkg/go/printer/printer.go install: pretty godoc untab cp godoc $(HOME)/bin/godoc - cp pretty $(HOME)/bin/pretty - cp untab $(HOME)/bin/untab + cp gofmt $(HOME)/bin/gofmt clean: - rm -f pretty untab godoc *.$O *.a 6.out *~ - -godoc.$O: astprinter.$O - -pretty.$O: astprinter.$O + rm -f godoc gofmt *.$O *.a 6.out *~ %.$O: %.go $(GC) $(F) $< diff --git a/usr/gri/pretty/astprinter.go b/usr/gri/pretty/astprinter.go deleted file mode 100644 index 867a84034b..0000000000 --- a/usr/gri/pretty/astprinter.go +++ /dev/null @@ -1,1269 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package astPrinter - -import ( - "flag"; - "fmt"; - "go/ast"; - "go/token"; - "io"; - "os"; -) - - -var ( - debug = flag.Bool("ast_debug", false, "print debugging information"); - - // layout control - newlines = flag.Bool("ast_newlines", false, "respect newlines in source"); - maxnewlines = flag.Int("ast_maxnewlines", 3, "max. number of consecutive newlines"); - - // formatting control - optsemicolons = flag.Bool("ast_optsemicolons", false, "print optional semicolons"); -) - - -// When we don't have a position use noPos. -var noPos token.Position; - - -// ---------------------------------------------------------------------------- -// Elementary support - -func unimplemented() { - panic("unimplemented"); -} - - -func unreachable() { - panic("unreachable"); -} - - -func assert(pred bool) { - if !pred { - panic("assertion failed"); - } -} - - -func hasExportedNames(names []*ast.Ident) bool { - for i, name := range names { - if name.IsExported() { - return true; - } - } - return false; -} - - -// ---------------------------------------------------------------------------- -// TokenPrinter - -// TODO This is not yet used - should fix this. - -// An implementation of a TokenPrinter may be provided when -// initializing an AST Printer. It is used to print tokens. -// -type TokenPrinter interface { - PrintLit(w io.Writer, tok token.Token, value []byte); - PrintIdent(w io.Writer, value string); - PrintToken(w io.Writer, token token.Token); - PrintComment(w io.Writer, value []byte); -} - - -type defaultPrinter struct {} - -func (p defaultPrinter) PrintLit(w io.Writer, tok token.Token, value []byte) { - w.Write(value); -} - - -func (p defaultPrinter) PrintIdent(w io.Writer, value string) { - fmt.Fprint(w, value); -} - - -func (p defaultPrinter) PrintToken(w io.Writer, token token.Token) { - fmt.Fprint(w, token.String()); -} - - -func (p defaultPrinter) PrintComment(w io.Writer, value []byte) { - w.Write(value); -} - - -// ---------------------------------------------------------------------------- -// ASTPrinter - - -// Separators - printed in a delayed fashion, depending on context. -const ( - none = iota; - blank; - tab; - comma; - semicolon; -) - - -// Semantic states - control formatting. -const ( - normal = iota; - opening_scope; // controls indentation, scope level - closing_scope; // controls indentation, scope level - inside_list; // controls extra line breaks -) - - -type Printer struct { - // output - text io.Writer; - - // token printing - tprinter TokenPrinter; - - // formatting control - html bool; - full bool; // if false, print interface only; print all otherwise - - // comments - comments []*ast.Comment; // the list of unassociated comments - cindex int; // the current comment index - cpos token.Position; // the position of the next comment - - // current state - lastpos token.Position; // position after last string - level int; // scope level - indentation int; // indentation level (may be different from scope level) - - // formatting parameters - opt_semi bool; // // true if semicolon separator is optional in statement list - separator int; // pending separator - newlines int; // pending newlines - - // semantic state - state int; // current semantic state - laststate int; // state for last string - - // expression precedence - prec int; -} - - -func (P *Printer) hasComment(pos token.Position) bool { - return P.cpos.Offset < pos.Offset; -} - - -func (P *Printer) nextComments() { - P.cindex++; - if P.comments != nil && P.cindex < len(P.comments) && P.comments[P.cindex] != nil { - P.cpos = P.comments[P.cindex].Pos(); - } else { - P.cpos = token.Position{1<<30, 1<<30, 1}; // infinite - } -} - - -func (P *Printer) Init(text io.Writer, tprinter TokenPrinter, comments []*ast.Comment, html bool) { - // writers - P.text = text; - - // token printing - if tprinter != nil { - P.tprinter = tprinter; - } else { - P.tprinter = defaultPrinter{}; - } - - // formatting control - P.html = html; - - // comments - P.comments = comments; - P.cindex = -1; - P.nextComments(); - - // formatting parameters & semantic state initialized correctly by default - - // expression precedence - P.prec = token.LowestPrec; -} - - -// ---------------------------------------------------------------------------- -// Printing support - -func (P *Printer) htmlEscape(s string) string { - if P.html { - var esc string; - for i := 0; i < len(s); i++ { - switch s[i] { - case '<': esc = "<"; - case '&': esc = "&"; - default: continue; - } - return s[0 : i] + esc + P.htmlEscape(s[i+1 : len(s)]); - } - } - return s; -} - - -// Reduce contiguous sequences of '\t' in a string to a single '\t'. -func untabify(s string) string { - for i := 0; i < len(s); i++ { - if s[i] == '\t' { - j := i; - for j < len(s) && s[j] == '\t' { - j++; - } - if j-i > 1 { // more then one tab - return s[0 : i+1] + untabify(s[j : len(s)]); - } - } - } - return s; -} - - -func (P *Printer) Printf(format string, s ...) { - n, err := fmt.Fprintf(P.text, format, s); - if err != nil { - panic("print error - exiting"); - } -} - - -func (P *Printer) newline(n int) { - if n > 0 { - m := int(*maxnewlines); - if n > m { - n = m; - } - for n > 0 { - P.Printf("\n"); - n--; - } - for i := P.indentation; i > 0; i-- { - P.Printf("\t"); - } - } -} - - -func (P *Printer) TaggedString(pos token.Position, tag, s, endtag string) { - // use estimate for pos if we don't have one - offs := pos.Offset; - if pos.Line == 0 { - offs = P.lastpos.Offset; - } - - // -------------------------------- - // print pending separator, if any - // - keep track of white space printed for better comment formatting - // TODO print white space separators after potential comments and newlines - // (currently, we may get trailing white space before a newline) - trailing_char := 0; - switch P.separator { - case none: // nothing to do - case blank: - P.Printf(" "); - trailing_char = ' '; - case tab: - P.Printf("\t"); - trailing_char = '\t'; - case comma: - P.Printf(","); - if P.newlines == 0 { - P.Printf(" "); - trailing_char = ' '; - } - case semicolon: - if P.level > 0 { // no semicolons at level 0 - P.Printf(";"); - if P.newlines == 0 { - P.Printf(" "); - trailing_char = ' '; - } - } - default: panic("UNREACHABLE"); - } - P.separator = none; - - // -------------------------------- - // interleave comments, if any - nlcount := 0; - if P.full { - for ; P.hasComment(pos); P.nextComments() { - // we have a comment that comes before the string - comment := P.comments[P.cindex]; - ctext := string(comment.Text); // TODO get rid of string conversion here - - // classify comment (len(ctext) >= 2) - //-style comment - if nlcount > 0 || P.cpos.Offset == 0 { - // only white space before comment on this line - // or file starts with comment - // - indent - if !*newlines && P.cpos.Offset != 0 { - nlcount = 1; - } - P.newline(nlcount); - nlcount = 0; - - } else { - // black space before comment on this line - if ctext[1] == '/' { - //-style comment - // - put in next cell unless a scope was just opened - // in which case we print 2 blanks (otherwise the - // entire scope gets indented like the next cell) - if P.laststate == opening_scope { - switch trailing_char { - case ' ': P.Printf(" "); // one space already printed - case '\t': // do nothing - default: P.Printf(" "); - } - } else { - if trailing_char != '\t' { - P.Printf("\t"); - } - } - } else { - /*-style comment */ - // - print surrounded by blanks - if trailing_char == 0 { - P.Printf(" "); - } - ctext += " "; - } - } - - // print comment - if *debug { - P.Printf("[%d]", P.cpos.Offset); - } - // calling untabify increases the change for idempotent output - // since tabs in comments are also interpreted by tabwriter - P.Printf("%s", P.htmlEscape(untabify(ctext))); - } - // At this point we may have nlcount > 0: In this case we found newlines - // that were not followed by a comment. They are recognized (or not) when - // printing newlines below. - } - - // -------------------------------- - // interpret state - // (any pending separator or comment must be printed in previous state) - switch P.state { - case normal: - case opening_scope: - case closing_scope: - P.indentation--; - case inside_list: - default: - panic("UNREACHABLE"); - } - - // -------------------------------- - // print pending newlines - if *newlines && (P.newlines > 0 || P.state == inside_list) && nlcount > P.newlines { - // Respect additional newlines in the source, but only if we - // enabled this feature (newlines.BVal()) and we are expecting - // newlines (P.newlines > 0 || P.state == inside_list). - // Otherwise - because we don't have all token positions - we - // get funny formatting. - P.newlines = nlcount; - } - nlcount = 0; - P.newline(P.newlines); - P.newlines = 0; - - // -------------------------------- - // print string - if *debug { - P.Printf("[%d]", pos); - } - P.Printf("%s%s%s", tag, P.htmlEscape(s), endtag); - - // -------------------------------- - // interpret state - switch P.state { - case normal: - case opening_scope: - P.level++; - P.indentation++; - case closing_scope: - P.level--; - case inside_list: - default: - panic("UNREACHABLE"); - } - P.laststate = P.state; - P.state = none; - - // -------------------------------- - // done - P.opt_semi = false; - pos.Offset += len(s); // rough estimate - pos.Column += len(s); // rough estimate - P.lastpos = pos; -} - - -func (P *Printer) String(pos token.Position, s string) { - P.TaggedString(pos, "", s, ""); -} - - -func (P *Printer) Token(pos token.Position, tok token.Token) { - P.String(pos, tok.String()); - //P.TaggedString(pos, "", tok.String(), ""); -} - - -func (P *Printer) Error(pos token.Position, tok token.Token, msg string) { - fmt.Printf("\ninternal printing error: pos = %d, tok = %s, %s\n", pos.Offset, tok.String(), msg); - panic(); -} - - -// An astPrinter implements io.Writer. -// TODO this is not yet used. -func (P *Printer) Write(p []byte) (n int, err os.Error) { - // TODO - // - no string conversion every time - // - return proper results - P.String(noPos, string(p)); - return len(p), nil; -} - - -// ---------------------------------------------------------------------------- -// HTML support - -func (P *Printer) HtmlIdentifier(x *ast.Ident) { - P.String(x.Pos(), x.Value); - /* - obj := x.Obj; - if P.html && obj.Kind != symbolTable.NONE { - // depending on whether we have a declaration or use, generate different html - // - no need to htmlEscape ident - id := utils.IntToString(obj.Id, 10); - if x.Loc_ == obj.Pos { - // probably the declaration of x - P.TaggedString(x.Loc_, ``, obj.Ident, ``); - } else { - // probably not the declaration of x - P.TaggedString(x.Loc_, ``, obj.Ident, ``); - } - } else { - P.String(x.Loc_, obj.Ident); - } - */ -} - - -func (P *Printer) HtmlPackageName(pos token.Position, name string) { - if P.html { - sname := name[1 : len(name)-1]; // strip quotes TODO do this elsewhere eventually - // TODO CAPITAL HACK BELOW FIX THIS - P.TaggedString(pos, `"`, sname, `"`); - } else { - P.String(pos, name); - } -} - - -// ---------------------------------------------------------------------------- -// Support - -func (P *Printer) Expr(x ast.Expr) - -func (P *Printer) Idents(list []*ast.Ident, full bool) int { - n := 0; - for i, x := range list { - if n > 0 { - P.Token(noPos, token.COMMA); - P.separator = blank; - P.state = inside_list; - } - if full || x.IsExported() { - P.Expr(x); - n++; - } - } - return n; -} - - -func (P *Printer) Exprs(list []ast.Expr) { - for i, x := range list { - if i > 0 { - P.Token(noPos, token.COMMA); - P.separator = blank; - P.state = inside_list; - } - P.Expr(x); - } -} - - -func (P *Printer) Parameters(list []*ast.Field) { - P.Token(noPos, token.LPAREN); - if len(list) > 0 { - for i, par := range list { - if i > 0 { - P.separator = comma; - } - n := P.Idents(par.Names, true); - if n > 0 { - P.separator = blank - }; - P.Expr(par.Type); - } - } - P.Token(noPos, token.RPAREN); -} - - -// Returns the separator (semicolon or none) required if -// the type is terminating a declaration or statement. -func (P *Printer) Signature(params, result []*ast.Field) { - P.Parameters(params); - if result != nil { - P.separator = blank; - - if len(result) == 1 && result[0].Names == nil { - // single anonymous result - // => no parentheses needed unless it's a function type - fld := result[0]; - if dummy, is_ftyp := fld.Type.(*ast.FuncType); !is_ftyp { - P.Expr(fld.Type); - return; - } - } - - P.Parameters(result); - } -} - - -func (P *Printer) Fields(lbrace token.Position, list []*ast.Field, rbrace token.Position, is_interface bool) { - P.state = opening_scope; - P.separator = blank; - P.Token(lbrace, token.LBRACE); - - if len(list) > 0 { - P.newlines = 1; - for i, fld := range list { - if i > 0 { - P.separator = semicolon; - P.newlines = 1; - } - n := P.Idents(fld.Names, P.full); - if n > 0 { - // at least one identifier - P.separator = tab - }; - if n > 0 || len(fld.Names) == 0 { - // at least one identifier or anonymous field - if is_interface { - if ftyp, is_ftyp := fld.Type.(*ast.FuncType); is_ftyp { - P.Signature(ftyp.Params, ftyp.Results); - } else { - P.Expr(fld.Type); - } - } else { - P.Expr(fld.Type); - if fld.Tag != nil { - P.separator = tab; - P.Expr(&ast.StringList{fld.Tag}); - } - } - } - } - P.newlines = 1; - } - - P.state = closing_scope; - P.Token(rbrace, token.RBRACE); - P.opt_semi = true; -} - - -// ---------------------------------------------------------------------------- -// Expressions - -func (P *Printer) Expr1(x ast.Expr, prec1 int) -func (P *Printer) Stmt(s ast.Stmt) - - -func (P *Printer) DoBadExpr(x *ast.BadExpr) { - P.String(noPos, "BadExpr"); -} - - -func (P *Printer) DoIdent(x *ast.Ident) { - P.HtmlIdentifier(x); -} - - -func (P *Printer) DoBinaryExpr(x *ast.BinaryExpr) { - prec := x.Op.Precedence(); - if prec < P.prec { - P.Token(noPos, token.LPAREN); - } - P.Expr1(x.X, prec); - P.separator = blank; - P.Token(x.OpPos, x.Op); - P.separator = blank; - P.Expr1(x.Y, prec); - if prec < P.prec { - P.Token(noPos, token.RPAREN); - } -} - - -func (P *Printer) DoKeyValueExpr(x *ast.KeyValueExpr) { - P.Expr(x.Key); - P.separator = blank; - P.Token(x.Colon, token.COLON); - P.separator = blank; - P.Expr(x.Value); -} - - -func (P *Printer) DoStarExpr(x *ast.StarExpr) { - P.Token(x.Pos(), token.MUL); - P.Expr(x.X); -} - - -func (P *Printer) DoUnaryExpr(x *ast.UnaryExpr) { - prec := token.UnaryPrec; - if prec < P.prec { - P.Token(noPos, token.LPAREN); - } - P.Token(x.Pos(), x.Op); - if x.Op == token.RANGE { - P.separator = blank; - } - P.Expr1(x.X, prec); - if prec < P.prec { - P.Token(noPos, token.RPAREN); - } -} - - -func (P *Printer) DoIntLit(x *ast.IntLit) { - // TODO get rid of string conversion here - P.String(x.Pos(), string(x.Value)); -} - - -func (P *Printer) DoFloatLit(x *ast.FloatLit) { - // TODO get rid of string conversion here - P.String(x.Pos(), string(x.Value)); -} - - -func (P *Printer) DoCharLit(x *ast.CharLit) { - // TODO get rid of string conversion here - P.String(x.Pos(), string(x.Value)); -} - - -func (P *Printer) DoStringLit(x *ast.StringLit) { - // TODO get rid of string conversion here - P.String(x.Pos(), string(x.Value)); -} - - -func (P *Printer) DoStringList(x *ast.StringList) { - for i, x := range x.Strings { - if i > 0 { - P.separator = blank; - } - P.DoStringLit(x); - } -} - - -func (P *Printer) DoFuncType(x *ast.FuncType) - -func (P *Printer) DoFuncLit(x *ast.FuncLit) { - P.DoFuncType(x.Type); - P.separator = blank; - P.Stmt(x.Body); - P.opt_semi = false; // BUG 6g or spec - P.newlines = 0; -} - - -func (P *Printer) DoParenExpr(x *ast.ParenExpr) { - P.Token(x.Pos(), token.LPAREN); - P.Expr(x.X); - P.Token(x.Rparen, token.RPAREN); -} - - -func (P *Printer) DoSelectorExpr(x *ast.SelectorExpr) { - P.Expr1(x.X, token.HighestPrec); - P.Token(noPos, token.PERIOD); - P.Expr1(x.Sel, token.HighestPrec); -} - - -func (P *Printer) DoTypeAssertExpr(x *ast.TypeAssertExpr) { - P.Expr1(x.X, token.HighestPrec); - P.Token(noPos, token.PERIOD); - P.Token(noPos, token.LPAREN); - P.Expr(x.Type); - P.Token(noPos, token.RPAREN); -} - - -func (P *Printer) DoIndexExpr(x *ast.IndexExpr) { - P.Expr1(x.X, token.HighestPrec); - P.Token(noPos, token.LBRACK); - P.Expr(x.Index); - if x.End != nil { - P.Token(noPos, token.COLON); - P.Expr(x.End); - } - P.Token(noPos, token.RBRACK); -} - - -func (P *Printer) DoCallExpr(x *ast.CallExpr) { - P.Expr1(x.Fun, token.HighestPrec); - P.Token(x.Lparen, token.LPAREN); - P.Exprs(x.Args); - P.Token(x.Rparen, token.RPAREN); -} - - -func (P *Printer) DoCompositeLit(x *ast.CompositeLit) { - P.Expr1(x.Type, token.HighestPrec); - P.Token(x.Lbrace, token.LBRACE); - P.Exprs(x.Elts); - P.Token(x.Rbrace, token.RBRACE); -} - - -func (P *Printer) DoEllipsis(x *ast.Ellipsis) { - P.Token(x.Pos(), token.ELLIPSIS); -} - - -func (P *Printer) DoArrayType(x *ast.ArrayType) { - P.Token(x.Pos(), token.LBRACK); - if x.Len != nil { - P.Expr(x.Len); - } - P.Token(noPos, token.RBRACK); - P.Expr(x.Elt); -} - - -func (P *Printer) DoStructType(x *ast.StructType) { - P.Token(x.Pos(), token.STRUCT); - if x.Fields != nil { - P.Fields(x.Lbrace, x.Fields, x.Rbrace, false); - } -} - - -func (P *Printer) DoFuncType(x *ast.FuncType) { - P.Token(x.Pos(), token.FUNC); - P.Signature(x.Params, x.Results); -} - - -func (P *Printer) DoInterfaceType(x *ast.InterfaceType) { - P.Token(x.Pos(), token.INTERFACE); - if x.Methods != nil { - P.Fields(x.Lbrace, x.Methods, x.Rbrace, true); - } -} - - -func (P *Printer) DoMapType(x *ast.MapType) { - P.Token(x.Pos(), token.MAP); - P.separator = blank; - P.Token(noPos, token.LBRACK); - P.Expr(x.Key); - P.Token(noPos, token.RBRACK); - P.Expr(x.Value); -} - - -func (P *Printer) DoChanType(x *ast.ChanType) { - switch x.Dir { - case ast.SEND | ast.RECV: - P.Token(x.Pos(), token.CHAN); - case ast.RECV: - P.Token(x.Pos(), token.ARROW); - P.Token(noPos, token.CHAN); - case ast.SEND: - P.Token(x.Pos(), token.CHAN); - P.separator = blank; - P.Token(noPos, token.ARROW); - } - P.separator = blank; - P.Expr(x.Value); -} - - -func (P *Printer) Expr1(x ast.Expr, prec1 int) { - if x == nil { - return; // empty expression list - } - - saved_prec := P.prec; - P.prec = prec1; - x.Visit(P); - P.prec = saved_prec; -} - - -func (P *Printer) Expr(x ast.Expr) { - P.Expr1(x, token.LowestPrec); -} - - -// ---------------------------------------------------------------------------- -// Statements - -func (P *Printer) Stmt(s ast.Stmt) { - s.Visit(P); -} - - -func (P *Printer) DoBadStmt(s *ast.BadStmt) { - panic(); -} - - -func (P *Printer) Decl(d ast.Decl); - -func (P *Printer) DoDeclStmt(s *ast.DeclStmt) { - P.Decl(s.Decl); -} - - -func (P *Printer) DoEmptyStmt(s *ast.EmptyStmt) { - P.String(s.Pos(), ""); -} - - -func (P *Printer) DoLabeledStmt(s *ast.LabeledStmt) { - P.indentation--; - P.Expr(s.Label); - P.Token(noPos, token.COLON); - P.indentation++; - // TODO be more clever if s.Stmt is a labeled stat as well - P.separator = tab; - P.Stmt(s.Stmt); -} - - -func (P *Printer) DoExprStmt(s *ast.ExprStmt) { - P.Expr(s.X); -} - - -func (P *Printer) DoIncDecStmt(s *ast.IncDecStmt) { - P.Expr(s.X); - P.Token(noPos, s.Tok); -} - - -func (P *Printer) DoAssignStmt(s *ast.AssignStmt) { - P.Exprs(s.Lhs); - P.separator = blank; - P.Token(s.TokPos, s.Tok); - P.separator = blank; - P.Exprs(s.Rhs); -} - - -func (P *Printer) DoGoStmt(s *ast.GoStmt) { - P.Token(s.Pos(), token.GO); - P.separator = blank; - P.Expr(s.Call); -} - - -func (P *Printer) DoDeferStmt(s *ast.DeferStmt) { - P.Token(s.Pos(), token.DEFER); - P.separator = blank; - P.Expr(s.Call); -} - - -func (P *Printer) DoReturnStmt(s *ast.ReturnStmt) { - P.Token(s.Pos(), token.RETURN); - P.separator = blank; - P.Exprs(s.Results); -} - - -func (P *Printer) DoBranchStmt(s *ast.BranchStmt) { - P.Token(s.Pos(), s.Tok); - if s.Label != nil { - P.separator = blank; - P.Expr(s.Label); - } -} - - -func (P *Printer) StatementList(list []ast.Stmt) { - if list != nil { - for i, s := range list { - if i == 0 { - P.newlines = 1; - } else { // i > 0 - if !P.opt_semi || *optsemicolons { - // semicolon is required - P.separator = semicolon; - } - } - P.Stmt(s); - P.newlines = 1; - P.state = inside_list; - } - } -} - - -/* -func (P *Printer) Block(list []ast.Stmt, indent bool) { - P.state = opening_scope; - P.Token(b.Pos_, b.Tok); - if !indent { - P.indentation--; - } - P.StatementList(b.List); - if !indent { - P.indentation++; - } - if !*optsemicolons { - P.separator = none; - } - P.state = closing_scope; - if b.Tok == token.LBRACE { - P.Token(b.Rbrace, token.RBRACE); - P.opt_semi = true; - } else { - P.String(noPos, ""); // process closing_scope state transition! - } -} -*/ - - -func (P *Printer) DoBlockStmt(s *ast.BlockStmt) { - P.state = opening_scope; - P.Token(s.Pos(), token.LBRACE); - P.StatementList(s.List); - if !*optsemicolons { - P.separator = none; - } - P.state = closing_scope; - P.Token(s.Rbrace, token.RBRACE); - P.opt_semi = true; -} - - -func (P *Printer) ControlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) { - P.separator = blank; - if init == nil && post == nil { - // no semicolons required - if expr != nil { - P.Expr(expr); - } - } else { - // all semicolons required - // (they are not separators, print them explicitly) - if init != nil { - P.Stmt(init); - P.separator = none; - } - P.Token(noPos, token.SEMICOLON); - P.separator = blank; - if expr != nil { - P.Expr(expr); - P.separator = none; - } - if isForStmt { - P.Token(noPos, token.SEMICOLON); - P.separator = blank; - if post != nil { - P.Stmt(post); - } - } - } - P.separator = blank; -} - - -func (P *Printer) DoIfStmt(s *ast.IfStmt) { - P.Token(s.Pos(), token.IF); - P.ControlClause(false, s.Init, s.Cond, nil); - P.Stmt(s.Body); - if s.Else != nil { - P.separator = blank; - P.Token(noPos, token.ELSE); - P.separator = blank; - P.Stmt(s.Else); - } -} - - -func (P *Printer) DoCaseClause(s *ast.CaseClause) { - if s.Values != nil { - P.Token(s.Pos(), token.CASE); - P.separator = blank; - P.Exprs(s.Values); - } else { - P.Token(s.Pos(), token.DEFAULT); - } - P.Token(s.Colon, token.COLON); - P.indentation++; - P.StatementList(s.Body); - P.indentation--; - P.newlines = 1; -} - - -func (P *Printer) DoSwitchStmt(s *ast.SwitchStmt) { - P.Token(s.Pos(), token.SWITCH); - P.ControlClause(false, s.Init, s.Tag, nil); - P.Stmt(s.Body); -} - - -func (P *Printer) DoTypeCaseClause(s *ast.TypeCaseClause) { - if s.Type != nil { - P.Token(s.Pos(), token.CASE); - P.separator = blank; - P.Expr(s.Type); - } else { - P.Token(s.Pos(), token.DEFAULT); - } - P.Token(s.Colon, token.COLON); - P.indentation++; - P.StatementList(s.Body); - P.indentation--; - P.newlines = 1; -} - - -func (P *Printer) DoTypeSwitchStmt(s *ast.TypeSwitchStmt) { - P.Token(s.Pos(), token.SWITCH); - P.separator = blank; - if s.Init != nil { - P.Stmt(s.Init); - P.separator = none; - P.Token(noPos, token.SEMICOLON); - } - P.separator = blank; - P.Stmt(s.Assign); - P.separator = blank; - P.Stmt(s.Body); -} - - -func (P *Printer) DoCommClause(s *ast.CommClause) { - if s.Rhs != nil { - P.Token(s.Pos(), token.CASE); - P.separator = blank; - if s.Lhs != nil { - P.Expr(s.Lhs); - P.separator = blank; - P.Token(noPos, s.Tok); - P.separator = blank; - } - P.Expr(s.Rhs); - } else { - P.Token(s.Pos(), token.DEFAULT); - } - P.Token(s.Colon, token.COLON); - P.indentation++; - P.StatementList(s.Body); - P.indentation--; - P.newlines = 1; -} - - -func (P *Printer) DoSelectStmt(s *ast.SelectStmt) { - P.Token(s.Pos(), token.SELECT); - P.separator = blank; - P.Stmt(s.Body); -} - - -func (P *Printer) DoForStmt(s *ast.ForStmt) { - P.Token(s.Pos(), token.FOR); - P.ControlClause(true, s.Init, s.Cond, s.Post); - P.Stmt(s.Body); -} - - -func (P *Printer) DoRangeStmt(s *ast.RangeStmt) { - P.Token(s.Pos(), token.FOR); - P.separator = blank; - P.Expr(s.Key); - if s.Value != nil { - P.Token(noPos, token.COMMA); - P.separator = blank; - P.state = inside_list; - P.Expr(s.Value); - } - P.separator = blank; - P.Token(s.TokPos, s.Tok); - P.separator = blank; - P.Token(noPos, token.RANGE); - P.separator = blank; - P.Expr(s.X); - P.separator = blank; - P.Stmt(s.Body); -} - - -// ---------------------------------------------------------------------------- -// Declarations - -func (P *Printer) DoBadDecl(d *ast.BadDecl) { - P.String(d.Pos(), ""); -} - - -func (P *Printer) importSpec(d *ast.ImportSpec) { - if d.Name != nil { - P.Expr(d.Name); - } else { - P.String(d.Path[0].Pos(), ""); // flush pending ';' separator/newlines - } - P.separator = tab; - // TODO fix for longer package names - P.HtmlPackageName(d.Path[0].Pos(), string(d.Path[0].Value)); - P.newlines = 2; -} - - -func (P *Printer) valueSpec(d *ast.ValueSpec) { - P.Idents(d.Names, P.full); - if d.Type != nil { - P.separator = blank; // TODO switch to tab? (indentation problem with structs) - P.Expr(d.Type); - } - if d.Values != nil { - P.separator = tab; - P.Token(noPos, token.ASSIGN); - P.separator = blank; - P.Exprs(d.Values); - } - P.newlines = 2; -} - - -func (P *Printer) typeSpec(d *ast.TypeSpec) { - P.Expr(d.Name); - P.separator = blank; // TODO switch to tab? (but indentation problem with structs) - P.Expr(d.Type); - P.newlines = 2; -} - - -func (P *Printer) spec(d ast.Spec) { - switch s := d.(type) { - case *ast.ImportSpec: P.importSpec(s); - case *ast.ValueSpec: P.valueSpec(s); - case *ast.TypeSpec: P.typeSpec(s); - default: panic("unreachable"); - } -} - - -func (P *Printer) DoGenDecl(d *ast.GenDecl) { - P.Token(d.Pos(), d.Tok); - P.separator = blank; - - if d.Lparen.Line > 0 { - // group of parenthesized declarations - P.state = opening_scope; - P.Token(d.Lparen, token.LPAREN); - if len(d.Specs) > 0 { - P.newlines = 1; - for i := 0; i < len(d.Specs); i++ { - if i > 0 { - P.separator = semicolon; - } - P.spec(d.Specs[i]); - P.newlines = 1; - } - } - P.state = closing_scope; - P.Token(d.Rparen, token.RPAREN); - P.opt_semi = true; - P.newlines = 2; - - } else { - // single declaration - P.spec(d.Specs[0]); - } -} - - -func (P *Printer) DoFuncDecl(d *ast.FuncDecl) { - P.Token(d.Pos(), token.FUNC); - P.separator = blank; - if recv := d.Recv; recv != nil { - // method: print receiver - P.Token(noPos, token.LPAREN); - if len(recv.Names) > 0 { - P.Expr(recv.Names[0]); - P.separator = blank; - } - P.Expr(recv.Type); - P.Token(noPos, token.RPAREN); - P.separator = blank; - } - P.Expr(d.Name); - P.Signature(d.Type.Params, d.Type.Results); - if P.full && d.Body != nil { - P.separator = blank; - P.Stmt(d.Body); - } - P.newlines = 3; -} - - -func (P *Printer) Decl(d ast.Decl) { - d.Visit(P); -} - - -// ---------------------------------------------------------------------------- -// Program - -func (P *Printer) DoProgram(p *ast.Program) { - P.full = true; - P.Token(p.Pos(), token.PACKAGE); - P.separator = blank; - P.Expr(p.Name); - P.newlines = 1; - for i := 0; i < len(p.Decls); i++ { - P.Decl(p.Decls[i]); - } - P.newlines = 1; -} diff --git a/usr/gri/pretty/godoc.go b/usr/gri/pretty/godoc.go index f2d66079a4..c4bc6d7e21 100644 --- a/usr/gri/pretty/godoc.go +++ b/usr/gri/pretty/godoc.go @@ -33,6 +33,7 @@ import ( "go/ast"; "go/doc"; "go/parser"; + "go/printer"; "go/token"; "http"; "io"; @@ -47,8 +48,6 @@ import ( "tabwriter"; "template"; "time"; - - "astprinter"; // TODO remove eventually in favor of ast.Fprint ) @@ -90,7 +89,6 @@ var ( // layout control tabwidth = flag.Int("tabwidth", 4, "tab width"); - usetabs = flag.Bool("tabs", false, "align with tabs instead of spaces"); html = flag.Bool("html", false, "print HTML in command-line mode"); // server control @@ -129,11 +127,7 @@ func isPkgDir(dir *os.Dir) bool { func makeTabwriter(writer io.Writer) *tabwriter.Writer { - padchar := byte(' '); - if *usetabs { - padchar = '\t'; - } - return tabwriter.NewWriter(writer, *tabwidth, 1, padchar, tabwriter.FilterHTML); + return tabwriter.NewWriter(writer, *tabwidth, 1, byte(' '), 0); } @@ -203,22 +197,12 @@ func parse(path string, mode uint) (*ast.Program, *parseErrors) { // ---------------------------------------------------------------------------- // Templates -// Return text for decl. -func DeclText(d ast.Decl) []byte { - var buf io.ByteBuffer; - var p astPrinter.Printer; - p.Init(&buf, nil, nil, false); - d.Visit(&p); - return buf.Data(); -} - - -// Return text for expr. -func ExprText(d ast.Expr) []byte { +// Return text for an AST node. +func nodeText(node interface{}, mode uint) []byte { var buf io.ByteBuffer; - var p astPrinter.Printer; - p.Init(&buf, nil, nil, false); - d.Visit(&p); + tw := makeTabwriter(&buf); + printer.Fprint(tw, node, mode); + tw.Flush(); return buf.Data(); } @@ -235,9 +219,9 @@ func toText(x interface{}) []byte { case String: return io.StringBytes(v.String()); case ast.Decl: - return DeclText(v); + return nodeText(v, printer.ExportsOnly); case ast.Expr: - return ExprText(v); + return nodeText(v, printer.ExportsOnly); } var buf io.ByteBuffer; fmt.Fprint(&buf, x); @@ -247,23 +231,7 @@ func toText(x interface{}) []byte { // Template formatter for "html" format. func htmlFmt(w io.Writer, x interface{}, format string) { - // Can do better than text in some cases. - switch v := x.(type) { - case ast.Decl: - var p astPrinter.Printer; - tw := makeTabwriter(w); - p.Init(tw, nil, nil, true); - v.Visit(&p); - tw.Flush(); - case ast.Expr: - var p astPrinter.Printer; - tw := makeTabwriter(w); - p.Init(tw, nil, nil, true); - v.Visit(&p); - tw.Flush(); - default: - template.HtmlEscape(w, toText(x)); - } + template.HtmlEscape(w, toText(x)); } @@ -363,11 +331,7 @@ func serveGoSource(c *http.Conn, name string) { var buf io.ByteBuffer; fmt.Fprintln(&buf, "
");
-	var p astPrinter.Printer;
-	writer := makeTabwriter(&buf);  // for nicely formatted output
-	p.Init(writer, nil, nil, true);
-	p.DoProgram(prog);
-	writer.Flush();  // ignore errors
+	template.HtmlEscape(&buf, nodeText(prog, printer.DocComments));
 	fmt.Fprintln(&buf, "
"); servePage(c, name + " - Go source", buf.Data()); diff --git a/usr/gri/pretty/gofmt.go b/usr/gri/pretty/gofmt.go new file mode 100644 index 0000000000..73f9d8e23c --- /dev/null +++ b/usr/gri/pretty/gofmt.go @@ -0,0 +1,107 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag"; + "fmt"; + "go/parser"; + "go/printer"; + "io"; + "os"; + "sort"; + "tabwriter"; +) + + +var ( + // operation modes + silent = flag.Bool("s", false, "silent mode: parsing only"); + verbose = flag.Bool("v", false, "verbose mode: trace parsing"); + exports = flag.Bool("x", false, "show exports only"); + + // layout control + tabwidth = flag.Int("tabwidth", 4, "tab width"); + usetabs = flag.Bool("tabs", false, "align with tabs instead of blanks"); + optcommas = flag.Bool("optcommas", false, "print optional commas"); + optsemis = flag.Bool("optsemis", false, "print optional semicolons"); +) + + +func usage() { + fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [file.go]\n"); + flag.PrintDefaults(); + os.Exit(1); +} + + +func parserMode() uint { + mode := parser.ParseComments; + if *verbose { + mode |= parser.Trace; + } + return mode; +} + + +func printerMode() uint { + mode := uint(0); + if *exports { + mode |= printer.ExportsOnly; + } + if *optcommas { + mode |= printer.OptCommas; + } + if *optsemis { + mode |= printer.OptSemis; + } + return mode; +} + + +func makeTabwriter(writer io.Writer) *tabwriter.Writer { + padchar := byte(' '); + if *usetabs { + padchar = '\t'; + } + return tabwriter.NewWriter(writer, *tabwidth, 1, padchar, 0); +} + + +func main() { + flag.Parse(); + + var filename string; + switch flag.NArg() { + case 0: filename = "/dev/stdin"; + case 1: filename = flag.Arg(0); + default: usage(); + } + + src, err := io.ReadFile(filename); + if err != nil { + fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err); + os.Exit(1); + } + + prog, err := parser.Parse(src, parserMode()); + if err != nil { + if errors, ok := err.(parser.ErrorList); ok { + sort.Sort(errors); + for _, e := range errors { + fmt.Fprintf(os.Stderr, "%s:%v\n", filename, e); + } + } else { + fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err); + } + os.Exit(1); + } + + if !*silent { + w := makeTabwriter(os.Stdout); + printer.Fprint(w, prog, printerMode()); + w.Flush(); + } +} diff --git a/usr/gri/pretty/pretty.go b/usr/gri/pretty/pretty.go deleted file mode 100644 index 82fc16b3c2..0000000000 --- a/usr/gri/pretty/pretty.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "astprinter"; // TODO remove once go/printer is fully functional - "flag"; - "fmt"; - "go/ast"; - "go/parser"; - "go/token"; - "io"; - "os"; - "sort"; - "tabwriter"; -) - - -var ( - // operation modes - columns bool; - // TODO remove silent flag eventually, can achieve same by proving no format file - silent = flag.Bool("s", false, "silent mode: no pretty print output"); - verbose = flag.Bool("v", false, "verbose mode: trace parsing"); - - // layout control - format = flag.String("format", "", "format file"); - tabwidth = flag.Int("tabwidth", 4, "tab width"); - usetabs = flag.Bool("tabs", false, "align with tabs instead of blanks"); -) - - -func init() { - user, err := os.Getenv("USER"); - flag.BoolVar(&columns, "columns", user == "gri", "print column no. in error messages"); -} - - -func usage() { - fmt.Fprintf(os.Stderr, "usage: pretty { flags } { files }\n"); - flag.PrintDefaults(); - os.Exit(1); -} - - -// TODO(gri) move this function into tabwriter.go? (also used in godoc) -func makeTabwriter(writer io.Writer) *tabwriter.Writer { - padchar := byte(' '); - if *usetabs { - padchar = '\t'; - } - return tabwriter.NewWriter(writer, *tabwidth, 1, padchar, 0); -} - - -func main() { - // handle flags - flag.Parse(); - if flag.NFlag() == 0 && flag.NArg() == 0 { - usage(); - } - - // initialize astFormat - astFormat, err := ast.NewFormat(*format); - if *format != "" && err != nil { // ignore error if no format file given - fmt.Fprintf(os.Stderr, "ast.NewFormat(%s): %v\n", *format, err); - os.Exit(1); - } - - // determine parsing mode - mode := parser.ParseComments; - if *verbose { - mode |= parser.Trace; - } - - // process files - exitcode := 0; - for i := 0; i < flag.NArg(); i++ { - filename := flag.Arg(i); - - src, err := io.ReadFile(filename); - if err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err); - exitcode = 1; - continue; // proceed with next file - } - - prog, err := parser.Parse(src, mode); - if err != nil { - if errors, ok := err.(parser.ErrorList); ok { - sort.Sort(errors); - for _, e := range errors { - fmt.Fprintf(os.Stderr, "%s:%v\n", filename, e); - } - } else { - fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err); - } - exitcode = 1; - continue; // proceed with next file - } - - if !*silent { - tw := makeTabwriter(os.Stdout); - if *format != "" { - _, err := astFormat.Fprint(tw, prog); - if err != nil { - fmt.Fprintf(os.Stderr, "format error: %v\n", err); - exitcode = 1; - continue; // proceed with next file - } - } else { - var p astPrinter.Printer; - p.Init(tw, nil, nil /*prog.Comments*/, false); - p.DoProgram(prog); - } - tw.Flush(); - } - } - - os.Exit(exitcode); -} diff --git a/usr/gri/pretty/test.sh b/usr/gri/pretty/test.sh index c330821155..4015b0c8ed 100755 --- a/usr/gri/pretty/test.sh +++ b/usr/gri/pretty/test.sh @@ -10,7 +10,7 @@ if [ -z "$O" ]; then exit 1 fi -CMD="./pretty -format=ast.txt" +CMD="./gofmt" TMP1=test_tmp1.go TMP2=test_tmp2.go TMP3=test_tmp3.go @@ -34,7 +34,7 @@ apply1() { # the following have semantic errors: bug039.go | bug040.go test_errors.go | calc.go | method1.go | selftest1.go | func3.go | const2.go | \ bug014.go | bug025.go | bug029.go | bug032.go | bug039.go | bug040.go | bug050.go | bug068.go | \ - bug088.go | bug083.go | bug106.go | bug121.go | bug125.go | bug126.go | bug132.go | bug133.go | bug134.go ) ;; + bug088.go | bug083.go | bug106.go | bug121.go | bug125.go | bug126.go | bug132.go | bug133.go | bug134.go | bug160.go ) ;; * ) $1 $2; count $F;; esac } diff --git a/usr/gri/pretty/untab.go b/usr/gri/pretty/untab.go deleted file mode 100644 index b18e08f8b7..0000000000 --- a/usr/gri/pretty/untab.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag"; - "fmt"; - "io"; - "os"; - "tabwriter"; -) - - -var ( - tabwidth = flag.Int("tabwidth", 4, "tab width"); - usetabs = flag.Bool("usetabs", false, "align with tabs instead of blanks"); -) - - -func error(format string, params ...) { - fmt.Printf(format, params); - os.Exit(1); -} - - -func untab(name string, src *os.File, dst *tabwriter.Writer) { - n, err := io.Copy(src, dst); - if err != nil { - error("error while processing %s (%v)", name, err); - } - //dst.Flush(); -} - - -func main() { - flag.Parse(); - padchar := byte(' '); - if *usetabs { - padchar = '\t'; - } - dst := tabwriter.NewWriter(os.Stdout, *tabwidth, 1, padchar, 0); - if flag.NArg() > 0 { - for i := 0; i < flag.NArg(); i++ { - name := flag.Arg(i); - src, err := os.Open(name, os.O_RDONLY, 0); - if err != nil { - error("could not open %s (%v)\n", name, err); - } - untab(name, src, dst); - src.Close(); // ignore errors - } - } else { - // no files => use stdin - untab("/dev/stdin", os.Stdin, dst); - } -} -- 2.48.1