The Cultural Evolution of gofmt

gofmt 的文化演变

Robert Griesemer

Google, Inc.

gofmt

2

Original motivation

3

History

GRINDEF  (Bill Gosper, 1967)           first to measure line length
SOAP     (R. Scowen et al, 1969)       Simplifies Obscure Algol Programs
NEATER2  (Ken Conrow, R. Smith, 1970)  PL/1 reformatter, use as (early) error detection tool
cb       (Unix Version 7, 1979)        C program beautifier
indent   (4.2 BSD, 1983)               indent and format C source code
etc.
ClangFormat                            C/C++/Objective-C formatter
Uncrustify                             beautifier for C, C++, C#, ObjectiveC, D, Java, Pawn and VALA
etc.
4

Reality check

5

The problem with pretty printers

6

Formatting Go

7

Keep it as simple as possible

One formatting style to rule them all!

8

Basic structure of gofmt

9

Parsing source code

// Syntax of an if statement.
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .

// An IfStmt node represents an if statement.
IfStmt struct {
    If   token.Pos // position of "if" keyword
    Init Stmt      // initialization statement; or nil
    Cond Expr      // condition
    Body *BlockStmt
    Else Stmt // else branch; or nil
}
10

Basic formatting

case *ast.IfStmt:
    p.print(token.IF)
    p.controlClause(false, s.Init, s.Cond, nil)
    p.block(s.Body, 1)
    if s.Else != nil {
        p.print(blank, token.ELSE, blank)
        switch s.Else.(type) {
        case *ast.BlockStmt, *ast.IfStmt:
            p.stmt(s.Else, nextIsRBrace)
        default:
            p.print(token.LBRACE, indent, formfeed)
            p.stmt(s.Else, true)
            p.print(unindent, formfeed, token.RBRACE)
        }
    }
11

Fine tuning

x = a + b
x = a + b*c
if a+b <= d {
if a+b*c <= d {
12

Handling of comments

// A CommentGroup represents a sequence of comments
// with no other tokens and no empty lines between.
//
type CommentGroup struct {
    List []*Comment // len(List) > 0
}
13

Representation of comments in the AST

14

Formatting with comments

15

Devil is in the details

16

Formatting individual comments

func f() {              func() {
 /*                             /*
  * foo                          * foo
  * bar         ==>              * bar
  * bal                          * bal
 */                              */
        if ...                   if  ...
}                       }
17

Alignment

var (                                 var (
        x, y int = 2, 3 // foo                x, y int     = 2, 3 // foo
        z float32 // bar         ==>          z    float32        // bar
        s string // bal                       s    string         // bal
)                                     )
18

Elastic tabstops

Regular tabs (\t) advance writing position to fixed tab stops.

Basic idea: Make tab stops elastic.

Proposed by Nick Gravgaard, 2006

Implemented by text/tabwriter package.

19

Elastic tabstops illustrated

20

Putting it all together (1)

Works well for fixed-width fonts.

Proportional fonts could be handled by an editor supporting elastic tab stops.

21

Putting it all together (2)

22

The big picture

23

gofmt applications

24

gofmt as source code transformer

gofmt -w -r 'a[i:len(x)] -> a[i:]' *.go
25

Reactions

gofmt is everybody's favorite.

Formatting has become a non-issue.

26

Others are starting to take note

Automatic source code formatting is becoming a requirement
for any kind of language.

27

Conclusions

28

Evolution in programming culture

29

Lessons learned: Application

Want:

30

Lessons learned: Implementation

=> Current design makes it extremely hard to manipulate AST
and maintain comments in right places.

Want:

31

Going forward

32

Thank you

Robert Griesemer

Google, Inc.

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)