interp: support map literals with integer keys

Этот коммит содержится в:
Konstantin Yegupov 2019-01-30 23:22:29 +10:00 коммит произвёл Ayke van Laethem
родитель 0308c92e67
коммит f8a1e5f449
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
4 изменённых файлов: 44 добавлений и 1 удалений

Просмотреть файл

@ -244,13 +244,18 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
case callee.Name() == "runtime.hashmapStringSet": case callee.Name() == "runtime.hashmapStringSet":
// set a string key in the map // set a string key in the map
m := fr.getLocal(inst.Operand(0)).(*MapValue) m := fr.getLocal(inst.Operand(0)).(*MapValue)
// "key" is a Go string value, which in the TinyGo calling convention is split up
// into separate pointer and length parameters.
keyBuf := fr.getLocal(inst.Operand(1)) keyBuf := fr.getLocal(inst.Operand(1))
keyLen := fr.getLocal(inst.Operand(2)) keyLen := fr.getLocal(inst.Operand(2))
valPtr := fr.getLocal(inst.Operand(3)) valPtr := fr.getLocal(inst.Operand(3))
m.PutString(keyBuf, keyLen, valPtr) m.PutString(keyBuf, keyLen, valPtr)
case callee.Name() == "runtime.hashmapBinarySet": case callee.Name() == "runtime.hashmapBinarySet":
// set a binary (int etc.) key in the map // set a binary (int etc.) key in the map
// TODO: unimplemented m := fr.getLocal(inst.Operand(0)).(*MapValue)
keyBuf := fr.getLocal(inst.Operand(1))
valPtr := fr.getLocal(inst.Operand(2))
m.PutBinary(keyBuf, valPtr)
case callee.Name() == "runtime.stringConcat": case callee.Name() == "runtime.stringConcat":
// adding two strings together // adding two strings together
buf1Ptr := fr.getLocal(inst.Operand(0)) buf1Ptr := fr.getLocal(inst.Operand(0))

Просмотреть файл

@ -561,6 +561,38 @@ func (v *MapValue) PutString(keyBuf, keyLen, valPtr Value) {
v.Values = append(v.Values, &LocalValue{v.Eval, value}) v.Values = append(v.Values, &LocalValue{v.Eval, value})
} }
// PutBinary does a map assign operation.
func (v *MapValue) PutBinary(keyPtr, valPtr Value) {
if !v.Underlying.IsNil() {
panic("map already created")
}
var value llvm.Value
switch valPtr := valPtr.(type) {
case *PointerCastValue:
value = valPtr.Underlying.Load()
if v.ValueType.IsNil() {
v.ValueType = value.Type()
if int(v.Eval.TargetData.TypeAllocSize(v.ValueType)) != v.ValueSize {
panic("interp: map store value type has the wrong size")
}
} else {
if value.Type() != v.ValueType {
panic("interp: map store value type is inconsistent")
}
}
default:
panic("interp: todo: handle map value pointer")
}
key := keyPtr.(*PointerCastValue).Underlying.Load()
v.KeyType = key.Type()
// TODO: avoid duplicate keys
v.Keys = append(v.Keys, &LocalValue{v.Eval, key})
v.Values = append(v.Values, &LocalValue{v.Eval, value})
}
// Get FNV-1a hash of this string. // Get FNV-1a hash of this string.
// //
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash

4
testdata/map.go предоставленный
Просмотреть файл

@ -15,6 +15,7 @@ var testmap2 = map[string]int{
"eleven": 11, "eleven": 11,
"twelve": 12, "twelve": 12,
} }
var testmapIntInt = map[int]int{1: 1, 2: 4, 3: 9}
func main() { func main() {
m := map[string]int{"answer": 42, "foo": 3} m := map[string]int{"answer": 42, "foo": 3}
@ -31,6 +32,9 @@ func main() {
var nilmap map[string]int var nilmap map[string]int
println(m == nil, m != nil, len(m)) println(m == nil, m != nil, len(m))
println(nilmap == nil, nilmap != nil, len(nilmap)) println(nilmap == nil, nilmap != nil, len(nilmap))
println(testmapIntInt[2])
testmapIntInt[2] = 42
println(testmapIntInt[2])
} }
func readMap(m map[string]int, key string) { func readMap(m map[string]int, key string) {

2
testdata/map.txt предоставленный
Просмотреть файл

@ -50,3 +50,5 @@ lookup with comma-ok: eight 8 true
lookup with comma-ok: nokey 0 false lookup with comma-ok: nokey 0 false
false true 2 false true 2
true false 0 true false 0
4
42