Repository: goplus/gop
Pull request #1471 (2023-10-18 08:09:41)

gop/env.Installed(); gop/ast.File.Pos()


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index 57f498d7..2a8ae547 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -1123,7 +1123,7 @@ type FileType = int16
 // are "free-floating" (see also issues #18593, #20744).
 type File struct {
 	Doc     *CommentGroup // associated documentation; or nil
-	Package token.Pos     // position of "package" keyword
+	Package token.Pos     // position of "package" keyword; or NoPos
 	Name    *Ident        // package name
 	Decls   []Decl        // top-level declarations; or nil
 
@@ -1145,7 +1145,12 @@ func (f *File) NoEntrypoint() bool {
 }
 
 // Pos returns position of first character belonging to the node.
-func (f *File) Pos() token.Pos { return f.Package }
+func (f *File) Pos() token.Pos {
+	if f.Package != token.NoPos {
+		return f.Package
+	}
+	return f.Name.NamePos
+}
 
 // End returns position of first character immediately after the node.
 func (f *File) End() token.Pos {
diff --git a/cl/internal/spx/game.go b/cl/internal/spx/game.go
index 9367eae7..a201d089 100644
--- a/cl/internal/spx/game.go
+++ b/cl/internal/spx/game.go
@@ -41,13 +41,6 @@ func (p *MyGame) Broadcast__2(msg string, data interface{}, wait bool) {
 func (p *MyGame) Play(media string, wait ...bool) {
 }
 
-func (p *MyGame) sendMessage(data interface{}) {
-}
-
-func (p *MyGame) SendMessage(data interface{}) {
-	p.sendMessage(data)
-}
-
 func Gopt_MyGame_Run(game interface{}, resource string) error {
 	return nil
 }
diff --git a/cl/internal/spx/pkg/pkg.go b/cl/internal/spx/pkg/pkg.go
deleted file mode 100644
index 649406b5..00000000
--- a/cl/internal/spx/pkg/pkg.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package pkg
-
-var (
-	GopPackage = true
-)
-
-type Vector struct {
-	x int
-	y int
-}
-
-func NewVector(x, y int) *Vector {
-	return &Vector{x, y}
-}
-
-func (v *Vector) Add__0(x int, y int) {
-	v.x += x
-	v.y += y
-}
-
-func (v *Vector) Add__1(o *Vector) {
-	v.Add__0(o.x, o.y)
-}
diff --git a/cl/internal/spx/sprite.go b/cl/internal/spx/sprite.go
index 00963bb8..9bbd27fd 100644
--- a/cl/internal/spx/sprite.go
+++ b/cl/internal/spx/sprite.go
@@ -16,12 +16,7 @@
 
 package spx
 
-import (
-	"github.com/goplus/gop/cl/internal/spx/pkg"
-)
-
 type Sprite struct {
-	pos pkg.Vector
 }
 
 func (p *Sprite) SetCostume(costume interface{}) {
@@ -30,10 +25,6 @@ func (p *Sprite) SetCostume(costume interface{}) {
 func (p *Sprite) Say(msg string, secs ...float64) {
 }
 
-func (p *Sprite) Position() *pkg.Vector {
-	return &p.pos
-}
-
 func Gopt_Sprite_Clone__0(sprite interface{}) {
 }
 
diff --git a/env/build.go b/env/build.go
index b7325414..1405cabf 100644
--- a/env/build.go
+++ b/env/build.go
@@ -22,6 +22,7 @@ var (
 	buildDate string
 )
 
+// BuildDate returns build date of the `gop` command.
 func BuildDate() string {
 	return buildDate
 }
diff --git a/env/gop_nonwindows.go b/env/gop_nonwindows.go
new file mode 100644
index 00000000..482e829f
--- /dev/null
+++ b/env/gop_nonwindows.go
@@ -0,0 +1,24 @@
+//go:build !windows
+// +build !windows
+
+/*
+ * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package env
+
+func isGopCmd(fname string) bool {
+	return fname == "gop"
+}
diff --git a/env/path.go b/env/path.go
index d52cf90a..1f071efa 100644
--- a/env/path.go
+++ b/env/path.go
@@ -28,6 +28,8 @@ var (
 	defaultGopRoot string
 )
 
+// GOPROOT returns the root of the Go+ tree. It uses the GOPROOT environment variable,
+// if set at process start, or else the root used during the Go+ build.
 func GOPROOT() string {
 	gopRoot, err := findGopRoot()
 	if err != nil {
diff --git a/env/sys_windows.go b/env/sys_windows.go
index 40149490..1975f0cd 100644
--- a/env/sys_windows.go
+++ b/env/sys_windows.go
@@ -19,3 +19,7 @@ package env
 const (
 	envHOME = "USERPROFILE"
 )
+
+func isGopCmd(fname string) bool {
+	return fname == "gop.exe" || fname == "gop"
+}
diff --git a/env/version.go b/env/version.go
index 5ce9b61e..e70a940d 100644
--- a/env/version.go
+++ b/env/version.go
@@ -17,6 +17,10 @@
 package env
 
 import (
+	"bytes"
+	"os"
+	"os/exec"
+	"path/filepath"
 	"strings"
 )
 
@@ -31,9 +35,42 @@ var (
 )
 
 func init() {
-	if buildVersion != "" && !strings.HasPrefix(buildVersion, "v"+MainVersion+".") {
-		panic("Invalid buildVersion: " + buildVersion)
+	initEnv()
+}
+
+func initEnv() {
+	if buildVersion == "" {
+		initEnvByGop()
+		return
 	}
+	if !strings.HasPrefix(buildVersion, "v"+MainVersion+".") {
+		panic("gop/env: [FATAL] Invalid buildVersion: " + buildVersion)
+	}
+}
+
+func initEnvByGop() {
+	if fname := filepath.Base(os.Args[0]); !isGopCmd(fname) {
+		if ret, err := gopEnv(); err == nil {
+			parts := strings.SplitN(strings.TrimRight(ret, "\n"), "\n", 3)
+			if len(parts) == 3 {
+				buildVersion, buildDate, defaultGopRoot = parts[0], parts[1], parts[2]
+			}
+		}
+	}
+}
+
+var gopEnv = func() (string, error) {
+	var b bytes.Buffer
+	cmd := exec.Command("gop", "env", "GOPVERSION", "BUILDDATE", "GOPROOT")
+	cmd.Stdout = &b
+	err := cmd.Run()
+	return b.String(), err
+}
+
+// Installed checks is `gop` installed or not.
+// If returns false, it means `gop` is not installed or not in PATH.
+func Installed() bool {
+	return buildVersion != ""
 }
 
 // Version returns the GoPlus tree's version string.
diff --git a/go.mod b/go.mod
index 9ae30e0d..95c7ec3f 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.17
 require (
 	github.com/fsnotify/fsnotify v1.6.0
 	github.com/goplus/c2go v0.7.16
-	github.com/goplus/gox v1.12.2-0.20231012035644-c3bf89ec9e2b
+	github.com/goplus/gox v1.12.5
 	github.com/goplus/mod v0.11.7
 	github.com/qiniu/x v1.13.1
 	golang.org/x/tools v0.14.0
diff --git a/go.sum b/go.sum
index 80ab5bf2..50d77c9b 100644
--- a/go.sum
+++ b/go.sum
@@ -7,8 +7,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
 github.com/goplus/c2go v0.7.16 h1:B9jRNNytoq7yDBQOZSm2qENQhRQMfNhgOea5XHWNUnI=
 github.com/goplus/c2go v0.7.16/go.mod h1:XODEFX2PeEEJXNLLdykWeZgMSaKJ51fVm+C9IM3FxNQ=
 github.com/goplus/gox v1.12.1/go.mod h1:wymoQJ7ydd42cTlaXb4wNbvn4LlKjR+j8PZehI7v1zQ=
-github.com/goplus/gox v1.12.2-0.20231012035644-c3bf89ec9e2b h1:5jCLZcnLj2jOTOw5j979XMoqeWI1ghZVnfuwmKbe5Eo=
-github.com/goplus/gox v1.12.2-0.20231012035644-c3bf89ec9e2b/go.mod h1:ferIrvJSoXae8gABk5Z4olEzfAxZpUy4hD91Vm5E/qs=
+github.com/goplus/gox v1.12.5 h1:YkdsZDIOW3DZLJctWYKVzdsqMeuCYNn7J4BsFi6B058=
+github.com/goplus/gox v1.12.5/go.mod h1:ferIrvJSoXae8gABk5Z4olEzfAxZpUy4hD91Vm5E/qs=
 github.com/goplus/mod v0.11.5/go.mod h1:NDC5E+XOT8vcJCMjqKhLDJHTHX7lyVN4Vbfi2U7dBhs=
 github.com/goplus/mod v0.11.7 h1:OTGFi/Jk0qmTy3ih8u3BQ6CbtcaPlTrJBlTacnge0jE=
 github.com/goplus/mod v0.11.7/go.mod h1:yl2QncBKTdXk+8UaNsdo4u2zSpGEJYA5JKjgD3K2h00=
diff --git a/parser/parser.go b/parser/parser.go
index b89ec37a..5de4dc46 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -3709,7 +3709,7 @@ func (p *parser) parseFile() *ast.File {
 	} else {
 		noPkgDecl = true
 		pos = token.NoPos
-		ident = ast.NewIdent("main")
+		ident = &ast.Ident{NamePos: p.file.Pos(0), Name: "main"}
 	}
 
 	p.openScope()


Test patch:
diff --git a/cl/compile_spx_test.go b/cl/compile_spx_test.go
index 9786376e..0451c301 100644
--- a/cl/compile_spx_test.go
+++ b/cl/compile_spx_test.go
@@ -654,78 +654,3 @@ func (this *Kai) onCloned() {
 }
 `, "Game.tgmx", "Kai.tspx")
 }
-
-func TestSpxErrorSel(t *testing.T) {
-	gopSpxErrorTestEx(t, `./Kai.tspx:2:9: this.pos undefined (type *Kai has no field or method pos)`, `
-println "hi"
-`, `
-println this.pos
-`, "Game.tgmx", "Kai.tspx")
-}
-
-func TestSpxMethodSel(t *testing.T) {
-	gopSpxTestEx(t, `
-sendMessage "Hi"
-`, `
-func onMsg(msg string) {
-}
-`, `package main
-
-import spx "github.com/goplus/gop/cl/internal/spx"
-
-type Game struct {
-	*spx.MyGame
-}
-
-func (this *Game) MainEntry() {
-	this.SendMessage("Hi")
-}
-func main() {
-	spx.Gopt_MyGame_Main(new(Game))
-}
-
-type Kai struct {
-	spx.Sprite
-	*Game
-}
-
-func (this *Kai) onMsg(msg string) {
-}
-`, "Game.tgmx", "Kai.tspx")
-}
-
-func TestSpxPkgOverload(t *testing.T) {
-	gopSpxTestEx(t, `
-println "Hi"
-`, `
-func onMsg(msg string) {
-	this.position.add 100,200
-}
-`, `package main
-
-import (
-	fmt "fmt"
-	spx "github.com/goplus/gop/cl/internal/spx"
-)
-
-type Game struct {
-	*spx.MyGame
-}
-
-func (this *Game) MainEntry() {
-	fmt.Println("Hi")
-}
-func main() {
-	spx.Gopt_MyGame_Main(new(Game))
-}
-
-type Kai struct {
-	spx.Sprite
-	*Game
-}
-
-func (this *Kai) onMsg(msg string) {
-	this.Position().Add__0(100, 200)
-}
-`, "Game.tgmx", "Kai.tspx")
-}
diff --git a/cl/outline/cl/compile_spx_test.go b/cl/outline/cl/compile_spx_test.go
index 583afaf9..e730234f 100644
--- a/cl/outline/cl/compile_spx_test.go
+++ b/cl/outline/cl/compile_spx_test.go
@@ -650,74 +650,3 @@ func (this *Kai) onCloned() {
 }
 `, "Game.tgmx", "Kai.tspx")
 }
-
-func TestSpxErrorSel(t *testing.T) {
-	gopSpxErrorTestEx(t, `./Kai.tspx:2:9: this.pos undefined (type *Kai has no field or method pos)`, `
-println "hi"
-`, `
-println this.pos
-`, "Game.tgmx", "Kai.tspx")
-}
-
-func TestSpxMethodSel(t *testing.T) {
-	gopSpxTestEx(t, `
-sendMessage "Hi"
-`, `
-func onMsg(msg string) {
-}
-`, `package main
-
-import spx "github.com/goplus/gop/cl/internal/spx"
-
-type Game struct {
-	*spx.MyGame
-}
-type Kai struct {
-	spx.Sprite
-	*Game
-}
-
-func (this *Game) MainEntry() {
-	this.SendMessage("Hi")
-}
-func (this *Kai) onMsg(msg string) {
-}
-func main() {
-	spx.Gopt_MyGame_Main(new(Game))
-}
-`, "Game.tgmx", "Kai.tspx")
-}
-
-func TestSpxPkgOverload(t *testing.T) {
-	gopSpxTestEx(t, `
-println "Hi"
-`, `
-func onMsg(msg string) {
-	this.position.add 100,200
-}
-`, `package main
-
-import (
-	fmt "fmt"
-	spx "github.com/goplus/gop/cl/internal/spx"
-)
-
-type Game struct {
-	*spx.MyGame
-}
-type Kai struct {
-	spx.Sprite
-	*Game
-}
-
-func (this *Game) MainEntry() {
-	fmt.Println("Hi")
-}
-func (this *Kai) onMsg(msg string) {
-	this.Position().Add__0(100, 200)
-}
-func main() {
-	spx.Gopt_MyGame_Main(new(Game))
-}
-`, "Game.tgmx", "Kai.tspx")
-}
diff --git a/env/path_test.go b/env/path_test.go
index a38dc654..834235b3 100644
--- a/env/path_test.go
+++ b/env/path_test.go
@@ -17,7 +17,6 @@
 package env
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -39,12 +38,13 @@ func findGoModFile(dir string) (modfile string, noCacheFile bool, err error) {
 
 // Common testing directory structure:
 // testing_root/
-//   src/
-//	   subdir/
-//   valid_goproot/
-//	   go.mod
-//	   go.sum
-//     cmd/gop/
+//
+//	  src/
+//		   subdir/
+//	  valid_goproot/
+//		   go.mod
+//		   go.sum
+//	    cmd/gop/
 func makeTestDir(t *testing.T) (root string, src string, gopRoot string) {
 	root, _ = filepath.EvalSymlinks(t.TempDir())
 	src = filepath.Join(root, "src")
@@ -57,12 +57,12 @@ func makeTestDir(t *testing.T) (root string, src string, gopRoot string) {
 func makeValidGopRoot(root string) {
 	os.Mkdir(root, 0755)
 	os.MkdirAll(filepath.Join(root, "cmd/gop"), 0755)
-	ioutil.WriteFile(filepath.Join(root, "go.mod"), []byte(""), 0644)
-	ioutil.WriteFile(filepath.Join(root, "go.sum"), []byte(""), 0644)
+	os.WriteFile(filepath.Join(root, "go.mod"), []byte(""), 0644)
+	os.WriteFile(filepath.Join(root, "go.sum"), []byte(""), 0644)
 }
 
 func writeDummyFile(path string) {
-	ioutil.WriteFile(path, []byte(""), 0644)
+	os.WriteFile(path, []byte(""), 0644)
 }
 
 func cleanup() {
diff --git a/env/version_test.go b/env/version_test.go
index 5b51422d..7beb6b9f 100644
--- a/env/version_test.go
+++ b/env/version_test.go
@@ -16,21 +16,53 @@
 
 package env
 
-import "testing"
+import (
+	"os"
+	"path/filepath"
+	"testing"
+)
 
-func TestVersion(t *testing.T) {
-	if Version() != "v"+MainVersion+".x" {
-		t.Fatal("TestVersion failed:", Version())
+func TestPanic(t *testing.T) {
+	t.Run("initEnvPanic", func(t *testing.T) {
+		defer func() {
+			if e := recover(); e == nil {
+				t.Fatal("initEnvPanic: no panic?")
+			}
+		}()
+		buildVersion = "v1.2"
+		initEnv()
+	})
+	t.Run("GOPROOT panic", func(t *testing.T) {
+		defer func() {
+			if e := recover(); e == nil {
+				t.Fatal("GOPROOT: no panic?")
+			}
+		}()
+		defaultGopRoot = ""
+		os.Setenv(envGOPROOT, "")
+		GOPROOT()
+	})
+}
+
+func TestEnv(t *testing.T) {
+	gopEnv = func() (string, error) {
+		wd, _ := os.Getwd()
+		root := filepath.Dir(wd)
+		return "v1.0.0-beta1\n2023-10-18_17-45-50\n" + root + "\n", nil
+	}
+	buildVersion = ""
+	initEnv()
+	if !Installed() {
+		t.Fatal("not Installed")
 	}
-	buildVersion = "v1.0.0-beta1"
-	if Version() != buildVersion {
+	if Version() != "v1.0.0-beta1" {
 		t.Fatal("TestVersion failed:", Version())
 	}
 	buildVersion = ""
-}
-
-func TestBuild(t *testing.T) {
-	if BuildDate() != "" {
+	if Version() != "v"+MainVersion+".x" {
+		t.Fatal("TestVersion failed:", Version())
+	}
+	if BuildDate() != "2023-10-18_17-45-50" {
 		t.Fatal("BuildInfo failed:", BuildDate())
 	}
 }