Repository: goplus/gop
Pull request #2323 (2025-05-06 06:18:45)

builtin: fatal, errorln


Patch:
diff --git a/builtin/iox/enum.go b/builtin/osx/osx.go
similarity index 66%
rename from builtin/iox/enum.go
rename to builtin/osx/osx.go
index eec0c269..e7d3a40d 100644
--- a/builtin/iox/enum.go
+++ b/builtin/osx/osx.go
@@ -11,19 +11,36 @@
  limitations under the License.
 */
 
-package iox
+package osx
 
 import (
 	"bufio"
+	"fmt"
 	"io"
+	"os"
 )
 
 // ----------------------------------------------------------------------------
 
+// Errorln formats and prints to standard error.
+func Errorln(args ...any) {
+	fmt.Fprintln(os.Stderr, args...)
+}
+
+// Fatal formats and prints to standard error.
+func Fatal(args ...any) {
+	fmt.Fprintln(os.Stderr, args...)
+	os.Exit(1)
+}
+
+// ----------------------------------------------------------------------------
+
+// LineIter is an iterator that reads lines from a reader.
 type LineIter struct {
 	s *bufio.Scanner
 }
 
+// Next reads the next line from the iterator.
 func (it LineIter) Next() (line string, ok bool) {
 	s := it.s
 	if ok = s.Scan(); ok {
@@ -34,6 +51,7 @@ func (it LineIter) Next() (line string, ok bool) {
 	return
 }
 
+// EnumLines returns a LineIter that reads lines from the given reader.
 func EnumLines(r io.Reader) LineIter {
 	scanner := bufio.NewScanner(r)
 	return LineIter{scanner}
@@ -41,10 +59,12 @@ func EnumLines(r io.Reader) LineIter {
 
 // ----------------------------------------------------------------------------
 
+// BLineIter is an iterator that reads lines from a reader.
 type BLineIter struct {
 	s *bufio.Scanner
 }
 
+// Next reads the next line from the iterator.
 func (it BLineIter) Next() (line []byte, ok bool) {
 	s := it.s
 	if ok = s.Scan(); ok {
@@ -55,6 +75,7 @@ func (it BLineIter) Next() (line []byte, ok bool) {
 	return
 }
 
+// EnumBLines returns a BLineIter that reads lines from the given reader.
 func EnumBLines(r io.Reader) BLineIter {
 	scanner := bufio.NewScanner(r)
 	return BLineIter{scanner}
@@ -62,6 +83,7 @@ func EnumBLines(r io.Reader) BLineIter {
 
 // ----------------------------------------------------------------------------
 
+// LineReader is a wrapper around io.Reader that provides a method to read lines.
 type LineReader struct {
 	r io.Reader
 }
@@ -70,12 +92,14 @@ func (p LineReader) Gop_Enum() LineIter {
 	return EnumLines(p.r)
 }
 
+// Lines returns a LineReader that reads lines from the given reader.
 func Lines(r io.Reader) LineReader {
 	return LineReader{r}
 }
 
 // ----------------------------------------------------------------------------
 
+// BLineReader is a wrapper around io.Reader that provides a method to read lines.
 type BLineReader struct {
 	r io.Reader
 }
@@ -84,6 +108,7 @@ func (p BLineReader) Gop_Enum() BLineIter {
 	return EnumBLines(p.r)
 }
 
+// BLines returns a BLineReader that reads lines from the given reader.
 func BLines(r io.Reader) BLineReader {
 	return BLineReader{r}
 }
diff --git a/cl/builtin.go b/cl/builtin.go
index 6becb512..bcec7f62 100644
--- a/cl/builtin.go
+++ b/cl/builtin.go
@@ -38,7 +38,7 @@ func initBuiltinFns(builtin *types.Package, scope *types.Scope, pkg gogen.PkgRef
 	}
 }
 
-func initBuiltin(_ *gogen.Package, builtin *types.Package, os, fmt, ng, iox, buil, reflect gogen.PkgRef) {
+func initBuiltin(_ *gogen.Package, builtin *types.Package, os, fmt, ng, osx, buil, reflect gogen.PkgRef) {
 	scope := builtin.Scope()
 	if ng.Types != nil {
 		typs := []string{"bigint", "bigrat", "bigfloat"}
@@ -62,11 +62,11 @@ func initBuiltin(_ *gogen.Package, builtin *types.Package, os, fmt, ng, iox, bui
 			"open", "create",
 		})
 	}
-	if iox.Types != nil {
-		initBuiltinFns(builtin, scope, iox, []string{
-			"lines",
+	if osx.Types != nil {
+		initBuiltinFns(builtin, scope, osx, []string{
+			"lines", "errorln", "fatal",
 		})
-		scope.Insert(gogen.NewOverloadFunc(token.NoPos, builtin, "blines", iox.Ref("BLines")))
+		scope.Insert(gogen.NewOverloadFunc(token.NoPos, builtin, "blines", osx.Ref("BLines")))
 	}
 	if reflect.Types != nil {
 		scope.Insert(gogen.NewOverloadFunc(token.NoPos, builtin, "type", reflect.Ref("TypeOf")))
@@ -84,7 +84,7 @@ func newBuiltinDefault(pkg *gogen.Package, conf *gogen.Config) *types.Package {
 	reflect := pkg.TryImport("reflect")
 	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")
+	osx := pkg.TryImport("github.com/goplus/gop/builtin/osx")
 	strx := pkg.TryImport("github.com/qiniu/x/stringutil")
 	stringslice := pkg.TryImport("github.com/goplus/gop/builtin/stringslice")
 	pkg.TryImport("strconv")
@@ -97,7 +97,7 @@ func newBuiltinDefault(pkg *gogen.Package, conf *gogen.Config) *types.Package {
 			}
 		}
 	}
-	initBuiltin(pkg, builtin, os, fmt, ng, iox, buil, reflect)
+	initBuiltin(pkg, builtin, os, fmt, ng, osx, buil, reflect)
 	gogen.InitBuiltin(pkg, builtin, conf)
 	if strx.Types != nil {
 		ti := pkg.BuiltinTI(types.Typ[types.String])
diff --git a/cl/compile.go b/cl/compile.go
index 20b3a69d..26bb202d 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -490,7 +490,7 @@ const (
 )
 
 const (
-	ioxPkgPath = "github.com/goplus/gop/builtin/iox"
+	osxPkgPath = "github.com/goplus/gop/builtin/osx"
 )
 
 // NewPackage creates a Go+ package instance.
@@ -520,7 +520,7 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gogen.Packag
 		NewBuiltin:      newBuiltinDefault,
 		DefaultGoFile:   defaultGoFile,
 		NoSkipConstant:  conf.NoSkipConstant,
-		PkgPathIox:      ioxPkgPath,
+		PkgPathIox:      osxPkgPath,
 		DbgPositioner:   interp,
 	}
 	var rec *goxRecorder


Test patch:
diff --git a/cl/_testgop/fatal/in.gop b/cl/_testgop/fatal/in.gop
new file mode 100644
index 00000000..3dd8d1e5
--- /dev/null
+++ b/cl/_testgop/fatal/in.gop
@@ -0,0 +1,8 @@
+import "os"
+
+f, err := os.open("hello.txt")
+if err != nil {
+    errorln "[WARN] an error"
+    fatal "open file failed: ${err}"
+}
+f.close
diff --git a/cl/_testgop/fatal/out.go b/cl/_testgop/fatal/out.go
new file mode 100644
index 00000000..0795ed2b
--- /dev/null
+++ b/cl/_testgop/fatal/out.go
@@ -0,0 +1,16 @@
+package main
+
+import (
+	"github.com/goplus/gop/builtin/osx"
+	"github.com/qiniu/x/stringutil"
+	"os"
+)
+
+func main() {
+	f, err := os.Open("hello.txt")
+	if err != nil {
+		osx.Errorln("[WARN] an error")
+		osx.Fatal(stringutil.Concat("open file failed: ", err.Error()))
+	}
+	f.Close()
+}
diff --git a/cl/compile_gop_test.go b/cl/compile_gop_test.go
index 3a799df7..d2e09520 100644
--- a/cl/compile_gop_test.go
+++ b/cl/compile_gop_test.go
@@ -1050,13 +1050,13 @@ for line <- open("foo.txt")! {
 
 import (
 	"fmt"
-	"github.com/goplus/gop/builtin/iox"
+	"github.com/goplus/gop/builtin/osx"
 	"github.com/qiniu/x/errors"
 	"os"
 )
 
 func main() {
-	for _gop_it := iox.EnumLines(func() (_gop_ret *os.File) {
+	for _gop_it := osx.EnumLines(func() (_gop_ret *os.File) {
 		var _gop_err error
 		_gop_ret, _gop_err = os.Open("foo.txt")
 		if _gop_err != nil {
@@ -1087,12 +1087,12 @@ for line <- os.Stdin {
 
 import (
 	"fmt"
-	"github.com/goplus/gop/builtin/iox"
+	"github.com/goplus/gop/builtin/osx"
 	"os"
 )
 
 func main() {
-	for _gop_it := iox.EnumLines(os.Stdin); ; {
+	for _gop_it := osx.EnumLines(os.Stdin); ; {
 		var _gop_ok bool
 		line, _gop_ok := _gop_it.Next()
 		if !_gop_ok {
@@ -1117,14 +1117,14 @@ for line <- lines(r) {
 
 import (
 	"fmt"
-	"github.com/goplus/gop/builtin/iox"
+	"github.com/goplus/gop/builtin/osx"
 	"io"
 )
 
 var r io.Reader
 
 func main() {
-	for _gop_it := iox.Lines(r).Gop_Enum(); ; {
+	for _gop_it := osx.Lines(r).Gop_Enum(); ; {
 		var _gop_ok bool
 		line, _gop_ok := _gop_it.Next()
 		if !_gop_ok {
diff --git a/x/build/build_test.go b/x/build/build_test.go
index 3c03bbb5..1536052f 100644
--- a/x/build/build_test.go
+++ b/x/build/build_test.go
@@ -264,14 +264,14 @@ for line <- lines(r) {
 
 import (
 	"fmt"
-	"github.com/goplus/gop/builtin/iox"
+	"github.com/goplus/gop/builtin/osx"
 	"io"
 )
 
 var r io.Reader
 
 func main() {
-	for _gop_it := iox.Lines(r).Gop_Enum(); ; {
+	for _gop_it := osx.Lines(r).Gop_Enum(); ; {
 		var _gop_ok bool
 		line, _gop_ok := _gop_it.Next()
 		if !_gop_ok {