From 66dd10002f0deab9573120d3bc644d44e9543c31 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Thu, 23 Sep 2021 08:05:51 +0800 Subject: [PATCH] fix #787 --- cl/builtin_test.go | 14 -------------- cl/class_file.go | 29 ++++++++++++++++------------- cl/compile.go | 8 +++++++- cl/compile_spx_test.go | 9 +++++++-- cl/compile_test.go | 12 ++++++++++++ cl/error_msg_test.go | 10 ++++++++++ cl/expr.go | 27 +++++++++++++++++++++------ cl/func_type_and_var.go | 8 +++----- 8 files changed, 76 insertions(+), 41 deletions(-) diff --git a/cl/builtin_test.go b/cl/builtin_test.go index 0efedb039..9fc84ba21 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -45,20 +45,6 @@ func TestToString(t *testing.T) { toString(&ast.BasicLit{Kind: token.INT, Value: "1"}) } -func TestLoadImport(t *testing.T) { - pkg := gox.NewPackage("", "foo", nil) - ctx := &blockCtx{pkg: pkg, cb: pkg.CB()} - defer func() { - if e := recover(); e == nil { - t.Fatal("loadImport: no error?") - } - }() - loadImport(ctx, &ast.ImportSpec{ - Name: &ast.Ident{Name: "."}, - Path: &ast.BasicLit{Kind: token.STRING, Value: `"fmt"`}, - }) -} - func TestGetTypeName(t *testing.T) { if getTypeName(types.Typ[types.Int]) != "int" { t.Fatal("getTypeName int failed") diff --git a/cl/class_file.go b/cl/class_file.go index 81cc340cd..9f532d7e4 100644 --- a/cl/class_file.go +++ b/cl/class_file.go @@ -33,35 +33,37 @@ import ( // ----------------------------------------------------------------------------- type gmxInfo struct { - pkgPath string - extSpx string + extSpx string + pkgPaths []string } var ( gmxTypes = map[string]gmxInfo{ - ".gmx": {"github.com/goplus/spx", ".spx"}, + ".gmx": {".spx", []string{"github.com/goplus/spx", "math"}}, } ) // RegisterClassFileType registers Go+ class file types. -func RegisterClassFileType(extGmx, extSpx string, pkgPath string) { +func RegisterClassFileType(extGmx, extSpx string, pkgPaths ...string) { + if pkgPaths == nil { + panic("RegisterClassFileType: no pkgPath specified") + } parser.RegisterFileType(extGmx, ast.FileTypeGmx) parser.RegisterFileType(extSpx, ast.FileTypeSpx) if _, ok := gmxTypes[extGmx]; !ok { - gmxTypes[extGmx] = gmxInfo{pkgPath, extSpx} + gmxTypes[extGmx] = gmxInfo{extSpx, pkgPaths} } } // ----------------------------------------------------------------------------- type gmxSettings struct { - pkgPath string gameClass string extSpx string - spx *gox.PkgRef game gox.Ref sprite gox.Ref scheds []goast.Stmt // nil or len(scheds) == 2 + pkgPaths []string } func newGmx(pkg *gox.Package, file string) *gmxSettings { @@ -71,15 +73,16 @@ func newGmx(pkg *gox.Package, file string) *gmxSettings { name = name[:idx] } gt := gmxTypes[ext] - p := &gmxSettings{pkgPath: gt.pkgPath, extSpx: gt.extSpx, gameClass: name} - p.spx = pkg.Import(p.pkgPath) - p.game = spxRef(p.spx, "Gop_game", "Game") - p.sprite = spxRef(p.spx, "Gop_sprite", "Sprite") - if x := getStringConst(p.spx, "Gop_sched"); x != "" { + pkgPaths := gt.pkgPaths + spx := pkg.Import(pkgPaths[0]) + p := &gmxSettings{extSpx: gt.extSpx, gameClass: name, pkgPaths: pkgPaths} + p.game = spxRef(spx, "Gop_game", "Game") + p.sprite = spxRef(spx, "Gop_sprite", "Sprite") + if x := getStringConst(spx, "Gop_sched"); x != "" { scheds := strings.SplitN(x, ",", 2) p.scheds = make([]goast.Stmt, 2) for i, v := range scheds { - fn := pkg.CB().Val(p.spx.Ref(v)).Call(0).InternalStack().Pop().Val + fn := pkg.CB().Val(spx.Ref(v)).Call(0).InternalStack().Pop().Val p.scheds[i] = &goast.ExprStmt{X: fn} } if len(scheds) < 2 { diff --git a/cl/compile.go b/cl/compile.go index d7cc46073..e0fca62e1 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -290,6 +290,7 @@ type blockCtx struct { cb *gox.CodeBuilder fset *token.FileSet imports map[string]*gox.PkgRef + lookups []*gox.PkgRef targetDir string classRecv *ast.FieldList // avaliable when gmxSettings != nil fileLine bool @@ -512,6 +513,10 @@ func preloadFile(p *gox.Package, parent *pkgCtx, file string, f *ast.File, targe if debugLoad { log.Println("==> Preload type", classType) } + ctx.lookups = make([]*gox.PkgRef, len(parent.pkgPaths)) + for i, pkgPath := range parent.pkgPaths { + ctx.lookups[i] = p.Import(pkgPath) + } pos := f.Pos() specs := getFields(ctx, f) ld := getTypeLoader(syms, pos, classType) @@ -788,7 +793,8 @@ func loadImport(ctx *blockCtx, spec *ast.ImportSpec) { if spec.Name != nil { name = spec.Name.Name if name == "." { - panic("TODO: not impl") + ctx.lookups = append(ctx.lookups, pkg) + return } if name == "_" { pkg.MarkForceUsed() diff --git a/cl/compile_spx_test.go b/cl/compile_spx_test.go index e8a4f411a..215c7b94a 100644 --- a/cl/compile_spx_test.go +++ b/cl/compile_spx_test.go @@ -39,7 +39,7 @@ func newTwoFileFS(dir string, fname, data string, fname2 string, data2 string) * } func init() { - cl.RegisterClassFileType(".tgmx", ".tspx", "github.com/goplus/gop/cl/internal/spx") + cl.RegisterClassFileType(".tgmx", ".tspx", "github.com/goplus/gop/cl/internal/spx", "math") } func gopSpxTest(t *testing.T, gmx, spxcode, expected string) { @@ -151,6 +151,7 @@ func onInit() { sched broadcast "msg1" testIntValue = 1 + x := round(1.2) } `, ` func onInit() { @@ -161,7 +162,10 @@ func onInit() { } `, `package main -import spx "github.com/goplus/gop/cl/internal/spx" +import ( + spx "github.com/goplus/gop/cl/internal/spx" + math "math" +) type Game struct { spx.MyGame @@ -171,6 +175,7 @@ func (this *Game) onInit() { spx.Sched() this.Broadcast__0("msg1") spx.TestIntValue = 1 + x := math.Round(1.2) } type bar struct { diff --git a/cl/compile_test.go b/cl/compile_test.go index 138e03931..dc5abf07c 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -2341,6 +2341,18 @@ func main() { `) } +func TestDotImport(t *testing.T) { + gopClTest(t, `import . "math" + +var a = round(1.2) +`, `package main + +import math "math" + +var a = math.Round(1.2) +`) +} + func TestImportUnused(t *testing.T) { gopClTest(t, `import "fmt" diff --git a/cl/error_msg_test.go b/cl/error_msg_test.go index 966dd4413..f0d18b9fa 100644 --- a/cl/error_msg_test.go +++ b/cl/error_msg_test.go @@ -160,6 +160,16 @@ func foo(v map[int]bar) { } func TestErrImport(t *testing.T) { + codeErrorTest(t, + `./bar.gop:8:2: confliction: NewEncoding declared both in "encoding/base64" and "encoding/base32"`, ` +import ( + . "encoding/base32" + . "encoding/base64" +) + +func foo() { + NewEncoding("Hi") +}`) codeErrorTest(t, "./bar.gop:5:2: cannot refer to unexported name os.undefined", ` import "os" diff --git a/cl/expr.go b/cl/expr.go index 087213f4f..844bbd066 100644 --- a/cl/expr.go +++ b/cl/expr.go @@ -108,11 +108,9 @@ func compileIdent(ctx *blockCtx, ident *ast.Ident, flags int) *gox.PkgRef { } } - // spx object - if ctx.fileType > 0 { - if compilePkgRef(ctx, ctx.spx, ident, flags) { - return nil - } + // object from import . "xxx" + if compilePkgRef(ctx, nil, ident, flags) { + return nil } // universe object @@ -334,8 +332,25 @@ func pkgRef(at *gox.PkgRef, name string) (o types.Object, canAutoCall bool) { return at.Ref(name), false } +func lookupPkgRef(ctx *blockCtx, pkg *gox.PkgRef, x *ast.Ident) (o types.Object, canAutoCall bool) { + if pkg != nil { + return pkgRef(pkg, x.Name) + } + for _, at := range ctx.lookups { + if o2, canAutoCall2 := pkgRef(at, x.Name); o2 != nil { + if o != nil { + panic(ctx.newCodeErrorf( + x.Pos(), "confliction: %s declared both in \"%s\" and \"%s\"", + x.Name, at.Types.Path(), pkg.Types.Path())) + } + pkg, o, canAutoCall = at, o2, canAutoCall2 + } + } + return +} + func compilePkgRef(ctx *blockCtx, at *gox.PkgRef, x *ast.Ident, flags int) bool { - if v, canAutoCall := pkgRef(at, x.Name); v != nil { + if v, canAutoCall := lookupPkgRef(ctx, at, x); v != nil { cb := ctx.cb if (flags & clIdentLHS) != 0 { cb.VarRef(v, x) diff --git a/cl/func_type_and_var.go b/cl/func_type_and_var.go index d31361c05..21e90a83a 100644 --- a/cl/func_type_and_var.go +++ b/cl/func_type_and_var.go @@ -171,11 +171,9 @@ func toIdentType(ctx *blockCtx, ident *ast.Ident) types.Type { if t, ok := v.(*types.TypeName); ok { return t.Type() } - if ctx.fileType > 0 { - if v := ctx.spx.Ref(ident.Name); v != nil { - if t, ok := v.(*types.TypeName); ok { - return t.Type() - } + if v, _ := lookupPkgRef(ctx, nil, ident); v != nil { + if t, ok := v.(*types.TypeName); ok { + return t.Type() } } panic(ctx.newCodeErrorf(ident.Pos(), "%s is not a type", ident.Name))