diff --git a/gnovm/cmd/gno/transpile.go b/gnovm/cmd/gno/transpile.go index 2e12ee6f4b3..156d6823636 100644 --- a/gnovm/cmd/gno/transpile.go +++ b/gnovm/cmd/gno/transpile.go @@ -25,6 +25,7 @@ import ( type transpileCfg struct { verbose bool rootDir string + extraDirs string skipImports bool gobuild bool goBinary string @@ -94,6 +95,13 @@ func (c *transpileCfg) RegisterFlags(fs *flag.FlagSet) { "clone location of github.com/gnolang/gno (gno tries to guess it)", ) + fs.StringVar( + &c.extraDirs, + "extra-dirs", + "", + "extra directories to look for packages in", + ) + fs.BoolVar( &c.skipImports, "skip-imports", @@ -251,7 +259,7 @@ func transpileFile(srcPath string, opts *transpileOptions) error { targetFilename, tags := transpiler.TranspiledFilenameAndTags(srcPath) // preprocess. - transpileRes, err := transpiler.Transpile(string(source), tags, srcPath) + transpileRes, err := transpiler.Transpile(string(source), tags, srcPath, strings.Split(opts.cfg.extraDirs, ",")) if err != nil { return fmt.Errorf("transpile: %w", err) } diff --git a/gnovm/pkg/transpiler/transpiler.go b/gnovm/pkg/transpiler/transpiler.go index bd4bb1b1bc9..841c831cfcc 100644 --- a/gnovm/pkg/transpiler/transpiler.go +++ b/gnovm/pkg/transpiler/transpiler.go @@ -10,9 +10,11 @@ import ( "go/parser" goscanner "go/scanner" "go/token" + "io/fs" "os" "path" "path/filepath" + "regexp" "strconv" "strings" @@ -75,7 +77,7 @@ func TranspiledFilenameAndTags(gnoFilePath string) (targetFilename, tags string) // Transpile performs transpilation on the given source code. tags can be used // to specify build tags; and filename helps generate useful error messages and // discriminate between test and normal source files. -func Transpile(source, tags, filename string) (*Result, error) { +func Transpile(source, tags, filename string, extraDirs []string) (*Result, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, filename, source, // SkipObjectResolution -- unused here. @@ -87,7 +89,8 @@ func Transpile(source, tags, filename string) (*Result, error) { isTestFile := strings.HasSuffix(filename, "_test.gno") || strings.HasSuffix(filename, "_filetest.gno") ctx := &transpileCtx{ - rootDir: gnoenv.RootDir(), + rootDir: gnoenv.RootDir(), + extraDirs: extraDirs, } stdlibPrefix := filepath.Join(ctx.rootDir, "gnovm", "stdlibs") if isTestFile { @@ -142,6 +145,9 @@ type transpileCtx struct { // If rootDir is given, we will check that the directory of the import path // exists (using rootDir/packageDirLocation()). rootDir string + // If extraDirs is given, we will check that the directory of the import path + // exists (using rootDir/packageDirLocation()). + extraDirs []string // This should be set if we're working with a file from a standard library. // This allows us to easily check if a function has a native binding, and as // such modify its call expressions appropriately. @@ -165,7 +171,41 @@ func (ctx *transpileCtx) transformFile(fset *token.FileSet, f *ast.File) (*ast.F continue } - if ctx.rootDir != "" { + foundInExtra := false + for _, extraDir := range ctx.extraDirs { + // TODO: find packages once + modFiles := []string{} + if err := filepath.Walk(extraDir, func(path string, info fs.FileInfo, err error) error { + if !strings.HasSuffix(path, "/gno.mod") { + return nil + } + modFiles = append(modFiles, path) + return nil + }); err != nil { + return nil, err + } + packageNames := []string{} + for _, modFile := range modFiles { + modData, err := os.ReadFile(modFile) + if err != nil { + continue + } + re := regexp.MustCompile(`^module (.+)`) + res := re.FindSubmatch(modData) + if len(res) != 2 { + continue + } + packageNames = append(packageNames, string(res[1])) + } + + for _, pn := range packageNames { + if pn == importPath { + foundInExtra = true + } + } + } + + if !foundInExtra && ctx.rootDir != "" { dirPath := filepath.Join(ctx.rootDir, PackageDirLocation(importPath)) if _, err := os.Stat(dirPath); err != nil { if !os.IsNotExist(err) { diff --git a/gnovm/pkg/transpiler/transpiler_test.go b/gnovm/pkg/transpiler/transpiler_test.go index 2a0707f7f79..bd341935cc1 100644 --- a/gnovm/pkg/transpiler/transpiler_test.go +++ b/gnovm/pkg/transpiler/transpiler_test.go @@ -420,7 +420,7 @@ func testfunc() { if filename == "" { filename = "foo.gno" } - res, err := Transpile(source, c.tags, filename) + res, err := Transpile(source, c.tags, filename, nil) if c.expectedError != "" { require.EqualError(t, err, c.expectedError) diff --git a/go.mod b/go.mod index a7f0d4b0ca4..771712ef918 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/nxadm/tail v1.4.11 // indirect + github.com/onsi/gomega v1.27.10 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/zondax/hid v0.9.2 // indirect diff --git a/go.sum b/go.sum index d563396d801..64cc9959e73 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,9 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= @@ -246,7 +247,6 @@ golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= @@ -271,8 +271,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=