]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile/internal/syntax: clean up node printing API
authorRobert Griesemer <gri@golang.org>
Thu, 7 Jan 2021 20:57:15 +0000 (12:57 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 8 Jan 2021 17:32:14 +0000 (17:32 +0000)
Preparation for using the syntax printer as expression printer in types2.

- Introduced Form to control printing format
- Cleaned up/added String and ShortString convenience functions
- Implemented ShortForm format which prints … for non-empty
  function and composite literal bodies
- Added test to check write error handling

Change-Id: Ie86e46d766fb60fcf07ef643c7788b2ef440ffa8
Reviewed-on: https://go-review.googlesource.com/c/go/+/282552
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/syntax/dumper.go
src/cmd/compile/internal/syntax/parser_test.go
src/cmd/compile/internal/syntax/printer.go
src/cmd/compile/internal/syntax/printer_test.go

index 01453d5a7ad0186c4795f5d9011d821fe3401a5e..d5247886dae53117ccf5934cd53dd68d499ea4ec 100644 (file)
@@ -26,7 +26,7 @@ func Fdump(w io.Writer, n Node) (err error) {
 
        defer func() {
                if e := recover(); e != nil {
-                       err = e.(localError).err // re-panics if it's not a localError
+                       err = e.(writeError).err // re-panics if it's not a writeError
                }
        }()
 
@@ -82,16 +82,16 @@ func (p *dumper) Write(data []byte) (n int, err error) {
        return
 }
 
-// localError wraps locally caught errors so we can distinguish
+// writeError wraps locally caught write errors so we can distinguish
 // them from genuine panics which we don't want to return as errors.
-type localError struct {
+type writeError struct {
        err error
 }
 
 // printf is a convenience wrapper that takes care of print errors.
 func (p *dumper) printf(format string, args ...interface{}) {
        if _, err := fmt.Fprintf(p, format, args...); err != nil {
-               panic(localError{err})
+               panic(writeError{err})
        }
 }
 
index ea9e9acc83c2e512e5c0ea7e23cd525ed1836c26..340ca6bb6f637b05d5756a44f09a371eec69819f 100644 (file)
@@ -169,7 +169,7 @@ func walkDirs(t *testing.T, dir string, action func(string)) {
 
 func verifyPrint(t *testing.T, filename string, ast1 *File) {
        var buf1 bytes.Buffer
-       _, err := Fprint(&buf1, ast1, true)
+       _, err := Fprint(&buf1, ast1, LineForm)
        if err != nil {
                panic(err)
        }
@@ -181,7 +181,7 @@ func verifyPrint(t *testing.T, filename string, ast1 *File) {
        }
 
        var buf2 bytes.Buffer
-       _, err = Fprint(&buf2, ast2, true)
+       _, err = Fprint(&buf2, ast2, LineForm)
        if err != nil {
                panic(err)
        }
index c8bf59675a2fedb8291580842e005275ba3d9400..0a60e1753ded1e4f7000c933b3a363a45e9b8b4b 100644 (file)
@@ -13,19 +13,28 @@ import (
        "strings"
 )
 
-// TODO(gri) Consider removing the linebreaks flag from this signature.
-// Its likely rarely used in common cases.
+// Form controls print formatting.
+type Form uint
 
-func Fprint(w io.Writer, x Node, linebreaks bool) (n int, err error) {
+const (
+       _         Form = iota // default
+       LineForm              // use spaces instead of linebreaks where possible
+       ShortForm             // like LineForm but print "…" for non-empty function or composite literal bodies
+)
+
+// Fprint prints node x to w in the specified form.
+// It returns the number of bytes written, and whether there was an error.
+func Fprint(w io.Writer, x Node, form Form) (n int, err error) {
        p := printer{
                output:     w,
-               linebreaks: linebreaks,
+               form:       form,
+               linebreaks: form == 0,
        }
 
        defer func() {
                n = p.written
                if e := recover(); e != nil {
-                       err = e.(localError).err // re-panics if it's not a localError
+                       err = e.(writeError).err // re-panics if it's not a writeError
                }
        }()
 
@@ -35,15 +44,20 @@ func Fprint(w io.Writer, x Node, linebreaks bool) (n int, err error) {
        return
 }
 
-func String(n Node) string {
+func asString(n Node, form Form) string {
        var buf bytes.Buffer
-       _, err := Fprint(&buf, n, false)
+       _, err := Fprint(&buf, n, form)
        if err != nil {
-               panic(err) // TODO(gri) print something sensible into buf instead
+               fmt.Fprintf(&buf, "<<< ERROR: %s", err)
        }
        return buf.String()
 }
 
+// String and ShortString are convenience functions that print n in
+// LineForm or ShortForm respectively, and return the printed string.
+func String(n Node) string      { return asString(n, LineForm) }
+func ShortString(n Node) string { return asString(n, ShortForm) }
+
 type ctrlSymbol int
 
 const (
@@ -65,7 +79,8 @@ type whitespace struct {
 
 type printer struct {
        output     io.Writer
-       written    int  // number of bytes written
+       written    int // number of bytes written
+       form       Form
        linebreaks bool // print linebreaks instead of semis
 
        indent  int // current indentation level
@@ -81,7 +96,7 @@ func (p *printer) write(data []byte) {
        n, err := p.output.Write(data)
        p.written += n
        if err != nil {
-               panic(localError{err})
+               panic(writeError{err})
        }
 }
 
@@ -355,17 +370,34 @@ func (p *printer) printRawNode(n Node) {
                p.print(_Name, n.Value) // _Name requires actual value following immediately
 
        case *FuncLit:
-               p.print(n.Type, blank, n.Body)
+               p.print(n.Type, blank)
+               if n.Body != nil {
+                       if p.form == ShortForm {
+                               p.print(_Lbrace)
+                               if len(n.Body.List) > 0 {
+                                       p.print(_Name, "…")
+                               }
+                               p.print(_Rbrace)
+                       } else {
+                               p.print(n.Body)
+                       }
+               }
 
        case *CompositeLit:
                if n.Type != nil {
                        p.print(n.Type)
                }
                p.print(_Lbrace)
-               if n.NKeys > 0 && n.NKeys == len(n.ElemList) {
-                       p.printExprLines(n.ElemList)
+               if p.form == ShortForm {
+                       if len(n.ElemList) > 0 {
+                               p.print(_Name, "…")
+                       }
                } else {
-                       p.printExprList(n.ElemList)
+                       if n.NKeys > 0 && n.NKeys == len(n.ElemList) {
+                               p.printExprLines(n.ElemList)
+                       } else {
+                               p.printExprList(n.ElemList)
+                       }
                }
                p.print(_Rbrace)
 
@@ -450,9 +482,13 @@ func (p *printer) printRawNode(n Node) {
                }
                p.print(_Lbrace)
                if len(n.FieldList) > 0 {
-                       p.print(newline, indent)
-                       p.printFieldList(n.FieldList, n.TagList)
-                       p.print(outdent, newline)
+                       if p.linebreaks {
+                               p.print(newline, indent)
+                               p.printFieldList(n.FieldList, n.TagList)
+                               p.print(outdent, newline)
+                       } else {
+                               p.printFieldList(n.FieldList, n.TagList)
+                       }
                }
                p.print(_Rbrace)
 
@@ -467,9 +503,13 @@ func (p *printer) printRawNode(n Node) {
                }
                p.print(_Lbrace)
                if len(n.MethodList) > 0 {
-                       p.print(newline, indent)
-                       p.printMethodList(n.MethodList)
-                       p.print(outdent, newline)
+                       if p.linebreaks {
+                               p.print(newline, indent)
+                               p.printMethodList(n.MethodList)
+                               p.print(outdent, newline)
+                       } else {
+                               p.printMethodList(n.MethodList)
+                       }
                }
                p.print(_Rbrace)
 
index 9f1f7e18cbf1f4bf6735a1762de381f50df51c66..6c07fe0a26aa1c1f063ab167762407353876a311 100644 (file)
@@ -25,11 +25,38 @@ func TestPrint(t *testing.T) {
        }
 
        if ast != nil {
-               Fprint(testOut(), ast, true)
+               Fprint(testOut(), ast, LineForm)
                fmt.Println()
        }
 }
 
+type shortBuffer struct {
+       buf []byte
+}
+
+func (w *shortBuffer) Write(data []byte) (n int, err error) {
+       w.buf = append(w.buf, data...)
+       n = len(data)
+       if len(w.buf) > 10 {
+               err = io.ErrShortBuffer
+       }
+       return
+}
+
+func TestPrintError(t *testing.T) {
+       const src = "package p; var x int"
+       ast, err := Parse(nil, strings.NewReader(src), nil, nil, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       var buf shortBuffer
+       _, err = Fprint(&buf, ast, 0)
+       if err == nil || err != io.ErrShortBuffer {
+               t.Errorf("got err = %s, want %s", err, io.ErrShortBuffer)
+       }
+}
+
 var stringTests = []string{
        "package p",
        "package p; type _ int; type T1 = struct{}; type ( _ *struct{}; T2 = float32 )",