mirror of
https://github.com/golang/go
synced 2024-11-22 01:04:40 -07:00
gc: implement []int(string) and []byte(string)
R=ken2 CC=golang-dev https://golang.org/cl/224060
This commit is contained in:
parent
b86c0b0c4a
commit
3910161307
@ -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
|
|||||||
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
|
|||||||
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*);
|
|||||||
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:
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
|||||||
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);
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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;
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user