diff options
Diffstat (limited to 'src/cmd/gc')
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; -} |