1
0
mirror of https://github.com/golang/go synced 2024-11-21 23:24:41 -07:00

gc: introduce rune

R=ken, r
CC=golang-dev
https://golang.org/cl/5293046
This commit is contained in:
Russ Cox 2011-10-25 22:19:39 -07:00
parent f4568882eb
commit 6ed3fa6553
15 changed files with 186 additions and 35 deletions

View File

@ -44,6 +44,8 @@ OFILES=\
walk.$O\
y1.tab.$O\
HOST_CFLAGS+=-DGOEXPERIMENT='"$(GOEXPERIMENT)"'
NOINSTALL=1
include ../../Make.clib

View File

@ -31,11 +31,11 @@ char *runtimeimport =
"func @\"\".slicestring1 (? string, ? int) string\n"
"func @\"\".intstring (? int64) string\n"
"func @\"\".slicebytetostring (? []byte) string\n"
"func @\"\".sliceinttostring (? []int) string\n"
"func @\"\".slicerunetostring (? []rune) string\n"
"func @\"\".stringtoslicebyte (? string) []byte\n"
"func @\"\".stringtosliceint (? string) []int\n"
"func @\"\".stringtoslicerune (? string) []rune\n"
"func @\"\".stringiter (? string, ? int) int\n"
"func @\"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
"func @\"\".stringiter2 (? string, ? int) (retk int, retv rune)\n"
"func @\"\".slicecopy (to any, fr any, wid uint32) int\n"
"func @\"\".slicestringcopy (to any, fr any) int\n"
"func @\"\".convI2E (elem any) any\n"

View File

@ -94,7 +94,7 @@ dumpprereq(Type *t)
if(t == T)
return;
if(t->printed || t == types[t->etype] || t == bytetype)
if(t->printed || t == types[t->etype] || t == bytetype || t == runetype)
return;
t->printed = 1;

View File

@ -785,6 +785,7 @@ EXTERN Type* types[NTYPE];
EXTERN Type* idealstring;
EXTERN Type* idealbool;
EXTERN Type* bytetype;
EXTERN Type* runetype;
EXTERN uchar simtype[NTYPE];
EXTERN uchar isptr[NTYPE];
EXTERN uchar isforw[NTYPE];
@ -840,6 +841,7 @@ EXTERN Node* nblank;
extern int thechar;
extern char* thestring;
EXTERN char* hunk;
EXTERN int32 nhunk;
EXTERN int32 thunk;
@ -854,6 +856,8 @@ EXTERN int packagequotes;
EXTERN int longsymnames;
EXTERN int compiling_runtime;
EXTERN int rune32;
/*
* y.tab.c
*/
@ -1009,6 +1013,7 @@ Node* renameinit(Node *n);
void cannedimports(char *file, char *cp);
void importfile(Val *f, int line);
char* lexname(int lex);
char* expstring(void);
void mkpackage(char* pkgname);
void unimportfile(void);
int32 yylex(void);

View File

@ -30,6 +30,60 @@ static void addidir(char*);
static int getlinepragma(void);
static char *goos, *goarch, *goroot;
// Compiler experiments.
// These are controlled by the GCEXPERIMENT environment
// variable recorded when the compiler is built.
static struct {
char *name;
int *val;
} exper[] = {
{"rune32", &rune32},
};
static void
addexp(char *s)
{
int i;
for(i=0; i<nelem(exper); i++) {
if(strcmp(exper[i].name, s) == 0) {
*exper[i].val = 1;
return;
}
}
print("unknown experiment %s\n", s);
exits("unknown experiment");
}
static void
setexp(void)
{
char *f[20];
int i, nf;
// The makefile #defines GOEXPERIMENT for us.
nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
for(i=0; i<nf; i++)
addexp(f[i]);
}
char*
expstring(void)
{
int i;
static char buf[512];
strcpy(buf, "X");
for(i=0; i<nelem(exper); i++)
if(*exper[i].val)
seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
if(strlen(buf) == 1)
strcpy(buf, "X,none");
buf[1] = ':';
return buf;
}
// Our own isdigit, isspace, isalpha, isalnum that take care
// of EOF and other out of range arguments.
static int
@ -94,7 +148,7 @@ usage(void)
print(" -u disable package unsafe\n");
print(" -w print the parse tree after typing\n");
print(" -x print lex tokens\n");
exits(0);
exits("usage");
}
void
@ -145,6 +199,8 @@ main(int argc, char *argv[])
goos = getgoos();
goarch = thestring;
setexp();
outfile = nil;
ARGBEGIN {
default:
@ -170,7 +226,10 @@ main(int argc, char *argv[])
break;
case 'V':
print("%cg version %s\n", thechar, getgoversion());
p = expstring();
if(strcmp(p, "X:none") == 0)
p = "";
print("%cg version %s%s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
exits(0);
} ARGEND
@ -540,7 +599,7 @@ importfile(Val *f, int line)
yyerror("import %s: not a go object file", file);
errorexit();
}
q = smprint("%s %s %s", getgoos(), thestring, getgoversion());
q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
if(strcmp(p+10, q) != 0) {
yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
errorexit();
@ -1720,6 +1779,18 @@ lexinit1(void)
s1 = pkglookup("byte", builtinpkg);
s1->lexical = LNAME;
s1->def = typenod(bytetype);
// rune alias
s = lookup("rune");
s->lexical = LNAME;
if(rune32)
runetype = typ(TINT32);
else
runetype = typ(TINT);
runetype->sym = s;
s1 = pkglookup("rune", builtinpkg);
s1->lexical = LNAME;
s1->def = typenod(runetype);
}
static void
@ -1761,6 +1832,10 @@ lexfini(void)
if(s->def == N)
s->def = typenod(bytetype);
s = lookup("rune");
if(s->def == N)
s->def = typenod(runetype);
types[TNIL] = typ(TNIL);
s = lookup("nil");
if(s->def == N) {

View File

@ -23,7 +23,7 @@ dumpobj(void)
errorexit();
}
Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
Bprint(bout, " exports automatically generated from\n");
Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
dumpexport();

View File

@ -54,7 +54,7 @@ typecheckrange(Node *n)
case TSTRING:
t1 = types[TINT];
t2 = types[TINT];
t2 = runetype;
break;
}
@ -216,7 +216,7 @@ walkrange(Node *n)
if(v2 == N)
a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
else {
hv2 = temp(types[TINT]);
hv2 = temp(runetype);
a = nod(OAS2, N, N);
a->list = list(list1(hv1), hv2);
fn = syslook("stringiter2", 0);

View File

@ -692,7 +692,7 @@ dtypesym(Type *t)
tbase = t->type;
dupok = tbase->sym == S;
if(compiling_runtime && (tbase == types[tbase->etype] || tbase == bytetype)) // int, float, etc
if(compiling_runtime && (tbase == types[tbase->etype] || tbase == bytetype || tbase == runetype)) // int, float, etc
goto ok;
// named types from other files are defined only by those files

View File

@ -47,11 +47,11 @@ func slicestring(string, int, int) string
func slicestring1(string, int) string
func intstring(int64) string
func slicebytetostring([]byte) string
func sliceinttostring([]int) string
func slicerunetostring([]rune) string
func stringtoslicebyte(string) []byte
func stringtosliceint(string) []int
func stringtoslicerune(string) []rune
func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int)
func stringiter2(string, int) (retk int, retv rune)
func slicecopy(to any, fr any, wid uint32) int
func slicestringcopy(to any, fr any) int

View File

@ -1285,13 +1285,15 @@ Tpretty(Fmt *fp, Type *t)
// called from typesym
if(t == bytetype)
t = types[bytetype->etype];
if(t == runetype)
t = types[runetype->etype];
}
if(t->etype != TFIELD
&& t->sym != S
&& !(fp->flags&FmtLong)) {
s = t->sym;
if((t == types[t->etype] && t->etype != TUNSAFEPTR) || t == bytetype)
if((t == types[t->etype] && t->etype != TUNSAFEPTR) || t == bytetype || t == runetype)
return fmtprint(fp, "%s", s->name);
if(exporting) {
if(fp->flags & FmtShort)
@ -1875,6 +1877,11 @@ eqtype(Type *t1, Type *t2)
if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
return 1;
break;
case TINT:
case TINT32:
if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
return 1;
break;
}
return 0;
}
@ -2100,7 +2107,7 @@ convertop(Type *src, Type *dst, char **why)
return OCONV;
}
// 6. src is an integer or has type []byte or []int
// 6. src is an integer or has type []byte or []rune
// and dst is a string type.
if(isint[src->etype] && dst->etype == TSTRING)
return ORUNESTR;
@ -2108,16 +2115,16 @@ convertop(Type *src, Type *dst, char **why)
if(isslice(src) && src->sym == nil && dst->etype == TSTRING) {
if(eqtype(src->type, bytetype))
return OARRAYBYTESTR;
if(eqtype(src->type, types[TINT]))
if(eqtype(src->type, runetype))
return OARRAYRUNESTR;
}
// 7. src is a string and dst is []byte or []int.
// 7. src is a string and dst is []byte or []rune.
// String to slice.
if(src->etype == TSTRING && isslice(dst) && dst->sym == nil) {
if(eqtype(dst->type, bytetype))
return OSTRARRAYBYTE;
if(eqtype(dst->type, types[TINT]))
if(eqtype(dst->type, runetype))
return OSTRARRAYRUNE;
}

View File

@ -2469,7 +2469,7 @@ stringtoarraylit(Node **np)
while(p < ep)
l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
} else {
// utf-8 []int
// utf-8 []rune
while(p < ep) {
p += chartorune(&r, p);
l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));

View File

@ -1151,8 +1151,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OARRAYRUNESTR:
// sliceinttostring([]int) string;
n = mkcall("sliceinttostring", n->type, init, n->left);
// slicerunetostring([]rune) string;
n = mkcall("slicerunetostring", n->type, init, n->left);
goto ret;
case OSTRARRAYBYTE:
@ -1161,8 +1161,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OSTRARRAYRUNE:
// stringtosliceint(string) []int
n = mkcall("stringtosliceint", n->type, init, n->left);
// stringtoslicerune(string) []rune
n = mkcall("stringtoslicerune", n->type, init, n->left);
goto ret;
case OCMPIFACE:

View File

@ -611,6 +611,43 @@ qcmd(char *arname, int count, char **files)
close(fd);
}
/*
* does the object header line p match the last one we saw?
* update *lastp if it gets more specific.
*/
int
matchhdr(char *p, char **lastp)
{
int n;
char *last;
// no information?
last = *lastp;
if(last == nil) {
*lastp = strdup(p);
return 1;
}
// identical match?
if(strcmp(last, p) == 0)
return 1;
// last has extra fields
n = strlen(p);
if(n < strlen(last) && last[n] == ' ')
return 1;
// p has extra fields - save in last
n = strlen(last);
if(n < strlen(p) && p[n] == ' ') {
free(last);
*lastp = strdup(p);
return 1;
}
return 0;
}
/*
* extract the symbol references from an object file
*/
@ -670,19 +707,24 @@ scanobj(Biobuf *b, Arfile *ap, long size)
return;
}
if ((lastobj >= 0 && obj != lastobj) || (objhdr != nil && strcmp(p, objhdr) != 0)) {
fprint(2, "gopack: inconsistent object file %s\n", file);
if (!matchhdr(p, &objhdr)) {
fprint(2, "gopack: inconsistent object file %s: [%s] vs [%s]\n", file, p, objhdr);
errors++;
allobj = 0;
free(p);
return;
}
lastobj = obj;
if(objhdr == nil)
objhdr = p;
else
free(p);
// Old check. Should be impossible since objhdrs match, but keep the check anyway.
if (lastobj >= 0 && obj != lastobj) {
fprint(2, "gopack: inconsistent object file %s\n", file);
errors++;
allobj = 0;
return;
}
lastobj = obj;
if (!readar(b, obj, offset+size, 0)) {
fprint(2, "gopack: invalid symbol reference in file %s\n", file);
errors++;

View File

@ -46,6 +46,7 @@ static int cout = -1;
char* goroot;
char* goarch;
char* goos;
char* theline;
void
Lflag(char *arg)
@ -478,12 +479,31 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
diag("%s: not an object file", pn);
return;
}
// First, check that the basic goos, string, and version match.
t = smprint("%s %s %s ", getgoos(), thestring, getgoversion());
if(strcmp(line+10, t) != 0 && !debug['f']) {
line[n] = ' ';
if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, t);
free(t);
return;
}
// Second, check that longer lines match each other exactly,
// so that the Go compiler and write additional information
// that must be the same from run to run.
line[n] = '\0';
if(n-10 > strlen(t)) {
if(theline == nil)
theline = strdup(line+10);
else if(strcmp(theline, line+10) != 0) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
free(t);
return;
}
}
free(t);
line[n] = '\n';

View File

@ -278,7 +278,7 @@ func stringtoslicebyte(s String) (b Slice) {
runtime·memmove(b.array, s.str, s.len);
}
func sliceinttostring(b Slice) (s String) {
func slicerunetostring(b Slice) (s String) {
int32 siz1, siz2, i;
int32 *a;
byte dum[8];
@ -301,13 +301,13 @@ func sliceinttostring(b Slice) (s String) {
s.str[s.len] = 0;
}
func stringtosliceint(s String) (b Slice) {
func stringtoslicerune(s String) (b Slice) {
int32 n;
int32 dum, *r;
uint8 *p, *ep;
// two passes.
// unlike sliceinttostring, no race because strings are immutable.
// unlike slicerunetostring, no race because strings are immutable.
p = s.str;
ep = s.str+s.len;
n = 0;