From fd3309afa8452fecffb81cbede3609d35dccaea8 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 11 Aug 2019 14:35:34 +0200 Subject: [PATCH] compiler,runtime: implement []rune to string conversion This is used by a few packages in the standard library, at least compress/gzip and regexp/syntax. --- compiler/compiler.go | 2 ++ src/runtime/string.go | 24 ++++++++++++++++++++++++ testdata/string.go | 7 ++++++- testdata/string.txt | 1 + 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index f6a583ef..66b2794d 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -2415,6 +2415,8 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p switch typeFrom.Elem().(*types.Basic).Kind() { case types.Byte: return c.createRuntimeCall("stringFromBytes", []llvm.Value{value}, ""), nil + case types.Rune: + return c.createRuntimeCall("stringFromRunes", []llvm.Value{value}, ""), nil default: return llvm.Value{}, c.makeError(pos, "todo: convert to string: "+typeFrom.String()) } diff --git a/src/runtime/string.go b/src/runtime/string.go index 6d9c3875..30736d30 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -89,6 +89,30 @@ func stringToBytes(x _string) (slice struct { return } +// Convert a []rune slice to a string. +func stringFromRunes(runeSlice []rune) (s _string) { + // Count the number of characters that will be in the string. + for _, r := range runeSlice { + _, numBytes := encodeUTF8(r) + s.length += numBytes + } + + // Allocate memory for the string. + s.ptr = (*byte)(alloc(s.length)) + + // Encode runes to UTF-8 and store the resulting bytes in the string. + index := uintptr(0) + for _, r := range runeSlice { + array, numBytes := encodeUTF8(r) + for _, c := range array[:numBytes] { + *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(s.ptr)) + index)) = c + index++ + } + } + + return +} + // Convert a string to []rune slice. func stringToRunes(s string) []rune { var n = 0 diff --git a/testdata/string.go b/testdata/string.go index f0aecd07..1c5ce630 100644 --- a/testdata/string.go +++ b/testdata/string.go @@ -8,12 +8,17 @@ func testRangeString() { func testStringToRunes() { var s = "abcü¢€𐍈°x" - for i,c := range []rune(s) { + for i, c := range []rune(s) { println(i, c) } } +func testRunesToString(r []rune) { + println("string from runes:", string(r)) +} + func main() { testRangeString() testStringToRunes() + testRunesToString([]rune{97, 98, 99, 252, 162, 8364, 66376, 176, 120}) } diff --git a/testdata/string.txt b/testdata/string.txt index b5dca198..54ff5f99 100644 --- a/testdata/string.txt +++ b/testdata/string.txt @@ -16,3 +16,4 @@ 6 66376 7 176 8 120 +string from runes: abcü¢€𐍈°x