diff --git a/compiler.go b/compiler.go index 0d0ce75d..4f901acb 100644 --- a/compiler.go +++ b/compiler.go @@ -2414,6 +2414,20 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value) ( return llvm.Value{}, errors.New("todo: convert: basic non-integer type: " + typeFrom.String() + " -> " + typeTo.String()) + case *types.Slice: + if basic, ok := typeFrom.(*types.Basic); !ok || basic.Kind() != types.String { + panic("can only convert from a string to a slice") + } + + elemType := typeTo.Elem().Underlying().(*types.Basic) // must be byte or rune + switch elemType.Kind() { + case types.Byte: + fn := c.mod.NamedFunction("runtime.stringToBytes") + return c.builder.CreateCall(fn, []llvm.Value{value}, ""), nil + default: + return llvm.Value{}, errors.New("todo: convert from string: " + elemType.String()) + } + default: return llvm.Value{}, errors.New("todo: convert " + typeTo.String() + " <- " + typeFrom.String()) } diff --git a/src/runtime/string.go b/src/runtime/string.go index 64a60b3a..6a38f13e 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -42,12 +42,28 @@ func stringConcat(x, y _string) _string { } // Create a string from a []byte slice. -func stringFromBytes(x []byte) _string { - buf := alloc(uintptr(len(x))) - for i, c := range x { - *(*byte)(unsafe.Pointer(uintptr(buf) + uintptr(i))) = c - } - return _string{lenType(len(x)), (*byte)(buf)} +func stringFromBytes(x struct { + ptr *byte + len lenType + cap lenType +}) _string { + buf := alloc(uintptr(x.len)) + memcpy(buf, unsafe.Pointer(x.ptr), uintptr(x.len)) + return _string{lenType(x.len), (*byte)(buf)} +} + +// Convert a string to a []byte slice. +func stringToBytes(x _string) (slice struct { + ptr *byte + len lenType + cap lenType +}) { + buf := alloc(uintptr(x.length)) + memcpy(buf, unsafe.Pointer(x.ptr), uintptr(x.length)) + slice.ptr = (*byte)(buf) + slice.len = x.length + slice.cap = x.length + return } // Create a string from a Unicode code point.