compiler: implement operations on nil hashmaps
* comparing a map against nil * getting the length of a nil map
Этот коммит содержится в:
родитель
c84fc6a670
коммит
436901dc49
4 изменённых файлов: 31 добавлений и 7 удалений
|
@ -1870,12 +1870,7 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
|
||||||
// string or slice
|
// string or slice
|
||||||
llvmLen = c.builder.CreateExtractValue(value, 1, "len")
|
llvmLen = c.builder.CreateExtractValue(value, 1, "len")
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
indices := []llvm.Value{
|
llvmLen = c.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len")
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), 2, false), // hashmap.count
|
|
||||||
}
|
|
||||||
ptr := c.builder.CreateGEP(value, indices, "lenptr")
|
|
||||||
llvmLen = c.builder.CreateLoad(ptr, "len")
|
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: len: unknown type")
|
return llvm.Value{}, errors.New("todo: len: unknown type")
|
||||||
}
|
}
|
||||||
|
@ -3053,7 +3048,10 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value) (
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("binop on interface: " + op.String())
|
return llvm.Value{}, errors.New("binop on interface: " + op.String())
|
||||||
}
|
}
|
||||||
case *types.Pointer:
|
case *types.Map, *types.Pointer:
|
||||||
|
// Maps are in general not comparable, but can be compared against nil
|
||||||
|
// (which is a nil pointer). This means they can be trivially compared
|
||||||
|
// by treating them as a pointer.
|
||||||
switch op {
|
switch op {
|
||||||
case token.EQL: // ==
|
case token.EQL: // ==
|
||||||
return c.builder.CreateICmp(llvm.IntEQ, x, y, ""), nil
|
return c.builder.CreateICmp(llvm.IntEQ, x, y, ""), nil
|
||||||
|
@ -3212,6 +3210,16 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) (llvm.Value, error
|
||||||
llvmLen, // cap
|
llvmLen, // cap
|
||||||
}, false)
|
}, false)
|
||||||
return slice, nil
|
return slice, nil
|
||||||
|
case *types.Map:
|
||||||
|
if !expr.IsNil() {
|
||||||
|
// I believe this is not allowed by the Go spec.
|
||||||
|
panic("non-nil map constant")
|
||||||
|
}
|
||||||
|
llvmType, err := c.getLLVMType(typ)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
return c.getZeroValue(llvmType)
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
return llvm.Value{}, errors.New("todo: unknown constant: " + expr.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,15 @@ func hashmapMake(keySize, valueSize uint8) *hashmap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the number of entries in this hashmap, called from the len builtin.
|
||||||
|
// A nil hashmap is defined as having length 0.
|
||||||
|
func hashmapLen(m *hashmap) int {
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return int(m.count)
|
||||||
|
}
|
||||||
|
|
||||||
// Set a specified key to a given value. Grow the map if necessary.
|
// Set a specified key to a given value. Grow the map if necessary.
|
||||||
//go:nobounds
|
//go:nobounds
|
||||||
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||||
|
|
5
testdata/map.go
предоставленный
5
testdata/map.go
предоставленный
|
@ -26,6 +26,11 @@ func main() {
|
||||||
readMap(testmap2, "seven")
|
readMap(testmap2, "seven")
|
||||||
lookup(testmap2, "eight")
|
lookup(testmap2, "eight")
|
||||||
lookup(testmap2, "nokey")
|
lookup(testmap2, "nokey")
|
||||||
|
|
||||||
|
// operations on nil maps
|
||||||
|
var nilmap map[string]int
|
||||||
|
println(m == nil, m != nil, len(m))
|
||||||
|
println(nilmap == nil, nilmap != nil, len(nilmap))
|
||||||
}
|
}
|
||||||
|
|
||||||
func readMap(m map[string]int, key string) {
|
func readMap(m map[string]int, key string) {
|
||||||
|
|
2
testdata/map.txt
предоставленный
2
testdata/map.txt
предоставленный
|
@ -48,3 +48,5 @@ map read: seven = 7
|
||||||
twelve = 12
|
twelve = 12
|
||||||
lookup with comma-ok: eight 8 true
|
lookup with comma-ok: eight 8 true
|
||||||
lookup with comma-ok: nokey 0 false
|
lookup with comma-ok: nokey 0 false
|
||||||
|
false true 2
|
||||||
|
true false 0
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче