Repository: goplus/gop
Pull request #1476 (2023-10-20 10:28:33)

gop fmt -t: test if Go+ files are formatted or not


Patch:
diff --git a/cl/builtin.go b/cl/builtin.go
index 3058e246..a97ecf34 100644
--- a/cl/builtin.go
+++ b/cl/builtin.go
@@ -41,51 +41,39 @@ func initBuiltinFns(builtin *types.Package, scope *types.Scope, pkg *gox.PkgRef,
 
 func initBuiltin(pkg *gox.Package, builtin *types.Package, os, fmt, ng, iox, buil *gox.PkgRef) {
 	scope := builtin.Scope()
-	if ng != nil {
-		typs := []string{"bigint", "bigrat", "bigfloat"}
-		for _, typ := range typs {
-			name := string(typ[0]-('a'-'A')) + typ[1:]
-			scope.Insert(types.NewTypeName(token.NoPos, builtin, typ, ng.Ref(name).Type()))
-		}
-		scope.Insert(types.NewTypeName(token.NoPos, builtin, "uint128", ng.Ref("Uint128").Type()))
-		scope.Insert(types.NewTypeName(token.NoPos, builtin, "int128", ng.Ref("Int128").Type()))
-	}
-	if fmt != nil {
-		initBuiltinFns(builtin, scope, fmt, []string{
-			"print", "println", "printf", "errorf",
-			"fprint", "fprintln", "fprintf",
-			"sprint", "sprintln", "sprintf",
-		})
-	}
-	if os != nil {
-		initBuiltinFns(builtin, scope, os, []string{
-			"open", "create",
-		})
-	}
-	if iox != nil {
-		initBuiltinFns(builtin, scope, iox, []string{
-			"lines",
-		})
-		scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "blines", iox.Ref("BLines")))
-	}
-	if buil != nil {
-		scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "newRange", buil.Ref("NewRange__0")))
+	typs := []string{"bigint", "bigrat", "bigfloat"}
+	for _, typ := range typs {
+		name := string(typ[0]-('a'-'A')) + typ[1:]
+		scope.Insert(types.NewTypeName(token.NoPos, builtin, typ, ng.Ref(name).Type()))
 	}
+	initBuiltinFns(builtin, scope, fmt, []string{
+		"print", "println", "printf", "errorf",
+		"fprint", "fprintln", "fprintf",
+		"sprint", "sprintln", "sprintf",
+	})
+	initBuiltinFns(builtin, scope, os, []string{
+		"open", "create",
+	})
+	initBuiltinFns(builtin, scope, iox, []string{
+		"lines",
+	})
+	scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "blines", iox.Ref("BLines")))
+	scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "newRange", buil.Ref("NewRange__0")))
+	scope.Insert(types.NewTypeName(token.NoPos, builtin, "uint128", ng.Ref("Uint128").Type()))
+	scope.Insert(types.NewTypeName(token.NoPos, builtin, "int128", ng.Ref("Int128").Type()))
 	scope.Insert(types.NewTypeName(token.NoPos, builtin, "any", gox.TyEmptyInterface))
 }
 
 func newBuiltinDefault(pkg *gox.Package, conf *gox.Config) *types.Package {
 	builtin := types.NewPackage("", "")
-	fmt := pkg.TryImport("fmt")
-	os := pkg.TryImport("os")
-	buil := pkg.TryImport("github.com/goplus/gop/builtin")
-	ng := pkg.TryImport("github.com/goplus/gop/builtin/ng")
-	iox := pkg.TryImport("github.com/goplus/gop/builtin/iox")
-	pkg.TryImport("strconv")
-	pkg.TryImport("strings")
-	if ng != nil {
-		initMathBig(pkg, conf, ng)
-	}
+	fmt := pkg.Import("fmt")
+	os := pkg.Import("os")
+	buil := pkg.Import("github.com/goplus/gop/builtin")
+	ng := pkg.Import("github.com/goplus/gop/builtin/ng")
+	iox := pkg.Import("github.com/goplus/gop/builtin/iox")
+	pkg.Import("strconv")
+	pkg.Import("strings")
+	initMathBig(pkg, conf, ng)
 	initBuiltin(pkg, builtin, os, fmt, ng, iox, buil)
 	gox.InitBuiltin(pkg, builtin, conf)
 	return builtin
diff --git a/cl/c.go b/cl/c.go
index b203bbb2..39b4c989 100644
--- a/cl/c.go
+++ b/cl/c.go
@@ -60,7 +60,8 @@ func c2goBase(base string) string {
 func loadC2goPkg(ctx *blockCtx, realPath string, src *ast.BasicLit) *gox.PkgRef {
 	cpkg, err := ctx.cpkgs.Import(realPath)
 	if err != nil {
-		ctx.handleErrorf(src.Pos(),
+		pos := ctx.Position(src.Pos())
+		ctx.handleCodeErrorf(&pos,
 			"%v not found or not a valid C package (c2go.a.pub file not found).\n", realPath)
 		return nil
 	}
diff --git a/cl/compile.go b/cl/compile.go
index f4f35968..1ce82085 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -36,10 +36,8 @@ import (
 	"github.com/qiniu/x/errors"
 )
 
-type dbgFlags int
-
 const (
-	DbgFlagLoad dbgFlags = 1 << iota
+	DbgFlagLoad = 1 << iota
 	DbgFlagLookup
 	DbgFlagAll = DbgFlagLoad | DbgFlagLookup
 )
@@ -57,7 +55,7 @@ func SetDisableRecover(disableRecover bool) {
 	enableRecover = !disableRecover
 }
 
-func SetDebug(flags dbgFlags) {
+func SetDebug(flags int) {
 	debugLoad = (flags & DbgFlagLoad) != 0
 	debugLookup = (flags & DbgFlagLookup) != 0
 }
@@ -273,9 +271,13 @@ func initLoader(ctx *pkgCtx, syms map[string]loader, start token.Pos, name strin
 		return
 	}
 	if old, ok := syms[name]; ok {
+		var pos token.Position
+		if start != token.NoPos {
+			pos = ctx.Position(start)
+		}
 		oldpos := ctx.Position(old.pos())
-		ctx.handleErrorf(
-			start, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
+		ctx.handleCodeErrorf(
+			&pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
 		return
 	}
 	syms[name] = &baseLoader{start: start, fn: fn}
@@ -303,8 +305,8 @@ func getTypeLoader(ctx *pkgCtx, syms map[string]loader, start token.Pos, name st
 			if ld.start == token.NoPos {
 				ld.start = start
 			} else {
-				ctx.handleErrorf(
-					start, "%s redeclared in this block\n\tprevious declaration at %v",
+				pos := ctx.Position(start)
+				ctx.handleCodeErrorf(&pos, "%s redeclared in this block\n\tprevious declaration at %v",
 					name, ctx.Position(ld.start))
 			}
 			return ld
@@ -412,11 +414,6 @@ func (p *pkgCtx) handleCodeErrorf(pos *token.Position, format string, args ...in
 	p.handleErr(newCodeErrorf(pos, format, args...))
 }
 
-func (p *pkgCtx) handleErrorf(start token.Pos, format string, args ...interface{}) {
-	pos := p.Position(start)
-	p.handleErr(newCodeErrorf(&pos, format, args...))
-}
-
 func (p *pkgCtx) handleErr(err error) {
 	p.errs = append(p.errs, err)
 }
diff --git a/cl/func_type_and_var.go b/cl/func_type_and_var.go
index 32191348..52b69f94 100644
--- a/cl/func_type_and_var.go
+++ b/cl/func_type_and_var.go
@@ -115,8 +115,7 @@ func toType(ctx *blockCtx, typ ast.Expr) types.Type {
 							break
 						}
 					}
-					ctx.handleErrorf(pos, "cannot use generic type %v without instantiation", t.Obj().Type())
-					return types.Typ[types.Invalid]
+					panic(ctx.newCodeErrorf(pos, "cannot use generic type %v without instantiation", t.Obj().Type()))
 				}
 			}
 		}
@@ -183,11 +182,9 @@ func toExternalType(ctx *blockCtx, v *ast.SelectorExpr) types.Type {
 		if t, ok := o.(*types.TypeName); ok {
 			return t.Type()
 		}
-		ctx.handleErrorf(v.Pos(), "%s.%s is not a type", name, v.Sel.Name)
-	} else {
-		ctx.handleErrorf(v.Pos(), "undefined: %s", name)
+		panic(ctx.newCodeErrorf(v.Pos(), "%s.%s is not a type", name, v.Sel.Name))
 	}
-	return types.Typ[types.Invalid]
+	panic(ctx.newCodeErrorf(v.Pos(), "undefined: %s", name))
 }
 
 /*-----------------------------------------------------------------------------
@@ -207,8 +204,7 @@ func toIdentType(ctx *blockCtx, ident *ast.Ident) types.Type {
 	}
 	v, builtin := lookupType(ctx, ident.Name)
 	if isBuiltin(builtin) {
-		ctx.handleErrorf(ident.Pos(), "use of builtin %s not in function call", ident.Name)
-		return types.Typ[types.Invalid]
+		panic(ctx.newCodeErrorf(ident.Pos(), "use of builtin %s not in function call", ident.Name))
 	}
 	if t, ok := v.(*types.TypeName); ok {
 		return t.Type()
@@ -218,8 +214,7 @@ func toIdentType(ctx *blockCtx, ident *ast.Ident) types.Type {
 			return t.Type()
 		}
 	}
-	ctx.handleErrorf(ident.Pos(), "%s is not a type", ident.Name)
-	return types.Typ[types.Invalid]
+	panic(ctx.newCodeErrorf(ident.Pos(), "%s is not a type", ident.Name))
 }
 
 // TODO: optimization
@@ -260,8 +255,8 @@ func (p *checkRedecl) chkRedecl(ctx *blockCtx, name string, pos token.Pos) bool
 		return false
 	}
 	if opos, ok := p.names[name]; ok {
-		ctx.handleErrorf(
-			pos, "%v redeclared\n\t%v other declaration of %v",
+		npos := ctx.Position(pos)
+		ctx.handleCodeErrorf(&npos, "%v redeclared\n\t%v other declaration of %v",
 			name, ctx.Position(opos), name)
 		return true
 	}
diff --git a/cl/stmt.go b/cl/stmt.go
index 121c2898..77183fc4 100644
--- a/cl/stmt.go
+++ b/cl/stmt.go
@@ -559,15 +559,11 @@ func compileTypeSwitchStmt(ctx *blockCtx, v *ast.TypeSwitchStmt) {
 			for t, other := range seen {
 				if T == nil && t == nil || T != nil && t != nil && types.Identical(T, t) {
 					haserr = true
-					pos := citem.Pos()
+					pos := ctx.Position(citem.Pos())
 					if T == types.Typ[types.UntypedNil] {
-						ctx.handleErrorf(
-							pos, "multiple nil cases in type switch (first at %v)",
-							ctx.Position(other.Pos()))
+						ctx.handleCodeErrorf(&pos, "multiple nil cases in type switch (first at %v)", ctx.Position(other.Pos()))
 					} else {
-						ctx.handleErrorf(
-							pos, "duplicate case %s in type switch\n\tprevious case at %v",
-							T, ctx.Position(other.Pos()))
+						ctx.handleCodeErrorf(&pos, "duplicate case %s in type switch\n\tprevious case at %v", T, ctx.Position(other.Pos()))
 					}
 				}
 			}
@@ -577,7 +573,8 @@ func compileTypeSwitchStmt(ctx *blockCtx, v *ast.TypeSwitchStmt) {
 		}
 		if c.List == nil {
 			if firstDefault != nil {
-				ctx.handleErrorf(c.Pos(), "multiple defaults in type switch (first at %v)", ctx.Position(firstDefault.Pos()))
+				pos := ctx.Position(c.Pos())
+				ctx.handleCodeErrorf(&pos, "multiple defaults in type switch (first at %v)", ctx.Position(firstDefault.Pos()))
 			} else {
 				firstDefault = c
 			}
@@ -651,7 +648,8 @@ func compileSwitchStmt(ctx *blockCtx, v *ast.SwitchStmt) {
 		}
 		if c.List == nil {
 			if firstDefault != nil {
-				ctx.handleErrorf(c.Pos(), "multiple defaults in switch (first at %v)", ctx.Position(firstDefault.Pos()))
+				pos := ctx.Position(c.Pos())
+				ctx.handleCodeErrorf(&pos, "multiple defaults in switch (first at %v)", ctx.Position(firstDefault.Pos()))
 			} else {
 				firstDefault = c
 			}
@@ -737,7 +735,8 @@ func compileBranchStmt(ctx *blockCtx, v *ast.BranchStmt) {
 	case token.CONTINUE:
 		ctx.cb.Continue(getLabel(ctx, label))
 	case token.FALLTHROUGH:
-		ctx.handleErrorf(v.Pos(), "fallthrough statement out of place")
+		pos := ctx.Position(v.Pos())
+		ctx.handleCodeErrorf(&pos, "fallthrough statement out of place")
 	default:
 		panic("unknown branch statement")
 	}
@@ -748,7 +747,8 @@ func getLabel(ctx *blockCtx, label *ast.Ident) *gox.Label {
 		if l, ok := ctx.cb.LookupLabel(label.Name); ok {
 			return l
 		}
-		ctx.handleErrorf(label.Pos(), "label %v is not defined", label.Name)
+		pos := ctx.Position(label.Pos())
+		ctx.handleCodeErrorf(&pos, "label %v is not defined", label.Name)
 	}
 	return nil
 }
diff --git a/cmd/internal/gopfmt/fmt.go b/cmd/internal/gopfmt/fmt.go
index d03045d0..40efc8a5 100644
--- a/cmd/internal/gopfmt/fmt.go
+++ b/cmd/internal/gopfmt/fmt.go
@@ -38,14 +38,15 @@ import (
 	xformat "github.com/goplus/gop/x/format"
 )
 
-// Cmd - gop go
+// Cmd - gop fmt
 var Cmd = &base.Command{
-	UsageLine: "gop fmt [-n --smart --mvgo] path ...",
+	UsageLine: "gop fmt [flags] path ...",
 	Short:     "Format Go+ packages",
 }
 
 var (
 	flag        = &Cmd.Flag
+	flagTest    = flag.Bool("t", false, "test if Go+ files are formatted or not.")
 	flagNotExec = flag.Bool("n", false, "prints commands that would be executed.")
 	flagMoveGo  = flag.Bool("mvgo", false, "move .go files to .gop files (only available in `--smart` mode).")
 	flagSmart   = flag.Bool("smart", false, "convert Go code style into Go+ style.")
@@ -56,6 +57,7 @@ func init() {
 }
 
 var (
+	testErrCnt = 0
 	procCnt    = 0
 	walkSubDir = false
 	rootDir    = ""
@@ -93,6 +95,10 @@ func gopfmt(path string, class, smart, mvgo bool) (err error) {
 		return
 	}
 	fmt.Println(path)
+	if *flagTest {
+		testErrCnt++
+		return nil
+	}
 	if mvgo {
 		newPath := strings.TrimSuffix(path, ".go") + ".gop"
 		if err = os.WriteFile(newPath, target, 0666); err != nil {
@@ -199,6 +205,14 @@ func runCmd(cmd *base.Command, args []string) {
 	if narg < 1 {
 		cmd.Usage(os.Stderr)
 	}
+	if *flagTest {
+		defer func() {
+			if testErrCnt > 0 {
+				fmt.Printf("total %d files are not formatted.\n", testErrCnt)
+				os.Exit(1)
+			}
+		}()
+	}
 	walker := newWalker()
 	for i := 0; i < narg; i++ {
 		path := flag.Arg(i)
diff --git a/x/build/build.go b/x/build/build.go
index 980e6064..9373c616 100644
--- a/x/build/build.go
+++ b/x/build/build.go
@@ -65,14 +65,14 @@ type Package struct {
 
 func (p *Package) ToSource() ([]byte, error) {
 	var buf bytes.Buffer
-	if err := p.Pkg.WriteTo(&buf); err != nil {
+	if err := gox.WriteTo(&buf, p.Pkg); err != nil {
 		return nil, err
 	}
 	return buf.Bytes(), nil
 }
 
 func (p *Package) ToAst() *goast.File {
-	return p.Pkg.ASTFile()
+	return gox.ASTFile(p.Pkg)
 }
 
 func ClassKind(fname string) (isProj, ok bool) {
diff --git a/x/typesutil/check.go b/x/typesutil/check.go
index 8febfaf8..6b6e2eb1 100644
--- a/x/typesutil/check.go
+++ b/x/typesutil/check.go
@@ -19,42 +19,12 @@ package typesutil
 import (
 	goast "go/ast"
 	"go/types"
-	"path/filepath"
-	"strings"
 
 	"github.com/goplus/gop/ast"
 	"github.com/goplus/gop/cl"
 	"github.com/goplus/gop/token"
-	"github.com/qiniu/x/log"
 )
 
-// -----------------------------------------------------------------------------
-
-type dbgFlags int
-
-const (
-	DbgFlagVerbose dbgFlags = 1 << iota
-	DbgFlagPrintError
-	DbgFlagDisableRecover
-	DbgFlagDefault = DbgFlagVerbose | DbgFlagPrintError
-	DbgFlagAll     = DbgFlagDefault | DbgFlagDisableRecover
-)
-
-var (
-	debugVerbose  bool
-	debugPrintErr bool
-)
-
-func SetDebug(flags dbgFlags) {
-	debugVerbose = (flags & DbgFlagVerbose) != 0
-	debugPrintErr = (flags & DbgFlagPrintError) != 0
-	if (flags & DbgFlagDisableRecover) != 0 {
-		cl.SetDisableRecover(true)
-	}
-}
-
-// -----------------------------------------------------------------------------
-
 type Project = cl.Project
 
 type Config struct {
@@ -111,20 +81,12 @@ func (p *Checker) Files(goFiles []*goast.File, gopFiles []*ast.File) error {
 	gopfs := make(map[string]*ast.File)
 	for _, goFile := range goFiles {
 		f := fset.File(goFile.Pos())
-		file := f.Name()
-		fname := filepath.Base(file)
-		if strings.HasPrefix(fname, "gop_autogen") {
-			continue
-		}
-		gofs[file] = goFile
+		gofs[f.Name()] = goFile
 	}
 	for _, gopFile := range gopFiles {
 		f := fset.File(gopFile.Pos())
 		gopfs[f.Name()] = gopFile
 	}
-	if debugVerbose {
-		log.Println("typesutil.Check:", pkgTypes.Path(), "gopFiles =", len(gopfs), "goFiles =", len(gofs))
-	}
 	pkg := &ast.Package{
 		Name:    pkgTypes.Name(),
 		Files:   gopfs,
@@ -143,11 +105,5 @@ func (p *Checker) Files(goFiles []*goast.File, gopFiles []*ast.File) error {
 		NoAutoGenMain:  true,
 		NoSkipConstant: true,
 	})
-	if debugPrintErr {
-		if err != nil {
-			log.Println("typesutil.Check err:", err)
-			log.SingleStack()
-		}
-	}
 	return err
 }
diff --git a/x/typesutil/gopinfo.go b/x/typesutil/typesutil.go
similarity index 97%
rename from x/typesutil/gopinfo.go
rename to x/typesutil/typesutil.go
index 0648ec4d..4f357561 100644
--- a/x/typesutil/gopinfo.go
+++ b/x/typesutil/typesutil.go
@@ -20,7 +20,6 @@ import (
 	"go/types"
 
 	"github.com/goplus/gop/ast"
-	"github.com/qiniu/x/log"
 )
 
 // -----------------------------------------------------------------------------
@@ -211,9 +210,6 @@ func (info gopRecorder) Instantiate(id *ast.Ident, inst types.Instance) {
 //
 // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
 func (info gopRecorder) Def(id *ast.Ident, obj types.Object) {
-	if debugVerbose {
-		log.Println("==> Def:", id, obj.Type())
-	}
 	info.Defs[id] = obj
 }
 
@@ -223,9 +219,6 @@ func (info gopRecorder) Def(id *ast.Ident, obj types.Object) {
 //
 // Invariant: Uses[id].Pos() != id.Pos()
 func (info gopRecorder) Use(id *ast.Ident, obj types.Object) {
-	if debugVerbose {
-		log.Println("==> Use:", id, obj.Type())
-	}
 	info.Uses[id] = obj
 }
 
@@ -238,9 +231,6 @@ func (info gopRecorder) Use(id *ast.Ident, obj types.Object) {
 //	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
 //	*ast.Field         anonymous parameter *Var (incl. unnamed results)
 func (info gopRecorder) Implicit(node ast.Node, obj types.Object) {
-	if debugVerbose {
-		log.Println("==> Implicit:", obj)
-	}
 	info.Implicits[node] = obj
 }
 
@@ -274,9 +264,6 @@ func (info gopRecorder) Select(e *ast.SelectorExpr, sel *types.Selection) {
 //	*ast.ForStmt
 //	*ast.RangeStmt
 func (info gopRecorder) Scope(n ast.Node, scope *types.Scope) {
-	if debugVerbose {
-		log.Println("==> Scope:", scope)
-	}
 	info.Scopes[n] = scope
 }
 


Test patch:
diff --git a/x/build/build_test.go b/x/build/build_test.go
index a677214e..72e46f14 100644
--- a/x/build/build_test.go
+++ b/x/build/build_test.go
@@ -515,7 +515,7 @@ func (i *emptyImporter) Import(path string) (*types.Package, error) {
 
 func TestContext(t *testing.T) {
 	ctx := build.NewContext(&emptyImporter{}, nil)
-	_, err := ctx.BuildFile("main.gop", `import "fmt"; fmt.Println "Go+"`)
+	_, err := ctx.BuildFile("main.gop", `println "Go+"`)
 	if err == nil {
 		t.Fatal("BuildFile: no error?")
 	}