From ae0356058954518db608a65eb060af799059753c Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 11 Feb 2020 11:10:51 +0300 Subject: [PATCH] compiler: support initializing struct fields from a variable While initializing a struct, it is a top item on ALTSTACK. This means that if we need to load a local variable, DUPFROMALTSTACK won't longer push an array of locals on stack but rather a currently initializing struct. Closes #656. --- pkg/compiler/codegen.go | 16 ++++++--- pkg/compiler/struct_test.go | 65 +++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 9a9b3aa61..98ad17a53 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -872,7 +872,6 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) { emit.Opcode(c.prog.BinWriter, opcode.NOP) emit.Int(c.prog.BinWriter, int64(strct.NumFields())) emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT) - emit.Opcode(c.prog.BinWriter, opcode.TOALTSTACK) // We need to locally store all the fields, even if they are not initialized. // We will initialize all fields to their "zero" value. @@ -886,9 +885,14 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) { fieldName := f.Key.(*ast.Ident).Name if sField.Name() == fieldName { - ast.Walk(c, f.Value) + emit.Opcode(c.prog.BinWriter, opcode.DUP) + pos := indexOfStruct(strct, fieldName) - c.emitStoreLocal(pos) + emit.Int(c.prog.BinWriter, int64(pos)) + + ast.Walk(c, f.Value) + + emit.Opcode(c.prog.BinWriter, opcode.SETITEM) fieldAdded = true break } @@ -902,10 +906,12 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) { c.prog.Err = err return } + + emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Int(c.prog.BinWriter, int64(i)) c.emitLoadConst(typeAndVal) - c.emitStoreLocal(i) + emit.Opcode(c.prog.BinWriter, opcode.SETITEM) } - emit.Opcode(c.prog.BinWriter, opcode.FROMALTSTACK) } func (c *codegen) convertToken(tok token.Token) { diff --git a/pkg/compiler/struct_test.go b/pkg/compiler/struct_test.go index 073367207..99521b57e 100644 --- a/pkg/compiler/struct_test.go +++ b/pkg/compiler/struct_test.go @@ -93,6 +93,71 @@ var structTestCases = []testCase{ `, big.NewInt(12), }, + { + "initialize struct field from variable", + ` + package foo + type token struct { + x int + y int + } + + func Main() int { + x := 10 + t := token { + x: x, + y: 4, + } + y := t.x + t.y + return y + }`, + big.NewInt(14), + }, + { + "assign a variable to a struct field", + ` + package foo + type token struct { + x int + y int + } + + func Main() int { + ten := 10 + t := token { + x: 2, + y: 4, + } + t.x = ten + y := t.y + t.x + return y + }`, + big.NewInt(14), + }, + { + "assign a struct field to a struct field", + ` + package foo + type token struct { + x int + y int + } + + func Main() int { + t1 := token { + x: 2, + y: 4, + } + t2 := token { + x: 3, + y: 5, + } + t1.x = t2.y + y := t1.x + t2.x + return y + }`, + big.NewInt(8), + }, { "initialize same struct twice", `