forked from TrueCloudLab/neoneo-go
Merge pull request #620 from nspcc-dev/feature/map
compiler: support map literals
This commit is contained in:
commit
ead0b8ff94
2 changed files with 109 additions and 21 deletions
|
@ -61,6 +61,14 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||||
}
|
}
|
||||||
switch typ := t.Type.Underlying().(type) {
|
switch typ := t.Type.Underlying().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
|
c.convertBasicType(t, typ)
|
||||||
|
default:
|
||||||
|
c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this constant: %v", t)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *codegen) convertBasicType(t types.TypeAndValue, typ *types.Basic) {
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case types.Int, types.UntypedInt, types.Uint:
|
case types.Int, types.UntypedInt, types.Uint:
|
||||||
val, _ := constant.Int64Val(t.Value)
|
val, _ := constant.Int64Val(t.Value)
|
||||||
|
@ -79,10 +87,6 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) {
|
||||||
c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this basic type: %v", t)
|
c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this basic type: %v", t)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
c.prog.Err = fmt.Errorf("compiler doesn't know how to convert this constant: %v", t)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *codegen) emitLoadLocal(name string) {
|
func (c *codegen) emitLoadLocal(name string) {
|
||||||
|
@ -357,6 +361,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
typ = c.typeInfo.ObjectOf(t).Type().Underlying()
|
typ = c.typeInfo.ObjectOf(t).Type().Underlying()
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
typ = c.typeInfo.ObjectOf(t.Sel).Type().Underlying()
|
typ = c.typeInfo.ObjectOf(t.Sel).Type().Underlying()
|
||||||
|
case *ast.MapType:
|
||||||
|
typ = c.typeInfo.TypeOf(t)
|
||||||
default:
|
default:
|
||||||
ln := len(n.Elts)
|
ln := len(n.Elts)
|
||||||
// ByteArrays needs a different approach than normal arrays.
|
// ByteArrays needs a different approach than normal arrays.
|
||||||
|
@ -375,6 +381,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
switch typ.(type) {
|
switch typ.(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
c.convertStruct(n)
|
c.convertStruct(n)
|
||||||
|
case *types.Map:
|
||||||
|
c.convertMap(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -570,12 +578,19 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
switch n.Index.(type) {
|
switch n.Index.(type) {
|
||||||
case *ast.BasicLit:
|
case *ast.BasicLit:
|
||||||
t := c.typeInfo.Types[n.Index]
|
t := c.typeInfo.Types[n.Index]
|
||||||
val, _ := constant.Int64Val(t.Value)
|
switch typ := t.Type.Underlying().(type) {
|
||||||
c.emitLoadField(int(val))
|
case *types.Basic:
|
||||||
|
c.convertBasicType(t, typ)
|
||||||
|
default:
|
||||||
|
c.prog.Err = fmt.Errorf("compiler can't use following type as an index: %T", typ)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ast.Walk(c, n.Index)
|
ast.Walk(c, n.Index)
|
||||||
emitOpcode(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitOpcode(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case *ast.ForStmt:
|
case *ast.ForStmt:
|
||||||
|
@ -700,6 +715,17 @@ func (c *codegen) convertByteArray(lit *ast.CompositeLit) {
|
||||||
emitBytes(c.prog.BinWriter, buf)
|
emitBytes(c.prog.BinWriter, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *codegen) convertMap(lit *ast.CompositeLit) {
|
||||||
|
emitOpcode(c.prog.BinWriter, opcode.NEWMAP)
|
||||||
|
for i := range lit.Elts {
|
||||||
|
elem := lit.Elts[i].(*ast.KeyValueExpr)
|
||||||
|
emitOpcode(c.prog.BinWriter, opcode.DUP)
|
||||||
|
ast.Walk(c, elem.Key)
|
||||||
|
ast.Walk(c, elem.Value)
|
||||||
|
emitOpcode(c.prog.BinWriter, opcode.SETITEM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
||||||
// Create a new structScope to initialize and store
|
// Create a new structScope to initialize and store
|
||||||
// the positions of its variables.
|
// the positions of its variables.
|
||||||
|
|
62
pkg/compiler/map_test.go
Normal file
62
pkg/compiler/map_test.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package compiler_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mapTestCases = []testCase{
|
||||||
|
{
|
||||||
|
"map composite literal",
|
||||||
|
`
|
||||||
|
package foo
|
||||||
|
func Main() int {
|
||||||
|
t := map[int]int{
|
||||||
|
1: 6,
|
||||||
|
2: 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
age := t[2]
|
||||||
|
return age
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(9),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nested map",
|
||||||
|
`
|
||||||
|
package foo
|
||||||
|
func Main() int {
|
||||||
|
t := map[int]map[int]int{
|
||||||
|
1: map[int]int{2: 5, 3: 1},
|
||||||
|
2: nil,
|
||||||
|
5: map[int]int{3: 4, 7: 2},
|
||||||
|
}
|
||||||
|
|
||||||
|
x := t[5][3]
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
big.NewInt(4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map with string index",
|
||||||
|
`
|
||||||
|
package foo
|
||||||
|
func Main() string {
|
||||||
|
t := map[string]string{
|
||||||
|
"name": "Valera",
|
||||||
|
"age": "33",
|
||||||
|
}
|
||||||
|
|
||||||
|
name := t["name"]
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
[]byte("Valera"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMaps(t *testing.T) {
|
||||||
|
runTestCases(t, mapTestCases)
|
||||||
|
}
|
Loading…
Reference in a new issue