mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
compiler: initialize packages according to go spec
`init()` functions should be called during package initialization, after global variables were processed.
This commit is contained in:
parent
6f2759be3a
commit
439d9ff94d
4 changed files with 37 additions and 5 deletions
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
"golang.org/x/tools/go/loader"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -47,8 +48,20 @@ func (c *codegen) traverseGlobals() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
emit.Instruction(c.prog.BinWriter, opcode.INITSSLOT, []byte{byte(n)})
|
emit.Instruction(c.prog.BinWriter, opcode.INITSSLOT, []byte{byte(n)})
|
||||||
c.ForEachFile(c.convertGlobals)
|
c.ForEachPackage(func(pkg *loader.PackageInfo) {
|
||||||
c.ForEachFile(c.convertInitFuncs)
|
for _, f := range pkg.Files {
|
||||||
|
c.fillImportMap(f, pkg.Pkg)
|
||||||
|
c.convertGlobals(f, pkg.Pkg)
|
||||||
|
}
|
||||||
|
for _, f := range pkg.Files {
|
||||||
|
c.fillImportMap(f, pkg.Pkg)
|
||||||
|
c.convertInitFuncs(f, pkg.Pkg)
|
||||||
|
}
|
||||||
|
// because we reuse `convertFuncDecl` for init funcs,
|
||||||
|
// we need to cleare scope, so that global variables
|
||||||
|
// encountered after will be recognized as globals.
|
||||||
|
c.scope = nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,17 +47,25 @@ type buildInfo struct {
|
||||||
program *loader.Program
|
program *loader.Program
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachFile executes fn on each file used in current program.
|
// ForEachPackage executes fn on each package used in the current program
|
||||||
func (c *codegen) ForEachFile(fn func(*ast.File, *types.Package)) {
|
// in the order they should be initialized.
|
||||||
|
func (c *codegen) ForEachPackage(fn func(*loader.PackageInfo)) {
|
||||||
for i := range c.packages {
|
for i := range c.packages {
|
||||||
pkg := c.buildInfo.program.Package(c.packages[i])
|
pkg := c.buildInfo.program.Package(c.packages[i])
|
||||||
c.typeInfo = &pkg.Info
|
c.typeInfo = &pkg.Info
|
||||||
c.currPkg = pkg.Pkg
|
c.currPkg = pkg.Pkg
|
||||||
|
fn(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEachFile executes fn on each file used in current program.
|
||||||
|
func (c *codegen) ForEachFile(fn func(*ast.File, *types.Package)) {
|
||||||
|
c.ForEachPackage(func(pkg *loader.PackageInfo) {
|
||||||
for _, f := range pkg.Files {
|
for _, f := range pkg.Files {
|
||||||
c.fillImportMap(f, pkg.Pkg)
|
c.fillImportMap(f, pkg.Pkg)
|
||||||
fn(f, pkg.Pkg)
|
fn(f, pkg.Pkg)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillImportMap fills import map for f.
|
// fillImportMap fills import map for f.
|
||||||
|
|
|
@ -80,4 +80,11 @@ func TestImportOrder(t *testing.T) {
|
||||||
func Main() int { return pkg3.A }`
|
func Main() int { return pkg3.A }`
|
||||||
eval(t, src, big.NewInt(1))
|
eval(t, src, big.NewInt(1))
|
||||||
})
|
})
|
||||||
|
t.Run("InitializeOnce", func(t *testing.T) {
|
||||||
|
src := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/pkg3"
|
||||||
|
var A = pkg3.A
|
||||||
|
func Main() int { return A }`
|
||||||
|
eval(t, src, big.NewInt(3))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
4
pkg/compiler/testdata/pkg3/pkg3.go
vendored
4
pkg/compiler/testdata/pkg3/pkg3.go
vendored
|
@ -1,3 +1,7 @@
|
||||||
package pkg3
|
package pkg3
|
||||||
|
|
||||||
var A int
|
var A int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
A = 3
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue