compiler: allow to declare variables of struct type

Previously, struct variables were initialize with VM's nil value
which is of primitive type. Thus SETITEM used for struct's field
updating wasn't working.
This commit is contained in:
Evgenii Stratonikov 2020-03-26 15:35:15 +03:00
parent 6baed7a010
commit 3cbd138b67
3 changed files with 43 additions and 0 deletions

View file

@ -203,6 +203,19 @@ func isByte(t types.Type) bool {
return ok && e.Kind() == types.Byte return ok && e.Kind() == types.Byte
} }
func (c *codegen) isStructType(t ast.Expr) (int, bool) {
switch s := t.(type) {
case *ast.StructType:
return s.Fields.NumFields(), true
case *ast.Ident:
st, ok := c.typeInfo.Types[s].Type.Underlying().(*types.Struct)
if ok {
return st.NumFields(), true
}
}
return 0, false
}
func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool { func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool {
if len(lit.Elts) == 0 { if len(lit.Elts) == 0 {
if typ, ok := lit.Type.(*ast.ArrayType); ok { if typ, ok := lit.Type.(*ast.ArrayType); ok {

View file

@ -287,6 +287,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY) emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY)
l := c.scope.newLocal(t.Names[0].Name) l := c.scope.newLocal(t.Names[0].Name)
c.emitStoreLocal(l) c.emitStoreLocal(l)
} else if n, ok := c.isStructType(t.Type); ok {
emit.Int(c.prog.BinWriter, int64(n))
emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT)
l := c.scope.newLocal(t.Names[0].Name)
c.emitStoreLocal(l)
} }
} }
} }

View file

@ -302,6 +302,31 @@ var structTestCases = []testCase{
`, `,
big.NewInt(14), big.NewInt(14),
}, },
{
"declare struct literal",
`package foo
func Main() int {
var x struct {
a int
}
x.a = 2
return x.a
}`,
big.NewInt(2),
},
{
"declare struct type",
`package foo
type withA struct {
a int
}
func Main() int {
var x withA
x.a = 2
return x.a
}`,
big.NewInt(2),
},
} }
func TestStructs(t *testing.T) { func TestStructs(t *testing.T) {