1
0
mirror of https://github.com/golang/go synced 2024-11-21 20:14:52 -07:00

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

R=ken2
CC=golang-dev
https://golang.org/cl/224060
This commit is contained in:
Russ Cox 2010-02-25 15:11:07 -08:00
parent b86c0b0c4a
commit 3910161307
8 changed files with 175 additions and 14 deletions

View File

@ -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"

View File

@ -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,
@ -411,7 +412,7 @@ enum
OTINTER, OTINTER,
OTFUNC, OTFUNC,
OTARRAY, OTARRAY,
// misc // misc
ODDD, ODDD,
@ -458,7 +459,7 @@ enum
TIDEAL, // 32 TIDEAL, // 32
TNIL, TNIL,
TBLANK, TBLANK,
// pseudo-type for frame layout // pseudo-type for frame layout
TFUNCARGS, TFUNCARGS,
TCHANARGS, TCHANARGS,

View File

@ -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

View File

@ -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))
@ -1534,7 +1554,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
// TODO(rsc): drop first if in DDD cleanup // TODO(rsc): drop first if in DDD cleanup
if(t->etype != TINTER) if(t->etype != TINTER)
if(checkconv(nl->n->type, t->type, 0, &xx, &yy, desc) < 0) if(checkconv(nl->n->type, t->type, 0, &xx, &yy, desc) < 0)
yyerror("cannot use %+N as type %T in %s", nl->n, t->type, desc); yyerror("cannot use %+N as type %T in %s", nl->n, t->type, desc);
} }
goto out; goto out;
} }
@ -1587,7 +1607,7 @@ exportassignok(Type *t, char *desc)
// it only happens for fields in a ... struct. // it only happens for fields in a ... struct.
if(s != nil && !exportname(s->name) && s->pkg != localpkg) { if(s != nil && !exportname(s->name) && s->pkg != localpkg) {
char *prefix; char *prefix;
prefix = ""; prefix = "";
if(desc != nil) if(desc != nil)
prefix = " in "; prefix = " in ";
@ -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;
}

View File

@ -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,
@ -122,7 +123,7 @@ static void
domethod(Node *n) domethod(Node *n)
{ {
Node *nt; Node *nt;
nt = n->type->nname; nt = n->type->nname;
typecheck(&nt, Etype); typecheck(&nt, Etype);
if(nt->type == T) { if(nt->type == T) {
@ -142,7 +143,7 @@ walkdeftype(Node *n)
int maplineno, embedlineno, lno; int maplineno, embedlineno, lno;
Type *t; Type *t;
NodeList *l; NodeList *l;
nwalkdeftype++; nwalkdeftype++;
lno = lineno; lno = lineno;
setlineno(n); setlineno(n);
@ -183,7 +184,7 @@ walkdeftype(Node *n)
ret: ret:
lineno = lno; lineno = lno;
// if there are no type definitions going on, it's safe to // if there are no type definitions going on, it's safe to
// try to resolve the method types for the interfaces // try to resolve the method types for the interfaces
// we just read. // we just read.
@ -868,7 +869,7 @@ walkexpr(Node **np, NodeList **init)
case OINDEX: case OINDEX:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
// if range of type cannot exceed static array bound, // if range of type cannot exceed static array bound,
// disable bounds check // disable bounds check
if(!isslice(n->left->type)) if(!isslice(n->left->type))
@ -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);
@ -1448,18 +1460,18 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
{ {
Node *a, *n; Node *a, *n;
Type *tslice; Type *tslice;
tslice = typ(TARRAY); tslice = typ(TARRAY);
tslice->type = l->type->type; tslice->type = l->type->type;
tslice->bound = -1; tslice->bound = -1;
n = nod(OCOMPLIT, N, typenod(tslice)); n = nod(OCOMPLIT, N, typenod(tslice));
n->list = lr0; n->list = lr0;
typecheck(&n, Erv); typecheck(&n, Erv);
if(n->type == T) if(n->type == T)
fatal("mkdotargslice: typecheck failed"); fatal("mkdotargslice: typecheck failed");
walkexpr(&n, init); walkexpr(&n, init);
a = nod(OAS, nodarg(l, fp), n); a = nod(OAS, nodarg(l, fp), n);
nn = list(nn, convas(a, init)); nn = list(nn, convas(a, init));
return nn; return nn;
@ -1758,7 +1770,7 @@ walkprint(Node *nn, NodeList **init, int defer)
n = nod(OCONV, n, N); n = nod(OCONV, n, N);
n->type = t; n->type = t;
} }
if(defer) { if(defer) {
intypes = list(intypes, nod(ODCLFIELD, N, typenod(t))); intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
args = list(args, n); args = list(args, n);
@ -1788,7 +1800,7 @@ walkprint(Node *nn, NodeList **init, int defer)
calls = list(calls, mkcall("printnl", T, nil)); calls = list(calls, mkcall("printnl", T, nil));
typechecklist(calls, Etop); typechecklist(calls, Etop);
walkexprlist(calls, init); walkexprlist(calls, init);
if(op == OPANIC || op == OPANICN) if(op == OPANIC || op == OPANICN)
r = mkcall("panicl", T, nil); r = mkcall("panicl", T, nil);
else else

View File

@ -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,

View File

@ -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"

View File

@ -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);
} }