Repository: goplus/gop
Pull request #1432 (2023-09-28 22:09:16)

Outline


Patch:
diff --git a/cl/compile.go b/cl/compile.go
index 3f6286c8..0249bd0f 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -99,8 +99,11 @@ type Config struct {
 	// NoAutoGenMain = true means not to auto generate main func is no entry.
 	NoAutoGenMain bool
 
-	// NoSkipConstant = true means disable optimization of skip constants
+	// NoSkipConstant = true means to disable optimization of skipping constants.
 	NoSkipConstant bool
+
+	// Outline = true means to skip compiling function bodies.
+	Outline bool
 }
 
 type nodeInterp struct {
@@ -153,9 +156,9 @@ type baseLoader struct {
 	start token.Pos
 }
 
-func initLoader(ctx *pkgCtx, syms map[string]loader, start token.Pos, name string, fn func(), genCode bool) {
+func initLoader(ctx *pkgCtx, syms map[string]loader, start token.Pos, name string, fn func(), genBody bool) {
 	if name == "_" {
-		if genCode {
+		if genBody {
 			ctx.inits = append(ctx.inits, fn)
 		}
 		return
@@ -244,14 +247,15 @@ func doInitMethods(ld *typeLoader) {
 type pkgCtx struct {
 	*nodeInterp
 	*gmxSettings
-	cpkgs    *cpackages.Importer
-	syms     map[string]loader
+	cpkgs *cpackages.Importer
+	syms  map[string]loader
+	inits []func()
+	tylds []*typeLoader
+	errs  errors.List
+
 	generics map[string]bool // generic type record
-	inits    []func()
-	tylds    []*typeLoader
-	idents   []*ast.Ident // toType ident recored
-	errs     errors.List
-	inInst   int // toType in generic instance
+	idents   []*ast.Ident    // toType ident recored
+	inInst   int             // toType in generic instance
 }
 
 type blockCtx struct {
@@ -430,7 +434,7 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gox.Package,
 			pkg: p, pkgCtx: ctx, cb: p.CB(), fset: p.Fset, targetDir: targetDir,
 			imports: make(map[string]*gox.PkgRef),
 		}
-		preloadFile(p, ctx, fpath, f, false)
+		preloadFile(p, ctx, fpath, f, false, false)
 	}
 
 	// sort files
@@ -533,8 +537,8 @@ func loadFile(ctx *pkgCtx, f *ast.File) {
 	}
 }
 
-func getGoFile(file string, genCode bool) string {
-	if genCode {
+func genGoFile(file string, gopFile bool) string {
+	if gopFile {
 		if strings.HasSuffix(file, "_test.gop") {
 			return testingGoFile
 		}
@@ -658,7 +662,7 @@ func preloadGopFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, con
 			})
 		}
 	}
-	preloadFile(p, ctx, file, f, true)
+	preloadFile(p, ctx, file, f, true, !conf.Outline)
 }
 
 func parseTypeEmbedName(typ ast.Expr) *ast.Ident {
@@ -675,10 +679,10 @@ retry:
 	return nil
 }
 
-func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, genCode bool) {
+func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, gopFile, genFnBody bool) {
 	parent := ctx.pkgCtx
 	syms := parent.syms
-	goFile := getGoFile(file, genCode)
+	goFile := genGoFile(file, gopFile)
 	old, _ := p.SetCurFile(goFile, true)
 	defer p.RestoreCurFile(old)
 	for _, decl := range f.Decls {
@@ -693,21 +697,14 @@ func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, genCod
 				}
 			}
 			if d.Recv == nil {
-				var name = d.Name
-				var fn func()
-				if genCode {
-					fn = func() {
-						old, _ := p.SetCurFile(goFile, true)
-						defer p.RestoreCurFile(old)
-						loadFunc(ctx, nil, d)
-					}
-				} else {
-					fn = func() {
-						declFunc(ctx, nil, d)
-					}
+				name := d.Name
+				fn := func() {
+					old, _ := p.SetCurFile(goFile, true)
+					defer p.RestoreCurFile(old)
+					loadFunc(ctx, nil, d, genFnBody)
 				}
 				if name.Name == "init" {
-					if genCode {
+					if genFnBody {
 						if debugLoad {
 							log.Println("==> Preload func init")
 						}
@@ -717,29 +714,20 @@ func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, genCod
 					if debugLoad {
 						log.Println("==> Preload func", name.Name)
 					}
-					initLoader(parent, syms, name.Pos(), name.Name, fn, genCode)
+					initLoader(parent, syms, name.Pos(), name.Name, fn, genFnBody)
 				}
 			} else {
 				if name, ok := getRecvTypeName(parent, d.Recv, true); ok {
 					if debugLoad {
 						log.Printf("==> Preload method %s.%s\n", name, d.Name.Name)
 					}
-					var ld = getTypeLoader(parent, syms, token.NoPos, name)
-					var fn func()
-					if genCode {
-						fn = func() {
-							old, _ := p.SetCurFile(goFile, true)
-							defer p.RestoreCurFile(old)
-							doInitType(ld)
-							recv := toRecv(ctx, d.Recv)
-							loadFunc(ctx, recv, d)
-						}
-					} else {
-						fn = func() {
-							doInitType(ld)
-							recv := toRecv(ctx, d.Recv)
-							declFunc(ctx, recv, d)
-						}
+					ld := getTypeLoader(parent, syms, token.NoPos, name)
+					fn := func() {
+						old, _ := p.SetCurFile(goFile, true)
+						defer p.RestoreCurFile(old)
+						doInitType(ld)
+						recv := toRecv(ctx, d.Recv)
+						loadFunc(ctx, recv, d, genFnBody)
 					}
 					ld.methods = append(ld.methods, fn)
 				}
@@ -758,7 +746,7 @@ func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, genCod
 						log.Println("==> Preload type", name)
 					}
 					ld := getTypeLoader(parent, syms, t.Name.Pos(), name)
-					if genCode {
+					if gopFile {
 						ld.typ = func() {
 							old, _ := p.SetCurFile(goFile, true)
 							defer p.RestoreCurFile(old)
@@ -867,40 +855,7 @@ func aliasType(pkg *types.Package, pos token.Pos, name string, typ types.Type) {
 	pkg.Scope().Insert(o)
 }
 
-func declFunc(ctx *blockCtx, recv *types.Var, d *ast.FuncDecl) {
-	name := d.Name.Name
-	if debugLoad {
-		if recv == nil {
-			log.Println("==> Load func", name)
-		} else {
-			log.Printf("==> Load method %v.%s\n", recv.Type(), name)
-		}
-	}
-	if name == "_" {
-		return
-	}
-	pkg := ctx.pkg.Types
-	sig := toFuncType(ctx, d.Type, recv, d)
-	fn := types.NewFunc(d.Pos(), pkg, name, sig)
-	if recv != nil {
-		typ := recv.Type()
-		switch t := typ.(type) {
-		case *types.Named:
-			t.AddMethod(fn)
-			return
-		case *types.Pointer:
-			if tt, ok := t.Elem().(*types.Named); ok {
-				tt.AddMethod(fn)
-				return
-			}
-		}
-		log.Panicf("invalid receiver type %v (%v is not a defined type)\n", typ, typ)
-	} else {
-		pkg.Scope().Insert(fn)
-	}
-}
-
-func loadFunc(ctx *blockCtx, recv *types.Var, d *ast.FuncDecl) {
+func loadFunc(ctx *blockCtx, recv *types.Var, d *ast.FuncDecl, genBody bool) {
 	name := d.Name.Name
 	if debugLoad {
 		if recv == nil {
@@ -936,13 +891,15 @@ func loadFunc(ctx *blockCtx, recv *types.Var, d *ast.FuncDecl) {
 	if d.Doc != nil {
 		fn.SetComments(d.Doc)
 	}
-	if body := d.Body; body != nil {
-		if recv != nil {
-			ctx.inits = append(ctx.inits, func() { // interface issue: #795
+	if genBody {
+		if body := d.Body; body != nil {
+			if recv != nil {
+				ctx.inits = append(ctx.inits, func() { // interface issue: #795
+					loadFuncBody(ctx, fn, body, d)
+				})
+			} else {
 				loadFuncBody(ctx, fn, body, d)
-			})
-		} else {
-			loadFuncBody(ctx, fn, body, d)
+			}
 		}
 	}
 }


Test patch:
diff --git a/cl/builtin_test.go b/cl/builtin_test.go
index 5721ecf9..b20381db 100644
--- a/cl/builtin_test.go
+++ b/cl/builtin_test.go
@@ -119,6 +119,30 @@ func TestGetStringConst(t *testing.T) {
 	}
 }
 
+func TestSpxRef(t *testing.T) {
+	defer func() {
+		if e := recover(); !isError(e, "foo.bar not found") {
+			t.Fatal("TestSpxRef:", e)
+		}
+	}()
+	pkg := &gox.PkgRef{
+		Types: types.NewPackage("foo", "foo"),
+	}
+	spxRef(pkg, "bar")
+}
+
+func isError(e interface{}, msg string) bool {
+	if e != nil {
+		if err, ok := e.(error); ok {
+			return err.Error() == msg
+		}
+		if err, ok := e.(string); ok {
+			return err == msg
+		}
+	}
+	return false
+}
+
 func TestGmxSettings(t *testing.T) {
 	pkg := gox.NewPackage("", "foo", goxConf)
 	gmx := newGmx(nil, pkg, "main.t2gmx", &ast.File{IsProj: true}, &Config{
@@ -176,10 +200,10 @@ func lookupClassErr(ext string) (c *modfile.Project, ok bool) {
 }
 
 func TestGetGoFile(t *testing.T) {
-	if f := getGoFile("a_test.gop", true); f != testingGoFile {
+	if f := genGoFile("a_test.gop", true); f != testingGoFile {
 		t.Fatal("TestGetGoFile:", f)
 	}
-	if f := getGoFile("a_test.gop", false); f != skippingGoFile {
+	if f := genGoFile("a_test.gop", false); f != skippingGoFile {
 		t.Fatal("TestGetGoFile:", f)
 	}
 }
@@ -200,17 +224,6 @@ func TestErrNewType(t *testing.T) {
 	})
 }
 
-func TestErrDeclFunc(t *testing.T) {
-	testPanic(t, "invalid receiver type **byte (**byte is not a defined type)\n", func() {
-		pkg := gox.NewPackage("", "foo", goxConf)
-		recv := pkg.NewParam(token.NoPos, "p", types.NewPointer(types.NewPointer(gox.TyByte)))
-		declFunc(&blockCtx{pkg: pkg}, recv, &ast.FuncDecl{
-			Name: &ast.Ident{Name: "m"},
-			Type: &ast.FuncType{Params: &ast.FieldList{}},
-		})
-	})
-}
-
 func TestErrLoadImport(t *testing.T) {
 	testPanic(t, ".: unknownpkg not found or not a valid C package (c2go.a.pub file not found).\n", func() {
 		pkg := &pkgCtx{
diff --git a/cl/compile_test.go b/cl/compile_test.go
index 21e2d561..ddd940e5 100644
--- a/cl/compile_test.go
+++ b/cl/compile_test.go
@@ -1849,6 +1849,32 @@ var y uint32 = *x
 `)
 }
 
+func TestLHS(t *testing.T) {
+	gopClTest(t, `
+type T struct {
+	a int
+}
+
+func foo() *T {
+	return nil
+}
+
+foo().a = 123
+`, `package main
+
+type T struct {
+	a int
+}
+
+func foo() *T {
+	return nil
+}
+func main() {
+	foo().a = 123
+}
+`)
+}
+
 func TestSend(t *testing.T) {
 	gopClTest(t, `
 var x chan bool
@@ -3891,6 +3917,19 @@ func main() {
 		fmt.Println(i)
 	}
 }
+`)
+	testRangeExpr(t, `
+for i $ 1:10:3 {
+	println(i)
+}`, `package main
+
+import fmt "fmt"
+
+func main() {
+	for i := 1; i < 10; i += 3 {
+		fmt.Println(i)
+	}
+}
 `)
 }
 
diff --git a/cl/error_msg_test.go b/cl/error_msg_test.go
index 131f5023..0561340e 100644
--- a/cl/error_msg_test.go
+++ b/cl/error_msg_test.go
@@ -486,6 +486,10 @@ a := struct{x int; y string}{1}
 		`./bar.gop:3:33: cannot use x (type int) as type string in value of field y`, `
 x := 1
 a := struct{x int; y string}{1, x}
+`)
+	codeErrorTest(t,
+		`./bar.gop:2:30: z undefined (type struct{x int; y string} has no field or method z)`, `
+a := struct{x int; y string}{z: 1}
 `)
 }