Commit 39101613 authored by Russ Cox's avatar Russ Cox

gc: implement []int(string) and []byte(string)

R=ken2
CC=golang-dev
https://golang.org/cl/224060
parent b86c0b0c
...@@ -26,6 +26,8 @@ char *runtimeimport = ...@@ -26,6 +26,8 @@ char *runtimeimport =
"func \"\".intstring (? int64) string\n" "func \"\".intstring (? int64) string\n"
"func \"\".slicebytetostring (? []uint8) string\n" "func \"\".slicebytetostring (? []uint8) string\n"
"func \"\".sliceinttostring (? []int) string\n" "func \"\".sliceinttostring (? []int) string\n"
"func \"\".stringtoslicebyte (? string) []uint8\n"
"func \"\".stringtosliceint (? string) []int\n"
"func \"\".stringiter (? string, ? int) int\n" "func \"\".stringiter (? string, ? int) int\n"
"func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n" "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
"func \"\".slicecopy (to any, fr any, wid uint32) int\n" "func \"\".slicecopy (to any, fr any, wid uint32) int\n"
......
...@@ -351,6 +351,7 @@ enum ...@@ -351,6 +351,7 @@ enum
OAPPENDSTR, OAPPENDSTR,
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR, OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP, OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD, OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
......
...@@ -38,6 +38,8 @@ func indexstring(string, int) byte ...@@ -38,6 +38,8 @@ func indexstring(string, int) byte
func intstring(int64) string func intstring(int64) string
func slicebytetostring([]byte) string func slicebytetostring([]byte) string
func sliceinttostring([]int) string func sliceinttostring([]int) string
func stringtoslicebyte(string) []byte
func stringtosliceint(string) []int
func stringiter(string, int) int func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int) func stringiter2(string, int) (retk int, retv int)
func slicecopy(to any, fr any, wid uint32) int func slicecopy(to any, fr any, wid uint32) int
......
...@@ -32,6 +32,7 @@ static void checklvalue(Node*, char*); ...@@ -32,6 +32,7 @@ static void checklvalue(Node*, char*);
static void checkassign(Node*); static void checkassign(Node*);
static void checkassignlist(NodeList*); static void checkassignlist(NodeList*);
static void toslice(Node**); static void toslice(Node**);
static void stringtoarraylit(Node**);
void void
typechecklist(NodeList *l, int top) typechecklist(NodeList *l, int top)
...@@ -835,6 +836,13 @@ reswitch: ...@@ -835,6 +836,13 @@ reswitch:
n = typecheckconv(n, n->left, n->type, 1, "conversion"); n = typecheckconv(n, n->left, n->type, 1, "conversion");
if(n->type == T) if(n->type == T)
goto error; goto error;
switch(n->op) {
case OSTRARRAYBYTE:
case OSTRARRAYRUNE:
if(n->left->op == OLITERAL)
stringtoarraylit(&n);
break;
}
goto ret; goto ret;
case OMAKE: case OMAKE:
...@@ -1406,6 +1414,18 @@ checkconv(Type *nt, Type *t, int explicit, int *op, int *et, char *desc) ...@@ -1406,6 +1414,18 @@ checkconv(Type *nt, Type *t, int explicit, int *op, int *et, char *desc)
} }
} }
// from string
if(istype(nt, TSTRING) && isslice(t) && t->sym == S) {
switch(t->type->etype) {
case TUINT8:
*op = OSTRARRAYBYTE;
return 1;
case TINT:
*op = OSTRARRAYRUNE;
return 1;
}
}
// convert to unsafe pointer // convert to unsafe pointer
if(isptrto(t, TANY) if(isptrto(t, TANY)
&& (isptr[nt->etype] || nt->etype == TUINTPTR)) && (isptr[nt->etype] || nt->etype == TUINTPTR))
...@@ -2164,3 +2184,39 @@ typecheckfunc(Node *n) ...@@ -2164,3 +2184,39 @@ typecheckfunc(Node *n)
if(rcvr != nil && n->shortname != N && !isblank(n->shortname)) if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
addmethod(n->shortname->sym, t, 1); addmethod(n->shortname->sym, t, 1);
} }
static void
stringtoarraylit(Node **np)
{
int32 i;
NodeList *l;
Strlit *s;
char *p, *ep;
Rune r;
Node *nn, *n;
n = *np;
if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
fatal("stringtoarraylit %N", n);
s = n->left->val.u.sval;
l = nil;
p = s->s;
ep = s->s + s->len;
i = 0;
if(n->type->type->etype == TUINT8) {
// raw []byte
while(p < ep)
l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
} else {
// utf-8 []int
while(p < ep) {
p += chartorune(&r, p);
l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
}
}
nn = nod(OCOMPLIT, N, typenod(n->type));
nn->list = l;
typecheck(&nn, Erv);
*np = nn;
}
...@@ -8,6 +8,7 @@ static Node* walkprint(Node*, NodeList**, int); ...@@ -8,6 +8,7 @@ static Node* walkprint(Node*, NodeList**, int);
static Node* conv(Node*, Type*); static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**); static Node* makenewvar(Type*, NodeList**, Node**);
enum enum
{ {
Inone, Inone,
...@@ -1092,10 +1093,20 @@ walkexpr(Node **np, NodeList **init) ...@@ -1092,10 +1093,20 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OARRAYRUNESTR: case OARRAYRUNESTR:
// sliceinttostring([]byte) string; // sliceinttostring([]int) string;
n = mkcall("sliceinttostring", n->type, init, n->left); n = mkcall("sliceinttostring", n->type, init, n->left);
goto ret; goto ret;
case OSTRARRAYBYTE:
// stringtoslicebyte(string) []byte;
n = mkcall("stringtoslicebyte", n->type, init, n->left);
goto ret;
case OSTRARRAYRUNE:
// stringtosliceint(string) []int
n = mkcall("stringtosliceint", n->type, init, n->left);
goto ret;
case OCMPIFACE: case OCMPIFACE:
// ifaceeq(i1 any-1, i2 any-2) (ret bool); // ifaceeq(i1 any-1, i2 any-2) (ret bool);
if(!eqtype(n->left->type, n->right->type)) if(!eqtype(n->left->type, n->right->type))
...@@ -1117,6 +1128,7 @@ walkexpr(Node **np, NodeList **init) ...@@ -1117,6 +1128,7 @@ walkexpr(Node **np, NodeList **init)
case OARRAYLIT: case OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
arraylit:
nvar = nod(OXXX, N, N); nvar = nod(OXXX, N, N);
tempname(nvar, n->type); tempname(nvar, n->type);
anylit(n, nvar, init); anylit(n, nvar, init);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package runtime package runtime
#include "runtime.h" #include "runtime.h"
#include "malloc.h"
String emptystring; String emptystring;
...@@ -210,6 +211,12 @@ func slicebytetostring(b Slice) (s String) { ...@@ -210,6 +211,12 @@ func slicebytetostring(b Slice) (s String) {
mcpy(s.str, b.array, s.len); mcpy(s.str, b.array, s.len);
} }
func stringtoslicebyte(s String) (b Slice) {
b.array = mallocgc(s.len, RefNoPointers, 1, 1);
b.len = s.len;
b.cap = s.len;
mcpy(b.array, s.str, s.len);
}
func sliceinttostring(b Slice) (s String) { func sliceinttostring(b Slice) (s String) {
int32 siz1, siz2, i; int32 siz1, siz2, i;
...@@ -233,6 +240,30 @@ func sliceinttostring(b Slice) (s String) { ...@@ -233,6 +240,30 @@ func sliceinttostring(b Slice) (s String) {
s.len = siz2; s.len = siz2;
} }
func stringtosliceint(s String) (b Slice) {
int32 n;
int32 dum, *r;
uint8 *p, *ep;
// two passes.
// unlike sliceinttostring, no race because strings are immutable.
p = s.str;
ep = s.str+s.len;
n = 0;
while(p < ep) {
p += charntorune(&dum, p, ep-p);
n++;
}
b.array = mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
b.len = n;
b.cap = n;
p = s.str;
r = (int32*)b.array;
while(p < ep)
p += charntorune(r++, p, ep-p);
}
enum enum
{ {
Runeself = 0x80, Runeself = 0x80,
......
...@@ -35,3 +35,30 @@ var good2 int = 1.0; ...@@ -35,3 +35,30 @@ var good2 int = 1.0;
var good3 int = 1e9; var good3 int = 1e9;
var good4 float = 1e20; var good4 float = 1e20;
// explicit conversion of string is okay
var _ = []int("abc")
var _ = []byte("abc")
// implicit is not
var _ []int = "abc" // ERROR "cannot use|incompatible|invalid"
var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid"
// named string is okay
type Tstring string
var ss Tstring = "abc"
var _ = []int(ss)
var _ = []byte(ss)
// implicit is still not
var _ []int = ss // ERROR "cannot use|incompatible|invalid"
var _ []byte = ss // ERROR "cannot use|incompatible|invalid"
// named slice is not
type Tint []int
type Tbyte []byte
var _ = Tint("abc") // ERROR "convert|incompatible|invalid"
var _ = Tbyte("abc") // ERROR "convert|incompatible|invalid"
// implicit is still not
var _ Tint = "abc" // ERROR "cannot use|incompatible|invalid"
var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid"
...@@ -34,6 +34,19 @@ func assert(a, b, c string) { ...@@ -34,6 +34,19 @@ func assert(a, b, c string) {
} }
} }
const (
gx1 = "aä本☺"
gx2 = "aä\xFF\xFF本☺"
gx2fix = "aä\uFFFD\uFFFD本☺"
)
var (
gr1 = []int(gx1)
gr2 = []int(gx2)
gb1 = []byte(gx1)
gb2 = []byte(gx2)
)
func main() { func main() {
ecode = 0; ecode = 0;
s := s :=
...@@ -86,5 +99,22 @@ func main() { ...@@ -86,5 +99,22 @@ func main() {
r = 0x10ffff + 1; r = 0x10ffff + 1;
s = string(r); s = string(r);
assert(s, "\xef\xbf\xbd", "too-large rune"); assert(s, "\xef\xbf\xbd", "too-large rune");
assert(string(gr1), gx1, "global ->[]int")
assert(string(gr2), gx2fix, "global invalid ->[]int")
assert(string(gb1), gx1, "->[]byte")
assert(string(gb2), gx2, "global invalid ->[]byte")
var (
r1 = []int(gx1)
r2 = []int(gx2)
b1 = []byte(gx1)
b2 = []byte(gx2)
)
assert(string(r1), gx1, "->[]int")
assert(string(r2), gx2fix, "invalid ->[]int")
assert(string(b1), gx1, "->[]byte")
assert(string(b2), gx2, "invalid ->[]byte")
os.Exit(ecode); os.Exit(ecode);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment