forked from TrueCloudLab/neoneo-go
compiler: allow to declare global variables in multiple files
Traverse and count globals across all used files. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
babd84ec10
commit
7009417325
6 changed files with 36 additions and 8 deletions
|
@ -28,20 +28,18 @@ func (c *codegen) newGlobal(name string) {
|
|||
|
||||
// traverseGlobals visits and initializes global variables.
|
||||
// and returns number of variables initialized.
|
||||
func (c *codegen) traverseGlobals(fs ...*ast.File) int {
|
||||
func (c *codegen) traverseGlobals() int {
|
||||
var n int
|
||||
for _, f := range fs {
|
||||
c.ForEachFile(func(f *ast.File) {
|
||||
n += countGlobals(f)
|
||||
}
|
||||
})
|
||||
if n != 0 {
|
||||
if n > 255 {
|
||||
c.prog.BinWriter.Err = errors.New("too many global variables")
|
||||
return 0
|
||||
}
|
||||
emit.Instruction(c.prog.BinWriter, opcode.INITSSLOT, []byte{byte(n)})
|
||||
for _, f := range fs {
|
||||
c.convertGlobals(f)
|
||||
}
|
||||
c.ForEachFile(c.convertGlobals)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ func (c *codegen) emitDefault(t types.Type) {
|
|||
// convertGlobals traverses the AST and only converts global declarations.
|
||||
// If we call this in convertFuncDecl then it will load all global variables
|
||||
// into the scope of the function.
|
||||
func (c *codegen) convertGlobals(f ast.Node) {
|
||||
func (c *codegen) convertGlobals(f *ast.File) {
|
||||
ast.Inspect(f, func(node ast.Node) bool {
|
||||
switch n := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
|
@ -1425,7 +1425,7 @@ func (c *codegen) compile(info *buildInfo, pkg *loader.PackageInfo) error {
|
|||
}
|
||||
|
||||
c.mainPkg = pkg
|
||||
n := c.traverseGlobals(pkg.Files...)
|
||||
n := c.traverseGlobals()
|
||||
if n > 0 {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.RET)
|
||||
c.initEndOffset = c.prog.Len()
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -42,6 +43,16 @@ type buildInfo struct {
|
|||
program *loader.Program
|
||||
}
|
||||
|
||||
// ForEachFile executes fn on each file used in current program.
|
||||
func (c *codegen) ForEachFile(fn func(*ast.File)) {
|
||||
for _, pkg := range c.buildInfo.program.AllPackages {
|
||||
c.typeInfo = &pkg.Info
|
||||
for _, f := range pkg.Files {
|
||||
fn(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getBuildInfo(src interface{}) (*buildInfo, error) {
|
||||
conf := loader.Config{ParserMode: parser.ParseComments}
|
||||
f, err := conf.ParseFile("", src)
|
||||
|
|
|
@ -127,3 +127,12 @@ func TestContractWithNoMain(t *testing.T) {
|
|||
require.Equal(t, 1, v.Estack().Len())
|
||||
require.Equal(t, big.NewInt(42), v.PopResult())
|
||||
}
|
||||
|
||||
func TestMultipleFiles(t *testing.T) {
|
||||
src := `package foo
|
||||
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/multi"
|
||||
func Main() int {
|
||||
return multi.Sum()
|
||||
}`
|
||||
eval(t, src, big.NewInt(42))
|
||||
}
|
||||
|
|
3
pkg/compiler/testdata/multi/file1.go
vendored
Normal file
3
pkg/compiler/testdata/multi/file1.go
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
package multi
|
||||
|
||||
var SomeVar12 = 12
|
7
pkg/compiler/testdata/multi/file2.go
vendored
Normal file
7
pkg/compiler/testdata/multi/file2.go
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package multi
|
||||
|
||||
var SomeVar30 = 30
|
||||
|
||||
func Sum() int {
|
||||
return SomeVar12 + SomeVar30
|
||||
}
|
Loading…
Reference in a new issue