2011-10-31 11:09:40 -06:00
|
|
|
// 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 <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include "go.h"
|
|
|
|
#include "opnames.h"
|
|
|
|
|
|
|
|
//
|
|
|
|
// Format conversions
|
|
|
|
// %L int Line numbers
|
|
|
|
//
|
|
|
|
// %E int etype values (aka 'Kind')
|
|
|
|
//
|
|
|
|
// %O int Node Opcodes
|
|
|
|
// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
|
|
|
|
//
|
|
|
|
// %J Node* Node details
|
|
|
|
// Flags: "%hJ" supresses things not relevant until walk.
|
|
|
|
//
|
|
|
|
// %V Val* Constant values
|
|
|
|
//
|
|
|
|
// %S Sym* Symbols
|
|
|
|
// Flags: +,- #: mode (see below)
|
|
|
|
// "%hS" unqualified identifier in any mode
|
2011-12-05 12:40:19 -07:00
|
|
|
// "%hhS" in export mode: unqualified identifier if exported, qualified if not
|
2011-10-31 11:09:40 -06:00
|
|
|
//
|
|
|
|
// %T Type* Types
|
|
|
|
// Flags: +,- #: mode (see below)
|
2011-11-09 03:27:27 -07:00
|
|
|
// 'l' definition instead of name.
|
2011-10-31 11:09:40 -06:00
|
|
|
// 'h' omit "func" and receiver in function types
|
2011-11-09 03:27:27 -07:00
|
|
|
// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
|
2011-10-31 11:09:40 -06:00
|
|
|
//
|
|
|
|
// %N Node* Nodes
|
|
|
|
// Flags: +,- #: mode (see below)
|
|
|
|
// 'h' (only in +/debug mode) suppress recursion
|
|
|
|
// 'l' (only in Error mode) print "foo (type Bar)"
|
|
|
|
//
|
|
|
|
// %H NodeList* NodeLists
|
|
|
|
// Flags: those of %N
|
|
|
|
// ',' separate items with ',' instead of ';'
|
|
|
|
//
|
2011-11-09 03:27:27 -07:00
|
|
|
// %Z Strlit* String literals
|
2011-10-31 11:09:40 -06:00
|
|
|
//
|
|
|
|
// In mparith1.c:
|
|
|
|
// %B Mpint* Big integers
|
|
|
|
// %F Mpflt* Big floats
|
|
|
|
//
|
|
|
|
// %S, %T and %N obey use the following flags to set the format mode:
|
|
|
|
enum {
|
|
|
|
FErr, // error mode (default)
|
|
|
|
FDbg, // "%+N" debug mode
|
|
|
|
FExp, // "%#N" export mode
|
|
|
|
FTypeId, // "%-N" turning-types-into-symbols-mode: identical types give identical strings
|
|
|
|
};
|
|
|
|
static int fmtmode;
|
|
|
|
static int fmtpkgpfx; // %uT stickyness
|
|
|
|
//
|
|
|
|
// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode.
|
|
|
|
//
|
|
|
|
// The mode flags +, - and # are sticky, meaning they persist through
|
|
|
|
// recursions of %N, %T and %S, but not the h and l flags. The u flag is
|
|
|
|
// sticky only on %T recursions and only used in %-/Sym mode.
|
|
|
|
|
|
|
|
//
|
|
|
|
// Useful format combinations:
|
|
|
|
//
|
|
|
|
// %+N %+H multiline recursive debug dump of node/nodelist
|
|
|
|
// %+hN %+hH non recursive debug dump
|
|
|
|
//
|
|
|
|
// %#N %#T export format
|
|
|
|
// %#lT type definition instead of name
|
|
|
|
// %#hT omit"func" and receiver in function signature
|
|
|
|
//
|
|
|
|
// %lN "foo (type Bar)" for error messages
|
|
|
|
//
|
|
|
|
// %-T type identifiers
|
|
|
|
// %-hT type identifiers without "func" and arg names in type signatures (methodsym)
|
|
|
|
// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
setfmode(unsigned long *flags)
|
|
|
|
{
|
|
|
|
int fm;
|
|
|
|
|
|
|
|
fm = fmtmode;
|
|
|
|
if(*flags & FmtSign)
|
|
|
|
fmtmode = FDbg;
|
|
|
|
else if(*flags & FmtSharp)
|
|
|
|
fmtmode = FExp;
|
|
|
|
else if(*flags & FmtLeft)
|
|
|
|
fmtmode = FTypeId;
|
|
|
|
|
|
|
|
*flags &= ~(FmtSharp|FmtLeft|FmtSign);
|
|
|
|
return fm;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt "%L": Linenumbers
|
|
|
|
static 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, " ");
|
|
|
|
}
|
2011-12-02 12:13:12 -07:00
|
|
|
if(debug['L'] || (fp->flags&FmtLong))
|
2011-10-31 11:09:40 -06:00
|
|
|
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)
|
2013-03-22 15:50:29 -06:00
|
|
|
fmtprint(fp, "<unknown line number>");
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
goopnames[] =
|
|
|
|
{
|
|
|
|
[OADDR] = "&",
|
|
|
|
[OADD] = "+",
|
|
|
|
[OADDSTR] = "+",
|
|
|
|
[OANDAND] = "&&",
|
|
|
|
[OANDNOT] = "&^",
|
|
|
|
[OAND] = "&",
|
|
|
|
[OAPPEND] = "append",
|
|
|
|
[OAS] = "=",
|
|
|
|
[OAS2] = "=",
|
|
|
|
[OBREAK] = "break",
|
|
|
|
[OCALL] = "function call", // not actual syntax
|
|
|
|
[OCAP] = "cap",
|
|
|
|
[OCASE] = "case",
|
|
|
|
[OCLOSE] = "close",
|
|
|
|
[OCOMPLEX] = "complex",
|
|
|
|
[OCOM] = "^",
|
|
|
|
[OCONTINUE] = "continue",
|
|
|
|
[OCOPY] = "copy",
|
|
|
|
[ODEC] = "--",
|
2012-01-17 02:00:57 -07:00
|
|
|
[ODELETE] = "delete",
|
2011-10-31 11:09:40 -06:00
|
|
|
[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] = "<-",
|
2013-01-30 13:10:19 -07:00
|
|
|
[ORECOVER] = "recover",
|
2011-10-31 11:09:40 -06:00
|
|
|
[ORETURN] = "return",
|
|
|
|
[ORSH] = ">>",
|
|
|
|
[OSELECT] = "select",
|
|
|
|
[OSEND] = "<-",
|
|
|
|
[OSUB] = "-",
|
|
|
|
[OSWITCH] = "switch",
|
|
|
|
[OXOR] = "^",
|
|
|
|
};
|
|
|
|
|
|
|
|
// Fmt "%O": Node opcodes
|
|
|
|
static int
|
|
|
|
Oconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
int o;
|
|
|
|
|
|
|
|
o = va_arg(fp->args, int);
|
|
|
|
if((fp->flags & FmtSharp) || fmtmode != FDbg)
|
|
|
|
if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
|
|
|
|
return fmtstrcpy(fp, goopnames[o]);
|
|
|
|
|
|
|
|
if(o >= 0 && o < nelem(opnames) && opnames[o] != nil)
|
|
|
|
return fmtstrcpy(fp, opnames[o]);
|
|
|
|
|
|
|
|
return fmtprint(fp, "O-%d", o);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* classnames[] = {
|
|
|
|
"Pxxx",
|
|
|
|
"PEXTERN",
|
|
|
|
"PAUTO",
|
|
|
|
"PPARAM",
|
|
|
|
"PPARAMOUT",
|
|
|
|
"PPARAMREF",
|
|
|
|
"PFUNC",
|
|
|
|
};
|
|
|
|
|
|
|
|
// Fmt "%J": Node details.
|
|
|
|
static int
|
|
|
|
Jconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
char *s;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
n = va_arg(fp->args, Node*);
|
|
|
|
|
|
|
|
c = fp->flags&FmtShort;
|
|
|
|
|
|
|
|
if(!c && n->ullman != 0)
|
|
|
|
fmtprint(fp, " u(%d)", n->ullman);
|
|
|
|
|
|
|
|
if(!c && n->addable != 0)
|
|
|
|
fmtprint(fp, " a(%d)", n->addable);
|
|
|
|
|
|
|
|
if(!c && n->vargen != 0)
|
|
|
|
fmtprint(fp, " g(%d)", n->vargen);
|
|
|
|
|
|
|
|
if(n->lineno != 0)
|
|
|
|
fmtprint(fp, " l(%d)", n->lineno);
|
|
|
|
|
|
|
|
if(!c && n->xoffset != BADWIDTH)
|
2013-01-18 20:08:00 -07:00
|
|
|
fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
switch(n->esc) {
|
|
|
|
case EscUnknown:
|
|
|
|
break;
|
|
|
|
case EscHeap:
|
|
|
|
fmtprint(fp, " esc(h)");
|
|
|
|
break;
|
|
|
|
case EscScope:
|
|
|
|
fmtprint(fp, " esc(s)");
|
|
|
|
break;
|
|
|
|
case EscNone:
|
|
|
|
fmtprint(fp, " esc(no)");
|
|
|
|
break;
|
|
|
|
case EscNever:
|
|
|
|
if(!c)
|
|
|
|
fmtprint(fp, " esc(N)");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fmtprint(fp, " esc(%d)", n->esc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n->escloopdepth)
|
|
|
|
fmtprint(fp, " ld(%d)", n->escloopdepth);
|
|
|
|
|
|
|
|
if(!c && n->typecheck != 0)
|
|
|
|
fmtprint(fp, " tc(%d)", n->typecheck);
|
|
|
|
|
|
|
|
if(!c && 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);
|
|
|
|
|
2011-12-05 12:40:19 -07:00
|
|
|
if(n->embedded != 0)
|
|
|
|
fmtprint(fp, " embedded(%d)", n->embedded);
|
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
if(!c && n->used != 0)
|
|
|
|
fmtprint(fp, " used(%d)", n->used);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt "%V": Values
|
|
|
|
static int
|
|
|
|
Vconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
Val *v;
|
2011-12-08 20:07:43 -07:00
|
|
|
vlong x;
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
v = va_arg(fp->args, Val*);
|
|
|
|
|
|
|
|
switch(v->ctype) {
|
|
|
|
case CTINT:
|
2012-05-22 11:53:38 -06:00
|
|
|
if((fp->flags & FmtSharp) || fmtmode == FExp)
|
|
|
|
return fmtprint(fp, "%#B", v->u.xval);
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtprint(fp, "%B", v->u.xval);
|
2011-12-08 20:07:43 -07:00
|
|
|
case CTRUNE:
|
|
|
|
x = mpgetfix(v->u.xval);
|
2011-12-08 20:43:31 -07:00
|
|
|
if(' ' <= x && x < 0x80 && x != '\\' && x != '\'')
|
2011-12-08 20:07:43 -07:00
|
|
|
return fmtprint(fp, "'%c'", (int)x);
|
|
|
|
if(0 <= x && x < (1<<16))
|
|
|
|
return fmtprint(fp, "'\\u%04ux'", (int)x);
|
|
|
|
if(0 <= x && x <= Runemax)
|
|
|
|
return fmtprint(fp, "'\\U%08llux'", x);
|
|
|
|
return fmtprint(fp, "('\\x00' + %B)", v->u.xval);
|
2011-10-31 11:09:40 -06:00
|
|
|
case CTFLT:
|
2011-12-14 00:22:36 -07:00
|
|
|
if((fp->flags & FmtSharp) || fmtmode == FExp)
|
|
|
|
return fmtprint(fp, "%F", v->u.fval);
|
|
|
|
return fmtprint(fp, "%#F", v->u.fval);
|
|
|
|
case CTCPLX:
|
|
|
|
if((fp->flags & FmtSharp) || fmtmode == FExp)
|
2012-10-17 12:33:44 -06:00
|
|
|
return fmtprint(fp, "(%F+%Fi)", &v->u.cval->real, &v->u.cval->imag);
|
2013-02-01 19:02:15 -07:00
|
|
|
if(mpcmpfltc(&v->u.cval->real, 0) == 0)
|
|
|
|
return fmtprint(fp, "%#Fi", &v->u.cval->imag);
|
|
|
|
if(mpcmpfltc(&v->u.cval->imag, 0) == 0)
|
|
|
|
return fmtprint(fp, "%#F", &v->u.cval->real);
|
|
|
|
if(mpcmpfltc(&v->u.cval->imag, 0) < 0)
|
|
|
|
return fmtprint(fp, "(%#F%#Fi)", &v->u.cval->real, &v->u.cval->imag);
|
|
|
|
return fmtprint(fp, "(%#F+%#Fi)", &v->u.cval->real, &v->u.cval->imag);
|
2011-10-31 11:09:40 -06:00
|
|
|
case CTSTR:
|
|
|
|
return fmtprint(fp, "\"%Z\"", v->u.sval);
|
|
|
|
case CTBOOL:
|
|
|
|
if( v->u.bval)
|
|
|
|
return fmtstrcpy(fp, "true");
|
|
|
|
return fmtstrcpy(fp, "false");
|
|
|
|
case CTNIL:
|
|
|
|
return fmtstrcpy(fp, "nil");
|
|
|
|
}
|
2013-02-01 19:02:15 -07:00
|
|
|
return fmtprint(fp, "<ctype=%d>", v->ctype);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt "%Z": escaped string literals
|
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
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",
|
|
|
|
};
|
|
|
|
|
|
|
|
// Fmt "%E": etype
|
|
|
|
static int
|
|
|
|
Econv(Fmt *fp)
|
|
|
|
{
|
|
|
|
int et;
|
|
|
|
|
|
|
|
et = va_arg(fp->args, int);
|
|
|
|
if(et >= 0 && et < nelem(etnames) && etnames[et] != nil)
|
|
|
|
return fmtstrcpy(fp, etnames[et]);
|
|
|
|
return fmtprint(fp, "E-%d", et);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt "%S": syms
|
|
|
|
static int
|
|
|
|
symfmt(Fmt *fp, Sym *s)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if(s->pkg && !(fp->flags&FmtShort)) {
|
|
|
|
switch(fmtmode) {
|
|
|
|
case FErr: // This is for the user
|
|
|
|
if(s->pkg == localpkg)
|
|
|
|
return fmtstrcpy(fp, s->name);
|
|
|
|
// If the name was used by multiple packages, display the full path,
|
2011-12-05 12:40:19 -07:00
|
|
|
if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1)
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
|
|
|
|
return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
|
|
|
|
case FDbg:
|
|
|
|
return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
|
|
|
|
case FTypeId:
|
|
|
|
if(fp->flags&FmtUnsigned)
|
|
|
|
return fmtprint(fp, "%s.%s", s->pkg->name, s->name); // dcommontype, typehash
|
|
|
|
return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name); // (methodsym), typesym, weaksym
|
|
|
|
case FExp:
|
2012-10-22 02:09:52 -06:00
|
|
|
if(s->name && s->name[0] == '.')
|
|
|
|
fatal("exporting synthetic symbol %s", s->name);
|
2011-12-13 01:15:46 -07:00
|
|
|
if(s->pkg != builtinpkg)
|
|
|
|
return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-05 12:40:19 -07:00
|
|
|
if(fp->flags&FmtByte) { // FmtByte (hh) implies FmtShort (h)
|
2011-10-31 11:09:40 -06:00
|
|
|
// skip leading "type." in method name
|
|
|
|
p = utfrrune(s->name, '.');
|
|
|
|
if(p)
|
2011-12-05 12:40:19 -07:00
|
|
|
p++;
|
|
|
|
else
|
|
|
|
p = s->name;
|
|
|
|
|
|
|
|
// exportname needs to see the name without the prefix too.
|
|
|
|
if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg)
|
|
|
|
return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p);
|
|
|
|
|
|
|
|
return fmtstrcpy(fp, p);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return fmtstrcpy(fp, s->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
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",
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
typefmt(Fmt *fp, Type *t)
|
|
|
|
{
|
|
|
|
Type *t1;
|
2011-11-09 03:27:27 -07:00
|
|
|
Sym *s;
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
if(t == T)
|
|
|
|
return fmtstrcpy(fp, "<T>");
|
|
|
|
|
|
|
|
if (t == bytetype || t == runetype) {
|
|
|
|
// in %-T mode collapse rune and byte with their originals.
|
|
|
|
if(fmtmode != FTypeId)
|
|
|
|
return fmtprint(fp, "%hS", t->sym);
|
|
|
|
t = types[t->etype];
|
|
|
|
}
|
|
|
|
|
2011-11-01 19:46:41 -06:00
|
|
|
if(t == errortype)
|
|
|
|
return fmtstrcpy(fp, "error");
|
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
// Unless the 'l' flag was specified, if the type has a name, just print that name.
|
|
|
|
if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) {
|
|
|
|
switch(fmtmode) {
|
|
|
|
case FTypeId:
|
|
|
|
if(fp->flags&FmtShort)
|
|
|
|
return fmtprint(fp, "%hS", t->sym);
|
|
|
|
if(fp->flags&FmtUnsigned)
|
|
|
|
return fmtprint(fp, "%uS", t->sym);
|
|
|
|
// fallthrough
|
|
|
|
case FExp:
|
|
|
|
if(t->sym->pkg == localpkg && t->vargen)
|
|
|
|
return fmtprint(fp, "%S·%d", t->sym, t->vargen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return fmtprint(fp, "%S", t->sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
|
2012-02-21 20:54:07 -07:00
|
|
|
if(fmtmode == FErr && (t == idealbool || t == idealstring))
|
2011-10-31 11:09:40 -06:00
|
|
|
fmtstrcpy(fp, "ideal ");
|
|
|
|
return fmtstrcpy(fp, basicnames[t->etype]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fmtmode == FDbg)
|
|
|
|
fmtprint(fp, "%E-", t->etype);
|
|
|
|
|
|
|
|
switch(t->etype) {
|
|
|
|
case TPTR32:
|
|
|
|
case TPTR64:
|
|
|
|
if(fmtmode == FTypeId && (fp->flags&FmtShort))
|
|
|
|
return fmtprint(fp, "*%hT", t->type);
|
|
|
|
return fmtprint(fp, "*%T", t->type);
|
|
|
|
|
|
|
|
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 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:
|
2011-12-02 12:45:07 -07:00
|
|
|
return fmtprint(fp, "map[%T]%T", t->down, t->type);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
case TINTER:
|
|
|
|
fmtstrcpy(fp, "interface {");
|
|
|
|
for(t1=t->type; t1!=T; t1=t1->down)
|
2012-01-20 15:14:09 -07:00
|
|
|
if(exportname(t1->sym->name)) {
|
2011-10-31 11:09:40 -06:00
|
|
|
if(t1->down)
|
|
|
|
fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
|
|
|
|
else
|
|
|
|
fmtprint(fp, " %hS%hT ", t1->sym, t1->type);
|
|
|
|
} else {
|
|
|
|
// non-exported method names must be qualified
|
|
|
|
if(t1->down)
|
|
|
|
fmtprint(fp, " %uS%hT;", t1->sym, t1->type);
|
|
|
|
else
|
|
|
|
fmtprint(fp, " %uS%hT ", t1->sym, t1->type);
|
|
|
|
}
|
|
|
|
fmtstrcpy(fp, "}");
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case TFUNC:
|
|
|
|
if(fp->flags & FmtShort) {
|
|
|
|
fmtprint(fp, "%T", getinargx(t));
|
|
|
|
} else {
|
|
|
|
if(t->thistuple)
|
|
|
|
fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t));
|
|
|
|
else
|
|
|
|
fmtprint(fp, "func%T", getinargx(t));
|
|
|
|
}
|
|
|
|
switch(t->outtuple) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
2012-01-11 18:32:02 -07:00
|
|
|
if(fmtmode != FExp) {
|
|
|
|
fmtprint(fp, " %T", getoutargx(t)->type->type); // struct->field->field's type
|
|
|
|
break;
|
|
|
|
}
|
2011-10-31 11:09:40 -06:00
|
|
|
default:
|
|
|
|
fmtprint(fp, " %T", getoutargx(t));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case TSTRUCT:
|
|
|
|
if(t->funarg) {
|
|
|
|
fmtstrcpy(fp, "(");
|
2011-12-15 09:38:47 -07:00
|
|
|
if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape" tags
|
2011-10-31 11:09:40 -06:00
|
|
|
for(t1=t->type; t1!=T; t1=t1->down)
|
|
|
|
if(t1->down)
|
|
|
|
fmtprint(fp, "%hT, ", t1);
|
|
|
|
else
|
|
|
|
fmtprint(fp, "%hT", t1);
|
|
|
|
} else {
|
|
|
|
for(t1=t->type; t1!=T; t1=t1->down)
|
|
|
|
if(t1->down)
|
|
|
|
fmtprint(fp, "%T, ", t1);
|
|
|
|
else
|
|
|
|
fmtprint(fp, "%T", t1);
|
|
|
|
}
|
|
|
|
fmtstrcpy(fp, ")");
|
|
|
|
} else {
|
|
|
|
fmtstrcpy(fp, "struct {");
|
|
|
|
for(t1=t->type; t1!=T; t1=t1->down)
|
|
|
|
if(t1->down)
|
2011-12-05 12:40:19 -07:00
|
|
|
fmtprint(fp, " %lT;", t1);
|
2011-10-31 11:09:40 -06:00
|
|
|
else
|
2011-12-05 12:40:19 -07:00
|
|
|
fmtprint(fp, " %lT ", t1);
|
2011-10-31 11:09:40 -06:00
|
|
|
fmtstrcpy(fp, "}");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case TFIELD:
|
|
|
|
if(!(fp->flags&FmtShort)) {
|
2011-11-09 03:27:27 -07:00
|
|
|
s = t->sym;
|
2012-10-22 02:09:52 -06:00
|
|
|
|
cmd/gc: emit explicit type information for local variables
The type information is (and for years has been) included
as an extra field in the address chunk of an instruction.
Unfortunately, suppose there is a string at a+24(FP) and
we have an instruction reading its length. It will say:
MOVQ x+32(FP), AX
and the type of *that* argument is int (not slice), because
it is the length being read. This confuses the picture seen
by debuggers and now, worse, by the garbage collector.
Instead of attaching the type information to all uses,
emit an explicit list of TYPE instructions with the information.
The TYPE instructions are no-ops whose only role is to
provide an address to attach type information to.
For example, this function:
func f(x, y, z int) (a, b string) {
return
}
now compiles into:
--- prog list "f" ---
0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56
0001 (/Users/rsc/x.go:3) LOCALS ,
0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8
0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8
0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8
0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16
0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16
0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP)
0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP)
0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP)
0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP)
0011 (/Users/rsc/x.go:4) RET ,
The { } show the formerly hidden type information.
The { } syntax is used when printing from within the gc compiler.
It is not accepted by the assemblers.
The same type information is now included on global variables:
0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0)
This more accurate type information fixes a bug in the
garbage collector's precise heap collection.
The linker only cares about globals right now, but having the
local information should make things a little nicer for Carl
in the future.
Fixes #4907.
R=ken2
CC=golang-dev
https://golang.org/cl/7395056
2013-02-25 10:13:47 -07:00
|
|
|
// Take the name from the original, lest we substituted it with ~anon%d
|
|
|
|
if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) {
|
|
|
|
if(t->nname->orig != N) {
|
2012-10-22 02:09:52 -06:00
|
|
|
s = t->nname->orig->sym;
|
cmd/gc: emit explicit type information for local variables
The type information is (and for years has been) included
as an extra field in the address chunk of an instruction.
Unfortunately, suppose there is a string at a+24(FP) and
we have an instruction reading its length. It will say:
MOVQ x+32(FP), AX
and the type of *that* argument is int (not slice), because
it is the length being read. This confuses the picture seen
by debuggers and now, worse, by the garbage collector.
Instead of attaching the type information to all uses,
emit an explicit list of TYPE instructions with the information.
The TYPE instructions are no-ops whose only role is to
provide an address to attach type information to.
For example, this function:
func f(x, y, z int) (a, b string) {
return
}
now compiles into:
--- prog list "f" ---
0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56
0001 (/Users/rsc/x.go:3) LOCALS ,
0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8
0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8
0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8
0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16
0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16
0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP)
0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP)
0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP)
0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP)
0011 (/Users/rsc/x.go:4) RET ,
The { } show the formerly hidden type information.
The { } syntax is used when printing from within the gc compiler.
It is not accepted by the assemblers.
The same type information is now included on global variables:
0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0)
This more accurate type information fixes a bug in the
garbage collector's precise heap collection.
The linker only cares about globals right now, but having the
local information should make things a little nicer for Carl
in the future.
Fixes #4907.
R=ken2
CC=golang-dev
https://golang.org/cl/7395056
2013-02-25 10:13:47 -07:00
|
|
|
if(s != S && s->name[0] == '~')
|
|
|
|
s = S;
|
|
|
|
} else
|
2012-10-22 02:09:52 -06:00
|
|
|
s = S;
|
cmd/gc: emit explicit type information for local variables
The type information is (and for years has been) included
as an extra field in the address chunk of an instruction.
Unfortunately, suppose there is a string at a+24(FP) and
we have an instruction reading its length. It will say:
MOVQ x+32(FP), AX
and the type of *that* argument is int (not slice), because
it is the length being read. This confuses the picture seen
by debuggers and now, worse, by the garbage collector.
Instead of attaching the type information to all uses,
emit an explicit list of TYPE instructions with the information.
The TYPE instructions are no-ops whose only role is to
provide an address to attach type information to.
For example, this function:
func f(x, y, z int) (a, b string) {
return
}
now compiles into:
--- prog list "f" ---
0000 (/Users/rsc/x.go:3) TEXT f+0(SB),$0-56
0001 (/Users/rsc/x.go:3) LOCALS ,
0002 (/Users/rsc/x.go:3) TYPE x+0(FP){int},$8
0003 (/Users/rsc/x.go:3) TYPE y+8(FP){int},$8
0004 (/Users/rsc/x.go:3) TYPE z+16(FP){int},$8
0005 (/Users/rsc/x.go:3) TYPE a+24(FP){string},$16
0006 (/Users/rsc/x.go:3) TYPE b+40(FP){string},$16
0007 (/Users/rsc/x.go:3) MOVQ $0,b+40(FP)
0008 (/Users/rsc/x.go:3) MOVQ $0,b+48(FP)
0009 (/Users/rsc/x.go:3) MOVQ $0,a+24(FP)
0010 (/Users/rsc/x.go:3) MOVQ $0,a+32(FP)
0011 (/Users/rsc/x.go:4) RET ,
The { } show the formerly hidden type information.
The { } syntax is used when printing from within the gc compiler.
It is not accepted by the assemblers.
The same type information is now included on global variables:
0055 (/Users/rsc/x.go:15) GLOBL slice+0(SB){[]string},$24(AL*0)
This more accurate type information fixes a bug in the
garbage collector's precise heap collection.
The linker only cares about globals right now, but having the
local information should make things a little nicer for Carl
in the future.
Fixes #4907.
R=ken2
CC=golang-dev
https://golang.org/cl/7395056
2013-02-25 10:13:47 -07:00
|
|
|
}
|
2011-12-05 12:40:19 -07:00
|
|
|
|
|
|
|
if(s != S && !t->embedded) {
|
2012-11-07 07:59:19 -07:00
|
|
|
if(t->funarg)
|
|
|
|
fmtprint(fp, "%N ", t->nname);
|
|
|
|
else if(fp->flags&FmtLong)
|
2011-12-05 12:40:19 -07:00
|
|
|
fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg)
|
|
|
|
else
|
|
|
|
fmtprint(fp, "%S ", s);
|
|
|
|
} else if(fmtmode == FExp) {
|
|
|
|
// TODO(rsc) this breaks on the eliding of unused arguments in the backend
|
|
|
|
// when this is fixed, the special case in dcl.c checkarglist can go.
|
|
|
|
//if(t->funarg)
|
|
|
|
// fmtstrcpy(fp, "_ ");
|
|
|
|
//else
|
2011-11-09 03:27:27 -07:00
|
|
|
fmtstrcpy(fp, "? ");
|
|
|
|
}
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(t->isddd)
|
|
|
|
fmtprint(fp, "...%T", t->type->type);
|
|
|
|
else
|
|
|
|
fmtprint(fp, "%T", t->type);
|
|
|
|
|
|
|
|
if(!(fp->flags&FmtShort) && t->note)
|
|
|
|
fmtprint(fp, " \"%Z\"", t->note);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case TFORW:
|
|
|
|
if(t->sym)
|
|
|
|
return fmtprint(fp, "undefined %S", t->sym);
|
|
|
|
return fmtstrcpy(fp, "undefined");
|
|
|
|
|
|
|
|
case TUNSAFEPTR:
|
|
|
|
if(fmtmode == FExp)
|
|
|
|
return fmtprint(fp, "@\"unsafe\".Pointer");
|
|
|
|
return fmtprint(fp, "unsafe.Pointer");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fmtmode == FExp)
|
|
|
|
fatal("missing %E case during export", t->etype);
|
|
|
|
// Don't know how to handle - fall back to detailed prints.
|
|
|
|
return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Statements which may be rendered with a simplestmt as init.
|
|
|
|
static int
|
|
|
|
stmtwithinit(int op)
|
|
|
|
{
|
|
|
|
switch(op) {
|
|
|
|
case OIF:
|
|
|
|
case OFOR:
|
|
|
|
case OSWITCH:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
stmtfmt(Fmt *f, Node *n)
|
|
|
|
{
|
|
|
|
int complexinit, simpleinit, extrablock;
|
|
|
|
|
|
|
|
// some statements allow for an init, but at most one,
|
|
|
|
// but we may have an arbitrary number added, eg by typecheck
|
|
|
|
// and inlining. If it doesn't fit the syntax, emit an enclosing
|
|
|
|
// block starting with the init statements.
|
|
|
|
|
|
|
|
// if we can just say "for" n->ninit; ... then do so
|
|
|
|
simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op);
|
|
|
|
// otherwise, print the inits as separate statements
|
|
|
|
complexinit = n->ninit && !simpleinit && (fmtmode != FErr);
|
|
|
|
// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
|
|
|
|
extrablock = complexinit && stmtwithinit(n->op);
|
|
|
|
|
|
|
|
if(extrablock)
|
|
|
|
fmtstrcpy(f, "{");
|
|
|
|
|
|
|
|
if(complexinit)
|
|
|
|
fmtprint(f, " %H; ", n->ninit);
|
|
|
|
|
|
|
|
switch(n->op){
|
|
|
|
case ODCL:
|
2012-11-07 07:59:19 -07:00
|
|
|
if(fmtmode == FExp) {
|
|
|
|
switch(n->left->class&~PHEAP) {
|
|
|
|
case PPARAM:
|
|
|
|
case PPARAMOUT:
|
|
|
|
case PAUTO:
|
|
|
|
fmtprint(f, "var %N %T", n->left, n->left->type);
|
|
|
|
goto ret;
|
|
|
|
}
|
|
|
|
}
|
2011-12-05 12:40:19 -07:00
|
|
|
fmtprint(f, "var %S %T", n->left->sym, n->left->type);
|
2011-10-31 11:09:40 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ODCLFIELD:
|
|
|
|
if(n->left)
|
|
|
|
fmtprint(f, "%N %N", n->left, n->right);
|
|
|
|
else
|
|
|
|
fmtprint(f, "%N", n->right);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OAS:
|
2012-10-29 06:55:27 -06:00
|
|
|
// Don't export "v = <N>" initializing statements, hope they're always
|
|
|
|
// preceded by the DCL which will be re-parsed and typecheck to reproduce
|
|
|
|
// the "v = <N>" again.
|
|
|
|
if(fmtmode == FExp && n->right == N)
|
|
|
|
break;
|
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
if(n->colas && !complexinit)
|
|
|
|
fmtprint(f, "%N := %N", n->left, n->right);
|
|
|
|
else
|
|
|
|
fmtprint(f, "%N = %N", n->left, n->right);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OASOP:
|
|
|
|
fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OAS2:
|
|
|
|
if(n->colas && !complexinit) {
|
|
|
|
fmtprint(f, "%,H := %,H", n->list, n->rlist);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fallthrough
|
|
|
|
case OAS2DOTTYPE:
|
|
|
|
case OAS2FUNC:
|
|
|
|
case OAS2MAPR:
|
|
|
|
case OAS2RECV:
|
|
|
|
fmtprint(f, "%,H = %,H", n->list, n->rlist);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ORETURN:
|
|
|
|
fmtprint(f, "return %,H", n->list);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPROC:
|
|
|
|
fmtprint(f, "go %N", n->left);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ODEFER:
|
|
|
|
fmtprint(f, "defer %N", n->left);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OIF:
|
|
|
|
if(simpleinit)
|
|
|
|
fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody);
|
|
|
|
else
|
|
|
|
fmtprint(f, "if %N { %H }", n->ntest, n->nbody);
|
|
|
|
if(n->nelse)
|
|
|
|
fmtprint(f, " else { %H }", n->nelse);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OFOR:
|
|
|
|
if(fmtmode == FErr) { // TODO maybe only if FmtShort, same below
|
|
|
|
fmtstrcpy(f, "for loop");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmtstrcpy(f, "for");
|
|
|
|
if(simpleinit)
|
|
|
|
fmtprint(f, " %N;", n->ninit->n);
|
|
|
|
else if(n->nincr)
|
|
|
|
fmtstrcpy(f, " ;");
|
|
|
|
|
|
|
|
if(n->ntest)
|
|
|
|
fmtprint(f, " %N", n->ntest);
|
|
|
|
|
|
|
|
if(n->nincr)
|
|
|
|
fmtprint(f, "; %N", n->nincr);
|
|
|
|
else if(simpleinit)
|
|
|
|
fmtstrcpy(f, ";");
|
|
|
|
|
|
|
|
|
|
|
|
fmtprint(f, " { %H }", n->nbody);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ORANGE:
|
|
|
|
if(fmtmode == FErr) {
|
|
|
|
fmtstrcpy(f, "for loop");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OSELECT:
|
|
|
|
case OSWITCH:
|
|
|
|
if(fmtmode == FErr) {
|
|
|
|
fmtprint(f, "%O statement", n->op);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmtprint(f, "%#O", n->op);
|
|
|
|
if(simpleinit)
|
|
|
|
fmtprint(f, " %N;", n->ninit->n);
|
|
|
|
if(n->ntest)
|
|
|
|
fmtprint(f, "%N", n->ntest);
|
|
|
|
|
|
|
|
fmtprint(f, " { %H }", n->list);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCASE:
|
|
|
|
case OXCASE:
|
|
|
|
if(n->list)
|
|
|
|
fmtprint(f, "case %,H: %H", n->list, n->nbody);
|
|
|
|
else
|
|
|
|
fmtprint(f, "default: %H", n->nbody);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBREAK:
|
|
|
|
case OCONTINUE:
|
|
|
|
case OGOTO:
|
|
|
|
case OFALL:
|
|
|
|
case OXFALL:
|
|
|
|
if(n->left)
|
|
|
|
fmtprint(f, "%#O %N", n->op, n->left);
|
|
|
|
else
|
|
|
|
fmtprint(f, "%#O", n->op);
|
|
|
|
break;
|
2011-12-15 09:35:59 -07:00
|
|
|
|
2011-12-15 09:50:59 -07:00
|
|
|
case OEMPTY:
|
|
|
|
break;
|
|
|
|
|
2011-12-15 09:35:59 -07:00
|
|
|
case OLABEL:
|
|
|
|
fmtprint(f, "%N: ", n->left);
|
|
|
|
break;
|
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
2012-11-07 07:59:19 -07:00
|
|
|
ret:
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
if(extrablock)
|
|
|
|
fmtstrcpy(f, "}");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int opprec[] = {
|
|
|
|
[OAPPEND] = 8,
|
|
|
|
[OARRAYBYTESTR] = 8,
|
2012-01-10 13:24:31 -07:00
|
|
|
[OARRAYLIT] = 8,
|
2012-01-18 01:52:16 -07:00
|
|
|
[OARRAYRUNESTR] = 8,
|
2011-10-31 11:09:40 -06:00
|
|
|
[OCALLFUNC] = 8,
|
|
|
|
[OCALLINTER] = 8,
|
|
|
|
[OCALLMETH] = 8,
|
|
|
|
[OCALL] = 8,
|
|
|
|
[OCAP] = 8,
|
|
|
|
[OCLOSE] = 8,
|
|
|
|
[OCONVIFACE] = 8,
|
|
|
|
[OCONVNOP] = 8,
|
|
|
|
[OCONV] = 8,
|
|
|
|
[OCOPY] = 8,
|
2012-01-17 02:00:57 -07:00
|
|
|
[ODELETE] = 8,
|
2011-10-31 11:09:40 -06:00
|
|
|
[OLEN] = 8,
|
|
|
|
[OLITERAL] = 8,
|
|
|
|
[OMAKESLICE] = 8,
|
|
|
|
[OMAKE] = 8,
|
2012-01-10 13:24:31 -07:00
|
|
|
[OMAPLIT] = 8,
|
2011-10-31 11:09:40 -06:00
|
|
|
[ONAME] = 8,
|
|
|
|
[ONEW] = 8,
|
|
|
|
[ONONAME] = 8,
|
|
|
|
[OPACK] = 8,
|
|
|
|
[OPANIC] = 8,
|
|
|
|
[OPAREN] = 8,
|
|
|
|
[OPRINTN] = 8,
|
|
|
|
[OPRINT] = 8,
|
|
|
|
[ORUNESTR] = 8,
|
2012-01-18 01:52:16 -07:00
|
|
|
[OSTRARRAYBYTE] = 8,
|
|
|
|
[OSTRARRAYRUNE] = 8,
|
2011-12-05 12:40:19 -07:00
|
|
|
[OSTRUCTLIT] = 8,
|
2012-01-10 13:24:31 -07:00
|
|
|
[OTARRAY] = 8,
|
|
|
|
[OTCHAN] = 8,
|
|
|
|
[OTFUNC] = 8,
|
|
|
|
[OTINTER] = 8,
|
|
|
|
[OTMAP] = 8,
|
|
|
|
[OTPAREN] = 8,
|
|
|
|
[OTSTRUCT] = 8,
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
[OINDEXMAP] = 8,
|
|
|
|
[OINDEX] = 8,
|
2011-12-05 12:40:19 -07:00
|
|
|
[OSLICE] = 8,
|
|
|
|
[OSLICESTR] = 8,
|
|
|
|
[OSLICEARR] = 8,
|
2011-10-31 11:09:40 -06:00
|
|
|
[ODOTINTER] = 8,
|
|
|
|
[ODOTMETH] = 8,
|
|
|
|
[ODOTPTR] = 8,
|
|
|
|
[ODOTTYPE2] = 8,
|
|
|
|
[ODOTTYPE] = 8,
|
|
|
|
[ODOT] = 8,
|
|
|
|
[OXDOT] = 8,
|
2013-03-20 21:53:27 -06:00
|
|
|
[OCALLPART] = 8,
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
[OPLUS] = 7,
|
|
|
|
[ONOT] = 7,
|
|
|
|
[OCOM] = 7,
|
|
|
|
[OMINUS] = 7,
|
|
|
|
[OADDR] = 7,
|
|
|
|
[OIND] = 7,
|
2012-07-31 16:45:26 -06:00
|
|
|
[ORECV] = 7,
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
[OMUL] = 6,
|
|
|
|
[ODIV] = 6,
|
|
|
|
[OMOD] = 6,
|
|
|
|
[OLSH] = 6,
|
|
|
|
[ORSH] = 6,
|
|
|
|
[OAND] = 6,
|
|
|
|
[OANDNOT] = 6,
|
|
|
|
|
|
|
|
[OADD] = 5,
|
|
|
|
[OSUB] = 5,
|
|
|
|
[OOR] = 5,
|
|
|
|
[OXOR] = 5,
|
|
|
|
|
|
|
|
[OEQ] = 4,
|
|
|
|
[OLT] = 4,
|
|
|
|
[OLE] = 4,
|
|
|
|
[OGE] = 4,
|
|
|
|
[OGT] = 4,
|
|
|
|
[ONE] = 4,
|
|
|
|
[OCMPSTR] = 4,
|
2012-01-17 02:00:57 -07:00
|
|
|
[OCMPIFACE] = 4,
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
[OSEND] = 3,
|
|
|
|
[OANDAND] = 2,
|
|
|
|
[OOROR] = 1,
|
|
|
|
|
|
|
|
// Statements handled by stmtfmt
|
|
|
|
[OAS] = -1,
|
|
|
|
[OAS2] = -1,
|
|
|
|
[OAS2DOTTYPE] = -1,
|
|
|
|
[OAS2FUNC] = -1,
|
|
|
|
[OAS2MAPR] = -1,
|
|
|
|
[OAS2RECV] = -1,
|
|
|
|
[OASOP] = -1,
|
|
|
|
[OBREAK] = -1,
|
|
|
|
[OCASE] = -1,
|
|
|
|
[OCONTINUE] = -1,
|
|
|
|
[ODCL] = -1,
|
|
|
|
[ODCLFIELD] = -1,
|
|
|
|
[ODEFER] = -1,
|
2011-12-15 09:50:59 -07:00
|
|
|
[OEMPTY] = -1,
|
2011-10-31 11:09:40 -06:00
|
|
|
[OFALL] = -1,
|
|
|
|
[OFOR] = -1,
|
|
|
|
[OIF] = -1,
|
2011-12-15 09:35:59 -07:00
|
|
|
[OLABEL] = -1,
|
2011-10-31 11:09:40 -06:00
|
|
|
[OPROC] = -1,
|
|
|
|
[ORANGE] = -1,
|
|
|
|
[ORETURN] = -1,
|
|
|
|
[OSELECT] = -1,
|
|
|
|
[OSWITCH] = -1,
|
|
|
|
[OXCASE] = -1,
|
|
|
|
[OXFALL] = -1,
|
|
|
|
|
|
|
|
[OEND] = 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
exprfmt(Fmt *f, Node *n, int prec)
|
|
|
|
{
|
|
|
|
int nprec;
|
2013-03-04 08:42:03 -07:00
|
|
|
int ptrlit;
|
2011-12-05 12:40:19 -07:00
|
|
|
NodeList *l;
|
2011-10-31 11:09:40 -06:00
|
|
|
|
2012-02-08 22:26:08 -07:00
|
|
|
while(n && n->implicit && (n->op == OIND || n->op == OADDR))
|
2011-10-31 11:09:40 -06:00
|
|
|
n = n->left;
|
|
|
|
|
|
|
|
if(n == N)
|
|
|
|
return fmtstrcpy(f, "<N>");
|
|
|
|
|
|
|
|
nprec = opprec[n->op];
|
|
|
|
if(n->op == OTYPE && n->sym != S)
|
|
|
|
nprec = 8;
|
|
|
|
|
|
|
|
if(prec > nprec)
|
|
|
|
return fmtprint(f, "(%N)", n);
|
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
case OPAREN:
|
|
|
|
return fmtprint(f, "(%N)", n->left);
|
|
|
|
|
|
|
|
case ODDDARG:
|
|
|
|
return fmtprint(f, "... argument");
|
|
|
|
|
|
|
|
case OREGISTER:
|
|
|
|
return fmtprint(f, "%R", n->val.u.reg);
|
|
|
|
|
2012-01-11 13:26:54 -07:00
|
|
|
case OLITERAL: // this is a bit of a mess
|
2011-10-31 11:09:40 -06:00
|
|
|
if(fmtmode == FErr && n->sym != S)
|
|
|
|
return fmtprint(f, "%S", n->sym);
|
2013-02-01 19:02:15 -07:00
|
|
|
if(n->val.ctype == CTNIL && n->orig != N && n->orig != n)
|
|
|
|
return exprfmt(f, n->orig, prec);
|
2012-10-07 13:35:01 -06:00
|
|
|
if(n->type != T && n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) {
|
2012-01-11 14:21:06 -07:00
|
|
|
// Need parens when type begins with what might
|
|
|
|
// be misinterpreted as a unary operator: * or <-.
|
|
|
|
if(isptr[n->type->etype] || (n->type->etype == TCHAN && n->type->chan == Crecv))
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtprint(f, "(%T)(%V)", n->type, &n->val);
|
|
|
|
else
|
|
|
|
return fmtprint(f, "%T(%V)", n->type, &n->val);
|
|
|
|
}
|
|
|
|
return fmtprint(f, "%V", &n->val);
|
|
|
|
|
|
|
|
case ONAME:
|
2012-11-07 07:59:19 -07:00
|
|
|
// Special case: name used as local variable in export.
|
|
|
|
switch(n->class&~PHEAP){
|
|
|
|
case PAUTO:
|
|
|
|
case PPARAM:
|
|
|
|
case PPARAMOUT:
|
|
|
|
if(fmtmode == FExp && n->sym && !isblanksym(n->sym) && n->vargen > 0)
|
|
|
|
return fmtprint(f, "%S·%d", n->sym, n->vargen);
|
|
|
|
}
|
|
|
|
|
2012-02-06 08:38:59 -07:00
|
|
|
// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
|
|
|
|
// but for export, this should be rendered as (*pkg.T).meth.
|
|
|
|
// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
|
|
|
|
if(fmtmode == FExp && n->left && n->left->op == OTYPE && n->right && n->right->op == ONAME) {
|
|
|
|
if(isptr[n->left->type->etype])
|
|
|
|
return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym);
|
|
|
|
else
|
|
|
|
return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym);
|
|
|
|
}
|
|
|
|
//fallthrough
|
2011-10-31 11:09:40 -06:00
|
|
|
case OPACK:
|
|
|
|
case ONONAME:
|
|
|
|
return fmtprint(f, "%S", n->sym);
|
|
|
|
|
|
|
|
case OTYPE:
|
|
|
|
if(n->type == T && n->sym != S)
|
|
|
|
return fmtprint(f, "%S", n->sym);
|
|
|
|
return fmtprint(f, "%T", n->type);
|
|
|
|
|
|
|
|
case OTARRAY:
|
2011-12-13 01:15:46 -07:00
|
|
|
if(n->left)
|
|
|
|
return fmtprint(f, "[]%N", n->left);
|
|
|
|
return fmtprint(f, "[]%N", n->right); // happens before typecheck
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
case OTPAREN:
|
|
|
|
return fmtprint(f, "(%N)", n->left);
|
|
|
|
|
|
|
|
case OTMAP:
|
2011-12-02 12:45:07 -07:00
|
|
|
return fmtprint(f, "map[%N]%N", n->left, n->right);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
case OTCHAN:
|
|
|
|
switch(n->etype) {
|
|
|
|
case Crecv:
|
|
|
|
return fmtprint(f, "<-chan %N", n->left);
|
|
|
|
case Csend:
|
|
|
|
return fmtprint(f, "chan<- %N", n->left);
|
|
|
|
default:
|
|
|
|
if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv)
|
|
|
|
return fmtprint(f, "chan (%N)", n->left);
|
|
|
|
else
|
|
|
|
return fmtprint(f, "chan %N", n->left);
|
|
|
|
}
|
|
|
|
|
|
|
|
case OTSTRUCT:
|
|
|
|
return fmtprint(f, "<struct>");
|
|
|
|
|
|
|
|
case OTINTER:
|
|
|
|
return fmtprint(f, "<inter>");
|
|
|
|
|
|
|
|
case OTFUNC:
|
|
|
|
return fmtprint(f, "<func>");
|
|
|
|
|
|
|
|
case OCLOSURE:
|
|
|
|
if(fmtmode == FErr)
|
|
|
|
return fmtstrcpy(f, "func literal");
|
2012-06-04 15:07:59 -06:00
|
|
|
if(n->nbody)
|
|
|
|
return fmtprint(f, "%T { %H }", n->type, n->nbody);
|
|
|
|
return fmtprint(f, "%T { %H }", n->type, n->closure->nbody);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
case OCOMPLIT:
|
2013-03-04 08:42:03 -07:00
|
|
|
ptrlit = n->right != N && n->right->implicit && n->right->type && isptr[n->right->type->etype];
|
|
|
|
if(fmtmode == FErr) {
|
|
|
|
if(n->right != N && n->right->type != T && !n->implicit) {
|
|
|
|
if(ptrlit)
|
|
|
|
return fmtprint(f, "&%T literal", n->right->type->type);
|
|
|
|
else
|
|
|
|
return fmtprint(f, "%T literal", n->right->type);
|
|
|
|
}
|
2011-12-13 01:15:46 -07:00
|
|
|
return fmtstrcpy(f, "composite literal");
|
2013-03-04 08:42:03 -07:00
|
|
|
}
|
|
|
|
if(fmtmode == FExp && ptrlit)
|
|
|
|
// typecheck has overwritten OIND by OTYPE with pointer type.
|
|
|
|
return fmtprint(f, "&%T{ %,H }", n->right->type->type, n->list);
|
2012-10-22 00:38:23 -06:00
|
|
|
return fmtprint(f, "(%N{ %,H })", n->right, n->list);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
2011-12-02 12:13:12 -07:00
|
|
|
case OPTRLIT:
|
2013-03-04 08:42:03 -07:00
|
|
|
if(fmtmode == FExp && n->left->implicit)
|
2012-02-06 04:19:59 -07:00
|
|
|
return fmtprint(f, "%N", n->left);
|
2011-12-05 12:40:19 -07:00
|
|
|
return fmtprint(f, "&%N", n->left);
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
2012-02-08 22:26:08 -07:00
|
|
|
if(fmtmode == FExp) { // requires special handling of field names
|
|
|
|
if(n->implicit)
|
2012-02-06 04:19:59 -07:00
|
|
|
fmtstrcpy(f, "{");
|
2012-10-22 00:38:23 -06:00
|
|
|
else
|
|
|
|
fmtprint(f, "(%T{", n->type);
|
2012-01-18 09:51:28 -07:00
|
|
|
for(l=n->list; l; l=l->next) {
|
2012-12-22 11:16:31 -07:00
|
|
|
fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right);
|
2012-01-18 09:51:28 -07:00
|
|
|
|
2011-12-05 12:40:19 -07:00
|
|
|
if(l->next)
|
2012-01-18 09:51:28 -07:00
|
|
|
fmtstrcpy(f, ",");
|
2011-12-05 12:40:19 -07:00
|
|
|
else
|
2012-01-18 09:51:28 -07:00
|
|
|
fmtstrcpy(f, " ");
|
|
|
|
}
|
2013-03-04 08:42:03 -07:00
|
|
|
if(!n->implicit)
|
2012-10-22 00:38:23 -06:00
|
|
|
return fmtstrcpy(f, "})");
|
2011-12-05 12:40:19 -07:00
|
|
|
return fmtstrcpy(f, "}");
|
|
|
|
}
|
|
|
|
// fallthrough
|
2011-12-02 12:13:12 -07:00
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
case OARRAYLIT:
|
|
|
|
case OMAPLIT:
|
|
|
|
if(fmtmode == FErr)
|
|
|
|
return fmtprint(f, "%T literal", n->type);
|
2012-02-08 22:26:08 -07:00
|
|
|
if(fmtmode == FExp && n->implicit)
|
|
|
|
return fmtprint(f, "{ %,H }", n->list);
|
2012-10-22 00:38:23 -06:00
|
|
|
return fmtprint(f, "(%T{ %,H })", n->type, n->list);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
case OKEY:
|
2013-03-04 08:42:03 -07:00
|
|
|
if(n->left && n->right) {
|
|
|
|
if(fmtmode == FExp && n->left->type && n->left->type->etype == TFIELD) {
|
|
|
|
// requires special handling of field names
|
|
|
|
return fmtprint(f, "%hhS:%N", n->left->sym, n->right);
|
|
|
|
} else
|
|
|
|
return fmtprint(f, "%N:%N", n->left, n->right);
|
|
|
|
}
|
2011-10-31 11:09:40 -06:00
|
|
|
if(!n->left && n->right)
|
|
|
|
return fmtprint(f, ":%N", n->right);
|
|
|
|
if(n->left && !n->right)
|
|
|
|
return fmtprint(f, "%N:", n->left);
|
|
|
|
return fmtstrcpy(f, ":");
|
|
|
|
|
|
|
|
case OXDOT:
|
|
|
|
case ODOT:
|
|
|
|
case ODOTPTR:
|
|
|
|
case ODOTINTER:
|
|
|
|
case ODOTMETH:
|
2013-03-20 21:53:27 -06:00
|
|
|
case OCALLPART:
|
2011-10-31 11:09:40 -06:00
|
|
|
exprfmt(f, n->left, nprec);
|
|
|
|
if(n->right == N || n->right->sym == S)
|
2013-03-20 21:53:27 -06:00
|
|
|
return fmtstrcpy(f, ".<nil>");
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtprint(f, ".%hhS", n->right->sym);
|
|
|
|
|
|
|
|
case ODOTTYPE:
|
|
|
|
case ODOTTYPE2:
|
|
|
|
exprfmt(f, n->left, nprec);
|
|
|
|
if(n->right != N)
|
|
|
|
return fmtprint(f, ".(%N)", n->right);
|
|
|
|
return fmtprint(f, ".(%T)", n->type);
|
|
|
|
|
|
|
|
case OINDEX:
|
|
|
|
case OINDEXMAP:
|
|
|
|
case OSLICE:
|
|
|
|
case OSLICESTR:
|
|
|
|
case OSLICEARR:
|
|
|
|
exprfmt(f, n->left, nprec);
|
|
|
|
return fmtprint(f, "[%N]", n->right);
|
|
|
|
|
2011-11-02 08:36:33 -06:00
|
|
|
case OCOPY:
|
2011-10-31 11:09:40 -06:00
|
|
|
case OCOMPLEX:
|
|
|
|
return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right);
|
|
|
|
|
|
|
|
case OCONV:
|
|
|
|
case OCONVIFACE:
|
|
|
|
case OCONVNOP:
|
|
|
|
case OARRAYBYTESTR:
|
2012-01-18 01:52:16 -07:00
|
|
|
case OARRAYRUNESTR:
|
2011-10-31 11:09:40 -06:00
|
|
|
case OSTRARRAYBYTE:
|
2012-01-18 01:52:16 -07:00
|
|
|
case OSTRARRAYRUNE:
|
2011-10-31 11:09:40 -06:00
|
|
|
case ORUNESTR:
|
|
|
|
if(n->type == T || n->type->sym == S)
|
|
|
|
return fmtprint(f, "(%T)(%N)", n->type, n->left);
|
|
|
|
if(n->left)
|
|
|
|
return fmtprint(f, "%T(%N)", n->type, n->left);
|
|
|
|
return fmtprint(f, "%T(%,H)", n->type, n->list);
|
|
|
|
|
|
|
|
case OREAL:
|
|
|
|
case OIMAG:
|
|
|
|
case OAPPEND:
|
|
|
|
case OCAP:
|
|
|
|
case OCLOSE:
|
2012-01-17 02:00:57 -07:00
|
|
|
case ODELETE:
|
2011-10-31 11:09:40 -06:00
|
|
|
case OLEN:
|
|
|
|
case OMAKE:
|
|
|
|
case ONEW:
|
|
|
|
case OPANIC:
|
2013-01-30 13:10:19 -07:00
|
|
|
case ORECOVER:
|
2011-10-31 11:09:40 -06:00
|
|
|
case OPRINT:
|
|
|
|
case OPRINTN:
|
|
|
|
if(n->left)
|
|
|
|
return fmtprint(f, "%#O(%N)", n->op, n->left);
|
|
|
|
if(n->isddd)
|
|
|
|
return fmtprint(f, "%#O(%,H...)", n->op, n->list);
|
|
|
|
return fmtprint(f, "%#O(%,H)", n->op, n->list);
|
|
|
|
|
|
|
|
case OCALL:
|
|
|
|
case OCALLFUNC:
|
|
|
|
case OCALLINTER:
|
|
|
|
case OCALLMETH:
|
|
|
|
exprfmt(f, n->left, nprec);
|
|
|
|
if(n->isddd)
|
|
|
|
return fmtprint(f, "(%,H...)", n->list);
|
|
|
|
return fmtprint(f, "(%,H)", n->list);
|
|
|
|
|
|
|
|
case OMAKEMAP:
|
|
|
|
case OMAKECHAN:
|
2011-11-02 08:36:33 -06:00
|
|
|
case OMAKESLICE:
|
2012-01-25 15:53:50 -07:00
|
|
|
if(n->list) // pre-typecheck
|
|
|
|
return fmtprint(f, "make(%T, %,H)", n->type, n->list);
|
|
|
|
if(n->right)
|
|
|
|
return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right);
|
|
|
|
if(n->left)
|
|
|
|
return fmtprint(f, "make(%T, %N)", n->type, n->left);
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtprint(f, "make(%T)", n->type);
|
|
|
|
|
2011-12-05 12:40:19 -07:00
|
|
|
// Unary
|
|
|
|
case OPLUS:
|
|
|
|
case OMINUS:
|
|
|
|
case OADDR:
|
|
|
|
case OCOM:
|
|
|
|
case OIND:
|
|
|
|
case ONOT:
|
|
|
|
case ORECV:
|
|
|
|
if(n->left->op == n->op)
|
|
|
|
fmtprint(f, "%#O ", n->op);
|
|
|
|
else
|
|
|
|
fmtprint(f, "%#O", n->op);
|
|
|
|
return exprfmt(f, n->left, nprec+1);
|
|
|
|
|
|
|
|
// Binary
|
2011-10-31 11:09:40 -06:00
|
|
|
case OADD:
|
|
|
|
case OADDSTR:
|
|
|
|
case OAND:
|
|
|
|
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);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case OCMPSTR:
|
2012-01-17 02:00:57 -07:00
|
|
|
case OCMPIFACE:
|
2011-10-31 11:09:40 -06:00
|
|
|
exprfmt(f, n->left, nprec);
|
|
|
|
fmtprint(f, " %#O ", n->etype);
|
|
|
|
exprfmt(f, n->right, nprec+1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmtprint(f, "<node %O>", n->op);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
nodefmt(Fmt *f, Node *n)
|
|
|
|
{
|
2011-12-14 09:34:35 -07:00
|
|
|
Type *t;
|
|
|
|
|
|
|
|
t = n->type;
|
2012-01-10 13:24:31 -07:00
|
|
|
|
|
|
|
// we almost always want the original, except in export mode for literals
|
|
|
|
// this saves the importer some work, and avoids us having to redo some
|
|
|
|
// special casing for package unsafe
|
2012-02-21 22:29:23 -07:00
|
|
|
if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N)
|
2011-12-14 09:34:35 -07:00
|
|
|
n = n->orig;
|
2011-10-31 11:09:40 -06:00
|
|
|
|
2011-12-14 09:34:35 -07:00
|
|
|
if(f->flags&FmtLong && t != T) {
|
|
|
|
if(t->etype == TNIL)
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtprint(f, "nil");
|
|
|
|
else
|
2011-12-14 09:34:35 -07:00
|
|
|
return fmtprint(f, "%N (type %T)", n, t);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO inlining produces expressions with ninits. we can't print these yet.
|
|
|
|
|
|
|
|
if(opprec[n->op] < 0)
|
|
|
|
return stmtfmt(f, n);
|
|
|
|
|
|
|
|
return exprfmt(f, n, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dumpdepth;
|
|
|
|
|
|
|
|
static void
|
|
|
|
indent(Fmt *fp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2011-12-05 12:40:19 -07:00
|
|
|
fmtstrcpy(fp, "\n");
|
2011-10-31 11:09:40 -06:00
|
|
|
for(i = 0; i < dumpdepth; ++i)
|
|
|
|
fmtstrcpy(fp, ". ");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
nodedump(Fmt *fp, Node *n)
|
|
|
|
{
|
|
|
|
int recur;
|
|
|
|
|
|
|
|
if(n == N)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
recur = !(fp->flags&FmtShort);
|
|
|
|
|
|
|
|
if(recur) {
|
|
|
|
indent(fp);
|
|
|
|
if(dumpdepth > 10)
|
2011-11-14 02:08:04 -07:00
|
|
|
return fmtstrcpy(fp, "...");
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
if(n->ninit != nil) {
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-init%H", n->op, n->ninit);
|
2011-10-31 11:09:40 -06:00
|
|
|
indent(fp);
|
|
|
|
}
|
|
|
|
}
|
2012-01-18 01:52:16 -07:00
|
|
|
|
|
|
|
// fmtprint(fp, "[%p]", n);
|
2011-10-31 11:09:40 -06:00
|
|
|
|
|
|
|
switch(n->op) {
|
|
|
|
default:
|
|
|
|
fmtprint(fp, "%O%J", n->op, n);
|
|
|
|
break;
|
|
|
|
case OREGISTER:
|
2012-11-02 00:50:59 -06:00
|
|
|
case OINDREG:
|
2011-10-31 11:09:40 -06:00
|
|
|
fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
|
|
|
|
break;
|
|
|
|
case OLITERAL:
|
|
|
|
fmtprint(fp, "%O-%V%J", n->op, &n->val, n);
|
|
|
|
break;
|
|
|
|
case ONAME:
|
|
|
|
case ONONAME:
|
|
|
|
if(n->sym != S)
|
|
|
|
fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
|
|
|
|
else
|
|
|
|
fmtprint(fp, "%O%J", n->op, n);
|
2012-10-29 06:55:27 -06:00
|
|
|
if(recur && n->type == T && n->ntype) {
|
|
|
|
indent(fp);
|
|
|
|
fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
|
|
|
|
}
|
2011-10-31 11:09:40 -06:00
|
|
|
break;
|
|
|
|
case OASOP:
|
|
|
|
fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
|
|
|
|
break;
|
|
|
|
case OTYPE:
|
2012-02-06 04:19:59 -07:00
|
|
|
fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type);
|
2011-10-31 11:09:40 -06:00
|
|
|
if(recur && n->type == T && n->ntype) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n->sym != S && n->op != ONAME)
|
|
|
|
fmtprint(fp, " %S G%d", n->sym, n->vargen);
|
|
|
|
|
|
|
|
if(n->type != T)
|
|
|
|
fmtprint(fp, " %T", n->type);
|
|
|
|
|
|
|
|
if(recur) {
|
|
|
|
if(n->left)
|
|
|
|
fmtprint(fp, "%N", n->left);
|
|
|
|
if(n->right)
|
|
|
|
fmtprint(fp, "%N", n->right);
|
|
|
|
if(n->list) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-list%H", n->op, n->list);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
if(n->rlist) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-rlist%H", n->op, n->rlist);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
if(n->ntest) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-test%N", n->op, n->ntest);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
if(n->nbody) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-body%H", n->op, n->nbody);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
if(n->nelse) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-else%H", n->op, n->nelse);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
if(n->nincr) {
|
|
|
|
indent(fp);
|
2011-11-14 02:08:04 -07:00
|
|
|
fmtprint(fp, "%O-incr%N", n->op, n->nincr);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt "%S": syms
|
|
|
|
// Flags: "%hS" suppresses qualifying with package
|
|
|
|
static int
|
|
|
|
Sconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
Sym *s;
|
|
|
|
int r, sm;
|
|
|
|
unsigned long sf;
|
|
|
|
|
|
|
|
s = va_arg(fp->args, Sym*);
|
|
|
|
if(s == S)
|
|
|
|
return fmtstrcpy(fp, "<S>");
|
|
|
|
|
2011-12-13 01:15:46 -07:00
|
|
|
if(s->name && s->name[0] == '_' && s->name[1] == '\0')
|
2011-12-05 12:40:19 -07:00
|
|
|
return fmtstrcpy(fp, "_");
|
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
sf = fp->flags;
|
|
|
|
sm = setfmode(&fp->flags);
|
|
|
|
r = symfmt(fp, s);
|
|
|
|
fp->flags = sf;
|
|
|
|
fmtmode = sm;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt "%T": types.
|
|
|
|
// Flags: 'l' print definition, not name
|
|
|
|
// 'h' omit 'func' and receiver from function types, short type names
|
|
|
|
// 'u' package name, not prefix (FTypeId mode, sticky)
|
|
|
|
static int
|
|
|
|
Tconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
int r, sm;
|
|
|
|
unsigned long sf;
|
|
|
|
|
|
|
|
t = va_arg(fp->args, Type*);
|
|
|
|
if(t == T)
|
|
|
|
return fmtstrcpy(fp, "<T>");
|
|
|
|
|
2012-01-09 10:45:08 -07:00
|
|
|
if(t->trecur > 4)
|
2011-10-31 11:09:40 -06:00
|
|
|
return fmtstrcpy(fp, "<...>");
|
|
|
|
|
|
|
|
t->trecur++;
|
|
|
|
sf = fp->flags;
|
|
|
|
sm = setfmode(&fp->flags);
|
|
|
|
|
|
|
|
if(fmtmode == FTypeId && (sf&FmtUnsigned))
|
|
|
|
fmtpkgpfx++;
|
|
|
|
if(fmtpkgpfx)
|
|
|
|
fp->flags |= FmtUnsigned;
|
|
|
|
|
|
|
|
r = typefmt(fp, t);
|
|
|
|
|
|
|
|
if(fmtmode == FTypeId && (sf&FmtUnsigned))
|
|
|
|
fmtpkgpfx--;
|
|
|
|
|
|
|
|
fp->flags = sf;
|
|
|
|
fmtmode = sm;
|
|
|
|
t->trecur--;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt '%N': Nodes.
|
|
|
|
// Flags: 'l' suffix with "(type %T)" where possible
|
|
|
|
// '+h' in debug mode, don't recurse, no multiline output
|
|
|
|
static int
|
|
|
|
Nconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
int r, sm;
|
|
|
|
unsigned long sf;
|
|
|
|
|
|
|
|
n = va_arg(fp->args, Node*);
|
|
|
|
if(n == N)
|
|
|
|
return fmtstrcpy(fp, "<N>");
|
|
|
|
sf = fp->flags;
|
|
|
|
sm = setfmode(&fp->flags);
|
|
|
|
|
|
|
|
r = -1;
|
|
|
|
switch(fmtmode) {
|
|
|
|
case FErr:
|
|
|
|
case FExp:
|
|
|
|
r = nodefmt(fp, n);
|
|
|
|
break;
|
|
|
|
case FDbg:
|
|
|
|
dumpdepth++;
|
|
|
|
r = nodedump(fp, n);
|
|
|
|
dumpdepth--;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal("unhandled %%N mode");
|
|
|
|
}
|
|
|
|
|
|
|
|
fp->flags = sf;
|
|
|
|
fmtmode = sm;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fmt '%H': NodeList.
|
|
|
|
// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
|
|
|
|
static int
|
|
|
|
Hconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
NodeList *l;
|
|
|
|
int r, sm;
|
|
|
|
unsigned long sf;
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
l = va_arg(fp->args, NodeList*);
|
|
|
|
|
|
|
|
if(l == nil && fmtmode == FDbg)
|
|
|
|
return fmtstrcpy(fp, "<nil>");
|
|
|
|
|
|
|
|
sf = fp->flags;
|
|
|
|
sm = setfmode(&fp->flags);
|
|
|
|
r = 0;
|
|
|
|
sep = "; ";
|
|
|
|
if(fmtmode == FDbg)
|
|
|
|
sep = "\n";
|
|
|
|
else if(fp->flags & FmtComma)
|
|
|
|
sep = ", ";
|
|
|
|
|
|
|
|
for(;l; l=l->next) {
|
|
|
|
r += fmtprint(fp, "%N", l->n);
|
|
|
|
if(l->next)
|
|
|
|
r += fmtstrcpy(fp, sep);
|
|
|
|
}
|
|
|
|
|
|
|
|
fp->flags = sf;
|
|
|
|
fmtmode = sm;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fmtinstallgo(void)
|
|
|
|
{
|
|
|
|
fmtmode = FErr;
|
|
|
|
fmtinstall('E', Econv); // etype opcodes
|
|
|
|
fmtinstall('J', Jconv); // all the node flags
|
|
|
|
fmtinstall('H', Hconv); // node lists
|
|
|
|
fmtinstall('L', Lconv); // line number
|
|
|
|
fmtinstall('N', Nconv); // node pointer
|
|
|
|
fmtinstall('O', Oconv); // node opcodes
|
|
|
|
fmtinstall('S', Sconv); // sym pointer
|
|
|
|
fmtinstall('T', Tconv); // type pointer
|
|
|
|
fmtinstall('V', Vconv); // val pointer
|
|
|
|
fmtinstall('Z', Zconv); // escaped string
|
|
|
|
|
|
|
|
// These are in mparith1.c
|
|
|
|
fmtinstall('B', Bconv); // big numbers
|
|
|
|
fmtinstall('F', Fconv); // big float numbers
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dumplist(char *s, NodeList *l)
|
|
|
|
{
|
2013-02-02 21:09:49 -07:00
|
|
|
print("%s%+H\n", s, l);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dump(char *s, Node *n)
|
|
|
|
{
|
2013-02-02 21:09:49 -07:00
|
|
|
print("%s [%p]%+N\n", s, n, n);
|
2011-10-31 11:09:40 -06:00
|
|
|
}
|