Skip to content

Commit f7164a8

Browse files
committed
add more tests, fix structs and if-else formatting
1 parent 904513e commit f7164a8

File tree

4 files changed

+127
-6
lines changed

4 files changed

+127
-6
lines changed

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ module github.com/quasilyte/minformat
22

33
go 1.15
44

5-
require github.com/go-toolsmith/strparse v1.0.0
5+
require (
6+
github.com/go-toolsmith/astcopy v1.0.0
7+
github.com/go-toolsmith/astequal v1.0.1 // indirect
8+
github.com/go-toolsmith/strparse v1.0.0
9+
github.com/google/go-cmp v0.5.6
10+
)

go.sum

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1+
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
2+
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
3+
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
4+
github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc=
5+
github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw=
16
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
27
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
8+
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
9+
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
10+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
11+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

go/minformat/minifier.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ func (m *minifier) printExpr(n ast.Expr) {
139139
m.out.WriteByte(',')
140140
}
141141
}
142+
if n.Ellipsis != token.NoPos {
143+
m.out.WriteString("...")
144+
}
142145
m.out.WriteByte(')')
143146

144147
case *ast.SliceExpr:
@@ -388,6 +391,13 @@ func (m *minifier) printStmt(n ast.Stmt) {
388391
}
389392
m.printExpr(n.Cond)
390393
m.printBlockStmt(n.Body)
394+
if n.Else != nil {
395+
m.out.WriteString("else")
396+
if _, ok := n.Else.(*ast.IfStmt); ok {
397+
m.out.WriteByte(' ')
398+
}
399+
m.printStmt(n.Else)
400+
}
391401

392402
case *ast.BlockStmt:
393403
m.printBlockStmt(n)
@@ -486,20 +496,29 @@ func (m *minifier) printGenDecl(n *ast.GenDecl) {
486496
}
487497

488498
func (m *minifier) printBinaryExpr(n *ast.BinaryExpr) {
499+
spaceBeforeY := false
500+
489501
// Handle `x < -y` and `x - -y`.
490502
if n.Op == token.LSS || n.Op == token.SUB {
491503
y := leftmostExpr(n.Y)
492504
if y, ok := y.(*ast.UnaryExpr); ok && y.Op == token.SUB {
493-
m.printExpr(n.X)
494-
m.out.WriteString(n.Op.String())
495-
m.out.WriteByte(' ')
496-
m.printExpr(n.Y)
497-
return
505+
spaceBeforeY = true
506+
}
507+
}
508+
509+
// Handle `x & ^y` so we don't output it as `x&^y`.
510+
if n.Op == token.AND {
511+
y, ok := n.Y.(*ast.UnaryExpr)
512+
if ok && y.Op == token.XOR {
513+
spaceBeforeY = true
498514
}
499515
}
500516

501517
m.printExpr(n.X)
502518
m.out.WriteString(n.Op.String())
519+
if spaceBeforeY {
520+
m.out.WriteByte(' ')
521+
}
503522
m.printExpr(n.Y)
504523
}
505524

@@ -553,6 +572,9 @@ func (m *minifier) printFieldList(n *ast.FieldList, sep byte) {
553572
m.out.WriteByte(' ')
554573
}
555574
m.printExpr(field.Type)
575+
if field.Tag != nil {
576+
m.out.WriteString(field.Tag.Value)
577+
}
556578
if j != len(n.List)-1 {
557579
m.out.WriteByte(sep)
558580
}

go/minformat/minifier_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@ package minformat
22

33
import (
44
"bytes"
5+
"fmt"
6+
"go/ast"
7+
"go/format"
8+
"go/parser"
59
"go/token"
10+
"io/fs"
11+
"os"
12+
"os/exec"
13+
"path/filepath"
14+
"strings"
615
"testing"
716

817
"github.com/go-toolsmith/strparse"
18+
"github.com/google/go-cmp/cmp"
919
)
1020

1121
func TestMinifyDecl(t *testing.T) {
@@ -20,6 +30,8 @@ func TestMinifyDecl(t *testing.T) {
2030
{`type x = int`, `type x=int`},
2131
{`type (a [2] int; b [ ]int)`, `type(a [2]int;b []int)`},
2232

33+
{`type _ struct { x int "struct tag" }`, `type _ struct{x int"struct tag"}`},
34+
2335
{`const x, y = 1, 2`, `const x,y=1,2`},
2436
{`const (x = 1; y = 2)`, `const(x=1;y=2)`},
2537
{`const x int = 1`, `const x int=1`},
@@ -78,6 +90,8 @@ func TestMinifyStmt(t *testing.T) {
7890

7991
{`if cond { return nil }`, `if cond{return nil}`},
8092
{`if x := f(); !x { return nil }`, `if x:=f();!x{return nil}`},
93+
{`if cond { f(); } else { g(); }`, `if cond{f()}else{g()}`},
94+
{`if cond { f(); } else if cond { g(); }`, `if cond{f()}else if cond{g()}`},
8195

8296
{`switch {default: return 1}`, `switch{default:return 1}`},
8397
{`switch tag {case 1, 2: return 0}`, `switch tag{case 1,2:return 0}`},
@@ -151,6 +165,10 @@ func TestMinifyExpr(t *testing.T) {
151165
{`[] int`, `[]int`},
152166
{`[ 2 ] int`, `[2]int`},
153167

168+
{`x &^ y`, `x&^y`},
169+
{`x & ^y`, `x& ^y`},
170+
{`x & (^y)`, `x&(^y)`},
171+
154172
{`func () `, `func()`},
155173
{`func ( int ) (int, int)`, `func(int)(int,int)`},
156174
{`func ( int, int ) (int)`, `func(int,int)int`},
@@ -183,6 +201,7 @@ func TestMinifyExpr(t *testing.T) {
183201
{`f(1, 2)`, `f(1,2)`},
184202
{`f(1, g(2, 3))`, `f(1,g(2,3))`},
185203
{`f( 1 )( 2, 3 )`, `f(1)(2,3)`},
204+
{`foo(1, args...)`, `foo(1,args...)`},
186205

187206
{`struct { }`, `struct{}`},
188207
{`struct{ int }`, `struct{int}`},
@@ -218,3 +237,69 @@ func TestMinifyExpr(t *testing.T) {
218237
}
219238
}
220239
}
240+
241+
func TestGoroot(t *testing.T) {
242+
var goroot string
243+
{
244+
out, err := exec.Command("go", "env", "GOROOT").CombinedOutput()
245+
if err != nil {
246+
t.Fatal(err)
247+
}
248+
goroot = strings.TrimSpace(string(out))
249+
}
250+
251+
visitFile := func(filename string) error {
252+
fset := token.NewFileSet()
253+
fileContents, err := os.ReadFile(filename)
254+
if err != nil {
255+
return err
256+
}
257+
f, err := parser.ParseFile(fset, filename, fileContents, 0)
258+
if err != nil {
259+
return nil
260+
}
261+
var minified bytes.Buffer
262+
if err := Node(&minified, fset, f); err != nil {
263+
return err
264+
}
265+
fset2 := token.NewFileSet()
266+
f2, err := parser.ParseFile(fset2, filename, minified.Bytes(), 0)
267+
if err != nil {
268+
return fmt.Errorf("re-parse minified: %w", err)
269+
}
270+
if diff := astDiff(f, f2); diff != "" {
271+
return fmt.Errorf("minified code produced different AST:\n%s", diff)
272+
}
273+
return nil
274+
}
275+
276+
srcDir := filepath.Join(goroot, "src")
277+
err := filepath.WalkDir(srcDir, func(path string, info fs.DirEntry, err error) error {
278+
if err != nil {
279+
return err
280+
}
281+
if info.IsDir() {
282+
return nil
283+
}
284+
if !strings.HasSuffix(info.Name(), ".go") {
285+
return nil
286+
}
287+
if err := visitFile(path); err != nil {
288+
return fmt.Errorf("%s: %w", path, err)
289+
}
290+
return nil
291+
})
292+
if err != nil {
293+
t.Fatal(err)
294+
}
295+
}
296+
297+
func astDiff(x, y ast.Node) string {
298+
var buf bytes.Buffer
299+
format.Node(&buf, token.NewFileSet(), x)
300+
s1 := buf.String()
301+
buf.Reset()
302+
format.Node(&buf, token.NewFileSet(), y)
303+
s2 := buf.String()
304+
return cmp.Diff(s1, s2)
305+
}

0 commit comments

Comments
 (0)