From 3cbd138b67e9a1b8b897891c10618094dffff78c Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 26 Mar 2020 15:35:15 +0300 Subject: [PATCH] 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. --- pkg/compiler/analysis.go | 13 +++++++++++++ pkg/compiler/codegen.go | 5 +++++ pkg/compiler/struct_test.go | 25 +++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index 6ae160931..90dd5e318 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -203,6 +203,19 @@ func isByte(t types.Type) bool { 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 { if len(lit.Elts) == 0 { if typ, ok := lit.Type.(*ast.ArrayType); ok { diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 7980b9ac1..ddd07a48e 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -287,6 +287,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY) l := c.scope.newLocal(t.Names[0].Name) 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) } } } diff --git a/pkg/compiler/struct_test.go b/pkg/compiler/struct_test.go index 964edbbd4..1dd63e07f 100644 --- a/pkg/compiler/struct_test.go +++ b/pkg/compiler/struct_test.go @@ -302,6 +302,31 @@ var structTestCases = []testCase{ `, 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) {