Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outline #1432

Merged
merged 6 commits into from
Sep 28, 2023
Merged

Outline #1432

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions cl/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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)
}
}
Expand All @@ -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{
Expand Down
131 changes: 44 additions & 87 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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")
}
Expand All @@ -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)
}
Expand All @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions cl/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}
`)
}

Expand Down
4 changes: 4 additions & 0 deletions cl/error_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
`)
}

Expand Down