summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/Makefile67
-rw-r--r--src/cmd/gc/align.c659
-rwxr-xr-xsrc/cmd/gc/bisonerrors124
-rw-r--r--src/cmd/gc/bits.c158
-rw-r--r--src/cmd/gc/builtin.c.boot115
-rw-r--r--src/cmd/gc/closure.c247
-rw-r--r--src/cmd/gc/const.c1283
-rw-r--r--src/cmd/gc/cplx.c479
-rw-r--r--src/cmd/gc/dcl.c1248
-rw-r--r--src/cmd/gc/doc.go55
-rw-r--r--src/cmd/gc/export.c428
-rw-r--r--src/cmd/gc/gen.c790
-rw-r--r--src/cmd/gc/go.errors70
-rw-r--r--src/cmd/gc/go.h1265
-rw-r--r--src/cmd/gc/go.y1966
-rw-r--r--src/cmd/gc/init.c195
-rw-r--r--src/cmd/gc/lex.c1935
-rw-r--r--src/cmd/gc/md5.c290
-rw-r--r--src/cmd/gc/md5.h16
-rwxr-xr-xsrc/cmd/gc/mkbuiltin31
-rw-r--r--src/cmd/gc/mkbuiltin1.c90
-rwxr-xr-xsrc/cmd/gc/mkopnames24
-rw-r--r--src/cmd/gc/mparith1.c509
-rw-r--r--src/cmd/gc/mparith2.c683
-rw-r--r--src/cmd/gc/mparith3.c313
-rw-r--r--src/cmd/gc/obj.c292
-rw-r--r--src/cmd/gc/pgen.c210
-rw-r--r--src/cmd/gc/print.c454
-rw-r--r--src/cmd/gc/range.c252
-rw-r--r--src/cmd/gc/reflect.c939
-rw-r--r--src/cmd/gc/runtime.go131
-rw-r--r--src/cmd/gc/select.c343
-rw-r--r--src/cmd/gc/sinit.c971
-rw-r--r--src/cmd/gc/subr.c3851
-rw-r--r--src/cmd/gc/swt.c896
-rw-r--r--src/cmd/gc/typecheck.c2822
-rw-r--r--src/cmd/gc/unsafe.c97
-rw-r--r--src/cmd/gc/unsafe.go22
-rw-r--r--src/cmd/gc/walk.c2177
39 files changed, 0 insertions, 26497 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
deleted file mode 100644
index 286618ec1..000000000
--- a/src/cmd/gc/Makefile
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-O:=$(HOST_O)
-
-LIB=gc.a
-
-HFILES=\
- go.h\
- y.tab.h\
- md5.h\
-
-YFILES=\
- go.y\
-
-OFILES=\
- align.$O\
- bits.$O\
- builtin.$O\
- closure.$O\
- const.$O\
- dcl.$O\
- export.$O\
- gen.$O\
- init.$O\
- lex.$O\
- md5.$O\
- mparith1.$O\
- mparith2.$O\
- mparith3.$O\
- obj.$O\
- print.$O\
- range.$O\
- reflect.$O\
- select.$O\
- sinit.$O\
- subr.$O\
- swt.$O\
- typecheck.$O\
- unsafe.$O\
- walk.$O\
- y1.tab.$O\
-
-NOINSTALL=1
-include ../../Make.clib
-
-install: $(LIB)
-
-y1.tab.c: y.tab.c # make yystate global, yytname mutable
- cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
-
-yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too
- awk -f bisonerrors y.output go.errors >yerr.h
-
-subr.$O: yerr.h
-
-builtin.c: builtin.c.boot
- cp builtin.c.boot builtin.c
-
-subr.$O: opnames.h
-
-opnames.h: mkopnames go.h
- ./mkopnames go.h >opnames.h
-
-CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
deleted file mode 100644
index 7fcac4833..000000000
--- a/src/cmd/gc/align.c
+++ /dev/null
@@ -1,659 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/*
- * machine size and rounding
- * alignment is dictated around
- * the size of a pointer, set in betypeinit
- * (see ../6g/galign.c).
- */
-
-static int defercalc;
-
-uint32
-rnd(uint32 o, uint32 r)
-{
- if(r < 1 || r > 8 || (r&(r-1)) != 0)
- fatal("rnd");
- return (o+r-1)&~(r-1);
-}
-
-static void
-offmod(Type *t)
-{
- Type *f;
- int32 o;
-
- o = 0;
- for(f=t->type; f!=T; f=f->down) {
- if(f->etype != TFIELD)
- fatal("widstruct: not TFIELD: %lT", f);
- f->width = o;
- o += widthptr;
- }
-}
-
-static uint32
-widstruct(Type *t, uint32 o, int flag)
-{
- Type *f;
- int32 w, maxalign;
-
- maxalign = flag;
- if(maxalign < 1)
- maxalign = 1;
- for(f=t->type; f!=T; f=f->down) {
- if(f->etype != TFIELD)
- fatal("widstruct: not TFIELD: %lT", f);
- dowidth(f->type);
- if(f->type->align > maxalign)
- maxalign = f->type->align;
- if(f->type->width < 0)
- fatal("invalid width %lld", f->type->width);
- w = f->type->width;
- if(f->type->align > 0)
- o = rnd(o, f->type->align);
- f->width = o; // really offset for TFIELD
- if(f->nname != N) {
- // this same stackparam logic is in addrescapes
- // in typecheck.c. usually addrescapes runs after
- // widstruct, in which case we could drop this,
- // but function closure functions are the exception.
- if(f->nname->stackparam) {
- f->nname->stackparam->xoffset = o;
- f->nname->xoffset = 0;
- } else
- f->nname->xoffset = o;
- }
- o += w;
- }
- // final width is rounded
- if(flag)
- o = rnd(o, maxalign);
- t->align = maxalign;
-
- // type width only includes back to first field's offset
- if(t->type == T)
- t->width = 0;
- else
- t->width = o - t->type->width;
- return o;
-}
-
-void
-dowidth(Type *t)
-{
- int32 et;
- int64 w;
- int lno;
- Type *t1;
-
- if(widthptr == 0)
- fatal("dowidth without betypeinit");
-
- if(t == T)
- return;
-
- if(t->width > 0)
- return;
-
- if(t->width == -2) {
- lno = lineno;
- lineno = t->lineno;
- yyerror("invalid recursive type %T", t);
- t->width = 0;
- lineno = lno;
- return;
- }
-
- // defer checkwidth calls until after we're done
- defercalc++;
-
- lno = lineno;
- lineno = t->lineno;
- t->width = -2;
- t->align = 0;
-
- et = t->etype;
- switch(et) {
- case TFUNC:
- case TCHAN:
- case TMAP:
- case TSTRING:
- break;
-
- default:
- /* simtype == 0 during bootstrap */
- if(simtype[t->etype] != 0)
- et = simtype[t->etype];
- break;
- }
-
- w = 0;
- switch(et) {
- default:
- fatal("dowidth: unknown type: %T", t);
- break;
-
- /* compiler-specific stuff */
- case TINT8:
- case TUINT8:
- case TBOOL: // bool is int8
- w = 1;
- break;
- case TINT16:
- case TUINT16:
- w = 2;
- break;
- case TINT32:
- case TUINT32:
- case TFLOAT32:
- w = 4;
- break;
- case TINT64:
- case TUINT64:
- case TFLOAT64:
- case TCOMPLEX64:
- w = 8;
- t->align = widthptr;
- break;
- case TCOMPLEX128:
- w = 16;
- t->align = widthptr;
- break;
- case TPTR32:
- w = 4;
- checkwidth(t->type);
- break;
- case TPTR64:
- w = 8;
- checkwidth(t->type);
- break;
- case TUNSAFEPTR:
- w = widthptr;
- break;
- case TINTER: // implemented as 2 pointers
- w = 2*widthptr;
- t->align = widthptr;
- offmod(t);
- break;
- case TCHAN: // implemented as pointer
- w = widthptr;
- checkwidth(t->type);
-
- // make fake type to check later to
- // trigger channel argument check.
- t1 = typ(TCHANARGS);
- t1->type = t;
- checkwidth(t1);
- break;
- case TCHANARGS:
- t1 = t->type;
- dowidth(t->type); // just in case
- if(t1->type->width >= (1<<16))
- yyerror("channel element type too large (>64kB)");
- t->width = 1;
- break;
- case TMAP: // implemented as pointer
- w = widthptr;
- checkwidth(t->type);
- checkwidth(t->down);
- break;
- case TFORW: // should have been filled in
- yyerror("invalid recursive type %T", t);
- w = 1; // anything will do
- break;
- case TANY:
- // dummy type; should be replaced before use.
- if(!debug['A'])
- fatal("dowidth any");
- w = 1; // anything will do
- break;
- case TSTRING:
- if(sizeof_String == 0)
- fatal("early dowidth string");
- w = sizeof_String;
- t->align = widthptr;
- break;
- case TARRAY:
- if(t->type == T)
- break;
- if(t->bound >= 0) {
- uint64 cap;
-
- dowidth(t->type);
- if(t->type->width == 0)
- fatal("no width for type %T", t->type);
- if(tptr == TPTR32)
- cap = ((uint32)-1) / t->type->width;
- else
- cap = ((uint64)-1) / t->type->width;
- if(t->bound > cap)
- yyerror("type %lT larger than address space", t);
- w = t->bound * t->type->width;
- t->align = t->type->align;
- if(w == 0) {
- w = 1;
- t->align = 1;
- }
- }
- else if(t->bound == -1) {
- w = sizeof_Array;
- checkwidth(t->type);
- t->align = widthptr;
- }
- else if(t->bound == -100)
- yyerror("use of [...] array outside of array literal");
- else
- fatal("dowidth %T", t); // probably [...]T
- break;
-
- case TSTRUCT:
- if(t->funarg)
- fatal("dowidth fn struct %T", t);
- w = widstruct(t, 0, 1);
- if(w == 0) {
- w = 1;
- t->align = 1;
- }
- break;
-
- case TFUNC:
- // make fake type to check later to
- // trigger function argument computation.
- t1 = typ(TFUNCARGS);
- t1->type = t;
- checkwidth(t1);
-
- // width of func type is pointer
- w = widthptr;
- break;
-
- case TFUNCARGS:
- // function is 3 cated structures;
- // compute their widths as side-effect.
- t1 = t->type;
- w = widstruct(*getthis(t1), 0, 0);
- w = widstruct(*getinarg(t1), w, widthptr);
- w = widstruct(*getoutarg(t1), w, widthptr);
- t1->argwid = w;
- if(w%widthptr)
- warn("bad type %T %d\n", t1, w);
- t->align = 1;
- break;
- }
-
- // catch all for error cases; avoid divide by zero later
- if(w == 0)
- w = 1;
- t->width = w;
- if(t->align == 0) {
- if(w > 8 || (w&(w-1)) != 0)
- fatal("invalid alignment for %T", t);
- t->align = w;
- }
- lineno = lno;
-
- if(defercalc == 1)
- resumecheckwidth();
- else
- --defercalc;
-}
-
-/*
- * when a type's width should be known, we call checkwidth
- * to compute it. during a declaration like
- *
- * type T *struct { next T }
- *
- * it is necessary to defer the calculation of the struct width
- * until after T has been initialized to be a pointer to that struct.
- * similarly, during import processing structs may be used
- * before their definition. in those situations, calling
- * defercheckwidth() stops width calculations until
- * resumecheckwidth() is called, at which point all the
- * checkwidths that were deferred are executed.
- * dowidth should only be called when the type's size
- * is needed immediately. checkwidth makes sure the
- * size is evaluated eventually.
- */
-typedef struct TypeList TypeList;
-struct TypeList {
- Type *t;
- TypeList *next;
-};
-
-static TypeList *tlfree;
-static TypeList *tlq;
-
-void
-checkwidth(Type *t)
-{
- TypeList *l;
-
- if(t == T)
- return;
-
- // function arg structs should not be checked
- // outside of the enclosing function.
- if(t->funarg)
- fatal("checkwidth %T", t);
-
- if(!defercalc) {
- dowidth(t);
- return;
- }
- if(t->deferwidth)
- return;
- t->deferwidth = 1;
-
- l = tlfree;
- if(l != nil)
- tlfree = l->next;
- else
- l = mal(sizeof *l);
-
- l->t = t;
- l->next = tlq;
- tlq = l;
-}
-
-void
-defercheckwidth(void)
-{
- // we get out of sync on syntax errors, so don't be pedantic.
- if(defercalc && nerrors == 0)
- fatal("defercheckwidth");
- defercalc = 1;
-}
-
-void
-resumecheckwidth(void)
-{
- TypeList *l;
-
- if(!defercalc)
- fatal("resumecheckwidth");
- for(l = tlq; l != nil; l = tlq) {
- l->t->deferwidth = 0;
- tlq = l->next;
- dowidth(l->t);
- l->next = tlfree;
- tlfree = l;
- }
- defercalc = 0;
-}
-
-void
-typeinit(void)
-{
- int i, etype, sameas;
- Type *t;
- Sym *s, *s1;
-
- if(widthptr == 0)
- fatal("typeinit before betypeinit");
-
- for(i=0; i<NTYPE; i++)
- simtype[i] = i;
-
- types[TPTR32] = typ(TPTR32);
- dowidth(types[TPTR32]);
-
- types[TPTR64] = typ(TPTR64);
- dowidth(types[TPTR64]);
-
- t = typ(TUNSAFEPTR);
- types[TUNSAFEPTR] = t;
- t->sym = pkglookup("Pointer", unsafepkg);
- t->sym->def = typenod(t);
-
- dowidth(types[TUNSAFEPTR]);
-
- tptr = TPTR32;
- if(widthptr == 8)
- tptr = TPTR64;
-
- for(i=TINT8; i<=TUINT64; i++)
- isint[i] = 1;
- isint[TINT] = 1;
- isint[TUINT] = 1;
- isint[TUINTPTR] = 1;
-
- isfloat[TFLOAT32] = 1;
- isfloat[TFLOAT64] = 1;
-
- iscomplex[TCOMPLEX64] = 1;
- iscomplex[TCOMPLEX128] = 1;
-
- isptr[TPTR32] = 1;
- isptr[TPTR64] = 1;
-
- isforw[TFORW] = 1;
-
- issigned[TINT] = 1;
- issigned[TINT8] = 1;
- issigned[TINT16] = 1;
- issigned[TINT32] = 1;
- issigned[TINT64] = 1;
-
- /*
- * initialize okfor
- */
- for(i=0; i<NTYPE; i++) {
- if(isint[i] || i == TIDEAL) {
- okforeq[i] = 1;
- okforcmp[i] = 1;
- okforarith[i] = 1;
- okforadd[i] = 1;
- okforand[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- minintval[i] = mal(sizeof(*minintval[i]));
- maxintval[i] = mal(sizeof(*maxintval[i]));
- }
- if(isfloat[i]) {
- okforeq[i] = 1;
- okforcmp[i] = 1;
- okforadd[i] = 1;
- okforarith[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- minfltval[i] = mal(sizeof(*minfltval[i]));
- maxfltval[i] = mal(sizeof(*maxfltval[i]));
- }
- if(iscomplex[i]) {
- okforeq[i] = 1;
- okforadd[i] = 1;
- okforarith[i] = 1;
- okforconst[i] = 1;
- issimple[i] = 1;
- }
- }
-
- issimple[TBOOL] = 1;
-
- okforadd[TSTRING] = 1;
-
- okforbool[TBOOL] = 1;
-
- okforcap[TARRAY] = 1;
- okforcap[TCHAN] = 1;
-
- okforconst[TBOOL] = 1;
- okforconst[TSTRING] = 1;
-
- okforlen[TARRAY] = 1;
- okforlen[TCHAN] = 1;
- okforlen[TMAP] = 1;
- okforlen[TSTRING] = 1;
-
- okforeq[TPTR32] = 1;
- okforeq[TPTR64] = 1;
- okforeq[TUNSAFEPTR] = 1;
- okforeq[TINTER] = 1;
- okforeq[TMAP] = 1;
- okforeq[TCHAN] = 1;
- okforeq[TFUNC] = 1;
- okforeq[TSTRING] = 1;
- okforeq[TBOOL] = 1;
- okforeq[TARRAY] = 1; // refined in typecheck
-
- okforcmp[TSTRING] = 1;
-
- for(i=0; i<nelem(okfor); i++)
- okfor[i] = okfornone;
-
- // binary
- okfor[OADD] = okforadd;
- okfor[OAND] = okforand;
- okfor[OANDAND] = okforbool;
- okfor[OANDNOT] = okforand;
- okfor[ODIV] = okforarith;
- okfor[OEQ] = okforeq;
- okfor[OGE] = okforcmp;
- okfor[OGT] = okforcmp;
- okfor[OLE] = okforcmp;
- okfor[OLT] = okforcmp;
- okfor[OMOD] = okforand;
- okfor[OMUL] = okforarith;
- okfor[ONE] = okforeq;
- okfor[OOR] = okforand;
- okfor[OOROR] = okforbool;
- okfor[OSUB] = okforarith;
- okfor[OXOR] = okforand;
- okfor[OLSH] = okforand;
- okfor[ORSH] = okforand;
-
- // unary
- okfor[OCOM] = okforand;
- okfor[OMINUS] = okforarith;
- okfor[ONOT] = okforbool;
- okfor[OPLUS] = okforarith;
-
- // special
- okfor[OCAP] = okforcap;
- okfor[OLEN] = okforlen;
-
- // comparison
- iscmp[OLT] = 1;
- iscmp[OGT] = 1;
- iscmp[OGE] = 1;
- iscmp[OLE] = 1;
- iscmp[OEQ] = 1;
- iscmp[ONE] = 1;
-
- mpatofix(maxintval[TINT8], "0x7f");
- mpatofix(minintval[TINT8], "-0x80");
- mpatofix(maxintval[TINT16], "0x7fff");
- mpatofix(minintval[TINT16], "-0x8000");
- mpatofix(maxintval[TINT32], "0x7fffffff");
- mpatofix(minintval[TINT32], "-0x80000000");
- mpatofix(maxintval[TINT64], "0x7fffffffffffffff");
- mpatofix(minintval[TINT64], "-0x8000000000000000");
-
- mpatofix(maxintval[TUINT8], "0xff");
- mpatofix(maxintval[TUINT16], "0xffff");
- mpatofix(maxintval[TUINT32], "0xffffffff");
- mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
-
- /* f is valid float if min < f < max. (min and max are not themselves valid.) */
- mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/
- mpatoflt(minfltval[TFLOAT32], "-33554431p103");
- mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */
- mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
-
- maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32];
- minfltval[TCOMPLEX64] = minfltval[TFLOAT32];
- maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64];
- minfltval[TCOMPLEX128] = minfltval[TFLOAT64];
-
- /* for walk to use in error messages */
- types[TFUNC] = functype(N, nil, nil);
-
- /* types used in front end */
- // types[TNIL] got set early in lexinit
- types[TIDEAL] = typ(TIDEAL);
- types[TINTER] = typ(TINTER);
-
- /* simple aliases */
- simtype[TMAP] = tptr;
- simtype[TCHAN] = tptr;
- simtype[TFUNC] = tptr;
- simtype[TUNSAFEPTR] = tptr;
-
- /* pick up the backend typedefs */
- for(i=0; typedefs[i].name; i++) {
- s = lookup(typedefs[i].name);
- s1 = pkglookup(typedefs[i].name, builtinpkg);
-
- etype = typedefs[i].etype;
- if(etype < 0 || etype >= nelem(types))
- fatal("typeinit: %s bad etype", s->name);
- sameas = typedefs[i].sameas;
- if(sameas < 0 || sameas >= nelem(types))
- fatal("typeinit: %s bad sameas", s->name);
- simtype[etype] = sameas;
- minfltval[etype] = minfltval[sameas];
- maxfltval[etype] = maxfltval[sameas];
- minintval[etype] = minintval[sameas];
- maxintval[etype] = maxintval[sameas];
-
- t = types[etype];
- if(t != T)
- fatal("typeinit: %s already defined", s->name);
-
- t = typ(etype);
- t->sym = s;
-
- dowidth(t);
- types[etype] = t;
- s1->def = typenod(t);
- }
-
- Array_array = rnd(0, widthptr);
- Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width);
- Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width);
- sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr);
-
- // string is same as slice wo the cap
- sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);
-
- dowidth(types[TSTRING]);
- dowidth(idealstring);
-}
-
-/*
- * compute total size of f's in/out arguments.
- */
-int
-argsize(Type *t)
-{
- Iter save;
- Type *fp;
- int w, x;
-
- w = 0;
-
- fp = structfirst(&save, getoutarg(t));
- while(fp != T) {
- x = fp->width + fp->type->width;
- if(x > w)
- w = x;
- fp = structnext(&save);
- }
-
- fp = funcfirst(&save, t);
- while(fp != T) {
- x = fp->width + fp->type->width;
- if(x > w)
- w = x;
- fp = funcnext(&save);
- }
-
- w = (w+widthptr-1) & ~(widthptr-1);
- return w;
-}
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
deleted file mode 100755
index 5110f5350..000000000
--- a/src/cmd/gc/bisonerrors
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/awk -f
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# This program implements the core idea from
-#
-# Clinton L. Jeffery, Generating LR syntax error messages from examples,
-# ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566
-#
-# It reads Bison's summary of a grammar followed by a file
-# like go.errors, replacing lines beginning with % by the
-# yystate and yychar that will be active when an error happens
-# while parsing that line.
-#
-# Unlike the system described in the paper, the lines in go.errors
-# give grammar symbol name lists, not actual program fragments.
-# This is a little less programmer-friendly but doesn't require being
-# able to run the text through lex.c.
-
-BEGIN{
- bison = 1
- grammar = 0
- states = 0
-}
-
-# In Grammar section of y.output,
-# record lhs and length of rhs for each rule.
-bison && /^Grammar/ { grammar = 1 }
-bison && /^(Terminals|state 0)/ { grammar = 0 }
-grammar && NF>0 {
- if($2 != "|") {
- r = $2
- sub(/:$/, "", r)
- }
- rulelhs[$1] = r
- rulesize[$1] = NF-2
- if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
- rulesize[$1] = 0
- }
-}
-
-# In state dumps, record shift/reduce actions.
-bison && /^state 0/ { grammar = 0; states = 1 }
-
-states && /^state / { state = $2 }
-states { statetext[state] = statetext[state] $0 "\n" }
-
-states && / shift, and go to state/ {
- n = nshift[state]++
- shift[state,n] = $7
- shifttoken[state,n] = $1
- next
-}
-states && / go to state/ {
- n = nshift[state]++
- shift[state,n] = $5
- shifttoken[state,n] = $1
- next
-}
-states && / reduce using rule/ {
- n = nreduce[state]++
- reduce[state,n] = $5
- reducetoken[state,n] = $1
- next
-}
-
-# First // comment marks the beginning of the pattern file.
-/^\/\// { bison = 0; grammar = 0; state = 0 }
-bison { next }
-
-# Treat % as first field on line as introducing a pattern (token sequence).
-# Run it through the LR machine and print the induced "yystate, yychar,"
-# at the point where the error happens.
-$1 == "%" {
- nstack = 0
- state = 0
- f = 2
- tok = ""
- for(;;) {
- if(tok == "" && f <= NF) {
- tok = $f
- f++
- }
- found = 0
- for(j=0; j<nshift[state]; j++) {
- if(shifttoken[state,j] == tok) {
- # print "SHIFT " tok " " state " -> " shift[state,j]
- stack[nstack++] = state
- state = shift[state,j]
- found = 1
- tok = ""
- break
- }
- }
- if(found)
- continue
- for(j=0; j<nreduce[state]; j++) {
- if(reducetoken[state,j] == tok || reducetoken[state,j] == "$default") {
- stack[nstack++] = state
- rule = reduce[state,j]
- nstack -= rulesize[rule]
- state = stack[--nstack]
- lhs = rulelhs[rule]
- if(tok != "")
- --f
- tok = rulelhs[rule]
- # print "REDUCE " nstack " " state " " tok " rule " rule " size " rulesize[rule]
- found = 1
- break
- }
- }
- if(found)
- continue
-
- # No shift or reduce applied - found the error.
- printf("\t%s, %s,\n", state, tok);
- break
- }
- next
-}
-
-# Print other lines verbatim.
-{print}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
deleted file mode 100644
index 1f2a776fd..000000000
--- a/src/cmd/gc/bits.c
+++ /dev/null
@@ -1,158 +0,0 @@
-// Inferno utils/cc/bits.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "go.h"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = a.b[i] | b.b[i];
- return c;
-}
-
-Bits
-band(Bits a, Bits b)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = a.b[i] & b.b[i];
- return c;
-}
-
-Bits
-bnot(Bits a)
-{
- Bits c;
- int i;
-
- for(i=0; i<BITS; i++)
- c.b[i] = ~a.b[i];
- return c;
-}
-*/
-
-int
-bany(Bits *a)
-{
- int i;
-
- for(i=0; i<BITS; i++)
- if(a->b[i])
- return 1;
- return 0;
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
- int i;
-
- for(i=0; i<BITS; i++)
- if(a.b[i] != b.b[i])
- return 0;
- return 1;
-}
-*/
-
-int
-bnum(Bits a)
-{
- int i;
- int32 b;
-
- for(i=0; i<BITS; i++)
- if(b = a.b[i])
- return 32*i + bitno(b);
- fatal("bad in bnum");
- return 0;
-}
-
-Bits
-blsh(uint n)
-{
- Bits c;
-
- c = zbits;
- c.b[n/32] = 1L << (n%32);
- return c;
-}
-
-/*
-int
-bset(Bits a, uint n)
-{
- if(a.b[n/32] & (1L << (n%32)))
- return 1;
- return 0;
-}
-*/
-
-int
-bitno(int32 b)
-{
- int i;
-
- for(i=0; i<32; i++)
- if(b & (1L<<i))
- return i;
- fatal("bad in bitno");
- return 0;
-}
-
-int
-Qconv(Fmt *fp)
-{
- Bits bits;
- int i, first;
-
- first = 1;
- bits = va_arg(fp->args, Bits);
- while(bany(&bits)) {
- i = bnum(bits);
- if(first)
- first = 0;
- else
- fmtprint(fp, " ");
- if(var[i].sym == S)
- fmtprint(fp, "$%lld", var[i].offset);
- else
- fmtprint(fp, var[i].sym->name);
- bits.b[i/32] &= ~(1L << (i%32));
- }
- return 0;
-}
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
deleted file mode 100644
index 95098c8af..000000000
--- a/src/cmd/gc/builtin.c.boot
+++ /dev/null
@@ -1,115 +0,0 @@
-char *runtimeimport =
- "package runtime\n"
- "import runtime \"runtime\"\n"
- "func \"\".new (? int32) *any\n"
- "func \"\".panicindex ()\n"
- "func \"\".panicslice ()\n"
- "func \"\".throwreturn ()\n"
- "func \"\".throwinit ()\n"
- "func \"\".panicwrap (? string, ? string, ? string)\n"
- "func \"\".panic (? interface { })\n"
- "func \"\".recover (? *int32) interface { }\n"
- "func \"\".printbool (? bool)\n"
- "func \"\".printfloat (? float64)\n"
- "func \"\".printint (? int64)\n"
- "func \"\".printuint (? uint64)\n"
- "func \"\".printcomplex (? complex128)\n"
- "func \"\".printstring (? string)\n"
- "func \"\".printpointer (? any)\n"
- "func \"\".printiface (? any)\n"
- "func \"\".printeface (? any)\n"
- "func \"\".printslice (? any)\n"
- "func \"\".printnl ()\n"
- "func \"\".printsp ()\n"
- "func \"\".goprintf ()\n"
- "func \"\".concatstring ()\n"
- "func \"\".append ()\n"
- "func \"\".appendslice (typ *uint8, x any, y []any) any\n"
- "func \"\".cmpstring (? string, ? string) int\n"
- "func \"\".slicestring (? string, ? int, ? int) string\n"
- "func \"\".slicestring1 (? string, ? int) string\n"
- "func \"\".intstring (? int64) string\n"
- "func \"\".slicebytetostring (? []uint8) string\n"
- "func \"\".sliceinttostring (? []int) string\n"
- "func \"\".stringtoslicebyte (? string) []uint8\n"
- "func \"\".stringtosliceint (? string) []int\n"
- "func \"\".stringiter (? string, ? int) int\n"
- "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\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"
- "func \"\".convI2I (typ *uint8, elem any) any\n"
- "func \"\".convT2E (typ *uint8, elem any) any\n"
- "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
- "func \"\".assertE2E (typ *uint8, iface any) any\n"
- "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertE2I (typ *uint8, iface any) any\n"
- "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertE2T (typ *uint8, iface any) any\n"
- "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2E (typ *uint8, iface any) any\n"
- "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2I (typ *uint8, iface any) any\n"
- "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2T (typ *uint8, iface any) any\n"
- "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".ifaceeq (i1 any, i2 any) bool\n"
- "func \"\".efaceeq (i1 any, i2 any) bool\n"
- "func \"\".ifacethash (i1 any) uint32\n"
- "func \"\".efacethash (i1 any) uint32\n"
- "func \"\".makemap (key *uint8, val *uint8, hint int64) map[any] any\n"
- "func \"\".mapaccess1 (hmap map[any] any, key any) any\n"
- "func \"\".mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
- "func \"\".mapassign1 (hmap map[any] any, key any, val any)\n"
- "func \"\".mapassign2 (hmap map[any] any, key any, val any, pres bool)\n"
- "func \"\".mapiterinit (hmap map[any] any, hiter *any)\n"
- "func \"\".mapiternext (hiter *any)\n"
- "func \"\".mapiter1 (hiter *any) any\n"
- "func \"\".mapiter2 (hiter *any) (key any, val any)\n"
- "func \"\".makechan (elem *uint8, hint int64) chan any\n"
- "func \"\".chanrecv1 (hchan <-chan any) any\n"
- "func \"\".chanrecv2 (hchan <-chan any) (elem any, received bool)\n"
- "func \"\".chansend1 (hchan chan<- any, elem any)\n"
- "func \"\".closechan (hchan any)\n"
- "func \"\".closedchan (hchan any) bool\n"
- "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n"
- "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
- "func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n"
- "func \"\".newselect (size int) *uint8\n"
- "func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n"
- "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
- "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
- "func \"\".selectdefault (sel *uint8) bool\n"
- "func \"\".selectgo (sel *uint8)\n"
- "func \"\".block ()\n"
- "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
- "func \"\".growslice (typ *uint8, old []any, n int64) []any\n"
- "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
- "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
- "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
- "func \"\".closure ()\n"
- "func \"\".int64div (? int64, ? int64) int64\n"
- "func \"\".uint64div (? uint64, ? uint64) uint64\n"
- "func \"\".int64mod (? int64, ? int64) int64\n"
- "func \"\".uint64mod (? uint64, ? uint64) uint64\n"
- "func \"\".float64toint64 (? float64) int64\n"
- "func \"\".float64touint64 (? float64) uint64\n"
- "func \"\".int64tofloat64 (? int64) float64\n"
- "func \"\".uint64tofloat64 (? uint64) float64\n"
- "func \"\".complex128div (num complex128, den complex128) complex128\n"
- "\n"
- "$$\n";
-char *unsafeimport =
- "package unsafe\n"
- "import runtime \"runtime\"\n"
- "type \"\".Pointer uintptr\n"
- "func \"\".Offsetof (? any) uintptr\n"
- "func \"\".Sizeof (? any) uintptr\n"
- "func \"\".Alignof (? any) uintptr\n"
- "func \"\".Typeof (i interface { }) interface { }\n"
- "func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n"
- "func \"\".Unreflect (typ interface { }, addr \"\".Pointer) interface { }\n"
- "func \"\".New (typ interface { }) \"\".Pointer\n"
- "func \"\".NewArray (typ interface { }, n int) \"\".Pointer\n"
- "\n"
- "$$\n";
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
deleted file mode 100644
index 7e7b40526..000000000
--- a/src/cmd/gc/closure.c
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * function literals aka closures
- */
-
-#include "go.h"
-
-void
-closurehdr(Node *ntype)
-{
- Node *n, *name, *a;
- NodeList *l;
-
- n = nod(OCLOSURE, N, N);
- n->ntype = ntype;
- n->funcdepth = funcdepth;
-
- funchdr(n);
-
- // steal ntype's argument names and
- // leave a fresh copy in their place.
- // references to these variables need to
- // refer to the variables in the external
- // function declared below; see walkclosure.
- n->list = ntype->list;
- n->rlist = ntype->rlist;
- ntype->list = nil;
- ntype->rlist = nil;
- for(l=n->list; l; l=l->next) {
- name = l->n->left;
- if(name)
- name = newname(name->sym);
- a = nod(ODCLFIELD, name, l->n->right);
- a->isddd = l->n->isddd;
- if(name)
- name->isddd = a->isddd;
- ntype->list = list(ntype->list, a);
- }
- for(l=n->rlist; l; l=l->next) {
- name = l->n->left;
- if(name)
- name = newname(name->sym);
- ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
- }
-}
-
-Node*
-closurebody(NodeList *body)
-{
- Node *func, *v;
- NodeList *l;
-
- if(body == nil)
- body = list1(nod(OEMPTY, N, N));
-
- func = curfn;
- l = func->dcl;
- func->nbody = body;
- funcbody(func);
-
- // closure-specific variables are hanging off the
- // ordinary ones in the symbol table; see oldname.
- // unhook them.
- // make the list of pointers for the closure call.
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- v->closure->closure = v->outer;
- v->heapaddr = nod(OADDR, oldname(v->sym), N);
- }
-
- return func;
-}
-
-void
-typecheckclosure(Node *func, int top)
-{
- Node *oldfn;
- NodeList *l;
- Node *v;
-
- oldfn = curfn;
- typecheck(&func->ntype, Etype);
- func->type = func->ntype->type;
- if(func->type != T) {
- curfn = func;
- typechecklist(func->nbody, Etop);
- curfn = oldfn;
- }
-
- // type check the & of closed variables outside the closure,
- // so that the outer frame also grabs them and knows they
- // escape.
- func->enter = nil;
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->type == T) {
- // if v->type is nil, it means v looked like it was
- // going to be used in the closure but wasn't.
- // this happens because when parsing a, b, c := f()
- // the a, b, c gets parsed as references to older
- // a, b, c before the parser figures out this is a
- // declaration.
- v->op = 0;
- continue;
- }
- // For a closure that is called in place, but not
- // inside a go statement, avoid moving variables to the heap.
- if ((top & (Ecall|Eproc)) == Ecall)
- v->heapaddr->etype = 1;
- typecheck(&v->heapaddr, Erv);
- func->enter = list(func->enter, v->heapaddr);
- v->heapaddr = N;
- }
-}
-
-static Node*
-makeclosure(Node *func, NodeList **init, int nowrap)
-{
- Node *xtype, *v, *addr, *xfunc;
- NodeList *l;
- static int closgen;
- char *p;
-
- /*
- * wrap body in external function
- * with extra closure parameters.
- */
- xtype = nod(OTFUNC, N, N);
-
- // each closure variable has a corresponding
- // address parameter.
- for(l=func->cvars; l; l=l->next) {
- v = l->n;
- if(v->op == 0)
- continue;
- addr = nod(ONAME, N, N);
- p = smprint("&%s", v->sym->name);
- addr->sym = lookup(p);
- free(p);
- addr->ntype = nod(OIND, typenod(v->type), N);
- addr->class = PPARAM;
- addr->addable = 1;
- addr->ullman = 1;
-
- v->heapaddr = addr;
-
- xtype->list = list(xtype->list, nod(ODCLFIELD, addr, addr->ntype));
- }
-
- // then a dummy arg where the closure's caller pc sits
- if (!nowrap)
- xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-
- // then the function arguments
- xtype->list = concat(xtype->list, func->list);
- xtype->rlist = concat(xtype->rlist, func->rlist);
-
- // create the function
- xfunc = nod(ODCLFUNC, N, N);
- snprint(namebuf, sizeof namebuf, "_func_%.3d", ++closgen);
- xfunc->nname = newname(lookup(namebuf));
- xfunc->nname->ntype = xtype;
- xfunc->nname->defn = xfunc;
- declare(xfunc->nname, PFUNC);
- xfunc->nname->funcdepth = func->funcdepth;
- xfunc->funcdepth = func->funcdepth;
- xfunc->nbody = func->nbody;
- xfunc->dcl = func->dcl;
- if(xfunc->nbody == nil)
- fatal("empty body - won't generate any code");
- typecheck(&xfunc, Etop);
- closures = list(closures, xfunc);
-
- return xfunc;
-}
-
-Node*
-walkclosure(Node *func, NodeList **init)
-{
- int narg;
- Node *xtype, *xfunc, *call, *clos;
- NodeList *l, *in;
-
- /*
- * wrap body in external function
- * with extra closure parameters.
- */
-
- // create the function
- xfunc = makeclosure(func, init, 0);
- xtype = xfunc->nname->ntype;
-
- // prepare call of sys.closure that turns external func into func literal value.
- clos = syslook("closure", 1);
- clos->type = T;
- clos->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
- in = list(in, nod(ODCLFIELD, N, xtype));
- narg = 0;
- for(l=func->cvars; l; l=l->next) {
- if(l->n->op == 0)
- continue;
- narg++;
- in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
- }
- clos->ntype->list = in;
- clos->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(func->type)));
- typecheck(&clos, Erv);
-
- call = nod(OCALL, clos, N);
- if(narg*widthptr > 100)
- yyerror("closure needs too many variables; runtime will reject it");
- in = list1(nodintconst(narg*widthptr));
- in = list(in, xfunc->nname);
- in = concat(in, func->enter);
- call->list = in;
-
- typecheck(&call, Erv);
- walkexpr(&call, init);
- return call;
-}
-
-// Special case for closures that get called in place.
-// Optimize runtime.closure(X, __func__xxxx_, .... ) away
-// to __func__xxxx_(Y ....).
-// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
-void
-walkcallclosure(Node *n, NodeList **init)
-{
- if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
- dump("walkcallclosure", n);
- fatal("abuse of walkcallclosure");
- }
-
- // New arg list for n. First the closure-args
- // and then the original parameter list.
- n->list = concat(n->left->enter, n->list);
- n->left = makeclosure(n->left, init, 1)->nname;
- dowidth(n->left->type);
- n->type = getoutargx(n->left->type);
- // for a single valued function, pull the field type out of the struct
- if (n->type && n->type->type && !n->type->type->down)
- n->type = n->type->type->type;
-}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
deleted file mode 100644
index 8fe9072b2..000000000
--- a/src/cmd/gc/const.c
+++ /dev/null
@@ -1,1283 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-#define TUP(x,y) (((x)<<16)|(y))
-
-static Val tocplx(Val);
-static Val toflt(Val);
-static Val tostr(Val);
-static Val copyval(Val);
-static void cmplxmpy(Mpcplx*, Mpcplx*);
-static void cmplxdiv(Mpcplx*, Mpcplx*);
-
-/*
- * truncate float literal fv to 32-bit or 64-bit precision
- * according to type; return truncated value.
- */
-Mpflt*
-truncfltlit(Mpflt *oldv, Type *t)
-{
- double d;
- float f;
- Mpflt *fv;
-
- if(t == T)
- return oldv;
-
- fv = mal(sizeof *fv);
- *fv = *oldv;
-
- // convert large precision literal floating
- // into limited precision (float64 or float32)
- // botch -- this assumes that compiler fp
- // has same precision as runtime fp
- switch(t->etype) {
- case TFLOAT64:
- d = mpgetflt(fv);
- mpmovecflt(fv, d);
- break;
-
- case TFLOAT32:
- d = mpgetflt(fv);
- f = d;
- d = f;
- mpmovecflt(fv, d);
- break;
- }
- return fv;
-}
-
-/*
- * convert n, if literal, to type t.
- * implicit conversion.
- */
-void
-convlit(Node **np, Type *t)
-{
- convlit1(np, t, 0);
-}
-
-/*
- * convert n, if literal, to type t.
- * return a new node if necessary
- * (if n is a named constant, can't edit n->type directly).
- */
-void
-convlit1(Node **np, Type *t, int explicit)
-{
- int ct, et;
- Node *n, *nn;
-
- n = *np;
- if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
- return;
- if(!explicit && !isideal(n->type))
- return;
-
- if(n->op == OLITERAL) {
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- }
-
- switch(n->op) {
- default:
- if(n->type->etype == TIDEAL) {
- convlit(&n->left, t);
- convlit(&n->right, t);
- n->type = t;
- }
- return;
- case OLITERAL:
- // target is invalid type for a constant? leave alone.
- if(!okforconst[t->etype] && n->type->etype != TNIL) {
- defaultlit(&n, T);
- *np = n;
- return;
- }
- break;
- case OLSH:
- case ORSH:
- convlit1(&n->left, t, explicit && isideal(n->left->type));
- t = n->left->type;
- if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
- n->val = toint(n->val);
- if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
- t = T;
- }
- n->type = t;
- return;
- }
-
- // avoided repeated calculations, errors
- if(eqtype(n->type, t))
- return;
-
- ct = consttype(n);
- if(ct < 0)
- goto bad;
-
- et = t->etype;
- if(et == TINTER) {
- if(ct == CTNIL && n->type == types[TNIL]) {
- n->type = t;
- return;
- }
- defaultlit(np, T);
- return;
- }
-
- switch(ct) {
- default:
- goto bad;
-
- case CTNIL:
- switch(et) {
- default:
- n->type = T;
- goto bad;
-
- case TSTRING:
- // let normal conversion code handle it
- return;
-
- case TARRAY:
- if(!isslice(t))
- goto bad;
- break;
-
- case TPTR32:
- case TPTR64:
- case TINTER:
- case TMAP:
- case TCHAN:
- case TFUNC:
- case TUNSAFEPTR:
- break;
- }
- break;
-
- case CTSTR:
- case CTBOOL:
- if(et != n->type->etype)
- goto bad;
- break;
-
- case CTINT:
- case CTFLT:
- case CTCPLX:
- ct = n->val.ctype;
- if(isint[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTFLT:
- n->val = toint(n->val);
- // flowthrough
- case CTINT:
- overflow(n->val, t);
- break;
- }
- } else
- if(isfloat[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTCPLX:
- case CTINT:
- n->val = toflt(n->val);
- // flowthrough
- case CTFLT:
- overflow(n->val, t);
- n->val.u.fval = truncfltlit(n->val.u.fval, t);
- break;
- }
- } else
- if(iscomplex[et]) {
- switch(ct) {
- default:
- goto bad;
- case CTFLT:
- case CTINT:
- n->val = tocplx(n->val);
- break;
- case CTCPLX:
- overflow(n->val, t);
- break;
- }
- } else
- if(et == TSTRING && ct == CTINT && explicit)
- n->val = tostr(n->val);
- else
- goto bad;
- break;
- }
- n->type = t;
- return;
-
-bad:
- if(!n->diag) {
- yyerror("cannot convert %#N to type %T", n, t);
- n->diag = 1;
- }
- if(isideal(n->type)) {
- defaultlit(&n, T);
- *np = n;
- }
- return;
-}
-
-static Val
-copyval(Val v)
-{
- Mpint *i;
- Mpflt *f;
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- i = mal(sizeof(*i));
- mpmovefixfix(i, v.u.xval);
- v.u.xval = i;
- break;
- case CTFLT:
- f = mal(sizeof(*f));
- mpmovefltflt(f, v.u.fval);
- v.u.fval = f;
- break;
- case CTCPLX:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, &v.u.cval->real);
- mpmovefltflt(&c->imag, &v.u.cval->imag);
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-tocplx(Val v)
-{
- Mpcplx *c;
-
- switch(v.ctype) {
- case CTINT:
- c = mal(sizeof(*c));
- mpmovefixflt(&c->real, v.u.xval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- case CTFLT:
- c = mal(sizeof(*c));
- mpmovefltflt(&c->real, v.u.fval);
- mpmovecflt(&c->imag, 0.0);
- v.ctype = CTCPLX;
- v.u.cval = c;
- break;
- }
- return v;
-}
-
-static Val
-toflt(Val v)
-{
- Mpflt *f;
-
- switch(v.ctype) {
- case CTINT:
- f = mal(sizeof(*f));
- mpmovefixflt(f, v.u.xval);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- case CTCPLX:
- f = mal(sizeof(*f));
- mpmovefltflt(f, &v.u.cval->real);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTFLT;
- v.u.fval = f;
- break;
- }
- return v;
-}
-
-Val
-toint(Val v)
-{
- Mpint *i;
-
- switch(v.ctype) {
- case CTFLT:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, v.u.fval) < 0)
- yyerror("constant %#F truncated to integer", v.u.fval);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- case CTCPLX:
- i = mal(sizeof(*i));
- if(mpmovefltfix(i, &v.u.cval->real) < 0)
- yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
- if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
- v.ctype = CTINT;
- v.u.xval = i;
- break;
- }
- return v;
-}
-
-void
-overflow(Val v, Type *t)
-{
- // v has already been converted
- // to appropriate form for t.
- if(t == T || t->etype == TIDEAL)
- return;
- switch(v.ctype) {
- case CTINT:
- if(!isint[t->etype])
- fatal("overflow: %T integer constant", t);
- if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
- yyerror("constant %B overflows %T", v.u.xval, t);
- break;
- case CTFLT:
- if(!isfloat[t->etype])
- fatal("overflow: %T floating-point constant", t);
- if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- case CTCPLX:
- if(!iscomplex[t->etype])
- fatal("overflow: %T complex constant", t);
- if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 ||
- mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 ||
- mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0)
- yyerror("constant %#F overflows %T", v.u.fval, t);
- break;
- }
-}
-
-static Val
-tostr(Val v)
-{
- Rune rune;
- int l;
- Strlit *s;
-
- switch(v.ctype) {
- case CTINT:
- if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
- mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
- yyerror("overflow in int -> string");
- rune = mpgetfix(v.u.xval);
- l = runelen(rune);
- s = mal(sizeof(*s)+l);
- s->len = l;
- runetochar((char*)s->s, &rune);
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = s;
- break;
-
- case CTFLT:
- yyerror("no float -> string");
-
- case CTNIL:
- memset(&v, 0, sizeof v);
- v.ctype = CTSTR;
- v.u.sval = mal(sizeof *s);
- break;
- }
- return v;
-}
-
-int
-consttype(Node *n)
-{
- if(n == N || n->op != OLITERAL)
- return -1;
- return n->val.ctype;
-}
-
-int
-isconst(Node *n, int ct)
-{
- return consttype(n) == ct;
-}
-
-/*
- * if n is constant, rewrite as OLITERAL node.
- */
-void
-evconst(Node *n)
-{
- Node *nl, *nr;
- int32 len;
- Strlit *str;
- int wl, wr, lno, et;
- Val v, rv;
- Mpint b;
-
- // pick off just the opcodes that can be
- // constant evaluated.
- switch(n->op) {
- default:
- return;
- case OADD:
- case OADDSTR:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case OARRAYBYTESTR:
- case OCOM:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMINUS:
- case OMOD:
- case OMUL:
- case ONE:
- case ONOT:
- case OOR:
- case OOROR:
- case OPLUS:
- case ORSH:
- case OSUB:
- case OXOR:
- break;
- case OCONV:
- if(n->type == T)
- return;
- if(!okforconst[n->type->etype] && n->type->etype != TNIL)
- return;
- break;
- }
-
- nl = n->left;
- if(nl == N || nl->type == T)
- return;
- if(consttype(nl) < 0)
- return;
- wl = nl->type->etype;
- if(isint[wl] || isfloat[wl] || iscomplex[wl])
- wl = TIDEAL;
-
- nr = n->right;
- if(nr == N)
- goto unary;
- if(nr->type == T)
- return;
- if(consttype(nr) < 0)
- return;
- wr = nr->type->etype;
- if(isint[wr] || isfloat[wr] || iscomplex[wr])
- wr = TIDEAL;
-
- // check for compatible general types (numeric, string, etc)
- if(wl != wr)
- goto illegal;
-
- // check for compatible types.
- switch(n->op) {
- default:
- // ideal const mixes with anything but otherwise must match.
- if(nl->type->etype != TIDEAL) {
- defaultlit(&nr, nl->type);
- n->right = nr;
- }
- if(nr->type->etype != TIDEAL) {
- defaultlit(&nl, nr->type);
- n->left = nl;
- }
- if(nl->type->etype != nr->type->etype)
- goto illegal;
- break;
-
- case OLSH:
- case ORSH:
- // right must be unsigned.
- // left can be ideal.
- defaultlit(&nr, types[TUINT]);
- n->right = nr;
- if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
- goto illegal;
- nl->val = toint(nl->val);
- nr->val = toint(nr->val);
- break;
- }
-
- // copy numeric value to avoid modifying
- // n->left, in case someone still refers to it (e.g. iota).
- v = nl->val;
- if(wl == TIDEAL)
- v = copyval(v);
-
- rv = nr->val;
-
- // convert to common ideal
- if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
- v = tocplx(v);
- rv = tocplx(rv);
- }
- if(v.ctype == CTFLT || rv.ctype == CTFLT) {
- v = toflt(v);
- rv = toflt(rv);
- }
- if(v.ctype != rv.ctype) {
- // Use of undefined name as constant?
- if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
- return;
- fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
- }
-
- // run op
- switch(TUP(n->op, v.ctype)) {
- default:
- illegal:
- if(!n->diag) {
- yyerror("illegal constant expression: %T %O %T",
- nl->type, n->op, nr->type);
- n->diag = 1;
- }
- return;
-
- case TUP(OADD, CTINT):
- mpaddfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OSUB, CTINT):
- mpsubfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMUL, CTINT):
- mpmulfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ODIV, CTINT):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpdivfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OMOD, CTINT):
- if(mpcmpfixc(rv.u.xval, 0) == 0) {
- yyerror("division by zero");
- mpmovecfix(v.u.xval, 1);
- break;
- }
- mpmodfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OLSH, CTINT):
- mplshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(ORSH, CTINT):
- mprshfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OOR, CTINT):
- mporfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OAND, CTINT):
- mpandfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OANDNOT, CTINT):
- mpandnotfixfix(v.u.xval, rv.u.xval);
- break;
- case TUP(OXOR, CTINT):
- mpxorfixfix(v.u.xval, rv.u.xval);
- break;
-
- case TUP(OADD, CTFLT):
- mpaddfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OSUB, CTFLT):
- mpsubfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(OMUL, CTFLT):
- mpmulfltflt(v.u.fval, rv.u.fval);
- break;
- case TUP(ODIV, CTFLT):
- if(mpcmpfltc(rv.u.fval, 0) == 0) {
- yyerror("division by zero");
- mpmovecflt(v.u.fval, 1.0);
- break;
- }
- mpdivfltflt(v.u.fval, rv.u.fval);
- break;
-
- case TUP(OADD, CTCPLX):
- mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OSUB, CTCPLX):
- mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
- mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
- break;
- case TUP(OMUL, CTCPLX):
- cmplxmpy(v.u.cval, rv.u.cval);
- break;
- case TUP(ODIV, CTCPLX):
- if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
- mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
- yyerror("complex division by zero");
- mpmovecflt(&rv.u.cval->real, 1.0);
- mpmovecflt(&rv.u.cval->imag, 0.0);
- break;
- }
- cmplxdiv(v.u.cval, rv.u.cval);
- break;
-
- case TUP(OEQ, CTNIL):
- goto settrue;
- case TUP(ONE, CTNIL):
- goto setfalse;
-
- case TUP(OEQ, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTINT):
- if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTFLT):
- if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTCPLX):
- if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
- mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0)
- goto settrue;
- goto setfalse;
-
- case TUP(OEQ, CTSTR):
- if(cmpslit(nl, nr) == 0)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTSTR):
- if(cmpslit(nl, nr) != 0)
- goto settrue;
- goto setfalse;
- case TUP(OLT, CTSTR):
- if(cmpslit(nl, nr) < 0)
- goto settrue;
- goto setfalse;
- case TUP(OLE, CTSTR):
- if(cmpslit(nl, nr) <= 0)
- goto settrue;
- goto setfalse;
- case TUP(OGE, CTSTR):
- if(cmpslit(nl, nr) >= 0l)
- goto settrue;
- goto setfalse;
- case TUP(OGT, CTSTR):
- if(cmpslit(nl, nr) > 0)
- goto settrue;
- goto setfalse;
- case TUP(OADDSTR, CTSTR):
- len = v.u.sval->len + rv.u.sval->len;
- str = mal(sizeof(*str) + len);
- str->len = len;
- memcpy(str->s, v.u.sval->s, v.u.sval->len);
- memcpy(str->s+v.u.sval->len, rv.u.sval->s, rv.u.sval->len);
- str->len = len;
- v.u.sval = str;
- break;
-
- case TUP(OOROR, CTBOOL):
- if(v.u.bval || rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OANDAND, CTBOOL):
- if(v.u.bval && rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(OEQ, CTBOOL):
- if(v.u.bval == rv.u.bval)
- goto settrue;
- goto setfalse;
- case TUP(ONE, CTBOOL):
- if(v.u.bval != rv.u.bval)
- goto settrue;
- goto setfalse;
- }
- goto ret;
-
-unary:
- // copy numeric value to avoid modifying
- // nl, in case someone still refers to it (e.g. iota).
- v = nl->val;
- if(wl == TIDEAL)
- v = copyval(v);
-
- switch(TUP(n->op, v.ctype)) {
- default:
- if(!n->diag) {
- yyerror("illegal constant expression %O %T", n->op, nl->type);
- n->diag = 1;
- }
- return;
-
- case TUP(OCONV, CTNIL):
- case TUP(OARRAYBYTESTR, CTNIL):
- if(n->type->etype == TSTRING) {
- v = tostr(v);
- nl->type = n->type;
- break;
- }
- // fall through
- case TUP(OCONV, CTINT):
- case TUP(OCONV, CTFLT):
- case TUP(OCONV, CTSTR):
- convlit1(&nl, n->type, 1);
- break;
-
- case TUP(OPLUS, CTINT):
- break;
- case TUP(OMINUS, CTINT):
- mpnegfix(v.u.xval);
- break;
- case TUP(OCOM, CTINT):
- et = Txxx;
- if(nl->type != T)
- et = nl->type->etype;
-
- // calculate the mask in b
- // result will be (a ^ mask)
- switch(et) {
- default:
- // signed guys change sign
- mpmovecfix(&b, -1);
- break;
-
- case TUINT8:
- case TUINT16:
- case TUINT32:
- case TUINT64:
- case TUINT:
- case TUINTPTR:
- // unsigned guys invert their bits
- mpmovefixfix(&b, maxintval[et]);
- break;
- }
- mpxorfixfix(v.u.xval, &b);
- break;
-
- case TUP(OPLUS, CTFLT):
- break;
- case TUP(OMINUS, CTFLT):
- mpnegflt(v.u.fval);
- break;
-
- case TUP(OPLUS, CTCPLX):
- break;
- case TUP(OMINUS, CTCPLX):
- mpnegflt(&v.u.cval->real);
- mpnegflt(&v.u.cval->imag);
- break;
-
- case TUP(ONOT, CTBOOL):
- if(!v.u.bval)
- goto settrue;
- goto setfalse;
- }
-
-ret:
- // rewrite n in place.
- *n = *nl;
- n->val = v;
-
- // check range.
- lno = setlineno(n);
- overflow(v, n->type);
- lineno = lno;
-
- // truncate precision for non-ideal float.
- if(v.ctype == CTFLT && n->type->etype != TIDEAL)
- n->val.u.fval = truncfltlit(v.u.fval, n->type);
- return;
-
-settrue:
- *n = *nodbool(1);
- return;
-
-setfalse:
- *n = *nodbool(0);
- return;
-}
-
-Node*
-nodlit(Val v)
-{
- Node *n;
-
- n = nod(OLITERAL, N, N);
- n->val = v;
- switch(v.ctype) {
- default:
- fatal("nodlit ctype %d", v.ctype);
- case CTSTR:
- n->type = idealstring;
- break;
- case CTBOOL:
- n->type = idealbool;
- break;
- case CTINT:
- case CTFLT:
- case CTCPLX:
- n->type = types[TIDEAL];
- break;
- case CTNIL:
- n->type = types[TNIL];
- break;
- }
- return n;
-}
-
-Node*
-nodcplxlit(Val r, Val i)
-{
- Node *n;
- Mpcplx *c;
-
- r = toflt(r);
- i = toflt(i);
-
- c = mal(sizeof(*c));
- n = nod(OLITERAL, N, N);
- n->type = types[TIDEAL];
- n->val.u.cval = c;
- n->val.ctype = CTCPLX;
-
- if(r.ctype != CTFLT || i.ctype != CTFLT)
- fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
-
- mpmovefltflt(&c->real, r.u.fval);
- mpmovefltflt(&c->imag, i.u.fval);
- return n;
-}
-
-// TODO(rsc): combine with convlit
-void
-defaultlit(Node **np, Type *t)
-{
- int lno;
- Node *n, *nn;
-
- n = *np;
- if(n == N || !isideal(n->type))
- return;
-
- switch(n->op) {
- case OLITERAL:
- nn = nod(OXXX, N, N);
- *nn = *n;
- n = nn;
- *np = n;
- break;
- case OLSH:
- case ORSH:
- defaultlit(&n->left, t);
- t = n->left->type;
- if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
- t = T;
- }
- n->type = t;
- return;
- default:
- if(n->left == N) {
- dump("defaultlit", n);
- fatal("defaultlit");
- }
- defaultlit(&n->left, t);
- defaultlit(&n->right, t);
- if(n->type == idealbool || n->type == idealstring)
- n->type = types[n->type->etype];
- else
- n->type = n->left->type;
- return;
- }
-
- lno = setlineno(n);
- switch(n->val.ctype) {
- default:
- if(t != T) {
- convlit(np, t);
- break;
- }
- if(n->val.ctype == CTNIL) {
- lineno = lno;
- yyerror("use of untyped nil");
- n->type = T;
- break;
- }
- if(n->val.ctype == CTSTR) {
- n->type = types[TSTRING];
- break;
- }
- yyerror("defaultlit: unknown literal: %#N", n);
- break;
- case CTBOOL:
- n->type = types[TBOOL];
- if(t != T && t->etype == TBOOL)
- n->type = t;
- break;
- case CTINT:
- n->type = types[TINT];
- goto num;
- case CTFLT:
- n->type = types[TFLOAT64];
- goto num;
- case CTCPLX:
- n->type = types[TCOMPLEX128];
- goto num;
- num:
- if(t != T) {
- if(isint[t->etype]) {
- n->type = t;
- n->val = toint(n->val);
- }
- else
- if(isfloat[t->etype]) {
- n->type = t;
- n->val = toflt(n->val);
- }
- else
- if(iscomplex[t->etype]) {
- n->type = t;
- n->val = tocplx(n->val);
- }
- }
- overflow(n->val, n->type);
- break;
- }
- lineno = lno;
-}
-
-/*
- * defaultlit on both nodes simultaneously;
- * if they're both ideal going in they better
- * get the same type going out.
- * force means must assign concrete (non-ideal) type.
- */
-void
-defaultlit2(Node **lp, Node **rp, int force)
-{
- Node *l, *r;
-
- l = *lp;
- r = *rp;
- if(l->type == T || r->type == T)
- return;
- if(!isideal(l->type)) {
- convlit(rp, l->type);
- return;
- }
- if(!isideal(r->type)) {
- convlit(lp, r->type);
- return;
- }
- if(!force)
- return;
- if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
- convlit(lp, types[TCOMPLEX128]);
- convlit(rp, types[TCOMPLEX128]);
- return;
- }
- if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
- convlit(lp, types[TFLOAT64]);
- convlit(rp, types[TFLOAT64]);
- return;
- }
- convlit(lp, types[TINT]);
- convlit(rp, types[TINT]);
-}
-
-int
-cmpslit(Node *l, Node *r)
-{
- int32 l1, l2, i, m;
- uchar *s1, *s2;
-
- l1 = l->val.u.sval->len;
- l2 = r->val.u.sval->len;
- s1 = (uchar*)l->val.u.sval->s;
- s2 = (uchar*)r->val.u.sval->s;
-
- m = l1;
- if(l2 < m)
- m = l2;
-
- for(i=0; i<m; i++) {
- if(s1[i] == s2[i])
- continue;
- if(s1[i] > s2[i])
- return +1;
- return -1;
- }
- if(l1 == l2)
- return 0;
- if(l1 > l2)
- return +1;
- return -1;
-}
-
-int
-smallintconst(Node *n)
-{
- if(n->op == OLITERAL && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TBOOL:
- case TPTR32:
- return 1;
- case TINT64:
- case TUINT64:
- if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return 1;
- }
- return 0;
-}
-
-long
-nonnegconst(Node *n)
-{
- if(n->op == OLITERAL && n->type != T)
- switch(simtype[n->type->etype]) {
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TIDEAL:
- // check negative and 2^31
- if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
- || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
- break;
- return mpgetfix(n->val.u.xval);
- }
- return -1;
-}
-
-/*
- * convert x to type et and back to int64
- * for sign extension and truncation.
- */
-static int64
-iconv(int64 x, int et)
-{
- switch(et) {
- case TINT8:
- x = (int8)x;
- break;
- case TUINT8:
- x = (uint8)x;
- break;
- case TINT16:
- x = (int16)x;
- break;
- case TUINT16:
- x = (uint64)x;
- break;
- case TINT32:
- x = (int32)x;
- break;
- case TUINT32:
- x = (uint32)x;
- break;
- case TINT64:
- case TUINT64:
- break;
- }
- return x;
-}
-
-/*
- * convert constant val to type t; leave in con.
- * for back end.
- */
-void
-convconst(Node *con, Type *t, Val *val)
-{
- int64 i;
- int tt;
-
- tt = simsimtype(t);
-
- // copy the constant for conversion
- nodconst(con, types[TINT8], 0);
- con->type = t;
- con->val = *val;
-
- if(isint[tt]) {
- con->val.ctype = CTINT;
- con->val.u.xval = mal(sizeof *con->val.u.xval);
- switch(val->ctype) {
- default:
- fatal("convconst ctype=%d %lT", val->ctype, t);
- case CTINT:
- i = mpgetfix(val->u.xval);
- break;
- case CTBOOL:
- i = val->u.bval;
- break;
- case CTNIL:
- i = 0;
- break;
- }
- i = iconv(i, tt);
- mpmovecfix(con->val.u.xval, i);
- return;
- }
-
- if(isfloat[tt]) {
- con->val = toflt(con->val);
- if(con->val.ctype != CTFLT)
- fatal("convconst ctype=%d %T", con->val.ctype, t);
- if(tt == TFLOAT32)
- con->val.u.fval = truncfltlit(con->val.u.fval, t);
- return;
- }
-
- if(iscomplex[tt]) {
- con->val = tocplx(con->val);
- if(tt == TCOMPLEX64) {
- con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
- con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
- }
- return;
- }
-
- fatal("convconst %lT constant", t);
-
-}
-
-// complex multiply v *= rv
-// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
-static void
-cmplxmpy(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad;
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpsubfltflt(&v->real, &bd); // ac-bd
-
- mpmovefltflt(&v->imag, &bc);
- mpaddfltflt(&v->imag, &ad); // bc+ad
-}
-
-// complex divide v /= rv
-// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
-static void
-cmplxdiv(Mpcplx *v, Mpcplx *rv)
-{
- Mpflt ac, bd, bc, ad, cc_plus_dd;
-
- mpmovefltflt(&cc_plus_dd, &rv->real);
- mpmulfltflt(&cc_plus_dd, &rv->real); // cc
-
- mpmovefltflt(&ac, &rv->imag);
- mpmulfltflt(&ac, &rv->imag); // dd
-
- mpaddfltflt(&cc_plus_dd, &ac); // cc+dd
-
- mpmovefltflt(&ac, &v->real);
- mpmulfltflt(&ac, &rv->real); // ac
-
- mpmovefltflt(&bd, &v->imag);
- mpmulfltflt(&bd, &rv->imag); // bd
-
- mpmovefltflt(&bc, &v->imag);
- mpmulfltflt(&bc, &rv->real); // bc
-
- mpmovefltflt(&ad, &v->real);
- mpmulfltflt(&ad, &rv->imag); // ad
-
- mpmovefltflt(&v->real, &ac);
- mpaddfltflt(&v->real, &bd); // ac+bd
- mpdivfltflt(&v->real, &cc_plus_dd); // (ac+bd)/(cc+dd)
-
- mpmovefltflt(&v->imag, &bc);
- mpsubfltflt(&v->imag, &ad); // bc-ad
- mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd)
-}
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
deleted file mode 100644
index 890cf7f10..000000000
--- a/src/cmd/gc/cplx.c
+++ /dev/null
@@ -1,479 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "gg.h"
-
-static void subnode(Node *nr, Node *ni, Node *nc);
-static void minus(Node *nl, Node *res);
- void complexminus(Node*, Node*);
- void complexadd(int op, Node*, Node*, Node*);
- void complexmul(Node*, Node*, Node*);
-
-#define CASE(a,b) (((a)<<16)|((b)<<0))
-
-static int
-overlap(Node *f, Node *t)
-{
- // check whether f and t could be overlapping stack references.
- // not exact, because it's hard to check for the stack register
- // in portable code. close enough: worst case we will allocate
- // an extra temporary and the registerizer will clean it up.
- return f->op == OINDREG &&
- t->op == OINDREG &&
- f->xoffset+f->type->width >= t->xoffset &&
- t->xoffset+t->type->width >= f->xoffset;
-}
-
-/*
- * generate:
- * res = n;
- * simplifies and calls gmove.
- */
-void
-complexmove(Node *f, Node *t)
-{
- int ft, tt;
- Node n1, n2, n3, n4;
-
- if(debug['g']) {
- dump("\ncomplexmove-f", f);
- dump("complexmove-t", t);
- }
-
- if(!t->addable)
- fatal("complexmove: to not addable");
-
- ft = simsimtype(f->type);
- tt = simsimtype(t->type);
- switch(CASE(ft,tt)) {
-
- default:
- fatal("complexmove: unknown conversion: %T -> %T\n",
- f->type, t->type);
-
- case CASE(TCOMPLEX64,TCOMPLEX64):
- case CASE(TCOMPLEX64,TCOMPLEX128):
- case CASE(TCOMPLEX128,TCOMPLEX64):
- case CASE(TCOMPLEX128,TCOMPLEX128):
- // complex to complex move/convert.
- // make f addable.
- // also use temporary if possible stack overlap.
- if(!f->addable || overlap(f, t)) {
- tempname(&n1, f->type);
- complexmove(f, &n1);
- f = &n1;
- }
-
- subnode(&n1, &n2, f);
- subnode(&n3, &n4, t);
-
- cgen(&n1, &n3);
- cgen(&n2, &n4);
- break;
- }
-}
-
-int
-complexop(Node *n, Node *res)
-{
- if(n != N && n->type != T)
- if(iscomplex[n->type->etype]) {
- goto maybe;
- }
- if(res != N && res->type != T)
- if(iscomplex[res->type->etype]) {
- goto maybe;
- }
-
- if(n->op == OREAL || n->op == OIMAG)
- goto yes;
-
- goto no;
-
-maybe:
- switch(n->op) {
- case OCONV: // implemented ops
- case OADD:
- case OSUB:
- case OMUL:
- case OMINUS:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- goto yes;
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME:
- goto yes;
- }
-
-no:
-//dump("\ncomplex-no", n);
- return 0;
-yes:
-//dump("\ncomplex-yes", n);
- return 1;
-}
-
-void
-complexgen(Node *n, Node *res)
-{
- Node *nl, *nr;
- Node tnl, tnr;
- Node n1, n2, tmp;
- int tl, tr;
-
- if(debug['g']) {
- dump("\ncomplexgen-n", n);
- dump("complexgen-res", res);
- }
-
- // pick off float/complex opcodes
- switch(n->op) {
- case OCOMPLEX:
- if(res->addable) {
- subnode(&n1, &n2, res);
- tempname(&tmp, n1.type);
- cgen(n->left, &tmp);
- cgen(n->right, &n2);
- cgen(&tmp, &n1);
- return;
- }
- break;
-
- case OREAL:
- case OIMAG:
- nl = n->left;
- if(!nl->addable) {
- tempname(&tmp, nl->type);
- complexgen(nl, &tmp);
- nl = &tmp;
- }
- subnode(&n1, &n2, nl);
- if(n->op == OREAL) {
- cgen(&n1, res);
- return;
- }
- cgen(&n2, res);
- return;
- }
-
- // perform conversion from n to res
- tl = simsimtype(res->type);
- tl = cplxsubtype(tl);
- tr = simsimtype(n->type);
- tr = cplxsubtype(tr);
- if(tl != tr) {
- if(!n->addable) {
- tempname(&n1, n->type);
- complexmove(n, &n1);
- n = &n1;
- }
- complexmove(n, res);
- return;
- }
-
- if(!res->addable) {
- igen(res, &n1, N);
- cgen(n, &n1);
- regfree(&n1);
- return;
- }
- if(n->addable) {
- complexmove(n, res);
- return;
- }
-
- switch(n->op) {
- default:
- dump("complexgen: unknown op", n);
- fatal("complexgen: unknown op %O", n->op);
-
- case ODOT:
- case ODOTPTR:
- case OINDEX:
- case OIND:
- case ONAME: // PHEAP or PPARAMREF var
- case OCALLFUNC:
- igen(n, &n1, res);
- complexmove(&n1, res);
- regfree(&n1);
- return;
-
- case OCONV:
- case OADD:
- case OSUB:
- case OMUL:
- case OMINUS:
- case OCOMPLEX:
- case OREAL:
- case OIMAG:
- break;
- }
-
- nl = n->left;
- if(nl == N)
- return;
- nr = n->right;
-
- // make both sides addable in ullman order
- if(nr != N) {
- if(nl->ullman > nr->ullman && !nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
- if(!nr->addable) {
- tempname(&tnr, nr->type);
- cgen(nr, &tnr);
- nr = &tnr;
- }
- }
- if(!nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
-
- switch(n->op) {
- default:
- fatal("complexgen: unknown op %O", n->op);
- break;
-
- case OCONV:
- complexmove(nl, res);
- break;
-
- case OMINUS:
- complexminus(nl, res);
- break;
-
- case OADD:
- case OSUB:
- complexadd(n->op, nl, nr, res);
- break;
-
- case OMUL:
- complexmul(nl, nr, res);
- break;
- }
-}
-
-void
-complexbool(int op, Node *nl, Node *nr, int true, Prog *to)
-{
- Node tnl, tnr;
- Node n1, n2, n3, n4;
- Node na, nb, nc;
-
- // make both sides addable in ullman order
- if(nr != N) {
- if(nl->ullman > nr->ullman && !nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
- if(!nr->addable) {
- tempname(&tnr, nr->type);
- cgen(nr, &tnr);
- nr = &tnr;
- }
- }
- if(!nl->addable) {
- tempname(&tnl, nl->type);
- cgen(nl, &tnl);
- nl = &tnl;
- }
-
- // build tree
- // real(l) == real(r) && imag(l) == imag(r)
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
-
- memset(&na, 0, sizeof(na));
- na.op = OANDAND;
- na.left = &nb;
- na.right = &nc;
- na.type = types[TBOOL];
-
- memset(&nb, 0, sizeof(na));
- nb.op = OEQ;
- nb.left = &n1;
- nb.right = &n3;
- nb.type = types[TBOOL];
-
- memset(&nc, 0, sizeof(na));
- nc.op = OEQ;
- nc.left = &n2;
- nc.right = &n4;
- nc.type = types[TBOOL];
-
- if(op == ONE)
- true = !true;
-
- bgen(&na, true, to);
-}
-
-void
-nodfconst(Node *n, Type *t, Mpflt* fval)
-{
- memset(n, 0, sizeof(*n));
- n->op = OLITERAL;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.fval = fval;
- n->val.ctype = CTFLT;
- n->type = t;
-
- if(!isfloat[t->etype])
- fatal("nodfconst: bad type %T", t);
-}
-
-// break addable nc-complex into nr-real and ni-imaginary
-static void
-subnode(Node *nr, Node *ni, Node *nc)
-{
- int tc;
- Type *t;
-
- if(!nc->addable)
- fatal("subnode not addable");
-
- tc = simsimtype(nc->type);
- tc = cplxsubtype(tc);
- t = types[tc];
-
- if(nc->op == OLITERAL) {
- nodfconst(nr, t, &nc->val.u.cval->real);
- nodfconst(ni, t, &nc->val.u.cval->imag);
- return;
- }
-
- *nr = *nc;
- nr->type = t;
-
- *ni = *nc;
- ni->type = t;
- ni->xoffset += t->width;
-}
-
-// generate code res = -nl
-static void
-minus(Node *nl, Node *res)
-{
- Node ra;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OMINUS;
- ra.left = nl;
- ra.type = nl->type;
- cgen(&ra, res);
-}
-
-// build and execute tree
-// real(res) = -real(nl)
-// imag(res) = -imag(nl)
-void
-complexminus(Node *nl, Node *res)
-{
- Node n1, n2, n5, n6;
-
- subnode(&n1, &n2, nl);
- subnode(&n5, &n6, res);
-
- minus(&n1, &n5);
- minus(&n2, &n6);
-}
-
-
-// build and execute tree
-// real(res) = real(nl) op real(nr)
-// imag(res) = imag(nl) op imag(nr)
-void
-complexadd(int op, Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, n6;
- Node ra;
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
- subnode(&n5, &n6, res);
-
- memset(&ra, 0, sizeof(ra));
- ra.op = op;
- ra.left = &n1;
- ra.right = &n3;
- ra.type = n1.type;
- cgen(&ra, &n5);
-
- memset(&ra, 0, sizeof(ra));
- ra.op = op;
- ra.left = &n2;
- ra.right = &n4;
- ra.type = n2.type;
- cgen(&ra, &n6);
-}
-
-// build and execute tree
-// tmp = real(nl)*real(nr) - imag(nl)*imag(nr)
-// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
-// real(res) = tmp
-void
-complexmul(Node *nl, Node *nr, Node *res)
-{
- Node n1, n2, n3, n4, n5, n6;
- Node rm1, rm2, ra, tmp;
-
- subnode(&n1, &n2, nl);
- subnode(&n3, &n4, nr);
- subnode(&n5, &n6, res);
- tempname(&tmp, n5.type);
-
- // real part -> tmp
- memset(&rm1, 0, sizeof(ra));
- rm1.op = OMUL;
- rm1.left = &n1;
- rm1.right = &n3;
- rm1.type = n1.type;
-
- memset(&rm2, 0, sizeof(ra));
- rm2.op = OMUL;
- rm2.left = &n2;
- rm2.right = &n4;
- rm2.type = n2.type;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OSUB;
- ra.left = &rm1;
- ra.right = &rm2;
- ra.type = rm1.type;
- cgen(&ra, &tmp);
-
- // imag part
- memset(&rm1, 0, sizeof(ra));
- rm1.op = OMUL;
- rm1.left = &n1;
- rm1.right = &n4;
- rm1.type = n1.type;
-
- memset(&rm2, 0, sizeof(ra));
- rm2.op = OMUL;
- rm2.left = &n2;
- rm2.right = &n3;
- rm2.type = n2.type;
-
- memset(&ra, 0, sizeof(ra));
- ra.op = OADD;
- ra.left = &rm1;
- ra.right = &rm2;
- ra.type = rm1.type;
- cgen(&ra, &n6);
-
- // tmp ->real part
- cgen(&tmp, &n5);
-}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
deleted file mode 100644
index 7290f9d3b..000000000
--- a/src/cmd/gc/dcl.c
+++ /dev/null
@@ -1,1248 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-#include "y.tab.h"
-
-static void funcargs(Node*);
-
-static int
-dflag(void)
-{
- if(!debug['d'])
- return 0;
- if(debug['y'])
- return 1;
- if(incannedimport)
- return 0;
- return 1;
-}
-
-/*
- * declaration stack & operations
- */
-
-static void
-dcopy(Sym *a, Sym *b)
-{
- a->pkg = b->pkg;
- a->name = b->name;
- a->def = b->def;
- a->block = b->block;
- a->lastlineno = b->lastlineno;
-}
-
-static Sym*
-push(void)
-{
- Sym *d;
-
- d = mal(sizeof(*d));
- d->lastlineno = lineno;
- d->link = dclstack;
- dclstack = d;
- return d;
-}
-
-static Sym*
-pushdcl(Sym *s)
-{
- Sym *d;
-
- d = push();
- dcopy(d, s);
- if(dflag())
- print("\t%L push %S %p\n", lineno, s, s->def);
- return d;
-}
-
-void
-popdcl(void)
-{
- Sym *d, *s;
- int lno;
-
-// if(dflag())
-// print("revert\n");
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil)
- break;
- s = pkglookup(d->name, d->pkg);
- lno = s->lastlineno;
- dcopy(s, d);
- d->lastlineno = lno;
- if(dflag())
- print("\t%L pop %S %p\n", lineno, s, s->def);
- }
- if(d == S)
- fatal("popdcl: no mark");
- dclstack = d->link;
- block = d->block;
-}
-
-void
-poptodcl(void)
-{
- // pop the old marker and push a new one
- // (cannot reuse the existing one)
- // because we use the markers to identify blocks
- // for the goto restriction checks.
- popdcl();
- markdcl();
-}
-
-void
-markdcl(void)
-{
- Sym *d;
-
- d = push();
- d->name = nil; // used as a mark in fifo
- d->block = block;
-
- blockgen++;
- block = blockgen;
-
-// if(dflag())
-// print("markdcl\n");
-}
-
-void
-dumpdcl(char *st)
-{
- Sym *s, *d;
- int i;
-
- i = 0;
- for(d=dclstack; d!=S; d=d->link) {
- i++;
- print(" %.2d %p", i, d);
- if(d->name == nil) {
- print("\n");
- continue;
- }
- print(" '%s'", d->name);
- s = pkglookup(d->name, d->pkg);
- print(" %lS\n", s);
- }
-}
-
-void
-testdclstack(void)
-{
- Sym *d;
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil) {
- yyerror("mark left on the stack");
- continue;
- }
- }
-}
-
-void
-redeclare(Sym *s, char *where)
-{
- if(s->lastlineno == 0)
- yyerror("%S redeclared %s\n"
- "\tprevious declaration during import",
- s, where);
- else
- yyerror("%S redeclared %s\n"
- "\tprevious declaration at %L",
- s, where, s->lastlineno);
-}
-
-/*
- * declare individual names - var, typ, const
- */
-void
-declare(Node *n, int ctxt)
-{
- Sym *s;
- int gen;
- static int typegen, vargen;
-
- if(isblank(n))
- return;
-
- n->lineno = parserline();
- s = n->sym;
- gen = 0;
- if(ctxt == PEXTERN) {
- externdcl = list(externdcl, n);
- if(dflag())
- print("\t%L global decl %S %p\n", lineno, s, n);
- } else {
- if(curfn == nil && ctxt == PAUTO)
- fatal("automatic outside function");
- if(curfn != nil)
- curfn->dcl = list(curfn->dcl, n);
- if(n->op == OTYPE)
- gen = ++typegen;
- else if(n->op == ONAME)
- gen = ++vargen;
- pushdcl(s);
- n->curfn = curfn;
- }
- if(ctxt == PAUTO)
- n->xoffset = BADWIDTH;
-
- if(s->block == block)
- redeclare(s, "in this block");
-
- s->block = block;
- s->lastlineno = parserline();
- s->def = n;
- n->vargen = gen;
- n->funcdepth = funcdepth;
- n->class = ctxt;
-
- autoexport(n, ctxt);
-}
-
-void
-addvar(Node *n, Type *t, int ctxt)
-{
- if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
- fatal("addvar: n=%N t=%T nil", n, t);
-
- n->op = ONAME;
- declare(n, ctxt);
- n->type = t;
-}
-
-/*
- * declare variables from grammar
- * new_name_list (type | [type] = expr_list)
- */
-NodeList*
-variter(NodeList *vl, Node *t, NodeList *el)
-{
- int doexpr;
- Node *v, *e, *as2;
- NodeList *init;
-
- init = nil;
- doexpr = el != nil;
-
- if(count(el) == 1 && count(vl) > 1) {
- e = el->n;
- as2 = nod(OAS2, N, N);
- as2->list = vl;
- as2->rlist = list1(e);
- for(; vl; vl=vl->next) {
- v = vl->n;
- v->op = ONAME;
- declare(v, dclcontext);
- v->ntype = t;
- v->defn = as2;
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- }
- return list(init, as2);
- }
-
- for(; vl; vl=vl->next) {
- if(doexpr) {
- if(el == nil) {
- yyerror("missing expr in var dcl");
- break;
- }
- e = el->n;
- el = el->next;
- } else
- e = N;
-
- v = vl->n;
- v->op = ONAME;
- declare(v, dclcontext);
- v->ntype = t;
-
- if(e != N || funcdepth > 0 || isblank(v)) {
- if(funcdepth > 0)
- init = list(init, nod(ODCL, v, N));
- e = nod(OAS, v, e);
- init = list(init, e);
- if(e->right != N)
- v->defn = e;
- }
- }
- if(el != nil)
- yyerror("extra expr in var dcl");
- return init;
-}
-
-/*
- * declare constants from grammar
- * new_name_list [[type] = expr_list]
- */
-NodeList*
-constiter(NodeList *vl, Node *t, NodeList *cl)
-{
- Node *v, *c;
- NodeList *vv;
-
- vv = nil;
- if(cl == nil) {
- if(t != N)
- yyerror("constdcl cannot have type without expr");
- cl = lastconst;
- t = lasttype;
- } else {
- lastconst = cl;
- lasttype = t;
- }
- cl = listtreecopy(cl);
-
- for(; vl; vl=vl->next) {
- if(cl == nil) {
- yyerror("missing expr in const dcl");
- break;
- }
- c = cl->n;
- cl = cl->next;
-
- v = vl->n;
- v->op = OLITERAL;
- declare(v, dclcontext);
-
- v->ntype = t;
- v->defn = c;
-
- vv = list(vv, nod(ODCLCONST, v, N));
- }
- if(cl != nil)
- yyerror("extra expr in const dcl");
- iota += 1;
- return vv;
-}
-
-/*
- * this generates a new name node,
- * typically for labels or other one-off names.
- */
-Node*
-newname(Sym *s)
-{
- Node *n;
-
- if(s == S)
- fatal("newname nil");
-
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = T;
- n->addable = 1;
- n->ullman = 1;
- n->xoffset = 0;
- return n;
-}
-
-/*
- * this generates a new name node for a name
- * being declared.
- */
-Node*
-dclname(Sym *s)
-{
- Node *n;
-
- n = newname(s);
- n->op = ONONAME; // caller will correct it
- return n;
-}
-
-Node*
-typenod(Type *t)
-{
- // if we copied another type with *t = *u
- // then t->nod might be out of date, so
- // check t->nod->type too
- if(t->nod == N || t->nod->type != t) {
- t->nod = nod(OTYPE, N, N);
- t->nod->type = t;
- t->nod->sym = t->sym;
- }
- return t->nod;
-}
-
-
-/*
- * this will return an old name
- * that has already been pushed on the
- * declaration list. a diagnostic is
- * generated if no name has been defined.
- */
-Node*
-oldname(Sym *s)
-{
- Node *n;
- Node *c;
-
- n = s->def;
- if(n == N) {
- // maybe a top-level name will come along
- // to give this a definition later.
- // walkdef will check s->def again once
- // all the input source has been processed.
- n = newname(s);
- n->op = ONONAME;
- n->iota = iota; // save current iota value in const declarations
- }
- if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
- // inner func is referring to var in outer func.
- //
- // TODO(rsc): If there is an outer variable x and we
- // are parsing x := 5 inside the closure, until we get to
- // the := it looks like a reference to the outer x so we'll
- // make x a closure variable unnecessarily.
- if(n->closure == N || n->closure->funcdepth != funcdepth) {
- // create new closure var.
- c = nod(ONAME, N, N);
- c->sym = s;
- c->class = PPARAMREF;
- c->isddd = n->isddd;
- c->defn = n;
- c->addable = 0;
- c->ullman = 2;
- c->funcdepth = funcdepth;
- c->outer = n->closure;
- n->closure = c;
- c->closure = n;
- c->xoffset = 0;
- curfn->cvars = list(curfn->cvars, c);
- }
- // return ref to closure var, not original
- return n->closure;
- }
- return n;
-}
-
-/*
- * same for types
- */
-Type*
-newtype(Sym *s)
-{
- Type *t;
-
- t = typ(TFORW);
- t->sym = s;
- t->type = T;
- return t;
-}
-
-
-/*
- * := declarations
- */
-
-static int
-colasname(Node *n)
-{
- switch(n->op) {
- case ONAME:
- case ONONAME:
- case OPACK:
- case OTYPE:
- case OLITERAL:
- return n->sym != S;
- }
- return 0;
-}
-
-void
-colasdefn(NodeList *left, Node *defn)
-{
- int nnew;
- NodeList *l;
- Node *n;
-
- nnew = 0;
- for(l=left; l; l=l->next) {
- n = l->n;
- if(isblank(n))
- continue;
- if(!colasname(n)) {
- yyerror("non-name %#N on left side of :=", n);
- continue;
- }
- if(n->sym->block == block)
- continue;
-
- nnew++;
- n = newname(n->sym);
- declare(n, dclcontext);
- n->defn = defn;
- defn->ninit = list(defn->ninit, nod(ODCL, n, N));
- l->n = n;
- }
- if(nnew == 0)
- yyerror("no new variables on left side of :=");
-}
-
-Node*
-colas(NodeList *left, NodeList *right)
-{
- Node *as;
-
- as = nod(OAS2, N, N);
- as->list = left;
- as->rlist = right;
- as->colas = 1;
- colasdefn(left, as);
-
- // make the tree prettier; not necessary
- if(count(left) == 1 && count(right) == 1) {
- as->left = as->list->n;
- as->right = as->rlist->n;
- as->list = nil;
- as->rlist = nil;
- as->op = OAS;
- }
-
- return as;
-}
-
-/*
- * declare the arguments in an
- * interface field declaration.
- */
-void
-ifacedcl(Node *n)
-{
- if(n->op != ODCLFIELD || n->right == N)
- fatal("ifacedcl");
-
- dclcontext = PAUTO;
- markdcl();
- funcdepth++;
- n->outer = curfn;
- curfn = n;
- funcargs(n->right);
-
- // funcbody is normally called after the parser has
- // seen the body of a function but since an interface
- // field declaration does not have a body, we must
- // call it now to pop the current declaration context.
- funcbody(n);
-}
-
-/*
- * declare the function proper
- * and declare the arguments.
- * called in extern-declaration context
- * returns in auto-declaration context.
- */
-void
-funchdr(Node *n)
-{
-
- if(n->nname != N) {
- n->nname->op = ONAME;
- declare(n->nname, PFUNC);
- n->nname->defn = n;
- }
-
- // change the declaration context from extern to auto
- if(funcdepth == 0 && dclcontext != PEXTERN)
- fatal("funchdr: dclcontext");
-
- dclcontext = PAUTO;
- markdcl();
- funcdepth++;
-
- n->outer = curfn;
- curfn = n;
- if(n->nname)
- funcargs(n->nname->ntype);
- else
- funcargs(n->ntype);
-}
-
-static void
-funcargs(Node *nt)
-{
- Node *n;
- NodeList *l;
- int gen;
-
- if(nt->op != OTFUNC)
- fatal("funcargs %O", nt->op);
-
- // declare the receiver and in arguments.
- // no n->defn because type checking of func header
- // will fill in the types before we can demand them.
- if(nt->left != N) {
- n = nt->left;
- if(n->op != ODCLFIELD)
- fatal("funcargs1 %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- declare(n->left, PPARAM);
- }
- }
- for(l=nt->list; l; l=l->next) {
- n = l->n;
- if(n->op != ODCLFIELD)
- fatal("funcargs2 %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- declare(n->left, PPARAM);
- }
- }
-
- // declare the out arguments.
- gen = 0;
- for(l=nt->rlist; l; l=l->next) {
- n = l->n;
- if(n->op != ODCLFIELD)
- fatal("funcargs3 %O", n->op);
- if(n->left != N) {
- n->left->op = ONAME;
- n->left->ntype = n->right;
- if(isblank(n->left)) {
- // Give it a name so we can assign to it during return.
- snprint(namebuf, sizeof(namebuf), ".anon%d", gen++);
- n->left->sym = lookup(namebuf);
- }
- declare(n->left, PPARAMOUT);
- }
- }
-}
-
-/*
- * finish the body.
- * called in auto-declaration context.
- * returns in extern-declaration context.
- */
-void
-funcbody(Node *n)
-{
- // change the declaration context from auto to extern
- if(dclcontext != PAUTO)
- fatal("funcbody: dclcontext");
- popdcl();
- funcdepth--;
- curfn = n->outer;
- n->outer = N;
- if(funcdepth == 0)
- dclcontext = PEXTERN;
-}
-
-/*
- * new type being defined with name s.
- */
-Node*
-typedcl0(Sym *s)
-{
- Node *n;
-
- n = dclname(s);
- n->op = OTYPE;
- declare(n, dclcontext);
- return n;
-}
-
-/*
- * node n, which was returned by typedcl0
- * is being declared to have uncompiled type t.
- * return the ODCLTYPE node to use.
- */
-Node*
-typedcl1(Node *n, Node *t, int local)
-{
- n->ntype = t;
- n->local = local;
- return nod(ODCLTYPE, n, N);
-}
-
-/*
- * typedcl1 but during imports
- */
-void
-typedcl2(Type *pt, Type *t)
-{
- Node *n;
-
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if(incannedimport &&
- strcmp(importpkg->name, "unsafe") == 0 &&
- strcmp(pt->nod->sym->name, "Pointer") == 0) {
- t = types[TUNSAFEPTR];
- }
-
- if(pt->etype == TFORW)
- goto ok;
- if(!eqtype(pt->orig, t))
- yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
- return;
-
-ok:
- n = pt->nod;
- copytype(pt->nod, t);
- // unzero nod
- pt->nod = n;
-
- pt->sym->lastlineno = parserline();
- declare(n, PEXTERN);
-
- checkwidth(pt);
-}
-
-/*
- * structs, functions, and methods.
- * they don't belong here, but where do they belong?
- */
-
-
-/*
- * turn a parsed struct into a type
- */
-static Type**
-stotype(NodeList *l, int et, Type **t, int funarg)
-{
- Type *f, *t1, *t2, **t0;
- Strlit *note;
- int lno;
- Node *n, *left;
- char *what;
-
- t0 = t;
- lno = lineno;
- what = "field";
- if(et == TINTER)
- what = "method";
-
- for(; l; l=l->next) {
- n = l->n;
- lineno = n->lineno;
- note = nil;
-
- if(n->op != ODCLFIELD)
- fatal("stotype: oops %N\n", n);
- left = n->left;
- if(funarg && isblank(left))
- left = N;
- if(n->right != N) {
- if(et == TINTER && left != N) {
- // queue resolution of method type for later.
- // right now all we need is the name list.
- // avoids cycles for recursive interface types.
- n->type = typ(TINTERMETH);
- n->type->nname = n->right;
- n->right = N;
- left->type = n->type;
- queuemethod(n);
- } else {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- if(n->type == T) {
- *t0 = T;
- return t0;
- }
- if(left != N)
- left->type = n->type;
- n->right = N;
- if(n->embedded && n->type != T) {
- t1 = n->type;
- if(t1->sym == S && isptr[t1->etype]) {
- t1 = t1->type;
- if(t1->etype == TINTER)
- yyerror("embedded type cannot be a pointer to interface");
- }
- if(isptr[t1->etype])
- yyerror("embedded type cannot be a pointer");
- else if(t1->etype == TFORW && t1->embedlineno == 0)
- t1->embedlineno = lineno;
- }
- }
- }
-
- if(n->type == T) {
- // assume error already printed
- continue;
- }
-
- switch(n->val.ctype) {
- case CTSTR:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- note = n->val.u.sval;
- break;
- default:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- else
- yyerror("field annotation must be string");
- case CTxxx:
- note = nil;
- break;
- }
-
- if(et == TINTER && left == N) {
- // embedded interface - inline the methods
- if(n->type->etype != TINTER) {
- if(n->type->etype == TFORW)
- yyerror("interface type loop involving %T", n->type);
- else
- yyerror("interface contains embedded non-interface %T", n->type);
- continue;
- }
- for(t1=n->type->type; t1!=T; t1=t1->down) {
- f = typ(TFIELD);
- f->type = t1->type;
- f->width = BADWIDTH;
- f->nname = newname(t1->sym);
- f->sym = t1->sym;
- for(t2=*t0; t2!=T; t2=t2->down) {
- if(t2->sym == f->sym) {
- yyerror("duplicate method %s", t2->sym->name);
- break;
- }
- }
- *t = f;
- t = &f->down;
- }
- continue;
- }
-
- f = typ(TFIELD);
- f->type = n->type;
- f->note = note;
- f->width = BADWIDTH;
- f->isddd = n->isddd;
-
- if(left != N && left->op == ONAME) {
- f->nname = left;
- f->embedded = n->embedded;
- f->sym = f->nname->sym;
- if(importpkg && !exportname(f->sym->name))
- f->sym = pkglookup(f->sym->name, structpkg);
- if(f->sym && !isblank(f->nname)) {
- for(t1=*t0; t1!=T; t1=t1->down) {
- if(t1->sym == f->sym) {
- yyerror("duplicate %s %s", what, t1->sym->name);
- break;
- }
- }
- }
- }
-
- *t = f;
- t = &f->down;
- }
-
- *t = T;
- lineno = lno;
- return t;
-}
-
-Type*
-dostruct(NodeList *l, int et)
-{
- Type *t;
- int funarg;
-
- /*
- * convert a parsed id/type list into
- * a type for struct/interface/arglist
- */
-
- funarg = 0;
- if(et == TFUNC) {
- funarg = 1;
- et = TSTRUCT;
- }
- t = typ(et);
- t->funarg = funarg;
- stotype(l, et, &t->type, funarg);
- if(t->type == T && l != nil) {
- t->broke = 1;
- return t;
- }
- if(et == TINTER)
- t = sortinter(t);
- if(!funarg)
- checkwidth(t);
- return t;
-}
-
-
-Node*
-embedded(Sym *s)
-{
- Node *n;
- char *name;
-
- // Names sometimes have disambiguation junk
- // appended after a center dot. Discard it when
- // making the name for the embedded struct field.
- enum { CenterDot = 0xB7 };
- name = s->name;
- if(utfrune(s->name, CenterDot)) {
- name = strdup(s->name);
- *utfrune(name, CenterDot) = 0;
- }
-
- n = newname(lookup(name));
- n = nod(ODCLFIELD, n, oldname(s));
- n->embedded = 1;
- return n;
-}
-
-/*
- * check that the list of declarations is either all anonymous or all named
- */
-
-static Node*
-findtype(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return l->n->right;
- return N;
-}
-
-NodeList*
-checkarglist(NodeList *all, int input)
-{
- int named;
- Node *n, *t, *nextt;
- NodeList *l;
-
- named = 0;
- for(l=all; l; l=l->next) {
- if(l->n->op == OKEY) {
- named = 1;
- break;
- }
- }
- if(named) {
- n = N;
- for(l=all; l; l=l->next) {
- n = l->n;
- if(n->op != OKEY && n->sym == S) {
- yyerror("mixed named and unnamed function parameters");
- break;
- }
- }
- if(l == nil && n != N && n->op != OKEY)
- yyerror("final function parameter must have type");
- }
-
- nextt = nil;
- for(l=all; l; l=l->next) {
- // can cache result from findtype to avoid
- // quadratic behavior here, but unlikely to matter.
- n = l->n;
- if(named) {
- if(n->op == OKEY) {
- t = n->right;
- n = n->left;
- nextt = nil;
- } else {
- if(nextt == nil)
- nextt = findtype(l);
- t = nextt;
- }
- } else {
- t = n;
- n = N;
- }
- if(n != N && n->sym == S) {
- t = n;
- n = N;
- }
- if(n != N)
- n = newname(n->sym);
- n = nod(ODCLFIELD, n, t);
- if(n->right != N && n->right->op == ODDD) {
- if(!input)
- yyerror("cannot use ... in output argument list");
- else if(l->next != nil)
- yyerror("can only use ... as final argument in list");
- n->right->op = OTARRAY;
- n->right->right = n->right->left;
- n->right->left = N;
- n->isddd = 1;
- if(n->left != N)
- n->left->isddd = 1;
- }
- l->n = n;
- }
- return all;
-}
-
-
-Node*
-fakethis(void)
-{
- Node *n;
-
- n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
- return n;
-}
-
-/*
- * Is this field a method on an interface?
- * Those methods have an anonymous
- * *struct{} as the receiver.
- * (See fakethis above.)
- */
-int
-isifacemethod(Type *f)
-{
- Type *rcvr;
- Type *t;
-
- rcvr = getthisx(f)->type;
- if(rcvr->sym != S)
- return 0;
- t = rcvr->type;
- if(!isptr[t->etype])
- return 0;
- t = t->type;
- if(t->sym != S || t->etype != TSTRUCT || t->type != T)
- return 0;
- return 1;
-}
-
-/*
- * turn a parsed function declaration
- * into a type
- */
-Type*
-functype(Node *this, NodeList *in, NodeList *out)
-{
- Type *t;
- NodeList *rcvr;
-
- t = typ(TFUNC);
-
- rcvr = nil;
- if(this)
- rcvr = list1(this);
- t->type = dostruct(rcvr, TFUNC);
- t->type->down = dostruct(out, TFUNC);
- t->type->down->down = dostruct(in, TFUNC);
-
- if(this)
- t->thistuple = 1;
- t->outtuple = count(out);
- t->intuple = count(in);
- t->outnamed = t->outtuple > 0 && out->n->left != N;
-
- return t;
-}
-
-Sym*
-methodsym(Sym *nsym, Type *t0, int iface)
-{
- Sym *s;
- char *p;
- Type *t;
- char *suffix;
-
- t = t0;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S) {
- if(!isptr[t->etype])
- goto bad;
- t = t->type;
- if(t == T)
- goto bad;
- s = t->sym;
- if(s == S)
- goto bad;
- }
-
- // if t0 == *t and t0 has a sym,
- // we want to see *t, not t0, in the method name.
- if(t != t0 && t0->sym)
- t0 = ptrto(t);
-
- suffix = "";
- if(iface) {
- dowidth(t0);
- if(t0->width < types[tptr]->width)
- suffix = "·i";
- }
- p = smprint("%#hT·%s%s", t0, nsym->name, suffix);
- s = pkglookup(p, s->pkg);
- free(p);
- return s;
-
-bad:
- yyerror("illegal receiver type: %T", t0);
- return S;
-}
-
-Node*
-methodname(Node *n, Type *t)
-{
- Sym *s;
-
- s = methodsym(n->sym, t, 0);
- if(s == S)
- return n;
- return newname(s);
-}
-
-Node*
-methodname1(Node *n, Node *t)
-{
- char *star;
- char *p;
-
- star = "";
- if(t->op == OIND) {
- star = "*";
- t = t->left;
- }
- if(t->sym == S || isblank(n))
- return newname(n->sym);
- p = smprint("%s%S·%S", star, t->sym, n->sym);
- n = newname(pkglookup(p, t->sym->pkg));
- free(p);
- return n;
-}
-
-/*
- * add a method, declared as a function,
- * n is fieldname, pa is base type, t is function type
- */
-void
-addmethod(Sym *sf, Type *t, int local)
-{
- Type *f, *d, *pa;
- Node *n;
-
- pa = nil;
-
- // get field sym
- if(sf == S)
- fatal("no method symbol");
-
- // get parent type sym
- pa = getthisx(t)->type; // ptr to this structure
- if(pa == T) {
- yyerror("missing receiver");
- return;
- }
-
- pa = pa->type;
- f = methtype(pa);
- if(f == T) {
- t = pa;
- if(t != T) {
- if(isptr[t->etype]) {
- if(t->sym != S) {
- yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
- return;
- }
- t = t->type;
- }
- }
- if(t != T) {
- if(t->sym == S) {
- yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
- return;
- }
- if(isptr[t->etype]) {
- yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
- return;
- }
- if(t->etype == TINTER) {
- yyerror("invalid receiver type %T (%T is an interface type)", pa, t);
- return;
- }
- }
- // Should have picked off all the reasons above,
- // but just in case, fall back to generic error.
- yyerror("invalid receiver type %T", pa);
- return;
- }
-
- pa = f;
- if(importpkg && !exportname(sf->name))
- sf = pkglookup(sf->name, importpkg);
-
- n = nod(ODCLFIELD, newname(sf), N);
- n->type = t;
-
- d = T; // last found
- for(f=pa->method; f!=T; f=f->down) {
- d = f;
- if(f->etype != TFIELD)
- fatal("addmethod: not TFIELD: %N", f);
- if(strcmp(sf->name, f->sym->name) != 0)
- continue;
- if(!eqtype(t, f->type))
- yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t);
- return;
- }
-
- if(local && !pa->local) {
- // defining method on non-local type.
- yyerror("cannot define new methods on non-local type %T", pa);
- return;
- }
-
- if(d == T)
- stotype(list1(n), 0, &pa->method, 0);
- else
- stotype(list1(n), 0, &d->down, 0);
- return;
-}
-
-void
-funccompile(Node *n, int isclosure)
-{
- stksize = BADWIDTH;
- maxarg = 0;
-
- if(n->type == T) {
- if(nerrors == 0)
- fatal("funccompile missing type");
- return;
- }
-
- // assign parameter offsets
- checkwidth(n->type);
-
- // record offset to actual frame pointer.
- // for closure, have to skip over leading pointers and PC slot.
- nodfp->xoffset = 0;
- if(isclosure) {
- NodeList *l;
- for(l=n->nname->ntype->list; l; l=l->next) {
- nodfp->xoffset += widthptr;
- if(l->n->left == N) // found slot for PC
- break;
- }
- }
-
- if(curfn)
- fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
-
- stksize = 0;
- dclcontext = PAUTO;
- funcdepth = n->funcdepth + 1;
- compile(n);
- curfn = nil;
- funcdepth = 0;
- dclcontext = PEXTERN;
-}
-
-
-
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
deleted file mode 100644
index 3fe7fafdd..000000000
--- a/src/cmd/gc/doc.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-
-Gc is the generic label for the family of Go compilers
-that function as part of the (modified) Plan 9 tool chain. The C compiler
-documentation at
-
- http://plan9.bell-labs.com/sys/doc/comp.pdf (Tools overview)
- http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)
-
-gives the overall design of the tool chain. Aside from a few adapted pieces,
-such as the optimizer, the Go compilers are wholly new programs.
-
-The compiler reads in a set of Go files, typically suffixed ".go". They
-must all be part of one package. The output is a single intermediate file
-representing the "binary assembly" of the compiled package, ready as input
-for the linker (6l, etc.).
-
-The generated files contain type information about the symbols exported by
-the package and about types used by symbols imported by the package from
-other packages. It is therefore not necessary when compiling client C of
-package P to read the files of P's dependencies, only the compiled output
-of P.
-
-Usage:
- 6g [flags] file...
-The specified files must be Go source files and all part of the same package.
-Substitute 6g with 8g or 5g where appropriate.
-
-Flags:
- -o file
- output file, default file.6 for 6g, etc.
- -e
- normally the compiler quits after 10 errors; -e prints all errors
- -L
- show entire file path when printing line numbers in errors
- -I dir1 -I dir2
- add dir1 and dir2 to the list of paths to check for imported packages
- -N
- disable optimization
- -S
- write assembly language text to standard output
- -u
- disallow importing packages not marked as safe
- -V
- print the compiler version
-
-There are also a number of debugging flags; run the command with no arguments
-to get a usage message.
-
-*/
-package documentation
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
deleted file mode 100644
index 014f0c5f0..000000000
--- a/src/cmd/gc/export.c
+++ /dev/null
@@ -1,428 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-#include "y.tab.h"
-
-static void dumpsym(Sym*);
-static void dumpexporttype(Sym*);
-static void dumpexportvar(Sym*);
-static void dumpexportconst(Sym*);
-
-void
-exportsym(Node *n)
-{
- if(n == N || n->sym == S)
- return;
- if(n->sym->flags & (SymExport|SymPackage)) {
- if(n->sym->flags & SymPackage)
- yyerror("export/package mismatch: %S", n->sym);
- return;
- }
- n->sym->flags |= SymExport;
-
- exportlist = list(exportlist, n);
-}
-
-static void
-packagesym(Node *n)
-{
- if(n == N || n->sym == S)
- return;
- if(n->sym->flags & (SymExport|SymPackage)) {
- if(n->sym->flags & SymExport)
- yyerror("export/package mismatch: %S", n->sym);
- return;
- }
- n->sym->flags |= SymPackage;
-
- exportlist = list(exportlist, n);
-}
-
-int
-exportname(char *s)
-{
- Rune r;
-
- if((uchar)s[0] < Runeself)
- return 'A' <= s[0] && s[0] <= 'Z';
- chartorune(&r, s);
- return isupperrune(r);
-}
-
-static int
-initname(char *s)
-{
- return strcmp(s, "init") == 0;
-}
-
-void
-autoexport(Node *n, int ctxt)
-{
- if(n == N || n->sym == S)
- return;
- if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
- return;
- if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
- return;
- if(exportname(n->sym->name) || initname(n->sym->name))
- exportsym(n);
- else
- packagesym(n);
-}
-
-static void
-dumppkg(Pkg *p)
-{
- char *suffix;
-
- if(p == nil || p == localpkg || p->exported)
- return;
- p->exported = 1;
- suffix = "";
- if(!p->direct)
- suffix = " // indirect";
- Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
-}
-
-static void
-dumpprereq(Type *t)
-{
- if(t == T)
- return;
-
- if(t->printed || t == types[t->etype])
- return;
- t->printed = 1;
-
- if(t->sym != S) {
- dumppkg(t->sym->pkg);
- if(t->etype != TFIELD)
- dumpsym(t->sym);
- }
- dumpprereq(t->type);
- dumpprereq(t->down);
-}
-
-static void
-dumpexportconst(Sym *s)
-{
- Node *n;
- Type *t;
-
- n = s->def;
- typecheck(&n, Erv);
- if(n == N || n->op != OLITERAL)
- fatal("dumpexportconst: oconst nil: %S", s);
-
- t = n->type; // may or may not be specified
- if(t != T)
- dumpprereq(t);
-
- Bprint(bout, "\t");
- Bprint(bout, "const %#S", s);
- if(t != T && !isideal(t))
- Bprint(bout, " %#T", t);
- Bprint(bout, " = ");
-
- switch(n->val.ctype) {
- default:
- fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
- case CTINT:
- Bprint(bout, "%B\n", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- Bprint(bout, "true\n");
- else
- Bprint(bout, "false\n");
- break;
- case CTFLT:
- Bprint(bout, "%F\n", n->val.u.fval);
- break;
- case CTCPLX:
- Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
- break;
- case CTSTR:
- Bprint(bout, "\"%Z\"\n", n->val.u.sval);
- break;
- }
-}
-
-static void
-dumpexportvar(Sym *s)
-{
- Node *n;
- Type *t;
-
- n = s->def;
- typecheck(&n, Erv);
- if(n == N || n->type == T) {
- yyerror("variable exported but not defined: %S", s);
- return;
- }
-
- t = n->type;
- dumpprereq(t);
-
- Bprint(bout, "\t");
- if(t->etype == TFUNC && n->class == PFUNC)
- Bprint(bout, "func %#S %#hhT", s, t);
- else
- Bprint(bout, "var %#S %#T", s, t);
- Bprint(bout, "\n");
-}
-
-static void
-dumpexporttype(Sym *s)
-{
- Type *t;
-
- t = s->def->type;
- dumpprereq(t);
- Bprint(bout, "\t");
- switch (t->etype) {
- case TFORW:
- yyerror("export of incomplete type %T", t);
- return;
- }
- if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
- fatal("Bprint failed for %T", t);
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
- Type *a, *b;
-
- a = *(Type**)va;
- b = *(Type**)vb;
- return strcmp(a->sym->name, b->sym->name);
-}
-
-static void
-dumpsym(Sym *s)
-{
- Type *f, *t;
- Type **m;
- int i, n;
-
- if(s->flags & SymExported)
- return;
- s->flags |= SymExported;
-
- if(s->def == N) {
- yyerror("unknown export symbol: %S", s);
- return;
- }
-
- dumppkg(s->pkg);
-
- switch(s->def->op) {
- default:
- yyerror("unexpected export symbol: %O %S", s->def->op, s);
- break;
- case OLITERAL:
- dumpexportconst(s);
- break;
- case OTYPE:
- t = s->def->type;
- n = 0;
- for(f=t->method; f!=T; f=f->down) {
- dumpprereq(f);
- n++;
- }
- m = mal(n*sizeof m[0]);
- i = 0;
- for(f=t->method; f!=T; f=f->down)
- m[i++] = f;
- qsort(m, n, sizeof m[0], methcmp);
-
- dumpexporttype(s);
- for(i=0; i<n; i++) {
- f = m[i];
- Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
- f->type->type->type, f->sym, f->type);
- }
- break;
- case ONAME:
- dumpexportvar(s);
- break;
- }
-}
-
-static void
-dumptype(Type *t)
-{
- // no need to re-dump type if already exported
- if(t->printed)
- return;
-
- // no need to dump type if it's not ours (was imported)
- if(t->sym != S && t->sym->def == typenod(t) && !t->local)
- return;
-
- Bprint(bout, "type %#T %l#T\n", t, t);
-}
-
-void
-dumpexport(void)
-{
- NodeList *l;
- int32 i, lno;
- Pkg *p;
-
- lno = lineno;
-
- packagequotes = 1;
- Bprint(bout, "\n$$ // exports\n");
-
- Bprint(bout, " package %s", localpkg->name);
- if(safemode)
- Bprint(bout, " safe");
- Bprint(bout, "\n");
-
- for(i=0; i<nelem(phash); i++)
- for(p=phash[i]; p; p=p->link)
- if(p->direct)
- dumppkg(p);
-
- for(l=exportlist; l; l=l->next) {
- lineno = l->n->lineno;
- dumpsym(l->n->sym);
- }
-
- Bprint(bout, "\n$$ // local types\n");
-
- for(l=typelist; l; l=l->next) {
- lineno = l->n->lineno;
- dumptype(l->n->type);
- }
-
- Bprint(bout, "\n$$\n");
- packagequotes = 0;
-
- lineno = lno;
-}
-
-/*
- * import
- */
-
-/*
- * return the sym for ss, which should match lexical
- */
-Sym*
-importsym(Sym *s, int op)
-{
- if(s->def != N && s->def->op != op)
- redeclare(s, "during import");
-
- // mark the symbol so it is not reexported
- if(s->def == N) {
- if(exportname(s->name) || initname(s->name))
- s->flags |= SymExport;
- else
- s->flags |= SymPackage; // package scope
- }
- return s;
-}
-
-/*
- * return the type pkg.name, forward declaring if needed
- */
-Type*
-pkgtype(Sym *s)
-{
- Type *t;
-
- importsym(s, OTYPE);
- if(s->def == N || s->def->op != OTYPE) {
- t = typ(TFORW);
- t->sym = s;
- s->def = typenod(t);
- }
- if(s->def->type == T)
- yyerror("pkgtype %lS", s);
- return s->def->type;
-}
-
-static int
-mypackage(Sym *s)
-{
- // we import all definitions for runtime.
- // lowercase ones can only be used by the compiler.
- return s->pkg == localpkg || s->pkg == runtimepkg;
-}
-
-void
-importconst(Sym *s, Type *t, Node *n)
-{
- Node *n1;
-
- if(!exportname(s->name) && !mypackage(s))
- return;
- importsym(s, OLITERAL);
- convlit(&n, t);
- if(s->def != N) {
- // TODO: check if already the same.
- return;
- }
-
- if(n->op != OLITERAL) {
- yyerror("expression must be a constant");
- return;
- }
- if(n->sym != S) {
- n1 = nod(OXXX, N, N);
- *n1 = *n;
- n = n1;
- }
- n->sym = s;
- declare(n, PEXTERN);
-
- if(debug['E'])
- print("import const %S\n", s);
-}
-
-void
-importvar(Sym *s, Type *t, int ctxt)
-{
- Node *n;
-
- if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
- return;
-
- importsym(s, ONAME);
- if(s->def != N && s->def->op == ONAME) {
- if(eqtype(t, s->def->type))
- return;
- yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
- s, s->def->type, t);
- }
- n = newname(s);
- n->type = t;
- declare(n, ctxt);
-
- if(debug['E'])
- print("import var %S %lT\n", s, t);
-}
-
-void
-importtype(Type *pt, Type *t)
-{
- if(pt != T && t != T)
- typedcl2(pt, t);
-
- if(debug['E'])
- print("import type %T %lT\n", pt, t);
-}
-
-void
-importmethod(Sym *s, Type *t)
-{
- checkwidth(t);
- addmethod(s, t, 0);
-}
-
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
deleted file mode 100644
index cb66921ba..000000000
--- a/src/cmd/gc/gen.c
+++ /dev/null
@@ -1,790 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * portable half of code generator.
- * mainly statements and control flow.
- */
-
-#include "go.h"
-
-static void cgen_dcl(Node *n);
-static void cgen_proc(Node *n, int proc);
-static void checkgoto(Node*, Node*);
-
-static Label *labellist;
-static Label *lastlabel;
-
-Node*
-sysfunc(char *name)
-{
- Node *n;
-
- n = newname(pkglookup(name, runtimepkg));
- n->class = PFUNC;
- return n;
-}
-
-void
-allocparams(void)
-{
- NodeList *l;
- Node *n;
- uint32 w;
- Sym *s;
- int lno;
-
- if(stksize < 0)
- fatal("allocparams not during code generation");
-
- /*
- * allocate (set xoffset) the stack
- * slots for all automatics.
- * allocated starting at -w down.
- */
- lno = lineno;
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op == ONAME && n->class == PHEAP-1) {
- // heap address variable; finish the job
- // started in addrescapes.
- s = n->sym;
- tempname(n, n->type);
- n->sym = s;
- }
- if(n->op != ONAME || n->class != PAUTO)
- continue;
- if (n->xoffset != BADWIDTH)
- continue;
- if(n->type == T)
- continue;
- dowidth(n->type);
- w = n->type->width;
- if(w >= MAXWIDTH)
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
- }
- lineno = lno;
-}
-
-void
-clearlabels(void)
-{
- Label *l;
-
- for(l=labellist; l!=L; l=l->link)
- l->sym->label = L;
-
- labellist = L;
- lastlabel = L;
-}
-
-static Label*
-newlab(Node *n)
-{
- Sym *s;
- Label *lab;
-
- s = n->left->sym;
- if((lab = s->label) == L) {
- lab = mal(sizeof(*lab));
- if(lastlabel == nil)
- labellist = lab;
- else
- lastlabel->link = lab;
- lastlabel = lab;
- lab->sym = s;
- s->label = lab;
- }
-
- if(n->op == OLABEL) {
- if(lab->def != N)
- yyerror("label %S already defined at %L", s, lab->def->lineno);
- else
- lab->def = n;
- } else
- lab->use = list(lab->use, n);
-
- return lab;
-}
-
-void
-checklabels(void)
-{
- Label *lab;
- NodeList *l;
-
- for(lab=labellist; lab!=L; lab=lab->link) {
- if(lab->def == N) {
- for(l=lab->use; l; l=l->next)
- yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
- continue;
- }
- if(lab->use == nil && !lab->used) {
- yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
- continue;
- }
- if(lab->gotopc != P)
- fatal("label %S never resolved", lab->sym);
- for(l=lab->use; l; l=l->next)
- checkgoto(l->n, lab->def);
- }
-}
-
-static void
-checkgoto(Node *from, Node *to)
-{
- int nf, nt;
- Sym *block, *dcl, *fs, *ts;
- int lno;
-
- if(from->sym == to->sym)
- return;
-
- nf = 0;
- for(fs=from->sym; fs; fs=fs->link)
- nf++;
- nt = 0;
- for(fs=to->sym; fs; fs=fs->link)
- nt++;
- fs = from->sym;
- for(; nf > nt; nf--)
- fs = fs->link;
- if(fs != to->sym) {
- lno = lineno;
- setlineno(from);
-
- // decide what to complain about.
- // prefer to complain about 'into block' over declarations,
- // so scan backward to find most recent block or else dcl.
- block = S;
- dcl = S;
- ts = to->sym;
- for(; nt > nf; nt--) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- }
- while(ts != fs) {
- if(ts->pkg == nil)
- block = ts;
- else
- dcl = ts;
- ts = ts->link;
- fs = fs->link;
- }
-
- if(block)
- yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
- else
- yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
- lineno = lno;
- }
-}
-
-static Label*
-stmtlabel(Node *n)
-{
- Label *lab;
-
- if(n->sym != S)
- if((lab = n->sym->label) != L)
- if(lab->def != N)
- if(lab->def->right == n)
- return lab;
- return L;
-}
-
-/*
- * compile statements
- */
-void
-genlist(NodeList *l)
-{
- for(; l; l=l->next)
- gen(l->n);
-}
-
-void
-gen(Node *n)
-{
- int32 lno;
- Prog *scontin, *sbreak;
- Prog *p1, *p2, *p3;
- Label *lab;
- int32 wasregalloc;
-
- lno = setlineno(n);
- wasregalloc = anyregalloc();
-
- if(n == N)
- goto ret;
-
- p3 = pc; // save pc for loop labels
- if(n->ninit)
- genlist(n->ninit);
-
- setlineno(n);
-
- switch(n->op) {
- default:
- fatal("gen: unknown op %N", n);
- break;
-
- case OCASE:
- case OFALL:
- case OXCASE:
- case OXFALL:
- case ODCLCONST:
- case ODCLFUNC:
- case ODCLTYPE:
- break;
-
- case OEMPTY:
- break;
-
- case OBLOCK:
- genlist(n->list);
- break;
-
- case OLABEL:
- lab = newlab(n);
-
- // if there are pending gotos, resolve them all to the current pc.
- for(p1=lab->gotopc; p1; p1=p2) {
- p2 = unpatch(p1);
- patch(p1, pc);
- }
- lab->gotopc = P;
- if(lab->labelpc == P)
- lab->labelpc = pc;
-
- if(n->right) {
- switch(n->right->op) {
- case OFOR:
- case OSWITCH:
- case OSELECT:
- // so stmtlabel can find the label
- n->right->sym = lab->sym;
- }
- }
- break;
-
- case OGOTO:
- // if label is defined, emit jump to it.
- // otherwise save list of pending gotos in lab->gotopc.
- // the list is linked through the normal jump target field
- // to avoid a second list. (the jumps are actually still
- // valid code, since they're just going to another goto
- // to the same label. we'll unwind it when we learn the pc
- // of the label in the OLABEL case above.)
- lab = newlab(n);
- if(lab->labelpc != P)
- gjmp(lab->labelpc);
- else
- lab->gotopc = gjmp(lab->gotopc);
- break;
-
- case OBREAK:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("break label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->breakpc == P) {
- yyerror("invalid break label %S", n->left->sym);
- break;
- }
- gjmp(lab->breakpc);
- break;
- }
- if(breakpc == P) {
- yyerror("break is not in a loop");
- break;
- }
- gjmp(breakpc);
- break;
-
- case OCONTINUE:
- if(n->left != N) {
- lab = n->left->sym->label;
- if(lab == L) {
- yyerror("continue label not defined: %S", n->left->sym);
- break;
- }
- lab->used = 1;
- if(lab->continpc == P) {
- yyerror("invalid continue label %S", n->left->sym);
- break;
- }
- gjmp(lab->continpc);
- break;
- }
- if(continpc == P) {
- yyerror("continue is not in a loop");
- break;
- }
- gjmp(continpc);
- break;
-
- case OFOR:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
- scontin = continpc;
- continpc = pc;
-
- // define break and continue labels
- if((lab = stmtlabel(n)) != L) {
- lab->breakpc = breakpc;
- lab->continpc = continpc;
- }
- gen(n->nincr); // contin: incr
- patch(p1, pc); // test:
- bgen(n->ntest, 0, breakpc); // if(!test) goto break
- genlist(n->nbody); // body
- gjmp(continpc);
- patch(breakpc, pc); // done:
- continpc = scontin;
- breakpc = sbreak;
- if(lab) {
- lab->breakpc = P;
- lab->continpc = P;
- }
- break;
-
- case OIF:
- p1 = gjmp(P); // goto test
- p2 = gjmp(P); // p2: goto else
- patch(p1, pc); // test:
- bgen(n->ntest, 0, p2); // if(!test) goto p2
- genlist(n->nbody); // then
- p3 = gjmp(P); // goto done
- patch(p2, pc); // else:
- genlist(n->nelse); // else
- patch(p3, pc); // done:
- break;
-
- case OSWITCH:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // switch(test) body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OSELECT:
- sbreak = breakpc;
- p1 = gjmp(P); // goto test
- breakpc = gjmp(P); // break: goto done
-
- // define break label
- if((lab = stmtlabel(n)) != L)
- lab->breakpc = breakpc;
-
- patch(p1, pc); // test:
- genlist(n->nbody); // select() body
- patch(breakpc, pc); // done:
- breakpc = sbreak;
- if(lab != L)
- lab->breakpc = P;
- break;
-
- case OASOP:
- cgen_asop(n);
- break;
-
- case ODCL:
- cgen_dcl(n->left);
- break;
-
- case OAS:
- if(gen_as_init(n))
- break;
- cgen_as(n->left, n->right);
- break;
-
- case OCALLMETH:
- cgen_callmeth(n, 0);
- break;
-
- case OCALLINTER:
- cgen_callinter(n, N, 0);
- break;
-
- case OCALLFUNC:
- cgen_call(n, 0);
- break;
-
- case OPROC:
- cgen_proc(n, 1);
- break;
-
- case ODEFER:
- cgen_proc(n, 2);
- break;
-
- case ORETURN:
- cgen_ret(n);
- break;
- }
-
-ret:
- if(anyregalloc() != wasregalloc) {
- dump("node", n);
- fatal("registers left allocated");
- }
-
- lineno = lno;
-}
-
-/*
- * generate call to non-interface method
- * proc=0 normal call
- * proc=1 goroutine run in new proc
- * proc=2 defer call save away stack
- */
-void
-cgen_callmeth(Node *n, int proc)
-{
- Node *l;
-
- // generate a rewrite for method call
- // (p.f)(...) goes to (f)(p,...)
-
- l = n->left;
- if(l->op != ODOTMETH)
- fatal("cgen_callmeth: not dotmethod: %N");
-
- n->op = OCALLFUNC;
- n->left = n->left->right;
- n->left->type = l->type;
-
- if(n->left->op == ONAME)
- n->left->class = PFUNC;
- cgen_call(n, proc);
-}
-
-/*
- * generate code to start new proc running call n.
- */
-void
-cgen_proc(Node *n, int proc)
-{
- switch(n->left->op) {
- default:
- fatal("cgen_proc: unknown call %O", n->left->op);
-
- case OCALLMETH:
- cgen_callmeth(n->left, proc);
- break;
-
- case OCALLINTER:
- cgen_callinter(n->left, N, proc);
- break;
-
- case OCALLFUNC:
- cgen_call(n->left, proc);
- break;
- }
-
-}
-
-/*
- * generate declaration.
- * nothing to do for on-stack automatics,
- * but might have to allocate heap copy
- * for escaped variables.
- */
-static void
-cgen_dcl(Node *n)
-{
- if(debug['g'])
- dump("\ncgen-dcl", n);
- if(n->op != ONAME) {
- dump("cgen_dcl", n);
- fatal("cgen_dcl");
- }
- if(!(n->class & PHEAP))
- return;
- if(n->alloc == nil)
- n->alloc = callnew(n->type);
- cgen_as(n->heapaddr, n->alloc);
-}
-
-/*
- * generate discard of value
- */
-static void
-cgen_discard(Node *nr)
-{
- Node tmp;
-
- if(nr == N)
- return;
-
- switch(nr->op) {
- case ONAME:
- if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
- gused(nr);
- break;
-
- // unary
- case OADD:
- case OAND:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLSH:
- case OLT:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case ORSH:
- case OSUB:
- case OXOR:
- cgen_discard(nr->left);
- cgen_discard(nr->right);
- break;
-
- // binary
- case OCAP:
- case OCOM:
- case OLEN:
- case OMINUS:
- case ONOT:
- case OPLUS:
- cgen_discard(nr->left);
- break;
-
- // special enough to just evaluate
- default:
- tempname(&tmp, nr->type);
- cgen_as(&tmp, nr);
- gused(&tmp);
- }
-}
-
-/*
- * generate assignment:
- * nl = nr
- * nr == N means zero nl.
- */
-void
-cgen_as(Node *nl, Node *nr)
-{
- Node nc;
- Type *tl;
- int iszer;
-
- if(nl == N)
- return;
-
- if(debug['g']) {
- dump("cgen_as", nl);
- dump("cgen_as = ", nr);
- }
-
- if(isblank(nl)) {
- cgen_discard(nr);
- return;
- }
-
- iszer = 0;
- if(nr == N || isnil(nr)) {
- // externals and heaps should already be clear
- if(nr == N) {
- if(nl->class == PEXTERN)
- return;
- if(nl->class & PHEAP)
- return;
- }
-
- tl = nl->type;
- if(tl == T)
- return;
- if(isfat(tl)) {
- clearfat(nl);
- goto ret;
- }
-
- /* invent a "zero" for the rhs */
- iszer = 1;
- nr = &nc;
- memset(nr, 0, sizeof(*nr));
- switch(simtype[tl->etype]) {
- default:
- fatal("cgen_as: tl %T", tl);
- break;
-
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- nr->val.u.xval = mal(sizeof(*nr->val.u.xval));
- mpmovecfix(nr->val.u.xval, 0);
- nr->val.ctype = CTINT;
- break;
-
- case TFLOAT32:
- case TFLOAT64:
- nr->val.u.fval = mal(sizeof(*nr->val.u.fval));
- mpmovecflt(nr->val.u.fval, 0.0);
- nr->val.ctype = CTFLT;
- break;
-
- case TBOOL:
- nr->val.u.bval = 0;
- nr->val.ctype = CTBOOL;
- break;
-
- case TPTR32:
- case TPTR64:
- nr->val.ctype = CTNIL;
- break;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- nr->val.u.cval = mal(sizeof(*nr->val.u.cval));
- mpmovecflt(&nr->val.u.cval->real, 0.0);
- mpmovecflt(&nr->val.u.cval->imag, 0.0);
- break;
- }
- nr->op = OLITERAL;
- nr->type = tl;
- nr->addable = 1;
- ullmancalc(nr);
- }
-
- tl = nl->type;
- if(tl == T)
- return;
-
- cgen(nr, nl);
- if(iszer && nl->addable)
- gused(nl);
-
-ret:
- ;
-}
-
-/*
- * gather series of offsets
- * >=0 is direct addressed field
- * <0 is pointer to next field (+1)
- */
-int
-dotoffset(Node *n, int *oary, Node **nn)
-{
- int i;
-
- switch(n->op) {
- case ODOT:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i > 0) {
- if(oary[i-1] >= 0)
- oary[i-1] += n->xoffset;
- else
- oary[i-1] -= n->xoffset;
- break;
- }
- if(i < 10)
- oary[i++] = n->xoffset;
- break;
-
- case ODOTPTR:
- if(n->xoffset == BADWIDTH) {
- dump("bad width in dotoffset", n);
- fatal("bad width in dotoffset");
- }
- i = dotoffset(n->left, oary, nn);
- if(i < 10)
- oary[i++] = -(n->xoffset+1);
- break;
-
- default:
- *nn = n;
- return 0;
- }
- if(i >= 10)
- *nn = N;
- return i;
-}
-
-/*
- * make a new off the books
- */
-void
-tempname(Node *nn, Type *t)
-{
- Node *n;
- Sym *s;
- uint32 w;
-
- if(stksize < 0)
- fatal("tempname not during code generation");
-
- if (curfn == N)
- fatal("no curfn for tempname");
-
- if(t == T) {
- yyerror("tempname called with nil type");
- t = types[TINT32];
- }
-
- // give each tmp a different name so that there
- // a chance to registerizer them
- snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
- statuniqgen++;
- s = lookup(namebuf);
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = t;
- n->class = PAUTO;
- n->addable = 1;
- n->ullman = 1;
- n->noescape = 1;
- n->curfn = curfn;
- curfn->dcl = list(curfn->dcl, n);
-
- dowidth(t);
- w = t->width;
- stksize += w;
- stksize = rnd(stksize, t->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
-
- // print("\ttmpname (%d): %N\n", stksize, n);
-
- *nn = *n;
-}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
deleted file mode 100644
index b5af4678c..000000000
--- a/src/cmd/gc/go.errors
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Example-based syntax error messages.
-// See bisonerrors, Makefile, go.y.
-
-static struct {
- int yystate;
- int yychar;
- char *msg;
-} yymsg[] = {
- // Each line of the form % token list
- // is converted by bisonerrors into the yystate and yychar caused
- // by that token list.
-
- % loadsys package LIMPORT '(' LLITERAL import_package import_there ','
- "unexpected comma during import block",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LFUNC LNAME '(' ')' ';' '{'
- "unexpected semicolon or newline before {",
-
- % loadsys package imports LTYPE LNAME ';'
- "unexpected semicolon or newline in type declaration",
-
- % loadsys package imports LCHAN '}'
- "unexpected } in channel type",
-
- % loadsys package imports LCHAN ')'
- "unexpected ) in channel type",
-
- % loadsys package imports LCHAN ','
- "unexpected comma in channel type",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
- "unexpected semicolon or newline before else",
-
- % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
- "name list not allowed in interface type",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
- "var declaration not allowed in for initializer",
-
- % loadsys package imports LVAR LNAME '[' ']' LNAME '{'
- "unexpected { at end of statement",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
- "unexpected { at end of statement",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
- "argument to go/defer must be function call",
-
- % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
- "need trailing comma before newline in composite literal",
-
- % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
- "nested func not allowed",
-};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
deleted file mode 100644
index 8ca086ee0..000000000
--- a/src/cmd/gc/go.h
+++ /dev/null
@@ -1,1265 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-#undef OAPPEND
-
-// avoid <ctype.h>
-#undef isblank
-#define isblank goisblank
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-#undef BUFSIZ
-
-enum
-{
- NHUNK = 50000,
- BUFSIZ = 8192,
- NSYMB = 500,
- NHASH = 1024,
- STRINGSZ = 200,
- YYMAXDEPTH = 500,
- MAXALIGN = 7,
- UINF = 100,
- HISTSZ = 10,
-
- PRIME1 = 3,
-
- AUNK = 100,
-
- // these values are known by runtime
- AMEM = 0,
- ANOEQ,
- ASTRING,
- AINTER,
- ANILINTER,
- AMEMWORD,
-
- BADWIDTH = -1000000000,
- MAXWIDTH = 1<<30
-};
-
-/*
- * note this is the representation
- * of the compilers string literals,
- * it is not the runtime representation
- */
-typedef struct Strlit Strlit;
-struct Strlit
-{
- int32 len;
- char s[3]; // variable
-};
-
-/*
- * note this is the runtime representation
- * of hashmap iterator. it is probably
- * insafe to use it this way, but it puts
- * all the changes in one place.
- * only flag is referenced from go.
- * actual placement does not matter as long
- * as the size is >= actual size.
- */
-typedef struct Hiter Hiter;
-struct Hiter
-{
- uchar data[8]; // return val from next
- int32 elemsize; // size of elements in table */
- int32 changes; // number of changes observed last time */
- int32 i; // stack pointer in subtable_state */
- uchar last[8]; // last hash value returned */
- uchar h[8]; // the hash table */
- struct
- {
- uchar sub[8]; // pointer into subtable */
- uchar start[8]; // pointer into start of subtable */
- uchar end[8]; // pointer into end of subtable */
- uchar pad[8];
- } sub[4];
-};
-
-enum
-{
- Mpscale = 29, // safely smaller than bits in a long
- Mpprec = 16, // Mpscale*Mpprec is max number of bits
- Mpnorm = Mpprec - 1, // significant words in a normalized float
- Mpbase = 1L << Mpscale,
- Mpsign = Mpbase >> 1,
- Mpmask = Mpbase - 1,
- Mpdebug = 0,
-};
-
-typedef struct Mpint Mpint;
-struct Mpint
-{
- long a[Mpprec];
- uchar neg;
- uchar ovf;
-};
-
-typedef struct Mpflt Mpflt;
-struct Mpflt
-{
- Mpint val;
- short exp;
-};
-
-typedef struct Mpcplx Mpcplx;
-struct Mpcplx
-{
- Mpflt real;
- Mpflt imag;
-};
-
-typedef struct Val Val;
-struct Val
-{
- short ctype;
- union
- {
- short reg; // OREGISTER
- short bval; // bool value CTBOOL
- Mpint* xval; // int CTINT
- Mpflt* fval; // float CTFLT
- Mpcplx* cval; // float CTCPLX
- Strlit* sval; // string CTSTR
- } u;
-};
-
-typedef struct Pkg Pkg;
-typedef struct Sym Sym;
-typedef struct Node Node;
-typedef struct NodeList NodeList;
-typedef struct Type Type;
-typedef struct Label Label;
-
-struct Type
-{
- uchar etype;
- uchar chan;
- uchar recur; // to detect loops
- uchar trecur; // to detect loops
- uchar printed;
- uchar embedded; // TFIELD embedded type
- uchar siggen;
- uchar funarg;
- uchar copyany;
- uchar local; // created in this file
- uchar deferwidth;
- uchar broke;
- uchar isddd; // TFIELD is ... argument
- uchar align;
-
- Node* nod; // canonical OTYPE node
- Type* orig; // original type (type literal or predefined type)
- int lineno;
-
- // TFUNCT
- uchar thistuple;
- uchar outtuple;
- uchar intuple;
- uchar outnamed;
-
- Type* method;
- Type* xmethod;
-
- Sym* sym;
- int32 vargen; // unique name for OTYPE/ONAME
-
- Node* nname;
- vlong argwid;
-
- // most nodes
- Type* type;
- vlong width; // offset in TFIELD, width in all others
-
- // TFIELD
- Type* down; // also used in TMAP
- Strlit* note; // literal string annotation
-
- // TARRAY
- int32 bound; // negative is dynamic array
-
- int32 maplineno; // first use of TFORW as map key
- int32 embedlineno; // first use of TFORW as embedded type
-};
-#define T ((Type*)0)
-
-struct Node
-{
- uchar op;
- uchar ullman; // sethi/ullman number
- uchar addable; // type of addressability - 0 is not addressable
- uchar trecur; // to detect loops
- uchar etype; // op for OASOP, etype for OTYPE, exclam for export
- uchar class; // PPARAM, PAUTO, PEXTERN, etc
- uchar method; // OCALLMETH name
- uchar embedded; // ODCLFIELD embedded type
- uchar colas; // OAS resulting from :=
- uchar diag; // already printed error about this
- uchar noescape; // ONAME never move to heap
- uchar funcdepth;
- uchar builtin; // built-in name, like len or close
- uchar walkdef;
- uchar typecheck;
- uchar local;
- uchar initorder;
- uchar dodata; // compile literal assignment as data statement
- uchar used;
- uchar isddd;
- uchar pun; // don't registerize variable ONAME
- uchar readonly;
- uchar implicit; // don't show in printout
-
- // most nodes
- Node* left;
- Node* right;
- Type* type;
- Type* realtype; // as determined by typecheck
- NodeList* list;
- NodeList* rlist;
- Node* orig; // original form, for printing, and tracking copies of ONAMEs
-
- // for-body
- NodeList* ninit;
- Node* ntest;
- Node* nincr;
- NodeList* nbody;
-
- // if-body
- NodeList* nelse;
-
- // cases
- Node* ncase;
-
- // func
- Node* nname;
- Node* shortname;
- NodeList* enter;
- NodeList* exit;
- NodeList* cvars; // closure params
- NodeList* dcl; // autodcl for this func/closure
-
- // OLITERAL/OREGISTER
- Val val;
-
- // ONAME
- Node* ntype;
- Node* defn;
- Node* pack; // real package for import . names
- Node* curfn; // function for local variables
-
- // ONAME func param with PHEAP
- Node* heapaddr; // temp holding heap address of param
- Node* stackparam; // OPARAM node referring to stack copy of param
- Node* alloc; // allocation call
-
- // ONAME closure param with PPARAMREF
- Node* outer; // outer PPARAMREF in nested closure
- Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
-
- // OPACK
- Pkg* pkg;
-
- Sym* sym; // various
- int32 vargen; // unique name for OTYPE/ONAME
- int32 lineno;
- int32 endlineno;
- vlong xoffset;
- int32 stkdelta; // offset added by stack frame compaction phase.
- int32 ostk;
- int32 iota;
-};
-#define N ((Node*)0)
-EXTERN int32 walkgen;
-
-struct NodeList
-{
- Node* n;
- NodeList* next;
- NodeList* end;
-};
-
-enum
-{
- SymExport = 1<<0,
- SymPackage = 1<<1,
- SymExported = 1<<2,
- SymUniq = 1<<3,
- SymSiggen = 1<<4,
-};
-
-struct Sym
-{
- ushort lexical;
- uchar flags;
- uchar sym; // huffman encoding in object file
- Sym* link;
- int32 npkg; // number of imported packages with this name
-
- // saved and restored by dcopy
- Pkg* pkg;
- char* name; // variable name
- Node* def; // definition: ONAME OTYPE OPACK or OLITERAL
- Label* label; // corresponding label (ephemeral)
- int32 block; // blocknumber to catch redeclaration
- int32 lastlineno; // last declaration for diagnostic
-};
-#define S ((Sym*)0)
-
-EXTERN Sym* dclstack;
-
-struct Pkg
-{
- char* name;
- Strlit* path;
- Sym* pathsym;
- char* prefix;
- Pkg* link;
- char exported; // import line written in export data
- char direct; // imported directly
-};
-
-typedef struct Iter Iter;
-struct Iter
-{
- int done;
- Type* tfunc;
- Type* t;
- Node** an;
- Node* n;
-};
-
-typedef struct Hist Hist;
-struct Hist
-{
- Hist* link;
- char* name;
- int32 line;
- int32 offset;
-};
-#define H ((Hist*)0)
-
-enum
-{
- OXXX,
-
- // names
- ONAME,
- ONONAME,
- OTYPE,
- OPACK,
- OLITERAL,
-
- // exprs
- OADD, OSUB, OOR, OXOR, OADDSTR,
- OADDR,
- OANDAND,
- OAPPEND,
- OARRAY,
- OARRAYBYTESTR, OARRAYRUNESTR,
- OSTRARRAYBYTE, OSTRARRAYRUNE,
- OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
- OBAD,
- OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
- OCAP,
- OCLOSE,
- OCLOSURE,
- OCMPIFACE, OCMPSTR,
- OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
- OCONV, OCONVIFACE, OCONVNOP,
- OCOPY,
- ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
- ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
- ODOTTYPE,
- ODOTTYPE2,
- OEQ, ONE, OLT, OLE, OGE, OGT,
- OIND,
- OINDEX, OINDEXMAP,
- OKEY, OPARAM,
- OLEN,
- OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
- OHMUL, ORRC, OLRC, // high-mul and rotate-carry
- OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
- ONEW,
- ONOT, OCOM, OPLUS, OMINUS,
- OOROR,
- OPANIC, OPRINT, OPRINTN,
- OSEND,
- OSLICE, OSLICEARR, OSLICESTR,
- ORECOVER,
- ORECV,
- ORUNESTR,
- OSELRECV,
- OSELRECV2,
- OIOTA,
- OREAL, OIMAG, OCOMPLEX,
-
- // stmts
- OBLOCK,
- OBREAK,
- OCASE, OXCASE,
- OCONTINUE,
- ODEFER,
- OEMPTY,
- OFALL, OXFALL,
- OFOR,
- OGOTO,
- OIF,
- OLABEL,
- OPROC,
- ORANGE,
- ORETURN,
- OSELECT,
- OSWITCH,
- OTYPESW, // l = r.(type)
-
- // types
- OTCHAN,
- OTMAP,
- OTSTRUCT,
- OTINTER,
- OTFUNC,
- OTARRAY,
- OTPAREN,
-
- // misc
- ODDD,
-
- // for back ends
- OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
-
- OEND,
-};
-enum
-{
- Txxx, // 0
-
- TINT8, TUINT8, // 1
- TINT16, TUINT16,
- TINT32, TUINT32,
- TINT64, TUINT64,
- TINT, TUINT, TUINTPTR,
-
- TCOMPLEX64, // 12
- TCOMPLEX128,
-
- TFLOAT32, // 14
- TFLOAT64,
-
- TBOOL, // 16
-
- TPTR32, TPTR64, // 17
-
- TFUNC, // 19
- TARRAY,
- T_old_DARRAY,
- TSTRUCT, // 22
- TCHAN,
- TMAP,
- TINTER, // 25
- TFORW,
- TFIELD,
- TANY,
- TSTRING,
- TUNSAFEPTR,
-
- // pseudo-types for literals
- TIDEAL, // 31
- TNIL,
- TBLANK,
-
- // pseudo-type for frame layout
- TFUNCARGS,
- TCHANARGS,
- TINTERMETH,
-
- NTYPE,
-};
-enum
-{
- CTxxx,
-
- CTINT,
- CTFLT,
- CTCPLX,
- CTSTR,
- CTBOOL,
- CTNIL,
-};
-
-enum
-{
- /* types of channel */
- /* must match ../../pkg/nreflect/type.go:/Chandir */
- Cxxx,
- Crecv = 1<<0,
- Csend = 1<<1,
- Cboth = Crecv | Csend,
-};
-
-enum
-{
- Pxxx,
-
- PEXTERN, // declaration context
- PAUTO,
- PPARAM,
- PPARAMOUT,
- PPARAMREF, // param passed by reference
- PFUNC,
-
- PHEAP = 1<<7,
-};
-
-enum
-{
- Etop = 1<<1, // evaluated at statement level
- Erv = 1<<2, // evaluated in value context
- Etype = 1<<3,
- Ecall = 1<<4, // call-only expressions are ok
- Efnstruct = 1<<5, // multivalue function returns are ok
- Eiota = 1<<6, // iota is ok
- Easgn = 1<<7, // assigning to expression
- Eindir = 1<<8, // indirecting through expression
- Eaddr = 1<<9, // taking address of expression
- Eproc = 1<<10, // inside a go statement
-};
-
-#define BITS 5
-#define NVAR (BITS*sizeof(uint32)*8)
-
-typedef struct Bits Bits;
-struct Bits
-{
- uint32 b[BITS];
-};
-
-EXTERN Bits zbits;
-
-typedef struct Var Var;
-struct Var
-{
- vlong offset;
- Sym* sym;
- Sym* gotype;
- Node* node;
- int width;
- char name;
- char etype;
- char addr;
-};
-
-EXTERN Var var[NVAR];
-
-typedef struct Typedef Typedef;
-struct Typedef
-{
- char* name;
- int etype;
- int sameas;
-};
-
-extern Typedef typedefs[];
-
-typedef struct Sig Sig;
-struct Sig
-{
- char* name;
- Pkg* pkg;
- Sym* isym;
- Sym* tsym;
- Type* type;
- Type* mtype;
- int32 offset;
- Sig* link;
-};
-
-typedef struct Io Io;
-struct Io
-{
- char* infile;
- Biobuf* bin;
- int32 ilineno;
- int nlsemi;
- int eofnl;
- int peekc;
- int peekc1; // second peekc for ...
- char* cp; // used for content when bin==nil
- int importsafe;
-};
-
-typedef struct Dlist Dlist;
-struct Dlist
-{
- Type* field;
-};
-
-typedef struct Idir Idir;
-struct Idir
-{
- Idir* link;
- char* dir;
-};
-
-/*
- * argument passing to/from
- * smagic and umagic
- */
-typedef struct Magic Magic;
-struct Magic
-{
- int w; // input for both - width
- int s; // output for both - shift
- int bad; // output for both - unexpected failure
-
- // magic multiplier for signed literal divisors
- int64 sd; // input - literal divisor
- int64 sm; // output - multiplier
-
- // magic multiplier for unsigned literal divisors
- uint64 ud; // input - literal divisor
- uint64 um; // output - multiplier
- int ua; // output - adder
-};
-
-typedef struct Prog Prog;
-
-struct Label
-{
- uchar used;
- Sym* sym;
- Node* def;
- NodeList* use;
- Label* link;
-
- // for use during gen
- Prog* gotopc; // pointer to unresolved gotos
- Prog* labelpc; // pointer to code
- Prog* breakpc; // pointer to code
- Prog* continpc; // pointer to code
-};
-#define L ((Label*)0)
-
-/*
- * note this is the runtime representation
- * of the compilers arrays.
- *
- * typedef struct
- * { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * uchar cap[4]; // allocated number of elements
- * } Array;
- */
-EXTERN int Array_array; // runtime offsetof(Array,array) - same for String
-EXTERN int Array_nel; // runtime offsetof(Array,nel) - same for String
-EXTERN int Array_cap; // runtime offsetof(Array,cap)
-EXTERN int sizeof_Array; // runtime sizeof(Array)
-
-
-/*
- * note this is the runtime representation
- * of the compilers strings.
- *
- * typedef struct
- * { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * } String;
- */
-EXTERN int sizeof_String; // runtime sizeof(String)
-
-EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
-
-EXTERN Io curio;
-EXTERN Io pushedio;
-EXTERN int32 lexlineno;
-EXTERN int32 lineno;
-EXTERN int32 prevlineno;
-EXTERN char* pathname;
-EXTERN Hist* hist;
-EXTERN Hist* ehist;
-
-EXTERN char* infile;
-EXTERN char* outfile;
-EXTERN Biobuf* bout;
-EXTERN int nerrors;
-EXTERN int nsavederrors;
-EXTERN int nsyntaxerrors;
-EXTERN int safemode;
-EXTERN char namebuf[NSYMB];
-EXTERN char lexbuf[NSYMB];
-EXTERN char debug[256];
-EXTERN Sym* hash[NHASH];
-EXTERN Sym* importmyname; // my name for package
-EXTERN Pkg* localpkg; // package being compiled
-EXTERN Pkg* importpkg; // package being imported
-EXTERN Pkg* structpkg; // package that declared struct, during import
-EXTERN Pkg* builtinpkg; // fake package for builtins
-EXTERN Pkg* gostringpkg; // fake pkg for Go strings
-EXTERN Pkg* runtimepkg; // package runtime
-EXTERN Pkg* stringpkg; // fake package for C strings
-EXTERN Pkg* typepkg; // fake package for runtime type info
-EXTERN Pkg* unsafepkg; // package unsafe
-EXTERN Pkg* phash[128];
-EXTERN int tptr; // either TPTR32 or TPTR64
-extern char* runtimeimport;
-extern char* unsafeimport;
-EXTERN Idir* idirs;
-
-EXTERN Type* types[NTYPE];
-EXTERN Type* idealstring;
-EXTERN Type* idealbool;
-EXTERN uchar simtype[NTYPE];
-EXTERN uchar isptr[NTYPE];
-EXTERN uchar isforw[NTYPE];
-EXTERN uchar isint[NTYPE];
-EXTERN uchar isfloat[NTYPE];
-EXTERN uchar iscomplex[NTYPE];
-EXTERN uchar issigned[NTYPE];
-EXTERN uchar issimple[NTYPE];
-
-EXTERN uchar okforeq[NTYPE];
-EXTERN uchar okforadd[NTYPE];
-EXTERN uchar okforand[NTYPE];
-EXTERN uchar okfornone[NTYPE];
-EXTERN uchar okforcmp[NTYPE];
-EXTERN uchar okforbool[NTYPE];
-EXTERN uchar okforcap[NTYPE];
-EXTERN uchar okforlen[NTYPE];
-EXTERN uchar okforarith[NTYPE];
-EXTERN uchar okforconst[NTYPE];
-EXTERN uchar* okfor[OEND];
-EXTERN uchar iscmp[OEND];
-
-EXTERN Mpint* minintval[NTYPE];
-EXTERN Mpint* maxintval[NTYPE];
-EXTERN Mpflt* minfltval[NTYPE];
-EXTERN Mpflt* maxfltval[NTYPE];
-
-EXTERN NodeList* xtop;
-EXTERN NodeList* externdcl;
-EXTERN NodeList* closures;
-EXTERN NodeList* exportlist;
-EXTERN NodeList* typelist;
-EXTERN int dclcontext; // PEXTERN/PAUTO
-EXTERN int incannedimport;
-EXTERN int statuniqgen; // name generator for static temps
-EXTERN int loophack;
-
-EXTERN int32 iota;
-EXTERN NodeList* lastconst;
-EXTERN Node* lasttype;
-EXTERN int32 maxarg;
-EXTERN int32 stksize; // stack size for current frame
-EXTERN int32 blockgen; // max block number
-EXTERN int32 block; // current block number
-EXTERN int hasdefer; // flag that curfn has defer statetment
-
-EXTERN Node* curfn;
-
-EXTERN int widthptr;
-
-EXTERN Node* typesw;
-EXTERN Node* nblank;
-
-extern int thechar;
-extern char* thestring;
-EXTERN char* hunk;
-EXTERN int32 nhunk;
-EXTERN int32 thunk;
-
-EXTERN int exporting;
-EXTERN int erroring;
-EXTERN int noargnames;
-
-EXTERN int funcdepth;
-EXTERN int typecheckok;
-EXTERN int packagequotes;
-EXTERN int longsymnames;
-EXTERN int compiling_runtime;
-
-/*
- * y.tab.c
- */
-int yyparse(void);
-
-/*
- * align.c
- */
-int argsize(Type *t);
-void checkwidth(Type *t);
-void defercheckwidth(void);
-void dowidth(Type *t);
-void resumecheckwidth(void);
-uint32 rnd(uint32 o, uint32 r);
-void typeinit(void);
-
-/*
- * bits.c
- */
-int Qconv(Fmt *fp);
-Bits band(Bits a, Bits b);
-int bany(Bits *a);
-int beq(Bits a, Bits b);
-int bitno(int32 b);
-Bits blsh(uint n);
-Bits bnot(Bits a);
-int bnum(Bits a);
-Bits bor(Bits a, Bits b);
-int bset(Bits a, uint n);
-
-/*
- * closure.c
- */
-Node* closurebody(NodeList *body);
-void closurehdr(Node *ntype);
-void typecheckclosure(Node *func, int top);
-Node* walkclosure(Node *func, NodeList **init);
-void walkcallclosure(Node *n, NodeList **init);
-
-/*
- * const.c
- */
-int cmpslit(Node *l, Node *r);
-int consttype(Node *n);
-void convconst(Node *con, Type *t, Val *val);
-void convlit(Node **np, Type *t);
-void convlit1(Node **np, Type *t, int explicit);
-void defaultlit(Node **np, Type *t);
-void defaultlit2(Node **lp, Node **rp, int force);
-void evconst(Node *n);
-int isconst(Node *n, int ct);
-Node* nodcplxlit(Val r, Val i);
-Node* nodlit(Val v);
-long nonnegconst(Node *n);
-void overflow(Val v, Type *t);
-int smallintconst(Node *n);
-Val toint(Val v);
-Mpflt* truncfltlit(Mpflt *oldv, Type *t);
-
-/*
- * cplx.c
- */
-void complexadd(int op, Node *nl, Node *nr, Node *res);
-void complexbool(int op, Node *nl, Node *nr, int true, Prog *to);
-void complexgen(Node *n, Node *res);
-void complexminus(Node *nl, Node *res);
-void complexmove(Node *f, Node *t);
-void complexmul(Node *nl, Node *nr, Node *res);
-int complexop(Node *n, Node *res);
-void nodfconst(Node *n, Type *t, Mpflt* fval);
-
-/*
- * dcl.c
- */
-void addmethod(Sym *sf, Type *t, int local);
-void addvar(Node *n, Type *t, int ctxt);
-NodeList* checkarglist(NodeList *all, int input);
-Node* colas(NodeList *left, NodeList *right);
-void colasdefn(NodeList *left, Node *defn);
-NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
-Node* dclname(Sym *s);
-void declare(Node *n, int ctxt);
-Type* dostruct(NodeList *l, int et);
-void dumpdcl(char *st);
-Node* embedded(Sym *s);
-Node* fakethis(void);
-void funcbody(Node *n);
-void funccompile(Node *n, int isclosure);
-void funchdr(Node *n);
-Type* functype(Node *this, NodeList *in, NodeList *out);
-void ifacedcl(Node *n);
-int isifacemethod(Type *f);
-void markdcl(void);
-Node* methodname(Node *n, Type *t);
-Node* methodname1(Node *n, Node *t);
-Sym* methodsym(Sym *nsym, Type *t0, int iface);
-Node* newname(Sym *s);
-Type* newtype(Sym *s);
-Node* oldname(Sym *s);
-void popdcl(void);
-void poptodcl(void);
-void redeclare(Sym *s, char *where);
-void testdclstack(void);
-Node* typedcl0(Sym *s);
-Node* typedcl1(Node *n, Node *t, int local);
-void typedcl2(Type *pt, Type *t);
-Node* typenod(Type *t);
-NodeList* variter(NodeList *vl, Node *t, NodeList *el);
-
-/*
- * export.c
- */
-void autoexport(Node *n, int ctxt);
-void dumpexport(void);
-int exportname(char *s);
-void exportsym(Node *n);
-void importconst(Sym *s, Type *t, Node *n);
-void importmethod(Sym *s, Type *t);
-Sym* importsym(Sym *s, int op);
-void importtype(Type *pt, Type *t);
-void importvar(Sym *s, Type *t, int ctxt);
-Type* pkgtype(Sym *s);
-
-/*
- * gen.c
- */
-void allocparams(void);
-void cgen_as(Node *nl, Node *nr);
-void cgen_callmeth(Node *n, int proc);
-void clearlabels(void);
-void checklabels(void);
-int dotoffset(Node *n, int *oary, Node **nn);
-void gen(Node *n);
-void genlist(NodeList *l);
-Node* sysfunc(char *name);
-void tempname(Node *n, Type *t);
-
-/*
- * init.c
- */
-void fninit(NodeList *n);
-Node* renameinit(Node *n);
-
-/*
- * lex.c
- */
-void cannedimports(char *file, char *cp);
-void importfile(Val *f, int line);
-char* lexname(int lex);
-void mkpackage(char* pkgname);
-void unimportfile(void);
-int32 yylex(void);
-extern int windows;
-extern int yylast;
-extern int yyprev;
-
-/*
- * mparith1.c
- */
-int Bconv(Fmt *fp);
-int Fconv(Fmt *fp);
-void mpaddcfix(Mpint *a, vlong c);
-void mpaddcflt(Mpflt *a, double c);
-void mpatofix(Mpint *a, char *as);
-void mpatoflt(Mpflt *a, char *as);
-int mpcmpfixc(Mpint *b, vlong c);
-int mpcmpfixfix(Mpint *a, Mpint *b);
-int mpcmpfixflt(Mpint *a, Mpflt *b);
-int mpcmpfltc(Mpflt *b, double c);
-int mpcmpfltfix(Mpflt *a, Mpint *b);
-int mpcmpfltflt(Mpflt *a, Mpflt *b);
-void mpcomfix(Mpint *a);
-void mpdivfixfix(Mpint *a, Mpint *b);
-void mpmodfixfix(Mpint *a, Mpint *b);
-void mpmovefixfix(Mpint *a, Mpint *b);
-void mpmovefixflt(Mpflt *a, Mpint *b);
-int mpmovefltfix(Mpint *a, Mpflt *b);
-void mpmovefltflt(Mpflt *a, Mpflt *b);
-void mpmulcfix(Mpint *a, vlong c);
-void mpmulcflt(Mpflt *a, double c);
-void mpsubfixfix(Mpint *a, Mpint *b);
-void mpsubfltflt(Mpflt *a, Mpflt *b);
-
-/*
- * mparith2.c
- */
-void mpaddfixfix(Mpint *a, Mpint *b);
-void mpandfixfix(Mpint *a, Mpint *b);
-void mpandnotfixfix(Mpint *a, Mpint *b);
-void mpdivfract(Mpint *a, Mpint *b);
-void mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d);
-vlong mpgetfix(Mpint *a);
-void mplshfixfix(Mpint *a, Mpint *b);
-void mpmovecfix(Mpint *a, vlong c);
-void mpmulfixfix(Mpint *a, Mpint *b);
-void mpmulfract(Mpint *a, Mpint *b);
-void mpnegfix(Mpint *a);
-void mporfixfix(Mpint *a, Mpint *b);
-void mprshfixfix(Mpint *a, Mpint *b);
-void mpshiftfix(Mpint *a, int s);
-int mptestfix(Mpint *a);
-void mpxorfixfix(Mpint *a, Mpint *b);
-
-/*
- * mparith3.c
- */
-void mpaddfltflt(Mpflt *a, Mpflt *b);
-void mpdivfltflt(Mpflt *a, Mpflt *b);
-double mpgetflt(Mpflt *a);
-void mpmovecflt(Mpflt *a, double c);
-void mpmulfltflt(Mpflt *a, Mpflt *b);
-void mpnegflt(Mpflt *a);
-void mpnorm(Mpflt *a);
-int mptestflt(Mpflt *a);
-int sigfig(Mpflt *a);
-
-/*
- * obj.c
- */
-void Bputname(Biobuf *b, Sym *s);
-int duint16(Sym *s, int off, uint16 v);
-int duint32(Sym *s, int off, uint32 v);
-int duint64(Sym *s, int off, uint64 v);
-int duint8(Sym *s, int off, uint8 v);
-int duintptr(Sym *s, int off, uint64 v);
-int dsname(Sym *s, int off, char *dat, int ndat);
-void dumpobj(void);
-void ieeedtod(uint64 *ieee, double native);
-Sym* stringsym(char*, int);
-
-/*
- * print.c
- */
-void exprfmt(Fmt *f, Node *n, int prec);
-void exprlistfmt(Fmt *f, NodeList *l);
-
-/*
- * range.c
- */
-void typecheckrange(Node *n);
-void walkrange(Node *n);
-
-/*
- * reflect.c
- */
-void dumptypestructs(void);
-Type* methodfunc(Type *f, Type*);
-Node* typename(Type *t);
-Sym* typesym(Type *t);
-
-/*
- * select.c
- */
-void typecheckselect(Node *sel);
-void walkselect(Node *sel);
-
-/*
- * sinit.c
- */
-void anylit(int, Node *n, Node *var, NodeList **init);
-int gen_as_init(Node *n);
-NodeList* initfix(NodeList *l);
-int oaslit(Node *n, NodeList **init);
-int stataddr(Node *nam, Node *n);
-
-/*
- * subr.c
- */
-int Econv(Fmt *fp);
-int Jconv(Fmt *fp);
-int Lconv(Fmt *fp);
-int Nconv(Fmt *fp);
-int Oconv(Fmt *fp);
-int Sconv(Fmt *fp);
-int Tconv(Fmt *fp);
-int Tpretty(Fmt *fp, Type *t);
-int Zconv(Fmt *fp);
-Node* adddot(Node *n);
-int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
-Type* aindex(Node *b, Type *t);
-int algtype(Type *t);
-void argtype(Node *on, Type *t);
-Node* assignconv(Node *n, Type *t, char *context);
-int assignop(Type *src, Type *dst, char **why);
-void badtype(int o, Type *tl, Type *tr);
-int brcom(int a);
-int brrev(int a);
-NodeList* concat(NodeList *a, NodeList *b);
-int convertop(Type *src, Type *dst, char **why);
-int count(NodeList *l);
-int cplxsubtype(int et);
-void dump(char *s, Node *n);
-void dumplist(char *s, NodeList *l);
-int eqtype(Type *t1, Type *t2);
-int eqtypenoname(Type *t1, Type *t2);
-void errorexit(void);
-void expandmeth(Sym *s, Type *t);
-void fatal(char *fmt, ...);
-void flusherrors(void);
-void frame(int context);
-Type* funcfirst(Iter *s, Type *t);
-Type* funcnext(Iter *s);
-void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
-Type** getinarg(Type *t);
-Type* getinargx(Type *t);
-Type** getoutarg(Type *t);
-Type* getoutargx(Type *t);
-Type** getthis(Type *t);
-Type* getthisx(Type *t);
-int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
-void importdot(Pkg *opkg, Node *pack);
-int is64(Type *t);
-int isblank(Node *n);
-int isfixedarray(Type *t);
-int isideal(Type *t);
-int isinter(Type *t);
-int isnil(Node *n);
-int isnilinter(Type *t);
-int isptrto(Type *t, int et);
-int isselect(Node *n);
-int isslice(Type *t);
-int istype(Type *t, int et);
-void linehist(char *file, int32 off, int relative);
-NodeList* list(NodeList *l, Node *n);
-NodeList* list1(Node *n);
-void listsort(NodeList**, int(*f)(Node*, Node*));
-Node* liststmt(NodeList *l);
-NodeList* listtreecopy(NodeList *l);
-Sym* lookup(char *name);
-void* mal(int32 n);
-Type* maptype(Type *key, Type *val);
-Type* methtype(Type *t);
-Pkg* mkpkg(Strlit *path);
-Sym* ngotype(Node *n);
-int noconv(Type *t1, Type *t2);
-Node* nod(int op, Node *nleft, Node *nright);
-Node* nodbool(int b);
-void nodconst(Node *n, Type *t, int64 v);
-Node* nodintconst(int64 v);
-Node* nodfltconst(Mpflt *v);
-Node* nodnil(void);
-int parserline(void);
-Sym* pkglookup(char *name, Pkg *pkg);
-int powtwo(Node *n);
-Type* ptrto(Type *t);
-void* remal(void *p, int32 on, int32 n);
-Sym* restrictlookup(char *name, Pkg *pkg);
-Node* safeexpr(Node *n, NodeList **init);
-void saveerrors(void);
-Node* cheapexpr(Node *n, NodeList **init);
-int32 setlineno(Node *n);
-void setmaxarg(Type *t);
-Type* shallow(Type *t);
-int simsimtype(Type *t);
-void smagic(Magic *m);
-Type* sortinter(Type *t);
-uint32 stringhash(char *p);
-Strlit* strlit(char *s);
-int structcount(Type *t);
-Type* structfirst(Iter *s, Type **nn);
-Type* structnext(Iter *s);
-Node* syslook(char *name, int copy);
-Type* tounsigned(Type *t);
-Node* treecopy(Node *n);
-Type* typ(int et);
-uint32 typehash(Type *t);
-void ullmancalc(Node *n);
-void umagic(Magic *m);
-void warn(char *fmt, ...);
-void yyerror(char *fmt, ...);
-void yyerrorl(int line, char *fmt, ...);
-
-/*
- * swt.c
- */
-void typecheckswitch(Node *n);
-void walkswitch(Node *sw);
-
-/*
- * typecheck.c
- */
-int exportassignok(Type *t, char *desc);
-int islvalue(Node *n);
-Node* typecheck(Node **np, int top);
-void typechecklist(NodeList *l, int top);
-Node* typecheckdef(Node *n);
-void resumetypecopy(void);
-void copytype(Node *n, Type *t);
-void defertypecopy(Node *n, Type *t);
-void queuemethod(Node *n);
-
-/*
- * unsafe.c
- */
-Node* unsafenmagic(Node *n);
-
-/*
- * walk.c
- */
-Node* callnew(Type *t);
-Node* chanfn(char *name, int n, Type *t);
-Node* mkcall(char *name, Type *t, NodeList **init, ...);
-Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
-int vmatch1(Node *l, Node *r);
-void walk(Node *fn);
-void walkexpr(Node **np, NodeList **init);
-void walkexprlist(NodeList *l, NodeList **init);
-void walkexprlistsafe(NodeList *l, NodeList **init);
-void walkstmt(Node **np);
-void walkstmtlist(NodeList *l);
-
-/*
- * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
- */
-#define P ((Prog*)0)
-
-typedef struct Plist Plist;
-struct Plist
-{
- Node* name;
- Prog* firstpc;
- int recur;
- Plist* link;
-};
-
-EXTERN Plist* plist;
-EXTERN Plist* plast;
-
-EXTERN Prog* continpc;
-EXTERN Prog* breakpc;
-EXTERN Prog* pc;
-EXTERN Prog* firstpc;
-EXTERN Prog* retpc;
-
-EXTERN Node* nodfp;
-
-int anyregalloc(void);
-void betypeinit(void);
-void bgen(Node *n, int true, Prog *to);
-void cgen(Node*, Node*);
-void cgen_asop(Node *n);
-void cgen_call(Node *n, int proc);
-void cgen_callinter(Node *n, Node *res, int proc);
-void cgen_ret(Node *n);
-void clearfat(Node *n);
-void compile(Node*);
-void defframe(Prog*);
-int dgostringptr(Sym*, int off, char *str);
-int dgostrlitptr(Sym*, int off, Strlit*);
-int dstringptr(Sym *s, int off, char *str);
-int dsymptr(Sym *s, int off, Sym *x, int xoff);
-int duintxx(Sym *s, int off, uint64 v, int wid);
-void dumpdata(void);
-void dumpfuncs(void);
-void fixautoused(Prog*);
-void gdata(Node*, Node*, int);
-void gdatacomplex(Node*, Mpcplx*);
-void gdatastring(Node*, Strlit*);
-void genembedtramp(Type*, Type*, Sym*, int iface);
-void ggloblnod(Node *nam, int32 width);
-void ggloblsym(Sym *s, int32 width, int dupok);
-Prog* gjmp(Prog*);
-void gused(Node*);
-int isfat(Type*);
-void markautoused(Prog*);
-Plist* newplist(void);
-Node* nodarg(Type*, int);
-void nopout(Prog*);
-void patch(Prog*, Prog*);
-Prog* unpatch(Prog*);
-void zfile(Biobuf *b, char *p, int n);
-void zhist(Biobuf *b, int line, vlong offset);
-void zname(Biobuf *b, Sym *s, int t);
-void data(void);
-void text(void);
-
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
deleted file mode 100644
index 01a4e822f..000000000
--- a/src/cmd/gc/go.y
+++ /dev/null
@@ -1,1966 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * Go language grammar.
- *
- * The Go semicolon rules are:
- *
- * 1. all statements and declarations are terminated by semicolons.
- * 2. semicolons can be omitted before a closing ) or }.
- * 3. semicolons are inserted by the lexer before a newline
- * following a specific list of tokens.
- *
- * Rules #1 and #2 are accomplished by writing the lists as
- * semicolon-separated lists with an optional trailing semicolon.
- * Rule #3 is implemented in yylex.
- */
-
-%{
-#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
-#include "go.h"
-
-static void fixlbrace(int);
-%}
-%union {
- Node* node;
- NodeList* list;
- Type* type;
- Sym* sym;
- struct Val val;
- int lint;
-}
-
-// |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'
-
-%token <val> LLITERAL
-%token <lint> LASOP
-%token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD
-%token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
-%token <sym> LIF LIMPORT LINTERFACE LMAP LNAME
-%token <sym> LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
-%token <sym> LTYPE LVAR
-
-%token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
-%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
-
-%type <lint> lbrace import_here
-%type <sym> sym packname
-%type <val> oliteral
-
-%type <node> stmt ntype
-%type <node> arg_type
-%type <node> case caseblock
-%type <node> compound_stmt dotname embed expr complitexpr
-%type <node> expr_or_type
-%type <node> fndcl fnliteral
-%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt
-%type <node> interfacedcl keyval labelname name
-%type <node> name_or_type non_expr_type
-%type <node> new_name dcl_name oexpr typedclname
-%type <node> onew_name
-%type <node> osimple_stmt pexpr pexpr_no_paren
-%type <node> pseudocall range_stmt select_stmt
-%type <node> simple_stmt
-%type <node> switch_stmt uexpr
-%type <node> xfndcl typedcl
-
-%type <list> xdcl fnbody fnres loop_body dcl_name_list
-%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
-%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
-%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
-%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
-
-%type <node> convtype comptype dotdotdot
-%type <node> indcl interfacetype structtype ptrtype
-%type <node> recvchantype non_recvchantype othertype fnret_type fntype
-
-%type <val> hidden_tag
-
-%type <sym> hidden_importsym hidden_pkg_importsym
-
-%type <node> hidden_constant hidden_literal hidden_dcl
-%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym
-
-%type <list> hidden_funres
-%type <list> ohidden_funres
-%type <list> hidden_funarg_list ohidden_funarg_list
-%type <list> hidden_interfacedcl_list ohidden_interfacedcl_list
-%type <list> hidden_structdcl_list ohidden_structdcl_list
-
-%type <type> hidden_type hidden_type_misc hidden_pkgtype
-%type <type> hidden_type_func
-%type <type> hidden_type_recv_chan hidden_type_non_recv_chan
-
-%left LCOMM /* outside the usual hierarchy; here for good error messages */
-
-%left LOROR
-%left LANDAND
-%left LEQ LNE LLE LGE LLT LGT
-%left '+' '-' '|' '^'
-%left '*' '/' '%' '&' LLSH LRSH LANDNOT
-
-/*
- * manual override of shift/reduce conflicts.
- * the general form is that we assign a precedence
- * to the token being shifted and then introduce
- * NotToken with lower precedence or PreferToToken with higher
- * and annotate the reducing rule accordingly.
- */
-%left NotPackage
-%left LPACKAGE
-
-%left NotParen
-%left '('
-
-%left ')'
-%left PreferToRightParen
-
-%error-verbose
-
-%%
-file:
- loadsys
- package
- imports
- xdcl_list
- {
- xtop = concat(xtop, $4);
- }
-
-package:
- %prec NotPackage
- {
- prevlineno = lineno;
- yyerror("package statement must be first");
- flusherrors();
- mkpackage("main");
- }
-| LPACKAGE sym ';'
- {
- mkpackage($2->name);
- }
-
-/*
- * this loads the definitions for the low-level runtime functions,
- * so that the compiler can generate calls to them,
- * but does not make the name "runtime" visible as a package.
- */
-loadsys:
- {
- importpkg = runtimepkg;
-
- if(debug['A'])
- cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
- else
- cannedimports("runtime.builtin", runtimeimport);
- curio.importsafe = 1;
- }
- import_package
- import_there
- {
- importpkg = nil;
- }
-
-imports:
-| imports import ';'
-
-import:
- LIMPORT import_stmt
-| LIMPORT '(' import_stmt_list osemi ')'
-| LIMPORT '(' ')'
-
-import_stmt:
- import_here import_package import_there
- {
- Pkg *ipkg;
- Sym *my;
- Node *pack;
-
- ipkg = importpkg;
- my = importmyname;
- importpkg = nil;
- importmyname = S;
-
- if(my == nil)
- my = lookup(ipkg->name);
-
- pack = nod(OPACK, N, N);
- pack->sym = my;
- pack->pkg = ipkg;
- pack->lineno = $1;
-
- if(my->name[0] == '.') {
- importdot(ipkg, pack);
- break;
- }
- if(my->name[0] == '_' && my->name[1] == '\0')
- break;
- if(my->def) {
- lineno = $1;
- redeclare(my, "as imported package name");
- }
- my->def = pack;
- my->lastlineno = $1;
- my->block = 1; // at top level
- }
-
-
-import_stmt_list:
- import_stmt
-| import_stmt_list ';' import_stmt
-
-import_here:
- LLITERAL
- {
- // import with original name
- $$ = parserline();
- importmyname = S;
- importfile(&$1, $$);
- }
-| sym LLITERAL
- {
- // import with given name
- $$ = parserline();
- importmyname = $1;
- importfile(&$2, $$);
- }
-| '.' LLITERAL
- {
- // import into my name space
- $$ = parserline();
- importmyname = lookup(".");
- importfile(&$2, $$);
- }
-
-import_package:
- LPACKAGE sym import_safety ';'
- {
- if(importpkg->name == nil) {
- importpkg->name = $2->name;
- pkglookup($2->name, nil)->npkg++;
- } else if(strcmp(importpkg->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path);
- importpkg->direct = 1;
-
- if(safemode && !curio.importsafe)
- yyerror("cannot import unsafe package %Z", importpkg->path);
- }
-
-import_safety:
-| LNAME
- {
- if(strcmp($1->name, "safe") == 0)
- curio.importsafe = 1;
- }
-
-import_there:
- {
- defercheckwidth();
- }
- hidden_import_list '$' '$'
- {
- resumecheckwidth();
- unimportfile();
- }
-
-/*
- * declarations
- */
-xdcl:
- {
- yyerror("empty top-level declaration");
- $$ = nil;
- }
-| common_dcl
-| xfndcl
- {
- $$ = list1($1);
- }
-| non_dcl_stmt
- {
- yyerror("non-declaration statement outside function body");
- $$ = nil;
- }
-| error
- {
- $$ = nil;
- }
-
-common_dcl:
- LVAR vardcl
- {
- $$ = $2;
- }
-| LVAR '(' vardcl_list osemi ')'
- {
- $$ = $3;
- }
-| LVAR '(' ')'
- {
- $$ = nil;
- }
-| lconst constdcl
- {
- $$ = $2;
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' constdcl osemi ')'
- {
- $$ = $3;
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' constdcl ';' constdcl_list osemi ')'
- {
- $$ = concat($3, $5);
- iota = -100000;
- lastconst = nil;
- }
-| lconst '(' ')'
- {
- $$ = nil;
- iota = -100000;
- }
-| LTYPE typedcl
- {
- $$ = list1($2);
- }
-| LTYPE '(' typedcl_list osemi ')'
- {
- $$ = $3;
- }
-| LTYPE '(' ')'
- {
- $$ = nil;
- }
-
-lconst:
- LCONST
- {
- iota = 0;
- }
-
-vardcl:
- dcl_name_list ntype
- {
- $$ = variter($1, $2, nil);
- }
-| dcl_name_list ntype '=' expr_list
- {
- $$ = variter($1, $2, $4);
- }
-| dcl_name_list '=' expr_list
- {
- $$ = variter($1, nil, $3);
- }
-
-constdcl:
- dcl_name_list ntype '=' expr_list
- {
- $$ = constiter($1, $2, $4);
- }
-| dcl_name_list '=' expr_list
- {
- $$ = constiter($1, N, $3);
- }
-
-constdcl1:
- constdcl
-| dcl_name_list ntype
- {
- $$ = constiter($1, $2, nil);
- }
-| dcl_name_list
- {
- $$ = constiter($1, N, nil);
- }
-
-typedclname:
- sym
- {
- // different from dclname because the name
- // becomes visible right here, not at the end
- // of the declaration.
- $$ = typedcl0($1);
- }
-
-typedcl:
- typedclname ntype
- {
- $$ = typedcl1($1, $2, 1);
- }
-
-simple_stmt:
- expr
- {
- $$ = $1;
- }
-| expr LASOP expr
- {
- $$ = nod(OASOP, $1, $3);
- $$->etype = $2; // rathole to pass opcode
- }
-| expr_list '=' expr_list
- {
- if($1->next == nil && $3->next == nil) {
- // simple
- $$ = nod(OAS, $1->n, $3->n);
- break;
- }
- // multiple
- $$ = nod(OAS2, N, N);
- $$->list = $1;
- $$->rlist = $3;
- }
-| expr_list LCOLAS expr_list
- {
- if($3->n->op == OTYPESW) {
- Node *n;
-
- n = N;
- if($3->next != nil)
- yyerror("expr.(type) must be alone in list");
- if($1->next != nil)
- yyerror("argument count mismatch: %d = %d", count($1), 1);
- else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
- yyerror("invalid variable name %#N in type switch", $1->n);
- else
- n = $1->n;
- $$ = nod(OTYPESW, n, $3->n->right);
- break;
- }
- $$ = colas($1, $3);
- }
-| expr LINC
- {
- $$ = nod(OASOP, $1, nodintconst(1));
- $$->etype = OADD;
- }
-| expr LDEC
- {
- $$ = nod(OASOP, $1, nodintconst(1));
- $$->etype = OSUB;
- }
-
-case:
- LCASE expr_or_type_list ':'
- {
- Node *n;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- $$->list = $2;
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- n = newname(n->sym);
- n->used = 1; // TODO(rsc): better job here
- declare(n, dclcontext);
- $$->nname = n;
- }
- break;
- }
-| LCASE expr_or_type_list '=' expr ':'
- {
- Node *n;
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- if($2->next == nil)
- n = nod(OAS, $2->n, $4);
- else {
- n = nod(OAS2, N, N);
- n->list = $2;
- n->rlist = list1($4);
- }
- $$->list = list1(n);
- }
-| LCASE expr_or_type_list LCOLAS expr ':'
- {
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl();
- $$ = nod(OXCASE, N, N);
- $$->list = list1(colas($2, list1($4)));
- }
-| LDEFAULT ':'
- {
- Node *n;
-
- markdcl();
- $$ = nod(OXCASE, N, N);
- if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
- // type switch - declare variable
- n = newname(n->sym);
- n->used = 1; // TODO(rsc): better job here
- declare(n, dclcontext);
- $$->nname = n;
- }
- }
-
-compound_stmt:
- '{'
- {
- markdcl();
- }
- stmt_list '}'
- {
- $$ = liststmt($3);
- popdcl();
- }
-
-caseblock:
- case
- {
- // If the last token read by the lexer was consumed
- // as part of the case, clear it (parser has cleared yychar).
- // If the last token read by the lexer was the lookahead
- // leave it alone (parser has it cached in yychar).
- // This is so that the stmt_list action doesn't look at
- // the case tokens if the stmt_list is empty.
- yylast = yychar;
- }
- stmt_list
- {
- int last;
-
- // This is the only place in the language where a statement
- // list is not allowed to drop the final semicolon, because
- // it's the only place where a statement list is not followed
- // by a closing brace. Handle the error for pedantry.
-
- // Find the final token of the statement list.
- // yylast is lookahead; yyprev is last of stmt_list
- last = yyprev;
-
- if(last > 0 && last != ';' && yychar != '}')
- yyerror("missing statement after label");
- $$ = $1;
- $$->nbody = $3;
- popdcl();
- }
-
-caseblock_list:
- {
- $$ = nil;
- }
-| caseblock_list caseblock
- {
- $$ = list($1, $2);
- }
-
-loop_body:
- LBODY
- {
- markdcl();
- }
- stmt_list '}'
- {
- $$ = $3;
- popdcl();
- }
-
-range_stmt:
- expr_list '=' LRANGE expr
- {
- $$ = nod(ORANGE, N, $4);
- $$->list = $1;
- $$->etype = 0; // := flag
- }
-| expr_list LCOLAS LRANGE expr
- {
- $$ = nod(ORANGE, N, $4);
- $$->list = $1;
- $$->colas = 1;
- colasdefn($1, $$);
- }
-
-for_header:
- osimple_stmt ';' osimple_stmt ';' osimple_stmt
- {
- // init ; test ; incr
- if($5 != N && $5->colas != 0)
- yyerror("cannot declare in the for-increment");
- $$ = nod(OFOR, N, N);
- if($1 != N)
- $$->ninit = list1($1);
- $$->ntest = $3;
- $$->nincr = $5;
- }
-| osimple_stmt
- {
- // normal test
- $$ = nod(OFOR, N, N);
- $$->ntest = $1;
- }
-| range_stmt
-
-for_body:
- for_header loop_body
- {
- $$ = $1;
- $$->nbody = concat($$->nbody, $2);
- }
-
-for_stmt:
- LFOR
- {
- markdcl();
- }
- for_body
- {
- $$ = $3;
- popdcl();
- }
-
-if_header:
- osimple_stmt
- {
- // test
- $$ = nod(OIF, N, N);
- $$->ntest = $1;
- }
-| osimple_stmt ';' osimple_stmt
- {
- // init ; test
- $$ = nod(OIF, N, N);
- if($1 != N)
- $$->ninit = list1($1);
- $$->ntest = $3;
- }
-
-if_stmt:
- LIF
- {
- markdcl();
- }
- if_header
- {
- if($3->ntest == N)
- yyerror("missing condition in if statement");
- }
- loop_body
- {
- $$ = $3;
- $$->nbody = $5;
- // no popdcl; maybe there's an LELSE
- }
-
-switch_stmt:
- LSWITCH
- {
- markdcl();
- }
- if_header
- {
- Node *n;
- n = $3->ntest;
- if(n != N && n->op != OTYPESW)
- n = N;
- typesw = nod(OXXX, typesw, n);
- }
- LBODY caseblock_list '}'
- {
- $$ = $3;
- $$->op = OSWITCH;
- $$->list = $6;
- typesw = typesw->left;
- popdcl();
- }
-
-select_stmt:
- LSELECT
- {
- typesw = nod(OXXX, typesw, N);
- }
- LBODY caseblock_list '}'
- {
- $$ = nod(OSELECT, N, N);
- $$->list = $4;
- typesw = typesw->left;
- }
-
-/*
- * expressions
- */
-expr:
- uexpr
-| expr LOROR expr
- {
- $$ = nod(OOROR, $1, $3);
- }
-| expr LANDAND expr
- {
- $$ = nod(OANDAND, $1, $3);
- }
-| expr LEQ expr
- {
- $$ = nod(OEQ, $1, $3);
- }
-| expr LNE expr
- {
- $$ = nod(ONE, $1, $3);
- }
-| expr LLT expr
- {
- $$ = nod(OLT, $1, $3);
- }
-| expr LLE expr
- {
- $$ = nod(OLE, $1, $3);
- }
-| expr LGE expr
- {
- $$ = nod(OGE, $1, $3);
- }
-| expr LGT expr
- {
- $$ = nod(OGT, $1, $3);
- }
-| expr '+' expr
- {
- $$ = nod(OADD, $1, $3);
- }
-| expr '-' expr
- {
- $$ = nod(OSUB, $1, $3);
- }
-| expr '|' expr
- {
- $$ = nod(OOR, $1, $3);
- }
-| expr '^' expr
- {
- $$ = nod(OXOR, $1, $3);
- }
-| expr '*' expr
- {
- $$ = nod(OMUL, $1, $3);
- }
-| expr '/' expr
- {
- $$ = nod(ODIV, $1, $3);
- }
-| expr '%' expr
- {
- $$ = nod(OMOD, $1, $3);
- }
-| expr '&' expr
- {
- $$ = nod(OAND, $1, $3);
- }
-| expr LANDNOT expr
- {
- $$ = nod(OANDNOT, $1, $3);
- }
-| expr LLSH expr
- {
- $$ = nod(OLSH, $1, $3);
- }
-| expr LRSH expr
- {
- $$ = nod(ORSH, $1, $3);
- }
- /* not an expression anymore, but left in so we can give a good error */
-| expr LCOMM expr
- {
- $$ = nod(OSEND, $1, $3);
- }
-
-uexpr:
- pexpr
-| '*' uexpr
- {
- $$ = nod(OIND, $2, N);
- }
-| '&' uexpr
- {
- $$ = nod(OADDR, $2, N);
- }
-| '+' uexpr
- {
- $$ = nod(OPLUS, $2, N);
- }
-| '-' uexpr
- {
- $$ = nod(OMINUS, $2, N);
- }
-| '!' uexpr
- {
- $$ = nod(ONOT, $2, N);
- }
-| '~' uexpr
- {
- yyerror("the bitwise complement operator is ^");
- $$ = nod(OCOM, $2, N);
- }
-| '^' uexpr
- {
- $$ = nod(OCOM, $2, N);
- }
-| LCOMM uexpr
- {
- $$ = nod(ORECV, $2, N);
- }
-
-/*
- * call-like statements that
- * can be preceded by 'defer' and 'go'
- */
-pseudocall:
- pexpr '(' ')'
- {
- $$ = nod(OCALL, $1, N);
- }
-| pexpr '(' expr_or_type_list ocomma ')'
- {
- $$ = nod(OCALL, $1, N);
- $$->list = $3;
- }
-| pexpr '(' expr_or_type_list LDDD ocomma ')'
- {
- $$ = nod(OCALL, $1, N);
- $$->list = $3;
- $$->isddd = 1;
- }
-
-pexpr_no_paren:
- LLITERAL
- {
- $$ = nodlit($1);
- }
-| name
-| pexpr '.' sym
- {
- if($1->op == OPACK) {
- Sym *s;
- s = restrictlookup($3->name, $1->pkg);
- $1->used = 1;
- $$ = oldname(s);
- break;
- }
- $$ = nod(OXDOT, $1, newname($3));
- }
-| pexpr '.' '(' expr_or_type ')'
- {
- $$ = nod(ODOTTYPE, $1, $4);
- }
-| pexpr '.' '(' LTYPE ')'
- {
- $$ = nod(OTYPESW, N, $1);
- }
-| pexpr '[' expr ']'
- {
- $$ = nod(OINDEX, $1, $3);
- }
-| pexpr '[' oexpr ':' oexpr ']'
- {
- $$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
- }
-| pseudocall
-| convtype '(' expr ')'
- {
- // conversion
- $$ = nod(OCALL, $1, N);
- $$->list = list1($3);
- }
-| comptype lbrace braced_keyval_list '}'
- {
- // composite expression
- $$ = nod(OCOMPLIT, N, $1);
- $$->list = $3;
-
- fixlbrace($2);
- }
-| pexpr_no_paren '{' braced_keyval_list '}'
- {
- // composite expression
- $$ = nod(OCOMPLIT, N, $1);
- $$->list = $3;
- }
-| '(' expr_or_type ')' '{' braced_keyval_list '}'
- {
- yyerror("cannot parenthesize type in composite literal");
- // composite expression
- $$ = nod(OCOMPLIT, N, $2);
- $$->list = $5;
- }
-| fnliteral
-
-keyval:
- expr ':' complitexpr
- {
- $$ = nod(OKEY, $1, $3);
- }
-
-complitexpr:
- expr
-| '{' braced_keyval_list '}'
- {
- $$ = nod(OCOMPLIT, N, N);
- $$->list = $2;
- }
-
-pexpr:
- pexpr_no_paren
-| '(' expr_or_type ')'
- {
- $$ = $2;
- }
-
-expr_or_type:
- expr
-| non_expr_type %prec PreferToRightParen
-
-name_or_type:
- ntype
-
-lbrace:
- LBODY
- {
- $$ = LBODY;
- }
-| '{'
- {
- $$ = '{';
- }
-
-/*
- * names and types
- * newname is used before declared
- * oldname is used after declared
- */
-new_name:
- sym
- {
- $$ = newname($1);
- }
-
-dcl_name:
- sym
- {
- $$ = dclname($1);
- }
-
-onew_name:
- {
- $$ = N;
- }
-| new_name
-
-sym:
- LNAME
-
-name:
- sym %prec NotParen
- {
- $$ = oldname($1);
- if($$->pack != N)
- $$->pack->used = 1;
- }
-
-labelname:
- new_name
-
-/*
- * to avoid parsing conflicts, type is split into
- * channel types
- * function types
- * parenthesized types
- * any other type
- * the type system makes additional restrictions,
- * but those are not implemented in the grammar.
- */
-dotdotdot:
- LDDD
- {
- yyerror("final argument in variadic function missing type");
- $$ = nod(ODDD, typenod(typ(TINTER)), N);
- }
-| LDDD ntype
- {
- $$ = nod(ODDD, $2, N);
- }
-
-ntype:
- recvchantype
-| fntype
-| othertype
-| ptrtype
-| dotname
-| '(' ntype ')'
- {
- $$ = nod(OTPAREN, $2, N);
- }
-
-non_expr_type:
- recvchantype
-| fntype
-| othertype
-| '*' non_expr_type
- {
- $$ = nod(OIND, $2, N);
- }
-
-non_recvchantype:
- fntype
-| othertype
-| ptrtype
-| dotname
-| '(' ntype ')'
- {
- $$ = nod(OTPAREN, $2, N);
- }
-
-convtype:
- fntype
-| othertype
-
-comptype:
- othertype
-
-fnret_type:
- recvchantype
-| fntype
-| othertype
-| ptrtype
-| dotname
-
-dotname:
- name
-| name '.' sym
- {
- if($1->op == OPACK) {
- Sym *s;
- s = restrictlookup($3->name, $1->pkg);
- $1->used = 1;
- $$ = oldname(s);
- break;
- }
- $$ = nod(OXDOT, $1, newname($3));
- }
-
-othertype:
- '[' oexpr ']' ntype
- {
- $$ = nod(OTARRAY, $2, $4);
- }
-| '[' LDDD ']' ntype
- {
- // array literal of nelem
- $$ = nod(OTARRAY, nod(ODDD, N, N), $4);
- }
-| LCHAN non_recvchantype
- {
- $$ = nod(OTCHAN, $2, N);
- $$->etype = Cboth;
- }
-| LCHAN LCOMM ntype
- {
- $$ = nod(OTCHAN, $3, N);
- $$->etype = Csend;
- }
-| LMAP '[' ntype ']' ntype
- {
- $$ = nod(OTMAP, $3, $5);
- }
-| structtype
-| interfacetype
-
-ptrtype:
- '*' ntype
- {
- $$ = nod(OIND, $2, N);
- }
-
-recvchantype:
- LCOMM LCHAN ntype
- {
- $$ = nod(OTCHAN, $3, N);
- $$->etype = Crecv;
- }
-
-structtype:
- LSTRUCT lbrace structdcl_list osemi '}'
- {
- $$ = nod(OTSTRUCT, N, N);
- $$->list = $3;
- fixlbrace($2);
- }
-| LSTRUCT lbrace '}'
- {
- $$ = nod(OTSTRUCT, N, N);
- fixlbrace($2);
- }
-
-interfacetype:
- LINTERFACE lbrace interfacedcl_list osemi '}'
- {
- $$ = nod(OTINTER, N, N);
- $$->list = $3;
- fixlbrace($2);
- }
-| LINTERFACE lbrace '}'
- {
- $$ = nod(OTINTER, N, N);
- fixlbrace($2);
- }
-
-/*
- * function stuff
- * all in one place to show how crappy it all is
- */
-xfndcl:
- LFUNC fndcl fnbody
- {
- $$ = $2;
- if($$ == N)
- break;
- $$->nbody = $3;
- $$->endlineno = lineno;
- funcbody($$);
- }
-
-fndcl:
- dcl_name '(' oarg_type_list_ocomma ')' fnres
- {
- Node *n;
-
- $3 = checkarglist($3, 1);
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = $1;
- n = nod(OTFUNC, N, N);
- n->list = $3;
- n->rlist = $5;
- if(strcmp($1->sym->name, "init") == 0) {
- $$->nname = renameinit($1);
- if($3 != nil || $5 != nil)
- yyerror("func init must have no arguments and no return values");
- }
- if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) {
- if($3 != nil || $5 != nil)
- yyerror("func main must have no arguments and no return values");
- }
- // TODO: check if nname already has an ntype
- $$->nname->ntype = n;
- funchdr($$);
- }
-| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
- {
- Node *rcvr, *t;
- Node *name;
-
- name = newname($4);
- $2 = checkarglist($2, 0);
- $6 = checkarglist($6, 1);
- $$ = N;
- if($2 == nil) {
- yyerror("method has no receiver");
- break;
- }
- if($2->next != nil) {
- yyerror("method has multiple receivers");
- break;
- }
- rcvr = $2->n;
- if(rcvr->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- break;
- }
- if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
- yyerror("cannot parenthesize receiver type");
-
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = methodname1(name, rcvr->right);
- t = nod(OTFUNC, rcvr, N);
- t->list = $6;
- t->rlist = $8;
- $$->nname->ntype = t;
- $$->shortname = name;
- funchdr($$);
- }
-
-fntype:
- LFUNC '(' oarg_type_list_ocomma ')' fnres
- {
- $3 = checkarglist($3, 1);
- $$ = nod(OTFUNC, N, N);
- $$->list = $3;
- $$->rlist = $5;
- }
-
-fnbody:
- {
- $$ = nil;
- }
-| '{' stmt_list '}'
- {
- $$ = $2;
- if($$ == nil)
- $$ = list1(nod(OEMPTY, N, N));
- }
-
-fnres:
- %prec NotParen
- {
- $$ = nil;
- }
-| fnret_type
- {
- $$ = list1(nod(ODCLFIELD, N, $1));
- }
-| '(' oarg_type_list_ocomma ')'
- {
- $2 = checkarglist($2, 0);
- $$ = $2;
- }
-
-fnlitdcl:
- fntype
- {
- closurehdr($1);
- }
-
-fnliteral:
- fnlitdcl lbrace stmt_list '}'
- {
- $$ = closurebody($3);
- fixlbrace($2);
- }
-
-
-/*
- * lists of things
- * note that they are left recursive
- * to conserve yacc stack. they need to
- * be reversed to interpret correctly
- */
-xdcl_list:
- {
- $$ = nil;
- }
-| xdcl_list xdcl ';'
- {
- $$ = concat($1, $2);
- if(nsyntaxerrors == 0)
- testdclstack();
- }
-
-vardcl_list:
- vardcl
-| vardcl_list ';' vardcl
- {
- $$ = concat($1, $3);
- }
-
-constdcl_list:
- constdcl1
-| constdcl_list ';' constdcl1
- {
- $$ = concat($1, $3);
- }
-
-typedcl_list:
- typedcl
- {
- $$ = list1($1);
- }
-| typedcl_list ';' typedcl
- {
- $$ = list($1, $3);
- }
-
-structdcl_list:
- structdcl
-| structdcl_list ';' structdcl
- {
- $$ = concat($1, $3);
- }
-
-interfacedcl_list:
- interfacedcl
- {
- $$ = list1($1);
- }
-| interfacedcl_list ';' interfacedcl
- {
- $$ = list($1, $3);
- }
-
-structdcl:
- new_name_list ntype oliteral
- {
- NodeList *l;
-
- for(l=$1; l; l=l->next) {
- l->n = nod(ODCLFIELD, l->n, $2);
- l->n->val = $3;
- }
- }
-| embed oliteral
- {
- $1->val = $2;
- $$ = list1($1);
- }
-| '(' embed ')' oliteral
- {
- $2->val = $4;
- $$ = list1($2);
- yyerror("cannot parenthesize embedded type");
- }
-| '*' embed oliteral
- {
- $2->right = nod(OIND, $2->right, N);
- $2->val = $3;
- $$ = list1($2);
- }
-| '(' '*' embed ')' oliteral
- {
- $3->right = nod(OIND, $3->right, N);
- $3->val = $5;
- $$ = list1($3);
- yyerror("cannot parenthesize embedded type");
- }
-| '*' '(' embed ')' oliteral
- {
- $3->right = nod(OIND, $3->right, N);
- $3->val = $5;
- $$ = list1($3);
- yyerror("cannot parenthesize embedded type");
- }
-
-packname:
- LNAME
- {
- Node *n;
-
- $$ = $1;
- n = oldname($1);
- if(n->pack != N)
- n->pack->used = 1;
- }
-| LNAME '.' sym
- {
- Pkg *pkg;
-
- if($1->def == N || $1->def->op != OPACK) {
- yyerror("%S is not a package", $1);
- pkg = localpkg;
- } else {
- $1->def->used = 1;
- pkg = $1->def->pkg;
- }
- $$ = restrictlookup($3->name, pkg);
- }
-
-embed:
- packname
- {
- $$ = embedded($1);
- }
-
-interfacedcl:
- new_name indcl
- {
- $$ = nod(ODCLFIELD, $1, $2);
- ifacedcl($$);
- }
-| packname
- {
- $$ = nod(ODCLFIELD, N, oldname($1));
- }
-| '(' packname ')'
- {
- $$ = nod(ODCLFIELD, N, oldname($2));
- yyerror("cannot parenthesize embedded type");
- }
-
-indcl:
- '(' oarg_type_list_ocomma ')' fnres
- {
- // without func keyword
- $2 = checkarglist($2, 1);
- $$ = nod(OTFUNC, fakethis(), N);
- $$->list = $2;
- $$->rlist = $4;
- }
-
-/*
- * function arguments.
- */
-arg_type:
- name_or_type
-| sym name_or_type
- {
- $$ = nod(ONONAME, N, N);
- $$->sym = $1;
- $$ = nod(OKEY, $$, $2);
- }
-| sym dotdotdot
- {
- $$ = nod(ONONAME, N, N);
- $$->sym = $1;
- $$ = nod(OKEY, $$, $2);
- }
-| dotdotdot
-
-arg_type_list:
- arg_type
- {
- $$ = list1($1);
- }
-| arg_type_list ',' arg_type
- {
- $$ = list($1, $3);
- }
-
-oarg_type_list_ocomma:
- {
- $$ = nil;
- }
-| arg_type_list ocomma
- {
- $$ = $1;
- }
-
-/*
- * statement
- */
-stmt:
- {
- $$ = N;
- }
-| compound_stmt
-| common_dcl
- {
- $$ = liststmt($1);
- }
-| non_dcl_stmt
-| error
- {
- $$ = N;
- }
-
-non_dcl_stmt:
- simple_stmt
-| for_stmt
-| switch_stmt
-| select_stmt
-| if_stmt
- {
- popdcl();
- $$ = $1;
- }
-| if_stmt LELSE stmt
- {
- popdcl();
- $$ = $1;
- $$->nelse = list1($3);
- }
-| labelname ':'
- {
- $1 = nod(OLABEL, $1, N);
- $1->sym = dclstack; // context, for goto restrictions
- }
- stmt
- {
- NodeList *l;
-
- $1->right = $4;
- l = list1($1);
- if($4)
- l = list(l, $4);
- $$ = liststmt(l);
- }
-| LFALL
- {
- // will be converted to OFALL
- $$ = nod(OXFALL, N, N);
- }
-| LBREAK onew_name
- {
- $$ = nod(OBREAK, $2, N);
- }
-| LCONTINUE onew_name
- {
- $$ = nod(OCONTINUE, $2, N);
- }
-| LGO pseudocall
- {
- $$ = nod(OPROC, $2, N);
- }
-| LDEFER pseudocall
- {
- $$ = nod(ODEFER, $2, N);
- }
-| LGOTO new_name
- {
- $$ = nod(OGOTO, $2, N);
- $$->sym = dclstack; // context, for goto restrictions
- }
-| LRETURN oexpr_list
- {
- $$ = nod(ORETURN, N, N);
- $$->list = $2;
- }
-
-stmt_list:
- stmt
- {
- $$ = nil;
- if($1 != N)
- $$ = list1($1);
- }
-| stmt_list ';' stmt
- {
- $$ = $1;
- if($3 != N)
- $$ = list($$, $3);
- }
-
-new_name_list:
- new_name
- {
- $$ = list1($1);
- }
-| new_name_list ',' new_name
- {
- $$ = list($1, $3);
- }
-
-dcl_name_list:
- dcl_name
- {
- $$ = list1($1);
- }
-| dcl_name_list ',' dcl_name
- {
- $$ = list($1, $3);
- }
-
-expr_list:
- expr
- {
- $$ = list1($1);
- }
-| expr_list ',' expr
- {
- $$ = list($1, $3);
- }
-
-expr_or_type_list:
- expr_or_type
- {
- $$ = list1($1);
- }
-| expr_or_type_list ',' expr_or_type
- {
- $$ = list($1, $3);
- }
-
-/*
- * list of combo of keyval and val
- */
-keyval_list:
- keyval
- {
- $$ = list1($1);
- }
-| complitexpr
- {
- $$ = list1($1);
- }
-| keyval_list ',' keyval
- {
- $$ = list($1, $3);
- }
-| keyval_list ',' complitexpr
- {
- $$ = list($1, $3);
- }
-
-braced_keyval_list:
- {
- $$ = nil;
- }
-| keyval_list ocomma
- {
- $$ = $1;
- }
-
-/*
- * optional things
- */
-osemi:
-| ';'
-
-ocomma:
-| ','
-
-oexpr:
- {
- $$ = N;
- }
-| expr
-
-oexpr_list:
- {
- $$ = nil;
- }
-| expr_list
-
-osimple_stmt:
- {
- $$ = N;
- }
-| simple_stmt
-
-ohidden_funarg_list:
- {
- $$ = nil;
- }
-| hidden_funarg_list
-
-ohidden_structdcl_list:
- {
- $$ = nil;
- }
-| hidden_structdcl_list
-
-ohidden_interfacedcl_list:
- {
- $$ = nil;
- }
-| hidden_interfacedcl_list
-
-oliteral:
- {
- $$.ctype = CTxxx;
- }
-| LLITERAL
-
-/*
- * import syntax from header of
- * an output package
- */
-hidden_import:
- LIMPORT sym LLITERAL ';'
- {
- // Informational: record package name
- // associated with import path, for use in
- // human-readable messages.
- Pkg *p;
-
- p = mkpkg($3.u.sval);
- if(p->name == nil) {
- p->name = $2->name;
- pkglookup($2->name, nil)->npkg++;
- } else if(strcmp(p->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path);
- }
-| LVAR hidden_pkg_importsym hidden_type ';'
- {
- importvar($2, $3, PEXTERN);
- }
-| LCONST hidden_pkg_importsym '=' hidden_constant ';'
- {
- importconst($2, types[TIDEAL], $4);
- }
-| LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
- {
- importconst($2, $3, $5);
- }
-| LTYPE hidden_pkgtype hidden_type ';'
- {
- importtype($2, $3);
- }
-| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';'
- {
- importvar($2, functype(N, $4, $6), PFUNC);
- }
-| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';'
- {
- if($3->next != nil || $3->n->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- YYERROR;
- }
- importmethod($5, functype($3->n, $7, $9));
- }
-
-hidden_pkgtype:
- hidden_pkg_importsym
- {
- $$ = pkgtype($1);
- importsym($1, OTYPE);
- }
-
-hidden_type:
- hidden_type_misc
-| hidden_type_recv_chan
-| hidden_type_func
-
-hidden_type_non_recv_chan:
- hidden_type_misc
-| hidden_type_func
-
-hidden_type_misc:
- hidden_importsym
- {
- $$ = pkgtype($1);
- }
-| LNAME
- {
- // predefined name like uint8
- $1 = pkglookup($1->name, builtinpkg);
- if($1->def == N || $1->def->op != OTYPE) {
- yyerror("%s is not a type", $1->name);
- $$ = T;
- } else
- $$ = $1->def->type;
- }
-| '[' ']' hidden_type
- {
- $$ = aindex(N, $3);
- }
-| '[' LLITERAL ']' hidden_type
- {
- $$ = aindex(nodlit($2), $4);
- }
-| LMAP '[' hidden_type ']' hidden_type
- {
- $$ = maptype($3, $5);
- }
-| LSTRUCT '{' ohidden_structdcl_list '}'
- {
- $$ = dostruct($3, TSTRUCT);
- }
-| LINTERFACE '{' ohidden_interfacedcl_list '}'
- {
- $$ = dostruct($3, TINTER);
- }
-| '*' hidden_type
- {
- $$ = ptrto($2);
- }
-| LCHAN hidden_type_non_recv_chan
- {
- $$ = typ(TCHAN);
- $$->type = $2;
- $$->chan = Cboth;
- }
-| LCHAN '(' hidden_type_recv_chan ')'
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Cboth;
- }
-| LCHAN LCOMM hidden_type
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Csend;
- }
-
-hidden_type_recv_chan:
- LCOMM LCHAN hidden_type
- {
- $$ = typ(TCHAN);
- $$->type = $3;
- $$->chan = Crecv;
- }
-
-hidden_type_func:
- LFUNC '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = functype(nil, $3, $5);
- }
-
-hidden_opt_sym:
- sym
- {
- $$ = newname($1);
- }
-| '?'
- {
- $$ = N;
- }
-
-hidden_dcl:
- hidden_opt_sym hidden_type hidden_tag
- {
- $$ = nod(ODCLFIELD, $1, typenod($2));
- $$->val = $3;
- }
-| hidden_opt_sym LDDD hidden_type hidden_tag
- {
- Type *t;
-
- t = typ(TARRAY);
- t->bound = -1;
- t->type = $3;
- $$ = nod(ODCLFIELD, $1, typenod(t));
- $$->isddd = 1;
- $$->val = $4;
- }
-
-hidden_structdcl:
- sym hidden_type hidden_tag
- {
- $$ = nod(ODCLFIELD, newname($1), typenod($2));
- $$->val = $3;
- }
-| '?' hidden_type hidden_tag
- {
- Sym *s;
-
- s = $2->sym;
- if(s == S && isptr[$2->etype])
- s = $2->type->sym;
- if(s && s->pkg == builtinpkg)
- s = lookup(s->name);
- $$ = embedded(s);
- $$->right = typenod($2);
- $$->val = $3;
- }
-
-hidden_tag:
- {
- $$.ctype = CTxxx;
- }
-| ':' LLITERAL // extra colon avoids conflict with "" looking like beginning of "".typename
- {
- $$ = $2;
- }
-
-hidden_interfacedcl:
- sym '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
- }
-| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres
- {
- $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
- }
-
-ohidden_funres:
- {
- $$ = nil;
- }
-| hidden_funres
-
-hidden_funres:
- '(' ohidden_funarg_list ')'
- {
- $$ = $2;
- }
-| hidden_type
- {
- $$ = list1(nod(ODCLFIELD, N, typenod($1)));
- }
-
-hidden_literal:
- LLITERAL
- {
- $$ = nodlit($1);
- }
-| '-' LLITERAL
- {
- $$ = nodlit($2);
- switch($$->val.ctype){
- case CTINT:
- mpnegfix($$->val.u.xval);
- break;
- case CTFLT:
- mpnegflt($$->val.u.fval);
- break;
- default:
- yyerror("bad negated constant");
- }
- }
-| sym
- {
- $$ = oldname(pkglookup($1->name, builtinpkg));
- if($$->op != OLITERAL)
- yyerror("bad constant %S", $$->sym);
- }
-
-hidden_constant:
- hidden_literal
-| '(' hidden_literal '+' hidden_literal ')'
- {
- $$ = nodcplxlit($2->val, $4->val);
- }
-
-hidden_importsym:
- LLITERAL '.' sym
- {
- Pkg *p;
-
- if($1.u.sval->len == 0)
- p = importpkg;
- else
- p = mkpkg($1.u.sval);
- $$ = pkglookup($3->name, p);
- }
-
-hidden_pkg_importsym:
- hidden_importsym
- {
- $$ = $1;
- structpkg = $$->pkg;
- }
-
-hidden_import_list:
-| hidden_import_list hidden_import
-
-hidden_funarg_list:
- hidden_dcl
- {
- $$ = list1($1);
- }
-| hidden_funarg_list ',' hidden_dcl
- {
- $$ = list($1, $3);
- }
-
-hidden_structdcl_list:
- hidden_structdcl
- {
- $$ = list1($1);
- }
-| hidden_structdcl_list ';' hidden_structdcl
- {
- $$ = list($1, $3);
- }
-
-hidden_interfacedcl_list:
- hidden_interfacedcl
- {
- $$ = list1($1);
- }
-| hidden_interfacedcl_list ';' hidden_interfacedcl
- {
- $$ = list($1, $3);
- }
-
-%%
-
-static void
-fixlbrace(int lbr)
-{
- // If the opening brace was an LBODY,
- // set up for another one now that we're done.
- // See comment in lex.c about loophack.
- if(lbr == LBODY)
- loophack = 1;
-}
-
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
deleted file mode 100644
index 8818db08c..000000000
--- a/src/cmd/gc/init.c
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/*
- * a function named init is a special case.
- * it is called by the initialization before
- * main is run. to make it unique within a
- * package and also uncallable, the name,
- * normally "pkg.init", is altered to "pkg.init·1".
- */
-Node*
-renameinit(Node *n)
-{
- Sym *s;
- static int initgen;
-
- s = n->sym;
- if(s == S)
- return n;
- if(strcmp(s->name, "init") != 0)
- return n;
-
- snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
- s = lookup(namebuf);
- return newname(s);
-}
-
-/*
- * hand-craft the following initialization code
- * var initdone· uint8 (1)
- * func init() (2)
- * if initdone· != 0 { (3)
- * if initdone· == 2 (4)
- * return
- * throw(); (5)
- * }
- * initdone· = 1; (6)
- * // over all matching imported symbols
- * <pkg>.init() (7)
- * { <init stmts> } (8)
- * init·<n>() // if any (9)
- * initdone· = 2; (10)
- * return (11)
- * }
- */
-static int
-anyinit(NodeList *n)
-{
- uint32 h;
- Sym *s;
- NodeList *l;
-
- // are there any interesting init statements
- for(l=n; l; l=l->next) {
- switch(l->n->op) {
- case ODCLFUNC:
- case ODCLCONST:
- case ODCLTYPE:
- case OEMPTY:
- break;
- default:
- return 1;
- }
- }
-
- // is this main
- if(strcmp(localpkg->name, "main") == 0)
- return 1;
-
- // is there an explicit init function
- snprint(namebuf, sizeof(namebuf), "init·1");
- s = lookup(namebuf);
- if(s->def != N)
- return 1;
-
- // are there any imported init functions
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
- continue;
- if(s->def == N)
- continue;
- return 1;
- }
-
- // then none
- return 0;
-}
-
-void
-fninit(NodeList *n)
-{
- int i;
- Node *gatevar;
- Node *a, *b, *fn;
- NodeList *r;
- uint32 h;
- Sym *s, *initsym;
-
- if(debug['A']) {
- // sys.go or unsafe.go during compiler build
- return;
- }
-
- n = initfix(n);
- if(!anyinit(n))
- return;
-
- r = nil;
-
- // (1)
- snprint(namebuf, sizeof(namebuf), "initdone·");
- gatevar = newname(lookup(namebuf));
- addvar(gatevar, types[TUINT8], PEXTERN);
-
- // (2)
- maxarg = 0;
- snprint(namebuf, sizeof(namebuf), "init");
-
- fn = nod(ODCLFUNC, N, N);
- initsym = lookup(namebuf);
- fn->nname = newname(initsym);
- fn->nname->ntype = nod(OTFUNC, N, N);
- funchdr(fn);
-
- // (3)
- a = nod(OIF, N, N);
- a->ntest = nod(ONE, gatevar, nodintconst(0));
- r = list(r, a);
-
- // (4)
- b = nod(OIF, N, N);
- b->ntest = nod(OEQ, gatevar, nodintconst(2));
- b->nbody = list1(nod(ORETURN, N, N));
- a->nbody = list1(b);
-
- // (5)
- b = syslook("throwinit", 0);
- b = nod(OCALL, b, N);
- a->nbody = list(a->nbody, b);
-
- // (6)
- a = nod(OAS, gatevar, nodintconst(1));
- r = list(r, a);
-
- // (7)
- for(h=0; h<NHASH; h++)
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
- continue;
- if(s->def == N)
- continue;
- if(s == initsym)
- continue;
-
- // could check that it is fn of no args/returns
- a = nod(OCALL, s->def, N);
- r = list(r, a);
- }
-
- // (8)
- r = concat(r, n);
-
- // (9)
- // could check that it is fn of no args/returns
- for(i=1;; i++) {
- snprint(namebuf, sizeof(namebuf), "init·%d", i);
- s = lookup(namebuf);
- if(s->def == N)
- break;
- a = nod(OCALL, s->def, N);
- r = list(r, a);
- }
-
- // (10)
- a = nod(OAS, gatevar, nodintconst(2));
- r = list(r, a);
-
- // (11)
- a = nod(ORETURN, N, N);
- r = list(r, a);
- exportsym(fn->nname);
-
- fn->nbody = r;
- funcbody(fn);
-
- curfn = fn;
- typecheck(&fn, Etop);
- typechecklist(r, Etop);
- curfn = nil;
- funccompile(fn, 0);
-}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
deleted file mode 100644
index 5c642375a..000000000
--- a/src/cmd/gc/lex.c
+++ /dev/null
@@ -1,1935 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#define EXTERN
-#include "go.h"
-#include "y.tab.h"
-#include <ar.h>
-
-#undef getc
-#undef ungetc
-#define getc ccgetc
-#define ungetc ccungetc
-
-extern int yychar;
-int windows;
-int yyprev;
-int yylast;
-
-static void lexinit(void);
-static void lexfini(void);
-static void yytinit(void);
-static int getc(void);
-static void ungetc(int);
-static int32 getr(void);
-static int escchar(int, int*, vlong*);
-static void addidir(char*);
-static int getlinepragma(void);
-static char *goos, *goarch, *goroot;
-
-// Our own isdigit, isspace, isalpha, isalnum that take care
-// of EOF and other out of range arguments.
-static int
-yy_isdigit(int c)
-{
- return c >= 0 && c <= 0xFF && isdigit(c);
-}
-
-static int
-yy_isspace(int c)
-{
- return c >= 0 && c <= 0xFF && isspace(c);
-}
-
-static int
-yy_isalpha(int c)
-{
- return c >= 0 && c <= 0xFF && isalpha(c);
-}
-
-static int
-yy_isalnum(int c)
-{
- return c >= 0 && c <= 0xFF && isalnum(c);
-}
-
-// Disallow use of isdigit etc.
-#undef isdigit
-#undef isspace
-#undef isalpha
-#undef isalnum
-#define isdigit use_yy_isdigit_instead_of_isdigit
-#define isspace use_yy_isspace_instead_of_isspace
-#define isalpha use_yy_isalpha_instead_of_isalpha
-#define isalnum use_yy_isalnum_instead_of_isalnum
-
-#define DBG if(!debug['x']);else print
-enum
-{
- EOF = -1,
-};
-
-void
-usage(void)
-{
- print("gc: usage: %cg [flags] file.go...\n", thechar);
- print("flags:\n");
- // -A is allow use of "any" type, for bootstrapping
- print(" -I DIR search for packages in DIR\n");
- print(" -d print declarations\n");
- print(" -e no limit on number of errors printed\n");
- print(" -f print stack frame structure\n");
- print(" -h panic on an error\n");
- print(" -o file specify output file\n");
- print(" -S print the assembly language\n");
- print(" -V print the compiler version\n");
- print(" -u disable package unsafe\n");
- print(" -w print the parse tree after typing\n");
- print(" -x print lex tokens\n");
- exit(0);
-}
-
-void
-fault(int s)
-{
- // If we've already complained about things
- // in the program, don't bother complaining
- // about the seg fault too; let the user clean up
- // the code and try again.
- if(nsavederrors + nerrors > 0)
- errorexit();
- fatal("fault");
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, c;
- NodeList *l;
- char *p;
-
- signal(SIGBUS, fault);
- signal(SIGSEGV, fault);
-
- localpkg = mkpkg(strlit(""));
- localpkg->prefix = "\"\"";
-
- builtinpkg = mkpkg(strlit("go.builtin"));
-
- gostringpkg = mkpkg(strlit("go.string"));
- gostringpkg->name = "go.string";
- gostringpkg->prefix = "go.string"; // not go%2estring
-
- runtimepkg = mkpkg(strlit("runtime"));
- runtimepkg->name = "runtime";
-
- typepkg = mkpkg(strlit("type"));
- typepkg->name = "type";
-
- unsafepkg = mkpkg(strlit("unsafe"));
- unsafepkg->name = "unsafe";
-
- goroot = getgoroot();
- goos = getgoos();
- goarch = thestring;
-
- outfile = nil;
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
-
- case 'o':
- outfile = EARGF(usage());
- break;
-
- case 'I':
- addidir(EARGF(usage()));
- break;
-
- case 'u':
- safemode = 1;
- break;
-
- case 'V':
- print("%cg version %s\n", thechar, getgoversion());
- exit(0);
- } ARGEND
-
- if(argc < 1)
- usage();
-
- // special flag to detect compilation of package runtime
- compiling_runtime = debug['+'];
-
- pathname = mal(1000);
- if(getwd(pathname, 999) == 0)
- strcpy(pathname, "/???");
-
- if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
- // On Windows.
- windows = 1;
-
- // Canonicalize path by converting \ to / (Windows accepts both).
- for(p=pathname; *p; p++)
- if(*p == '\\')
- *p = '/';
- }
-
- fmtinstall('O', Oconv); // node opcodes
- fmtinstall('E', Econv); // etype opcodes
- fmtinstall('J', Jconv); // all the node flags
- fmtinstall('S', Sconv); // sym pointer
- fmtinstall('T', Tconv); // type pointer
- fmtinstall('N', Nconv); // node pointer
- fmtinstall('Z', Zconv); // escaped string
- fmtinstall('L', Lconv); // line number
- fmtinstall('B', Bconv); // big numbers
- fmtinstall('F', Fconv); // big float numbers
-
- betypeinit();
- if(widthptr == 0)
- fatal("betypeinit failed");
-
- lexinit();
- typeinit();
- yytinit();
-
- blockgen = 1;
- dclcontext = PEXTERN;
- nerrors = 0;
- lexlineno = 1;
-
- for(i=0; i<argc; i++) {
- infile = argv[i];
- linehist(infile, 0, 0);
-
- curio.infile = infile;
- curio.bin = Bopen(infile, OREAD);
- if(curio.bin == nil) {
- print("open %s: %r\n", infile);
- errorexit();
- }
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.nlsemi = 0;
-
- block = 1;
-
- yyparse();
- if(nsyntaxerrors != 0)
- errorexit();
-
- linehist(nil, 0, 0);
- if(curio.bin != nil)
- Bterm(curio.bin);
- }
- testdclstack();
- mkpackage(localpkg->name); // final import not used checks
- lexfini();
-
- typecheckok = 1;
- if(debug['f'])
- frame(1);
-
- // Process top-level declarations in four phases.
- // Phase 1: const, type, and names and types of funcs.
- // This will gather all the information about types
- // and methods but doesn't depend on any of it.
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
- // Phase 3: Type check function bodies.
- // Phase 4: Compile function bodies.
- defercheckwidth();
- for(l=xtop; l; l=l->next)
- if(l->n->op != ODCL && l->n->op != OAS)
- typecheck(&l->n, Etop);
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCL || l->n->op == OAS)
- typecheck(&l->n, Etop);
- resumetypecopy();
- resumecheckwidth();
-
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC) {
- curfn = l->n;
- saveerrors();
- typechecklist(l->n->nbody, Etop);
- if(nerrors != 0)
- l->n->nbody = nil; // type errors; do not compile
- }
- curfn = nil;
-
- for(l=xtop; l; l=l->next)
- if(l->n->op == ODCLFUNC)
- funccompile(l->n, 0);
-
- if(nsavederrors+nerrors == 0)
- fninit(xtop);
-
- while(closures) {
- l = closures;
- closures = nil;
- for(; l; l=l->next)
- funccompile(l->n, 1);
- }
-
- for(l=externdcl; l; l=l->next)
- if(l->n->op == ONAME)
- typecheck(&l->n, Erv);
-
- if(nerrors+nsavederrors)
- errorexit();
-
- dumpobj();
-
- if(nerrors+nsavederrors)
- errorexit();
-
- flusherrors();
- exit(0);
- return 0;
-}
-
-void
-saveerrors(void)
-{
- nsavederrors += nerrors;
- nerrors = 0;
-}
-
-static int
-arsize(Biobuf *b, char *name)
-{
- struct ar_hdr *a;
-
- if((a = Brdline(b, '\n')) == nil)
- return -1;
- if(Blinelen(b) != sizeof(struct ar_hdr))
- return -1;
- if(strncmp(a->name, name, strlen(name)) != 0)
- return -1;
- return atoi(a->size);
-}
-
-static int
-skiptopkgdef(Biobuf *b)
-{
- char *p;
- int sz;
-
- /* archive header */
- if((p = Brdline(b, '\n')) == nil)
- return 0;
- if(Blinelen(b) != 8)
- return 0;
- if(memcmp(p, "!<arch>\n", 8) != 0)
- return 0;
- /* symbol table is first; skip it */
- sz = arsize(b, "__.SYMDEF");
- if(sz < 0)
- return 0;
- Bseek(b, sz, 1);
- /* package export block is second */
- sz = arsize(b, "__.PKGDEF");
- if(sz <= 0)
- return 0;
- return 1;
-}
-
-static void
-addidir(char* dir)
-{
- Idir** pp;
-
- if(dir == nil)
- return;
-
- for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
- ;
- *pp = mal(sizeof(Idir));
- (*pp)->link = nil;
- (*pp)->dir = dir;
-}
-
-// is this path a local name? begins with ./ or ../ or /
-static int
-islocalname(Strlit *name)
-{
- if(!windows && name->len >= 1 && name->s[0] == '/')
- return 1;
- if(windows && name->len >= 3 &&
- yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
- return 1;
- if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
- return 1;
- if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
- return 1;
- return 0;
-}
-
-static int
-findpkg(Strlit *name)
-{
- Idir *p;
- char *q;
-
- if(islocalname(name)) {
- if(safemode)
- return 0;
- // try .a before .6. important for building libraries:
- // if there is an array.6 in the array.a library,
- // want to find all of array.a, not just array.6.
- snprint(namebuf, sizeof(namebuf), "%Z.a", name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- return 0;
- }
-
- // local imports should be canonicalized already.
- // don't want to see "container/../container/vector"
- // as different from "container/vector".
- q = mal(name->len+1);
- memmove(q, name->s, name->len);
- q[name->len] = '\0';
- cleanname(q);
- if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
- yyerror("non-canonical import path %Z (should be %s)", name, q);
- return 0;
- }
-
- for(p = idirs; p != nil; p = p->link) {
- snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- }
- if(goroot != nil) {
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.a", goroot, goos, goarch, name);
- if(access(namebuf, 0) >= 0)
- return 1;
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.%c", goroot, goos, goarch, name, thechar);
- if(access(namebuf, 0) >= 0)
- return 1;
- }
- return 0;
-}
-
-void
-importfile(Val *f, int line)
-{
- Biobuf *imp;
- char *file, *p, *q;
- int32 c;
- int len;
- Strlit *path;
- char *cleanbuf;
-
- // TODO(rsc): don't bother reloading imports more than once?
-
- if(f->ctype != CTSTR) {
- yyerror("import statement not a string");
- return;
- }
-
- if(strlen(f->u.sval->s) != f->u.sval->len) {
- yyerror("import path contains NUL");
- errorexit();
- }
-
- // The package name main is no longer reserved,
- // but we reserve the import path "main" to identify
- // the main package, just as we reserve the import
- // path "math" to identify the standard math package.
- if(strcmp(f->u.sval->s, "main") == 0) {
- yyerror("cannot import \"main\"");
- errorexit();
- }
-
- if(strcmp(f->u.sval->s, "unsafe") == 0) {
- if(safemode) {
- yyerror("cannot import package unsafe");
- errorexit();
- }
- importpkg = mkpkg(f->u.sval);
- cannedimports("unsafe.6", unsafeimport);
- return;
- }
-
- path = f->u.sval;
- if(islocalname(path)) {
- cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
- strcpy(cleanbuf, pathname);
- strcat(cleanbuf, "/");
- strcat(cleanbuf, path->s);
- cleanname(cleanbuf);
- path = strlit(cleanbuf);
- }
-
- if(!findpkg(path)) {
- yyerror("can't find import: %Z", f->u.sval);
- errorexit();
- }
- importpkg = mkpkg(path);
-
- imp = Bopen(namebuf, OREAD);
- if(imp == nil) {
- yyerror("can't open import: %Z: %r", f->u.sval);
- errorexit();
- }
- file = strdup(namebuf);
-
- len = strlen(namebuf);
- if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
- if(!skiptopkgdef(imp)) {
- yyerror("import %s: not a package file", file);
- errorexit();
- }
- }
-
- // check object header
- p = Brdstr(imp, '\n', 1);
- if(strcmp(p, "empty archive") != 0) {
- if(strncmp(p, "go object ", 10) != 0) {
- yyerror("import %s: not a go object file", file);
- errorexit();
- }
- q = smprint("%s %s %s", getgoos(), thestring, getgoversion());
- if(strcmp(p+10, q) != 0) {
- yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
- errorexit();
- }
- free(q);
- }
-
- // assume files move (get installed)
- // so don't record the full path.
- linehist(file + len - path->len - 2, -1, 1); // acts as #pragma lib
-
- /*
- * position the input right
- * after $$ and return
- */
- pushedio = curio;
- curio.bin = imp;
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.infile = file;
- curio.nlsemi = 0;
- typecheckok = 1;
-
- for(;;) {
- c = getc();
- if(c == EOF)
- break;
- if(c != '$')
- continue;
- c = getc();
- if(c == EOF)
- break;
- if(c != '$')
- continue;
- return;
- }
- yyerror("no import in: %Z", f->u.sval);
- unimportfile();
-}
-
-void
-unimportfile(void)
-{
- if(curio.bin != nil) {
- Bterm(curio.bin);
- curio.bin = nil;
- } else
- lexlineno--; // re correct sys.6 line number
-
- curio = pushedio;
- pushedio.bin = nil;
- incannedimport = 0;
- typecheckok = 0;
-}
-
-void
-cannedimports(char *file, char *cp)
-{
- lexlineno++; // if sys.6 is included on line 1,
-
- pushedio = curio;
- curio.bin = nil;
- curio.peekc = 0;
- curio.peekc1 = 0;
- curio.infile = file;
- curio.cp = cp;
- curio.nlsemi = 0;
- curio.importsafe = 0;
-
- typecheckok = 1;
- incannedimport = 1;
-}
-
-static int
-isfrog(int c)
-{
- // complain about possibly invisible control characters
- if(c < 0)
- return 1;
- if(c < ' ') {
- if(c == '\n' || c== '\r' || c == '\t') // good white space
- return 0;
- return 1;
- }
- if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
- return 1;
- return 0;
-}
-
-typedef struct Loophack Loophack;
-struct Loophack {
- int v;
- Loophack *next;
-};
-
-static int32
-_yylex(void)
-{
- int c, c1, clen, escflag, ncp;
- vlong v;
- char *cp, *ep;
- Rune rune;
- Sym *s;
- static Loophack *lstk;
- Loophack *h;
-
- prevlineno = lineno;
-
-l0:
- c = getc();
- if(yy_isspace(c)) {
- if(c == '\n' && curio.nlsemi) {
- ungetc(c);
- DBG("lex: implicit semi\n");
- return ';';
- }
- goto l0;
- }
-
- lineno = lexlineno; /* start of token */
-
- if(c >= Runeself) {
- /* all multibyte runes are alpha */
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
- }
-
- if(yy_isalpha(c)) {
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
- }
-
- if(yy_isdigit(c))
- goto tnum;
-
- switch(c) {
- case EOF:
- lineno = prevlineno;
- ungetc(EOF);
- return -1;
-
- case '_':
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- goto talph;
-
- case '.':
- c1 = getc();
- if(yy_isdigit(c1)) {
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- *cp++ = c;
- c = c1;
- c1 = 0;
- goto casedot;
- }
- if(c1 == '.') {
- c1 = getc();
- if(c1 == '.') {
- c = LDDD;
- goto lx;
- }
- ungetc(c1);
- c1 = '.';
- }
- break;
-
- case '"':
- /* "..." */
- strcpy(lexbuf, "\"<string>\"");
- cp = mal(8);
- clen = sizeof(int32);
- ncp = 8;
-
- for(;;) {
- if(clen+UTFmax > ncp) {
- cp = remal(cp, ncp, ncp);
- ncp += ncp;
- }
- if(escchar('"', &escflag, &v))
- break;
- if(v < Runeself || escflag) {
- cp[clen++] = v;
- } else {
- rune = v;
- c = runelen(rune);
- runetochar(cp+clen, &rune);
- clen += c;
- }
- }
- goto strlit;
-
- case '`':
- /* `...` */
- strcpy(lexbuf, "`<string>`");
- cp = mal(8);
- clen = sizeof(int32);
- ncp = 8;
-
- for(;;) {
- if(clen+UTFmax > ncp) {
- cp = remal(cp, ncp, ncp);
- ncp += ncp;
- }
- c = getr();
- if(c == EOF) {
- yyerror("eof in string");
- break;
- }
- if(c == '`')
- break;
- rune = c;
- clen += runetochar(cp+clen, &rune);
- }
-
- strlit:
- *(int32*)cp = clen-sizeof(int32); // length
- do {
- cp[clen++] = 0;
- } while(clen & MAXALIGN);
- yylval.val.u.sval = (Strlit*)cp;
- yylval.val.ctype = CTSTR;
- DBG("lex: string literal\n");
- return LLITERAL;
-
- case '\'':
- /* '.' */
- if(escchar('\'', &escflag, &v)) {
- yyerror("empty character literal or unescaped ' in character literal");
- v = '\'';
- }
- if(!escchar('\'', &escflag, &v)) {
- yyerror("missing '");
- ungetc(v);
- }
- yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
- mpmovecfix(yylval.val.u.xval, v);
- yylval.val.ctype = CTINT;
- DBG("lex: codepoint literal\n");
- return LLITERAL;
-
- case '/':
- c1 = getc();
- if(c1 == '*') {
- int nl;
-
- nl = 0;
- for(;;) {
- c = getr();
- if(c == '\n')
- nl = 1;
- while(c == '*') {
- c = getr();
- if(c == '/') {
- if(nl)
- ungetc('\n');
- goto l0;
- }
- if(c == '\n')
- nl = 1;
- }
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
- }
- }
- if(c1 == '/') {
- c = getlinepragma();
- for(;;) {
- if(c == '\n' || c == EOF) {
- ungetc(c);
- goto l0;
- }
- c = getr();
- }
- }
- if(c1 == '=') {
- c = ODIV;
- goto asop;
- }
- break;
-
- case ':':
- c1 = getc();
- if(c1 == '=') {
- c = LCOLAS;
- goto lx;
- }
- break;
-
- case '*':
- c1 = getc();
- if(c1 == '=') {
- c = OMUL;
- goto asop;
- }
- break;
-
- case '%':
- c1 = getc();
- if(c1 == '=') {
- c = OMOD;
- goto asop;
- }
- break;
-
- case '+':
- c1 = getc();
- if(c1 == '+') {
- c = LINC;
- goto lx;
- }
- if(c1 == '=') {
- c = OADD;
- goto asop;
- }
- break;
-
- case '-':
- c1 = getc();
- if(c1 == '-') {
- c = LDEC;
- goto lx;
- }
- if(c1 == '=') {
- c = OSUB;
- goto asop;
- }
- break;
-
- case '>':
- c1 = getc();
- if(c1 == '>') {
- c = LRSH;
- c1 = getc();
- if(c1 == '=') {
- c = ORSH;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = LGE;
- goto lx;
- }
- c = LGT;
- break;
-
- case '<':
- c1 = getc();
- if(c1 == '<') {
- c = LLSH;
- c1 = getc();
- if(c1 == '=') {
- c = OLSH;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = LLE;
- goto lx;
- }
- if(c1 == '-') {
- c = LCOMM;
- goto lx;
- }
- c = LLT;
- break;
-
- case '=':
- c1 = getc();
- if(c1 == '=') {
- c = LEQ;
- goto lx;
- }
- break;
-
- case '!':
- c1 = getc();
- if(c1 == '=') {
- c = LNE;
- goto lx;
- }
- break;
-
- case '&':
- c1 = getc();
- if(c1 == '&') {
- c = LANDAND;
- goto lx;
- }
- if(c1 == '^') {
- c = LANDNOT;
- c1 = getc();
- if(c1 == '=') {
- c = OANDNOT;
- goto asop;
- }
- break;
- }
- if(c1 == '=') {
- c = OAND;
- goto asop;
- }
- break;
-
- case '|':
- c1 = getc();
- if(c1 == '|') {
- c = LOROR;
- goto lx;
- }
- if(c1 == '=') {
- c = OOR;
- goto asop;
- }
- break;
-
- case '^':
- c1 = getc();
- if(c1 == '=') {
- c = OXOR;
- goto asop;
- }
- break;
-
- /*
- * clumsy dance:
- * to implement rule that disallows
- * if T{1}[0] { ... }
- * but allows
- * if (T{1}[0]) { ... }
- * the block bodies for if/for/switch/select
- * begin with an LBODY token, not '{'.
- *
- * when we see the keyword, the next
- * non-parenthesized '{' becomes an LBODY.
- * loophack is normally 0.
- * a keyword makes it go up to 1.
- * parens push loophack onto a stack and go back to 0.
- * a '{' with loophack == 1 becomes LBODY and disables loophack.
- *
- * i said it was clumsy.
- */
- case '(':
- case '[':
- if(loophack || lstk != nil) {
- h = malloc(sizeof *h);
- h->v = loophack;
- h->next = lstk;
- lstk = h;
- loophack = 0;
- }
- goto lx;
- case ')':
- case ']':
- if(lstk != nil) {
- h = lstk;
- loophack = h->v;
- lstk = h->next;
- free(h);
- }
- goto lx;
- case '{':
- if(loophack == 1) {
- DBG("%L lex: LBODY\n", lexlineno);
- loophack = 0;
- return LBODY;
- }
- goto lx;
-
- default:
- goto lx;
- }
- ungetc(c1);
-
-lx:
- if(c > 0xff)
- DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
- else
- DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
- if(isfrog(c)) {
- yyerror("illegal character 0x%ux", c);
- goto l0;
- }
- if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
- yyerror("%s: unexpected %c", "syntax error", c);
- goto l0;
- }
- return c;
-
-asop:
- yylval.lint = c; // rathole to hold which asop
- DBG("lex: TOKEN ASOP %c\n", c);
- return LASOP;
-
-talph:
- /*
- * cp is set to lexbuf and some
- * prefix has been stored
- */
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- if(c >= Runeself) {
- ungetc(c);
- rune = getr();
- // 0xb7 · is used for internal names
- if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
- yyerror("invalid identifier character 0x%ux", rune);
- cp += runetochar(cp, &rune);
- } else if(!yy_isalnum(c) && c != '_')
- break;
- else
- *cp++ = c;
- c = getc();
- }
- *cp = 0;
- ungetc(c);
-
- s = lookup(lexbuf);
- switch(s->lexical) {
- case LIGNORE:
- goto l0;
-
- case LFOR:
- case LIF:
- case LSWITCH:
- case LSELECT:
- loophack = 1; // see comment about loophack above
- break;
- }
-
- DBG("lex: %S %s\n", s, lexname(s->lexical));
- yylval.sym = s;
- return s->lexical;
-
-tnum:
- c1 = 0;
- cp = lexbuf;
- ep = lexbuf+sizeof lexbuf;
- if(c != '0') {
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(yy_isdigit(c))
- continue;
- goto dc;
- }
- }
- *cp++ = c;
- c = getc();
- if(c == 'x' || c == 'X') {
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(yy_isdigit(c))
- continue;
- if(c >= 'a' && c <= 'f')
- continue;
- if(c >= 'A' && c <= 'F')
- continue;
- if(cp == lexbuf+2)
- yyerror("malformed hex constant");
- goto ncu;
- }
- }
-
- if(c == 'p') // 0p begins floating point zero
- goto casep;
-
- c1 = 0;
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- if(!yy_isdigit(c))
- break;
- if(c < '0' || c > '7')
- c1 = 1; // not octal
- *cp++ = c;
- c = getc();
- }
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
- if(c == 'i')
- goto casei;
- if(c1)
- yyerror("malformed octal constant");
- goto ncu;
-
-dc:
- if(c == '.')
- goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
- if(c == 'p' || c == 'P')
- goto casep;
- if(c == 'i')
- goto casei;
-
-ncu:
- *cp = 0;
- ungetc(c);
-
- yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
- mpatofix(yylval.val.u.xval, lexbuf);
- if(yylval.val.u.xval->ovf) {
- yyerror("overflow in constant");
- mpmovecfix(yylval.val.u.xval, 0);
- }
- yylval.val.ctype = CTINT;
- DBG("lex: integer literal\n");
- return LLITERAL;
-
-casedot:
- for(;;) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- if(!yy_isdigit(c))
- break;
- }
- if(c == 'i')
- goto casei;
- if(c != 'e' && c != 'E')
- goto caseout;
-
-casee:
- *cp++ = 'e';
- c = getc();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = getc();
- }
- if(!yy_isdigit(c))
- yyerror("malformed fp constant exponent");
- while(yy_isdigit(c)) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- }
- if(c == 'i')
- goto casei;
- goto caseout;
-
-casep:
- *cp++ = 'p';
- c = getc();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = getc();
- }
- if(!yy_isdigit(c))
- yyerror("malformed fp constant exponent");
- while(yy_isdigit(c)) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- }
- if(c == 'i')
- goto casei;
- goto caseout;
-
-casei:
- // imaginary constant
- *cp = 0;
- yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
- mpmovecflt(&yylval.val.u.cval->real, 0.0);
- mpatoflt(&yylval.val.u.cval->imag, lexbuf);
- if(yylval.val.u.cval->imag.val.ovf) {
- yyerror("overflow in imaginary constant");
- mpmovecflt(&yylval.val.u.cval->real, 0.0);
- }
- yylval.val.ctype = CTCPLX;
- DBG("lex: imaginary literal\n");
- return LLITERAL;
-
-caseout:
- *cp = 0;
- ungetc(c);
-
- yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
- mpatoflt(yylval.val.u.fval, lexbuf);
- if(yylval.val.u.fval->val.ovf) {
- yyerror("overflow in float constant");
- mpmovecflt(yylval.val.u.fval, 0.0);
- }
- yylval.val.ctype = CTFLT;
- DBG("lex: floating literal\n");
- return LLITERAL;
-}
-
-/*
- * read and interpret syntax that looks like
- * //line parse.y:15
- * as a discontinuity in sequential line numbers.
- * the next line of input comes from parse.y:15
- */
-static int
-getlinepragma(void)
-{
- int i, c, n;
- char *cp, *ep;
- Hist *h;
-
- for(i=0; i<5; i++) {
- c = getr();
- if(c != "line "[i])
- goto out;
- }
-
- cp = lexbuf;
- ep = lexbuf+sizeof(lexbuf)-5;
- for(;;) {
- c = getr();
- if(c == '\n' || c == EOF)
- goto out;
- if(c == ' ')
- continue;
- if(c == ':')
- break;
- if(cp < ep)
- *cp++ = c;
- }
- *cp = 0;
-
- n = 0;
- for(;;) {
- c = getr();
- if(!yy_isdigit(c))
- break;
- n = n*10 + (c-'0');
- if(n > 1e8) {
- yyerror("line number out of range");
- errorexit();
- }
- }
-
- if(c != '\n' || n <= 0)
- goto out;
-
- // try to avoid allocating file name over and over
- for(h=hist; h!=H; h=h->link) {
- if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
- linehist(h->name, n, 0);
- goto out;
- }
- }
- linehist(strdup(lexbuf), n, 0);
-
-out:
- return c;
-}
-
-int32
-yylex(void)
-{
- int lx;
-
- lx = _yylex();
-
- if(curio.nlsemi && lx == EOF) {
- // Treat EOF as "end of line" for the purposes
- // of inserting a semicolon.
- lx = ';';
- }
-
- switch(lx) {
- case LNAME:
- case LLITERAL:
- case LBREAK:
- case LCONTINUE:
- case LFALL:
- case LRETURN:
- case LINC:
- case LDEC:
- case ')':
- case '}':
- case ']':
- curio.nlsemi = 1;
- break;
- default:
- curio.nlsemi = 0;
- break;
- }
-
- // Track last two tokens returned by yylex.
- yyprev = yylast;
- yylast = lx;
- return lx;
-}
-
-static int
-getc(void)
-{
- int c;
-
- c = curio.peekc;
- if(c != 0) {
- curio.peekc = curio.peekc1;
- curio.peekc1 = 0;
- if(c == '\n' && pushedio.bin == nil)
- lexlineno++;
- return c;
- }
-
- if(curio.bin == nil) {
- c = *curio.cp & 0xff;
- if(c != 0)
- curio.cp++;
- } else
- c = Bgetc(curio.bin);
-
- switch(c) {
- case 0:
- if(curio.bin != nil) {
- yyerror("illegal NUL byte");
- break;
- }
- case EOF:
- // insert \n at EOF
- if(curio.eofnl)
- return EOF;
- curio.eofnl = 1;
- c = '\n';
- case '\n':
- if(pushedio.bin == nil)
- lexlineno++;
- break;
- }
- return c;
-}
-
-static void
-ungetc(int c)
-{
- curio.peekc1 = curio.peekc;
- curio.peekc = c;
- if(c == '\n' && pushedio.bin == nil)
- lexlineno--;
-}
-
-static int32
-getr(void)
-{
- int c, i;
- char str[UTFmax+1];
- Rune rune;
-
- c = getc();
- if(c < Runeself)
- return c;
- i = 0;
- str[i++] = c;
-
-loop:
- c = getc();
- str[i++] = c;
- if(!fullrune(str, i))
- goto loop;
- c = chartorune(&rune, str);
- if(rune == Runeerror && c == 1) {
- lineno = lexlineno;
- yyerror("illegal UTF-8 sequence");
- flusherrors();
- print("\t");
- for(c=0; c<i; c++)
- print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
- print("\n");
- }
- return rune;
-}
-
-static int
-escchar(int e, int *escflg, vlong *val)
-{
- int i, u, c;
- vlong l;
-
- *escflg = 0;
-
- c = getr();
- switch(c) {
- case EOF:
- yyerror("eof in string");
- return 1;
- case '\n':
- yyerror("newline in string");
- return 1;
- case '\\':
- break;
- default:
- if(c == e)
- return 1;
- *val = c;
- return 0;
- }
-
- u = 0;
- c = getr();
- switch(c) {
- case 'x':
- *escflg = 1; // it's a byte
- i = 2;
- goto hex;
-
- case 'u':
- i = 4;
- u = 1;
- goto hex;
-
- case 'U':
- i = 8;
- u = 1;
- goto hex;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- *escflg = 1; // it's a byte
- goto oct;
-
- case 'a': c = '\a'; break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'v': c = '\v'; break;
- case '\\': c = '\\'; break;
-
- default:
- if(c != e)
- yyerror("unknown escape sequence: %c", c);
- }
- *val = c;
- return 0;
-
-hex:
- l = 0;
- for(; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '9') {
- l = l*16 + c-'0';
- continue;
- }
- if(c >= 'a' && c <= 'f') {
- l = l*16 + c-'a' + 10;
- continue;
- }
- if(c >= 'A' && c <= 'F') {
- l = l*16 + c-'A' + 10;
- continue;
- }
- yyerror("non-hex character in escape sequence: %c", c);
- ungetc(c);
- break;
- }
- if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
- yyerror("invalid Unicode code point in escape sequence: %#llx", l);
- l = Runeerror;
- }
- *val = l;
- return 0;
-
-oct:
- l = c - '0';
- for(i=2; i>0; i--) {
- c = getc();
- if(c >= '0' && c <= '7') {
- l = l*8 + c-'0';
- continue;
- }
- yyerror("non-octal character in escape sequence: %c", c);
- ungetc(c);
- }
- if(l > 255)
- yyerror("octal escape value > 255: %d", l);
-
- *val = l;
- return 0;
-}
-
-static struct
-{
- char* name;
- int lexical;
- int etype;
- int op;
-} syms[] =
-{
-/* name lexical etype op
- */
-/* basic types */
- "int8", LNAME, TINT8, OXXX,
- "int16", LNAME, TINT16, OXXX,
- "int32", LNAME, TINT32, OXXX,
- "int64", LNAME, TINT64, OXXX,
-
- "uint8", LNAME, TUINT8, OXXX,
- "uint16", LNAME, TUINT16, OXXX,
- "uint32", LNAME, TUINT32, OXXX,
- "uint64", LNAME, TUINT64, OXXX,
-
- "float32", LNAME, TFLOAT32, OXXX,
- "float64", LNAME, TFLOAT64, OXXX,
-
- "complex64", LNAME, TCOMPLEX64, OXXX,
- "complex128", LNAME, TCOMPLEX128, OXXX,
-
- "bool", LNAME, TBOOL, OXXX,
- "byte", LNAME, TUINT8, OXXX,
- "string", LNAME, TSTRING, OXXX,
-
- "any", LNAME, TANY, OXXX,
-
- "break", LBREAK, Txxx, OXXX,
- "case", LCASE, Txxx, OXXX,
- "chan", LCHAN, Txxx, OXXX,
- "const", LCONST, Txxx, OXXX,
- "continue", LCONTINUE, Txxx, OXXX,
- "default", LDEFAULT, Txxx, OXXX,
- "else", LELSE, Txxx, OXXX,
- "defer", LDEFER, Txxx, OXXX,
- "fallthrough", LFALL, Txxx, OXXX,
- "for", LFOR, Txxx, OXXX,
- "func", LFUNC, Txxx, OXXX,
- "go", LGO, Txxx, OXXX,
- "goto", LGOTO, Txxx, OXXX,
- "if", LIF, Txxx, OXXX,
- "import", LIMPORT, Txxx, OXXX,
- "interface", LINTERFACE, Txxx, OXXX,
- "map", LMAP, Txxx, OXXX,
- "package", LPACKAGE, Txxx, OXXX,
- "range", LRANGE, Txxx, OXXX,
- "return", LRETURN, Txxx, OXXX,
- "select", LSELECT, Txxx, OXXX,
- "struct", LSTRUCT, Txxx, OXXX,
- "switch", LSWITCH, Txxx, OXXX,
- "type", LTYPE, Txxx, OXXX,
- "var", LVAR, Txxx, OXXX,
-
- "append", LNAME, Txxx, OAPPEND,
- "cap", LNAME, Txxx, OCAP,
- "close", LNAME, Txxx, OCLOSE,
- "complex", LNAME, Txxx, OCOMPLEX,
- "copy", LNAME, Txxx, OCOPY,
- "imag", LNAME, Txxx, OIMAG,
- "len", LNAME, Txxx, OLEN,
- "make", LNAME, Txxx, OMAKE,
- "new", LNAME, Txxx, ONEW,
- "panic", LNAME, Txxx, OPANIC,
- "print", LNAME, Txxx, OPRINT,
- "println", LNAME, Txxx, OPRINTN,
- "real", LNAME, Txxx, OREAL,
- "recover", LNAME, Txxx, ORECOVER,
-
- "notwithstanding", LIGNORE, Txxx, OXXX,
- "thetruthofthematter", LIGNORE, Txxx, OXXX,
- "despiteallobjections", LIGNORE, Txxx, OXXX,
- "whereas", LIGNORE, Txxx, OXXX,
- "insofaras", LIGNORE, Txxx, OXXX,
-};
-
-static void
-lexinit(void)
-{
- int i, lex;
- Sym *s, *s1;
- Type *t;
- int etype;
-
- /*
- * initialize basic types array
- * initialize known symbols
- */
- for(i=0; i<nelem(syms); i++) {
- lex = syms[i].lexical;
- s = lookup(syms[i].name);
- s->lexical = lex;
-
- etype = syms[i].etype;
- if(etype != Txxx) {
- if(etype < 0 || etype >= nelem(types))
- fatal("lexinit: %s bad etype", s->name);
- t = types[etype];
- if(t == T) {
- t = typ(etype);
- t->sym = s;
-
- if(etype != TANY && etype != TSTRING)
- dowidth(t);
- types[etype] = t;
- }
- s1 = pkglookup(syms[i].name, builtinpkg);
- s1->lexical = LNAME;
- s1->def = typenod(t);
- continue;
- }
- }
-
- // logically, the type of a string literal.
- // types[TSTRING] is the named type string
- // (the type of x in var x string or var x = "hello").
- // this is the ideal form
- // (the type of x in const x = "hello").
- idealstring = typ(TSTRING);
- idealbool = typ(TBOOL);
-
- s = pkglookup("true", builtinpkg);
- s->def = nodbool(1);
- s->def->sym = lookup("true");
- s->def->type = idealbool;
-
- s = pkglookup("false", builtinpkg);
- s->def = nodbool(0);
- s->def->sym = lookup("false");
- s->def->type = idealbool;
-
- s = lookup("_");
- s->block = -100;
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- types[TBLANK] = typ(TBLANK);
- s->def->type = types[TBLANK];
- nblank = s->def;
-}
-
-static void
-lexfini(void)
-{
- Sym *s;
- int lex, etype, i;
- Val v;
-
- for(i=0; i<nelem(syms); i++) {
- lex = syms[i].lexical;
- if(lex != LNAME)
- continue;
- s = lookup(syms[i].name);
- s->lexical = lex;
-
- etype = syms[i].etype;
- if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N)
- s->def = typenod(types[etype]);
-
- etype = syms[i].op;
- if(etype != OXXX && s->def == N) {
- s->def = nod(ONAME, N, N);
- s->def->sym = s;
- s->def->etype = etype;
- s->def->builtin = 1;
- }
- }
-
- for(i=0; typedefs[i].name; i++) {
- s = lookup(typedefs[i].name);
- if(s->def == N)
- s->def = typenod(types[typedefs[i].etype]);
- }
-
- // there's only so much table-driven we can handle.
- // these are special cases.
- types[TNIL] = typ(TNIL);
- s = lookup("nil");
- if(s->def == N) {
- v.ctype = CTNIL;
- s->def = nodlit(v);
- s->def->sym = s;
- }
-
- s = lookup("iota");
- if(s->def == N) {
- s->def = nod(OIOTA, N, N);
- s->def->sym = s;
- }
-
- s = lookup("true");
- if(s->def == N) {
- s->def = nodbool(1);
- s->def->sym = s;
- }
-
- s = lookup("false");
- if(s->def == N) {
- s->def = nodbool(0);
- s->def->sym = s;
- }
-
- nodfp = nod(ONAME, N, N);
- nodfp->noescape = 1;
- nodfp->type = types[TINT32];
- nodfp->xoffset = 0;
- nodfp->class = PPARAM;
- nodfp->sym = lookup(".fp");
-}
-
-struct
-{
- int lex;
- char* name;
-} lexn[] =
-{
- LANDAND, "ANDAND",
- LASOP, "ASOP",
- LBREAK, "BREAK",
- LCASE, "CASE",
- LCHAN, "CHAN",
- LCOLAS, "COLAS",
- LCONST, "CONST",
- LCONTINUE, "CONTINUE",
- LDEC, "DEC",
- LDEFER, "DEFER",
- LELSE, "ELSE",
- LEQ, "EQ",
- LFALL, "FALL",
- LFOR, "FOR",
- LFUNC, "FUNC",
- LGE, "GE",
- LGO, "GO",
- LGOTO, "GOTO",
- LGT, "GT",
- LIF, "IF",
- LIMPORT, "IMPORT",
- LINC, "INC",
- LINTERFACE, "INTERFACE",
- LLE, "LE",
- LLITERAL, "LITERAL",
- LLSH, "LSH",
- LLT, "LT",
- LMAP, "MAP",
- LNAME, "NAME",
- LNE, "NE",
- LOROR, "OROR",
- LPACKAGE, "PACKAGE",
- LRANGE, "RANGE",
- LRETURN, "RETURN",
- LRSH, "RSH",
- LSTRUCT, "STRUCT",
- LSWITCH, "SWITCH",
- LTYPE, "TYPE",
- LVAR, "VAR",
-};
-
-char*
-lexname(int lex)
-{
- int i;
- static char buf[100];
-
- for(i=0; i<nelem(lexn); i++)
- if(lexn[i].lex == lex)
- return lexn[i].name;
- snprint(buf, sizeof(buf), "LEX-%d", lex);
- return buf;
-}
-
-struct
-{
- char *have;
- char *want;
-} yytfix[] =
-{
- "$end", "EOF",
- "LLITERAL", "literal",
- "LASOP", "op=",
- "LBREAK", "break",
- "LCASE", "case",
- "LCOLAS", ":=",
- "LCONST", "const",
- "LCONTINUE", "continue",
- "LDDD", "...",
- "LDEFAULT", "default",
- "LDEFER", "defer",
- "LELSE", "else",
- "LFALL", "fallthrough",
- "LFOR", "for",
- "LFUNC", "func",
- "LGO", "go",
- "LGOTO", "goto",
- "LIF", "if",
- "LIMPORT", "import",
- "LINTERFACE", "interface",
- "LMAP", "map",
- "LNAME", "name",
- "LPACKAGE", "package",
- "LRANGE", "range",
- "LRETURN", "return",
- "LSELECT", "select",
- "LSTRUCT", "struct",
- "LSWITCH", "switch",
- "LTYPE", "type",
- "LVAR", "var",
- "LANDAND", "&&",
- "LANDNOT", "&^",
- "LBODY", "{",
- "LCOMM", "<-",
- "LDEC", "--",
- "LINC", "++",
- "LEQ", "==",
- "LGE", ">=",
- "LGT", ">",
- "LLE", "<=",
- "LLT", "<",
- "LLSH", "<<",
- "LRSH", ">>",
- "LOROR", "||",
- "LNE", "!=",
-
- // spell out to avoid confusion with punctuation in error messages
- "';'", "semicolon or newline",
- "','", "comma",
-};
-
-static void
-yytinit(void)
-{
- int i, j;
- extern char *yytname[];
- char *s, *t;
-
- for(i=0; yytname[i] != nil; i++) {
- s = yytname[i];
-
- // apply yytfix if possible
- for(j=0; j<nelem(yytfix); j++) {
- if(strcmp(s, yytfix[j].have) == 0) {
- yytname[i] = yytfix[j].want;
- goto loop;
- }
- }
-
- // turn 'x' into x.
- if(s[0] == '\'') {
- t = strdup(s+1);
- t[strlen(t)-1] = '\0';
- yytname[i] = t;
- }
- loop:;
- }
-}
-
-void
-mkpackage(char* pkgname)
-{
- Sym *s;
- int32 h;
- char *p;
-
- if(localpkg->name == nil) {
- if(strcmp(pkgname, "_") == 0)
- yyerror("invalid package name _");
- localpkg->name = pkgname;
- } else {
- if(strcmp(pkgname, localpkg->name) != 0)
- yyerror("package %s; expected %s", pkgname, localpkg->name);
- for(h=0; h<NHASH; h++) {
- for(s = hash[h]; s != S; s = s->link) {
- if(s->def == N || s->pkg != localpkg)
- continue;
- if(s->def->op == OPACK) {
- // throw away top-level package name leftover
- // from previous file.
- // leave s->block set to cause redeclaration
- // errors if a conflicting top-level name is
- // introduced by a different file.
- if(!s->def->used && !nsyntaxerrors)
- yyerrorl(s->def->lineno, "imported and not used: %Z", s->def->pkg->path);
- s->def = N;
- continue;
- }
- if(s->def->sym != s) {
- // throw away top-level name left over
- // from previous import . "x"
- if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
- yyerrorl(s->def->pack->lineno, "imported and not used: %Z", s->def->pack->pkg->path);
- s->def->pack->used = 1;
- }
- s->def = N;
- continue;
- }
- }
- }
- }
-
- if(outfile == nil) {
- p = strrchr(infile, '/');
- if(p == nil)
- p = infile;
- else
- p = p+1;
- snprint(namebuf, sizeof(namebuf), "%s", p);
- p = strrchr(namebuf, '.');
- if(p != nil)
- *p = 0;
- outfile = smprint("%s.%c", namebuf, thechar);
- }
-}
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
deleted file mode 100644
index 7cea1a6cf..000000000
--- a/src/cmd/gc/md5.c
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// 64-bit MD5 (does full MD5 but returns 64 bits only).
-// Translation of ../../pkg/crypto/md5/md5*.go.
-
-#include "go.h"
-#include "md5.h"
-
-static int md5block(MD5 *dig, uchar *p, int nn);
-
-enum {
- _Chunk = 64
-};
-
-#define _Init0 0x67452301
-#define _Init1 0xEFCDAB89
-#define _Init2 0x98BADCFE
-#define _Init3 0x10325476
-
-void
-md5reset(MD5 *d)
-{
- d->s[0] = _Init0;
- d->s[1] = _Init1;
- d->s[2] = _Init2;
- d->s[3] = _Init3;
- d->nx = 0;
- d->len = 0;
-}
-
-void
-md5write(MD5 *d, uchar *p, int nn)
-{
- int i, n;
-
- d->len += nn;
- if(d->nx > 0) {
- n = nn;
- if(n > _Chunk - d->nx)
- n = _Chunk - d->nx;
- for(i=0; i<n; i++)
- d->x[d->nx+i] = p[i];
- d->nx += n;
- if(d->nx == _Chunk) {
- md5block(d, d->x, _Chunk);
- d->nx = 0;
- }
- p += n;
- nn -= n;
- }
- n = md5block(d, p, nn);
- p += n;
- nn -= n;
- if(nn > 0) {
- for(i=0; i<nn; i++)
- d->x[i] = p[i];
- d->nx = nn;
- }
-}
-
-uint64
-md5sum(MD5 *d)
-{
- uchar tmp[64];
- int i;
- uint64 len;
-
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
- len = d->len;
- memset(tmp, 0, sizeof tmp);
- tmp[0] = 0x80;
- if(len%64 < 56)
- md5write(d, tmp, 56-len%64);
- else
- md5write(d, tmp, 64+56-len%64);
-
- // Length in bits.
- len <<= 3;
- for(i=0; i<8; i++)
- tmp[i] = len>>(8*i);
- md5write(d, tmp, 8);
-
- if(d->nx != 0)
- fatal("md5sum");
-
- return d->s[0] | ((uint64)d->s[1]<<32);
-}
-
-
-// MD5 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
-// table[i] = int((1<<32) * abs(sin(i+1 radians))).
-static uint32 table[64] = {
- // round 1
- 0xd76aa478,
- 0xe8c7b756,
- 0x242070db,
- 0xc1bdceee,
- 0xf57c0faf,
- 0x4787c62a,
- 0xa8304613,
- 0xfd469501,
- 0x698098d8,
- 0x8b44f7af,
- 0xffff5bb1,
- 0x895cd7be,
- 0x6b901122,
- 0xfd987193,
- 0xa679438e,
- 0x49b40821,
-
- // round 2
- 0xf61e2562,
- 0xc040b340,
- 0x265e5a51,
- 0xe9b6c7aa,
- 0xd62f105d,
- 0x2441453,
- 0xd8a1e681,
- 0xe7d3fbc8,
- 0x21e1cde6,
- 0xc33707d6,
- 0xf4d50d87,
- 0x455a14ed,
- 0xa9e3e905,
- 0xfcefa3f8,
- 0x676f02d9,
- 0x8d2a4c8a,
-
- // round3
- 0xfffa3942,
- 0x8771f681,
- 0x6d9d6122,
- 0xfde5380c,
- 0xa4beea44,
- 0x4bdecfa9,
- 0xf6bb4b60,
- 0xbebfbc70,
- 0x289b7ec6,
- 0xeaa127fa,
- 0xd4ef3085,
- 0x4881d05,
- 0xd9d4d039,
- 0xe6db99e5,
- 0x1fa27cf8,
- 0xc4ac5665,
-
- // round 4
- 0xf4292244,
- 0x432aff97,
- 0xab9423a7,
- 0xfc93a039,
- 0x655b59c3,
- 0x8f0ccc92,
- 0xffeff47d,
- 0x85845dd1,
- 0x6fa87e4f,
- 0xfe2ce6e0,
- 0xa3014314,
- 0x4e0811a1,
- 0xf7537e82,
- 0xbd3af235,
- 0x2ad7d2bb,
- 0xeb86d391,
-};
-
-static uint32 shift1[] = { 7, 12, 17, 22 };
-static uint32 shift2[] = { 5, 9, 14, 20 };
-static uint32 shift3[] = { 4, 11, 16, 23 };
-static uint32 shift4[] = { 6, 10, 15, 21 };
-
-static int
-md5block(MD5 *dig, uchar *p, int nn)
-{
- uint32 a, b, c, d, aa, bb, cc, dd;
- int i, j, n;
- uint32 X[16];
-
- a = dig->s[0];
- b = dig->s[1];
- c = dig->s[2];
- d = dig->s[3];
- n = 0;
-
- while(nn >= _Chunk) {
- aa = a;
- bb = b;
- cc = c;
- dd = d;
-
- for(i=0; i<16; i++) {
- j = i*4;
- X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | (p[j+3]<<24);
- }
-
- // Round 1.
- for(i=0; i<16; i++) {
- uint32 x, t, s, f;
- x = i;
- t = i;
- s = shift1[i%4];
- f = ((c ^ d) & b) ^ d;
- a += f + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 2.
- for(i=0; i<16; i++) {
- uint32 x, t, s, g;
-
- x = (1+5*i)%16;
- t = 16+i;
- s = shift2[i%4];
- g = ((b ^ c) & d) ^ c;
- a += g + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 3.
- for(i=0; i<16; i++) {
- uint32 x, t, s, h;
-
- x = (5+3*i)%16;
- t = 32+i;
- s = shift3[i%4];
- h = b ^ c ^ d;
- a += h + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- // Round 4.
- for(i=0; i<16; i++) {
- uint32 x, s, t, ii;
-
- x = (7*i)%16;
- s = shift4[i%4];
- t = 48+i;
- ii = c ^ (b | ~d);
- a += ii + X[x] + table[t];
- a = a<<s | a>>(32-s);
- a += b;
-
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
-
- a += aa;
- b += bb;
- c += cc;
- d += dd;
-
- p += _Chunk;
- n += _Chunk;
- nn -= _Chunk;
- }
-
- dig->s[0] = a;
- dig->s[1] = b;
- dig->s[2] = c;
- dig->s[3] = d;
- return n;
-}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
deleted file mode 100644
index f153e30f2..000000000
--- a/src/cmd/gc/md5.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-typedef struct MD5 MD5;
-struct MD5
-{
- uint32 s[4];
- uchar x[64];
- int nx;
- uint64 len;
-};
-
-void md5reset(MD5*);
-void md5write(MD5*, uchar*, int);
-uint64 md5sum(MD5*);
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
deleted file mode 100755
index 4dfff1caa..000000000
--- a/src/cmd/gc/mkbuiltin
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Generate builtin.c and builtin.c.boot from $* (runtime.go and unsafe.go).
-# Run this after changing runtime.go and unsafe.go
-# or after changing the export metadata format in the compiler.
-# Either way, you need to have a working compiler binary first.
-
-set -e
-
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-if [ -z "$GC" ]; then
- echo 'missing $GC - gomake failed?' 1>&2
- exit 1
-fi
-
-gcc -o mkbuiltin1 mkbuiltin1.c
-rm -f _builtin.c
-for i in runtime unsafe
-do
- $GC -A $i.go
- O=$O ./mkbuiltin1 $i >>_builtin.c
-done
-
-# If _builtin.c has changed vs builtin.c.boot,
-# check in the new change.
-cmp -s _builtin.c builtin.c.boot || cp _builtin.c builtin.c.boot
-
-mv _builtin.c builtin.c
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
deleted file mode 100644
index aa28e295b..000000000
--- a/src/cmd/gc/mkbuiltin1.c
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Compile .go file, import data from .6 file, and generate C string version.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-void esc(char*);
-
-int
-main(int argc, char **argv)
-{
- char *name;
- FILE *fin;
- char buf[1024], initfunc[1024], *p, *q;
-
- if(argc != 2) {
- fprintf(stderr, "usage: mkbuiltin1 sys\n");
- fprintf(stderr, "in file $1.6 s/PACKAGE/$1/\n");
- exit(1);
- }
-
- name = argv[1];
- snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
-
- snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
- if((fin = fopen(buf, "r")) == NULL) {
- fprintf(stderr, "open %s: %s\n", buf, strerror(errno));
- exit(1);
- }
-
- // look for $$ that introduces imports
- while(fgets(buf, sizeof buf, fin) != NULL)
- if(strstr(buf, "$$"))
- goto begin;
- fprintf(stderr, "did not find beginning of imports\n");
- exit(1);
-
-begin:
- printf("char *%simport =\n", name);
-
- // process imports, stopping at $$ that closes them
- while(fgets(buf, sizeof buf, fin) != NULL) {
- buf[strlen(buf)-1] = 0; // chop \n
- if(strstr(buf, "$$"))
- goto end;
-
- // chop leading white space
- for(p=buf; *p==' ' || *p == '\t'; p++)
- ;
-
- // cut out decl of init_$1_function - it doesn't exist
- if(strstr(buf, initfunc))
- continue;
-
- // sys.go claims to be in package PACKAGE to avoid
- // conflicts during "6g sys.go". rename PACKAGE to $2.
- printf("\t\"");
- while(q = strstr(p, "PACKAGE")) {
- *q = 0;
- esc(p); // up to the substitution
- printf("%s", name); // the sub name
- p = q+7; // continue with rest
- }
-
- esc(p);
- printf("\\n\"\n", p);
- }
- fprintf(stderr, "did not find end of imports\n");
- exit(1);
-
-end:
- printf("\t\"$$\\n\";\n");
- return 0;
-}
-
-void
-esc(char *p)
-{
- for(; *p; p++) {
- if(*p == '\\' || *p == '\"')
- printf("\\");
- putchar(*p);
- }
-}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
deleted file mode 100755
index fb2ceec81..000000000
--- a/src/cmd/gc/mkopnames
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Disable colored grep if user has it set to --color=always.
-# (Arguably user error.)
-export GREP_OPTIONS=""
-
-echo '// auto generated by mkopnames'
-echo 'static char*'
-echo 'opnames[] = '
-echo '{'
-sed -n '/OXXX/,/OEND/p' go.h |
- cpp |
- sed 's!//.*!!; /^#/d' |
- tr ' ' '\n' |
- tr -d ' \t,' |
- grep . |
- sort |
- grep -v '^OEND$' |
- sed 's/O//; s/.*/ [O&] = "&",/'
-echo '};'
-
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
deleted file mode 100644
index 6cd4e2500..000000000
--- a/src/cmd/gc/mparith1.c
+++ /dev/null
@@ -1,509 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/// uses arithmetic
-
-int
-mpcmpfixflt(Mpint *a, Mpflt *b)
-{
- char buf[500];
- Mpflt c;
-
- snprint(buf, sizeof(buf), "%B", a);
- mpatoflt(&c, buf);
- return mpcmpfltflt(&c, b);
-}
-
-int
-mpcmpfltfix(Mpflt *a, Mpint *b)
-{
- char buf[500];
- Mpflt c;
-
- snprint(buf, sizeof(buf), "%B", b);
- mpatoflt(&c, buf);
- return mpcmpfltflt(a, &c);
-}
-
-int
-mpcmpfixfix(Mpint *a, Mpint *b)
-{
- Mpint c;
-
- mpmovefixfix(&c, a);
- mpsubfixfix(&c, b);
- return mptestfix(&c);
-}
-
-int
-mpcmpfixc(Mpint *b, vlong c)
-{
- Mpint a;
-
- mpmovecfix(&a, c);
- return mpcmpfixfix(&a, b);
-}
-
-int
-mpcmpfltflt(Mpflt *a, Mpflt *b)
-{
- Mpflt c;
-
- mpmovefltflt(&c, a);
- mpsubfltflt(&c, b);
- return mptestflt(&c);
-}
-
-int
-mpcmpfltc(Mpflt *b, double c)
-{
- Mpflt a;
-
- mpmovecflt(&a, c);
- return mpcmpfltflt(&a, b);
-}
-
-void
-mpsubfixfix(Mpint *a, Mpint *b)
-{
- mpnegfix(a);
- mpaddfixfix(a, b);
- mpnegfix(a);
-}
-
-void
-mpsubfltflt(Mpflt *a, Mpflt *b)
-{
- mpnegflt(a);
- mpaddfltflt(a, b);
- mpnegflt(a);
-}
-
-void
-mpaddcfix(Mpint *a, vlong c)
-{
- Mpint b;
-
- mpmovecfix(&b, c);
- mpaddfixfix(a, &b);
-}
-
-void
-mpaddcflt(Mpflt *a, double c)
-{
- Mpflt b;
-
- mpmovecflt(&b, c);
- mpaddfltflt(a, &b);
-}
-
-void
-mpmulcfix(Mpint *a, vlong c)
-{
- Mpint b;
-
- mpmovecfix(&b, c);
- mpmulfixfix(a, &b);
-}
-
-void
-mpmulcflt(Mpflt *a, double c)
-{
- Mpflt b;
-
- mpmovecflt(&b, c);
- mpmulfltflt(a, &b);
-}
-
-void
-mpdivfixfix(Mpint *a, Mpint *b)
-{
- Mpint q, r;
-
- mpdivmodfixfix(&q, &r, a, b);
- mpmovefixfix(a, &q);
-}
-
-void
-mpmodfixfix(Mpint *a, Mpint *b)
-{
- Mpint q, r;
-
- mpdivmodfixfix(&q, &r, a, b);
- mpmovefixfix(a, &r);
-}
-
-void
-mpcomfix(Mpint *a)
-{
- Mpint b;
-
- mpmovecfix(&b, 1);
- mpnegfix(a);
- mpsubfixfix(a, &b);
-}
-
-void
-mpmovefixflt(Mpflt *a, Mpint *b)
-{
- a->val = *b;
- a->exp = 0;
- mpnorm(a);
-}
-
-// convert (truncate) b to a.
-// return -1 (but still convert) if b was non-integer.
-static int
-mpexactfltfix(Mpint *a, Mpflt *b)
-{
- Mpflt f;
-
- *a = b->val;
- mpshiftfix(a, b->exp);
- if(b->exp < 0) {
- f.val = *a;
- f.exp = 0;
- mpnorm(&f);
- if(mpcmpfltflt(b, &f) != 0)
- return -1;
- }
- return 0;
-}
-
-int
-mpmovefltfix(Mpint *a, Mpflt *b)
-{
- Mpflt f;
- int i;
-
- if(mpexactfltfix(a, b) == 0)
- return 0;
-
- // try rounding down a little
- f = *b;
- f.val.a[0] = 0;
- if(mpexactfltfix(a, &f) == 0)
- return 0;
-
- // try rounding up a little
- for(i=1; i<Mpprec; i++) {
- f.val.a[i]++;
- if(f.val.a[i] != Mpbase)
- break;
- f.val.a[i] = 0;
- }
- mpnorm(&f);
- if(mpexactfltfix(a, &f) == 0)
- return 0;
-
- return -1;
-}
-
-void
-mpmovefixfix(Mpint *a, Mpint *b)
-{
- *a = *b;
-}
-
-void
-mpmovefltflt(Mpflt *a, Mpflt *b)
-{
- *a = *b;
-}
-
-static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
-static void
-mppow10flt(Mpflt *a, int p)
-{
- if(p < 0)
- abort();
- if(p < nelem(tab)) {
- mpmovecflt(a, tab[p]);
- return;
- }
- mppow10flt(a, p>>1);
- mpmulfltflt(a, a);
- if(p & 1)
- mpmulcflt(a, 10);
-}
-
-//
-// floating point input
-// required syntax is [+-]d*[.]d*[e[+-]d*]
-//
-void
-mpatoflt(Mpflt *a, char *as)
-{
- Mpflt b;
- int dp, c, f, ef, ex, eb;
- char *s;
-
- s = as;
- dp = 0; /* digits after decimal point */
- f = 0; /* sign */
- ex = 0; /* exponent */
- eb = 0; /* binary point */
-
- mpmovecflt(a, 0.0);
- for(;;) {
- switch(c = *s++) {
- default:
- goto bad;
-
- case '-':
- f = 1;
-
- case ' ':
- case '\t':
- case '+':
- continue;
-
- case '.':
- dp = 1;
- continue;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- mpmulcflt(a, 10);
- mpaddcflt(a, c-'0');
- if(dp)
- dp++;
- continue;
-
- case 'P':
- case 'p':
- eb = 1;
-
- case 'E':
- case 'e':
- ex = 0;
- ef = 0;
- for(;;) {
- c = *s++;
- if(c == '+' || c == ' ' || c == '\t')
- continue;
- if(c == '-') {
- ef = 1;
- continue;
- }
- if(c >= '0' && c <= '9') {
- ex = ex*10 + (c-'0');
- if(ex > 1e8) {
- yyerror("exponent out of range");
- errorexit();
- }
- continue;
- }
- break;
- }
- if(ef)
- ex = -ex;
-
- case 0:
- break;
- }
- break;
- }
-
- if(eb) {
- if(dp)
- goto bad;
- a->exp += ex;
- goto out;
- }
-
- if(dp)
- dp--;
- if(mpcmpfltc(a, 0.0) != 0) {
- if(ex >= dp) {
- mppow10flt(&b, ex-dp);
- mpmulfltflt(a, &b);
- } else {
- mppow10flt(&b, dp-ex);
- mpdivfltflt(a, &b);
- }
- }
-
-out:
- if(f)
- mpnegflt(a);
- return;
-
-bad:
- yyerror("set ovf in mpatof");
- mpmovecflt(a, 0.0);
-}
-
-//
-// fixed point input
-// required syntax is [+-][0[x]]d*
-//
-void
-mpatofix(Mpint *a, char *as)
-{
- int c, f;
- char *s;
-
- s = as;
- f = 0;
- mpmovecfix(a, 0);
-
- c = *s++;
- switch(c) {
- case '-':
- f = 1;
-
- case '+':
- c = *s++;
- if(c != '0')
- break;
-
- case '0':
- goto oct;
- }
-
- while(c) {
- if(c >= '0' && c <= '9') {
- mpmulcfix(a, 10);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- goto bad;
- }
- goto out;
-
-oct:
- c = *s++;
- if(c == 'x' || c == 'X')
- goto hex;
- while(c) {
- if(c >= '0' && c <= '7') {
- mpmulcfix(a, 8);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- goto bad;
- }
- goto out;
-
-hex:
- c = *s++;
- while(c) {
- if(c >= '0' && c <= '9') {
- mpmulcfix(a, 16);
- mpaddcfix(a, c-'0');
- c = *s++;
- continue;
- }
- if(c >= 'a' && c <= 'f') {
- mpmulcfix(a, 16);
- mpaddcfix(a, c+10-'a');
- c = *s++;
- continue;
- }
- if(c >= 'A' && c <= 'F') {
- mpmulcfix(a, 16);
- mpaddcfix(a, c+10-'A');
- c = *s++;
- continue;
- }
- goto bad;
- }
-
-out:
- if(f)
- mpnegfix(a);
- return;
-
-bad:
- yyerror("set ovf in mpatov: %s", as);
- mpmovecfix(a, 0);
-}
-
-int
-Bconv(Fmt *fp)
-{
- char buf[500], *p;
- Mpint *xval, q, r, ten;
- int f;
-
- xval = va_arg(fp->args, Mpint*);
- mpmovefixfix(&q, xval);
- f = 0;
- if(mptestfix(&q) < 0) {
- f = 1;
- mpnegfix(&q);
- }
- mpmovecfix(&ten, 10);
-
- p = &buf[sizeof(buf)];
- *--p = 0;
- for(;;) {
- mpdivmodfixfix(&q, &r, &q, &ten);
- *--p = mpgetfix(&r) + '0';
- if(mptestfix(&q) <= 0)
- break;
- }
- if(f)
- *--p = '-';
- return fmtstrcpy(fp, p);
-}
-
-int
-Fconv(Fmt *fp)
-{
- char buf[500];
- Mpflt *fvp, fv;
- double d;
-
- fvp = va_arg(fp->args, Mpflt*);
- if(fp->flags & FmtSharp) {
- // alternate form - decimal for error messages.
- // for well in range, convert to double and use print's %g
- if(-900 < fvp->exp && fvp->exp < 900) {
- d = mpgetflt(fvp);
- if(d >= 0 && (fp->flags & FmtSign))
- fmtprint(fp, "+");
- return fmtprint(fp, "%g", d);
- }
- // TODO(rsc): for well out of range, print
- // an approximation like 1.234e1000
- }
-
- if(sigfig(fvp) == 0) {
- snprint(buf, sizeof(buf), "0p+0");
- goto out;
- }
- fv = *fvp;
-
- while(fv.val.a[0] == 0) {
- mpshiftfix(&fv.val, -Mpscale);
- fv.exp += Mpscale;
- }
- while((fv.val.a[0]&1) == 0) {
- mpshiftfix(&fv.val, -1);
- fv.exp += 1;
- }
-
- if(fv.exp >= 0) {
- snprint(buf, sizeof(buf), "%Bp+%d", &fv.val, fv.exp);
- goto out;
- }
- snprint(buf, sizeof(buf), "%Bp-%d", &fv.val, -fv.exp);
-
-out:
- return fmtstrcpy(fp, buf);
-}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
deleted file mode 100644
index 403255005..000000000
--- a/src/cmd/gc/mparith2.c
+++ /dev/null
@@ -1,683 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-//
-// return the significant
-// words of the argument
-//
-static int
-mplen(Mpint *a)
-{
- int i, n;
- long *a1;
-
- n = -1;
- a1 = &a->a[0];
- for(i=0; i<Mpprec; i++) {
- if(*a1++ != 0)
- n = i;
- }
- return n+1;
-}
-
-//
-// left shift mpint by one
-// ignores sign and overflow
-//
-static void
-mplsh(Mpint *a)
-{
- long *a1, x;
- int i, c;
-
- c = 0;
- a1 = &a->a[0];
- for(i=0; i<Mpprec; i++) {
- x = (*a1 << 1) + c;
- c = 0;
- if(x >= Mpbase) {
- x -= Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
-}
-
-//
-// left shift mpint by Mpscale
-// ignores sign and overflow
-//
-static void
-mplshw(Mpint *a)
-{
- long *a1;
- int i;
-
- a1 = &a->a[Mpprec-1];
- for(i=1; i<Mpprec; i++) {
- a1[0] = a1[-1];
- a1--;
- }
- a1[0] = 0;
-}
-
-//
-// right shift mpint by one
-// ignores sign and overflow
-//
-static void
-mprsh(Mpint *a)
-{
- long *a1, x, lo;
- int i, c;
-
- c = 0;
- lo = a->a[0] & 1;
- a1 = &a->a[Mpprec];
- for(i=0; i<Mpprec; i++) {
- x = *--a1;
- *a1 = (x + c) >> 1;
- c = 0;
- if(x & 1)
- c = Mpbase;
- }
- if(a->neg && lo != 0)
- mpaddcfix(a, -1);
-}
-
-//
-// right shift mpint by Mpscale
-// ignores sign and overflow
-//
-static void
-mprshw(Mpint *a)
-{
- long *a1, lo;
- int i;
-
- lo = a->a[0];
- a1 = &a->a[0];
- for(i=1; i<Mpprec; i++) {
- a1[0] = a1[1];
- a1++;
- }
- a1[0] = 0;
- if(a->neg && lo != 0)
- mpaddcfix(a, -1);
-}
-
-//
-// return the sign of (abs(a)-abs(b))
-//
-static int
-mpcmp(Mpint *a, Mpint *b)
-{
- long x, *a1, *b1;
- int i;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in cmp");
- return 0;
- }
-
- a1 = &a->a[0] + Mpprec;
- b1 = &b->a[0] + Mpprec;
-
- for(i=0; i<Mpprec; i++) {
- x = *--a1 - *--b1;
- if(x > 0)
- return +1;
- if(x < 0)
- return -1;
- }
- return 0;
-}
-
-//
-// negate a
-// ignore sign and ovf
-//
-static void
-mpneg(Mpint *a)
-{
- long x, *a1;
- int i, c;
-
- a1 = &a->a[0];
- c = 0;
- for(i=0; i<Mpprec; i++) {
- x = -*a1 -c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
-}
-
-// shift left by s (or right by -s)
-void
-mpshiftfix(Mpint *a, int s)
-{
- if(s >= 0) {
- while(s >= Mpscale) {
- mplshw(a);
- s -= Mpscale;
- }
- while(s > 0) {
- mplsh(a);
- s--;
- }
- } else {
- s = -s;
- while(s >= Mpscale) {
- mprshw(a);
- s -= Mpscale;
- }
- while(s > 0) {
- mprsh(a);
- s--;
- }
- }
-}
-
-/// implements fix arihmetic
-
-void
-mpaddfixfix(Mpint *a, Mpint *b)
-{
- int i, c;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpaddxx");
- a->ovf = 1;
- return;
- }
-
- c = 0;
- a1 = &a->a[0];
- b1 = &b->a[0];
- if(a->neg != b->neg)
- goto sub;
-
- // perform a+b
- for(i=0; i<Mpprec; i++) {
- x = *a1 + *b1++ + c;
- c = 0;
- if(x >= Mpbase) {
- x -= Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
- a->ovf = c;
- if(a->ovf)
- yyerror("set ovf in mpaddxx");
-
- return;
-
-sub:
- // perform a-b
- switch(mpcmp(a, b)) {
- case 0:
- mpmovecfix(a, 0);
- break;
-
- case 1:
- for(i=0; i<Mpprec; i++) {
- x = *a1 - *b1++ - c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
- break;
-
- case -1:
- a->neg ^= 1;
- for(i=0; i<Mpprec; i++) {
- x = *b1++ - *a1 - c;
- c = 0;
- if(x < 0) {
- x += Mpbase;
- c = 1;
- }
- *a1++ = x;
- }
- break;
- }
-}
-
-void
-mpmulfixfix(Mpint *a, Mpint *b)
-{
-
- int i, j, na, nb;
- long *a1, x;
- Mpint s, q;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpmulfixfix");
- a->ovf = 1;
- return;
- }
-
- // pick the smaller
- // to test for bits
- na = mplen(a);
- nb = mplen(b);
- if(na > nb) {
- mpmovefixfix(&s, a);
- a1 = &b->a[0];
- na = nb;
- } else {
- mpmovefixfix(&s, b);
- a1 = &a->a[0];
- }
- s.neg = 0;
-
- mpmovecfix(&q, 0);
- for(i=0; i<na; i++) {
- x = *a1++;
- for(j=0; j<Mpscale; j++) {
- if(x & 1)
- mpaddfixfix(&q, &s);
- mplsh(&s);
- x >>= 1;
- }
- }
-
- q.neg = a->neg ^ b->neg;
- mpmovefixfix(a, &q);
- if(a->ovf)
- yyerror("set ovf in mpmulfixfix");
-}
-
-void
-mpmulfract(Mpint *a, Mpint *b)
-{
-
- int i, j;
- long *a1, x;
- Mpint s, q;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpmulflt");
- a->ovf = 1;
- return;
- }
-
- mpmovefixfix(&s, b);
- a1 = &a->a[Mpprec];
- s.neg = 0;
- mpmovecfix(&q, 0);
-
- x = *--a1;
- if(x != 0)
- yyerror("mpmulfract not normal");
-
- for(i=0; i<Mpprec-1; i++) {
- x = *--a1;
- if(x == 0) {
- mprshw(&s);
- continue;
- }
- for(j=0; j<Mpscale; j++) {
- x <<= 1;
- if(x & Mpbase)
- mpaddfixfix(&q, &s);
- mprsh(&s);
- }
- }
-
- q.neg = a->neg ^ b->neg;
- mpmovefixfix(a, &q);
- if(a->ovf)
- yyerror("set ovf in mpmulflt");
-}
-
-void
-mporfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 | *b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpandfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpandfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 & *b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpandnotfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mpandnotfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 & ~*b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mpxorfixfix(Mpint *a, Mpint *b)
-{
- int i;
- long x, *a1, *b1;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- if(a->neg) {
- a->neg = 0;
- mpneg(a);
- }
- if(b->neg)
- mpneg(b);
-
- a1 = &a->a[0];
- b1 = &b->a[0];
- for(i=0; i<Mpprec; i++) {
- x = *a1 ^ *b1++;
- *a1++ = x;
- }
-
- if(b->neg)
- mpneg(b);
- if(x & Mpsign) {
- a->neg = 1;
- mpneg(a);
- }
-}
-
-void
-mplshfixfix(Mpint *a, Mpint *b)
-{
- vlong s;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- s = mpgetfix(b);
- if(s < 0 || s >= Mpprec*Mpscale) {
- yyerror("stupid shift: %lld", s);
- mpmovecfix(a, 0);
- return;
- }
-
- mpshiftfix(a, s);
-}
-
-void
-mprshfixfix(Mpint *a, Mpint *b)
-{
- vlong s;
-
- if(a->ovf || b->ovf) {
- yyerror("ovf in mprshfixfix");
- mpmovecfix(a, 0);
- a->ovf = 1;
- return;
- }
- s = mpgetfix(b);
- if(s < 0 || s >= Mpprec*Mpscale) {
- yyerror("stupid shift: %lld", s);
- if(a->neg)
- mpmovecfix(a, -1);
- else
- mpmovecfix(a, 0);
- return;
- }
-
- mpshiftfix(a, -s);
-}
-
-void
-mpnegfix(Mpint *a)
-{
- a->neg ^= 1;
-}
-
-vlong
-mpgetfix(Mpint *a)
-{
- vlong v;
-
- if(a->ovf) {
- yyerror("constant overflow");
- return 0;
- }
-
- v = (vlong)a->a[0];
- v |= (vlong)a->a[1] << Mpscale;
- v |= (vlong)a->a[2] << (Mpscale+Mpscale);
- if(a->neg)
- v = -v;
- return v;
-}
-
-void
-mpmovecfix(Mpint *a, vlong c)
-{
- int i;
- long *a1;
- vlong x;
-
- a->neg = 0;
- a->ovf = 0;
-
- x = c;
- if(x < 0) {
- a->neg = 1;
- x = -x;
- }
-
- a1 = &a->a[0];
- for(i=0; i<Mpprec; i++) {
- *a1++ = x&Mpmask;
- x >>= Mpscale;
- }
-}
-
-void
-mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
-{
- int i, ns, ds;
-
- ns = n->neg;
- ds = d->neg;
- n->neg = 0;
- d->neg = 0;
-
- mpmovefixfix(r, n);
- mpmovecfix(q, 0);
-
- // shift denominator until it
- // is larger than numerator
- for(i=0; i<Mpprec*Mpscale; i++) {
- if(mpcmp(d, r) > 0)
- break;
- mplsh(d);
- }
-
- // if it never happens
- // denominator is probably zero
- if(i >= Mpprec*Mpscale) {
- q->ovf = 1;
- r->ovf = 1;
- n->neg = ns;
- d->neg = ds;
- yyerror("set ovf in mpdivmodfixfix");
- return;
- }
-
- // shift denominator back creating
- // quotient a bit at a time
- // when done the remaining numerator
- // will be the remainder
- for(; i>0; i--) {
- mplsh(q);
- mprsh(d);
- if(mpcmp(d, r) <= 0) {
- mpaddcfix(q, 1);
- mpsubfixfix(r, d);
- }
- }
-
- n->neg = ns;
- d->neg = ds;
- r->neg = ns;
- q->neg = ns^ds;
-}
-
-static int
-iszero(Mpint *a)
-{
- long *a1;
- int i;
- a1 = &a->a[0] + Mpprec;
- for(i=0; i<Mpprec; i++) {
- if(*--a1 != 0)
- return 0;
- }
- return 1;
-}
-
-void
-mpdivfract(Mpint *a, Mpint *b)
-{
- Mpint n, d;
- int i, j, neg;
- long *a1, x;
-
- mpmovefixfix(&n, a); // numerator
- mpmovefixfix(&d, b); // denominator
- a1 = &a->a[Mpprec]; // quotient
-
- neg = n.neg ^ d.neg;
- n.neg = 0;
- d.neg = 0;
- for(i=0; i<Mpprec; i++) {
- x = 0;
- for(j=0; j<Mpscale; j++) {
- x <<= 1;
- if(mpcmp(&d, &n) <= 0) {
- if(!iszero(&d))
- x |= 1;
- mpsubfixfix(&n, &d);
- }
- mprsh(&d);
- }
- *--a1 = x;
- }
- a->neg = neg;
-}
-
-int
-mptestfix(Mpint *a)
-{
- Mpint b;
- int r;
-
- mpmovecfix(&b, 0);
- r = mpcmp(a, &b);
- if(a->neg) {
- if(r > 0)
- return -1;
- if(r < 0)
- return +1;
- }
- return r;
-}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
deleted file mode 100644
index b11a4f5f1..000000000
--- a/src/cmd/gc/mparith3.c
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/*
- * returns the leading non-zero
- * word of the number
- */
-int
-sigfig(Mpflt *a)
-{
- int i;
-
- for(i=Mpprec-1; i>=0; i--)
- if(a->val.a[i] != 0)
- break;
-//print("sigfig %d %d\n", i-z+1, z);
- return i+1;
-}
-
-/*
- * shifts the leading non-zero
- * word of the number to Mpnorm
- */
-void
-mpnorm(Mpflt *a)
-{
- int s, os;
- long x;
-
- os = sigfig(a);
- if(os == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- // this will normalize to the nearest word
- x = a->val.a[os-1];
- s = (Mpnorm-os) * Mpscale;
-
- // further normalize to the nearest bit
- for(;;) {
- x <<= 1;
- if(x & Mpbase)
- break;
- s++;
- if(x == 0) {
- // this error comes from trying to
- // convert an Inf or something
- // where the initial x=0x80000000
- s = (Mpnorm-os) * Mpscale;
- break;
- }
- }
-
- mpshiftfix(&a->val, s);
- a->exp -= s;
-}
-
-/// implements float arihmetic
-
-void
-mpaddfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb, s;
- Mpflt c;
-
- if(Mpdebug)
- print("\n%F + %F", a, b);
-
- sa = sigfig(a);
- if(sa == 0) {
- mpmovefltflt(a, b);
- goto out;
- }
-
- sb = sigfig(b);
- if(sb == 0)
- goto out;
-
- s = a->exp - b->exp;
- if(s > 0) {
- // a is larger, shift b right
- mpmovefltflt(&c, b);
- mpshiftfix(&c.val, -s);
- mpaddfixfix(&a->val, &c.val);
- goto out;
- }
- if(s < 0) {
- // b is larger, shift a right
- mpshiftfix(&a->val, s);
- a->exp -= s;
- mpaddfixfix(&a->val, &b->val);
- goto out;
- }
- mpaddfixfix(&a->val, &b->val);
-
-out:
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-void
-mpmulfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb;
-
- if(Mpdebug)
- print("%F\n * %F\n", a, b);
-
- sa = sigfig(a);
- if(sa == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- sb = sigfig(b);
- if(sb == 0) {
- // zero
- mpmovefltflt(a, b);
- return;
- }
-
- mpmulfract(&a->val, &b->val);
- a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
-
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-void
-mpdivfltflt(Mpflt *a, Mpflt *b)
-{
- int sa, sb;
- Mpflt c;
-
- if(Mpdebug)
- print("%F\n / %F\n", a, b);
-
- sb = sigfig(b);
- if(sb == 0) {
- // zero and ovfl
- a->exp = 0;
- a->val.neg = 0;
- a->val.ovf = 1;
- yyerror("mpdivfltflt divide by zero");
- return;
- }
-
- sa = sigfig(a);
- if(sa == 0) {
- // zero
- a->exp = 0;
- a->val.neg = 0;
- return;
- }
-
- // adjust b to top
- mpmovefltflt(&c, b);
- mpshiftfix(&c.val, Mpscale);
-
- // divide
- mpdivfract(&a->val, &c.val);
- a->exp = (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1;
-
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n\n", a);
-}
-
-double
-mpgetflt(Mpflt *a)
-{
- int s, i, e;
- uvlong v, vm;
- double f;
-
- if(a->val.ovf)
- yyerror("mpgetflt ovf");
-
- s = sigfig(a);
- if(s == 0)
- return 0;
-
- if(s != Mpnorm) {
- yyerror("mpgetflt norm");
- mpnorm(a);
- }
-
- while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
- mpshiftfix(&a->val, 1);
- a->exp -= 1;
- }
-
- // the magic numbers (64, 63, 53, 10, -1074) are
- // IEEE specific. this should be done machine
- // independently or in the 6g half of the compiler
-
- // pick up the mantissa and a rounding bit in a uvlong
- s = 53+1;
- v = 0;
- for(i=Mpnorm-1; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- vm = v;
- if(s > 0)
- vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
-
- // continue with 64 more bits
- s += 64;
- for(; s>=Mpscale; i--) {
- v = (v<<Mpscale) | a->val.a[i];
- s -= Mpscale;
- }
- if(s > 0)
- v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
-
- // gradual underflow
- e = Mpnorm*Mpscale + a->exp - 53;
- if(e < -1074) {
- s = -e - 1074;
- if(s > 54)
- s = 54;
- v |= vm & ((1ULL<<s) - 1);
- vm >>= s;
- e = -1074;
- }
-
-//print("vm=%.16llux v=%.16llux\n", vm, v);
- // round toward even
- if(v != 0 || (vm&2ULL) != 0)
- vm = (vm>>1) + (vm&1ULL);
- else
- vm >>= 1;
-
- f = (double)(vm);
- f = ldexp(f, e);
-
- if(a->val.neg)
- f = -f;
- return f;
-}
-
-void
-mpmovecflt(Mpflt *a, double c)
-{
- int i;
- double f;
- long l;
-
- if(Mpdebug)
- print("\nconst %g", c);
- mpmovecfix(&a->val, 0);
- a->exp = 0;
- if(c == 0)
- goto out;
- if(c < 0) {
- a->val.neg = 1;
- c = -c;
- }
-
- f = frexp(c, &i);
- a->exp = i;
-
- for(i=0; i<10; i++) {
- f = f*Mpbase;
- l = floor(f);
- f = f - l;
- a->exp -= Mpscale;
- a->val.a[0] = l;
- if(f == 0)
- break;
- mpshiftfix(&a->val, Mpscale);
- }
-
-out:
- mpnorm(a);
- if(Mpdebug)
- print(" = %F\n", a);
-}
-
-void
-mpnegflt(Mpflt *a)
-{
- a->val.neg ^= 1;
-}
-
-int
-mptestflt(Mpflt *a)
-{
- int s;
-
- if(Mpdebug)
- print("\n%F?", a);
- s = sigfig(a);
- if(s != 0) {
- s = +1;
- if(a->val.neg)
- s = -1;
- }
- if(Mpdebug)
- print(" = %d\n", s);
- return s;
-}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
deleted file mode 100644
index f34fc76c8..000000000
--- a/src/cmd/gc/obj.c
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/*
- * architecture-independent object file output
- */
-
-static void outhist(Biobuf *b);
-static void dumpglobls(void);
-
-void
-dumpobj(void)
-{
- bout = Bopen(outfile, OWRITE);
- if(bout == nil) {
- flusherrors();
- print("can't create %s: %r\n", outfile);
- errorexit();
- }
-
- Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
- Bprint(bout, " exports automatically generated from\n");
- Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
- dumpexport();
- Bprint(bout, "\n!\n");
-
- outhist(bout);
-
- // add nil plist w AEND to catch
- // auto-generated trampolines, data
- newplist();
-
- dumpglobls();
- dumptypestructs();
- dumpdata();
- dumpfuncs();
-
- Bterm(bout);
-}
-
-static void
-dumpglobls(void)
-{
- Node *n;
- NodeList *l;
-
- // add globals
- for(l=externdcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME)
- continue;
-
- if(n->type == T)
- fatal("external %#N nil type\n", n);
- if(n->class == PFUNC)
- continue;
- if(n->sym->pkg != localpkg)
- continue;
- dowidth(n->type);
-
- ggloblnod(n, n->type->width);
- }
-}
-
-void
-Bputname(Biobuf *b, Sym *s)
-{
- Bprint(b, "%s", s->pkg->prefix);
- Bputc(b, '.');
- Bwrite(b, s->name, strlen(s->name)+1);
-}
-
-static void
-outzfile(Biobuf *b, char *p)
-{
- char *q, *q2;
-
- while(p) {
- q = utfrune(p, '/');
- if(windows) {
- q2 = utfrune(p, '\\');
- if(q2 && (!q || q2 < q))
- q = q2;
- }
- if(!q) {
- zfile(b, p, strlen(p));
- return;
- }
- if(q > p)
- zfile(b, p, q-p);
- p = q + 1;
- }
-}
-
-#define isdelim(c) (c == '/' || c == '\\')
-
-static void
-outwinname(Biobuf *b, Hist *h, char *ds, char *p)
-{
- if(isdelim(p[0])) {
- // full rooted name
- zfile(b, ds, 3); // leading "c:/"
- outzfile(b, p+1);
- } else {
- // relative name
- if(h->offset == 0 && pathname && pathname[1] == ':') {
- if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
- // using current drive
- zfile(b, pathname, 3); // leading "c:/"
- outzfile(b, pathname+3);
- } else {
- // using drive other then current,
- // we don't have any simple way to
- // determine current working directory
- // there, therefore will output name as is
- zfile(b, ds, 2); // leading "c:"
- }
- }
- outzfile(b, p);
- }
-}
-
-static void
-outhist(Biobuf *b)
-{
- Hist *h;
- char *p, ds[] = {'c', ':', '/', 0};
-
- for(h = hist; h != H; h = h->link) {
- p = h->name;
- if(p) {
- if(windows) {
- // if windows variable is set, then, we know already,
- // pathname is started with windows drive specifier
- // and all '\' were replaced with '/' (see lex.c)
- if(isdelim(p[0]) && isdelim(p[1])) {
- // file name has network name in it,
- // like \\server\share\dir\file.go
- zfile(b, "//", 2); // leading "//"
- outzfile(b, p+2);
- } else if(p[1] == ':') {
- // file name has drive letter in it
- ds[0] = p[0];
- outwinname(b, h, ds, p+2);
- } else {
- // no drive letter in file name
- outwinname(b, h, pathname, p);
- }
- } else {
- if(p[0] == '/') {
- // full rooted name, like /home/rsc/dir/file.go
- zfile(b, "/", 1); // leading "/"
- outzfile(b, p+1);
- } else {
- // relative name, like dir/file.go
- if(h->offset == 0 && pathname && pathname[0] == '/') {
- zfile(b, "/", 1); // leading "/"
- outzfile(b, pathname+1);
- }
- outzfile(b, p);
- }
- }
- }
- zhist(b, h->line, h->offset);
- }
-}
-
-void
-ieeedtod(uint64 *ieee, double native)
-{
- double fr, ho, f;
- int exp;
- uint32 h, l;
- uint64 bits;
-
- if(native < 0) {
- ieeedtod(ieee, -native);
- *ieee |= 1ULL<<63;
- return;
- }
- if(native == 0) {
- *ieee = 0;
- return;
- }
- fr = frexp(native, &exp);
- f = 2097152L; /* shouldnt use fp constants here */
- fr = modf(fr*f, &ho);
- h = ho;
- h &= 0xfffffL;
- f = 65536L;
- fr = modf(fr*f, &ho);
- l = ho;
- l <<= 16;
- l |= (int32)(fr*f);
- bits = ((uint64)h<<32) | l;
- if(exp < -1021) {
- // gradual underflow
- bits |= 1LL<<52;
- bits >>= -1021 - exp;
- exp = -1022;
- }
- bits |= (uint64)(exp+1022L) << 52;
- *ieee = bits;
-}
-
-int
-duint8(Sym *s, int off, uint8 v)
-{
- return duintxx(s, off, v, 1);
-}
-
-int
-duint16(Sym *s, int off, uint16 v)
-{
- return duintxx(s, off, v, 2);
-}
-
-int
-duint32(Sym *s, int off, uint32 v)
-{
- return duintxx(s, off, v, 4);
-}
-
-int
-duint64(Sym *s, int off, uint64 v)
-{
- return duintxx(s, off, v, 8);
-}
-
-int
-duintptr(Sym *s, int off, uint64 v)
-{
- return duintxx(s, off, v, widthptr);
-}
-
-Sym*
-stringsym(char *s, int len)
-{
- static int gen;
- Sym *sym;
- int off, n, m;
- struct {
- Strlit lit;
- char buf[110];
- } tmp;
- Pkg *pkg;
-
- if(len > 100) {
- // huge strings are made static to avoid long names
- snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
- pkg = localpkg;
- } else {
- // small strings get named by their contents,
- // so that multiple modules using the same string
- // can share it.
- tmp.lit.len = len;
- memmove(tmp.lit.s, s, len);
- tmp.lit.s[len] = '\0';
- snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp);
- pkg = gostringpkg;
- }
- sym = pkglookup(namebuf, pkg);
-
- // SymUniq flag indicates that data is generated already
- if(sym->flags & SymUniq)
- return sym;
- sym->flags |= SymUniq;
-
- data();
- off = 0;
-
- // string header
- off = dsymptr(sym, off, sym, widthptr+4);
- off = duint32(sym, off, len);
-
- // string data
- for(n=0; n<len; n+=m) {
- m = 8;
- if(m > len-n)
- m = len-n;
- off = dsname(sym, off, s+n, m);
- }
- off = duint8(sym, off, 0); // terminating NUL for runtime
- off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
- ggloblsym(sym, off, 1);
- text();
-
- return sym;
-}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
deleted file mode 100644
index 552e405d8..000000000
--- a/src/cmd/gc/pgen.c
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "gg.h"
-#include "opt.h"
-
-static void compactframe(Prog* p);
-
-void
-compile(Node *fn)
-{
- Plist *pl;
- Node nod1, *n;
- Prog *ptxt;
- int32 lno;
- Type *t;
- Iter save;
- vlong oldstksize;
-
- if(newproc == N) {
- newproc = sysfunc("newproc");
- deferproc = sysfunc("deferproc");
- deferreturn = sysfunc("deferreturn");
- panicindex = sysfunc("panicindex");
- panicslice = sysfunc("panicslice");
- throwreturn = sysfunc("throwreturn");
- }
-
- if(fn->nbody == nil)
- return;
-
- saveerrors();
-
- // set up domain for labels
- clearlabels();
-
- lno = setlineno(fn);
-
- curfn = fn;
- dowidth(curfn->type);
-
- if(curfn->type->outnamed) {
- // add clearing of the output parameters
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- if(t->nname != N) {
- n = nod(OAS, t->nname, N);
- typecheck(&n, Etop);
- curfn->nbody = concat(list1(n), curfn->nbody);
- }
- t = structnext(&save);
- }
- }
-
- hasdefer = 0;
- walk(curfn);
- if(nerrors != 0)
- goto ret;
-
- allocparams();
-
- continpc = P;
- breakpc = P;
-
- pl = newplist();
- pl->name = curfn->nname;
-
- setlineno(curfn);
-
- nodconst(&nod1, types[TINT32], 0);
- ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
- afunclit(&ptxt->from);
-
- ginit();
- genlist(curfn->enter);
-
- retpc = nil;
- if(hasdefer || curfn->exit) {
- Prog *p1;
-
- p1 = gjmp(nil);
- retpc = gjmp(nil);
- patch(p1, pc);
- }
-
- genlist(curfn->nbody);
- gclean();
- checklabels();
- if(nerrors != 0)
- goto ret;
- if(curfn->endlineno)
- lineno = curfn->endlineno;
-
- if(curfn->type->outtuple != 0)
- ginscall(throwreturn, 0);
-
- if(retpc)
- patch(retpc, pc);
- ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
- gclean();
- if(nerrors != 0)
- goto ret;
- pc->as = ARET; // overwrite AEND
- pc->lineno = lineno;
-
- if(!debug['N'] || debug['R'] || debug['P']) {
- regopt(ptxt);
- }
-
- oldstksize = stksize;
- compactframe(ptxt);
- if(0)
- print("compactframe: %ld to %ld\n", oldstksize, stksize);
-
- defframe(ptxt);
-
- if(0)
- frame(0);
-
-ret:
- lineno = lno;
-}
-
-
-// Sort the list of stack variables. autos after anything else,
-// within autos, unused after used, and within used on reverse alignment.
-// non-autos sort on offset.
-static int
-cmpstackvar(Node *a, Node *b)
-{
- if (a->class != b->class)
- return (a->class == PAUTO) ? 1 : -1;
- if (a->class != PAUTO)
- return a->xoffset - b->xoffset;
- if ((a->used == 0) != (b->used == 0))
- return b->used - a->used;
- return b->type->align - a->type->align;
-
-}
-
-// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
-static void
-compactframe(Prog* ptxt)
-{
- NodeList *ll;
- Node* n;
- uint32 w;
-
- if (stksize == 0)
- return;
-
- // Mark the PAUTO's unused.
- for(ll=curfn->dcl; ll != nil; ll=ll->next)
- if (ll->n->class == PAUTO)
- ll->n->used = 0;
-
- markautoused(ptxt);
-
- listsort(&curfn->dcl, cmpstackvar);
-
- // Unused autos are at the end, chop 'em off.
- ll = curfn->dcl;
- n = ll->n;
- if (n->class == PAUTO && n->op == ONAME && !n->used) {
- curfn->dcl = nil;
- stksize = 0;
- return;
- }
-
- for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
- n = ll->next->n;
- if (n->class == PAUTO && n->op == ONAME && !n->used) {
- ll->next = nil;
- curfn->dcl->end = ll;
- break;
- }
- }
-
- // Reassign stack offsets of the locals that are still there.
- stksize = 0;
- for(ll = curfn->dcl; ll != nil; ll=ll->next) {
- n = ll->n;
- if (n->class != PAUTO || n->op != ONAME)
- continue;
-
- w = n->type->width;
- if((w >= MAXWIDTH) || (w < 1))
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->stkdelta = -stksize - n->xoffset;
- }
-
- fixautoused(ptxt);
-
- // The debug information needs accurate offsets on the symbols.
- for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
- if (ll->n->class != PAUTO || ll->n->op != ONAME)
- continue;
- ll->n->xoffset += ll->n->stkdelta;
- ll->n->stkdelta = 0;
- }
-}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
deleted file mode 100644
index e88e0f844..000000000
--- a/src/cmd/gc/print.c
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-enum
-{
- PFIXME = 0,
-};
-
-void
-exprlistfmt(Fmt *f, NodeList *l)
-{
- for(; l; l=l->next) {
- exprfmt(f, l->n, 0);
- if(l->next)
- fmtprint(f, ", ");
- }
-}
-
-void
-exprfmt(Fmt *f, Node *n, int prec)
-{
- int nprec;
- char *p;
-
- nprec = 0;
- if(n == nil) {
- fmtprint(f, "<nil>");
- return;
- }
-
- if(n->implicit) {
- exprfmt(f, n->left, prec);
- return;
- }
-
- switch(n->op) {
- case OAPPEND:
- case ONAME:
- case ONONAME:
- case OPACK:
- case OLITERAL:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- case ODOTTYPE:
- case ODOTTYPE2:
- case OXDOT:
- case OARRAYBYTESTR:
- case OCAP:
- case OCLOSE:
- case OCOPY:
- case OLEN:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- case OCALL:
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- case OCONV:
- case OCONVNOP:
- case OMAKESLICE:
- case ORUNESTR:
- case OADDR:
- case OCOM:
- case OIND:
- case OMINUS:
- case ONOT:
- case OPLUS:
- case ORECV:
- case OCONVIFACE:
- case OTPAREN:
- case OINDEX:
- case OINDEXMAP:
- nprec = 7;
- break;
-
- case OMUL:
- case ODIV:
- case OMOD:
- case OLSH:
- case ORSH:
- case OAND:
- case OANDNOT:
- nprec = 6;
- break;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- nprec = 5;
- break;
-
- case OEQ:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case ONE:
- nprec = 4;
- break;
-
- case OSEND:
- nprec = 3;
- break;
-
- case OANDAND:
- nprec = 2;
- break;
-
- case OOROR:
- nprec = 1;
- break;
-
- case OTYPE:
- if(n->sym != S)
- nprec = 7;
- break;
- }
-
- if(prec > nprec)
- fmtprint(f, "(");
-
- switch(n->op) {
- default:
- bad:
- fmtprint(f, "(node %O)", n->op);
- break;
-
- case OREGISTER:
- fmtprint(f, "%R", n->val.u.reg);
- break;
-
- case OLITERAL:
- if(n->sym != S) {
- fmtprint(f, "%S", n->sym);
- break;
- }
- switch(n->val.ctype) {
- default:
- goto bad;
- case CTINT:
- fmtprint(f, "%B", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- fmtprint(f, "true");
- else
- fmtprint(f, "false");
- break;
- case CTCPLX:
- fmtprint(f, "%.17g+%.17gi",
- mpgetflt(&n->val.u.cval->real),
- mpgetflt(&n->val.u.cval->imag));
- break;
- case CTFLT:
- fmtprint(f, "%.17g", mpgetflt(n->val.u.fval));
- break;
- case CTSTR:
- fmtprint(f, "\"%Z\"", n->val.u.sval);
- break;
- case CTNIL:
- fmtprint(f, "nil");
- break;
- }
- break;
-
- case ONAME:
- case OPACK:
- case ONONAME:
- fmtprint(f, "%S", n->sym);
- break;
-
- case OTYPE:
- if(n->type == T && n->sym != S) {
- fmtprint(f, "%S", n->sym);
- break;
- }
- fmtprint(f, "%T", n->type);
- break;
-
- case OTARRAY:
- fmtprint(f, "[]");
- exprfmt(f, n->left, PFIXME);
- break;
-
- case OTPAREN:
- fmtprint(f, "(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OTMAP:
- fmtprint(f, "map[");
- exprfmt(f, n->left, 0);
- fmtprint(f, "] ");
- exprfmt(f, n->right, 0);
- break;
-
- case OTCHAN:
- if(n->etype == Crecv)
- fmtprint(f, "<-");
- fmtprint(f, "chan");
- if(n->etype == Csend) {
- fmtprint(f, "<- ");
- exprfmt(f, n->left, 0);
- } else {
- fmtprint(f, " ");
- if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) {
- fmtprint(f, "(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- } else
- exprfmt(f, n->left, 0);
- }
- break;
-
- case OTSTRUCT:
- fmtprint(f, "<struct>");
- break;
-
- case OTINTER:
- fmtprint(f, "<inter>");
- break;
-
- case OTFUNC:
- fmtprint(f, "<func>");
- break;
-
- case OAS:
- exprfmt(f, n->left, 0);
- fmtprint(f, " = ");
- exprfmt(f, n->right, 0);
- break;
-
- case OASOP:
- exprfmt(f, n->left, 0);
- fmtprint(f, " %#O= ", n->etype);
- exprfmt(f, n->right, 0);
- break;
-
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2MAPW:
- case OAS2RECV:
- exprlistfmt(f, n->list);
- fmtprint(f, " = ");
- exprlistfmt(f, n->rlist);
- break;
-
- case OADD:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case ORSH:
- case OSEND:
- case OSUB:
- case OXOR:
- exprfmt(f, n->left, nprec);
- fmtprint(f, " %#O ", n->op);
- exprfmt(f, n->right, nprec+1);
- break;
-
- case OADDR:
- case OCOM:
- case OIND:
- case OMINUS:
- case ONOT:
- case OPLUS:
- case ORECV:
- fmtprint(f, "%#O", n->op);
- if((n->op == OMINUS || n->op == OPLUS) && n->left->op == n->op)
- fmtprint(f, " ");
- exprfmt(f, n->left, 0);
- break;
-
- case OCLOSURE:
- fmtprint(f, "func literal");
- break;
-
- case OCOMPLIT:
- fmtprint(f, "composite literal");
- break;
-
- case OARRAYLIT:
- if(isslice(n->type))
- fmtprint(f, "slice literal");
- else
- fmtprint(f, "array literal");
- break;
-
- case OMAPLIT:
- fmtprint(f, "map literal");
- break;
-
- case OSTRUCTLIT:
- fmtprint(f, "struct literal");
- break;
-
- case OXDOT:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- exprfmt(f, n->left, 7);
- if(n->right == N || n->right->sym == S)
- fmtprint(f, ".<nil>");
- else {
- // skip leading type· in method name
- p = utfrrune(n->right->sym->name, 0xb7);
- if(p)
- p+=2;
- else
- p = n->right->sym->name;
- fmtprint(f, ".%s", p);
- }
- break;
-
- case ODOTTYPE:
- case ODOTTYPE2:
- exprfmt(f, n->left, 7);
- fmtprint(f, ".(");
- if(n->right != N)
- exprfmt(f, n->right, 0);
- else
- fmtprint(f, "%T", n->type);
- fmtprint(f, ")");
- break;
-
- case OINDEX:
- case OINDEXMAP:
- exprfmt(f, n->left, 7);
- fmtprint(f, "[");
- exprfmt(f, n->right, 0);
- fmtprint(f, "]");
- break;
-
- case OSLICE:
- case OSLICESTR:
- case OSLICEARR:
- exprfmt(f, n->left, 7);
- fmtprint(f, "[");
- if(n->right->left != N)
- exprfmt(f, n->right->left, 0);
- fmtprint(f, ":");
- if(n->right->right != N)
- exprfmt(f, n->right->right, 0);
- fmtprint(f, "]");
- break;
-
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- exprfmt(f, n->left, 7);
- fmtprint(f, "(");
- exprlistfmt(f, n->list);
- if(n->isddd)
- fmtprint(f, "...");
- fmtprint(f, ")");
- break;
-
- case OCOMPLEX:
- fmtprint(f, "complex(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ", ");
- exprfmt(f, n->right, 0);
- fmtprint(f, ")");
- break;
-
- case OREAL:
- fmtprint(f, "real(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OIMAG:
- fmtprint(f, "imag(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case OARRAYBYTESTR:
- case ORUNESTR:
- if(n->type == T || n->type->sym == S)
- fmtprint(f, "(%T)(", n->type);
- else
- fmtprint(f, "%T(", n->type);
- if(n->left == N)
- exprlistfmt(f, n->list);
- else
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OAPPEND:
- case OCAP:
- case OCLOSE:
- case OLEN:
- case OCOPY:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- fmtprint(f, "%#O(", n->op);
- if(n->left)
- exprfmt(f, n->left, 0);
- else
- exprlistfmt(f, n->list);
- fmtprint(f, ")");
- break;
-
- case OMAKESLICE:
- fmtprint(f, "make(%#T, ", n->type);
- exprfmt(f, n->left, 0);
- if(count(n->list) > 2) {
- fmtprint(f, ", ");
- exprfmt(f, n->right, 0);
- }
- fmtprint(f, ")");
- break;
-
- case OMAKEMAP:
- fmtprint(f, "make(%#T)", n->type);
- break;
- }
-
- if(prec > nprec)
- fmtprint(f, ")");
-}
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
deleted file mode 100644
index dfb2b8efd..000000000
--- a/src/cmd/gc/range.c
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * range
- */
-
-#include "go.h"
-
-void
-typecheckrange(Node *n)
-{
- char *why;
- Type *t, *t1, *t2;
- Node *v1, *v2;
- NodeList *ll;
-
- // delicate little dance. see typecheckas2
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->defn != n)
- typecheck(&ll->n, Erv | Easgn);
-
- typecheck(&n->right, Erv);
- if((t = n->right->type) == T)
- goto out;
- if(isptr[t->etype] && isfixedarray(t->type))
- t = t->type;
- n->type = t;
-
- switch(t->etype) {
- default:
- yyerror("cannot range over %+N", n->right);
- goto out;
-
- case TARRAY:
- t1 = types[TINT];
- t2 = t->type;
- break;
-
- case TMAP:
- t1 = t->down;
- t2 = t->type;
- break;
-
- case TCHAN:
- t1 = t->type;
- t2 = nil;
- if(count(n->list) == 2)
- goto toomany;
- break;
-
- case TSTRING:
- t1 = types[TINT];
- t2 = types[TINT];
- break;
- }
-
- if(count(n->list) > 2) {
- toomany:
- yyerror("too many variables in range");
- }
-
- v1 = n->list->n;
- v2 = N;
- if(n->list->next)
- v2 = n->list->next->n;
-
- if(v1->defn == n)
- v1->type = t1;
- else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
- yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
- if(v2) {
- if(v2->defn == n)
- v2->type = t2;
- else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
- yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
- }
-
-out:
- typechecklist(n->nbody, Etop);
-
- // second half of dance
- n->typecheck = 1;
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->typecheck == 0)
- typecheck(&ll->n, Erv | Easgn);
-}
-
-void
-walkrange(Node *n)
-{
- Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
- Node *ha, *hit; // hidden aggregate, iterator
- Node *hn, *hp; // hidden len, pointer
- Node *hb; // hidden bool
- Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
- Node *fn, *tmp;
- NodeList *body, *init;
- Type *th, *t;
-
- t = n->type;
- init = nil;
-
- a = n->right;
- if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) {
- a = nod(OCONV, n->right, N);
- a->type = types[TSTRING];
- }
-
- v1 = n->list->n;
- hv1 = N;
-
- v2 = N;
- if(n->list->next)
- v2 = n->list->next->n;
- hv2 = N;
-
- if(v2 == N && t->etype == TARRAY) {
- // will have just one reference to argument.
- // no need to make a potentially expensive copy.
- ha = a;
- } else {
- ha = nod(OXXX, N, N);
- tempname(ha, a->type);
- init = list(init, nod(OAS, ha, a));
- }
-
- switch(t->etype) {
- default:
- fatal("walkrange");
-
- case TARRAY:
- hv1 = nod(OXXX, N, n);
- tempname(hv1, types[TINT]);
- hn = nod(OXXX, N, N);
- tempname(hn, types[TINT]);
- hp = nil;
-
- init = list(init, nod(OAS, hv1, N));
- init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
- if(v2) {
- hp = nod(OXXX, N, N);
- tempname(hp, ptrto(n->type->type));
- tmp = nod(OINDEX, ha, nodintconst(0));
- tmp->etype = 1; // no bounds check
- init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
- }
-
- n->ntest = nod(OLT, hv1, hn);
- n->nincr = nod(OASOP, hv1, nodintconst(1));
- n->nincr->etype = OADD;
- body = list1(nod(OAS, v1, hv1));
- if(v2) {
- body = list(body, nod(OAS, v2, nod(OIND, hp, N)));
- tmp = nod(OADD, hp, nodintconst(t->type->width));
- tmp->type = hp->type;
- tmp->typecheck = 1;
- tmp->right->type = types[tptr];
- tmp->right->typecheck = 1;
- body = list(body, nod(OAS, hp, tmp));
- }
- break;
-
- case TMAP:
- th = typ(TARRAY);
- th->type = ptrto(types[TUINT8]);
- th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
- hit = nod(OXXX, N, N);
- tempname(hit, th);
-
- fn = syslook("mapiterinit", 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, th);
- init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N)));
- n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil());
-
- fn = syslook("mapiternext", 1);
- argtype(fn, th);
- n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
-
- if(v2 == N) {
- fn = syslook("mapiter1", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N)));
- } else {
- fn = syslook("mapiter2", 1);
- argtype(fn, th);
- argtype(fn, t->down);
- argtype(fn, t->type);
- a = nod(OAS2, N, N);
- a->list = list(list1(v1), v2);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N)));
- }
- body = list1(a);
- break;
-
- case TCHAN:
- hv1 = nod(OXXX, N, n);
- tempname(hv1, t->type);
- hb = nod(OXXX, N, N);
- tempname(hb, types[TBOOL]);
-
- n->ntest = nod(ONE, hb, nodbool(0));
- a = nod(OAS2RECV, N, N);
- a->typecheck = 1;
- a->list = list(list1(hv1), hb);
- a->rlist = list1(nod(ORECV, ha, N));
- n->ntest->ninit = list1(a);
- body = list1(nod(OAS, v1, hv1));
- break;
-
- case TSTRING:
- ohv1 = nod(OXXX, N, N);
- tempname(ohv1, types[TINT]);
-
- hv1 = nod(OXXX, N, N);
- tempname(hv1, types[TINT]);
- init = list(init, nod(OAS, hv1, N));
-
- if(v2 == N)
- a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
- else {
- hv2 = nod(OXXX, N, N);
- tempname(hv2, types[TINT]);
- a = nod(OAS2, N, N);
- a->list = list(list1(hv1), hv2);
- fn = syslook("stringiter2", 0);
- a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
- }
- n->ntest = nod(ONE, hv1, nodintconst(0));
- n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
-
- body = list1(nod(OAS, v1, ohv1));
- if(v2 != N)
- body = list(body, nod(OAS, v2, hv2));
- break;
- }
-
- n->op = OFOR;
- typechecklist(init, Etop);
- n->ninit = concat(n->ninit, init);
- typechecklist(n->ntest->ninit, Etop);
- typecheck(&n->ntest, Erv);
- typecheck(&n->nincr, Etop);
- typechecklist(body, Etop);
- n->nbody = concat(body, n->nbody);
- walkstmt(&n);
-}
-
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
deleted file mode 100644
index 810787d30..000000000
--- a/src/cmd/gc/reflect.c
+++ /dev/null
@@ -1,939 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/*
- * runtime interface and reflection data structures
- */
-
-static NodeList* signatlist;
-static Sym* dtypesym(Type*);
-static Sym* weaktypesym(Type*);
-
-static int
-sigcmp(Sig *a, Sig *b)
-{
- int i;
-
- i = strcmp(a->name, b->name);
- if(i != 0)
- return i;
- if(a->pkg == b->pkg)
- return 0;
- if(a->pkg == nil)
- return -1;
- if(b->pkg == nil)
- return +1;
- return strcmp(a->pkg->path->s, b->pkg->path->s);
-}
-
-static Sig*
-lsort(Sig *l, int(*f)(Sig*, Sig*))
-{
- Sig *l1, *l2, *le;
-
- if(l == 0 || l->link == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == 0)
- break;
- l2 = l2->link;
- if(l2 == 0)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = 0;
- l1 = lsort(l, f);
- l2 = lsort(l2, f);
-
- /* set up lead element */
- if((*f)(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if((*f)(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = 0;
- return l;
-}
-
-/*
- * f is method type, with receiver.
- * return function type, receiver as first argument (or not).
- */
-Type*
-methodfunc(Type *f, Type *receiver)
-{
- NodeList *in, *out;
- Node *d;
- Type *t;
-
- in = nil;
- if(receiver) {
- d = nod(ODCLFIELD, N, N);
- d->type = receiver;
- in = list(in, d);
- }
- for(t=getinargx(f)->type; t; t=t->down) {
- d = nod(ODCLFIELD, N, N);
- d->type = t->type;
- d->isddd = t->isddd;
- in = list(in, d);
- }
-
- out = nil;
- for(t=getoutargx(f)->type; t; t=t->down) {
- d = nod(ODCLFIELD, N, N);
- d->type = t->type;
- out = list(out, d);
- }
-
- return functype(N, in, out);
-}
-
-/*
- * return methods of non-interface type t, sorted by name.
- * generates stub functions as needed.
- */
-static Sig*
-methods(Type *t)
-{
- Type *f, *mt, *it, *this;
- Sig *a, *b;
- Sym *method;
- Prog *oldlist;
-
- // named method type
- mt = methtype(t);
- if(mt == T)
- return nil;
- expandmeth(mt->sym, mt);
-
- // type stored in interface word
- it = t;
- if(it->width > widthptr)
- it = ptrto(t);
-
- // make list of methods for t,
- // generating code if necessary.
- a = nil;
- oldlist = nil;
- for(f=mt->xmethod; f; f=f->down) {
- if(f->type->etype != TFUNC)
- continue;
- if(f->etype != TFIELD)
- fatal("methods: not field");
- method = f->sym;
- if(method == nil)
- continue;
-
- // get receiver type for this particular method.
- // if pointer receiver but non-pointer t and
- // this is not an embedded pointer inside a struct,
- // method does not apply.
- this = getthisx(f->type)->type->type;
- if(isptr[this->etype] && this->type == t)
- continue;
- if(isptr[this->etype] && !isptr[t->etype]
- && f->embedded != 2 && !isifacemethod(f->type))
- continue;
-
- b = mal(sizeof(*b));
- b->link = a;
- a = b;
-
- a->name = method->name;
- if(!exportname(method->name)) {
- if(method->pkg == nil)
- fatal("methods: missing package");
- a->pkg = method->pkg;
- }
- a->isym = methodsym(method, it, 1);
- a->tsym = methodsym(method, t, 0);
- a->type = methodfunc(f->type, t);
- a->mtype = methodfunc(f->type, nil);
-
- if(!(a->isym->flags & SymSiggen)) {
- a->isym->flags |= SymSiggen;
- if(!eqtype(this, it) || this->width < types[tptr]->width) {
- if(oldlist == nil)
- oldlist = pc;
- // Is okay to call genwrapper here always,
- // but we can generate more efficient code
- // using genembedtramp if all that is necessary
- // is a pointer adjustment and a JMP.
- if(isptr[it->etype] && isptr[this->etype]
- && f->embedded && !isifacemethod(f->type))
- genembedtramp(it, f, a->isym, 1);
- else
- genwrapper(it, f, a->isym, 1);
- }
- }
-
- if(!(a->tsym->flags & SymSiggen)) {
- a->tsym->flags |= SymSiggen;
- if(!eqtype(this, t)) {
- if(oldlist == nil)
- oldlist = pc;
- if(isptr[t->etype] && isptr[this->etype]
- && f->embedded && !isifacemethod(f->type))
- genembedtramp(t, f, a->tsym, 0);
- else
- genwrapper(t, f, a->tsym, 0);
- }
- }
- }
-
- // restore data output
- if(oldlist) {
- // old list ended with AEND; change to ANOP
- // so that the trampolines that follow can be found.
- nopout(oldlist);
-
- // start new data list
- newplist();
- }
-
- return lsort(a, sigcmp);
-}
-
-/*
- * return methods of interface type t, sorted by name.
- */
-static Sig*
-imethods(Type *t)
-{
- Sig *a, *all, *last;
- Type *f;
- Sym *method, *isym;
- Prog *oldlist;
-
- all = nil;
- last = nil;
- oldlist = nil;
- for(f=t->type; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("imethods: not field");
- if(f->type->etype != TFUNC || f->sym == nil)
- continue;
- method = f->sym;
- a = mal(sizeof(*a));
- a->name = method->name;
- if(!exportname(method->name)) {
- if(method->pkg == nil)
- fatal("imethods: missing package");
- a->pkg = method->pkg;
- }
- a->mtype = f->type;
- a->offset = 0;
- a->type = methodfunc(f->type, nil);
-
- if(last && sigcmp(last, a) >= 0)
- fatal("sigcmp vs sortinter %s %s", last->name, a->name);
- if(last == nil)
- all = a;
- else
- last->link = a;
- last = a;
-
- // Compiler can only refer to wrappers for
- // named interface types.
- if(t->sym == S)
- continue;
-
- // NOTE(rsc): Perhaps an oversight that
- // IfaceType.Method is not in the reflect data.
- // Generate the method body, so that compiled
- // code can refer to it.
- isym = methodsym(method, t, 0);
- if(!(isym->flags & SymSiggen)) {
- isym->flags |= SymSiggen;
- if(oldlist == nil)
- oldlist = pc;
- genwrapper(t, f, isym, 0);
- }
- }
-
- if(oldlist) {
- // old list ended with AEND; change to ANOP
- // so that the trampolines that follow can be found.
- nopout(oldlist);
-
- // start new data list
- newplist();
- }
-
- return all;
-}
-
-static void
-dimportpath(Pkg *p)
-{
- static Pkg *gopkg;
- char *nam;
- Node *n;
-
- if(p->pathsym != S)
- return;
-
- if(gopkg == nil) {
- gopkg = mkpkg(strlit("go"));
- gopkg->name = "go";
- }
- nam = smprint("importpath.%s.", p->prefix);
-
- n = nod(ONAME, N, N);
- n->sym = pkglookup(nam, gopkg);
- free(nam);
- n->class = PEXTERN;
- n->xoffset = 0;
- p->pathsym = n->sym;
-
- gdatastring(n, p->path);
- ggloblsym(n->sym, types[TSTRING]->width, 1);
-}
-
-static int
-dgopkgpath(Sym *s, int ot, Pkg *pkg)
-{
- if(pkg == nil)
- return dgostringptr(s, ot, nil);
-
- // Emit reference to go.importpath.""., which 6l will
- // rewrite using the correct import path. Every package
- // that imports this one directly defines the symbol.
- if(pkg == localpkg) {
- static Sym *ns;
-
- if(ns == nil)
- ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
- return dsymptr(s, ot, ns, 0);
- }
-
- dimportpath(pkg);
- return dsymptr(s, ot, pkg->pathsym, 0);
-}
-
-/*
- * uncommonType
- * ../../pkg/runtime/type.go:/uncommonType
- */
-static int
-dextratype(Sym *sym, int off, Type *t, int ptroff)
-{
- int ot, n;
- Sym *s;
- Sig *a, *m;
-
- m = methods(t);
- if(t->sym == nil && m == nil)
- return off;
-
- // fill in *extraType pointer in header
- dsymptr(sym, ptroff, sym, off);
-
- n = 0;
- for(a=m; a; a=a->link) {
- dtypesym(a->type);
- n++;
- }
-
- ot = off;
- s = sym;
- if(t->sym) {
- ot = dgostringptr(s, ot, t->sym->name);
- if(t != types[t->etype])
- ot = dgopkgpath(s, ot, t->sym->pkg);
- else
- ot = dgostringptr(s, ot, nil);
- } else {
- ot = dgostringptr(s, ot, nil);
- ot = dgostringptr(s, ot, nil);
- }
-
- // slice header
- ot = dsymptr(s, ot, s, ot + widthptr + 2*4);
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
-
- // methods
- for(a=m; a; a=a->link) {
- // method
- // ../../pkg/runtime/type.go:/method
- ot = dgostringptr(s, ot, a->name);
- ot = dgopkgpath(s, ot, a->pkg);
- ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
- ot = dsymptr(s, ot, dtypesym(a->type), 0);
- if(a->isym)
- ot = dsymptr(s, ot, a->isym, 0);
- else
- ot = duintptr(s, ot, 0);
- if(a->tsym)
- ot = dsymptr(s, ot, a->tsym, 0);
- else
- ot = duintptr(s, ot, 0);
- }
-
- return ot;
-}
-
-enum {
- KindBool = 1,
- KindInt,
- KindInt8,
- KindInt16,
- KindInt32,
- KindInt64,
- KindUint,
- KindUint8,
- KindUint16,
- KindUint32,
- KindUint64,
- KindUintptr,
- KindFloat32,
- KindFloat64,
- KindComplex64,
- KindComplex128,
- KindArray,
- KindChan,
- KindFunc,
- KindInterface,
- KindMap,
- KindPtr,
- KindSlice,
- KindString,
- KindStruct,
- KindUnsafePointer,
-
- KindNoPointers = 1<<7,
-};
-
-static int
-kinds[] =
-{
- [TINT] = KindInt,
- [TUINT] = KindUint,
- [TINT8] = KindInt8,
- [TUINT8] = KindUint8,
- [TINT16] = KindInt16,
- [TUINT16] = KindUint16,
- [TINT32] = KindInt32,
- [TUINT32] = KindUint32,
- [TINT64] = KindInt64,
- [TUINT64] = KindUint64,
- [TUINTPTR] = KindUintptr,
- [TFLOAT32] = KindFloat32,
- [TFLOAT64] = KindFloat64,
- [TBOOL] = KindBool,
- [TSTRING] = KindString,
- [TPTR32] = KindPtr,
- [TPTR64] = KindPtr,
- [TSTRUCT] = KindStruct,
- [TINTER] = KindInterface,
- [TCHAN] = KindChan,
- [TMAP] = KindMap,
- [TARRAY] = KindArray,
- [TFUNC] = KindFunc,
- [TCOMPLEX64] = KindComplex64,
- [TCOMPLEX128] = KindComplex128,
- [TUNSAFEPTR] = KindUnsafePointer,
-};
-
-static char*
-structnames[] =
-{
- [TINT] = "*runtime.IntType",
- [TUINT] = "*runtime.UintType",
- [TINT8] = "*runtime.IntType",
- [TUINT8] = "*runtime.UintType",
- [TINT16] = "*runtime.IntType",
- [TUINT16] = "*runtime.UintType",
- [TINT32] = "*runtime.IntType",
- [TUINT32] = "*runtime.UintType",
- [TINT64] = "*runtime.IntType",
- [TUINT64] = "*runtime.UintType",
- [TUINTPTR] = "*runtime.UintType",
- [TCOMPLEX64] = "*runtime.ComplexType",
- [TCOMPLEX128] = "*runtime.ComplexType",
- [TFLOAT32] = "*runtime.FloatType",
- [TFLOAT64] = "*runtime.FloatType",
- [TBOOL] = "*runtime.BoolType",
- [TSTRING] = "*runtime.StringType",
- [TUNSAFEPTR] = "*runtime.UnsafePointerType",
-
- [TPTR32] = "*runtime.PtrType",
- [TPTR64] = "*runtime.PtrType",
- [TSTRUCT] = "*runtime.StructType",
- [TINTER] = "*runtime.InterfaceType",
- [TCHAN] = "*runtime.ChanType",
- [TMAP] = "*runtime.MapType",
- [TARRAY] = "*runtime.ArrayType",
- [TFUNC] = "*runtime.FuncType",
-};
-
-static Sym*
-typestruct(Type *t)
-{
- char *name;
- int et;
-
- et = t->etype;
- if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) {
- fatal("typestruct %lT", t);
- return nil; // silence gcc
- }
-
- if(isslice(t))
- name = "*runtime.SliceType";
-
- return pkglookup(name, typepkg);
-}
-
-static int
-haspointers(Type *t)
-{
- Type *t1;
-
- switch(t->etype) {
- case TINT:
- case TUINT:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TUINTPTR:
- case TFLOAT32:
- case TFLOAT64:
- case TBOOL:
- return 0;
- case TARRAY:
- if(t->bound < 0) // slice
- return 1;
- return haspointers(t->type);
- case TSTRUCT:
- for(t1=t->type; t1!=T; t1=t1->down)
- if(haspointers(t1->type))
- return 1;
- return 0;
- case TSTRING:
- case TPTR32:
- case TPTR64:
- case TUNSAFEPTR:
- case TINTER:
- case TCHAN:
- case TMAP:
- case TFUNC:
- default:
- return 1;
- }
-}
-
-/*
- * commonType
- * ../../pkg/runtime/type.go:/commonType
- */
-static int
-dcommontype(Sym *s, int ot, Type *t)
-{
- int i;
- Sym *sptr;
- char *p;
-
- dowidth(t);
-
- sptr = nil;
- if(t->sym != nil && !isptr[t->etype])
- sptr = dtypesym(ptrto(t));
- else
- sptr = weaktypesym(ptrto(t));
-
- // empty interface pointing at this type.
- // all the references that we emit are *interface{};
- // they point here.
- ot = rnd(ot, widthptr);
- ot = dsymptr(s, ot, typestruct(t), 0);
- ot = dsymptr(s, ot, s, 2*widthptr);
-
- // ../../pkg/runtime/type.go:/commonType
- // actual type structure
- // type commonType struct {
- // size uintptr;
- // hash uint32;
- // alg uint8;
- // align uint8;
- // fieldAlign uint8;
- // kind uint8;
- // string *string;
- // *extraType;
- // ptrToThis *Type
- // }
- ot = duintptr(s, ot, t->width);
- ot = duint32(s, ot, typehash(t));
- ot = duint8(s, ot, algtype(t));
- ot = duint8(s, ot, t->align); // align
- ot = duint8(s, ot, t->align); // fieldAlign
- i = kinds[t->etype];
- if(t->etype == TARRAY && t->bound < 0)
- i = KindSlice;
- if(!haspointers(t))
- i |= KindNoPointers;
- ot = duint8(s, ot, i); // kind
- longsymnames = 1;
- p = smprint("%-T", t);
- longsymnames = 0;
- ot = dgostringptr(s, ot, p); // string
- free(p);
-
- // skip pointer to extraType,
- // which follows the rest of this type structure.
- // caller will fill in if needed.
- // otherwise linker will assume 0.
- ot += widthptr;
-
- ot = dsymptr(s, ot, sptr, 0); // ptrto type
- return ot;
-}
-
-Sym*
-typesym(Type *t)
-{
- char *p;
- Sym *s;
-
- p = smprint("%#-T", t);
- s = pkglookup(p, typepkg);
- free(p);
- return s;
-}
-
-Node*
-typename(Type *t)
-{
- Sym *s;
- Node *n;
-
- if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
- fatal("typename %T", t);
- s = typesym(t);
- if(s->def == N) {
- n = nod(ONAME, N, N);
- n->sym = s;
- n->type = types[TUINT8];
- n->addable = 1;
- n->ullman = 1;
- n->class = PEXTERN;
- n->xoffset = 0;
- s->def = n;
-
- signatlist = list(signatlist, typenod(t));
- }
-
- n = nod(OADDR, s->def, N);
- n->type = ptrto(s->def->type);
- n->addable = 1;
- n->ullman = 2;
- return n;
-}
-
-static Sym*
-weaktypesym(Type *t)
-{
- char *p;
- Sym *s;
- static Pkg *weak;
-
- if(weak == nil) {
- weak = mkpkg(strlit("weak.type"));
- weak->name = "weak.type";
- weak->prefix = "weak.type"; // not weak%2etype
- }
-
- p = smprint("%#-T", t);
- s = pkglookup(p, weak);
- free(p);
- return s;
-}
-
-static Sym*
-dtypesym(Type *t)
-{
- int ot, xt, n, isddd, dupok;
- Sym *s, *s1, *s2;
- Sig *a, *m;
- Type *t1, *tbase, *t2;
-
- if(isideal(t))
- fatal("dtypesym %T", t);
-
- s = typesym(t);
- if(s->flags & SymSiggen)
- return s;
- s->flags |= SymSiggen;
-
- // special case (look for runtime below):
- // when compiling package runtime,
- // emit the type structures for int, float, etc.
- tbase = t;
- if(isptr[t->etype] && t->sym == S && t->type->sym != S)
- tbase = t->type;
- dupok = tbase->sym == S;
-
- if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc
- goto ok;
-
- // named types from other files are defined only by those files
- if(tbase->sym && !tbase->local)
- return s;
- if(isforw[tbase->etype])
- return s;
-
-ok:
- ot = 0;
- xt = 0;
- switch(t->etype) {
- default:
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- break;
-
- case TARRAY:
- if(t->bound >= 0) {
- // ../../pkg/runtime/type.go:/ArrayType
- s1 = dtypesym(t->type);
- t2 = typ(TARRAY);
- t2->type = t->type;
- t2->bound = -1; // slice
- s2 = dtypesym(t2);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = dsymptr(s, ot, s2, 0);
- ot = duintptr(s, ot, t->bound);
- } else {
- // ../../pkg/runtime/type.go:/SliceType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- }
- break;
-
- case TCHAN:
- // ../../pkg/runtime/type.go:/ChanType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = duintptr(s, ot, t->chan);
- break;
-
- case TFUNC:
- for(t1=getthisx(t)->type; t1; t1=t1->down)
- dtypesym(t1->type);
- isddd = 0;
- for(t1=getinargx(t)->type; t1; t1=t1->down) {
- isddd = t1->isddd;
- dtypesym(t1->type);
- }
- for(t1=getoutargx(t)->type; t1; t1=t1->down)
- dtypesym(t1->type);
-
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = duint8(s, ot, isddd);
-
- // two slice headers: in and out.
- ot = rnd(ot, widthptr);
- ot = dsymptr(s, ot, s, ot+2*(widthptr+2*4));
- n = t->thistuple + t->intuple;
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
- ot = dsymptr(s, ot, s, ot+1*(widthptr+2*4)+n*widthptr);
- ot = duint32(s, ot, t->outtuple);
- ot = duint32(s, ot, t->outtuple);
-
- // slice data
- for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- break;
-
- case TINTER:
- m = imethods(t);
- n = 0;
- for(a=m; a; a=a->link) {
- dtypesym(a->type);
- n++;
- }
-
- // ../../pkg/runtime/type.go:/InterfaceType
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s, ot+widthptr+2*4);
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
- for(a=m; a; a=a->link) {
- // ../../pkg/runtime/type.go:/imethod
- ot = dgostringptr(s, ot, a->name);
- ot = dgopkgpath(s, ot, a->pkg);
- ot = dsymptr(s, ot, dtypesym(a->type), 0);
- }
- break;
-
- case TMAP:
- // ../../pkg/runtime/type.go:/MapType
- s1 = dtypesym(t->down);
- s2 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- ot = dsymptr(s, ot, s2, 0);
- break;
-
- case TPTR32:
- case TPTR64:
- if(t->type->etype == TANY) {
- // ../../pkg/runtime/type.go:/UnsafePointerType
- ot = dcommontype(s, ot, t);
- break;
- }
- // ../../pkg/runtime/type.go:/PtrType
- s1 = dtypesym(t->type);
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s1, 0);
- break;
-
- case TSTRUCT:
- // ../../pkg/runtime/type.go:/StructType
- // for security, only the exported fields.
- n = 0;
- for(t1=t->type; t1!=T; t1=t1->down) {
- dtypesym(t1->type);
- n++;
- }
- ot = dcommontype(s, ot, t);
- xt = ot - 2*widthptr;
- ot = dsymptr(s, ot, s, ot+widthptr+2*4);
- ot = duint32(s, ot, n);
- ot = duint32(s, ot, n);
- for(t1=t->type; t1!=T; t1=t1->down) {
- // ../../pkg/runtime/type.go:/structField
- if(t1->sym && !t1->embedded) {
- ot = dgostringptr(s, ot, t1->sym->name);
- if(exportname(t1->sym->name))
- ot = dgostringptr(s, ot, nil);
- else
- ot = dgopkgpath(s, ot, t1->sym->pkg);
- } else {
- ot = dgostringptr(s, ot, nil);
- ot = dgostringptr(s, ot, nil);
- }
- ot = dsymptr(s, ot, dtypesym(t1->type), 0);
- ot = dgostrlitptr(s, ot, t1->note);
- ot = duintptr(s, ot, t1->width); // field offset
- }
- break;
- }
- ot = dextratype(s, ot, t, xt);
- ggloblsym(s, ot, dupok);
- return s;
-}
-
-void
-dumptypestructs(void)
-{
- int i;
- NodeList *l;
- Node *n;
- Type *t;
- Pkg *p;
-
- // copy types from externdcl list to signatlist
- for(l=externdcl; l; l=l->next) {
- n = l->n;
- if(n->op != OTYPE)
- continue;
- signatlist = list(signatlist, n);
- }
-
- // process signatlist
- for(l=signatlist; l; l=l->next) {
- n = l->n;
- if(n->op != OTYPE)
- continue;
- t = n->type;
- dtypesym(t);
- if(t->sym)
- dtypesym(ptrto(t));
- }
-
- // generate import strings for imported packages
- for(i=0; i<nelem(phash); i++)
- for(p=phash[i]; p; p=p->link)
- if(p->direct)
- dimportpath(p);
-
- // do basic types if compiling package runtime.
- // they have to be in at least one package,
- // and runtime is always loaded implicitly,
- // so this is as good as any.
- // another possible choice would be package main,
- // but using runtime means fewer copies in .6 files.
- if(compiling_runtime) {
- for(i=1; i<=TBOOL; i++)
- dtypesym(ptrto(types[i]));
- dtypesym(ptrto(types[TSTRING]));
- dtypesym(ptrto(types[TUNSAFEPTR]));
-
- // add paths for runtime and main, which 6l imports implicitly.
- dimportpath(runtimepkg);
- dimportpath(mkpkg(strlit("main")));
- }
-}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
deleted file mode 100644
index e13c95db9..000000000
--- a/src/cmd/gc/runtime.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-package PACKAGE
-
-// emitted by compiler, not referred to by go programs
-
-func new(int32) *any
-func panicindex()
-func panicslice()
-func throwreturn()
-func throwinit()
-func panicwrap(string, string, string)
-
-func panic(interface{})
-func recover(*int32) interface{}
-
-func printbool(bool)
-func printfloat(float64)
-func printint(int64)
-func printuint(uint64)
-func printcomplex(complex128)
-func printstring(string)
-func printpointer(any)
-func printiface(any)
-func printeface(any)
-func printslice(any)
-func printnl()
-func printsp()
-func goprintf()
-
-// filled in by compiler: int n, string, string, ...
-func concatstring()
-
-// filled in by compiler: Type*, int n, Slice, ...
-func append()
-func appendslice(typ *byte, x any, y []any) any
-
-func cmpstring(string, string) int
-func slicestring(string, int, int) string
-func slicestring1(string, int) string
-func intstring(int64) string
-func slicebytetostring([]byte) string
-func sliceinttostring([]int) string
-func stringtoslicebyte(string) []byte
-func stringtosliceint(string) []int
-func stringiter(string, int) int
-func stringiter2(string, int) (retk int, retv int)
-func slicecopy(to any, fr any, wid uint32) int
-func slicestringcopy(to any, fr any) int
-
-// interface conversions
-func convI2E(elem any) (ret any)
-func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem any) (ret any)
-func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
-
-// interface type assertions x.(T)
-func assertE2E(typ *byte, iface any) (ret any)
-func assertE2E2(typ *byte, iface any) (ret any, ok bool)
-func assertE2I(typ *byte, iface any) (ret any)
-func assertE2I2(typ *byte, iface any) (ret any, ok bool)
-func assertE2T(typ *byte, iface any) (ret any)
-func assertE2T2(typ *byte, iface any) (ret any, ok bool)
-func assertI2E(typ *byte, iface any) (ret any)
-func assertI2E2(typ *byte, iface any) (ret any, ok bool)
-func assertI2I(typ *byte, iface any) (ret any)
-func assertI2I2(typ *byte, iface any) (ret any, ok bool)
-func assertI2T(typ *byte, iface any) (ret any)
-func assertI2T2(typ *byte, iface any) (ret any, ok bool)
-
-func ifaceeq(i1 any, i2 any) (ret bool)
-func efaceeq(i1 any, i2 any) (ret bool)
-func ifacethash(i1 any) (ret uint32)
-func efacethash(i1 any) (ret uint32)
-
-// *byte is really *runtime.Type
-func makemap(key, val *byte, hint int64) (hmap map[any]any)
-func mapaccess1(hmap map[any]any, key any) (val any)
-func mapaccess2(hmap map[any]any, key any) (val any, pres bool)
-func mapassign1(hmap map[any]any, key any, val any)
-func mapassign2(hmap map[any]any, key any, val any, pres bool)
-func mapiterinit(hmap map[any]any, hiter *any)
-func mapiternext(hiter *any)
-func mapiter1(hiter *any) (key any)
-func mapiter2(hiter *any) (key any, val any)
-
-// *byte is really *runtime.Type
-func makechan(elem *byte, hint int64) (hchan chan any)
-func chanrecv1(hchan <-chan any) (elem any)
-func chanrecv2(hchan <-chan any) (elem any, received bool)
-func chansend1(hchan chan<- any, elem any)
-func closechan(hchan any)
-func closedchan(hchan any) bool
-
-func selectnbsend(hchan chan<- any, elem any) bool
-func selectnbrecv(elem *any, hchan <-chan any) bool
-func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
-
-func newselect(size int) (sel *byte)
-func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool)
-func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
-func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
-func selectdefault(sel *byte) (selected bool)
-func selectgo(sel *byte)
-func block()
-
-func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func growslice(typ *byte, old []any, n int64) (ary []any)
-func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
-func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
-func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
-
-func closure() // has args, but compiler fills in
-
-// only used on 32-bit
-func int64div(int64, int64) int64
-func uint64div(uint64, uint64) uint64
-func int64mod(int64, int64) int64
-func uint64mod(uint64, uint64) uint64
-func float64toint64(float64) int64
-func float64touint64(float64) uint64
-func int64tofloat64(int64) float64
-func uint64tofloat64(uint64) float64
-
-func complex128div(num complex128, den complex128) (quo complex128)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
deleted file mode 100644
index 91d4ebfd5..000000000
--- a/src/cmd/gc/select.c
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * select
- */
-
-#include "go.h"
-
-void
-typecheckselect(Node *sel)
-{
- Node *ncase, *n, *def;
- NodeList *l;
- int lno, count;
-
- def = nil;
- lno = setlineno(sel);
- count = 0;
- typechecklist(sel->ninit, Etop);
- for(l=sel->list; l; l=l->next) {
- count++;
- ncase = l->n;
- setlineno(ncase);
- if(ncase->op != OXCASE)
- fatal("typecheckselect %O", ncase->op);
-
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in select (first at %L)", def->lineno);
- else
- def = ncase;
- } else if(ncase->list->next) {
- yyerror("select cases cannot be lists");
- } else {
- n = typecheck(&ncase->list->n, Etop);
- ncase->left = n;
- ncase->list = nil;
- setlineno(n);
- switch(n->op) {
- default:
- yyerror("select case must be receive, send or assign recv");
- break;
-
- case OAS:
- // convert x = <-c into OSELRECV(x, <-c).
- // remove implicit conversions; the eventual assignment
- // will reintroduce them.
- if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
- n->right = n->right->left;
-
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV;
- break;
-
- case OAS2RECV:
- // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV2;
- n->left = n->list->n;
- n->ntest = n->list->next->n;
- n->right = n->rlist->n;
- break;
-
- case ORECV:
- // convert <-c into OSELRECV(N, <-c)
- n = nod(OSELRECV, N, n);
- ncase->left = n;
- break;
-
- case OSEND:
- break;
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
- sel->xoffset = count;
- lineno = lno;
-}
-
-void
-walkselect(Node *sel)
-{
- int lno, i;
- Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
- NodeList *l, *init;
-
- if(sel->list == nil && sel->xoffset != 0)
- fatal("double walkselect"); // already rewrote
-
- lno = setlineno(sel);
- i = count(sel->list);
-
- // optimization: zero-case select
- if(i == 0) {
- sel->nbody = list1(mkcall("block", nil, nil));
- goto out;
- }
-
- // optimization: one-case select: single op.
- if(i == 1) {
- cas = sel->list->n;
- l = cas->ninit;
- if(cas->left != N) { // not default:
- n = cas->left;
- l = concat(l, n->ninit);
- n->ninit = nil;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- ch = cheapexpr(n->left, &l);
- n->left = ch;
- break;
-
- case OSELRECV:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- if(n->left == N)
- n = r;
- else {
- n = nod(OAS, n->left, r);
- typecheck(&n, Etop);
- }
- break;
-
- case OSELRECV2:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- a = nod(OAS2, N, N);
- a->list = n->list;
- a->rlist = n->rlist;
- n = a;
- typecheck(&n, Etop);
- break;
- }
-
- // if ch == nil { block() }; n;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, ch, nodnil());
- a->nbody = list1(mkcall("block", nil, &l));
- typecheck(&a, Etop);
- l = list(l, a);
- l = list(l, n);
- }
- l = concat(l, cas->nbody);
- sel->nbody = l;
- goto out;
- }
-
- // introduce temporary variables for OSELRECV where needed.
- // this rewrite is used by both the general code and the next optimization.
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- n = cas->left;
- if(n == N)
- continue;
- switch(n->op) {
- case OSELRECV:
- case OSELRECV2:
- ch = n->right->left;
-
- // If we can use the address of the target without
- // violating addressability or order of operations, do so.
- // Otherwise introduce a temporary.
- // Also introduce a temporary for := variables that escape,
- // so that we can delay the heap allocation until the case
- // is selected.
- if(n->op == OSELRECV2) {
- if(n->ntest == N || isblank(n->ntest))
- n->ntest = nodnil();
- else if(n->ntest->op == ONAME &&
- (!n->colas || (n->ntest->class&PHEAP) == 0) &&
- convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) {
- n->ntest = nod(OADDR, n->ntest, N);
- n->ntest->etype = 1; // pointer does not escape
- typecheck(&n->ntest, Erv);
- } else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, types[TBOOL]);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->ntest, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->ntest = a;
- }
- }
-
- if(n->left == N || isblank(n->left))
- n->left = nodnil();
- else if(n->left->op == ONAME &&
- (!n->colas || (n->left->class&PHEAP) == 0) &&
- convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
- n->left = nod(OADDR, n->left, N);
- n->left->etype = 1; // pointer does not escape
- typecheck(&n->left, Erv);
- } else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, ch->type->type);
- a = nod(OADDR, tmp, N);
- a->etype = 1; // pointer does not escape
- typecheck(&a, Erv);
- r = nod(OAS, n->left, tmp);
- typecheck(&r, Etop);
- cas->nbody = concat(list1(r), cas->nbody);
- n->left = a;
- }
-
- cas->nbody = concat(n->ninit, cas->nbody);
- n->ninit = nil;
- break;
- }
- }
-
- // optimization: two-case select but one is default: single non-blocking op.
- if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
- if(sel->list->n->left == nil) {
- cas = sel->list->next->n;
- dflt = sel->list->n;
- } else {
- dflt = sel->list->next->n;
- cas = sel->list->n;
- }
-
- n = cas->left;
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // if c != nil && selectnbsend(c, v) { body } else { default body }
- ch = cheapexpr(n->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbsend", 2, ch->type),
- types[TBOOL], &r->ninit, ch, n->right));
- break;
-
- case OSELRECV:
- // if c != nil && selectnbrecv(&v, c) { body } else { default body }
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbrecv", 2, ch->type),
- types[TBOOL], &r->ninit, n->left, ch));
- break;
-
- case OSELRECV2:
- // if c != nil && selectnbrecv2(&v, c) { body } else { default body }
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- ch = cheapexpr(n->right->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbrecv2", 2, ch->type),
- types[TBOOL], &r->ninit, n->left, n->ntest, ch));
- break;
- }
- typecheck(&r->ntest, Erv);
- r->nbody = cas->nbody;
- r->nelse = concat(dflt->ninit, dflt->nbody);
- sel->nbody = list1(r);
- goto out;
- }
-
- init = sel->ninit;
- sel->ninit = nil;
-
- // generate sel-struct
- var = nod(OXXX, N, N);
- tempname(var, ptrto(types[TUINT8]));
- r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
- typecheck(&r, Etop);
- init = list(init, r);
-
- // register cases
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- n = cas->left;
- r = nod(OIF, N, N);
- r->nbody = cas->ninit;
- cas->ninit = nil;
- if(n != nil) {
- r->nbody = concat(r->nbody, n->ninit);
- n->ninit = nil;
- }
- if(n == nil) {
- // selectdefault(sel *byte);
- r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
- } else {
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
- r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
- &init, var, n->left, n->right);
- break;
-
- case OSELRECV:
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
- &init, var, n->right->left, n->left);
- break;
-
- case OSELRECV2:
- // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
- &init, var, n->right->left, n->left, n->ntest);
- break;
- }
- }
- r->nbody = concat(r->nbody, cas->nbody);
- r->nbody = list(r->nbody, nod(OBREAK, N, N));
- init = list(init, r);
- }
-
- // run the select
- init = list(init, mkcall("selectgo", T, nil, var));
- sel->nbody = init;
-
-out:
- sel->list = nil;
- walkstmtlist(sel->nbody);
- lineno = lno;
-}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
deleted file mode 100644
index eb7ef31ec..000000000
--- a/src/cmd/gc/sinit.c
+++ /dev/null
@@ -1,971 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * static initialization
- */
-
-#include "go.h"
-
-static NodeList *initlist;
-static void init2(Node*, NodeList**);
-static void init2list(NodeList*, NodeList**);
-
-static void
-init1(Node *n, NodeList **out)
-{
- NodeList *l;
-
- if(n == N)
- return;
- init1(n->left, out);
- init1(n->right, out);
- for(l=n->list; l; l=l->next)
- init1(l->n, out);
-
- if(n->op != ONAME)
- return;
- switch(n->class) {
- case PEXTERN:
- case PFUNC:
- break;
- default:
- if(isblank(n) && n->defn != N && !n->defn->initorder) {
- n->defn->initorder = 1;
- *out = list(*out, n->defn);
- }
- return;
- }
-
- if(n->initorder == 1)
- return;
- if(n->initorder == 2) {
- if(n->class == PFUNC)
- return;
-
- // if there have already been errors printed,
- // those errors probably confused us and
- // there might not be a loop. let the user
- // fix those first.
- flusherrors();
- if(nerrors > 0)
- errorexit();
-
- print("initialization loop:\n");
- for(l=initlist;; l=l->next) {
- if(l->next == nil)
- break;
- l->next->end = l;
- }
- for(; l; l=l->end)
- print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
- print("\t%L %S\n", n->lineno, n->sym);
- errorexit();
- }
- n->initorder = 2;
- l = malloc(sizeof *l);
- l->next = initlist;
- l->n = n;
- l->end = nil;
- initlist = l;
-
- // make sure that everything n depends on is initialized.
- // n->defn is an assignment to n
- if(n->defn != N) {
- switch(n->defn->op) {
- default:
- goto bad;
-
- case ODCLFUNC:
- init2list(n->defn->nbody, out);
- break;
-
- case OAS:
- if(n->defn->left != n)
- goto bad;
- n->defn->dodata = 1;
- init1(n->defn->right, out);
- if(debug['j'])
- print("%S\n", n->sym);
- *out = list(*out, n->defn);
- break;
-
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2DOTTYPE:
- case OAS2RECV:
- if(n->defn->initorder)
- break;
- n->defn->initorder = 1;
- for(l=n->defn->rlist; l; l=l->next)
- init1(l->n, out);
- *out = list(*out, n->defn);
- break;
- }
- }
- l = initlist;
- initlist = l->next;
- if(l->n != n)
- fatal("bad initlist");
- free(l);
- n->initorder = 1;
- return;
-
-bad:
- dump("defn", n->defn);
- fatal("init1: bad defn");
-}
-
-// recurse over n, doing init1 everywhere.
-static void
-init2(Node *n, NodeList **out)
-{
- if(n == N || n->initorder == 1)
- return;
- init1(n, out);
- init2(n->left, out);
- init2(n->right, out);
- init2(n->ntest, out);
- init2list(n->ninit, out);
- init2list(n->list, out);
- init2list(n->rlist, out);
- init2list(n->nbody, out);
- init2list(n->nelse, out);
-}
-
-static void
-init2list(NodeList *l, NodeList **out)
-{
- for(; l; l=l->next)
- init2(l->n, out);
-}
-
-
-static void
-initreorder(NodeList *l, NodeList **out)
-{
- Node *n;
-
- for(; l; l=l->next) {
- n = l->n;
- switch(n->op) {
- case ODCLFUNC:
- case ODCLCONST:
- case ODCLTYPE:
- continue;
- }
- initreorder(n->ninit, out);
- n->ninit = nil;
- init1(n, out);
- }
-}
-
-NodeList*
-initfix(NodeList *l)
-{
- NodeList *lout;
-
- lout = nil;
- initreorder(l, &lout);
- return lout;
-}
-
-/*
- * from here down is the walk analysis
- * of composite literals.
- * most of the work is to generate
- * data statements for the constant
- * part of the composite literal.
- */
-
-static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static void slicelit(int ctxt, Node *n, Node *var, NodeList **init);
-static void maplit(int ctxt, Node *n, Node *var, NodeList **init);
-
-static Node*
-staticname(Type *t, int ctxt)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
- statuniqgen++;
- n = newname(lookup(namebuf));
- if(!ctxt)
- n->readonly = 1;
- addvar(n, t, PEXTERN);
- return n;
-}
-
-static int
-isliteral(Node *n)
-{
- if(n->op == OLITERAL)
- if(n->val.ctype != CTNIL)
- return 1;
- return 0;
-}
-
-static int
-simplename(Node *n)
-{
- if(n->op != ONAME)
- goto no;
- if(!n->addable)
- goto no;
- if(n->class & PHEAP)
- goto no;
- if(n->class == PPARAMREF)
- goto no;
- return 1;
-
-no:
- return 0;
-}
-
-static void
-litas(Node *l, Node *r, NodeList **init)
-{
- Node *a;
-
- a = nod(OAS, l, r);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-}
-
-enum
-{
- MODEDYNAM = 1,
- MODECONST = 2,
-};
-
-static int
-getdyn(Node *n, int top)
-{
- NodeList *nl;
- Node *value;
- int mode;
-
- mode = 0;
- switch(n->op) {
- default:
- if(isliteral(n))
- return MODECONST;
- return MODEDYNAM;
- case OARRAYLIT:
- if(!top && n->type->bound < 0)
- return MODEDYNAM;
- case OSTRUCTLIT:
- break;
- }
-
- for(nl=n->list; nl; nl=nl->next) {
- value = nl->n->right;
- mode |= getdyn(value, 0);
- if(mode == (MODEDYNAM|MODECONST))
- break;
- }
- return mode;
-}
-
-static void
-structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *nl;
- Node *index, *value;
-
- for(nl=n->list; nl; nl=nl->next) {
- r = nl->n;
- if(r->op != OKEY)
- fatal("structlit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0) {
- if(pass == 1 && ctxt != 0) {
- a = nod(ODOT, var, newname(index->sym));
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 2 && ctxt == 0) {
- a = nod(ODOT, var, newname(index->sym));
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 3)
- break;
- continue;
- }
- a = nod(ODOT, var, newname(index->sym));
- arraylit(ctxt, pass, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- a = nod(ODOT, var, newname(index->sym));
- structlit(ctxt, pass, value, a, init);
- continue;
- }
-
- if(isliteral(value)) {
- if(pass == 2)
- continue;
- } else
- if(pass == 1)
- continue;
-
- // build list of var.field = expr
- a = nod(ODOT, var, newname(index->sym));
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- if(pass == 1) {
- if(a->op != OAS)
- fatal("structlit: not as");
- a->dodata = 2;
- }
- *init = list(*init, a);
- }
-}
-
-static void
-arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- Node *index, *value;
-
- for(l=n->list; l; l=l->next) {
- r = l->n;
- if(r->op != OKEY)
- fatal("arraylit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0) {
- if(pass == 1 && ctxt != 0) {
- a = nod(OINDEX, var, index);
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 2 && ctxt == 0) {
- a = nod(OINDEX, var, index);
- slicelit(ctxt, value, a, init);
- } else
- if(pass == 3)
- break;
- continue;
- }
- a = nod(OINDEX, var, index);
- arraylit(ctxt, pass, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- a = nod(OINDEX, var, index);
- structlit(ctxt, pass, value, a, init);
- continue;
- }
-
- if(isliteral(index) && isliteral(value)) {
- if(pass == 2)
- continue;
- } else
- if(pass == 1)
- continue;
-
- // build list of var[index] = value
- a = nod(OINDEX, var, index);
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init); // add any assignments in r to top
- if(pass == 1) {
- if(a->op != OAS)
- fatal("structlit: not as");
- a->dodata = 2;
- }
- *init = list(*init, a);
- }
-}
-
-static void
-slicelit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- Type *t;
- Node *vstat, *vauto;
- Node *index, *value;
- int mode;
-
- // make an array type
- t = shallow(n->type);
- t->bound = mpgetfix(n->right->val.u.xval);
- t->width = 0;
- t->sym = nil;
- dowidth(t);
-
- if(ctxt != 0) {
-
- // put everything into static array
- vstat = staticname(t, ctxt);
- arraylit(ctxt, 1, n, vstat, init);
- arraylit(ctxt, 2, n, vstat, init);
-
- // copy static to slice
- a = nod(OSLICE, vstat, nod(OKEY, N, N));
- a = nod(OAS, var, a);
- typecheck(&a, Etop);
- a->dodata = 2;
- *init = list(*init, a);
- return;
- }
-
- // recipe for var = []t{...}
- // 1. make a static array
- // var vstat [...]t
- // 2. assign (data statements) the constant part
- // vstat = constpart{}
- // 3. make an auto pointer to array and allocate heap to it
- // var vauto *[...]t = new([...]t)
- // 4. copy the static array to the auto array
- // *vauto = vstat
- // 5. assign slice of allocated heap to var
- // var = [0:]*auto
- // 6. for each dynamic part assign to the slice
- // var[i] = dynamic part
- //
- // an optimization is done if there is no constant part
- // 3. var vauto *[...]t = new([...]t)
- // 5. var = [0:]*auto
- // 6. var[i] = dynamic part
-
- // if the literal contains constants,
- // make static initialized array (1),(2)
- vstat = N;
- mode = getdyn(n, 1);
- if(mode & MODECONST) {
- vstat = staticname(t, ctxt);
- arraylit(ctxt, 1, n, vstat, init);
- }
-
- // make new auto *array (3 declare)
- vauto = nod(OXXX, N, N);
- tempname(vauto, ptrto(t));
-
- // set auto to point at new heap (3 assign)
- a = nod(ONEW, N, N);
- a->list = list1(typenod(t));
- a = nod(OAS, vauto, a);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- if(vstat != N) {
- // copy static to heap (4)
- a = nod(OIND, vauto, N);
- a = nod(OAS, a, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
-
- // make slice out of heap (5)
- a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // put dynamics into slice (6)
- for(l=n->list; l; l=l->next) {
- r = l->n;
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
- a = nod(OINDEX, var, index);
- a->etype = 1; // no bounds checking
- // TODO need to check bounds?
-
- switch(value->op) {
- case OARRAYLIT:
- if(value->type->bound < 0)
- break;
- arraylit(ctxt, 2, value, a, init);
- continue;
-
- case OSTRUCTLIT:
- structlit(ctxt, 2, value, a, init);
- continue;
- }
-
- if(isliteral(index) && isliteral(value))
- continue;
-
- // build list of var[c] = expr
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
-}
-
-static void
-maplit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Node *r, *a;
- NodeList *l;
- int nerr, b;
- Type *t, *tk, *tv, *t1;
- Node *vstat, *index, *value;
- Sym *syma, *symb;
-
-ctxt = 0;
-
- // make the map var
- nerr = nerrors;
-
- a = nod(OMAKE, N, N);
- a->list = list1(typenod(n->type));
- litas(var, a, init);
-
- // count the initializers
- b = 0;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value))
- b++;
- }
-
- t = T;
- if(b != 0) {
- // build type [count]struct { a Tindex, b Tvalue }
- t = n->type;
- tk = t->down;
- tv = t->type;
-
- symb = lookup("b");
- t = typ(TFIELD);
- t->type = tv;
- t->sym = symb;
-
- syma = lookup("a");
- t1 = t;
- t = typ(TFIELD);
- t->type = tk;
- t->sym = syma;
- t->down = t1;
-
- t1 = t;
- t = typ(TSTRUCT);
- t->type = t1;
-
- t1 = t;
- t = typ(TARRAY);
- t->bound = b;
- t->type = t1;
-
- dowidth(t);
-
- // make and initialize static array
- vstat = staticname(t, ctxt);
- b = 0;
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value)) {
- // build vstat[b].a = key;
- a = nodintconst(b);
- a = nod(OINDEX, vstat, a);
- a = nod(ODOT, a, newname(syma));
- a = nod(OAS, a, index);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- a->dodata = 2;
- *init = list(*init, a);
-
- // build vstat[b].b = value;
- a = nodintconst(b);
- a = nod(OINDEX, vstat, a);
- a = nod(ODOT, a, newname(symb));
- a = nod(OAS, a, value);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- a->dodata = 2;
- *init = list(*init, a);
-
- b++;
- }
- }
-
- // loop adding structure elements to map
- // for i = 0; i < len(vstat); i++ {
- // map[vstat[i].a] = vstat[i].b
- // }
- index = nod(OXXX, N, N);
- tempname(index, types[TINT]);
-
- a = nod(OINDEX, vstat, index);
- a->etype = 1; // no bounds checking
- a = nod(ODOT, a, newname(symb));
-
- r = nod(OINDEX, vstat, index);
- r->etype = 1; // no bounds checking
- r = nod(ODOT, r, newname(syma));
- r = nod(OINDEX, var, r);
-
- r = nod(OAS, r, a);
-
- a = nod(OFOR, N, N);
- a->nbody = list1(r);
-
- a->ninit = list1(nod(OAS, index, nodintconst(0)));
- a->ntest = nod(OLT, index, nodintconst(t->bound));
- a->nincr = nod(OASOP, index, nodintconst(1));
- a->nincr->etype = OADD;
-
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- }
-
- // put in dynamic entries one-at-a-time
- for(l=n->list; l; l=l->next) {
- r = l->n;
-
- if(r->op != OKEY)
- fatal("slicelit: rhs not OKEY: %N", r);
- index = r->left;
- value = r->right;
-
- if(isliteral(index) && isliteral(value))
- continue;
-
- // build list of var[c] = expr
- a = nod(OINDEX, var, r->left);
- a = nod(OAS, a, r->right);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- if(nerr != nerrors)
- break;
-
- *init = list(*init, a);
- }
-}
-
-void
-anylit(int ctxt, Node *n, Node *var, NodeList **init)
-{
- Type *t;
- Node *a, *vstat;
-
- t = n->type;
- switch(n->op) {
- default:
- fatal("anylit: not lit");
-
- case OSTRUCTLIT:
- if(t->etype != TSTRUCT)
- fatal("anylit: not struct");
-
- if(simplename(var)) {
-
- if(ctxt == 0) {
- // lay out static data
- vstat = staticname(t, ctxt);
- structlit(1, 1, n, vstat, init);
-
- // copy static to var
- a = nod(OAS, var, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // add expressions to automatic
- structlit(ctxt, 2, n, var, init);
- break;
- }
- structlit(ctxt, 1, n, var, init);
- structlit(ctxt, 2, n, var, init);
- break;
- }
-
- // initialize of not completely specified
- if(count(n->list) < structcount(t)) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
- structlit(ctxt, 3, n, var, init);
- break;
-
- case OARRAYLIT:
- if(t->etype != TARRAY)
- fatal("anylit: not array");
- if(t->bound < 0) {
- slicelit(ctxt, n, var, init);
- break;
- }
-
- if(simplename(var)) {
-
- if(ctxt == 0) {
- // lay out static data
- vstat = staticname(t, ctxt);
- arraylit(1, 1, n, vstat, init);
-
- // copy static to automatic
- a = nod(OAS, var, vstat);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
-
- // add expressions to automatic
- arraylit(ctxt, 2, n, var, init);
- break;
- }
- arraylit(ctxt, 1, n, var, init);
- arraylit(ctxt, 2, n, var, init);
- break;
- }
-
- // initialize of not completely specified
- if(count(n->list) < t->bound) {
- a = nod(OAS, var, N);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- }
- arraylit(ctxt, 3, n, var, init);
- break;
-
- case OMAPLIT:
- if(t->etype != TMAP)
- fatal("anylit: not map");
- maplit(ctxt, n, var, init);
- break;
- }
-}
-
-int
-oaslit(Node *n, NodeList **init)
-{
- int ctxt;
-
- if(n->left == N || n->right == N)
- goto no;
- if(n->left->type == T || n->right->type == T)
- goto no;
- if(!simplename(n->left))
- goto no;
- if(!eqtype(n->left->type, n->right->type))
- goto no;
-
- // context is init() function.
- // implies generated data executed
- // exactly once and not subject to races.
- ctxt = 0;
-// if(n->dodata == 1)
-// ctxt = 1;
-
- switch(n->right->op) {
- default:
- goto no;
-
- case OSTRUCTLIT:
- case OARRAYLIT:
- case OMAPLIT:
- if(vmatch1(n->left, n->right))
- goto no;
- anylit(ctxt, n->right, n->left, init);
- break;
- }
- n->op = OEMPTY;
- return 1;
-
-no:
- // not a special composit literal assignment
- return 0;
-}
-
-static int
-getlit(Node *lit)
-{
- if(smallintconst(lit))
- return mpgetfix(lit->val.u.xval);
- return -1;
-}
-
-int
-stataddr(Node *nam, Node *n)
-{
- int l;
-
- if(n == N)
- goto no;
-
- switch(n->op) {
-
- case ONAME:
- *nam = *n;
- return n->addable;
-
- case ODOT:
- if(!stataddr(nam, n->left))
- break;
- nam->xoffset += n->xoffset;
- nam->type = n->type;
- return 1;
-
- case OINDEX:
- if(n->left->type->bound < 0)
- break;
- if(!stataddr(nam, n->left))
- break;
- l = getlit(n->right);
- if(l < 0)
- break;
- nam->xoffset += l*n->type->width;
- nam->type = n->type;
- return 1;
- }
-
-no:
- return 0;
-}
-
-int
-gen_as_init(Node *n)
-{
- Node *nr, *nl;
- Node nam, nod1;
-
- if(n->dodata == 0)
- goto no;
-
- nr = n->right;
- nl = n->left;
- if(nr == N) {
- if(!stataddr(&nam, nl))
- goto no;
- if(nam.class != PEXTERN)
- goto no;
- goto yes;
- }
-
- if(nr->type == T || !eqtype(nl->type, nr->type))
- goto no;
-
- if(!stataddr(&nam, nl))
- goto no;
-
- if(nam.class != PEXTERN)
- goto no;
-
- switch(nr->op) {
- default:
- goto no;
-
- case OCONVNOP:
- nr = nr->left;
- if(nr == N || nr->op != OSLICEARR)
- goto no;
- // fall through
-
- case OSLICEARR:
- if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
- nr = nr->left;
- goto slice;
- }
- goto no;
-
- case OLITERAL:
- break;
- }
-
- switch(nr->type->etype) {
- default:
- goto no;
-
- case TBOOL:
- case TINT8:
- case TUINT8:
- case TINT16:
- case TUINT16:
- case TINT32:
- case TUINT32:
- case TINT64:
- case TUINT64:
- case TINT:
- case TUINT:
- case TUINTPTR:
- case TPTR32:
- case TPTR64:
- case TFLOAT32:
- case TFLOAT64:
- gused(N); // in case the data is the dest of a goto
- gdata(&nam, nr, nr->type->width);
- break;
-
- case TCOMPLEX64:
- case TCOMPLEX128:
- gused(N); // in case the data is the dest of a goto
- gdatacomplex(&nam, nr->val.u.cval);
- break;
-
- case TSTRING:
- gused(N); // in case the data is the dest of a goto
- gdatastring(&nam, nr->val.u.sval);
- break;
- }
-
-yes:
- return 1;
-
-slice:
- gused(N); // in case the data is the dest of a goto
- nl = nr;
- if(nr == N || nr->op != OADDR)
- goto no;
- nr = nr->left;
- if(nr == N || nr->op != ONAME)
- goto no;
-
- // nr is the array being converted to a slice
- if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0)
- goto no;
-
- nam.xoffset += Array_array;
- gdata(&nam, nl, types[tptr]->width);
-
- nam.xoffset += Array_nel-Array_array;
- nodconst(&nod1, types[TINT32], nr->type->bound);
- gdata(&nam, &nod1, types[TINT32]->width);
-
- nam.xoffset += Array_cap-Array_nel;
- gdata(&nam, &nod1, types[TINT32]->width);
-
- goto yes;
-
-no:
- if(n->dodata == 2) {
- dump("\ngen_as_init", n);
- fatal("gen_as_init couldnt make data statement");
- }
- return 0;
-}
-
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
deleted file mode 100644
index 40b0c4fd1..000000000
--- a/src/cmd/gc/subr.c
+++ /dev/null
@@ -1,3851 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-#include "md5.h"
-#include "y.tab.h"
-#include "opnames.h"
-#include "yerr.h"
-
-static void dodump(Node*, int);
-
-typedef struct Error Error;
-struct Error
-{
- int lineno;
- int seq;
- char *msg;
-};
-static Error *err;
-static int nerr;
-static int merr;
-
-void
-errorexit(void)
-{
- flusherrors();
- if(outfile)
- remove(outfile);
- exit(1);
-}
-
-extern int yychar;
-int
-parserline(void)
-{
- if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
- return prevlineno;
- return lineno;
-}
-
-static void
-adderr(int line, char *fmt, va_list arg)
-{
- Fmt f;
- Error *p;
-
- erroring++;
- fmtstrinit(&f);
- fmtprint(&f, "%L: ", line);
- fmtvprint(&f, fmt, arg);
- fmtprint(&f, "\n");
- erroring--;
-
- if(nerr >= merr) {
- if(merr == 0)
- merr = 16;
- else
- merr *= 2;
- p = realloc(err, merr*sizeof err[0]);
- if(p == nil) {
- merr = nerr;
- flusherrors();
- print("out of memory\n");
- errorexit();
- }
- err = p;
- }
- err[nerr].seq = nerr;
- err[nerr].lineno = line;
- err[nerr].msg = fmtstrflush(&f);
- nerr++;
-}
-
-static int
-errcmp(const void *va, const void *vb)
-{
- Error *a, *b;
-
- a = (Error*)va;
- b = (Error*)vb;
- if(a->lineno != b->lineno)
- return a->lineno - b->lineno;
- if(a->seq != b->seq)
- return a->seq - b->seq;
- return strcmp(a->msg, b->msg);
-}
-
-void
-flusherrors(void)
-{
- int i;
-
- if(nerr == 0)
- return;
- qsort(err, nerr, sizeof err[0], errcmp);
- for(i=0; i<nerr; i++)
- if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
- print("%s", err[i].msg);
- nerr = 0;
-}
-
-static void
-hcrash(void)
-{
- if(debug['h']) {
- flusherrors();
- if(outfile)
- unlink(outfile);
- *(volatile int*)0 = 0;
- }
-}
-
-void
-yyerrorl(int line, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(line, fmt, arg);
- va_end(arg);
-
- hcrash();
- nerrors++;
- if(nerrors >= 10 && !debug['e']) {
- flusherrors();
- print("%L: too many errors\n", line);
- errorexit();
- }
-}
-
-extern int yystate, yychar;
-
-void
-yyerror(char *fmt, ...)
-{
- int i;
- static int lastsyntax;
- va_list arg;
- char buf[512], *p;
-
- if(strncmp(fmt, "syntax error", 12) == 0) {
- nsyntaxerrors++;
-
- if(debug['x'])
- print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
-
- // only one syntax error per line
- if(lastsyntax == lexlineno)
- return;
- lastsyntax = lexlineno;
-
- if(strstr(fmt, "{ or {")) {
- // The grammar has { and LBRACE but both show up as {.
- // Rewrite syntax error referring to "{ or {" to say just "{".
- strecpy(buf, buf+sizeof buf, fmt);
- p = strstr(buf, "{ or {");
- if(p)
- memmove(p+1, p+6, strlen(p+6)+1);
- fmt = buf;
- }
-
- // look for parse state-specific errors in list (see go.errors).
- for(i=0; i<nelem(yymsg); i++) {
- if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
- yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
- return;
- }
- }
-
- // plain "syntax error" gets "near foo" added
- if(strcmp(fmt, "syntax error") == 0) {
- yyerrorl(lexlineno, "syntax error near %s", lexbuf);
- return;
- }
-
- // if bison says "syntax error, more info"; print "syntax error: more info".
- if(fmt[12] == ',') {
- yyerrorl(lexlineno, "syntax error:%s", fmt+13);
- return;
- }
-
- yyerrorl(lexlineno, "%s", fmt);
- return;
- }
-
- va_start(arg, fmt);
- adderr(parserline(), fmt, arg);
- va_end(arg);
-
- hcrash();
- nerrors++;
- if(nerrors >= 10 && !debug['e']) {
- flusherrors();
- print("%L: too many errors\n", parserline());
- errorexit();
- }
-}
-
-void
-warn(char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- adderr(parserline(), fmt, arg);
- va_end(arg);
-
- hcrash();
-}
-
-void
-fatal(char *fmt, ...)
-{
- va_list arg;
-
- flusherrors();
-
- print("%L: internal compiler error: ", lineno);
- va_start(arg, fmt);
- vfprint(1, fmt, arg);
- va_end(arg);
- print("\n");
-
- // If this is a released compiler version, ask for a bug report.
- if(strncmp(getgoversion(), "release", 7) == 0) {
- print("\n");
- print("Please file a bug report including a short program that triggers the error.\n");
- print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
- }
- hcrash();
- errorexit();
-}
-
-void
-linehist(char *file, int32 off, int relative)
-{
- Hist *h;
- char *cp;
-
- if(debug['i']) {
- if(file != nil) {
- if(off < 0)
- print("pragma %s", file);
- else
- if(off > 0)
- print("line %s", file);
- else
- print("import %s", file);
- } else
- print("end of import");
- print(" at line %L\n", lexlineno);
- }
-
- if(off < 0 && file[0] != '/' && !relative) {
- cp = mal(strlen(file) + strlen(pathname) + 2);
- sprint(cp, "%s/%s", pathname, file);
- file = cp;
- }
-
- h = mal(sizeof(Hist));
- h->name = file;
- h->line = lexlineno;
- h->offset = off;
- h->link = H;
- if(ehist == H) {
- hist = h;
- ehist = h;
- return;
- }
- ehist->link = h;
- ehist = h;
-}
-
-int32
-setlineno(Node *n)
-{
- int32 lno;
-
- lno = lineno;
- if(n != N)
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OPACK:
- case OLITERAL:
- break;
- default:
- lineno = n->lineno;
- if(lineno == 0) {
- if(debug['K'])
- warn("setlineno: line 0");
- lineno = lno;
- }
- }
- return lno;
-}
-
-uint32
-stringhash(char *p)
-{
- int32 h;
- int c;
-
- h = 0;
- for(;;) {
- c = *p++;
- if(c == 0)
- break;
- h = h*PRIME1 + c;
- }
-
- if(h < 0) {
- h = -h;
- if(h < 0)
- h = 0;
- }
- return h;
-}
-
-Sym*
-lookup(char *name)
-{
- return pkglookup(name, localpkg);
-}
-
-Sym*
-pkglookup(char *name, Pkg *pkg)
-{
- Sym *s;
- uint32 h;
- int c;
-
- h = stringhash(name) % NHASH;
- c = name[0];
- for(s = hash[h]; s != S; s = s->link) {
- if(s->name[0] != c || s->pkg != pkg)
- continue;
- if(strcmp(s->name, name) == 0)
- return s;
- }
-
- s = mal(sizeof(*s));
- s->name = mal(strlen(name)+1);
- strcpy(s->name, name);
-
- s->pkg = pkg;
-
- s->link = hash[h];
- hash[h] = s;
- s->lexical = LNAME;
-
- return s;
-}
-
-Sym*
-restrictlookup(char *name, Pkg *pkg)
-{
- if(!exportname(name) && pkg != localpkg)
- yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
- return pkglookup(name, pkg);
-}
-
-
-// find all the exported symbols in package opkg
-// and make them available in the current package
-void
-importdot(Pkg *opkg, Node *pack)
-{
- Sym *s, *s1;
- uint32 h;
- int n;
-
- n = 0;
- for(h=0; h<NHASH; h++) {
- for(s = hash[h]; s != S; s = s->link) {
- if(s->pkg != opkg)
- continue;
- if(s->def == N)
- continue;
- if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot
- continue;
- s1 = lookup(s->name);
- if(s1->def != N) {
- redeclare(s1, "during import");
- continue;
- }
- s1->def = s->def;
- s1->block = s->block;
- s1->def->pack = pack;
- n++;
- }
- }
- if(n == 0) {
- // can't possibly be used - there were no symbols
- yyerrorl(pack->lineno, "imported and not used: %Z", opkg->path);
- }
-}
-
-static void
-gethunk(void)
-{
- char *h;
- int32 nh;
-
- nh = NHUNK;
- if(thunk >= 10L*NHUNK)
- nh = 10L*NHUNK;
- h = (char*)malloc(nh);
- if(h == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- hunk = h;
- nhunk = nh;
- thunk += nh;
-}
-
-void*
-mal(int32 n)
-{
- void *p;
-
- if(n >= NHUNK) {
- p = malloc(n);
- if(p == nil) {
- flusherrors();
- yyerror("out of memory");
- errorexit();
- }
- memset(p, 0, n);
- return p;
- }
-
- while((uintptr)hunk & MAXALIGN) {
- hunk++;
- nhunk--;
- }
- if(nhunk < n)
- gethunk();
-
- p = hunk;
- nhunk -= n;
- hunk += n;
- memset(p, 0, n);
- return p;
-}
-
-void*
-remal(void *p, int32 on, int32 n)
-{
- void *q;
-
- q = (uchar*)p + on;
- if(q != hunk || nhunk < n) {
- if(on+n >= NHUNK) {
- q = mal(on+n);
- memmove(q, p, on);
- return q;
- }
- if(nhunk < on+n)
- gethunk();
- memmove(hunk, p, on);
- p = hunk;
- hunk += on;
- nhunk -= on;
- }
- hunk += n;
- nhunk -= n;
- return p;
-}
-
-Node*
-nod(int op, Node *nleft, Node *nright)
-{
- Node *n;
-
- n = mal(sizeof(*n));
- n->op = op;
- n->left = nleft;
- n->right = nright;
- n->lineno = parserline();
- n->xoffset = BADWIDTH;
- n->orig = n;
- return n;
-}
-
-int
-algtype(Type *t)
-{
- int a;
-
- if(issimple[t->etype] || isptr[t->etype] ||
- t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) {
- if(t->width == widthptr)
- a = AMEMWORD;
- else
- a = AMEM; // just bytes (int, ptr, etc)
- } else if(t->etype == TSTRING)
- a = ASTRING; // string
- else if(isnilinter(t))
- a = ANILINTER; // nil interface
- else if(t->etype == TINTER)
- a = AINTER; // interface
- else
- a = ANOEQ; // just bytes, but no hash/eq
- return a;
-}
-
-Type*
-maptype(Type *key, Type *val)
-{
- Type *t;
-
-
- if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) {
- if(key->etype == TFORW) {
- // map[key] used during definition of key.
- // postpone check until key is fully defined.
- // if there are multiple uses of map[key]
- // before key is fully defined, the error
- // will only be printed for the first one.
- // good enough.
- if(key->maplineno == 0)
- key->maplineno = lineno;
- } else
- yyerror("invalid map key type %T", key);
- }
- t = typ(TMAP);
- t->down = key;
- t->type = val;
- return t;
-}
-
-Type*
-typ(int et)
-{
- Type *t;
-
- t = mal(sizeof(*t));
- t->etype = et;
- t->width = BADWIDTH;
- t->lineno = lineno;
- t->orig = t;
- return t;
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
- Type *a, *b;
- int i;
-
- a = *(Type**)va;
- b = *(Type**)vb;
- i = strcmp(a->sym->name, b->sym->name);
- if(i != 0)
- return i;
- if(!exportname(a->sym->name)) {
- i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
- if(i != 0)
- return i;
- }
- return 0;
-}
-
-Type*
-sortinter(Type *t)
-{
- Type *f;
- int i;
- Type **a;
-
- if(t->type == nil || t->type->down == nil)
- return t;
-
- i=0;
- for(f=t->type; f; f=f->down)
- i++;
- a = mal(i*sizeof f);
- i = 0;
- for(f=t->type; f; f=f->down)
- a[i++] = f;
- qsort(a, i, sizeof a[0], methcmp);
- while(i-- > 0) {
- a[i]->down = f;
- f = a[i];
- }
- t->type = f;
- return t;
-}
-
-Node*
-nodintconst(int64 v)
-{
- Node *c;
-
- c = nod(OLITERAL, N, N);
- c->addable = 1;
- c->val.u.xval = mal(sizeof(*c->val.u.xval));
- mpmovecfix(c->val.u.xval, v);
- c->val.ctype = CTINT;
- c->type = types[TIDEAL];
- ullmancalc(c);
- return c;
-}
-
-Node*
-nodfltconst(Mpflt* v)
-{
- Node *c;
-
- c = nod(OLITERAL, N, N);
- c->addable = 1;
- c->val.u.fval = mal(sizeof(*c->val.u.fval));
- mpmovefltflt(c->val.u.fval, v);
- c->val.ctype = CTFLT;
- c->type = types[TIDEAL];
- ullmancalc(c);
- return c;
-}
-
-void
-nodconst(Node *n, Type *t, int64 v)
-{
- memset(n, 0, sizeof(*n));
- n->op = OLITERAL;
- n->addable = 1;
- ullmancalc(n);
- n->val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(n->val.u.xval, v);
- n->val.ctype = CTINT;
- n->type = t;
-
- if(isfloat[t->etype])
- fatal("nodconst: bad type %T", t);
-}
-
-Node*
-nodnil(void)
-{
- Node *c;
-
- c = nodintconst(0);
- c->val.ctype = CTNIL;
- c->type = types[TNIL];
- return c;
-}
-
-Node*
-nodbool(int b)
-{
- Node *c;
-
- c = nodintconst(0);
- c->val.ctype = CTBOOL;
- c->val.u.bval = b;
- c->type = idealbool;
- return c;
-}
-
-Type*
-aindex(Node *b, Type *t)
-{
- Type *r;
- int bound;
-
- bound = -1; // open bound
- typecheck(&b, Erv);
- if(b != nil) {
- switch(consttype(b)) {
- default:
- yyerror("array bound must be an integer expression");
- break;
- case CTINT:
- bound = mpgetfix(b->val.u.xval);
- if(bound < 0)
- yyerror("array bound must be non negative");
- break;
- }
- }
-
- // fixed array
- r = typ(TARRAY);
- r->type = t;
- r->bound = bound;
- return r;
-}
-
-static void
-indent(int dep)
-{
- int i;
-
- for(i=0; i<dep; i++)
- print(". ");
-}
-
-static void
-dodumplist(NodeList *l, int dep)
-{
- for(; l; l=l->next)
- dodump(l->n, dep);
-}
-
-static void
-dodump(Node *n, int dep)
-{
- if(n == N)
- return;
-
- indent(dep);
- if(dep > 10) {
- print("...\n");
- return;
- }
-
- if(n->ninit != nil) {
- print("%O-init\n", n->op);
- dodumplist(n->ninit, dep+1);
- indent(dep);
- }
-
- switch(n->op) {
- default:
- print("%N\n", n);
- dodump(n->left, dep+1);
- dodump(n->right, dep+1);
- break;
-
- case OTYPE:
- print("%O %S type=%T\n", n->op, n->sym, n->type);
- if(n->type == T && n->ntype) {
- indent(dep);
- print("%O-ntype\n", n->op);
- dodump(n->ntype, dep+1);
- }
- break;
-
- case OIF:
- print("%O%J\n", n->op, n);
- dodump(n->ntest, dep+1);
- if(n->nbody != nil) {
- indent(dep);
- print("%O-then\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
- if(n->nelse != nil) {
- indent(dep);
- print("%O-else\n", n->op);
- dodumplist(n->nelse, dep+1);
- }
- break;
-
- case OSELECT:
- print("%O%J\n", n->op, n);
- dodumplist(n->nbody, dep+1);
- break;
-
- case OSWITCH:
- case OFOR:
- print("%O%J\n", n->op, n);
- dodump(n->ntest, dep+1);
-
- if(n->nbody != nil) {
- indent(dep);
- print("%O-body\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
-
- if(n->nincr != N) {
- indent(dep);
- print("%O-incr\n", n->op);
- dodump(n->nincr, dep+1);
- }
- break;
-
- case OCASE:
- // the right side points to label of the body
- if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME)
- print("%O%J GOTO %N\n", n->op, n, n->right->left);
- else
- print("%O%J\n", n->op, n);
- dodump(n->left, dep+1);
- break;
-
- case OXCASE:
- print("%N\n", n);
- dodump(n->left, dep+1);
- dodump(n->right, dep+1);
- indent(dep);
- print("%O-nbody\n", n->op);
- dodumplist(n->nbody, dep+1);
- break;
- }
-
- if(0 && n->ntype != nil) {
- indent(dep);
- print("%O-ntype\n", n->op);
- dodump(n->ntype, dep+1);
- }
- if(n->list != nil) {
- indent(dep);
- print("%O-list\n", n->op);
- dodumplist(n->list, dep+1);
- }
- if(n->rlist != nil) {
- indent(dep);
- print("%O-rlist\n", n->op);
- dodumplist(n->rlist, dep+1);
- }
- if(n->op != OIF && n->nbody != nil) {
- indent(dep);
- print("%O-nbody\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
-}
-
-void
-dumplist(char *s, NodeList *l)
-{
- print("%s\n", s);
- dodumplist(l, 1);
-}
-
-void
-dump(char *s, Node *n)
-{
- print("%s [%p]\n", s, n);
- dodump(n, 1);
-}
-
-static char*
-goopnames[] =
-{
- [OADDR] = "&",
- [OADD] = "+",
- [OANDAND] = "&&",
- [OANDNOT] = "&^",
- [OAND] = "&",
- [OAPPEND] = "append",
- [OAS] = "=",
- [OAS2] = "=",
- [OBREAK] = "break",
- [OCALL] = "function call",
- [OCAP] = "cap",
- [OCASE] = "case",
- [OCLOSE] = "close",
- [OCOMPLEX] = "complex",
- [OCOM] = "^",
- [OCONTINUE] = "continue",
- [OCOPY] = "copy",
- [ODEC] = "--",
- [ODEFER] = "defer",
- [ODIV] = "/",
- [OEQ] = "==",
- [OFALL] = "fallthrough",
- [OFOR] = "for",
- [OGE] = ">=",
- [OGOTO] = "goto",
- [OGT] = ">",
- [OIF] = "if",
- [OIMAG] = "imag",
- [OINC] = "++",
- [OIND] = "*",
- [OLEN] = "len",
- [OLE] = "<=",
- [OLSH] = "<<",
- [OLT] = "<",
- [OMAKE] = "make",
- [OMINUS] = "-",
- [OMOD] = "%",
- [OMUL] = "*",
- [ONEW] = "new",
- [ONE] = "!=",
- [ONOT] = "!",
- [OOROR] = "||",
- [OOR] = "|",
- [OPANIC] = "panic",
- [OPLUS] = "+",
- [OPRINTN] = "println",
- [OPRINT] = "print",
- [ORANGE] = "range",
- [OREAL] = "real",
- [ORECV] = "<-",
- [ORETURN] = "return",
- [ORSH] = ">>",
- [OSELECT] = "select",
- [OSEND] = "<-",
- [OSUB] = "-",
- [OSWITCH] = "switch",
- [OXOR] = "^",
-};
-
-int
-Oconv(Fmt *fp)
-{
- int o;
-
- o = va_arg(fp->args, int);
- if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
- return fmtstrcpy(fp, goopnames[o]);
- if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
- return fmtprint(fp, "O-%d", o);
- return fmtstrcpy(fp, opnames[o]);
-}
-
-int
-Lconv(Fmt *fp)
-{
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 lno, d;
- int i, n;
- Hist *h;
-
- lno = va_arg(fp->args, int32);
-
- n = 0;
- for(h=hist; h!=H; h=h->link) {
- if(h->offset < 0)
- continue;
- if(lno < h->line)
- break;
- if(h->name) {
- if(h->offset > 0) {
- // #line directive
- if(n > 0 && n < HISTSZ) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- // beginning of file
- if(n < HISTSZ) {
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
-
- if(n > HISTSZ)
- n = HISTSZ;
-
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec))
- break;
- fmtprint(fp, " ");
- }
- if(debug['L'])
- fmtprint(fp, "%s/", pathname);
- if(a[i].line)
- fmtprint(fp, "%s:%d[%s:%d]",
- a[i].line->name, lno-a[i].ldel+1,
- a[i].incl->name, lno-a[i].idel+1);
- else
- fmtprint(fp, "%s:%d",
- a[i].incl->name, lno-a[i].idel+1);
- lno = a[i].incl->line - 1; // now print out start of this file
- }
- if(n == 0)
- fmtprint(fp, "<epoch>");
-
- return 0;
-}
-
-/*
-s%,%,\n%g
-s%\n+%\n%g
-s%^[ ]*T%%g
-s%,.*%%g
-s%.+% [T&] = "&",%g
-s%^ ........*\]%&~%g
-s%~ %%g
-*/
-
-static char*
-etnames[] =
-{
- [TINT] = "INT",
- [TUINT] = "UINT",
- [TINT8] = "INT8",
- [TUINT8] = "UINT8",
- [TINT16] = "INT16",
- [TUINT16] = "UINT16",
- [TINT32] = "INT32",
- [TUINT32] = "UINT32",
- [TINT64] = "INT64",
- [TUINT64] = "UINT64",
- [TUINTPTR] = "UINTPTR",
- [TFLOAT32] = "FLOAT32",
- [TFLOAT64] = "FLOAT64",
- [TCOMPLEX64] = "COMPLEX64",
- [TCOMPLEX128] = "COMPLEX128",
- [TBOOL] = "BOOL",
- [TPTR32] = "PTR32",
- [TPTR64] = "PTR64",
- [TFUNC] = "FUNC",
- [TARRAY] = "ARRAY",
- [TSTRUCT] = "STRUCT",
- [TCHAN] = "CHAN",
- [TMAP] = "MAP",
- [TINTER] = "INTER",
- [TFORW] = "FORW",
- [TFIELD] = "FIELD",
- [TSTRING] = "STRING",
- [TANY] = "ANY",
-};
-
-int
-Econv(Fmt *fp)
-{
- int et;
-
- et = va_arg(fp->args, int);
- if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
- return fmtprint(fp, "E-%d", et);
- return fmtstrcpy(fp, etnames[et]);
-}
-
-static const char* classnames[] = {
- "Pxxx",
- "PEXTERN",
- "PAUTO",
- "PPARAM",
- "PPARAMOUT",
- "PPARAMREF",
- "PFUNC",
-};
-
-int
-Jconv(Fmt *fp)
-{
- Node *n;
- char *s;
-
- n = va_arg(fp->args, Node*);
- if(n->ullman != 0)
- fmtprint(fp, " u(%d)", n->ullman);
-
- if(n->addable != 0)
- fmtprint(fp, " a(%d)", n->addable);
-
- if(n->vargen != 0)
- fmtprint(fp, " g(%d)", n->vargen);
-
- if(n->lineno != 0)
- fmtprint(fp, " l(%d)", n->lineno);
-
- if(n->xoffset != BADWIDTH)
- fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
-
- if(n->class != 0) {
- s = "";
- if (n->class & PHEAP) s = ",heap";
- if ((n->class & ~PHEAP) < nelem(classnames))
- fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
- else
- fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
- }
-
- if(n->colas != 0)
- fmtprint(fp, " colas(%d)", n->colas);
-
- if(n->funcdepth != 0)
- fmtprint(fp, " f(%d)", n->funcdepth);
-
- if(n->typecheck != 0)
- fmtprint(fp, " tc(%d)", n->typecheck);
-
- if(n->dodata != 0)
- fmtprint(fp, " dd(%d)", n->dodata);
-
- if(n->isddd != 0)
- fmtprint(fp, " isddd(%d)", n->isddd);
-
- if(n->implicit != 0)
- fmtprint(fp, " implicit(%d)", n->implicit);
-
- if(n->pun != 0)
- fmtprint(fp, " pun(%d)", n->pun);
-
- if(n->used != 0)
- fmtprint(fp, " used(%d)", n->used);
- return 0;
-}
-
-int
-Sconv(Fmt *fp)
-{
- Sym *s;
-
- s = va_arg(fp->args, Sym*);
- if(s == S) {
- fmtstrcpy(fp, "<S>");
- return 0;
- }
-
- if(fp->flags & FmtShort)
- goto shrt;
-
- if(exporting || (fp->flags & FmtSharp)) {
- if(packagequotes)
- fmtprint(fp, "\"%Z\"", s->pkg->path);
- else
- fmtprint(fp, "%s", s->pkg->prefix);
- fmtprint(fp, ".%s", s->name);
- return 0;
- }
-
- if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) {
- // This one is for the user. If the package name
- // was used by multiple packages, give the full
- // import path to disambiguate.
- if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) {
- fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
- return 0;
- }
- fmtprint(fp, "%s.%s", s->pkg->name, s->name);
- return 0;
- }
-
-shrt:
- fmtstrcpy(fp, s->name);
- return 0;
-}
-
-static char*
-basicnames[] =
-{
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TBOOL] = "bool",
- [TANY] = "any",
- [TSTRING] = "string",
- [TNIL] = "nil",
- [TIDEAL] = "ideal",
- [TBLANK] = "blank",
-};
-
-int
-Tpretty(Fmt *fp, Type *t)
-{
- Type *t1;
- Sym *s;
-
- if(0 && debug['r']) {
- debug['r'] = 0;
- fmtprint(fp, "%T (orig=%T)", t, t->orig);
- debug['r'] = 1;
- return 0;
- }
-
- if(t->etype != TFIELD
- && t->sym != S
- && !(fp->flags&FmtLong)) {
- s = t->sym;
- if(t == types[t->etype] && t->etype != TUNSAFEPTR)
- return fmtprint(fp, "%s", s->name);
- if(exporting) {
- if(fp->flags & FmtShort)
- fmtprint(fp, "%hS", s);
- else
- fmtprint(fp, "%S", s);
- if(s->pkg != localpkg)
- return 0;
- if(t->vargen)
- fmtprint(fp, "·%d", t->vargen);
- return 0;
- }
- return fmtprint(fp, "%S", s);
- }
-
- if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
- if(isideal(t) && t->etype != TIDEAL && t->etype != TNIL)
- fmtprint(fp, "ideal ");
- return fmtprint(fp, "%s", basicnames[t->etype]);
- }
-
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- if(fp->flags&FmtShort) // pass flag thru for methodsym
- return fmtprint(fp, "*%hT", t->type);
- return fmtprint(fp, "*%T", t->type);
-
- case TCHAN:
- switch(t->chan) {
- case Crecv:
- return fmtprint(fp, "<-chan %T", t->type);
- case Csend:
- return fmtprint(fp, "chan<- %T", t->type);
- }
- if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
- return fmtprint(fp, "chan (%T)", t->type);
- return fmtprint(fp, "chan %T", t->type);
-
- case TMAP:
- return fmtprint(fp, "map[%T] %T", t->down, t->type);
-
- case TFUNC:
- // t->type is method struct
- // t->type->down is result struct
- // t->type->down->down is arg struct
- if(t->thistuple && !(fp->flags&FmtSharp) && !(fp->flags&FmtShort)) {
- fmtprint(fp, "method(");
- for(t1=getthisx(t)->type; t1; t1=t1->down) {
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- }
-
- if(!(fp->flags&FmtByte))
- fmtprint(fp, "func");
- fmtprint(fp, "(");
- for(t1=getinargx(t)->type; t1; t1=t1->down) {
- if(noargnames && t1->etype == TFIELD) {
- if(t1->isddd)
- fmtprint(fp, "...%T", t1->type->type);
- else
- fmtprint(fp, "%T", t1->type);
- } else
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- switch(t->outtuple) {
- case 0:
- break;
- case 1:
- t1 = getoutargx(t)->type;
- if(t1 == T) {
- // failure to typecheck earlier; don't know the type
- fmtprint(fp, " ?unknown-type?");
- break;
- }
- if(t1->etype == TFIELD)
- t1 = t1->type;
- fmtprint(fp, " %T", t1);
- break;
- default:
- t1 = getoutargx(t)->type;
- fmtprint(fp, " (");
- for(; t1; t1=t1->down) {
- if(noargnames && t1->etype == TFIELD)
- fmtprint(fp, "%T", t1->type);
- else
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- break;
- }
- return 0;
-
- case TARRAY:
- if(t->bound >= 0)
- return fmtprint(fp, "[%d]%T", (int)t->bound, t->type);
- if(t->bound == -100)
- return fmtprint(fp, "[...]%T", t->type);
- return fmtprint(fp, "[]%T", t->type);
-
- case TINTER:
- fmtprint(fp, "interface {");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, " ");
- if(exportname(t1->sym->name))
- fmtprint(fp, "%hS", t1->sym);
- else
- fmtprint(fp, "%S", t1->sym);
- fmtprint(fp, "%hhT", t1->type);
- if(t1->down)
- fmtprint(fp, ";");
- }
- return fmtprint(fp, " }");
-
- case TSTRUCT:
- if(t->funarg) {
- fmtprint(fp, "(");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- return fmtprint(fp, ")");
- }
- fmtprint(fp, "struct {");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, " %T", t1);
- if(t1->down)
- fmtprint(fp, ";");
- }
- return fmtprint(fp, " }");
-
- case TFIELD:
- if(t->sym == S || t->embedded) {
- if(exporting)
- fmtprint(fp, "? ");
- } else
- fmtprint(fp, "%hS ", t->sym);
- if(t->isddd)
- fmtprint(fp, "...%T", t->type->type);
- else
- fmtprint(fp, "%T", t->type);
- if(t->note) {
- fmtprint(fp, " ");
- if(exporting)
- fmtprint(fp, ":");
- fmtprint(fp, "\"%Z\"", t->note);
- }
- return 0;
-
- case TFORW:
- if(exporting)
- yyerror("undefined type %S", t->sym);
- if(t->sym)
- return fmtprint(fp, "undefined %S", t->sym);
- return fmtprint(fp, "undefined");
-
- case TUNSAFEPTR:
- if(exporting)
- return fmtprint(fp, "\"unsafe\".Pointer");
- return fmtprint(fp, "unsafe.Pointer");
- }
-
- // Don't know how to handle - fall back to detailed prints.
- return -1;
-}
-
-int
-Tconv(Fmt *fp)
-{
- Type *t, *t1;
- int r, et, sharp, minus;
-
- sharp = (fp->flags & FmtSharp);
- minus = (fp->flags & FmtLeft);
- fp->flags &= ~(FmtSharp|FmtLeft);
-
- t = va_arg(fp->args, Type*);
- if(t == T)
- return fmtstrcpy(fp, "<T>");
-
- t->trecur++;
- if(t->trecur > 5) {
- fmtprint(fp, "...");
- goto out;
- }
-
- if(!debug['t']) {
- if(sharp)
- exporting++;
- if(minus)
- noargnames++;
- r = Tpretty(fp, t);
- if(sharp)
- exporting--;
- if(minus)
- noargnames--;
- if(r >= 0) {
- t->trecur--;
- return 0;
- }
- }
-
- if(sharp || exporting)
- fatal("missing %E case during export", t->etype);
-
- et = t->etype;
- fmtprint(fp, "%E ", et);
- if(t->sym != S)
- fmtprint(fp, "<%S>", t->sym);
-
- switch(et) {
- default:
- if(t->type != T)
- fmtprint(fp, " %T", t->type);
- break;
-
- case TFIELD:
- fmtprint(fp, "%T", t->type);
- break;
-
- case TFUNC:
- if(fp->flags & FmtLong)
- fmtprint(fp, "%d%d%d(%lT,%lT)%lT",
- t->thistuple, t->intuple, t->outtuple,
- t->type, t->type->down->down, t->type->down);
- else
- fmtprint(fp, "%d%d%d(%T,%T)%T",
- t->thistuple, t->intuple, t->outtuple,
- t->type, t->type->down->down, t->type->down);
- break;
-
- case TINTER:
- fmtprint(fp, "{");
- if(fp->flags & FmtLong)
- for(t1=t->type; t1!=T; t1=t1->down)
- fmtprint(fp, "%lT;", t1);
- fmtprint(fp, "}");
- break;
-
- case TSTRUCT:
- fmtprint(fp, "{");
- if(fp->flags & FmtLong)
- for(t1=t->type; t1!=T; t1=t1->down)
- fmtprint(fp, "%lT;", t1);
- fmtprint(fp, "}");
- break;
-
- case TMAP:
- fmtprint(fp, "[%T]%T", t->down, t->type);
- break;
-
- case TARRAY:
- if(t->bound >= 0)
- fmtprint(fp, "[%d]%T", t->bound, t->type);
- else
- fmtprint(fp, "[]%T", t->type);
- break;
-
- case TPTR32:
- case TPTR64:
- fmtprint(fp, "%T", t->type);
- break;
- }
-
-out:
- t->trecur--;
- return 0;
-}
-
-int
-Nconv(Fmt *fp)
-{
- char buf1[500];
- Node *n;
-
- n = va_arg(fp->args, Node*);
- if(n == N) {
- fmtprint(fp, "<N>");
- goto out;
- }
-
- if(fp->flags & FmtSign) {
- if(n->type == T)
- fmtprint(fp, "%#N", n);
- else if(n->type->etype == TNIL)
- fmtprint(fp, "nil");
- else
- fmtprint(fp, "%#N (type %T)", n, n->type);
- goto out;
- }
-
- if(fp->flags & FmtSharp) {
- if(n->orig != N)
- n = n->orig;
- exprfmt(fp, n, 0);
- goto out;
- }
-
- switch(n->op) {
- default:
- fmtprint(fp, "%O%J", n->op, n);
- break;
-
- case ONAME:
- case ONONAME:
- if(n->sym == S) {
- fmtprint(fp, "%O%J", n->op, n);
- break;
- }
- fmtprint(fp, "%O-%S G%d%J", n->op,
- n->sym, n->vargen, n);
- goto ptyp;
-
- case OREGISTER:
- fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d", n->val.ctype);
- break;
- case CTINT:
- snprint(buf1, sizeof(buf1), "I%B", n->val.u.xval);
- break;
- case CTFLT:
- snprint(buf1, sizeof(buf1), "F%g", mpgetflt(n->val.u.fval));
- break;
- case CTCPLX:
- snprint(buf1, sizeof(buf1), "(F%g+F%gi)",
- mpgetflt(&n->val.u.cval->real),
- mpgetflt(&n->val.u.cval->imag));
- break;
- case CTSTR:
- snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.u.sval);
- break;
- case CTBOOL:
- snprint(buf1, sizeof(buf1), "B%d", n->val.u.bval);
- break;
- case CTNIL:
- snprint(buf1, sizeof(buf1), "N");
- break;
- }
- fmtprint(fp, "%O-%s%J", n->op, buf1, n);
- break;
-
- case OASOP:
- fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
- break;
-
- case OTYPE:
- fmtprint(fp, "%O %T", n->op, n->type);
- break;
- }
- if(n->sym != S)
- fmtprint(fp, " %S G%d", n->sym, n->vargen);
-
-ptyp:
- if(n->type != T)
- fmtprint(fp, " %T", n->type);
-
-out:
- return 0;
-}
-
-Node*
-treecopy(Node *n)
-{
- Node *m;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- default:
- m = nod(OXXX, N, N);
- *m = *n;
- m->left = treecopy(n->left);
- m->right = treecopy(n->right);
- m->list = listtreecopy(n->list);
- if(m->defn)
- abort();
- break;
-
- case ONONAME:
- if(n->sym == lookup("iota")) {
- // Not sure yet whether this is the real iota,
- // but make a copy of the Node* just in case,
- // so that all the copies of this const definition
- // don't have the same iota value.
- m = nod(OXXX, N, N);
- *m = *n;
- m->iota = iota;
- break;
- }
- // fall through
- case ONAME:
- case OLITERAL:
- case OTYPE:
- m = n;
- break;
- }
- return m;
-}
-
-int
-Zconv(Fmt *fp)
-{
- Rune r;
- Strlit *sp;
- char *s, *se;
- int n;
-
- sp = va_arg(fp->args, Strlit*);
- if(sp == nil)
- return fmtstrcpy(fp, "<nil>");
-
- s = sp->s;
- se = s + sp->len;
- while(s < se) {
- n = chartorune(&r, s);
- s += n;
- switch(r) {
- case Runeerror:
- if(n == 1) {
- fmtprint(fp, "\\x%02x", (uchar)*(s-1));
- break;
- }
- // fall through
- default:
- if(r < ' ') {
- fmtprint(fp, "\\x%02x", r);
- break;
- }
- fmtrune(fp, r);
- break;
- case '\t':
- fmtstrcpy(fp, "\\t");
- break;
- case '\n':
- fmtstrcpy(fp, "\\n");
- break;
- case '\"':
- case '\\':
- fmtrune(fp, '\\');
- fmtrune(fp, r);
- break;
- }
- }
- return 0;
-}
-
-int
-isnil(Node *n)
-{
- if(n == N)
- return 0;
- if(n->op != OLITERAL)
- return 0;
- if(n->val.ctype != CTNIL)
- return 0;
- return 1;
-}
-
-int
-isptrto(Type *t, int et)
-{
- if(t == T)
- return 0;
- if(!isptr[t->etype])
- return 0;
- t = t->type;
- if(t == T)
- return 0;
- if(t->etype != et)
- return 0;
- return 1;
-}
-
-int
-istype(Type *t, int et)
-{
- return t != T && t->etype == et;
-}
-
-int
-isfixedarray(Type *t)
-{
- return t != T && t->etype == TARRAY && t->bound >= 0;
-}
-
-int
-isslice(Type *t)
-{
- return t != T && t->etype == TARRAY && t->bound < 0;
-}
-
-int
-isblank(Node *n)
-{
- char *p;
-
- if(n == N || n->sym == S)
- return 0;
- p = n->sym->name;
- if(p == nil)
- return 0;
- return p[0] == '_' && p[1] == '\0';
-}
-
-int
-isselect(Node *n)
-{
- Sym *s;
-
- if(n == N)
- return 0;
- n = n->left;
- s = pkglookup("selectsend", runtimepkg);
- if(s == n->sym)
- return 1;
- s = pkglookup("selectrecv", runtimepkg);
- if(s == n->sym)
- return 1;
- s = pkglookup("selectrecv2", runtimepkg);
- if(s == n->sym)
- return 1;
- s = pkglookup("selectdefault", runtimepkg);
- if(s == n->sym)
- return 1;
- return 0;
-}
-
-int
-isinter(Type *t)
-{
- return t != T && t->etype == TINTER;
-}
-
-int
-isnilinter(Type *t)
-{
- if(!isinter(t))
- return 0;
- if(t->type != T)
- return 0;
- return 1;
-}
-
-int
-isideal(Type *t)
-{
- if(t == T)
- return 0;
- if(t == idealstring || t == idealbool)
- return 1;
- switch(t->etype) {
- case TNIL:
- case TIDEAL:
- return 1;
- }
- return 0;
-}
-
-/*
- * given receiver of type t (t == r or t == *r)
- * return type to hang methods off (r).
- */
-Type*
-methtype(Type *t)
-{
- if(t == T)
- return T;
-
- // strip away pointer if it's there
- if(isptr[t->etype]) {
- if(t->sym != S)
- return T;
- t = t->type;
- if(t == T)
- return T;
- }
-
- // need a type name
- if(t->sym == S)
- return T;
-
- // check types
- if(!issimple[t->etype])
- switch(t->etype) {
- default:
- return T;
- case TSTRUCT:
- case TARRAY:
- case TMAP:
- case TCHAN:
- case TSTRING:
- case TFUNC:
- break;
- }
-
- return t;
-}
-
-int
-cplxsubtype(int et)
-{
- switch(et) {
- case TCOMPLEX64:
- return TFLOAT32;
- case TCOMPLEX128:
- return TFLOAT64;
- }
- fatal("cplxsubtype: %E\n", et);
- return 0;
-}
-
-static int
-eqnote(Strlit *a, Strlit *b)
-{
- if(a == b)
- return 1;
- if(a == nil || b == nil)
- return 0;
- if(a->len != b->len)
- return 0;
- return memcmp(a->s, b->s, a->len) == 0;
-}
-
-// Return 1 if t1 and t2 are identical, following the spec rules.
-//
-// Any cyclic type must go through a named type, and if one is
-// named, it is only identical to the other if they are the same
-// pointer (t1 == t2), so there's no chance of chasing cycles
-// ad infinitum, so no need for a depth counter.
-int
-eqtype(Type *t1, Type *t2)
-{
- if(t1 == t2)
- return 1;
- if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
- return 0;
-
- switch(t1->etype) {
- case TINTER:
- case TSTRUCT:
- for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
- if(t1->etype != TFIELD || t2->etype != TFIELD)
- fatal("struct/interface missing field: %T %T", t1, t2);
- if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note))
- return 0;
- }
- return t1 == T && t2 == T;
-
- case TFUNC:
- // Loop over structs: receiver, in, out.
- for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
- Type *ta, *tb;
-
- if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- fatal("func missing struct: %T %T", t1, t2);
-
- // Loop over fields in structs, ignoring argument names.
- for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
- if(ta->etype != TFIELD || tb->etype != TFIELD)
- fatal("func struct missing field: %T %T", ta, tb);
- if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
- return 0;
- }
- if(ta != T || tb != T)
- return 0;
- }
- return t1 == T && t2 == T;
-
- case TARRAY:
- if(t1->bound != t2->bound)
- return 0;
- break;
-
- case TCHAN:
- if(t1->chan != t2->chan)
- return 0;
- break;
- }
-
- return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
-}
-
-// Are t1 and t2 equal struct types when field names are ignored?
-// For deciding whether the result struct from g can be copied
-// directly when compiling f(g()).
-int
-eqtypenoname(Type *t1, Type *t2)
-{
- if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
- return 0;
-
- t1 = t1->type;
- t2 = t2->type;
- for(;;) {
- if(!eqtype(t1, t2))
- return 0;
- if(t1 == T)
- return 1;
- t1 = t1->down;
- t2 = t2->down;
- }
-}
-
-// Is type src assignment compatible to type dst?
-// If so, return op code to use in conversion.
-// If not, return 0.
-//
-// It is the caller's responsibility to call exportassignok
-// to check for assignments to other packages' unexported fields,
-int
-assignop(Type *src, Type *dst, char **why)
-{
- Type *missing, *have;
- int ptr;
-
- if(why != nil)
- *why = "";
-
- if(safemode && src != T && src->etype == TUNSAFEPTR) {
- yyerror("cannot use unsafe.Pointer");
- errorexit();
- }
-
- if(src == dst)
- return OCONVNOP;
- if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
- return 0;
-
- // 1. src type is identical to dst.
- if(eqtype(src, dst))
- return OCONVNOP;
-
- // 2. src and dst have identical underlying types
- // and either src or dst is not a named type or
- // both are interface types.
- if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER))
- return OCONVNOP;
-
- // 3. dst is an interface type and src implements dst.
- if(dst->etype == TINTER && src->etype != TNIL) {
- if(implements(src, dst, &missing, &have, &ptr))
- return OCONVIFACE;
- if(why != nil) {
- if(isptrto(src, TINTER))
- *why = smprint(":\n\t%T is pointer to interface, not interface", src);
- else if(have && have->sym == missing->sym)
- *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else if(ptr)
- *why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)",
- src, dst, missing->sym);
- else if(have)
- *why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
- "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
- have->sym, have->type, missing->sym, missing->type);
- else
- *why = smprint(":\n\t%T does not implement %T (missing %S method)",
- src, dst, missing->sym);
- }
- return 0;
- }
- if(isptrto(dst, TINTER)) {
- if(why != nil)
- *why = smprint(":\n\t%T is pointer to interface, not interface", dst);
- return 0;
- }
- if(src->etype == TINTER && dst->etype != TBLANK) {
- if(why != nil)
- *why = ": need type assertion";
- return 0;
- }
-
- // 4. src is a bidirectional channel value, dst is a channel type,
- // src and dst have identical element types, and
- // either src or dst is not a named type.
- if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
- if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
- return OCONVNOP;
-
- // 5. src is the predeclared identifier nil and dst is a nillable type.
- if(src->etype == TNIL) {
- switch(dst->etype) {
- case TARRAY:
- if(dst->bound != -100) // not slice
- break;
- case TPTR32:
- case TPTR64:
- case TFUNC:
- case TMAP:
- case TCHAN:
- case TINTER:
- return OCONVNOP;
- }
- }
-
- // 6. rule about untyped constants - already converted by defaultlit.
-
- // 7. Any typed value can be assigned to the blank identifier.
- if(dst->etype == TBLANK)
- return OCONVNOP;
-
- return 0;
-}
-
-// Can we convert a value of type src to a value of type dst?
-// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return 0.
-int
-convertop(Type *src, Type *dst, char **why)
-{
- int op;
-
- if(why != nil)
- *why = "";
-
- if(src == dst)
- return OCONVNOP;
- if(src == T || dst == T)
- return 0;
-
- // 1. src can be assigned to dst.
- if((op = assignop(src, dst, why)) != 0)
- return op;
-
- // The rules for interfaces are no different in conversions
- // than assignments. If interfaces are involved, stop now
- // with the good message from assignop.
- // Otherwise clear the error.
- if(src->etype == TINTER || dst->etype == TINTER)
- return 0;
- if(why != nil)
- *why = "";
-
- // 2. src and dst have identical underlying types.
- if(eqtype(src->orig, dst->orig))
- return OCONVNOP;
-
- // 3. src and dst are unnamed pointer types
- // and their base types have identical underlying types.
- if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
- if(eqtype(src->type->orig, dst->type->orig))
- return OCONVNOP;
-
- // 4. src and dst are both integer or floating point types.
- if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
- if(simtype[src->etype] == simtype[dst->etype])
- return OCONVNOP;
- return OCONV;
- }
-
- // 5. src and dst are both complex types.
- if(iscomplex[src->etype] && iscomplex[dst->etype]) {
- if(simtype[src->etype] == simtype[dst->etype])
- return OCONVNOP;
- return OCONV;
- }
-
- // 6. src is an integer or has type []byte or []int
- // and dst is a string type.
- if(isint[src->etype] && dst->etype == TSTRING)
- return ORUNESTR;
-
- if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) {
- switch(src->type->etype) {
- case TUINT8:
- return OARRAYBYTESTR;
- case TINT:
- return OARRAYRUNESTR;
- }
- }
-
- // 7. src is a string and dst is []byte or []int.
- // String to slice.
- if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) {
- switch(dst->type->etype) {
- case TUINT8:
- return OSTRARRAYBYTE;
- case TINT:
- return OSTRARRAYRUNE;
- }
- }
-
- // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
- if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
- return OCONVNOP;
-
- // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
- if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
- return OCONVNOP;
-
- return 0;
-}
-
-// Convert node n for assignment to type t.
-Node*
-assignconv(Node *n, Type *t, char *context)
-{
- int op;
- Node *r, *old;
- char *why;
-
- if(n == N || n->type == T)
- return n;
-
- old = n;
- old->diag++; // silence errors about n; we'll issue one below
- defaultlit(&n, t);
- old->diag--;
- if(t->etype == TBLANK)
- return n;
-
- exportassignok(n->type, context);
- if(eqtype(n->type, t))
- return n;
-
- op = assignop(n->type, t, &why);
- if(op == 0) {
- yyerror("cannot use %+N as type %T in %s%s", n, t, context, why);
- op = OCONV;
- }
-
- r = nod(op, n, N);
- r->type = t;
- r->typecheck = 1;
- r->implicit = 1;
- return r;
-}
-
-static int
-subtype(Type **stp, Type *t, int d)
-{
- Type *st;
-
-loop:
- st = *stp;
- if(st == T)
- return 0;
-
- d++;
- if(d >= 10)
- return 0;
-
- switch(st->etype) {
- default:
- return 0;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TARRAY:
- stp = &st->type;
- goto loop;
-
- case TANY:
- if(!st->copyany)
- return 0;
- *stp = t;
- break;
-
- case TMAP:
- if(subtype(&st->down, t, d))
- break;
- stp = &st->type;
- goto loop;
-
- case TFUNC:
- for(;;) {
- if(subtype(&st->type, t, d))
- break;
- if(subtype(&st->type->down->down, t, d))
- break;
- if(subtype(&st->type->down, t, d))
- break;
- return 0;
- }
- break;
-
- case TSTRUCT:
- for(st=st->type; st!=T; st=st->down)
- if(subtype(&st->type, t, d))
- return 1;
- return 0;
- }
- return 1;
-}
-
-/*
- * Is this a 64-bit type?
- */
-int
-is64(Type *t)
-{
- if(t == T)
- return 0;
- switch(simtype[t->etype]) {
- case TINT64:
- case TUINT64:
- case TPTR64:
- return 1;
- }
- return 0;
-}
-
-/*
- * Is a conversion between t1 and t2 a no-op?
- */
-int
-noconv(Type *t1, Type *t2)
-{
- int e1, e2;
-
- e1 = simtype[t1->etype];
- e2 = simtype[t2->etype];
-
- switch(e1) {
- case TINT8:
- case TUINT8:
- return e2 == TINT8 || e2 == TUINT8;
-
- case TINT16:
- case TUINT16:
- return e2 == TINT16 || e2 == TUINT16;
-
- case TINT32:
- case TUINT32:
- case TPTR32:
- return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;
-
- case TINT64:
- case TUINT64:
- case TPTR64:
- return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;
-
- case TFLOAT32:
- return e2 == TFLOAT32;
-
- case TFLOAT64:
- return e2 == TFLOAT64;
- }
- return 0;
-}
-
-void
-argtype(Node *on, Type *t)
-{
- dowidth(t);
- if(!subtype(&on->type, t, 0))
- fatal("argtype: failed %N %T\n", on, t);
-}
-
-Type*
-shallow(Type *t)
-{
- Type *nt;
-
- if(t == T)
- return T;
- nt = typ(0);
- *nt = *t;
- if(t->orig == t)
- nt->orig = nt;
- return nt;
-}
-
-static Type*
-deep(Type *t)
-{
- Type *nt, *xt;
-
- if(t == T)
- return T;
-
- switch(t->etype) {
- default:
- nt = t; // share from here down
- break;
-
- case TANY:
- nt = shallow(t);
- nt->copyany = 1;
- break;
-
- case TPTR32:
- case TPTR64:
- case TCHAN:
- case TARRAY:
- nt = shallow(t);
- nt->type = deep(t->type);
- break;
-
- case TMAP:
- nt = shallow(t);
- nt->down = deep(t->down);
- nt->type = deep(t->type);
- break;
-
- case TFUNC:
- nt = shallow(t);
- nt->type = deep(t->type);
- nt->type->down = deep(t->type->down);
- nt->type->down->down = deep(t->type->down->down);
- break;
-
- case TSTRUCT:
- nt = shallow(t);
- nt->type = shallow(t->type);
- xt = nt->type;
-
- for(t=t->type; t!=T; t=t->down) {
- xt->type = deep(t->type);
- xt->down = shallow(t->down);
- xt = xt->down;
- }
- break;
- }
- return nt;
-}
-
-Node*
-syslook(char *name, int copy)
-{
- Sym *s;
- Node *n;
-
- s = pkglookup(name, runtimepkg);
- if(s == S || s->def == N)
- fatal("syslook: can't find runtime.%s", name);
-
- if(!copy)
- return s->def;
-
- n = nod(0, N, N);
- *n = *s->def;
- n->type = deep(s->def->type);
-
- return n;
-}
-
-/*
- * compute a hash value for type t.
- * if t is a method type, ignore the receiver
- * so that the hash can be used in interface checks.
- * %-T (which calls Tpretty, above) already contains
- * all the necessary logic to generate a representation
- * of the type that completely describes it.
- * using smprint here avoids duplicating that code.
- * using md5 here is overkill, but i got tired of
- * accidental collisions making the runtime think
- * two types are equal when they really aren't.
- */
-uint32
-typehash(Type *t)
-{
- char *p;
- MD5 d;
-
- longsymnames = 1;
- if(t->thistuple) {
- // hide method receiver from Tpretty
- t->thistuple = 0;
- p = smprint("%-T", t);
- t->thistuple = 1;
- }else
- p = smprint("%-T", t);
- longsymnames = 0;
- md5reset(&d);
- md5write(&d, (uchar*)p, strlen(p));
- free(p);
- return md5sum(&d);
-}
-
-Type*
-ptrto(Type *t)
-{
- Type *t1;
-
- if(tptr == 0)
- fatal("ptrto: nil");
- t1 = typ(tptr);
- t1->type = t;
- t1->width = widthptr;
- t1->align = widthptr;
- return t1;
-}
-
-void
-frame(int context)
-{
- char *p;
- NodeList *l;
- Node *n;
- int flag;
-
- p = "stack";
- l = nil;
- if(curfn)
- l = curfn->dcl;
- if(context) {
- p = "external";
- l = externdcl;
- }
-
- flag = 1;
- for(; l; l=l->next) {
- n = l->n;
- switch(n->op) {
- case ONAME:
- if(flag)
- print("--- %s frame ---\n", p);
- print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
- flag = 0;
- break;
-
- case OTYPE:
- if(flag)
- print("--- %s frame ---\n", p);
- print("%O %T\n", n->op, n->type);
- flag = 0;
- break;
- }
- }
-}
-
-/*
- * calculate sethi/ullman number
- * roughly how many registers needed to
- * compile a node. used to compile the
- * hardest side first to minimize registers.
- */
-void
-ullmancalc(Node *n)
-{
- int ul, ur;
-
- if(n == N)
- return;
-
- switch(n->op) {
- case OREGISTER:
- case OLITERAL:
- case ONAME:
- ul = 1;
- if(n->class == PPARAMREF || (n->class & PHEAP))
- ul++;
- goto out;
- case OCALL:
- case OCALLFUNC:
- case OCALLMETH:
- case OCALLINTER:
- ul = UINF;
- goto out;
- }
- ul = 1;
- if(n->left != N)
- ul = n->left->ullman;
- ur = 1;
- if(n->right != N)
- ur = n->right->ullman;
- if(ul == ur)
- ul += 1;
- if(ur > ul)
- ul = ur;
-
-out:
- n->ullman = ul;
-}
-
-void
-badtype(int o, Type *tl, Type *tr)
-{
- Fmt fmt;
- char *s;
-
- fmtstrinit(&fmt);
- if(tl != T)
- fmtprint(&fmt, "\n %T", tl);
- if(tr != T)
- fmtprint(&fmt, "\n %T", tr);
-
- // common mistake: *struct and *interface.
- if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
- if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
- fmtprint(&fmt, "\n (*struct vs *interface)");
- else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
- fmtprint(&fmt, "\n (*interface vs *struct)");
- }
- s = fmtstrflush(&fmt);
- yyerror("illegal types for operand: %O%s", o, s);
-}
-
-/*
- * iterator to walk a structure declaration
- */
-Type*
-structfirst(Iter *s, Type **nn)
-{
- Type *n, *t;
-
- n = *nn;
- if(n == T)
- goto bad;
-
- switch(n->etype) {
- default:
- goto bad;
-
- case TSTRUCT:
- case TINTER:
- case TFUNC:
- break;
- }
-
- t = n->type;
- if(t == T)
- goto rnil;
-
- if(t->etype != TFIELD)
- fatal("structfirst: not field %T", t);
-
- s->t = t;
- return t;
-
-bad:
- fatal("structfirst: not struct %T", n);
-
-rnil:
- return T;
-}
-
-Type*
-structnext(Iter *s)
-{
- Type *n, *t;
-
- n = s->t;
- t = n->down;
- if(t == T)
- goto rnil;
-
- if(t->etype != TFIELD)
- goto bad;
-
- s->t = t;
- return t;
-
-bad:
- fatal("structnext: not struct %T", n);
-
-rnil:
- return T;
-}
-
-/*
- * iterator to this and inargs in a function
- */
-Type*
-funcfirst(Iter *s, Type *t)
-{
- Type *fp;
-
- if(t == T)
- goto bad;
-
- if(t->etype != TFUNC)
- goto bad;
-
- s->tfunc = t;
- s->done = 0;
- fp = structfirst(s, getthis(t));
- if(fp == T) {
- s->done = 1;
- fp = structfirst(s, getinarg(t));
- }
- return fp;
-
-bad:
- fatal("funcfirst: not func %T", t);
- return T;
-}
-
-Type*
-funcnext(Iter *s)
-{
- Type *fp;
-
- fp = structnext(s);
- if(fp == T && !s->done) {
- s->done = 1;
- fp = structfirst(s, getinarg(s->tfunc));
- }
- return fp;
-}
-
-Type**
-getthis(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getthis: not a func %T", t);
- return &t->type;
-}
-
-Type**
-getoutarg(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getoutarg: not a func %T", t);
- return &t->type->down;
-}
-
-Type**
-getinarg(Type *t)
-{
- if(t->etype != TFUNC)
- fatal("getinarg: not a func %T", t);
- return &t->type->down->down;
-}
-
-Type*
-getthisx(Type *t)
-{
- return *getthis(t);
-}
-
-Type*
-getoutargx(Type *t)
-{
- return *getoutarg(t);
-}
-
-Type*
-getinargx(Type *t)
-{
- return *getinarg(t);
-}
-
-/*
- * return !(op)
- * eg == <=> !=
- */
-int
-brcom(int a)
-{
- switch(a) {
- case OEQ: return ONE;
- case ONE: return OEQ;
- case OLT: return OGE;
- case OGT: return OLE;
- case OLE: return OGT;
- case OGE: return OLT;
- }
- fatal("brcom: no com for %A\n", a);
- return a;
-}
-
-/*
- * return reverse(op)
- * eg a op b <=> b r(op) a
- */
-int
-brrev(int a)
-{
- switch(a) {
- case OEQ: return OEQ;
- case ONE: return ONE;
- case OLT: return OGT;
- case OGT: return OLT;
- case OLE: return OGE;
- case OGE: return OLE;
- }
- fatal("brcom: no rev for %A\n", a);
- return a;
-}
-
-/*
- * return side effect-free n, appending side effects to init.
- * result is assignable if n is.
- */
-Node*
-safeexpr(Node *n, NodeList **init)
-{
- Node *l;
- Node *r;
- Node *a;
-
- if(n == N)
- return N;
-
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
-
- case ODOT:
- l = safeexpr(n->left, init);
- if(l == n->left)
- return n;
- r = nod(OXXX, N, N);
- *r = *n;
- r->left = l;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- return r;
-
- case ODOTPTR:
- case OIND:
- l = safeexpr(n->left, init);
- if(l == n->left)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->left = l;
- walkexpr(&a, init);
- return a;
-
- case OINDEX:
- case OINDEXMAP:
- l = safeexpr(n->left, init);
- r = safeexpr(n->right, init);
- if(l == n->left && r == n->right)
- return n;
- a = nod(OXXX, N, N);
- *a = *n;
- a->left = l;
- a->right = r;
- walkexpr(&a, init);
- return a;
- }
-
- // make a copy; must not be used as an lvalue
- if(islvalue(n))
- fatal("missing lvalue case in safeexpr: %N", n);
- return cheapexpr(n, init);
-}
-
-/*
- * return side-effect free and cheap n, appending side effects to init.
- * result may not be assignable.
- */
-Node*
-cheapexpr(Node *n, NodeList **init)
-{
- Node *a, *l;
-
- switch(n->op) {
- case ONAME:
- case OLITERAL:
- return n;
- }
-
- l = nod(OXXX, N, N);
- tempname(l, n->type);
- a = nod(OAS, l, n);
- typecheck(&a, Etop);
- walkexpr(&a, init);
- *init = list(*init, a);
- return l;
-}
-
-void
-setmaxarg(Type *t)
-{
- int32 w;
-
- dowidth(t);
- w = t->argwid;
- if(t->argwid >= MAXWIDTH)
- fatal("bad argwid %T", t);
- if(w > maxarg)
- maxarg = w;
-}
-
-/* unicode-aware case-insensitive strcmp */
-
-static int
-cistrcmp(char *p, char *q)
-{
- Rune rp, rq;
-
- while(*p || *q) {
- if(*p == 0)
- return +1;
- if(*q == 0)
- return -1;
- p += chartorune(&rp, p);
- q += chartorune(&rq, q);
- rp = tolowerrune(rp);
- rq = tolowerrune(rq);
- if(rp < rq)
- return -1;
- if(rp > rq)
- return +1;
- }
- return 0;
-}
-
-/*
- * code to resolve elided DOTs
- * in embedded types
- */
-
-// search depth 0 --
-// return count of fields+methods
-// found with a given name
-static int
-lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
-{
- Type *f, *u;
- int c;
-
- u = t;
- if(isptr[u->etype])
- u = u->type;
-
- c = 0;
- if(u->etype == TSTRUCT || u->etype == TINTER) {
- for(f=u->type; f!=T; f=f->down)
- if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) {
- if(save)
- *save = f;
- c++;
- }
- }
- u = methtype(t);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down)
- if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) {
- if(save)
- *save = f;
- c++;
- }
- }
- return c;
-}
-
-// search depth d --
-// return count of fields+methods
-// found at search depth.
-// answer is in dotlist array and
-// count of number of ways is returned.
-int
-adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
-{
- Type *f, *u;
- int c, a;
-
- if(t->trecur)
- return 0;
- t->trecur = 1;
-
- if(d == 0) {
- c = lookdot0(s, t, save, ignorecase);
- goto out;
- }
-
- c = 0;
- u = t;
- if(isptr[u->etype])
- u = u->type;
- if(u->etype != TSTRUCT && u->etype != TINTER)
- goto out;
-
- d--;
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- a = adddot1(s, f->type, d, save, ignorecase);
- if(a != 0 && c == 0)
- dotlist[d].field = f;
- c += a;
- }
-
-out:
- t->trecur = 0;
- return c;
-}
-
-// in T.field
-// find missing fields that
-// will give shortest unique addressing.
-// modify the tree with missing type names.
-Node*
-adddot(Node *n)
-{
- Type *t;
- Sym *s;
- int c, d;
-
- typecheck(&n->left, Etype|Erv);
- t = n->left->type;
- if(t == T)
- goto ret;
-
- if(n->left->op == OTYPE)
- goto ret;
-
- if(n->right->op != ONAME)
- goto ret;
- s = n->right->sym;
- if(s == S)
- goto ret;
-
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(s, t, d, nil, 0);
- if(c > 0)
- goto out;
- }
- goto ret;
-
-out:
- if(c > 1)
- yyerror("ambiguous DOT reference %T.%S", t, s);
-
- // rebuild elided dots
- for(c=d-1; c>=0; c--)
- n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
-ret:
- return n;
-}
-
-
-/*
- * code to help generate trampoline
- * functions for methods on embedded
- * subtypes.
- * these are approx the same as
- * the corresponding adddot routines
- * except that they expect to be called
- * with unique tasks and they return
- * the actual methods.
- */
-
-typedef struct Symlink Symlink;
-struct Symlink
-{
- Type* field;
- uchar good;
- uchar followptr;
- Symlink* link;
-};
-static Symlink* slist;
-
-static void
-expand0(Type *t, int followptr)
-{
- Type *f, *u;
- Symlink *sl;
-
- u = t;
- if(isptr[u->etype]) {
- followptr = 1;
- u = u->type;
- }
-
- if(u->etype == TINTER) {
- for(f=u->type; f!=T; f=f->down) {
- if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
- continue;
- if(f->sym->flags & SymUniq)
- continue;
- f->sym->flags |= SymUniq;
- sl = mal(sizeof(*sl));
- sl->field = f;
- sl->link = slist;
- sl->followptr = followptr;
- slist = sl;
- }
- return;
- }
-
- u = methtype(t);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down) {
- if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
- continue;
- if(f->sym->flags & SymUniq)
- continue;
- f->sym->flags |= SymUniq;
- sl = mal(sizeof(*sl));
- sl->field = f;
- sl->link = slist;
- sl->followptr = followptr;
- slist = sl;
- }
- }
-}
-
-static void
-expand1(Type *t, int d, int followptr)
-{
- Type *f, *u;
-
- if(t->trecur)
- return;
- if(d == 0)
- return;
- t->trecur = 1;
-
- if(d != nelem(dotlist)-1)
- expand0(t, followptr);
-
- u = t;
- if(isptr[u->etype]) {
- followptr = 1;
- u = u->type;
- }
- if(u->etype != TSTRUCT && u->etype != TINTER)
- goto out;
-
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- expand1(f->type, d-1, followptr);
- }
-
-out:
- t->trecur = 0;
-}
-
-void
-expandmeth(Sym *s, Type *t)
-{
- Symlink *sl;
- Type *f;
- int c, d;
-
- if(s == S)
- return;
- if(t == T || t->xmethod != nil)
- return;
-
- // mark top-level method symbols
- // so that expand1 doesn't consider them.
- for(f=t->method; f != nil; f=f->down)
- f->sym->flags |= SymUniq;
-
- // generate all reachable methods
- slist = nil;
- expand1(t, nelem(dotlist)-1, 0);
-
- // check each method to be uniquely reachable
- for(sl=slist; sl!=nil; sl=sl->link) {
- sl->field->sym->flags &= ~SymUniq;
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(sl->field->sym, t, d, &f, 0);
- if(c == 0)
- continue;
- if(c == 1) {
- sl->good = 1;
- sl->field = f;
- }
- break;
- }
- }
-
- for(f=t->method; f != nil; f=f->down)
- f->sym->flags &= ~SymUniq;
-
- t->xmethod = t->method;
- for(sl=slist; sl!=nil; sl=sl->link) {
- if(sl->good) {
- // add it to the base type method list
- f = typ(TFIELD);
- *f = *sl->field;
- f->embedded = 1; // needs a trampoline
- if(sl->followptr)
- f->embedded = 2;
- f->down = t->xmethod;
- t->xmethod = f;
- }
- }
-}
-
-/*
- * Given funarg struct list, return list of ODCLFIELD Node fn args.
- */
-static NodeList*
-structargs(Type **tl, int mustname)
-{
- Iter savet;
- Node *a, *n;
- NodeList *args;
- Type *t;
- char buf[100];
- int gen;
-
- args = nil;
- gen = 0;
- for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
- n = N;
- if(t->sym)
- n = newname(t->sym);
- else if(mustname) {
- // have to give it a name so we can refer to it in trampoline
- snprint(buf, sizeof buf, ".anon%d", gen++);
- n = newname(lookup(buf));
- }
- a = nod(ODCLFIELD, n, typenod(t->type));
- a->isddd = t->isddd;
- if(n != N)
- n->isddd = t->isddd;
- args = list(args, a);
- }
- return args;
-}
-
-/*
- * Generate a wrapper function to convert from
- * a receiver of type T to a receiver of type U.
- * That is,
- *
- * func (t T) M() {
- * ...
- * }
- *
- * already exists; this function generates
- *
- * func (u U) M() {
- * u.M()
- * }
- *
- * where the types T and U are such that u.M() is valid
- * and calls the T.M method.
- * The resulting function is for use in method tables.
- *
- * rcvr - U
- * method - M func (t T)(), a TFIELD type struct
- * newnam - the eventual mangled name of this function
- */
-void
-genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
- Node *this, *fn, *call, *n, *t, *pad;
- NodeList *l, *args, *in, *out;
- Type *tpad;
- int isddd;
- Val v;
-
- if(debug['r'])
- print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
- rcvr, method, newnam);
-
- lineno = 1; // less confusing than end of input
-
- dclcontext = PEXTERN;
- markdcl();
-
- this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
- this->left->ntype = this->right;
- in = structargs(getinarg(method->type), 1);
- out = structargs(getoutarg(method->type), 0);
-
- fn = nod(ODCLFUNC, N, N);
- fn->nname = newname(newnam);
- t = nod(OTFUNC, N, N);
- l = list1(this);
- if(iface && rcvr->width < types[tptr]->width) {
- // Building method for interface table and receiver
- // is smaller than the single pointer-sized word
- // that the interface call will pass in.
- // Add a dummy padding argument after the
- // receiver to make up the difference.
- tpad = typ(TARRAY);
- tpad->type = types[TUINT8];
- tpad->bound = types[tptr]->width - rcvr->width;
- pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
- l = list(l, pad);
- }
- t->list = concat(l, in);
- t->rlist = out;
- fn->nname->ntype = t;
- funchdr(fn);
-
- // arg list
- args = nil;
- isddd = 0;
- for(l=in; l; l=l->next) {
- args = list(args, l->n->left);
- isddd = l->n->left->isddd;
- }
-
- // generate nil pointer check for better error
- if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) {
- // generating wrapper from *T to T.
- n = nod(OIF, N, N);
- n->ntest = nod(OEQ, this->left, nodnil());
- // these strings are already in the reflect tables,
- // so no space cost to use them here.
- l = nil;
- v.ctype = CTSTR;
- v.u.sval = strlit(rcvr->type->sym->pkg->name); // package name
- l = list(l, nodlit(v));
- v.u.sval = strlit(rcvr->type->sym->name); // type name
- l = list(l, nodlit(v));
- v.u.sval = strlit(method->sym->name);
- l = list(l, nodlit(v)); // method name
- call = nod(OCALL, syslook("panicwrap", 0), N);
- call->list = l;
- n->nbody = list1(call);
- fn->nbody = list(fn->nbody, n);
- }
-
- // generate call
- call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
- call->list = args;
- call->isddd = isddd;
- if(method->type->outtuple > 0) {
- n = nod(ORETURN, N, N);
- n->list = list1(call);
- call = n;
- }
- fn->nbody = list(fn->nbody, call);
-
- if(0 && debug['r'])
- dumplist("genwrapper body", fn->nbody);
-
- funcbody(fn);
- curfn = fn;
- typecheck(&fn, Etop);
- typechecklist(fn->nbody, Etop);
- curfn = nil;
- funccompile(fn, 0);
-}
-
-static Type*
-ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
-{
- int i, c, d;
- Type *m;
-
- *followptr = 0;
-
- if(t == T)
- return T;
-
- for(d=0; d<nelem(dotlist); d++) {
- c = adddot1(s, t, d, &m, ignorecase);
- if(c > 1) {
- yyerror("%T.%S is ambiguous", t, s);
- return T;
- }
- if(c == 1) {
- for(i=0; i<d; i++) {
- if(isptr[dotlist[i].field->type->etype]) {
- *followptr = 1;
- break;
- }
- }
- if(m->type->etype != TFUNC || m->type->thistuple == 0) {
- yyerror("%T.%S is a field, not a method", t, s);
- return T;
- }
- return m;
- }
- }
- return T;
-}
-
-int
-implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
-{
- Type *t0, *im, *tm, *rcvr, *imtype;
- int followptr;
-
- t0 = t;
- if(t == T)
- return 0;
-
- // if this is too slow,
- // could sort these first
- // and then do one loop.
-
- if(t->etype == TINTER) {
- for(im=iface->type; im; im=im->down) {
- for(tm=t->type; tm; tm=tm->down) {
- if(tm->sym == im->sym) {
- if(eqtype(tm->type, im->type))
- goto found;
- *m = im;
- *samename = tm;
- *ptr = 0;
- return 0;
- }
- }
- *m = im;
- *samename = nil;
- *ptr = 0;
- return 0;
- found:;
- }
- return 1;
- }
-
- t = methtype(t);
- if(t != T)
- expandmeth(t->sym, t);
- for(im=iface->type; im; im=im->down) {
- imtype = methodfunc(im->type, 0);
- tm = ifacelookdot(im->sym, t, &followptr, 0);
- if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) {
- if(tm == T)
- tm = ifacelookdot(im->sym, t, &followptr, 1);
- *m = im;
- *samename = tm;
- *ptr = 0;
- return 0;
- }
- // if pointer receiver in method,
- // the method does not exist for value types.
- rcvr = getthisx(tm->type)->type->type;
- if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
- if(0 && debug['r'])
- yyerror("interface pointer mismatch");
-
- *m = im;
- *samename = nil;
- *ptr = 1;
- return 0;
- }
- }
- return 1;
-}
-
-/*
- * even simpler simtype; get rid of ptr, bool.
- * assuming that the front end has rejected
- * all the invalid conversions (like ptr -> bool)
- */
-int
-simsimtype(Type *t)
-{
- int et;
-
- if(t == 0)
- return 0;
-
- et = simtype[t->etype];
- switch(et) {
- case TPTR32:
- et = TUINT32;
- break;
- case TPTR64:
- et = TUINT64;
- break;
- case TBOOL:
- et = TUINT8;
- break;
- }
- return et;
-}
-
-NodeList*
-concat(NodeList *a, NodeList *b)
-{
- if(a == nil)
- return b;
- if(b == nil)
- return a;
-
- a->end->next = b;
- a->end = b->end;
- b->end = nil;
- return a;
-}
-
-NodeList*
-list1(Node *n)
-{
- NodeList *l;
-
- if(n == nil)
- return nil;
- if(n->op == OBLOCK && n->ninit == nil)
- return n->list;
- l = mal(sizeof *l);
- l->n = n;
- l->end = l;
- return l;
-}
-
-NodeList*
-list(NodeList *l, Node *n)
-{
- return concat(l, list1(n));
-}
-
-void
-listsort(NodeList** l, int(*f)(Node*, Node*))
-{
- NodeList *l1, *l2, *le;
-
- if(*l == nil || (*l)->next == nil)
- return;
-
- l1 = *l;
- l2 = *l;
- for(;;) {
- l2 = l2->next;
- if(l2 == nil)
- break;
- l2 = l2->next;
- if(l2 == nil)
- break;
- l1 = l1->next;
- }
-
- l2 = l1->next;
- l1->next = nil;
- l2->end = (*l)->end;
- (*l)->end = l1;
-
- l1 = *l;
- listsort(&l1, f);
- listsort(&l2, f);
-
- if ((*f)(l1->n, l2->n) < 0) {
- *l = l1;
- } else {
- *l = l2;
- l2 = l1;
- l1 = *l;
- }
-
- // now l1 == *l; and l1 < l2
-
- while ((l1 != nil) && (l2 != nil)) {
- while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
- l1 = l1->next;
-
- // l1 is last one from l1 that is < l2
- le = l1->next; // le is the rest of l1, first one that is >= l2
- if (le != nil)
- le->end = (*l)->end;
-
- (*l)->end = l1; // cut *l at l1
- *l = concat(*l, l2); // glue l2 to *l's tail
-
- l1 = l2; // l1 is the first element of *l that is < the new l2
- l2 = le; // ... because l2 now is the old tail of l1
- }
-
- *l = concat(*l, l2); // any remainder
-}
-
-NodeList*
-listtreecopy(NodeList *l)
-{
- NodeList *out;
-
- out = nil;
- for(; l; l=l->next)
- out = list(out, treecopy(l->n));
- return out;
-}
-
-Node*
-liststmt(NodeList *l)
-{
- Node *n;
-
- n = nod(OBLOCK, N, N);
- n->list = l;
- if(l)
- n->lineno = l->n->lineno;
- return n;
-}
-
-/*
- * return nelem of list
- */
-int
-count(NodeList *l)
-{
- int n;
-
- n = 0;
- for(; l; l=l->next)
- n++;
- return n;
-}
-
-/*
- * return nelem of list
- */
-int
-structcount(Type *t)
-{
- int v;
- Iter s;
-
- v = 0;
- for(t = structfirst(&s, &t); t != T; t = structnext(&s))
- v++;
- return v;
-}
-
-/*
- * return power of 2 of the constant
- * operand. -1 if it is not a power of 2.
- * 1000+ if it is a -(power of 2)
- */
-int
-powtwo(Node *n)
-{
- uvlong v, b;
- int i;
-
- if(n == N || n->op != OLITERAL || n->type == T)
- goto no;
- if(!isint[n->type->etype])
- goto no;
-
- v = mpgetfix(n->val.u.xval);
- b = 1ULL;
- for(i=0; i<64; i++) {
- if(b == v)
- return i;
- b = b<<1;
- }
-
- if(!issigned[n->type->etype])
- goto no;
-
- v = -v;
- b = 1ULL;
- for(i=0; i<64; i++) {
- if(b == v)
- return i+1000;
- b = b<<1;
- }
-
-no:
- return -1;
-}
-
-/*
- * return the unsigned type for
- * a signed integer type.
- * returns T if input is not a
- * signed integer type.
- */
-Type*
-tounsigned(Type *t)
-{
-
- // this is types[et+1], but not sure
- // that this relation is immutable
- switch(t->etype) {
- default:
- print("tounsigned: unknown type %T\n", t);
- t = T;
- break;
- case TINT:
- t = types[TUINT];
- break;
- case TINT8:
- t = types[TUINT8];
- break;
- case TINT16:
- t = types[TUINT16];
- break;
- case TINT32:
- t = types[TUINT32];
- break;
- case TINT64:
- t = types[TUINT64];
- break;
- }
- return t;
-}
-
-/*
- * magic number for signed division
- * see hacker's delight chapter 10
- */
-void
-smagic(Magic *m)
-{
- int p;
- uint64 ad, anc, delta, q1, r1, q2, r2, t;
- uint64 mask, two31;
-
- m->bad = 0;
- switch(m->w) {
- default:
- m->bad = 1;
- return;
- case 8:
- mask = 0xffLL;
- break;
- case 16:
- mask = 0xffffLL;
- break;
- case 32:
- mask = 0xffffffffLL;
- break;
- case 64:
- mask = 0xffffffffffffffffLL;
- break;
- }
- two31 = mask ^ (mask>>1);
-
- p = m->w-1;
- ad = m->sd;
- if(m->sd < 0)
- ad = -m->sd;
-
- // bad denominators
- if(ad == 0 || ad == 1 || ad == two31) {
- m->bad = 1;
- return;
- }
-
- t = two31;
- ad &= mask;
-
- anc = t - 1 - t%ad;
- anc &= mask;
-
- q1 = two31/anc;
- r1 = two31 - q1*anc;
- q1 &= mask;
- r1 &= mask;
-
- q2 = two31/ad;
- r2 = two31 - q2*ad;
- q2 &= mask;
- r2 &= mask;
-
- for(;;) {
- p++;
- q1 <<= 1;
- r1 <<= 1;
- q1 &= mask;
- r1 &= mask;
- if(r1 >= anc) {
- q1++;
- r1 -= anc;
- q1 &= mask;
- r1 &= mask;
- }
-
- q2 <<= 1;
- r2 <<= 1;
- q2 &= mask;
- r2 &= mask;
- if(r2 >= ad) {
- q2++;
- r2 -= ad;
- q2 &= mask;
- r2 &= mask;
- }
-
- delta = ad - r2;
- delta &= mask;
- if(q1 < delta || (q1 == delta && r1 == 0)) {
- continue;
- }
- break;
- }
-
- m->sm = q2+1;
- if(m->sm & two31)
- m->sm |= ~mask;
- m->s = p-m->w;
-}
-
-/*
- * magic number for unsigned division
- * see hacker's delight chapter 10
- */
-void
-umagic(Magic *m)
-{
- int p;
- uint64 nc, delta, q1, r1, q2, r2;
- uint64 mask, two31;
-
- m->bad = 0;
- m->ua = 0;
-
- switch(m->w) {
- default:
- m->bad = 1;
- return;
- case 8:
- mask = 0xffLL;
- break;
- case 16:
- mask = 0xffffLL;
- break;
- case 32:
- mask = 0xffffffffLL;
- break;
- case 64:
- mask = 0xffffffffffffffffLL;
- break;
- }
- two31 = mask ^ (mask>>1);
-
- m->ud &= mask;
- if(m->ud == 0 || m->ud == two31) {
- m->bad = 1;
- return;
- }
- nc = mask - (-m->ud&mask)%m->ud;
- p = m->w-1;
-
- q1 = two31/nc;
- r1 = two31 - q1*nc;
- q1 &= mask;
- r1 &= mask;
-
- q2 = (two31-1) / m->ud;
- r2 = (two31-1) - q2*m->ud;
- q2 &= mask;
- r2 &= mask;
-
- for(;;) {
- p++;
- if(r1 >= nc-r1) {
- q1 <<= 1;
- q1++;
- r1 <<= 1;
- r1 -= nc;
- } else {
- q1 <<= 1;
- r1 <<= 1;
- }
- q1 &= mask;
- r1 &= mask;
- if(r2+1 >= m->ud-r2) {
- if(q2 >= two31-1) {
- m->ua = 1;
- }
- q2 <<= 1;
- q2++;
- r2 <<= 1;
- r2++;
- r2 -= m->ud;
- } else {
- if(q2 >= two31) {
- m->ua = 1;
- }
- q2 <<= 1;
- r2 <<= 1;
- r2++;
- }
- q2 &= mask;
- r2 &= mask;
-
- delta = m->ud - 1 - r2;
- delta &= mask;
-
- if(p < m->w+m->w)
- if(q1 < delta || (q1 == delta && r1 == 0)) {
- continue;
- }
- break;
- }
- m->um = q2+1;
- m->s = p-m->w;
-}
-
-Sym*
-ngotype(Node *n)
-{
- if(n->sym != S && n->realtype != T)
- if(strncmp(n->sym->name, "autotmp_", 8) != 0)
- if(strncmp(n->sym->name, "statictmp_", 8) != 0)
- return typename(n->realtype)->left->sym;
-
- return S;
-}
-
-/*
- * Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx. Right now the only bytes that need
- * escaping are %, ., and ", but we escape all control characters too.
- */
-static char*
-pathtoprefix(char *s)
-{
- static char hex[] = "0123456789abcdef";
- char *p, *r, *w;
- int n;
-
- // check for chars that need escaping
- n = 0;
- for(r=s; *r; r++)
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
- n++;
-
- // quick exit
- if(n == 0)
- return s;
-
- // escape
- p = mal((r-s)+1+2*n);
- for(r=s, w=p; *r; r++) {
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
- *w++ = '%';
- *w++ = hex[(*r>>4)&0xF];
- *w++ = hex[*r&0xF];
- } else
- *w++ = *r;
- }
- *w = '\0';
- return p;
-}
-
-Pkg*
-mkpkg(Strlit *path)
-{
- Pkg *p;
- int h;
-
- if(strlen(path->s) != path->len) {
- yyerror("import path contains NUL byte");
- errorexit();
- }
-
- h = stringhash(path->s) & (nelem(phash)-1);
- for(p=phash[h]; p; p=p->link)
- if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
- return p;
-
- p = mal(sizeof *p);
- p->path = path;
- p->prefix = pathtoprefix(path->s);
- p->link = phash[h];
- phash[h] = p;
- return p;
-}
-
-Strlit*
-strlit(char *s)
-{
- Strlit *t;
-
- t = mal(sizeof *t + strlen(s));
- strcpy(t->s, s);
- t->len = strlen(s);
- return t;
-}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
deleted file mode 100644
index c2968c44b..000000000
--- a/src/cmd/gc/swt.c
+++ /dev/null
@@ -1,896 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-enum
-{
- Snorm = 0,
- Strue,
- Sfalse,
- Stype,
-
- Tdefault, // default case
- Texprconst, // normal constant case
- Texprvar, // normal variable case
- Ttypenil, // case nil
- Ttypeconst, // type hashes
- Ttypevar, // interface type
-
- Ncase = 4, // count needed to split
-};
-
-typedef struct Case Case;
-struct Case
-{
- Node* node; // points at case statement
- uint32 hash; // hash of a type switch
- uint8 type; // type of case
- uint8 diag; // suppress multiple diagnostics
- uint16 ordinal; // position in switch
- Case* link; // linked list to link
-};
-#define C ((Case*)nil)
-
-void
-dumpcase(Case *c0)
-{
- Case *c;
-
- for(c=c0; c!=C; c=c->link) {
- switch(c->type) {
- case Tdefault:
- print("case-default\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Texprconst:
- print("case-exprconst\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Texprvar:
- print("case-exprvar\n");
- print(" ord=%d\n", c->ordinal);
- print(" op=%O\n", c->node->left->op);
- break;
- case Ttypenil:
- print("case-typenil\n");
- print(" ord=%d\n", c->ordinal);
- break;
- case Ttypeconst:
- print("case-typeconst\n");
- print(" ord=%d\n", c->ordinal);
- print(" hash=%ux\n", c->hash);
- break;
- case Ttypevar:
- print("case-typevar\n");
- print(" ord=%d\n", c->ordinal);
- break;
- default:
- print("case-???\n");
- print(" ord=%d\n", c->ordinal);
- print(" op=%O\n", c->node->left->op);
- print(" hash=%ux\n", c->hash);
- break;
- }
- }
- print("\n");
-}
-
-static int
-ordlcmp(Case *c1, Case *c2)
-{
- // sort default first
- if(c1->type == Tdefault)
- return -1;
- if(c2->type == Tdefault)
- return +1;
-
- // sort nil second
- if(c1->type == Ttypenil)
- return -1;
- if(c2->type == Ttypenil)
- return +1;
-
- // sort by ordinal
- if(c1->ordinal > c2->ordinal)
- return +1;
- if(c1->ordinal < c2->ordinal)
- return -1;
- return 0;
-}
-
-static int
-exprcmp(Case *c1, Case *c2)
-{
- int ct, n;
- Node *n1, *n2;
-
- // sort non-constants last
- if(c1->type != Texprconst)
- return +1;
- if(c2->type != Texprconst)
- return -1;
-
- n1 = c1->node->left;
- n2 = c2->node->left;
-
- ct = n1->val.ctype;
- if(ct != n2->val.ctype) {
- // invalid program, but return a sort
- // order so that we can give a better
- // error later.
- return ct - n2->val.ctype;
- }
-
- // sort by constant value
- n = 0;
- switch(ct) {
- case CTFLT:
- n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
- break;
- case CTINT:
- n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
- break;
- case CTSTR:
- n = cmpslit(n1, n2);
- break;
- }
-
- return n;
-}
-
-static int
-typecmp(Case *c1, Case *c2)
-{
-
- // sort non-constants last
- if(c1->type != Ttypeconst)
- return +1;
- if(c2->type != Ttypeconst)
- return -1;
-
- // sort by hash code
- if(c1->hash > c2->hash)
- return +1;
- if(c1->hash < c2->hash)
- return -1;
-
- // sort by ordinal so duplicate error
- // happens on later case.
- if(c1->ordinal > c2->ordinal)
- return +1;
- if(c1->ordinal < c2->ordinal)
- return -1;
- return 0;
-}
-
-static Case*
-csort(Case *l, int(*f)(Case*, Case*))
-{
- Case *l1, *l2, *le;
-
- if(l == C || l->link == C)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == C)
- break;
- l2 = l2->link;
- if(l2 == C)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = C;
- l1 = csort(l, f);
- l2 = csort(l2, f);
-
- /* set up lead element */
- if((*f)(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == C) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = C;
- break;
- }
- if(l2 == C) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if((*f)(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = C;
- return l;
-}
-
-static Node*
-newlabel(void)
-{
- static int label;
-
- label++;
- snprint(namebuf, sizeof(namebuf), "%.6d", label);
- return newname(lookup(namebuf));
-}
-
-/*
- * build separate list of statements and cases
- * make labels between cases and statements
- * deal with fallthrough, break, unreachable statements
- */
-static void
-casebody(Node *sw, Node *typeswvar)
-{
- Node *n, *c, *last;
- Node *def;
- NodeList *cas, *stat, *l, *lc;
- Node *go, *br;
- int32 lno, needvar;
-
- lno = setlineno(sw);
- if(sw->list == nil)
- return;
-
- cas = nil; // cases
- stat = nil; // statements
- def = N; // defaults
- br = nod(OBREAK, N, N);
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
- lno = setlineno(n);
- if(n->op != OXCASE)
- fatal("casebody %O", n->op);
- n->op = OCASE;
- needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
-
- go = nod(OGOTO, newlabel(), N);
- if(n->list == nil) {
- if(def != N)
- yyerror("more than one default case");
- // reuse original default case
- n->right = go;
- def = n;
- }
-
- if(n->list != nil && n->list->next == nil) {
- // one case - reuse OCASE node.
- c = n->list->n;
- n->left = c;
- n->right = go;
- n->list = nil;
- cas = list(cas, n);
- } else {
- // expand multi-valued cases
- for(lc=n->list; lc; lc=lc->next) {
- c = lc->n;
- cas = list(cas, nod(OCASE, c, go));
- }
- }
-
- stat = list(stat, nod(OLABEL, go->left, N));
- if(typeswvar && needvar && n->nname != N) {
- NodeList *l;
-
- l = list1(nod(ODCL, n->nname, N));
- l = list(l, nod(OAS, n->nname, typeswvar));
- typechecklist(l, Etop);
- stat = concat(stat, l);
- }
- stat = concat(stat, n->nbody);
-
- // botch - shouldnt fall thru declaration
- last = stat->end->n;
- if(last->op == OXFALL) {
- if(typeswvar) {
- setlineno(last);
- yyerror("cannot fallthrough in type switch");
- }
- last->op = OFALL;
- } else
- stat = list(stat, br);
- }
-
- stat = list(stat, br);
- if(def)
- cas = list(cas, def);
-
- sw->list = cas;
- sw->nbody = stat;
- lineno = lno;
-}
-
-static Case*
-mkcaselist(Node *sw, int arg)
-{
- Node *n;
- Case *c, *c1, *c2;
- NodeList *l;
- int ord;
-
- c = C;
- ord = 0;
-
- for(l=sw->list; l; l=l->next) {
- n = l->n;
- c1 = mal(sizeof(*c1));
- c1->link = c;
- c = c1;
-
- ord++;
- c->ordinal = ord;
- c->node = n;
-
- if(n->left == N) {
- c->type = Tdefault;
- continue;
- }
-
- switch(arg) {
- case Stype:
- c->hash = 0;
- if(n->left->op == OLITERAL) {
- c->type = Ttypenil;
- continue;
- }
- if(istype(n->left->type, TINTER)) {
- c->type = Ttypevar;
- continue;
- }
-
- c->hash = typehash(n->left->type);
- c->type = Ttypeconst;
- continue;
-
- case Snorm:
- case Strue:
- case Sfalse:
- c->type = Texprvar;
- switch(consttype(n->left)) {
- case CTFLT:
- case CTINT:
- case CTSTR:
- c->type = Texprconst;
- }
- continue;
- }
- }
-
- if(c == C)
- return C;
-
- // sort by value and diagnose duplicate cases
- switch(arg) {
- case Stype:
- c = csort(c, typecmp);
- for(c1=c; c1!=C; c1=c1->link) {
- for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
- if(c1->type == Ttypenil || c1->type == Tdefault)
- break;
- if(c2->type == Ttypenil || c2->type == Tdefault)
- break;
- if(!eqtype(c1->node->left->type, c2->node->left->type))
- continue;
- yyerrorl(c2->node->lineno, "duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
- }
- }
- break;
- case Snorm:
- case Strue:
- case Sfalse:
- c = csort(c, exprcmp);
- for(c1=c; c1->link!=C; c1=c1->link) {
- if(exprcmp(c1, c1->link) != 0)
- continue;
- setlineno(c1->link->node);
- yyerror("duplicate case in switch\n\tprevious case at %L", c1->node->lineno);
- }
- break;
- }
-
- // put list back in processing order
- c = csort(c, ordlcmp);
- return c;
-}
-
-static Node* exprname;
-
-static Node*
-exprbsw(Case *c0, int ncase, int arg)
-{
- NodeList *cas;
- Node *a, *n;
- Case *c;
- int i, half, lno;
-
- cas = nil;
- if(ncase < Ncase) {
- for(i=0; i<ncase; i++) {
- n = c0->node;
- lno = setlineno(n);
-
- switch(arg) {
- case Strue:
- a = nod(OIF, N, N);
- a->ntest = n->left; // if val
- a->nbody = list1(n->right); // then goto l
- break;
-
- case Sfalse:
- a = nod(OIF, N, N);
- a->ntest = nod(ONOT, n->left, N); // if !val
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // then goto l
- break;
-
- default:
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, exprname, n->left); // if name == val
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // then goto l
- break;
- }
-
- cas = list(cas, a);
- c0 = c0->link;
- lineno = lno;
- }
- return liststmt(cas);
- }
-
- // find the middle and recur
- c = c0;
- half = ncase>>1;
- for(i=1; i<half; i++)
- c = c->link;
- a = nod(OIF, N, N);
- a->ntest = nod(OLE, exprname, c->node->left);
- typecheck(&a->ntest, Erv);
- a->nbody = list1(exprbsw(c0, half, arg));
- a->nelse = list1(exprbsw(c->link, ncase-half, arg));
- return a;
-}
-
-/*
- * normal (expression) switch.
- * rebulid case statements into if .. goto
- */
-static void
-exprswitch(Node *sw)
-{
- Node *def;
- NodeList *cas;
- Node *a;
- Case *c0, *c, *c1;
- Type *t;
- int arg, ncase;
-
- casebody(sw, N);
-
- arg = Snorm;
- if(isconst(sw->ntest, CTBOOL)) {
- arg = Strue;
- if(sw->ntest->val.u.bval == 0)
- arg = Sfalse;
- }
- walkexpr(&sw->ntest, &sw->ninit);
- t = sw->type;
- if(t == T)
- return;
-
- /*
- * convert the switch into OIF statements
- */
- exprname = N;
- cas = nil;
- if(arg != Strue && arg != Sfalse) {
- exprname = nod(OXXX, N, N);
- tempname(exprname, sw->ntest->type);
- cas = list1(nod(OAS, exprname, sw->ntest));
- typechecklist(cas, Etop);
- }
-
- c0 = mkcaselist(sw, arg);
- if(c0 != C && c0->type == Tdefault) {
- def = c0->node->right;
- c0 = c0->link;
- } else {
- def = nod(OBREAK, N, N);
- }
-
-loop:
- if(c0 == C) {
- cas = list(cas, def);
- sw->nbody = concat(cas, sw->nbody);
- sw->list = nil;
- walkstmtlist(sw->nbody);
- return;
- }
-
- // deal with the variables one-at-a-time
- if(c0->type != Texprconst) {
- a = exprbsw(c0, 1, arg);
- cas = list(cas, a);
- c0 = c0->link;
- goto loop;
- }
-
- // do binary search on run of constants
- ncase = 1;
- for(c=c0; c->link!=C; c=c->link) {
- if(c->link->type != Texprconst)
- break;
- ncase++;
- }
-
- // break the chain at the count
- c1 = c->link;
- c->link = C;
-
- // sort and compile constants
- c0 = csort(c0, exprcmp);
- a = exprbsw(c0, ncase, arg);
- cas = list(cas, a);
-
- c0 = c1;
- goto loop;
-
-}
-
-static Node* hashname;
-static Node* facename;
-static Node* boolname;
-
-static Node*
-typeone(Node *t)
-{
- NodeList *init;
- Node *a, *b, *var;
-
- var = t->nname;
- init = nil;
- if(var == N) {
- typecheck(&nblank, Erv | Easgn);
- var = nblank;
- } else
- init = list1(nod(ODCL, var, N));
-
- a = nod(OAS2, N, N);
- a->list = list(list1(var), boolname); // var,bool =
- b = nod(ODOTTYPE, facename, N);
- b->type = t->left->type; // interface.(type)
- a->rlist = list1(b);
- typecheck(&a, Etop);
- init = list(init, a);
-
- b = nod(OIF, N, N);
- b->ntest = boolname;
- b->nbody = list1(t->right); // if bool { goto l }
- a = liststmt(list(init, b));
- return a;
-}
-
-static Node*
-typebsw(Case *c0, int ncase)
-{
- NodeList *cas;
- Node *a, *n;
- Case *c;
- int i, half;
-
- cas = nil;
-
- if(ncase < Ncase) {
- for(i=0; i<ncase; i++) {
- n = c0->node;
- if(c0->type != Ttypeconst)
- fatal("typebsw");
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right);
- cas = list(cas, a);
- c0 = c0->link;
- }
- return liststmt(cas);
- }
-
- // find the middle and recur
- c = c0;
- half = ncase>>1;
- for(i=1; i<half; i++)
- c = c->link;
- a = nod(OIF, N, N);
- a->ntest = nod(OLE, hashname, nodintconst(c->hash));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(typebsw(c0, half));
- a->nelse = list1(typebsw(c->link, ncase-half));
- return a;
-}
-
-/*
- * convert switch of the form
- * switch v := i.(type) { case t1: ..; case t2: ..; }
- * into if statements
- */
-static void
-typeswitch(Node *sw)
-{
- Node *def;
- NodeList *cas, *hash;
- Node *a, *n;
- Case *c, *c0, *c1;
- int ncase;
- Type *t;
- Val v;
-
- if(sw->ntest == nil)
- return;
- if(sw->ntest->right == nil) {
- setlineno(sw);
- yyerror("type switch must have an assignment");
- return;
- }
- walkexpr(&sw->ntest->right, &sw->ninit);
- if(!istype(sw->ntest->right->type, TINTER)) {
- yyerror("type switch must be on an interface");
- return;
- }
- cas = nil;
-
- /*
- * predeclare temporary variables
- * and the boolean var
- */
- facename = nod(OXXX, N, N);
- tempname(facename, sw->ntest->right->type);
- a = nod(OAS, facename, sw->ntest->right);
- typecheck(&a, Etop);
- cas = list(cas, a);
-
- casebody(sw, facename);
-
- boolname = nod(OXXX, N, N);
- tempname(boolname, types[TBOOL]);
- typecheck(&boolname, Erv);
-
- hashname = nod(OXXX, N, N);
- tempname(hashname, types[TUINT32]);
- typecheck(&hashname, Erv);
-
- t = sw->ntest->right->type;
- if(isnilinter(t))
- a = syslook("efacethash", 1);
- else
- a = syslook("ifacethash", 1);
- argtype(a, t);
- a = nod(OCALL, a, N);
- a->list = list1(facename);
- a = nod(OAS, hashname, a);
- typecheck(&a, Etop);
- cas = list(cas, a);
-
- c0 = mkcaselist(sw, Stype);
- if(c0 != C && c0->type == Tdefault) {
- def = c0->node->right;
- c0 = c0->link;
- } else {
- def = nod(OBREAK, N, N);
- }
-
- /*
- * insert if statement into each case block
- */
- for(c=c0; c!=C; c=c->link) {
- n = c->node;
- switch(c->type) {
-
- case Ttypenil:
- v.ctype = CTNIL;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, facename, nodlit(v));
- typecheck(&a->ntest, Erv);
- a->nbody = list1(n->right); // if i==nil { goto l }
- n->right = a;
- break;
-
- case Ttypevar:
- case Ttypeconst:
- n->right = typeone(n);
- break;
- }
- }
-
- /*
- * generate list of if statements, binary search for constant sequences
- */
- while(c0 != C) {
- if(c0->type != Ttypeconst) {
- n = c0->node;
- cas = list(cas, n->right);
- c0=c0->link;
- continue;
- }
-
- // identify run of constants
- c1 = c = c0;
- while(c->link!=C && c->link->type==Ttypeconst)
- c = c->link;
- c0 = c->link;
- c->link = nil;
-
- // sort by hash
- c1 = csort(c1, typecmp);
-
- // for debugging: linear search
- if(0) {
- for(c=c1; c!=C; c=c->link) {
- n = c->node;
- cas = list(cas, n->right);
- }
- continue;
- }
-
- // combine adjacent cases with the same hash
- ncase = 0;
- for(c=c1; c!=C; c=c->link) {
- ncase++;
- hash = list1(c->node->right);
- while(c->link != C && c->link->hash == c->hash) {
- hash = list(hash, c->link->node->right);
- c->link = c->link->link;
- }
- c->node->right = liststmt(hash);
- }
-
- // binary search among cases to narrow by hash
- cas = list(cas, typebsw(c1, ncase));
- }
- if(nerrors == 0) {
- cas = list(cas, def);
- sw->nbody = concat(cas, sw->nbody);
- sw->list = nil;
- walkstmtlist(sw->nbody);
- }
-}
-
-void
-walkswitch(Node *sw)
-{
-
- /*
- * reorder the body into (OLIST, cases, statements)
- * cases have OGOTO into statements.
- * both have inserted OBREAK statements
- */
- walkstmtlist(sw->ninit);
- if(sw->ntest == N) {
- sw->ntest = nodbool(1);
- typecheck(&sw->ntest, Erv);
- }
-
- if(sw->ntest->op == OTYPESW) {
- typeswitch(sw);
-//dump("sw", sw);
- return;
- }
- exprswitch(sw);
-}
-
-/*
- * type check switch statement
- */
-void
-typecheckswitch(Node *n)
-{
- int top, lno;
- Type *t;
- NodeList *l, *ll;
- Node *ncase, *nvar;
- Node *def;
-
- lno = lineno;
- typechecklist(n->ninit, Etop);
-
- if(n->ntest != N && n->ntest->op == OTYPESW) {
- // type switch
- top = Etype;
- typecheck(&n->ntest->right, Erv);
- t = n->ntest->right->type;
- if(t != T && t->etype != TINTER)
- yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
- } else {
- // value switch
- top = Erv;
- if(n->ntest) {
- typecheck(&n->ntest, Erv);
- defaultlit(&n->ntest, T);
- t = n->ntest->type;
- } else
- t = types[TBOOL];
- }
- n->type = t;
-
- def = N;
- for(l=n->list; l; l=l->next) {
- ncase = l->n;
- setlineno(n);
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in switch (first at %L)", def->lineno);
- else
- def = ncase;
- } else {
- for(ll=ncase->list; ll; ll=ll->next) {
- setlineno(ll->n);
- typecheck(&ll->n, Erv | Etype);
- if(ll->n->type == T || t == T)
- continue;
- switch(top) {
- case Erv: // expression switch
- defaultlit(&ll->n, t);
- if(ll->n->op == OTYPE)
- yyerror("type %T is not an expression", ll->n->type);
- else if(ll->n->type != T && !eqtype(ll->n->type, t))
- yyerror("case %+N in %T switch", ll->n, t);
- break;
- case Etype: // type switch
- if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
- ;
- else if(ll->n->op != OTYPE && ll->n->type != T) {
- yyerror("%#N is not a type", ll->n);
- // reset to original type
- ll->n = n->ntest->right;
- }
- break;
- }
- }
- }
- if(top == Etype && n->type != T) {
- ll = ncase->list;
- nvar = ncase->nname;
- if(nvar != N) {
- if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
- // single entry type switch
- nvar->ntype = typenod(ll->n->type);
- } else {
- // multiple entry type switch or default
- nvar->ntype = typenod(n->type);
- }
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
-
- lineno = lno;
-}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
deleted file mode 100644
index dfe0f30f7..000000000
--- a/src/cmd/gc/typecheck.c
+++ /dev/null
@@ -1,2822 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * type check the whole tree of an expression.
- * calculates expression types.
- * evaluates compile time constants.
- * marks variables that escape the local frame.
- * rewrites n->op to be more specific in some cases.
- */
-
-#include "go.h"
-
-static void implicitstar(Node**);
-static int onearg(Node*, char*, ...);
-static int twoarg(Node*);
-static int lookdot(Node*, Type*, int);
-static int looktypedot(Node*, Type*, int);
-static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
-static Type* lookdot1(Sym *s, Type *t, Type *f, int);
-static int nokeys(NodeList*);
-static void typecheckcomplit(Node**);
-static void addrescapes(Node*);
-static void typecheckas2(Node*);
-static void typecheckas(Node*);
-static void typecheckfunc(Node*);
-static void checklvalue(Node*, char*);
-static void checkassign(Node*);
-static void checkassignlist(NodeList*);
-static void stringtoarraylit(Node**);
-static Node* resolve(Node*);
-static Type* getforwtype(Node*);
-
-static NodeList* typecheckdefstack;
-
-/*
- * resolve ONONAME to definition, if any.
- */
-Node*
-resolve(Node *n)
-{
- Node *r;
-
- if(n != N && n->op == ONONAME && (r = n->sym->def) != N) {
- if(r->op != OIOTA)
- n = r;
- else if(n->iota >= 0)
- n = nodintconst(n->iota);
- }
- return n;
-}
-
-void
-typechecklist(NodeList *l, int top)
-{
- for(; l; l=l->next)
- typecheck(&l->n, top);
-}
-
-static char* _typekind[] = {
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TBOOL] = "bool",
- [TSTRING] = "string",
- [TPTR32] = "pointer",
- [TPTR64] = "pointer",
- [TSTRUCT] = "struct",
- [TINTER] = "interface",
- [TCHAN] = "chan",
- [TMAP] = "map",
- [TARRAY] = "array",
- [TFUNC] = "func",
- [TNIL] = "nil",
- [TIDEAL] = "ideal number",
-};
-
-static char*
-typekind(int et)
-{
- static char buf[50];
- char *s;
-
- if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
- return s;
- snprint(buf, sizeof buf, "etype=%d", et);
- return buf;
-}
-
-/*
- * type check node *np.
- * replaces *np with a new pointer in some cases.
- * returns the final value of *np as a convenience.
- */
-Node*
-typecheck(Node **np, int top)
-{
- int et, aop, op, ptr;
- Node *n, *l, *r;
- NodeList *args;
- int lno, ok, ntop;
- Type *t, *tp, *ft, *missing, *have;
- Sym *sym;
- Val v;
- char *why;
-
- // cannot type check until all the source has been parsed
- if(!typecheckok)
- fatal("early typecheck");
-
- n = *np;
- if(n == N)
- return N;
-
- // Resolve definition of name and value of iota lazily.
- n = resolve(n);
- *np = n;
-
- // Skip typecheck if already done.
- // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
- if(n->typecheck == 1) {
- switch(n->op) {
- case ONAME:
- case OTYPE:
- case OLITERAL:
- case OPACK:
- break;
- default:
- return n;
- }
- }
-
- if(n->typecheck == 2) {
- yyerror("typechecking loop");
- return n;
- }
- n->typecheck = 2;
-
- lno = setlineno(n);
- if(n->sym) {
- if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
- yyerror("use of builtin %S not in function call", n->sym);
- goto error;
- }
-
- // a dance to handle forward-declared recursive pointer types.
- if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
- defertypecopy(n, ft);
-
- typecheckdef(n);
- n->realtype = n->type;
- if(n->op == ONONAME)
- goto error;
- }
- *np = n;
-
-reswitch:
- ok = 0;
- switch(n->op) {
- default:
- // until typecheck is complete, do nothing.
- dump("typecheck", n);
- fatal("typecheck %O", n->op);
-
- /*
- * names
- */
- case OLITERAL:
- ok |= Erv;
- if(n->type == T && n->val.ctype == CTSTR)
- n->type = idealstring;
- goto ret;
-
- case ONONAME:
- ok |= Erv;
- goto ret;
-
- case ONAME:
- if(n->etype != 0) {
- ok |= Ecall;
- goto ret;
- }
- if(!(top & Easgn)) {
- // not a write to the variable
- if(isblank(n)) {
- yyerror("cannot use _ as value");
- goto error;
- }
- n->used = 1;
- }
- ok |= Erv;
- goto ret;
-
- case OPACK:
- yyerror("use of package %S not in selector", n->sym);
- goto error;
-
- case ODDD:
- break;
-
- /*
- * types (OIND is with exprs)
- */
- case OTYPE:
- ok |= Etype;
- if(n->type == T)
- goto error;
- break;
-
- case OTPAREN:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- if(l->type == T)
- goto error;
- n->op = OTYPE;
- n->type = l->type;
- n->left = N;
- break;
-
- case OTARRAY:
- ok |= Etype;
- t = typ(TARRAY);
- l = n->left;
- r = n->right;
- if(l == nil) {
- t->bound = -1; // slice
- } else if(l->op == ODDD) {
- t->bound = -100; // to be filled in
- } else {
- l = typecheck(&n->left, Erv);
- switch(consttype(l)) {
- case CTINT:
- v = l->val;
- break;
- case CTFLT:
- v = toint(l->val);
- break;
- default:
- yyerror("invalid array bound %#N", l);
- goto error;
- }
- t->bound = mpgetfix(v.u.xval);
- if(t->bound < 0) {
- yyerror("array bound must be non-negative");
- goto error;
- } else
- overflow(v, types[TINT]);
- }
- typecheck(&r, Etype);
- if(r->type == T)
- goto error;
- t->type = r->type;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->right = N;
- if(t->bound != -100)
- checkwidth(t);
- break;
-
- case OTMAP:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- r = typecheck(&n->right, Etype);
- if(l->type == T || r->type == T)
- goto error;
- n->op = OTYPE;
- n->type = maptype(l->type, r->type);
- n->left = N;
- n->right = N;
- break;
-
- case OTCHAN:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- if(l->type == T)
- goto error;
- t = typ(TCHAN);
- t->type = l->type;
- t->chan = n->etype;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->etype = 0;
- break;
-
- case OTSTRUCT:
- ok |= Etype;
- n->op = OTYPE;
- n->type = dostruct(n->list, TSTRUCT);
- if(n->type == T)
- goto error;
- n->list = nil;
- break;
-
- case OTINTER:
- ok |= Etype;
- n->op = OTYPE;
- n->type = dostruct(n->list, TINTER);
- if(n->type == T)
- goto error;
- break;
-
- case OTFUNC:
- ok |= Etype;
- n->op = OTYPE;
- n->type = functype(n->left, n->list, n->rlist);
- if(n->type == T)
- goto error;
- break;
-
- /*
- * type or expr
- */
- case OIND:
- ntop = Erv | Etype;
- if(!(top & Eaddr))
- ntop |= Eindir;
- l = typecheck(&n->left, ntop);
- if((t = l->type) == T)
- goto error;
- if(l->op == OTYPE) {
- ok |= Etype;
- n->op = OTYPE;
- n->type = ptrto(l->type);
- n->left = N;
- goto ret;
- }
- if(!isptr[t->etype]) {
- yyerror("invalid indirect of %+N", n->left);
- goto error;
- }
- ok |= Erv;
- n->type = t->type;
- goto ret;
-
- /*
- * arithmetic exprs
- */
- case OASOP:
- ok |= Etop;
- l = typecheck(&n->left, Erv);
- checkassign(n->left);
- r = typecheck(&n->right, Erv);
- if(l->type == T || r->type == T)
- goto error;
- op = n->etype;
- goto arith;
-
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case ORSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case OSUB:
- case OXOR:
- ok |= Erv;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- op = n->op;
- arith:
- if(op == OLSH || op == ORSH)
- goto shift;
- // ideal mixed with non-ideal
- defaultlit2(&l, &r, 0);
- n->left = l;
- n->right = r;
- if(l->type == T || r->type == T)
- goto error;
- t = l->type;
- if(t->etype == TIDEAL)
- t = r->type;
- et = t->etype;
- if(et == TIDEAL)
- et = TINT;
- if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- // comparison is okay as long as one side is
- // assignable to the other. convert so they have
- // the same type. (the only conversion that isn't
- // a no-op is concrete == interface.)
- if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
- l = nod(aop, l, N);
- l->type = r->type;
- l->typecheck = 1;
- n->left = l;
- t = l->type;
- } else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
- r = nod(aop, r, N);
- r->type = l->type;
- r->typecheck = 1;
- n->right = r;
- t = r->type;
- }
- et = t->etype;
- }
- if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- defaultlit2(&l, &r, 1);
- yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type);
- goto error;
- }
- if(!okfor[op][et]) {
- notokfor:
- yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind(et));
- goto error;
- }
- // okfor allows any array == array;
- // restrict to slice == nil and nil == slice.
- if(l->type->etype == TARRAY && !isslice(l->type))
- goto notokfor;
- if(r->type->etype == TARRAY && !isslice(r->type))
- goto notokfor;
- if(isslice(l->type) && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %#N (slice can only be compared to nil)", n);
- goto error;
- }
- t = l->type;
- if(iscmp[n->op]) {
- evconst(n);
- t = types[TBOOL];
- if(n->op != OLITERAL) {
- defaultlit2(&l, &r, 1);
- n->left = l;
- n->right = r;
- }
- }
- if(et == TSTRING) {
- if(iscmp[n->op]) {
- n->etype = n->op;
- n->op = OCMPSTR;
- } else if(n->op == OADD)
- n->op = OADDSTR;
- }
- if(et == TINTER) {
- if(l->op == OLITERAL && l->val.ctype == CTNIL) {
- // swap for back end
- n->left = r;
- n->right = l;
- } else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
- // leave alone for back end
- } else {
- n->etype = n->op;
- n->op = OCMPIFACE;
- }
- }
- n->type = t;
- goto ret;
-
- shift:
- defaultlit(&r, types[TUINT]);
- n->right = r;
- t = r->type;
- if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type);
- goto error;
- }
- t = l->type;
- if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
- goto error;
- }
- // no defaultlit for left
- // the outer context gives the type
- n->type = l->type;
- goto ret;
-
- case OCOM:
- case OMINUS:
- case ONOT:
- case OPLUS:
- ok |= Erv;
- l = typecheck(&n->left, Erv | (top & Eiota));
- if((t = l->type) == T)
- goto error;
- if(!okfor[n->op][t->etype]) {
- yyerror("invalid operation: %#O %T", n->op, t);
- goto error;
- }
- n->type = t;
- goto ret;
-
- /*
- * exprs
- */
- case OADDR:
- ok |= Erv;
- typecheck(&n->left, Erv | Eaddr);
- if(n->left->type == T)
- goto error;
- switch(n->left->op) {
- case OMAPLIT:
- case OSTRUCTLIT:
- case OARRAYLIT:
- break;
- default:
- checklvalue(n->left, "take the address of");
- }
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(!(top & Eindir) && !n->etype)
- addrescapes(n->left);
- n->type = ptrto(t);
- goto ret;
-
- case OCOMPLIT:
- ok |= Erv;
- typecheckcomplit(&n);
- if(n->type == T)
- goto error;
- goto ret;
-
- case OXDOT:
- n = adddot(n);
- n->op = ODOT;
- // fall through
- case ODOT:
- typecheck(&n->left, Erv|Etype);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(n->right->op != ONAME) {
- yyerror("rhs of . must be a name"); // impossible
- goto error;
- }
- sym = n->right->sym;
- if(l->op == OTYPE) {
- if(!looktypedot(n, t, 0)) {
- if(looktypedot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported method %S)", n, n->right->sym);
- else
- yyerror("%#N undefined (type %T has no method %S)", n, t, n->right->sym);
- goto error;
- }
- if(n->type->etype != TFUNC || n->type->thistuple != 1) {
- yyerror("type %T has no method %hS", n->left->type, sym);
- n->type = T;
- goto error;
- }
- n->op = ONAME;
- n->sym = methodsym(sym, l->type, 0);
- n->type = methodfunc(n->type, l->type);
- n->xoffset = 0;
- n->class = PFUNC;
- ok = Erv;
- goto ret;
- }
- tp = t;
- if(isptr[t->etype] && t->type->etype != TINTER) {
- t = t->type;
- if(t == T)
- goto error;
- n->op = ODOTPTR;
- checkwidth(t);
- }
- if(!lookdot(n, t, 0)) {
- if(lookdot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
- else
- yyerror("%#N undefined (type %T has no field or method %S)", n, tp, n->right->sym);
- goto error;
- }
- switch(n->op) {
- case ODOTINTER:
- case ODOTMETH:
- ok |= Ecall;
- break;
- default:
- ok |= Erv;
- break;
- }
- goto ret;
-
- case ODOTTYPE:
- ok |= Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(!isinter(t)) {
- yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t);
- goto error;
- }
- if(n->right != N) {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- n->right = N;
- if(n->type == T)
- goto error;
- }
- if(n->type != T && n->type->etype != TINTER)
- if(!implements(n->type, t, &missing, &have, &ptr)) {
- if(have)
- yyerror("impossible type assertion: %+N cannot have dynamic type %T"
- " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
- l, n->type, missing->sym, have->sym, have->type,
- missing->sym, missing->type);
- else
- yyerror("impossible type assertion: %+N cannot have dynamic type %T"
- " (missing %S method)", l, n->type, missing->sym);
- goto error;
- }
- goto ret;
-
- case OINDEX:
- ok |= Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- implicitstar(&n->left);
- l = n->left;
- typecheck(&n->right, Erv);
- r = n->right;
- if((t = l->type) == T || r->type == T)
- goto error;
- switch(t->etype) {
- default:
- yyerror("invalid operation: %#N (index of type %T)", n, t);
- goto error;
-
- case TARRAY:
- defaultlit(&n->right, T);
- if(n->right->type != T && !isint[n->right->type->etype])
- yyerror("non-integer array index %#N", n->right);
- n->type = t->type;
- break;
-
- case TMAP:
- n->etype = 0;
- defaultlit(&n->right, t->down);
- if(n->right->type != T)
- n->right = assignconv(n->right, t->down, "map index");
- n->type = t->type;
- n->op = OINDEXMAP;
- break;
-
- case TSTRING:
- defaultlit(&n->right, types[TUINT]);
- if(n->right->type != T && !isint[n->right->type->etype])
- yyerror("non-integer string index %#N", n->right);
- n->type = types[TUINT8];
- break;
- }
- goto ret;
-
- case ORECV:
- ok |= Etop | Erv;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (receive from non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Crecv)) {
- yyerror("invalid operation: %#N (receive from send-only type %T)", n, t);
- goto error;
- }
- n->type = t->type;
- goto ret;
-
- case OSEND:
- if(top & Erv) {
- yyerror("send statement %#N used as value; use select for non-blocking send", n);
- goto error;
- }
- ok |= Etop | Erv;
- l = typecheck(&n->left, Erv);
- typecheck(&n->right, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (send to non-chan type %T)", n, t);
- goto error;
- }
- if(!(t->chan & Csend)) {
- yyerror("invalid operation: %#N (send to receive-only type %T)", n, t);
- goto error;
- }
- defaultlit(&n->right, t->type);
- r = n->right;
- if((t = r->type) == T)
- goto error;
- r = assignconv(r, l->type->type, "send");
- // TODO: more aggressive
- n->etype = 0;
- n->type = T;
- goto ret;
-
- case OSLICE:
- ok |= Erv;
- typecheck(&n->left, top);
- typecheck(&n->right->left, Erv);
- typecheck(&n->right->right, Erv);
- defaultlit(&n->left, T);
- defaultlit(&n->right->left, T);
- defaultlit(&n->right->right, T);
- if(isfixedarray(n->left->type)) {
- n->left = nod(OADDR, n->left, N);
- typecheck(&n->left, top);
- }
- if(n->right->left != N) {
- if((t = n->right->left->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->left, t);
- goto error;
- }
- }
- if(n->right->right != N) {
- if((t = n->right->right->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->right, t);
- goto error;
- }
- }
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(istype(t, TSTRING)) {
- n->type = t;
- n->op = OSLICESTR;
- goto ret;
- }
- if(isptr[t->etype] && isfixedarray(t->type)) {
- n->type = typ(TARRAY);
- n->type->type = t->type->type;
- n->type->bound = -1;
- dowidth(n->type);
- n->op = OSLICEARR;
- goto ret;
- }
- if(isslice(t)) {
- n->type = t;
- goto ret;
- }
- yyerror("cannot slice %#N (type %T)", l, t);
- goto error;
-
- /*
- * call and call like
- */
- case OCALL:
- l = n->left;
- if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
- if(n->isddd)
- yyerror("invalid use of ... with builtin %#N", l);
- n = r;
- goto reswitch;
- }
- typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
- l = n->left;
- if(l->op == ONAME && l->etype != 0) {
- if(n->isddd && l->etype != OAPPEND)
- yyerror("invalid use of ... with builtin %#N", l);
- // builtin: OLEN, OCAP, etc.
- n->op = l->etype;
- n->left = n->right;
- n->right = N;
- goto reswitch;
- }
- defaultlit(&n->left, T);
- l = n->left;
- if(l->op == OTYPE) {
- if(n->isddd || l->type->bound == -100)
- yyerror("invalid use of ... in type conversion", l);
- // pick off before type-checking arguments
- ok |= Erv;
- // turn CALL(type, arg) into CONV(arg) w/ type
- n->left = N;
- n->op = OCONV;
- n->type = l->type;
- if(onearg(n, "conversion to %T", l->type) < 0)
- goto error;
- goto doconv;
- }
-
- if(count(n->list) == 1)
- typecheck(&n->list->n, Erv | Efnstruct);
- else
- typechecklist(n->list, Erv);
- if((t = l->type) == T)
- goto error;
- checkwidth(t);
-
- switch(l->op) {
- case ODOTINTER:
- n->op = OCALLINTER;
- break;
-
- case ODOTMETH:
- n->op = OCALLMETH;
- // typecheckaste was used here but there wasn't enough
- // information further down the call chain to know if we
- // were testing a method receiver for unexported fields.
- // It isn't necessary, so just do a sanity check.
- tp = getthisx(t)->type->type;
- if(l->left == N || !eqtype(l->left->type, tp))
- fatal("method receiver");
- break;
-
- default:
- n->op = OCALLFUNC;
- if(t->etype != TFUNC) {
- yyerror("cannot call non-function %#N (type %T)", l, t);
- goto error;
- }
- break;
- }
- typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
- ok |= Etop;
- if(t->outtuple == 0)
- goto ret;
- ok |= Erv;
- if(t->outtuple == 1) {
- t = getoutargx(l->type)->type;
- if(t == T)
- goto error;
- if(t->etype == TFIELD)
- t = t->type;
- n->type = t;
- goto ret;
- }
- // multiple return
- if(!(top & (Efnstruct | Etop))) {
- yyerror("multiple-value %#N() in single-value context", l);
- goto ret;
- }
- n->type = getoutargx(l->type);
- goto ret;
-
- case OCAP:
- case OLEN:
- case OREAL:
- case OIMAG:
- ok |= Erv;
- if(onearg(n, "%#O", n->op) < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- implicitstar(&n->left);
- l = n->left;
- t = l->type;
- if(t == T)
- goto error;
- switch(n->op) {
- case OCAP:
- if(!okforcap[t->etype])
- goto badcall1;
- break;
- case OLEN:
- if(!okforlen[t->etype])
- goto badcall1;
- break;
- case OREAL:
- case OIMAG:
- if(!iscomplex[t->etype])
- goto badcall1;
- if(isconst(l, CTCPLX)){
- if(n->op == OREAL)
- n = nodfltconst(&l->val.u.cval->real);
- else
- n = nodfltconst(&l->val.u.cval->imag);
- }
- n->type = types[cplxsubtype(t->etype)];
- goto ret;
- }
- // might be constant
- switch(t->etype) {
- case TSTRING:
- if(isconst(l, CTSTR)) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], l->val.u.sval->len);
- r->orig = n;
- n = r;
- }
- break;
- case TARRAY:
- if(t->bound >= 0 && l->op == ONAME) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], t->bound);
- r->orig = n;
- n = r;
- }
- break;
- }
- n->type = types[TINT];
- goto ret;
-
- case OCOMPLEX:
- ok |= Erv;
- if(twoarg(n) < 0)
- goto error;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- defaultlit2(&l, &r, 0);
- n->left = l;
- n->right = r;
- if(l->type->etype != r->type->etype) {
- badcmplx:
- yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type);
- goto error;
- }
- switch(l->type->etype) {
- default:
- goto badcmplx;
- case TIDEAL:
- t = types[TIDEAL];
- break;
- case TFLOAT32:
- t = types[TCOMPLEX64];
- break;
- case TFLOAT64:
- t = types[TCOMPLEX128];
- break;
- }
- if(l->op == OLITERAL && r->op == OLITERAL) {
- // make it a complex literal
- n = nodcplxlit(l->val, r->val);
- }
- n->type = t;
- goto ret;
-
- case OCLOSE:
- if(onearg(n, "%#O", n->op) < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
- goto error;
- if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (non-chan type %T)", n, t);
- goto error;
- }
- ok |= Etop;
- goto ret;
-
- case OAPPEND:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing arguments to append");
- goto error;
- }
- typechecklist(args, Erv);
- if((t = args->n->type) == T)
- goto error;
- n->type = t;
- if(!isslice(t)) {
- yyerror("first argument to append must be slice; have %lT", t);
- goto error;
- }
- if(n->isddd) {
- if(args->next == nil) {
- yyerror("cannot use ... on first argument to append");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to append");
- goto error;
- }
- args->next->n = assignconv(args->next->n, t->orig, "append");
- goto ret;
- }
- for(args=args->next; args != nil; args=args->next) {
- if(args->n->type == T)
- continue;
- args->n = assignconv(args->n, t->type, "append");
- }
- goto ret;
-
- case OCOPY:
- ok |= Etop|Erv;
- args = n->list;
- if(args == nil || args->next == nil) {
- yyerror("missing arguments to copy");
- goto error;
- }
- if(args->next->next != nil) {
- yyerror("too many arguments to copy");
- goto error;
- }
- n->left = args->n;
- n->right = args->next->n;
- n->type = types[TINT];
- typecheck(&n->left, Erv);
- typecheck(&n->right, Erv);
- if(n->left->type == T || n->right->type == T)
- goto error;
- defaultlit(&n->left, T);
- defaultlit(&n->right, T);
-
- // copy([]byte, string)
- if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
- if (n->left->type->type == types[TUINT8])
- goto ret;
- yyerror("arguments to copy have different element types: %lT and string", n->left->type);
- goto error;
- }
-
- if(!isslice(n->left->type) || !isslice(n->right->type)) {
- if(!isslice(n->left->type) && !isslice(n->right->type))
- yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
- else if(!isslice(n->left->type))
- yyerror("first argument to copy should be slice; have %lT", n->left->type);
- else
- yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
- goto error;
- }
- if(!eqtype(n->left->type->type, n->right->type->type)) {
- yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
- goto error;
- }
- goto ret;
-
- case OCONV:
- doconv:
- ok |= Erv;
- typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
- convlit1(&n->left, n->type, 1);
- if((t = n->left->type) == T || n->type == T)
- goto error;
- if((n->op = convertop(t, n->type, &why)) == 0) {
- yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
- op = OCONV;
- }
- switch(n->op) {
- case OCONVNOP:
- if(n->left->op == OLITERAL) {
- n->op = OLITERAL;
- n->val = n->left->val;
- }
- break;
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- if(n->left->op == OLITERAL)
- stringtoarraylit(&n);
- break;
- }
- goto ret;
-
- case OMAKE:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing argument to make");
- goto error;
- }
- l = args->n;
- args = args->next;
- typecheck(&l, Etype);
- if((t = l->type) == T)
- goto error;
-
- switch(t->etype) {
- default:
- badmake:
- yyerror("cannot make type %T", t);
- goto error;
-
- case TARRAY:
- if(!isslice(t))
- goto badmake;
- if(args == nil) {
- yyerror("missing len argument to make(%T)", t);
- goto error;
- }
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- r = N;
- if(args != nil) {
- r = args->n;
- args = args->next;
- typecheck(&r, Erv);
- defaultlit(&r, types[TINT]);
- }
- if(l->type == T || (r && r->type == T))
- goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer len argument to make(%T)", t);
- goto error;
- }
- if(r && !isint[r->type->etype]) {
- yyerror("non-integer cap argument to make(%T)", t);
- goto error;
- }
- n->left = l;
- n->right = r;
- n->op = OMAKESLICE;
- break;
-
- case TMAP:
- if(args != nil) {
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- if(l->type == T)
- goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer size argument to make(%T)", t);
- goto error;
- }
- n->left = l;
- } else
- n->left = nodintconst(0);
- n->op = OMAKEMAP;
- break;
-
- case TCHAN:
- l = N;
- if(args != nil) {
- l = args->n;
- args = args->next;
- typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
- if(l->type == T)
- goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer buffer argument to make(%T)", t);
- goto error;
- }
- n->left = l;
- } else
- n->left = nodintconst(0);
- n->op = OMAKECHAN;
- break;
- }
- if(args != nil) {
- yyerror("too many arguments to make(%T)", t);
- n->op = OMAKE;
- goto error;
- }
- n->type = t;
- goto ret;
-
- case ONEW:
- ok |= Erv;
- args = n->list;
- if(args == nil) {
- yyerror("missing argument to new");
- goto error;
- }
- l = args->n;
- typecheck(&l, Etype);
- if((t = l->type) == T)
- goto error;
- if(args->next != nil) {
- yyerror("too many arguments to new(%T)", t);
- goto error;
- }
- n->left = l;
- n->type = ptrto(t);
- goto ret;
-
- case OPRINT:
- case OPRINTN:
- ok |= Etop;
- typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
- goto ret;
-
- case OPANIC:
- ok |= Etop;
- if(onearg(n, "panic") < 0)
- goto error;
- typecheck(&n->left, Erv);
- defaultlit(&n->left, types[TINTER]);
- if(n->left->type == T)
- goto error;
- goto ret;
-
- case ORECOVER:
- ok |= Erv|Etop;
- if(n->list != nil) {
- yyerror("too many arguments to recover");
- goto error;
- }
- n->type = types[TINTER];
- goto ret;
-
- case OCLOSURE:
- ok |= Erv;
- typecheckclosure(n, top);
- if(n->type == T)
- goto error;
- goto ret;
-
- /*
- * statements
- */
- case OAS:
- ok |= Etop;
- typecheckas(n);
- goto ret;
-
- case OAS2:
- ok |= Etop;
- typecheckas2(n);
- goto ret;
-
- case OBREAK:
- case OCONTINUE:
- case ODCL:
- case OEMPTY:
- case OGOTO:
- case OLABEL:
- case OXFALL:
- ok |= Etop;
- goto ret;
-
- case ODEFER:
- ok |= Etop;
- typecheck(&n->left, Etop);
- goto ret;
-
- case OPROC:
- ok |= Etop;
- typecheck(&n->left, Etop|Eproc);
- goto ret;
-
- case OFOR:
- ok |= Etop;
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %+N used as for condition", n->ntest);
- typecheck(&n->nincr, Etop);
- typechecklist(n->nbody, Etop);
- goto ret;
-
- case OIF:
- ok |= Etop;
- typechecklist(n->ninit, Etop);
- typecheck(&n->ntest, Erv);
- if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %+N used as if condition", n->ntest);
- typechecklist(n->nbody, Etop);
- typechecklist(n->nelse, Etop);
- goto ret;
-
- case ORETURN:
- ok |= Etop;
- typechecklist(n->list, Erv | Efnstruct);
- if(curfn == N) {
- yyerror("return outside function");
- goto error;
- }
- if(curfn->type->outnamed && n->list == nil)
- goto ret;
- typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
- goto ret;
-
- case OSELECT:
- ok |= Etop;
- typecheckselect(n);
- goto ret;
-
- case OSWITCH:
- ok |= Etop;
- typecheckswitch(n);
- goto ret;
-
- case ORANGE:
- ok |= Etop;
- typecheckrange(n);
- goto ret;
-
- case OTYPESW:
- yyerror("use of .(type) outside type switch");
- goto error;
-
- case OXCASE:
- ok |= Etop;
- typechecklist(n->list, Erv);
- typechecklist(n->nbody, Etop);
- goto ret;
-
- case ODCLFUNC:
- ok |= Etop;
- typecheckfunc(n);
- goto ret;
-
- case ODCLCONST:
- ok |= Etop;
- typecheck(&n->left, Erv);
- goto ret;
-
- case ODCLTYPE:
- ok |= Etop;
- typecheck(&n->left, Etype);
- if(!incannedimport)
- checkwidth(n->left->type);
- goto ret;
- }
-
-ret:
- t = n->type;
- if(t && !t->funarg && n->op != OTYPE) {
- switch(t->etype) {
- case TFUNC: // might have TANY; wait until its called
- case TANY:
- case TFORW:
- case TIDEAL:
- case TNIL:
- case TBLANK:
- break;
- case TARRAY:
- if(t->bound == -100) {
- yyerror("use of [...] array outside of array literal");
- t->bound = 1;
- }
- default:
- checkwidth(t);
- }
- }
-
- // TODO(rsc): should not need to check importpkg,
- // but reflect mentions unsafe.Pointer.
- if(safemode && !incannedimport && !importpkg && t && t->etype == TUNSAFEPTR)
- yyerror("cannot use unsafe.Pointer");
-
- evconst(n);
- if(n->op == OTYPE && !(top & Etype)) {
- yyerror("type %T is not an expression", n->type);
- goto error;
- }
- if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
- yyerror("%#N is not a type", n);
- goto error;
- }
- if((ok & Ecall) && !(top & Ecall)) {
- yyerror("method %#N is not an expression, must be called", n);
- goto error;
- }
- // TODO(rsc): simplify
- if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
- yyerror("%#N used as value", n);
- goto error;
- }
- if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
- if(n->diag == 0) {
- yyerror("%#N not used", n);
- n->diag = 1;
- }
- goto error;
- }
-
- /* TODO
- if(n->type == T)
- fatal("typecheck nil type");
- */
- goto out;
-
-badcall1:
- yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op);
- goto error;
-
-error:
- n->type = T;
-
-out:
- lineno = lno;
- n->typecheck = 1;
- *np = n;
- return n;
-}
-
-static void
-implicitstar(Node **nn)
-{
- Type *t;
- Node *n;
-
- // insert implicit * if needed for fixed array
- n = *nn;
- t = n->type;
- if(t == T || !isptr[t->etype])
- return;
- t = t->type;
- if(t == T)
- return;
- if(!isfixedarray(t))
- return;
- n = nod(OIND, n, N);
- typecheck(&n, Erv);
- *nn = n;
-}
-
-static int
-onearg(Node *n, char *f, ...)
-{
- va_list arg;
- char *p;
-
- if(n->left != N)
- return 0;
- if(n->list == nil) {
- va_start(arg, f);
- p = vsmprint(f, arg);
- va_end(arg);
- yyerror("missing argument to %s: %#N", p, n);
- return -1;
- }
- if(n->list->next != nil) {
- va_start(arg, f);
- p = vsmprint(f, arg);
- va_end(arg);
- yyerror("too many arguments to %s: %#N", p, n);
- n->left = n->list->n;
- n->list = nil;
- return -1;
- }
- n->left = n->list->n;
- n->list = nil;
- return 0;
-}
-
-static int
-twoarg(Node *n)
-{
- if(n->left != N)
- return 0;
- if(n->list == nil) {
- yyerror("missing argument to %#O - %#N", n->op, n);
- return -1;
- }
- n->left = n->list->n;
- if(n->list->next == nil) {
- yyerror("missing argument to %#O - %#N", n->op, n);
- n->list = nil;
- return -1;
- }
- if(n->list->next->next != nil) {
- yyerror("too many arguments to %#O - %#N", n->op, n);
- n->list = nil;
- return -1;
- }
- n->right = n->list->next->n;
- n->list = nil;
- return 0;
-}
-
-static Type*
-lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
-{
- Type *r;
-
- r = T;
- for(; f!=T; f=f->down) {
- if(dostrcmp && strcmp(f->sym->name, s->name) == 0)
- return f;
- if(f->sym != s)
- continue;
- if(r != T) {
- yyerror("ambiguous DOT reference %T.%S", t, s);
- break;
- }
- r = f;
- }
- return r;
-}
-
-static int
-looktypedot(Node *n, Type *t, int dostrcmp)
-{
- Type *f1, *f2, *tt;
- Sym *s;
-
- s = n->right->sym;
-
- if(t->etype == TINTER) {
- f1 = lookdot1(s, t, t->type, dostrcmp);
- if(f1 == T)
- return 0;
-
- if(f1->width == BADWIDTH)
- fatal("lookdot badwidth %T %p", f1, f1);
- n->right = methodname(n->right, t);
- n->xoffset = f1->width;
- n->type = f1->type;
- n->op = ODOTINTER;
- return 1;
- }
-
- tt = t;
- if(t->sym == S && isptr[t->etype])
- tt = t->type;
-
- f2 = methtype(tt);
- if(f2 == T)
- return 0;
-
- expandmeth(f2->sym, f2);
- f2 = lookdot1(s, f2, f2->xmethod, dostrcmp);
- if(f2 == T)
- return 0;
-
- // disallow T.m if m requires *T receiver
- if(isptr[getthisx(f2->type)->type->type->etype]
- && !isptr[t->etype]
- && f2->embedded != 2
- && !isifacemethod(f2->type)) {
- yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name);
- return 0;
- }
-
- n->right = methodname(n->right, t);
- n->xoffset = f2->width;
- n->type = f2->type;
- n->op = ODOTMETH;
- return 1;
-}
-
-static int
-lookdot(Node *n, Type *t, int dostrcmp)
-{
- Type *f1, *f2, *tt, *rcvr;
- Sym *s;
-
- s = n->right->sym;
-
- dowidth(t);
- f1 = T;
- if(t->etype == TSTRUCT || t->etype == TINTER)
- f1 = lookdot1(s, t, t->type, dostrcmp);
-
- f2 = T;
- if(n->left->type == t || n->left->type->sym == S) {
- f2 = methtype(t);
- if(f2 != T) {
- // Use f2->method, not f2->xmethod: adddot has
- // already inserted all the necessary embedded dots.
- f2 = lookdot1(s, f2, f2->method, dostrcmp);
- }
- }
-
- if(f1 != T) {
- if(f2 != T)
- yyerror("ambiguous DOT reference %S as both field and method",
- n->right->sym);
- if(f1->width == BADWIDTH)
- fatal("lookdot badwidth %T %p", f1, f1);
- n->xoffset = f1->width;
- n->type = f1->type;
- if(t->etype == TINTER) {
- if(isptr[n->left->type->etype]) {
- n->left = nod(OIND, n->left, N); // implicitstar
- typecheck(&n->left, Erv);
- }
- n->op = ODOTINTER;
- }
- return 1;
- }
-
- if(f2 != T) {
- tt = n->left->type;
- dowidth(tt);
- rcvr = getthisx(f2->type)->type->type;
- if(!eqtype(rcvr, tt)) {
- if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
- checklvalue(n->left, "call pointer method on");
- addrescapes(n->left);
- n->left = nod(OADDR, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
- n->left = nod(OIND, n->left, N);
- n->left->implicit = 1;
- typecheck(&n->left, Etype|Erv);
- } else {
- // method is attached to wrong type?
- fatal("method mismatch: %T for %T", rcvr, tt);
- }
- }
- n->right = methodname(n->right, n->left->type);
- n->xoffset = f2->width;
- n->type = f2->type;
- n->op = ODOTMETH;
- return 1;
- }
-
- return 0;
-}
-
-static int
-nokeys(NodeList *l)
-{
- for(; l; l=l->next)
- if(l->n->op == OKEY)
- return 0;
- return 1;
-}
-
-/*
- * typecheck assignment: type list = expression list
- */
-static void
-typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
-{
- Type *t, *tl, *tn;
- Node *n;
- int lno;
- char *why;
-
- lno = lineno;
-
- if(tstruct->broke)
- goto out;
-
- if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
- if(n->type->etype == TSTRUCT && n->type->funarg) {
- tn = n->type->type;
- for(tl=tstruct->type; tl; tl=tl->down) {
- if(tl->isddd) {
- for(; tn; tn=tn->down) {
- exportassignok(tn->type, desc);
- if(assignop(tn->type, tl->type->type, &why) == 0) {
- if(call != N)
- yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, call, why);
- else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
- }
- }
- goto out;
- }
- if(tn == T)
- goto notenough;
- exportassignok(tn->type, desc);
- if(assignop(tn->type, tl->type, &why) == 0) {
- if(call != N)
- yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, call, why);
- else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
- }
- tn = tn->down;
- }
- if(tn != T)
- goto toomany;
- goto out;
- }
-
- for(tl=tstruct->type; tl; tl=tl->down) {
- t = tl->type;
- if(tl->isddd) {
- if(isddd) {
- if(nl == nil)
- goto notenough;
- if(nl->next != nil)
- goto toomany;
- n = nl->n;
- setlineno(n);
- if(n->type != T)
- nl->n = assignconv(n, t, desc);
- goto out;
- }
- for(; nl; nl=nl->next) {
- n = nl->n;
- setlineno(nl->n);
- if(n->type != T)
- nl->n = assignconv(n, t->type, desc);
- }
- goto out;
- }
- if(nl == nil)
- goto notenough;
- n = nl->n;
- setlineno(n);
- if(n->type != T)
- nl->n = assignconv(n, t, desc);
- nl = nl->next;
- }
- if(nl != nil)
- goto toomany;
- if(isddd) {
- if(call != N)
- yyerror("invalid use of ... in call to %#N", call);
- else
- yyerror("invalid use of ... in %#O", op);
- }
-
-out:
- lineno = lno;
- return;
-
-notenough:
- if(call != N)
- yyerror("not enough arguments in call to %#N", call);
- else
- yyerror("not enough arguments to %#O", op);
- goto out;
-
-toomany:
- if(call != N)
- yyerror("too many arguments in call to %#N", call);
- else
- yyerror("too many arguments to %#O", op);
- goto out;
-}
-
-/*
- * do the export rules allow writing to this type?
- * cannot be implicitly assigning to any type with
- * an unavailable field.
- */
-int
-exportassignok(Type *t, char *desc)
-{
- Type *f;
- Sym *s;
-
- if(t == T)
- return 1;
- if(t->trecur)
- return 1;
- t->trecur = 1;
-
- switch(t->etype) {
- default:
- // most types can't contain others; they're all fine.
- break;
- case TSTRUCT:
- for(f=t->type; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("structas: not field");
- s = f->sym;
- // s == nil doesn't happen for embedded fields (they get the type symbol).
- // it only happens for fields in a ... struct.
- if(s != nil && !exportname(s->name) && s->pkg != localpkg) {
- char *prefix;
-
- prefix = "";
- if(desc != nil)
- prefix = " in ";
- else
- desc = "";
- yyerror("implicit assignment of unexported field '%s' of %T%s%s", s->name, t, prefix, desc);
- goto no;
- }
- if(!exportassignok(f->type, desc))
- goto no;
- }
- break;
-
- case TARRAY:
- if(t->bound < 0) // slices are pointers; that's fine
- break;
- if(!exportassignok(t->type, desc))
- goto no;
- break;
- }
- t->trecur = 0;
- return 1;
-
-no:
- t->trecur = 0;
- return 0;
-}
-
-
-/*
- * type check composite
- */
-
-static void
-fielddup(Node *n, Node *hash[], ulong nhash)
-{
- uint h;
- char *s;
- Node *a;
-
- if(n->op != ONAME)
- fatal("fielddup: not ONAME");
- s = n->sym->name;
- h = stringhash(s)%nhash;
- for(a=hash[h]; a!=N; a=a->ntest) {
- if(strcmp(a->sym->name, s) == 0) {
- yyerror("duplicate field name in struct literal: %s", s);
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static void
-keydup(Node *n, Node *hash[], ulong nhash)
-{
- uint h;
- ulong b;
- double d;
- int i;
- Node *a;
- Node cmp;
- char *s;
-
- evconst(n);
- if(n->op != OLITERAL)
- return; // we dont check variables
-
- switch(n->val.ctype) {
- default: // unknown, bool, nil
- b = 23;
- break;
- case CTINT:
- b = mpgetfix(n->val.u.xval);
- break;
- case CTFLT:
- d = mpgetflt(n->val.u.fval);
- s = (char*)&d;
- b = 0;
- for(i=sizeof(d); i>0; i--)
- b = b*PRIME1 + *s++;
- break;
- case CTSTR:
- b = 0;
- s = n->val.u.sval->s;
- for(i=n->val.u.sval->len; i>0; i--)
- b = b*PRIME1 + *s++;
- break;
- }
-
- h = b%nhash;
- memset(&cmp, 0, sizeof(cmp));
- for(a=hash[h]; a!=N; a=a->ntest) {
- cmp.op = OEQ;
- cmp.left = n;
- cmp.right = a;
- evconst(&cmp);
- b = cmp.val.u.bval;
- if(b) {
- // too lazy to print the literal
- yyerror("duplicate key in map literal");
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static void
-indexdup(Node *n, Node *hash[], ulong nhash)
-{
- uint h;
- Node *a;
- ulong b, c;
-
- if(n->op != OLITERAL)
- fatal("indexdup: not OLITERAL");
-
- b = mpgetfix(n->val.u.xval);
- h = b%nhash;
- for(a=hash[h]; a!=N; a=a->ntest) {
- c = mpgetfix(a->val.u.xval);
- if(b == c) {
- yyerror("duplicate index in array literal: %ld", b);
- return;
- }
- }
- n->ntest = hash[h];
- hash[h] = n;
-}
-
-static int
-prime(ulong h, ulong sr)
-{
- ulong n;
-
- for(n=3; n<=sr; n+=2)
- if(h%n == 0)
- return 0;
- return 1;
-}
-
-static ulong
-inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
-{
- ulong h, sr;
- NodeList *ll;
- int i;
-
- // count the number of entries
- h = 0;
- for(ll=n->list; ll; ll=ll->next)
- h++;
-
- // if the auto hash table is
- // large enough use it.
- if(h <= nautohash) {
- *hash = autohash;
- memset(*hash, 0, nautohash * sizeof(**hash));
- return nautohash;
- }
-
- // make hash size odd and 12% larger than entries
- h += h/8;
- h |= 1;
-
- // calculate sqrt of h
- sr = h/2;
- for(i=0; i<5; i++)
- sr = (sr + h/sr)/2;
-
- // check for primeality
- while(!prime(h, sr))
- h += 2;
-
- // build and return a throw-away hash table
- *hash = mal(h * sizeof(**hash));
- memset(*hash, 0, h * sizeof(**hash));
- return h;
-}
-
-static void
-typecheckcomplit(Node **np)
-{
- int bad, i, len, nerr;
- Node *l, *n, **hash;
- NodeList *ll;
- Type *t, *f, *pushtype;
- Sym *s;
- int32 lno;
- ulong nhash;
- Node *autohash[101];
-
- n = *np;
- lno = lineno;
-
- if(n->right == N) {
- if(n->list != nil)
- setlineno(n->list->n);
- yyerror("missing type in composite literal");
- goto error;
- }
-
- setlineno(n->right);
- l = typecheck(&n->right /* sic */, Etype);
- if((t = l->type) == T)
- goto error;
- nerr = nerrors;
-
- // can omit type on composite literal values if the outer
- // composite literal is array, slice, or map, and the
- // element type is itself a struct, array, slice, or map.
- pushtype = T;
- if(t->etype == TARRAY || t->etype == TMAP) {
- pushtype = t->type;
- if(pushtype != T) {
- switch(pushtype->etype) {
- case TSTRUCT:
- case TARRAY:
- case TMAP:
- break;
- default:
- pushtype = T;
- break;
- }
- }
- }
-
- switch(t->etype) {
- default:
- yyerror("invalid type for composite literal: %T", t);
- n->type = T;
- break;
-
- case TARRAY:
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- len = 0;
- i = 0;
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- l = nod(OKEY, nodintconst(i), l);
- l->left->type = types[TINT];
- l->left->typecheck = 1;
- ll->n = l;
- }
-
- typecheck(&l->left, Erv);
- evconst(l->left);
- i = nonnegconst(l->left);
- if(i < 0) {
- yyerror("array index must be non-negative integer constant");
- i = -(1<<30); // stay negative for a while
- }
- if(i >= 0)
- indexdup(l->left, hash, nhash);
- i++;
- if(i > len) {
- len = i;
- if(t->bound >= 0 && len > t->bound) {
- setlineno(l);
- yyerror("array index %d out of bounds [0:%d]", len, t->bound);
- t->bound = -1; // no more errors
- }
- }
-
- if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
- l->right->right = typenod(pushtype);
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "array index");
- }
- if(t->bound == -100)
- t->bound = len;
- if(t->bound < 0)
- n->right = nodintconst(len);
- n->op = OARRAYLIT;
- break;
-
- case TMAP:
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- typecheck(&ll->n, Erv);
- yyerror("missing key in map literal");
- continue;
- }
-
- typecheck(&l->left, Erv);
- defaultlit(&l->left, t->down);
- l->left = assignconv(l->left, t->down, "map key");
- keydup(l->left, hash, nhash);
-
- if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
- l->right->right = typenod(pushtype);
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "map value");
- }
- n->op = OMAPLIT;
- break;
-
- case TSTRUCT:
- bad = 0;
- if(n->list != nil && nokeys(n->list)) {
- // simple list of variables
- f = t->type;
- for(ll=n->list; ll; ll=ll->next) {
- setlineno(ll->n);
- typecheck(&ll->n, Erv);
- if(f == nil) {
- if(!bad++)
- yyerror("too many values in struct initializer");
- continue;
- }
- s = f->sym;
- if(s != nil && !exportname(s->name) && s->pkg != localpkg)
- yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
- ll->n = assignconv(ll->n, f->type, "field value");
- ll->n = nod(OKEY, newname(f->sym), ll->n);
- ll->n->left->typecheck = 1;
- f = f->down;
- }
- if(f != nil)
- yyerror("too few values in struct initializer");
- } else {
- nhash = inithash(n, &hash, autohash, nelem(autohash));
-
- // keyed list
- for(ll=n->list; ll; ll=ll->next) {
- l = ll->n;
- setlineno(l);
- if(l->op != OKEY) {
- if(!bad++)
- yyerror("mixture of field:value and value initializers");
- typecheck(&ll->n, Erv);
- continue;
- }
- s = l->left->sym;
- if(s == S) {
- yyerror("invalid field name %#N in struct initializer", l->left);
- typecheck(&l->right, Erv);
- continue;
- }
- // Sym might have resolved to name in other top-level
- // package, because of import dot. Redirect to correct sym
- // before we do the lookup.
- if(s->pkg != localpkg)
- s = lookup(s->name);
- l->left = newname(s);
- l->left->typecheck = 1;
- f = lookdot1(s, t, t->type, 0);
- typecheck(&l->right, Erv);
- if(f == nil) {
- yyerror("unknown %T field '%s' in struct literal", t, s->name);
- continue;
- }
- s = f->sym;
- fielddup(newname(s), hash, nhash);
- l->right = assignconv(l->right, f->type, "field value");
- }
- }
- n->op = OSTRUCTLIT;
- break;
- }
- if(nerr != nerrors)
- goto error;
- n->type = t;
-
- *np = n;
- lineno = lno;
- return;
-
-error:
- n->type = T;
- *np = n;
- lineno = lno;
-}
-
-/*
- * the address of n has been taken and might be used after
- * the current function returns. mark any local vars
- * as needing to move to the heap.
- */
-static void
-addrescapes(Node *n)
-{
- char buf[100];
- switch(n->op) {
- default:
- // probably a type error already.
- // dump("addrescapes", n);
- break;
-
- case ONAME:
- if(n->noescape)
- break;
- switch(n->class) {
- case PPARAMREF:
- addrescapes(n->defn);
- break;
- case PPARAM:
- case PPARAMOUT:
- // if func param, need separate temporary
- // to hold heap pointer.
- // the function type has already been checked
- // (we're in the function body)
- // so the param already has a valid xoffset.
-
- // expression to refer to stack copy
- n->stackparam = nod(OPARAM, n, N);
- n->stackparam->type = n->type;
- n->stackparam->addable = 1;
- if(n->xoffset == BADWIDTH)
- fatal("addrescapes before param assignment");
- n->stackparam->xoffset = n->xoffset;
- n->xoffset = 0;
- // fallthrough
- case PAUTO:
-
- n->class |= PHEAP;
- n->addable = 0;
- n->ullman = 2;
- n->xoffset = 0;
-
- // create stack variable to hold pointer to heap
- n->heapaddr = nod(ONAME, N, N);
- n->heapaddr->type = ptrto(n->type);
- snprint(buf, sizeof buf, "&%S", n->sym);
- n->heapaddr->sym = lookup(buf);
- n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
- n->heapaddr->ullman = 1;
- n->curfn->dcl = list(n->curfn->dcl, n->heapaddr);
-
- break;
- }
- break;
-
- case OIND:
- case ODOTPTR:
- break;
-
- case ODOT:
- case OINDEX:
- // ODOTPTR has already been introduced,
- // so these are the non-pointer ODOT and OINDEX.
- // In &x[0], if x is a slice, then x does not
- // escape--the pointer inside x does, but that
- // is always a heap pointer anyway.
- if(!isslice(n->left->type))
- addrescapes(n->left);
- break;
- }
-}
-
-/*
- * lvalue etc
- */
-int
-islvalue(Node *n)
-{
- switch(n->op) {
- case OINDEX:
- if(isfixedarray(n->left->type))
- return islvalue(n->left);
- if(n->left->type != T && n->left->type->etype == TSTRING)
- return 0;
- // fall through
- case OIND:
- case ODOTPTR:
- return 1;
- case ODOT:
- return islvalue(n->left);
- case ONAME:
- if(n->class == PFUNC)
- return 0;
- return 1;
- }
- return 0;
-}
-
-static void
-checklvalue(Node *n, char *verb)
-{
- if(!islvalue(n))
- yyerror("cannot %s %#N", verb, n);
-}
-
-static void
-checkassign(Node *n)
-{
- if(islvalue(n))
- return;
- if(n->op == OINDEXMAP) {
- n->etype = 1;
- return;
- }
- yyerror("cannot assign to %#N", n);
-}
-
-static void
-checkassignlist(NodeList *l)
-{
- for(; l; l=l->next)
- checkassign(l->n);
-}
-
-/*
- * type check assignment.
- * if this assignment is the definition of a var on the left side,
- * fill in the var's type.
- */
-
-static void
-typecheckas(Node *n)
-{
- // delicate little dance.
- // the definition of n may refer to this assignment
- // as its definition, in which case it will call typecheckas.
- // in that case, do not call typecheck back, or it will cycle.
- // if the variable has a type (ntype) then typechecking
- // will not look at defn, so it is okay (and desirable,
- // so that the conversion below happens).
- n->left = resolve(n->left);
- if(n->left->defn != n || n->left->ntype)
- typecheck(&n->left, Erv | Easgn);
-
- checkassign(n->left);
- typecheck(&n->right, Erv);
- if(n->right && n->right->type != T) {
- if(n->left->type != T)
- n->right = assignconv(n->right, n->left->type, "assignment");
- else if(!isblank(n->left))
- exportassignok(n->right->type, "assignment");
- }
- if(n->left->defn == n && n->left->ntype == N) {
- defaultlit(&n->right, T);
- n->left->type = n->right->type;
- }
-
- // second half of dance.
- // now that right is done, typecheck the left
- // just to get it over with. see dance above.
- n->typecheck = 1;
- if(n->left->typecheck == 0)
- typecheck(&n->left, Erv | Easgn);
-}
-
-static void
-checkassignto(Type *src, Node *dst)
-{
- char *why;
-
- if(assignop(src, dst->type, &why) == 0) {
- yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why);
- return;
- }
- exportassignok(dst->type, "multiple assignment");
-}
-
-static void
-typecheckas2(Node *n)
-{
- int cl, cr;
- NodeList *ll, *lr;
- Node *l, *r;
- Iter s;
- Type *t;
-
- for(ll=n->list; ll; ll=ll->next) {
- // delicate little dance.
- ll->n = resolve(ll->n);
- if(ll->n->defn != n || ll->n->ntype)
- typecheck(&ll->n, Erv | Easgn);
- }
- cl = count(n->list);
- cr = count(n->rlist);
- checkassignlist(n->list);
- if(cl > 1 && cr == 1)
- typecheck(&n->rlist->n, Erv | Efnstruct);
- else
- typechecklist(n->rlist, Erv);
-
- if(cl == cr) {
- // easy
- for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
- if(ll->n->type != T && lr->n->type != T)
- lr->n = assignconv(lr->n, ll->n->type, "assignment");
- if(ll->n->defn == n && ll->n->ntype == N) {
- defaultlit(&lr->n, T);
- ll->n->type = lr->n->type;
- }
- }
- goto out;
- }
-
-
- l = n->list->n;
- r = n->rlist->n;
-
- // m[i] = x, ok
- if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
- if(l->type == T)
- goto out;
- n->op = OAS2MAPW;
- n->rlist->n = assignconv(r, l->type, "assignment");
- r = n->rlist->next->n;
- n->rlist->next->n = assignconv(r, types[TBOOL], "assignment");
- goto out;
- }
-
- // x,y,z = f()
- if(cr == 1) {
- if(r->type == T)
- goto out;
- switch(r->op) {
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- if(r->type->etype != TSTRUCT || r->type->funarg == 0)
- break;
- cr = structcount(r->type);
- if(cr != cl)
- goto mismatch;
- n->op = OAS2FUNC;
- t = structfirst(&s, &r->type);
- for(ll=n->list; ll; ll=ll->next) {
- if(ll->n->type != T)
- checkassignto(t->type, ll->n);
- if(ll->n->defn == n && ll->n->ntype == N)
- ll->n->type = t->type;
- t = structnext(&s);
- }
- goto out;
- }
- }
-
- // x, ok = y
- if(cl == 2 && cr == 1) {
- if(r->type == T)
- goto out;
- switch(r->op) {
- case OINDEXMAP:
- n->op = OAS2MAPR;
- goto common;
- case ORECV:
- n->op = OAS2RECV;
- n->right = n->rlist->n;
- goto common;
- case ODOTTYPE:
- n->op = OAS2DOTTYPE;
- r->op = ODOTTYPE2;
- common:
- if(l->type != T)
- checkassignto(r->type, l);
- if(l->defn == n)
- l->type = r->type;
- l = n->list->next->n;
- if(l->type != T)
- checkassignto(types[TBOOL], l);
- if(l->defn == n && l->ntype == N)
- l->type = types[TBOOL];
- goto out;
- }
- }
-
-mismatch:
- yyerror("assignment count mismatch: %d = %d", cl, cr);
-
-out:
- // second half of dance
- n->typecheck = 1;
- for(ll=n->list; ll; ll=ll->next)
- if(ll->n->typecheck == 0)
- typecheck(&ll->n, Erv | Easgn);
-}
-
-/*
- * type check function definition
- */
-static void
-typecheckfunc(Node *n)
-{
- Type *t, *rcvr;
-
-//dump("nname", n->nname);
- typecheck(&n->nname, Erv | Easgn);
- if((t = n->nname->type) == T)
- return;
- n->type = t;
-
- rcvr = getthisx(t)->type;
- if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
- 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;
-}
-
-static Type*
-getforwtype(Node *n)
-{
- Node *f1, *f2;
-
- for(f1=f2=n; ; n=n->ntype) {
- if((n = resolve(n)) == N || n->op != OTYPE)
- return T;
-
- if(n->type != T && n->type->etype == TFORW)
- return n->type;
-
- // Check for ntype cycle.
- if((f2 = resolve(f2)) != N && (f1 = resolve(f2->ntype)) != N) {
- f2 = resolve(f1->ntype);
- if(f1 == n || f2 == n)
- return T;
- }
- }
-}
-
-static int ntypecheckdeftype;
-static NodeList *methodqueue;
-
-static void
-domethod(Node *n)
-{
- Node *nt;
-
- nt = n->type->nname;
- typecheck(&nt, Etype);
- if(nt->type == T) {
- // type check failed; leave empty func
- n->type->etype = TFUNC;
- n->type->nod = N;
- return;
- }
- *n->type = *nt->type;
- n->type->nod = N;
- checkwidth(n->type);
-}
-
-typedef struct NodeTypeList NodeTypeList;
-struct NodeTypeList {
- Node *n;
- Type *t;
- NodeTypeList *next;
-};
-
-static NodeTypeList *dntq;
-static NodeTypeList *dntend;
-
-void
-defertypecopy(Node *n, Type *t)
-{
- NodeTypeList *ntl;
-
- if(n == N || t == T)
- return;
-
- ntl = mal(sizeof *ntl);
- ntl->n = n;
- ntl->t = t;
- ntl->next = nil;
-
- if(dntq == nil)
- dntq = ntl;
- else
- dntend->next = ntl;
-
- dntend = ntl;
-}
-
-void
-resumetypecopy(void)
-{
- NodeTypeList *l;
-
- for(l=dntq; l; l=l->next)
- copytype(l->n, l->t);
-}
-
-void
-copytype(Node *n, Type *t)
-{
- *n->type = *t;
-
- t = n->type;
- t->sym = n->sym;
- t->local = n->local;
- t->vargen = n->vargen;
- t->siggen = 0;
- t->method = nil;
- t->nod = N;
- t->printed = 0;
- t->deferwidth = 0;
-}
-
-static void
-typecheckdeftype(Node *n)
-{
- int maplineno, embedlineno, lno;
- Type *t;
- NodeList *l;
-
- ntypecheckdeftype++;
- lno = lineno;
- setlineno(n);
- n->type->sym = n->sym;
- n->typecheck = 1;
- typecheck(&n->ntype, Etype);
- if((t = n->ntype->type) == T) {
- n->diag = 1;
- goto ret;
- }
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
-
- maplineno = n->type->maplineno;
- embedlineno = n->type->embedlineno;
-
- // copy new type and clear fields
- // that don't come along.
- // anything zeroed here must be zeroed in
- // typedcl2 too.
- copytype(n, t);
-
- // double-check use of type as map key.
- if(maplineno) {
- lineno = maplineno;
- maptype(n->type, types[TBOOL]);
- }
- if(embedlineno) {
- lineno = embedlineno;
- if(isptr[t->etype])
- yyerror("embedded type cannot be a pointer");
- }
-
-ret:
- lineno = lno;
-
- // if there are no type definitions going on, it's safe to
- // try to resolve the method types for the interfaces
- // we just read.
- if(ntypecheckdeftype == 1) {
- while((l = methodqueue) != nil) {
- methodqueue = nil;
- for(; l; l=l->next)
- domethod(l->n);
- }
- }
- ntypecheckdeftype--;
-}
-
-void
-queuemethod(Node *n)
-{
- if(ntypecheckdeftype == 0) {
- domethod(n);
- return;
- }
- methodqueue = list(methodqueue, n);
-}
-
-Node*
-typecheckdef(Node *n)
-{
- int lno;
- Node *e;
- Type *t;
- NodeList *l;
-
- lno = lineno;
- setlineno(n);
-
- if(n->op == ONONAME) {
- if(!n->diag) {
- n->diag = 1;
- if(n->lineno != 0)
- lineno = n->lineno;
- yyerror("undefined: %S", n->sym);
- }
- return n;
- }
-
- if(n->walkdef == 1)
- return n;
-
- l = mal(sizeof *l);
- l->n = n;
- l->next = typecheckdefstack;
- typecheckdefstack = l;
-
- if(n->walkdef == 2) {
- flusherrors();
- print("typecheckdef loop:");
- for(l=typecheckdefstack; l; l=l->next)
- print(" %S", l->n->sym);
- print("\n");
- fatal("typecheckdef loop");
- }
- n->walkdef = 2;
-
- if(n->type != T || n->sym == S) // builtin or no name
- goto ret;
-
- switch(n->op) {
- default:
- fatal("typecheckdef %O", n->op);
-
- case OGOTO:
- case OLABEL:
- // not really syms
- break;
-
- case OLITERAL:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- n->ntype = N;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- e = n->defn;
- n->defn = N;
- if(e == N) {
- lineno = n->lineno;
- dump("typecheckdef nil defn", n);
- yyerror("xxx");
- }
- typecheck(&e, Erv | Eiota);
- if(e->type != T && e->op != OLITERAL) {
- yyerror("const initializer must be constant");
- goto ret;
- }
- if(isconst(e, CTNIL)) {
- yyerror("const initializer cannot be nil");
- goto ret;
- }
- t = n->type;
- if(t != T) {
- if(!okforconst[t->etype]) {
- yyerror("invalid constant type %T", t);
- goto ret;
- }
- if(!isideal(e->type) && !eqtype(t, e->type)) {
- yyerror("cannot use %+N as type %T in const initializer", e, t);
- goto ret;
- }
- convlit(&e, t);
- }
- n->val = e->val;
- n->type = e->type;
- break;
-
- case ONAME:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- if(n->type != T)
- break;
- if(n->defn == N) {
- if(n->etype != 0) // like OPRINTN
- break;
- if(nsavederrors+nerrors > 0) {
- // Can have undefined variables in x := foo
- // that make x have an n->ndefn == nil.
- // If there are other errors anyway, don't
- // bother adding to the noise.
- break;
- }
- fatal("var without type, init: %S", n->sym);
- }
- if(n->defn->op == ONAME) {
- typecheck(&n->defn, Erv);
- n->type = n->defn->type;
- break;
- }
- typecheck(&n->defn, Etop); // fills in n->type
- break;
-
- case OTYPE:
- if(curfn)
- defercheckwidth();
- n->walkdef = 1;
- n->type = typ(TFORW);
- n->type->sym = n->sym;
- typecheckdeftype(n);
- if(curfn)
- resumecheckwidth();
- break;
-
- case OPACK:
- // nothing to see here
- break;
- }
-
-ret:
- if(typecheckdefstack->n != n)
- fatal("typecheckdefstack mismatch");
- l = typecheckdefstack;
- typecheckdefstack = l->next;
-
- lineno = lno;
- n->walkdef = 1;
- return n;
-}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
deleted file mode 100644
index d304077c8..000000000
--- a/src/cmd/gc/unsafe.c
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-/*
- * look for
- * unsafe.Sizeof
- * unsafe.Offsetof
- * rewrite with a constant
- */
-Node*
-unsafenmagic(Node *nn)
-{
- Node *r, *n;
- Sym *s;
- Type *t, *tr;
- long v;
- Val val;
- Node *fn;
- NodeList *args;
-
- fn = nn->left;
- args = nn->list;
-
- if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
- goto no;
- if(s->pkg != unsafepkg)
- goto no;
-
- if(args == nil) {
- yyerror("missing argument for %S", s);
- goto no;
- }
- r = args->n;
-
- if(strcmp(s->name, "Sizeof") == 0) {
- typecheck(&r, Erv);
- defaultlit(&r, T);
- tr = r->type;
- if(tr == T)
- goto bad;
- dowidth(tr);
- v = tr->width;
- goto yes;
- }
- if(strcmp(s->name, "Offsetof") == 0) {
- typecheck(&r, Erv);
- if(r->op != ODOT && r->op != ODOTPTR)
- goto bad;
- typecheck(&r, Erv);
- v = r->xoffset;
- goto yes;
- }
- if(strcmp(s->name, "Alignof") == 0) {
- typecheck(&r, Erv);
- defaultlit(&r, T);
- tr = r->type;
- if(tr == T)
- goto bad;
-
- // make struct { byte; T; }
- t = typ(TSTRUCT);
- t->type = typ(TFIELD);
- t->type->type = types[TUINT8];
- t->type->down = typ(TFIELD);
- t->type->down->type = tr;
- // compute struct widths
- dowidth(t);
-
- // the offset of T is its required alignment
- v = t->type->down->width;
- goto yes;
- }
-
-no:
- return N;
-
-bad:
- yyerror("invalid expression %#N", nn);
- v = 0;
- goto ret;
-
-yes:
- if(args->next != nil)
- yyerror("extra arguments for %S", s);
-ret:
- // any side effects disappear; ignore init
- val.ctype = CTINT;
- val.u.xval = mal(sizeof(*n->val.u.xval));
- mpmovecfix(val.u.xval, v);
- n = nod(OLITERAL, N, N);
- n->val = val;
- n->type = types[TUINTPTR];
- return n;
-}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
deleted file mode 100644
index db27d7425..000000000
--- a/src/cmd/gc/unsafe.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-package PACKAGE
-
-type Pointer uintptr // not really; filled in by compiler
-
-// return types here are ignored; see unsafe.c
-func Offsetof(any) uintptr
-func Sizeof(any) uintptr
-func Alignof(any) uintptr
-
-func Typeof(i interface{}) (typ interface{})
-func Reflect(i interface{}) (typ interface{}, addr Pointer)
-func Unreflect(typ interface{}, addr Pointer) (ret interface{})
-func New(typ interface{}) Pointer
-func NewArray(typ interface{}, n int) Pointer
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
deleted file mode 100644
index c9ca9b3b3..000000000
--- a/src/cmd/gc/walk.c
+++ /dev/null
@@ -1,2177 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go.h"
-
-static Node* walkprint(Node*, NodeList**, int);
-static Node* conv(Node*, Type*);
-static Node* mapfn(char*, Type*);
-static Node* makenewvar(Type*, NodeList**, Node**);
-static Node* ascompatee1(int, Node*, Node*, NodeList**);
-static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
-static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
-static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**);
-static Node* convas(Node*, NodeList**);
-static void heapmoves(void);
-static NodeList* paramstoheap(Type **argin, int out);
-static NodeList* reorder1(NodeList*);
-static NodeList* reorder3(NodeList*);
-static Node* addstr(Node*, NodeList**);
-static Node* appendslice(Node*, NodeList**);
-static Node* append(Node*, NodeList**);
-
-// can this code branch reach the end
-// without an unconditional RETURN
-// this is hard, so it is conservative
-static int
-walkret(NodeList *l)
-{
- Node *n;
-
-loop:
- while(l && l->next)
- l = l->next;
- if(l == nil)
- return 1;
-
- // at this point, we have the last
- // statement of the function
- n = l->n;
- switch(n->op) {
- case OBLOCK:
- l = n->list;
- goto loop;
-
- case OGOTO:
- case ORETURN:
- case OPANIC:
- return 0;
- break;
- }
-
- // all other statements
- // will flow to the end
- return 1;
-}
-
-void
-walk(Node *fn)
-{
- char s[50];
- NodeList *l;
- Node *n;
- int lno;
-
- curfn = fn;
-
- if(debug['W']) {
- snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
- dumplist(s, curfn->nbody);
- }
- if(curfn->type->outtuple)
- if(walkret(curfn->nbody))
- yyerror("function ends without a return statement");
-
- lno = lineno;
- for(l=fn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME || n->class != PAUTO)
- continue;
- lineno = n->lineno;
- typecheck(&n, Erv | Easgn); // only needed for unused variables
- if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
- yyerror("%S declared and not used", n->sym);
- }
- lineno = lno;
- if(nerrors != 0)
- return;
- walkstmtlist(curfn->nbody);
- if(debug['W']) {
- snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
- dumplist(s, curfn->nbody);
- }
- heapmoves();
- if(debug['W'] && curfn->enter != nil) {
- snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
- dumplist(s, curfn->enter);
- }
-}
-
-
-void
-walkstmtlist(NodeList *l)
-{
- for(; l; l=l->next)
- walkstmt(&l->n);
-}
-
-static int
-samelist(NodeList *a, NodeList *b)
-{
- for(; a && b; a=a->next, b=b->next)
- if(a->n != b->n)
- return 0;
- return a == b;
-}
-
-static int
-paramoutheap(Node *fn)
-{
- NodeList *l;
-
- for(l=fn->dcl; l; l=l->next) {
- switch(l->n->class) {
- case PPARAMOUT|PHEAP:
- return 1;
- case PAUTO:
- case PAUTO|PHEAP:
- // stop early - parameters are over
- return 0;
- }
- }
- return 0;
-}
-
-void
-walkstmt(Node **np)
-{
- NodeList *init;
- NodeList *ll, *rl;
- int cl;
- Node *n, *f;
-
- n = *np;
- if(n == N)
- return;
-
- setlineno(n);
-
- switch(n->op) {
- default:
- if(n->op == ONAME)
- yyerror("%S is not a top level statement", n->sym);
- else
- yyerror("%O is not a top level statement", n->op);
- dump("nottop", n);
- break;
-
- case OASOP:
- case OAS:
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2RECV:
- case OAS2FUNC:
- case OAS2MAPW:
- case OAS2MAPR:
- case OCLOSE:
- case OCOPY:
- case OCALLMETH:
- case OCALLINTER:
- case OCALL:
- case OCALLFUNC:
- case OSEND:
- case ORECV:
- case OPRINT:
- case OPRINTN:
- case OPANIC:
- case OEMPTY:
- case ORECOVER:
- if(n->typecheck == 0) {
- dump("missing typecheck:", n);
- fatal("missing typecheck");
- }
- init = n->ninit;
- n->ninit = nil;
- walkexpr(&n, &init);
- n->ninit = concat(init, n->ninit);
- break;
-
- case OBREAK:
- case ODCL:
- case OCONTINUE:
- case OFALL:
- case OGOTO:
- case OLABEL:
- case ODCLCONST:
- case ODCLTYPE:
- break;
-
- case OBLOCK:
- walkstmtlist(n->list);
- break;
-
- case OXCASE:
- yyerror("case statement out of place");
- n->op = OCASE;
- case OCASE:
- walkstmt(&n->right);
- break;
-
- case ODEFER:
- hasdefer = 1;
- switch(n->left->op) {
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->left->list, &n->ninit);
- n->left = walkprint(n->left, &n->ninit, 1);
- break;
- default:
- walkexpr(&n->left, &n->ninit);
- break;
- }
- break;
-
- case OFOR:
- walkstmtlist(n->ninit);
- if(n->ntest != N) {
- walkstmtlist(n->ntest->ninit);
- init = n->ntest->ninit;
- n->ntest->ninit = nil;
- walkexpr(&n->ntest, &init);
- n->ntest->ninit = concat(init, n->ntest->ninit);
- }
- walkstmt(&n->nincr);
- walkstmtlist(n->nbody);
- break;
-
- case OIF:
- walkstmtlist(n->ninit);
- walkexpr(&n->ntest, &n->ninit);
- walkstmtlist(n->nbody);
- walkstmtlist(n->nelse);
- break;
-
- case OPROC:
- switch(n->left->op) {
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->left->list, &n->ninit);
- n->left = walkprint(n->left, &n->ninit, 1);
- break;
- default:
- walkexpr(&n->left, &n->ninit);
- break;
- }
- break;
-
- case ORETURN:
- walkexprlist(n->list, &n->ninit);
- if(n->list == nil)
- break;
- if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
- // assign to the function out parameters,
- // so that reorder3 can fix up conflicts
- rl = nil;
- for(ll=curfn->dcl; ll != nil; ll=ll->next) {
- cl = ll->n->class & ~PHEAP;
- if(cl == PAUTO)
- break;
- if(cl == PPARAMOUT)
- rl = list(rl, ll->n);
- }
- if(samelist(rl, n->list)) {
- // special return in disguise
- n->list = nil;
- break;
- }
- if(count(n->list) == 1 && count(rl) > 1) {
- // OAS2FUNC in disguise
- f = n->list->n;
- if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
- fatal("expected return of call, have %#N", f);
- n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
- break;
- }
- ll = ascompatee(n->op, rl, n->list, &n->ninit);
- n->list = reorder3(ll);
- break;
- }
- ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
- n->list = ll;
- break;
-
- case OSELECT:
- walkselect(n);
- break;
-
- case OSWITCH:
- walkswitch(n);
- break;
-
- case ORANGE:
- walkrange(n);
- break;
-
- case OXFALL:
- yyerror("fallthrough statement out of place");
- n->op = OFALL;
- break;
- }
-
- *np = n;
-}
-
-
-/*
- * walk the whole tree of the body of an
- * expression or simple statement.
- * the types expressions are calculated.
- * compile-time constants are evaluated.
- * complex side effects like statements are appended to init
- */
-
-void
-walkexprlist(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next)
- walkexpr(&l->n, init);
-}
-
-void
-walkexprlistsafe(NodeList *l, NodeList **init)
-{
- for(; l; l=l->next) {
- l->n = safeexpr(l->n, init);
- walkexpr(&l->n, init);
- }
-}
-
-void
-walkexpr(Node **np, NodeList **init)
-{
- Node *r, *l, *var, *a;
- NodeList *ll, *lr, *lpost;
- Type *t;
- int et;
- int64 v, v1, v2, len;
- int32 lno;
- Node *n, *fn;
- char buf[100], *p;
-
- n = *np;
-
- if(n == N)
- return;
-
- if(init == &n->ninit) {
- // not okay to use n->ninit when walking n,
- // because we might replace n with some other node
- // and would lose the init list.
- fatal("walkexpr init == &n->ninit");
- }
-
- // annoying case - not typechecked
- if(n->op == OKEY) {
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- return;
- }
-
- lno = setlineno(n);
-
- if(debug['w'] > 1)
- dump("walk-before", n);
-
- if(n->typecheck != 1) {
- dump("missed typecheck", n);
- fatal("missed typecheck");
- }
-
- t = T;
- et = Txxx;
-
- switch(n->op) {
- default:
- dump("walk", n);
- fatal("walkexpr: switch 1 unknown op %N", n);
- goto ret;
-
- case OTYPE:
- case ONONAME:
- case OINDREG:
- case OEMPTY:
- goto ret;
-
- case ONOT:
- case OMINUS:
- case OPLUS:
- case OCOM:
- case OREAL:
- case OIMAG:
- case ODOT:
- case ODOTPTR:
- case ODOTMETH:
- case ODOTINTER:
- case OIND:
- walkexpr(&n->left, init);
- goto ret;
-
- case OLEN:
- case OCAP:
- walkexpr(&n->left, init);
-
- // replace len(*[10]int) with 10.
- // delayed until now to preserve side effects.
- t = n->left->type;
- if(isptr[t->etype])
- t = t->type;
- if(isfixedarray(t)) {
- safeexpr(n->left, init);
- nodconst(n, n->type, t->bound);
- n->typecheck = 1;
- }
- goto ret;
-
- case OLSH:
- case ORSH:
- case OAND:
- case OOR:
- case OXOR:
- case OSUB:
- case OMUL:
- case OEQ:
- case ONE:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case OADD:
- case OCOMPLEX:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- goto ret;
-
- case OANDAND:
- case OOROR:
- walkexpr(&n->left, init);
- // cannot put side effects from n->right on init,
- // because they cannot run before n->left is checked.
- // save elsewhere and store on the eventual n->right.
- ll = nil;
- walkexpr(&n->right, &ll);
- n->right->ninit = concat(n->right->ninit, ll);
- goto ret;
-
- case OPRINT:
- case OPRINTN:
- walkexprlist(n->list, init);
- n = walkprint(n, init, 0);
- goto ret;
-
- case OPANIC:
- n = mkcall("panic", T, init, n->left);
- goto ret;
-
- case ORECOVER:
- n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N));
- goto ret;
-
- case OLITERAL:
- n->addable = 1;
- goto ret;
-
- case ONAME:
- if(!(n->class & PHEAP) && n->class != PPARAMREF)
- n->addable = 1;
- goto ret;
-
- case OCALLINTER:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
- n->list = reorder1(ll);
- goto ret;
-
- case OCALLFUNC:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
-
- if(n->left->op == OCLOSURE) {
- walkcallclosure(n, init);
- t = n->left->type;
- }
-
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
-
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
- n->list = reorder1(ll);
- if(isselect(n)) {
- // special prob with selectsend and selectrecv:
- // if chan is nil, they don't know big the channel
- // element is and therefore don't know how to find
- // the output bool, so we clear it before the call.
- Node *b;
- b = nodbool(0);
- typecheck(&b, Erv);
- lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init);
- n->list = concat(n->list, lr);
- }
- goto ret;
-
- case OCALLMETH:
- t = n->left->type;
- if(n->list && n->list->n->op == OAS)
- goto ret;
- walkexpr(&n->left, init);
- walkexprlist(n->list, init);
- ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init);
- lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
- ll = concat(ll, lr);
- n->left->left = N;
- ullmancalc(n->left);
- n->list = reorder1(ll);
- goto ret;
-
- case OAS:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
-
- if(oaslit(n, init))
- goto ret;
-
- walkexpr(&n->right, init);
- if(n->left != N && n->right != N) {
- r = convas(nod(OAS, n->left, n->right), init);
- r->dodata = n->dodata;
- n = r;
- }
-
- goto ret;
-
- case OAS2:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexprlistsafe(n->list, init);
- walkexprlistsafe(n->rlist, init);
- ll = ascompatee(OAS, n->list, n->rlist, init);
- ll = reorder3(ll);
- n = liststmt(ll);
- goto ret;
-
- case OAS2FUNC:
- as2func:
- // a,b,... = fn()
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r, init);
- l = n->list->n;
-
- // all the really hard stuff - explicit function calls and so on -
- // is gone, but map assignments remain.
- // if there are map assignments here, assign via
- // temporaries, because ascompatet assumes
- // the targets can be addressed without function calls
- // and map index has an implicit one.
- lpost = nil;
- if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
- n->list->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
- l = n->list->next->n;
- if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
- n->list->next->n = var;
- a = nod(OAS, l, var);
- typecheck(&a, Etop);
- lpost = list(lpost, a);
- }
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- walkexprlist(lpost, init);
- n = liststmt(concat(concat(list1(r), ll), lpost));
- goto ret;
-
- case OAS2RECV:
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, r->left);
- n->rlist->n = r;
- n->op = OAS2FUNC;
- goto as2func;
-
- case OAS2MAPR:
- // a,b = m[i];
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- walkexpr(&r->left, init);
- fn = mapfn("mapaccess2", r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, r->left, r->right);
- n->rlist = list1(r);
- n->op = OAS2FUNC;
- goto as2func;
-
- case OAS2MAPW:
- // map[] = a,b - mapassign2
- // a,b = m[i];
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- walkexprlistsafe(n->list, init);
- l = n->list->n;
- t = l->left->type;
- n = mkcall1(mapfn("mapassign2", t), T, init, l->left, l->right, n->rlist->n, n->rlist->next->n);
- goto ret;
-
- case OAS2DOTTYPE:
- // a,b = i.(T)
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- r = n->rlist->n;
- walkexprlistsafe(n->list, init);
- r->op = ODOTTYPE2;
- walkexpr(&r, init);
- ll = ascompatet(n->op, n->list, &r->type, 0, init);
- n = liststmt(concat(list1(r), ll));
- goto ret;
-
- case ODOTTYPE:
- case ODOTTYPE2:
- // Build name of function: assertI2E2 etc.
- strcpy(buf, "assert");
- p = buf+strlen(buf);
- if(isnilinter(n->left->type))
- *p++ = 'E';
- else
- *p++ = 'I';
- *p++ = '2';
- if(isnilinter(n->type))
- *p++ = 'E';
- else if(isinter(n->type))
- *p++ = 'I';
- else
- *p++ = 'T';
- if(n->op == ODOTTYPE2)
- *p++ = '2';
- *p = '\0';
-
- fn = syslook(buf, 1);
- ll = list1(typename(n->type));
- ll = list(ll, n->left);
- argtype(fn, n->left->type);
- argtype(fn, n->type);
- n = nod(OCALL, fn, N);
- n->list = ll;
- typecheck(&n, Erv | Efnstruct);
- walkexpr(&n, init);
- goto ret;
-
- case OCONVIFACE:
- // Build name of function: convI2E etc.
- // Not all names are possible
- // (e.g., we'll never generate convE2E or convE2I).
- walkexpr(&n->left, init);
- strcpy(buf, "conv");
- p = buf+strlen(buf);
- if(isnilinter(n->left->type))
- *p++ = 'E';
- else if(isinter(n->left->type))
- *p++ = 'I';
- else
- *p++ = 'T';
- *p++ = '2';
- if(isnilinter(n->type))
- *p++ = 'E';
- else
- *p++ = 'I';
- *p = '\0';
-
- fn = syslook(buf, 1);
- ll = nil;
- if(!isinter(n->left->type))
- ll = list(ll, typename(n->left->type));
- if(!isnilinter(n->type))
- ll = list(ll, typename(n->type));
- ll = list(ll, n->left);
- argtype(fn, n->left->type);
- argtype(fn, n->type);
- dowidth(fn->type);
- n = nod(OCALL, fn, N);
- n->list = ll;
- typecheck(&n, Erv);
- walkexpr(&n, init);
- goto ret;
-
- case OCONV:
- case OCONVNOP:
- if(thechar == '5') {
- if(isfloat[n->left->type->etype]) {
- if(n->type->etype == TINT64) {
- n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
- }
- if(n->type->etype == TUINT64) {
- n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
- }
- }
- if(isfloat[n->type->etype]) {
- if(n->left->type->etype == TINT64) {
- n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
- goto ret;
- }
- if(n->left->type->etype == TUINT64) {
- n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
- goto ret;
- }
- }
- }
- walkexpr(&n->left, init);
- goto ret;
-
- case OASOP:
- if(n->etype == OANDNOT) {
- n->etype = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- }
- n->left = safeexpr(n->left, init);
- walkexpr(&n->left, init);
- l = n->left;
- walkexpr(&n->right, init);
-
- /*
- * on 32-bit arch, rewrite 64-bit ops into l = l op r.
- * on 386, rewrite float ops into l = l op r.
- * everywhere, rewrite map ops into l = l op r.
- * everywhere, rewrite string += into l = l op r.
- * everywhere, rewrite complex /= into l = l op r.
- * TODO(rsc): Maybe this rewrite should be done always?
- */
- et = n->left->type->etype;
- if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
- (thechar == '8' && isfloat[et]) ||
- l->op == OINDEXMAP ||
- et == TSTRING ||
- (iscomplex[et] && n->etype == ODIV)) {
- l = safeexpr(n->left, init);
- a = l;
- if(a->op == OINDEXMAP) {
- // map index has "lhs" bit set in a->etype.
- // make a copy so we can clear it on the rhs.
- a = nod(OXXX, N, N);
- *a = *l;
- a->etype = 0;
- }
- r = nod(OAS, l, nod(n->etype, a, n->right));
- typecheck(&r, Etop);
- walkexpr(&r, init);
- n = r;
- }
- goto ret;
-
- case OANDNOT:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- n->op = OAND;
- n->right = nod(OCOM, n->right, N);
- typecheck(&n->right, Erv);
- goto ret;
-
- case ODIV:
- case OMOD:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- /*
- * rewrite complex div into function call.
- */
- et = n->left->type->etype;
- if(iscomplex[et] && n->op == ODIV) {
- t = n->type;
- n = mkcall("complex128div", types[TCOMPLEX128], init,
- conv(n->left, types[TCOMPLEX128]),
- conv(n->right, types[TCOMPLEX128]));
- n = conv(n, t);
- goto ret;
- }
- /*
- * rewrite div and mod into function calls
- * on 32-bit architectures.
- */
- if(widthptr > 4 || (et != TUINT64 && et != TINT64))
- goto ret;
- if(et == TINT64)
- strcpy(namebuf, "int64");
- else
- strcpy(namebuf, "uint64");
- if(n->op == ODIV)
- strcat(namebuf, "div");
- else
- strcat(namebuf, "mod");
- n = mkcall(namebuf, n->type, init,
- conv(n->left, types[et]), conv(n->right, types[et]));
- goto ret;
-
- case OINDEX:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
-
- // if range of type cannot exceed static array bound,
- // disable bounds check
- if(isfixedarray(n->left->type))
- if(n->right->type->width < 4)
- if((1<<(8*n->right->type->width)) <= n->left->type->bound)
- n->etype = 1;
-
- if(isconst(n->left, CTSTR))
- if(n->right->type->width < 4)
- if((1<<(8*n->right->type->width)) <= n->left->val.u.sval->len)
- n->etype = 1;
-
- // check for static out of bounds
- if(isconst(n->right, CTINT) && !n->etype) {
- v = mpgetfix(n->right->val.u.xval);
- len = 1LL<<60;
- t = n->left->type;
- if(isconst(n->left, CTSTR))
- len = n->left->val.u.sval->len;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t))
- len = t->bound;
- if(v < 0 || v >= (1LL<<31) || v >= len)
- yyerror("index out of bounds");
- else if(isconst(n->left, CTSTR)) {
- // replace "abc"[2] with 'b'.
- // delayed until now because "abc"[2] is not
- // an ideal constant.
- nodconst(n, n->type, n->left->val.u.sval->s[v]);
- }
- }
- goto ret;
-
- case OINDEXMAP:
- if(n->etype == 1)
- goto ret;
-
- t = n->left->type;
- n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
- goto ret;
-
- case ORECV:
- walkexpr(&n->left, init);
- walkexpr(&n->right, init);
- n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left);
- goto ret;
-
- case OSLICE:
- case OSLICEARR:
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
- walkexpr(&n->right->left, init);
- n->right->left = safeexpr(n->right->left, init);
- walkexpr(&n->right->right, init);
- n->right->right = safeexpr(n->right->right, init);
-
- len = 1LL<<60;
- t = n->left->type;
- if(t != T && isptr[t->etype])
- t = t->type;
- if(isfixedarray(t))
- len = t->bound;
-
- // check for static out of bounds
- // NOTE: v > len not v >= len.
- v1 = -1;
- v2 = -1;
- if(isconst(n->right->left, CTINT)) {
- v1 = mpgetfix(n->right->left->val.u.xval);
- if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
- yyerror("slice index out of bounds");
- v1 = -1;
- }
- }
- if(isconst(n->right->right, CTINT)) {
- v2 = mpgetfix(n->right->right->val.u.xval);
- if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
- yyerror("slice index out of bounds");
- v2 = -1;
- }
- }
- if(v1 >= 0 && v2 >= 0 && v1 > v2)
- yyerror("inverted slice range");
-
- if(n->op == OSLICEARR)
- goto slicearray;
-
- // dynamic slice
- // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
- // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
- t = n->type;
- et = n->etype;
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TUINT64]);
- if(n->right->right != N) {
- fn = syslook("sliceslice", 1);
- argtype(fn, t->type); // any-1
- argtype(fn, t->type); // any-2
- n = mkcall1(fn, t, init,
- n->left,
- l,
- conv(n->right->right, types[TUINT64]),
- nodintconst(t->type->width));
- } else {
- fn = syslook("sliceslice1", 1);
- argtype(fn, t->type); // any-1
- argtype(fn, t->type); // any-2
- n = mkcall1(fn, t, init,
- n->left,
- l,
- nodintconst(t->type->width));
- }
- n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
- goto ret;
-
- slicearray:
- // static slice
- // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
- t = n->type;
- fn = syslook("slicearray", 1);
- argtype(fn, n->left->type->type); // any-1
- argtype(fn, t->type); // any-2
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TUINT64]);
- if(n->right->right == N)
- r = nodintconst(n->left->type->type->bound);
- else
- r = conv(n->right->right, types[TUINT64]);
- n = mkcall1(fn, t, init,
- n->left, nodintconst(n->left->type->type->bound),
- l,
- r,
- nodintconst(t->type->width));
- goto ret;
-
- case OADDR:;
- Node *nvar, *nstar;
-
- // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
- // initialize with
- // nvar := new(*Point);
- // *nvar = Point(1, 2);
- // and replace expression with nvar
- switch(n->left->op) {
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- nvar = makenewvar(n->type, init, &nstar);
- anylit(0, n->left, nstar, init);
- n = nvar;
- goto ret;
- }
-
- walkexpr(&n->left, init);
- goto ret;
-
- case ONEW:
- n = callnew(n->type->type);
- goto ret;
-
- case OCMPSTR:
- // If one argument to the comparison is an empty string,
- // comparing the lengths instead will yield the same result
- // without the function call.
- if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
- (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
- r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
- typecheck(&r, Erv);
- walkexpr(&r, init);
- n = r;
- goto ret;
- }
-
- // s + "badgerbadgerbadger" == "badgerbadgerbadger"
- if((n->etype == OEQ || n->etype == ONE) &&
- isconst(n->right, CTSTR) &&
- n->left->op == OADDSTR && isconst(n->left->right, CTSTR) &&
- cmpslit(n->right, n->left->right) == 0) {
- r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
- typecheck(&r, Erv);
- walkexpr(&r, init);
- n = r;
- goto ret;
- }
-
- // prepare for rewrite below
- if(n->etype == OEQ || n->etype == ONE) {
- n->left = cheapexpr(n->left, init);
- n->right = cheapexpr(n->right, init);
- }
-
- // sys_cmpstring(s1, s2) :: 0
- r = mkcall("cmpstring", types[TINT], init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
- r = nod(n->etype, r, nodintconst(0));
-
- // quick check of len before full compare for == or !=
- if(n->etype == OEQ || n->etype == ONE) {
- if(n->etype == OEQ)
- r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
- else
- r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
- typecheck(&r, Erv);
- walkexpr(&r, nil);
- }
- typecheck(&r, Erv);
- n = r;
- goto ret;
-
- case OADDSTR:
- n = addstr(n, init);
- goto ret;
-
- case OSLICESTR:
- // sys_slicestring(s, lb, hb)
- if(n->right->left == N)
- l = nodintconst(0);
- else
- l = conv(n->right->left, types[TINT]);
- if(n->right->right) {
- n = mkcall("slicestring", n->type, init,
- conv(n->left, types[TSTRING]),
- l,
- conv(n->right->right, types[TINT]));
- } else {
- n = mkcall("slicestring1", n->type, init,
- conv(n->left, types[TSTRING]),
- l);
- }
- goto ret;
-
- case OAPPEND:
- if(n->isddd)
- n = appendslice(n, init);
- else
- n = append(n, init);
- goto ret;
-
- case OCOPY:
- if(n->right->type->etype == TSTRING)
- fn = syslook("slicestringcopy", 1);
- else
- fn = syslook("slicecopy", 1);
- argtype(fn, n->left->type);
- argtype(fn, n->right->type);
- n = mkcall1(fn, n->type, init,
- n->left, n->right,
- nodintconst(n->left->type->type->width));
- goto ret;
-
- case OCLOSE:
- // cannot use chanfn - closechan takes any, not chan any
- fn = syslook("closechan", 1);
- argtype(fn, n->left->type);
- n = mkcall1(fn, T, init, n->left);
- goto ret;
-
- case OMAKECHAN:
- n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
- typename(n->type->type),
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OMAKEMAP:
- t = n->type;
-
- fn = syslook("makemap", 1);
- argtype(fn, t->down); // any-1
- argtype(fn, t->type); // any-2
-
- n = mkcall1(fn, n->type, init,
- typename(t->down), // key type
- typename(t->type), // value type
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OMAKESLICE:
- // makeslice(t *Type, nel int64, max int64) (ary []any)
- l = n->left;
- r = n->right;
- if(r == nil)
- l = r = safeexpr(l, init);
- t = n->type;
- fn = syslook("makeslice", 1);
- argtype(fn, t->type); // any-1
- n = mkcall1(fn, n->type, init,
- typename(n->type),
- conv(l, types[TINT64]),
- conv(r, types[TINT64]));
- goto ret;
-
- case ORUNESTR:
- // sys_intstring(v)
- n = mkcall("intstring", n->type, init,
- conv(n->left, types[TINT64]));
- goto ret;
-
- case OARRAYBYTESTR:
- // slicebytetostring([]byte) string;
- n = mkcall("slicebytetostring", n->type, init, n->left);
- goto ret;
-
- case OARRAYRUNESTR:
- // sliceinttostring([]int) string;
- n = mkcall("sliceinttostring", n->type, init, n->left);
- goto ret;
-
- case OSTRARRAYBYTE:
- // stringtoslicebyte(string) []byte;
- n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
- goto ret;
-
- case OSTRARRAYRUNE:
- // stringtosliceint(string) []int
- n = mkcall("stringtosliceint", n->type, init, n->left);
- goto ret;
-
- case OCMPIFACE:
- // ifaceeq(i1 any-1, i2 any-2) (ret bool);
- if(!eqtype(n->left->type, n->right->type))
- fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
- if(isnilinter(n->left->type))
- fn = syslook("efaceeq", 1);
- else
- fn = syslook("ifaceeq", 1);
- argtype(fn, n->right->type);
- argtype(fn, n->left->type);
- r = mkcall1(fn, n->type, init, n->left, n->right);
- if(n->etype == ONE) {
- r = nod(ONOT, r, N);
- typecheck(&r, Erv);
- }
- n = r;
- goto ret;
-
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- nvar = nod(OXXX, N, N);
- tempname(nvar, n->type);
- anylit(0, n, nvar, init);
- n = nvar;
- goto ret;
-
- case OSEND:
- n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
- goto ret;
-
- case OCLOSURE:
- n = walkclosure(n, init);
- goto ret;
- }
- fatal("missing switch %O", n->op);
-
-ret:
- if(debug['w'] && n != N)
- dump("walk", n);
-
- ullmancalc(n);
- lineno = lno;
- *np = n;
-}
-
-static Node*
-makenewvar(Type *t, NodeList **init, Node **nstar)
-{
- Node *nvar, *nas;
-
- nvar = nod(OXXX, N, N);
- tempname(nvar, t);
- nas = nod(OAS, nvar, callnew(t->type));
- typecheck(&nas, Etop);
- walkexpr(&nas, init);
- *init = list(*init, nas);
-
- *nstar = nod(OIND, nvar, N);
- typecheck(nstar, Erv);
- return nvar;
-}
-
-static Node*
-ascompatee1(int op, Node *l, Node *r, NodeList **init)
-{
- return convas(nod(OAS, l, r), init);
-}
-
-static NodeList*
-ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
-{
- NodeList *ll, *lr, *nn;
-
- /*
- * check assign expression list to
- * a expression list. called in
- * expr-list = expr-list
- */
-
- // ensure order of evaluation for function calls
- for(ll=nl; ll; ll=ll->next)
- ll->n = safeexpr(ll->n, init);
- for(lr=nr; lr; lr=lr->next)
- lr->n = safeexpr(lr->n, init);
-
- nn = nil;
- for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next)
- nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
-
- // cannot happen: caller checked that lists had same length
- if(ll || lr)
- yyerror("error in shape across %O", op);
- return nn;
-}
-
-/*
- * l is an lv and rt is the type of an rv
- * return 1 if this implies a function call
- * evaluating the lv or a function call
- * in the conversion of the types
- */
-static int
-fncall(Node *l, Type *rt)
-{
- if(l->ullman >= UINF || l->op == OINDEXMAP)
- return 1;
- if(eqtype(l->type, rt))
- return 0;
- return 1;
-}
-
-static NodeList*
-ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
-{
- Node *l, *tmp, *a;
- NodeList *ll;
- Type *r;
- Iter saver;
- int ucount;
- NodeList *nn, *mm;
-
- /*
- * check assign type list to
- * a expression list. called in
- * expr-list = func()
- */
- r = structfirst(&saver, nr);
- nn = nil;
- mm = nil;
- ucount = 0;
- for(ll=nl; ll; ll=ll->next) {
- if(r == T)
- break;
- l = ll->n;
- if(isblank(l)) {
- r = structnext(&saver);
- continue;
- }
-
- // any lv that causes a fn call must be
- // deferred until all the return arguments
- // have been pulled from the output arguments
- if(fncall(l, r->type)) {
- tmp = nod(OXXX, N, N);
- tempname(tmp, r->type);
- typecheck(&tmp, Erv);
- a = nod(OAS, l, tmp);
- a = convas(a, init);
- mm = list(mm, a);
- l = tmp;
- }
-
- a = nod(OAS, l, nodarg(r, fp));
- a = convas(a, init);
- ullmancalc(a);
- if(a->ullman >= UINF)
- ucount++;
- nn = list(nn, a);
- r = structnext(&saver);
- }
-
- if(ll != nil || r != T)
- yyerror("assignment count mismatch: %d = %d",
- count(nl), structcount(*nr));
- if(ucount)
- fatal("reorder2: too many function calls evaluating parameters");
- return concat(nn, mm);
-}
-
- /*
- * package all the arguments that match a ... T parameter into a []T.
- */
-static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
-{
- Node *a, *n;
- Type *tslice;
-
- tslice = typ(TARRAY);
- tslice->type = l->type->type;
- tslice->bound = -1;
-
- n = nod(OCOMPLIT, N, typenod(tslice));
- n->list = lr0;
- typecheck(&n, Erv);
- if(n->type == T)
- fatal("mkdotargslice: typecheck failed");
- walkexpr(&n, init);
-
- a = nod(OAS, nodarg(l, fp), n);
- nn = list(nn, convas(a, init));
- return nn;
-}
-
-/*
- * helpers for shape errors
- */
-static char*
-dumptypes(Type **nl, char *what)
-{
- int first;
- Type *l;
- Iter savel;
- Fmt fmt;
-
- fmtstrinit(&fmt);
- fmtprint(&fmt, "\t");
- l = structfirst(&savel, nl);
- first = 1;
- for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
- if(first)
- first = 0;
- else
- fmtprint(&fmt, ", ");
- fmtprint(&fmt, "%T", l);
- }
- if(first)
- fmtprint(&fmt, "[no arguments %s]", what);
- return fmtstrflush(&fmt);
-}
-
-static char*
-dumpnodetypes(NodeList *l, char *what)
-{
- int first;
- Node *r;
- Fmt fmt;
-
- fmtstrinit(&fmt);
- fmtprint(&fmt, "\t");
- first = 1;
- for(; l; l=l->next) {
- r = l->n;
- if(first)
- first = 0;
- else
- fmtprint(&fmt, ", ");
- fmtprint(&fmt, "%T", r->type);
- }
- if(first)
- fmtprint(&fmt, "[no arguments %s]", what);
- return fmtstrflush(&fmt);
-}
-
-/*
- * check assign expression list to
- * a type list. called in
- * return expr-list
- * func(expr-list)
- */
-static NodeList*
-ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
-{
- Type *l, *ll;
- Node *r, *a;
- NodeList *nn, *lr0, *alist;
- Iter savel;
- char *l1, *l2;
-
- lr0 = lr;
- l = structfirst(&savel, nl);
- r = N;
- if(lr)
- r = lr->n;
- nn = nil;
-
- // f(g()) where g has multiple return values
- if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
- // optimization - can do block copy
- if(eqtypenoname(r->type, *nl)) {
- a = nodarg(*nl, fp);
- a->type = r->type;
- nn = list1(convas(nod(OAS, a, r), init));
- goto ret;
- }
-
- // conversions involved.
- // copy into temporaries.
- alist = nil;
- for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
- a = nod(OXXX, N, N);
- tempname(a, l->type);
- alist = list(alist, a);
- }
- a = nod(OAS2, N, N);
- a->list = alist;
- a->rlist = lr;
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
- lr = alist;
- r = lr->n;
- l = structfirst(&savel, nl);
- }
-
-loop:
- if(l != T && l->isddd) {
- // the ddd parameter must be last
- ll = structnext(&savel);
- if(ll != T)
- yyerror("... must be last argument");
-
- // special case --
- // only if we are assigning a single ddd
- // argument to a ddd parameter then it is
- // passed thru unencapsulated
- if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
- a = nod(OAS, nodarg(l, fp), r);
- a = convas(a, init);
- nn = list(nn, a);
- goto ret;
- }
-
- // normal case -- make a slice of all
- // remaining arguments and pass it to
- // the ddd parameter.
- nn = mkdotargslice(lr, nn, l, fp, init);
- goto ret;
- }
-
- if(l == T || r == N) {
- if(l != T || r != N) {
- l1 = dumptypes(nl, "expected");
- l2 = dumpnodetypes(lr0, "given");
- if(l != T)
- yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
- else
- yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
- }
- goto ret;
- }
-
- a = nod(OAS, nodarg(l, fp), r);
- a = convas(a, init);
- nn = list(nn, a);
-
- l = structnext(&savel);
- r = N;
- lr = lr->next;
- if(lr != nil)
- r = lr->n;
- goto loop;
-
-ret:
- for(lr=nn; lr; lr=lr->next)
- lr->n->typecheck = 1;
- return nn;
-}
-
-// generate code for print
-static Node*
-walkprint(Node *nn, NodeList **init, int defer)
-{
- Node *r;
- Node *n;
- NodeList *l, *all;
- Node *on;
- Type *t;
- int notfirst, et, op;
- NodeList *calls, *intypes, *args;
- Fmt fmt;
-
- on = nil;
- op = nn->op;
- all = nn->list;
- calls = nil;
- notfirst = 0;
- intypes = nil;
- args = nil;
-
- memset(&fmt, 0, sizeof fmt);
- if(defer) {
- // defer print turns into defer printf with format string
- fmtstrinit(&fmt);
- intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
- args = list1(nod(OXXX, N, N));
- }
-
- for(l=all; l; l=l->next) {
- if(notfirst) {
- if(defer)
- fmtprint(&fmt, " ");
- else
- calls = list(calls, mkcall("printsp", T, init));
- }
- notfirst = op == OPRINTN;
-
- n = l->n;
- if(n->op == OLITERAL) {
- switch(n->val.ctype) {
- case CTINT:
- defaultlit(&n, types[TINT64]);
- break;
- case CTFLT:
- defaultlit(&n, types[TFLOAT64]);
- break;
- }
- }
- if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
- defaultlit(&n, types[TINT64]);
- defaultlit(&n, nil);
- l->n = n;
- if(n->type == T || n->type->etype == TFORW)
- continue;
-
- t = n->type;
- et = n->type->etype;
- if(isinter(n->type)) {
- if(defer) {
- if(isnilinter(n->type))
- fmtprint(&fmt, "%%e");
- else
- fmtprint(&fmt, "%%i");
- } else {
- if(isnilinter(n->type))
- on = syslook("printeface", 1);
- else
- on = syslook("printiface", 1);
- argtype(on, n->type); // any-1
- }
- } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
- if(defer) {
- fmtprint(&fmt, "%%p");
- } else {
- on = syslook("printpointer", 1);
- argtype(on, n->type); // any-1
- }
- } else if(isslice(n->type)) {
- if(defer) {
- fmtprint(&fmt, "%%a");
- } else {
- on = syslook("printslice", 1);
- argtype(on, n->type); // any-1
- }
- } else if(isint[et]) {
- if(defer) {
- if(et == TUINT64)
- fmtprint(&fmt, "%%U");
- else {
- fmtprint(&fmt, "%%D");
- t = types[TINT64];
- }
- } else {
- if(et == TUINT64)
- on = syslook("printuint", 0);
- else
- on = syslook("printint", 0);
- }
- } else if(isfloat[et]) {
- if(defer) {
- fmtprint(&fmt, "%%f");
- t = types[TFLOAT64];
- } else
- on = syslook("printfloat", 0);
- } else if(iscomplex[et]) {
- if(defer) {
- fmtprint(&fmt, "%%C");
- t = types[TCOMPLEX128];
- } else
- on = syslook("printcomplex", 0);
- } else if(et == TBOOL) {
- if(defer)
- fmtprint(&fmt, "%%t");
- else
- on = syslook("printbool", 0);
- } else if(et == TSTRING) {
- if(defer)
- fmtprint(&fmt, "%%S");
- else
- on = syslook("printstring", 0);
- } else {
- badtype(OPRINT, n->type, T);
- continue;
- }
-
- if(!defer) {
- t = *getinarg(on->type);
- if(t != nil)
- t = t->type;
- if(t != nil)
- t = t->type;
- }
-
- if(!eqtype(t, n->type)) {
- n = nod(OCONV, n, N);
- n->type = t;
- }
-
- if(defer) {
- intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
- args = list(args, n);
- } else {
- r = nod(OCALL, on, N);
- r->list = list1(n);
- calls = list(calls, r);
- }
- }
-
- if(defer) {
- if(op == OPRINTN)
- fmtprint(&fmt, "\n");
- on = syslook("goprintf", 1);
- on->type = functype(nil, intypes, nil);
- args->n = nod(OLITERAL, N, N);
- args->n->val.ctype = CTSTR;
- args->n->val.u.sval = strlit(fmtstrflush(&fmt));
- r = nod(OCALL, on, N);
- r->list = args;
- typecheck(&r, Etop);
- walkexpr(&r, init);
- } else {
- if(op == OPRINTN)
- calls = list(calls, mkcall("printnl", T, nil));
- typechecklist(calls, Etop);
- walkexprlist(calls, init);
-
- r = nod(OEMPTY, N, N);
- typecheck(&r, Etop);
- walkexpr(&r, init);
- r->ninit = calls;
- }
- return r;
-}
-
-Node*
-callnew(Type *t)
-{
- Node *fn;
-
- dowidth(t);
- fn = syslook("new", 1);
- argtype(fn, t);
- return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
-}
-
-static Node*
-convas(Node *n, NodeList **init)
-{
- Type *lt, *rt;
-
- if(n->op != OAS)
- fatal("convas: not OAS %O", n->op);
-
- n->typecheck = 1;
-
- if(n->left == N || n->right == N)
- goto out;
-
- lt = n->left->type;
- rt = n->right->type;
- if(lt == T || rt == T)
- goto out;
-
- if(isblank(n->left)) {
- defaultlit(&n->right, T);
- goto out;
- }
-
- if(n->left->op == OINDEXMAP) {
- n = mkcall1(mapfn("mapassign1", n->left->left->type), T, init,
- n->left->left, n->left->right, n->right);
- goto out;
- }
-
- if(eqtype(lt, rt))
- goto out;
-
- n->right = assignconv(n->right, lt, "assignment");
- walkexpr(&n->right, init);
-
-out:
- ullmancalc(n);
- return n;
-}
-
-/*
- * from ascompat[te]
- * evaluating actual function arguments.
- * f(a,b)
- * if there is exactly one function expr,
- * then it is done first. otherwise must
- * make temp variables
- */
-NodeList*
-reorder1(NodeList *all)
-{
- Node *f, *a, *n;
- NodeList *l, *r, *g;
- int c, d, t;
-
- c = 0; // function calls
- t = 0; // total parameters
-
- for(l=all; l; l=l->next) {
- n = l->n;
- t++;
- ullmancalc(n);
- if(n->ullman >= UINF)
- c++;
- }
- if(c == 0 || t == 1)
- return all;
-
- g = nil; // fncalls assigned to tempnames
- f = N; // last fncall assigned to stack
- r = nil; // non fncalls and tempnames assigned to stack
- d = 0;
- for(l=all; l; l=l->next) {
- n = l->n;
- if(n->ullman < UINF) {
- r = list(r, n);
- continue;
- }
- d++;
- if(d == c) {
- f = n;
- continue;
- }
-
- // make assignment of fncall to tempname
- a = nod(OXXX, N, N);
- tempname(a, n->right->type);
- a = nod(OAS, a, n->right);
- g = list(g, a);
-
- // put normal arg assignment on list
- // with fncall replaced by tempname
- n->right = a->left;
- r = list(r, n);
- }
-
- if(f != N)
- g = list(g, f);
- return concat(g, r);
-}
-
-/*
- * from ascompat[ee]
- * a,b = c,d
- * simultaneous assignment. there cannot
- * be later use of an earlier lvalue.
- */
-
-static int
-vmatch2(Node *l, Node *r)
-{
- NodeList *ll;
-
- /*
- * isolate all right sides
- */
- if(r == N)
- return 0;
- switch(r->op) {
- case ONAME:
- // match each right given left
- if(l == r)
- return 1;
- case OLITERAL:
- return 0;
- }
- if(vmatch2(l, r->left))
- return 1;
- if(vmatch2(l, r->right))
- return 1;
- for(ll=r->list; ll; ll=ll->next)
- if(vmatch2(l, ll->n))
- return 1;
- return 0;
-}
-
-int
-vmatch1(Node *l, Node *r)
-{
- NodeList *ll;
-
- /*
- * isolate all left sides
- */
- if(l == N || r == N)
- return 0;
- switch(l->op) {
- case ONAME:
- switch(l->class) {
- case PPARAM:
- case PPARAMREF:
- case PAUTO:
- break;
- default:
- // assignment to non-stack variable
- // must be delayed if right has function calls.
- if(r->ullman >= UINF)
- return 1;
- break;
- }
- return vmatch2(l, r);
- case OLITERAL:
- return 0;
- }
- if(vmatch1(l->left, r))
- return 1;
- if(vmatch1(l->right, r))
- return 1;
- for(ll=l->list; ll; ll=ll->next)
- if(vmatch1(ll->n, r))
- return 1;
- return 0;
-}
-
-NodeList*
-reorder3(NodeList *all)
-{
- Node *n1, *n2, *q;
- int c1, c2;
- NodeList *l1, *l2, *r;
-
- r = nil;
- for(l1=all, c1=0; l1; l1=l1->next, c1++) {
- n1 = l1->n;
- for(l2=all, c2=0; l2; l2=l2->next, c2++) {
- n2 = l2->n;
- if(c2 > c1) {
- if(vmatch1(n1->left, n2->right)) {
- // delay assignment to n1->left
- q = nod(OXXX, N, N);
- tempname(q, n1->right->type);
- q = nod(OAS, n1->left, q);
- n1->left = q->right;
- r = list(r, q);
- break;
- }
- }
- }
- }
- return concat(all, r);
-}
-
-/*
- * walk through argin parameters.
- * generate and return code to allocate
- * copies of escaped parameters to the heap.
- */
-static NodeList*
-paramstoheap(Type **argin, int out)
-{
- Type *t;
- Iter savet;
- Node *v;
- NodeList *nn;
-
- nn = nil;
- for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- v = t->nname;
- if(v == N && out && hasdefer) {
- // Defer might stop a panic and show the
- // return values as they exist at the time of panic.
- // Make sure to zero them on entry to the function.
- nn = list(nn, nod(OAS, nodarg(t, 1), N));
- }
- if(v == N || !(v->class & PHEAP))
- continue;
-
- // generate allocation & copying code
- if(v->alloc == nil)
- v->alloc = callnew(v->type);
- nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
- if((v->class & ~PHEAP) != PPARAMOUT)
- nn = list(nn, nod(OAS, v, v->stackparam));
- }
- return nn;
-}
-
-/*
- * walk through argout parameters copying back to stack
- */
-static NodeList*
-returnsfromheap(Type **argin)
-{
- Type *t;
- Iter savet;
- Node *v;
- NodeList *nn;
-
- nn = nil;
- for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
- v = t->nname;
- if(v == N || v->class != (PHEAP|PPARAMOUT))
- continue;
- nn = list(nn, nod(OAS, v->stackparam, v));
- }
- return nn;
-}
-
-/*
- * take care of migrating any function in/out args
- * between the stack and the heap. adds code to
- * curfn's before and after lists.
- */
-static void
-heapmoves(void)
-{
- NodeList *nn;
- int32 lno;
-
- lno = lineno;
- lineno = curfn->lineno;
- nn = paramstoheap(getthis(curfn->type), 0);
- nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
- nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
- curfn->enter = concat(curfn->enter, nn);
- lineno = curfn->endlineno;
- curfn->exit = returnsfromheap(getoutarg(curfn->type));
- lineno = lno;
-}
-
-static Node*
-vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
-{
- int i, n;
- Node *r;
- NodeList *args;
-
- if(fn->type == T || fn->type->etype != TFUNC)
- fatal("mkcall %#N %T", fn, fn->type);
-
- args = nil;
- n = fn->type->intuple;
- for(i=0; i<n; i++)
- args = list(args, va_arg(va, Node*));
-
- r = nod(OCALL, fn, N);
- r->list = args;
- if(fn->type->outtuple > 0)
- typecheck(&r, Erv | Efnstruct);
- else
- typecheck(&r, Etop);
- walkexpr(&r, init);
- r->type = t;
- return r;
-}
-
-Node*
-mkcall(char *name, Type *t, NodeList **init, ...)
-{
- Node *r;
- va_list va;
-
- va_start(va, init);
- r = vmkcall(syslook(name, 0), t, init, va);
- va_end(va);
- return r;
-}
-
-Node*
-mkcall1(Node *fn, Type *t, NodeList **init, ...)
-{
- Node *r;
- va_list va;
-
- va_start(va, init);
- r = vmkcall(fn, t, init, va);
- va_end(va);
- return r;
-}
-
-static Node*
-conv(Node *n, Type *t)
-{
- if(eqtype(n->type, t))
- return n;
- n = nod(OCONV, n, N);
- n->type = t;
- typecheck(&n, Erv);
- return n;
-}
-
-Node*
-chanfn(char *name, int n, Type *t)
-{
- Node *fn;
- int i;
-
- if(t->etype != TCHAN)
- fatal("chanfn %T", t);
- fn = syslook(name, 1);
- for(i=0; i<n; i++)
- argtype(fn, t->type);
- return fn;
-}
-
-static Node*
-mapfn(char *name, Type *t)
-{
- Node *fn;
-
- if(t->etype != TMAP)
- fatal("mapfn %T", t);
- fn = syslook(name, 1);
- argtype(fn, t->down);
- argtype(fn, t->type);
- argtype(fn, t->down);
- argtype(fn, t->type);
- return fn;
-}
-
-static Node*
-addstr(Node *n, NodeList **init)
-{
- Node *r, *cat, *typstr;
- NodeList *in, *args;
- int i, count;
-
- count = 0;
- for(r=n; r->op == OADDSTR; r=r->left)
- count++; // r->right
- count++; // r
-
- // prepare call of runtime.catstring of type int, string, string, string
- // with as many strings as we have.
- cat = syslook("concatstring", 1);
- cat->type = T;
- cat->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
- typstr = typenod(types[TSTRING]);
- for(i=0; i<count; i++)
- in = list(in, nod(ODCLFIELD, N, typstr));
- cat->ntype->list = in;
- cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
-
- args = nil;
- for(r=n; r->op == OADDSTR; r=r->left)
- args = concat(list1(conv(r->right, types[TSTRING])), args);
- args = concat(list1(conv(r, types[TSTRING])), args);
- args = concat(list1(nodintconst(count)), args);
-
- r = nod(OCALL, cat, N);
- r->list = args;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
-
- return r;
-}
-
-static Node*
-appendslice(Node *n, NodeList **init)
-{
- Node *f;
-
- f = syslook("appendslice", 1);
- argtype(f, n->type);
- argtype(f, n->type->type);
- argtype(f, n->type);
- return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
-}
-
-// expand append(src, a [, b]* ) to
-//
-// init {
-// s := src
-// const argc = len(args) - 1
-// if cap(s) - len(s) < argc {
-// s = growslice(s, argc)
-// }
-// n := len(s)
-// s = s[:n+argc]
-// s[n] = a
-// s[n+1] = b
-// ...
-// }
-// s
-static Node*
-append(Node *n, NodeList **init)
-{
- NodeList *l, *a;
- Node *nsrc, *ns, *nn, *na, *nx, *fn;
- int argc;
-
- walkexprlistsafe(n->list, init);
-
- nsrc = n->list->n;
- argc = count(n->list) - 1;
- if (argc < 1) {
- return nsrc;
- }
-
- l = nil;
-
- ns = nod(OXXX, N, N); // var s
- tempname(ns, nsrc->type);
- l = list(l, nod(OAS, ns, nsrc)); // s = src
-
- na = nodintconst(argc); // const argc
- nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
- nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
-
- fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
- argtype(fn, ns->type->type); // 1 old []any
- argtype(fn, ns->type->type); // 2 ret []any
-
- nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
- typename(ns->type),
- ns,
- conv(na, types[TINT64]))));
- l = list(l, nx);
-
- nn = nod(OXXX, N, N); // var n
- tempname(nn, types[TINT]);
- l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
-
- nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
-
- for (a = n->list->next; a != nil; a = a->next) {
- nx = nod(OINDEX, ns, nn); // s[n] ...
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
- if (a->next != nil)
- l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
- }
-
- typechecklist(l, Etop);
- walkstmtlist(l);
- *init = concat(*init, l);
- return ns;
-}