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.
|
// traverseGlobals visits and initializes global variables.
|
||||||
// and returns number of variables initialized.
|
// and returns number of variables initialized.
|
||||||
func (c *codegen) traverseGlobals(fs ...*ast.File) int {
|
func (c *codegen) traverseGlobals() int {
|
||||||
var n int
|
var n int
|
||||||
for _, f := range fs {
|
c.ForEachFile(func(f *ast.File) {
|
||||||
n += countGlobals(f)
|
n += countGlobals(f)
|
||||||
}
|
})
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
if n > 255 {
|
if n > 255 {
|
||||||
c.prog.BinWriter.Err = errors.New("too many global variables")
|
c.prog.BinWriter.Err = errors.New("too many global variables")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
emit.Instruction(c.prog.BinWriter, opcode.INITSSLOT, []byte{byte(n)})
|
emit.Instruction(c.prog.BinWriter, opcode.INITSSLOT, []byte{byte(n)})
|
||||||
for _, f := range fs {
|
c.ForEachFile(c.convertGlobals)
|
||||||
c.convertGlobals(f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ func (c *codegen) emitDefault(t types.Type) {
|
||||||
// convertGlobals traverses the AST and only converts global declarations.
|
// convertGlobals traverses the AST and only converts global declarations.
|
||||||
// If we call this in convertFuncDecl then it will load all global variables
|
// If we call this in convertFuncDecl then it will load all global variables
|
||||||
// into the scope of the function.
|
// 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 {
|
ast.Inspect(f, func(node ast.Node) bool {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
|
@ -1425,7 +1425,7 @@ func (c *codegen) compile(info *buildInfo, pkg *loader.PackageInfo) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.mainPkg = pkg
|
c.mainPkg = pkg
|
||||||
n := c.traverseGlobals(pkg.Files...)
|
n := c.traverseGlobals()
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.RET)
|
emit.Opcode(c.prog.BinWriter, opcode.RET)
|
||||||
c.initEndOffset = c.prog.Len()
|
c.initEndOffset = c.prog.Len()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -42,6 +43,16 @@ type buildInfo struct {
|
||||||
program *loader.Program
|
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) {
|
func getBuildInfo(src interface{}) (*buildInfo, error) {
|
||||||
conf := loader.Config{ParserMode: parser.ParseComments}
|
conf := loader.Config{ParserMode: parser.ParseComments}
|
||||||
f, err := conf.ParseFile("", src)
|
f, err := conf.ParseFile("", src)
|
||||||
|
|
|
@ -127,3 +127,12 @@ func TestContractWithNoMain(t *testing.T) {
|
||||||
require.Equal(t, 1, v.Estack().Len())
|
require.Equal(t, 1, v.Estack().Len())
|
||||||
require.Equal(t, big.NewInt(42), v.PopResult())
|
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