Commit b536adbf authored by Luuk van Dijk's avatar Luuk van Dijk

gc: changes to export format in preparation for inlining.

string literals used as package qualifiers are now prefixed with '@'
which obviates the need for the extra ':' before tags.

R=rsc, gri, lvd
CC=golang-dev
https://golang.org/cl/5129057
parent bffadd6b
This diff is collapsed.
......@@ -88,7 +88,7 @@ escapes(void)
if(debug['m']) {
for(l=noesc; l; l=l->next)
if(l->n->esc == EscNone)
warnl(l->n->lineno, "%S %#N does not escape",
warnl(l->n->lineno, "%S %#hN does not escape",
(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
l->n);
}
......@@ -643,7 +643,7 @@ escwalk(int level, Node *dst, Node *src)
if(src->class == PPARAM && leaks && src->esc == EscNone) {
src->esc = EscScope;
if(debug['m'])
warnl(src->lineno, "leaking param: %hN", src);
warnl(src->lineno, "leaking param: %#hN", src);
}
break;
......@@ -652,7 +652,7 @@ escwalk(int level, Node *dst, Node *src)
src->esc = EscHeap;
addrescapes(src->left);
if(debug['m'])
warnl(src->lineno, "%#N escapes to heap", src);
warnl(src->lineno, "%#hN escapes to heap", src);
}
escwalk(level-1, dst, src->left);
break;
......@@ -671,7 +671,7 @@ escwalk(int level, Node *dst, Node *src)
if(leaks) {
src->esc = EscHeap;
if(debug['m'])
warnl(src->lineno, "%#N escapes to heap", src);
warnl(src->lineno, "%#hN escapes to heap", src);
}
break;
......
......@@ -7,7 +7,7 @@
#include "go.h"
#include "y.tab.h"
static void dumpsym(Sym*);
static void dumpsym(Sym*);
static void dumpexporttype(Sym*);
static void dumpexportvar(Sym*);
static void dumpexportconst(Sym*);
......
......@@ -94,7 +94,7 @@ addrescapes(Node *n)
if(!debug['s'])
n->esc = EscHeap;
if(debug['m'])
print("%L: moved to heap: %hN\n", n->lineno, n);
print("%L: moved to heap: %#hN\n", n->lineno, n);
curfn = oldfn;
break;
}
......
......@@ -375,10 +375,10 @@ EXTERN Sym* dclstack;
struct Pkg
{
char* name;
Strlit* path;
char* name; // package name
Strlit* path; // string literal used in import statement
Sym* pathsym;
char* prefix;
char* prefix; // escaped path for use in symbol table
Pkg* link;
char exported; // import line written in export data
char direct; // imported directly
......@@ -1130,7 +1130,7 @@ int Nconv(Fmt *fp);
int Oconv(Fmt *fp);
int Sconv(Fmt *fp);
int Tconv(Fmt *fp);
int Tpretty(Fmt *fp, Type *t);
int Vconv(Fmt *fp);
int Zconv(Fmt *fp);
Node* adddot(Node *n);
int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
......@@ -1348,5 +1348,6 @@ void zname(Biobuf *b, Sym *s, int t);
#pragma varargck type "lS" Sym*
#pragma varargck type "T" Type*
#pragma varargck type "lT" Type*
#pragma varargck type "V" Val*
#pragma varargck type "Y" char*
#pragma varargck type "Z" Strlit*
......@@ -78,8 +78,6 @@ static void fixlbrace(int);
%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
......@@ -993,6 +991,16 @@ onew_name:
sym:
LNAME
| hidden_importsym
hidden_importsym:
'@' LLITERAL '.' LNAME
{
if($2.u.sval->len == 0)
$$ = pkglookup($4->name, importpkg);
else
$$ = pkglookup($4->name, mkpkg($2.u.sval));
}
name:
sym %prec NotParen
......@@ -1826,12 +1834,12 @@ hidden_opt_sym:
}
hidden_dcl:
hidden_opt_sym hidden_type hidden_tag
hidden_opt_sym hidden_type oliteral
{
$$ = nod(ODCLFIELD, $1, typenod($2));
$$->val = $3;
}
| hidden_opt_sym LDDD hidden_type hidden_tag
| hidden_opt_sym LDDD hidden_type oliteral
{
Type *t;
......@@ -1844,12 +1852,12 @@ hidden_dcl:
}
hidden_structdcl:
sym hidden_type hidden_tag
sym hidden_type oliteral
{
$$ = nod(ODCLFIELD, newname($1), typenod($2));
$$->val = $3;
}
| '?' hidden_type hidden_tag
| '?' hidden_type oliteral
{
Sym *s;
......@@ -1863,24 +1871,11 @@ hidden_structdcl:
$$->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:
{
......@@ -1931,18 +1926,6 @@ hidden_constant:
$$ = 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
{
......
......@@ -198,6 +198,7 @@ main(int argc, char *argv[])
fmtinstall('J', Jconv); // all the node flags
fmtinstall('S', Sconv); // sym pointer
fmtinstall('T', Tconv); // type pointer
fmtinstall('V', Vconv); // Val pointer
fmtinstall('N', Nconv); // node pointer
fmtinstall('Z', Zconv); // escaped string
fmtinstall('L', Lconv); // line number
......
......@@ -21,11 +21,22 @@ exprlistfmt(Fmt *f, NodeList *l)
}
}
void
stmtlistfmt(Fmt *f, NodeList *l)
{
for(; l; l=l->next) {
fmtprint(f, " %#N", l->n);
if(l->next)
fmtprint(f, ";");
}
}
void
exprfmt(Fmt *f, Node *n, int prec)
{
int nprec;
char *p;
NodeList *l;
nprec = 0;
if(n == nil) {
......@@ -107,6 +118,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case OGE:
case OGT:
case ONE:
case OCMPSTR:
nprec = 4;
break;
......@@ -269,6 +281,8 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OADD:
case OADDSTR:
case OAND:
case OANDAND:
case OANDNOT:
case ODIV:
......@@ -292,6 +306,12 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->right, nprec+1);
break;
case OCMPSTR:
exprfmt(f, n->left, nprec);
fmtprint(f, " %#O ", n->etype);
exprfmt(f, n->right, nprec+1);
break;
case OADDR:
case OCOM:
case OIND:
......@@ -306,7 +326,13 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OCLOSURE:
fmtprint(f, "func literal");
if(f->flags & FmtShort) {
fmtprint(f, "func literal", n->type);
} else {
fmtprint(f, "func %hhT {", n->type);
stmtlistfmt(f, n->nbody);
fmtprint(f, " }");
}
break;
case OCOMPLIT:
......@@ -314,18 +340,18 @@ exprfmt(Fmt *f, Node *n, int prec)
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");
if(f->flags & FmtShort) {
fmtprint(f, "%#hhT literal", n->type);
} else {
fmtprint(f, "%#hhT{", n->type);
for (l=n->list; l; l=l->next) {
fmtprint(f, " %#N:%#N", l->n->left, l->n->right);
if (l->next) fmtprint(f, ",");
}
fmtprint(f, " }");
}
break;
case OXDOT:
......@@ -479,6 +505,119 @@ exprfmt(Fmt *f, Node *n, int prec)
case ODEFER:
fmtprint(f, "defer %#N", n->left);
break;
case OIF:
if (n->ninit && n->ninit->next) {
fmtprint(f, "{");
stmtlistfmt(f, n->ninit);
fmtprint(f, "; ");
}
fmtstrcpy(f, "if ");
if (n->ninit && !n->ninit->next)
fmtprint(f, "%#N; ", n->ninit->n);
fmtprint(f, "%#N {", n->ntest);
stmtlistfmt(f, n->nbody);
if (n->nelse) {
fmtprint(f, "} else {");
stmtlistfmt(f, n->nelse);
}
fmtprint(f, "}");
if (n->ninit && n->ninit->next)
fmtprint(f, "}");
break;
case OFOR:
if (n->ninit && n->ninit->next) {
fmtprint(f, "{");
stmtlistfmt(f, n->ninit);
fmtprint(f, "; ");
}
fmtstrcpy(f, "for");
if (n->ninit && !n->ninit->next)
fmtprint(f, " %#N;", n->ninit->n);
else if (n->ntest || n->nincr)
fmtstrcpy(f, " ;");
if (n->ntest)
fmtprint(f, "%#N", n->ntest);
if (n->nincr)
fmtprint(f, "; %#N", n->nincr);
else if (n->ninit && !n->ninit->next)
fmtstrcpy(f, " ;");
fmtstrcpy(f, " {");
stmtlistfmt(f, n->nbody);
fmtprint(f, "}");
if (n->ninit && n->ninit->next)
fmtprint(f, "}");
break;
case ORANGE:
if (n->ninit) {
fmtprint(f, "{");
stmtlistfmt(f, n->ninit);
fmtprint(f, "; ");
}
fmtprint(f, "for ");
exprlistfmt(f, n->list);
fmtprint(f, " = range %#N {", n->right);
stmtlistfmt(f, n->nbody);
fmtprint(f, "}");
if (n->ninit)
fmtprint(f, "}");
break;
case OSWITCH:
if (n->ninit && n->ninit->next) {
fmtprint(f, "{");
stmtlistfmt(f, n->ninit);
fmtprint(f, "; ");
}
fmtstrcpy(f, "select");
if (n->ninit && !n->ninit->next)
fmtprint(f, " %#N;", n->ninit->n);
if (n->ntest)
fmtprint(f, "%#N", n->ntest);
fmtstrcpy(f, " {");
for(l=n->list; l; l=l->next) {
if (l->n->list) {
fmtprint(f, " case ");
exprlistfmt(f, l->n->list);
} else {
fmtprint(f, " default");
}
fmtstrcpy(f, ":");
stmtlistfmt(f, l->n->nbody);
if (l->next)
fmtprint(f, ";");
}
fmtprint(f, " }");
if (n->ninit)
fmtprint(f, "}");
break;
case OSELECT:
if (n->ninit) {
fmtprint(f, "{");
stmtlistfmt(f, n->ninit);
fmtprint(f, "; ");
}
fmtstrcpy(f, "select {");
for(l=n->list; l; l=l->next) {
if (l->n->list) {
fmtprint(f, " case ");
exprlistfmt(f, l->n->list);
} else {
fmtprint(f, " default");
}
fmtstrcpy(f, ":");
stmtlistfmt(f, l->n->nbody);
if (l->next)
fmtprint(f, ";");
}
fmtprint(f, " }");
if (n->ninit)
fmtprint(f, "}");
break;
}
if(prec > nprec)
......
......@@ -768,6 +768,10 @@ dodump(Node *n, int dep)
dodump(n->right, dep+1);
break;
case OLITERAL:
print("%N v(%V)\n", n, &n->val);
break;
case OTYPE:
print("%O %S type=%T\n", n->op, n->sym, n->type);
if(n->type == T && n->ntype) {
......@@ -870,11 +874,38 @@ dump(char *s, Node *n)
dodump(n, 1);
}
int
Vconv(Fmt *fp)
{
Val *v;
v = va_arg(fp->args, Val*);
switch(v->ctype) {
case CTINT:
return fmtprint(fp, "%B", v->u.xval);
case CTFLT:
return fmtprint(fp, "%g", mpgetflt(v->u.fval));
case CTCPLX:
return fmtprint(fp, "(%g+%gi)",
mpgetflt(&v->u.cval->real),
mpgetflt(&v->u.cval->imag));
case CTSTR:
return fmtprint(fp, "\"%Z\"", v->u.sval);
case CTBOOL:
return fmtprint(fp, "%d", v->u.bval);
case CTNIL:
return fmtprint(fp, "nil");
}
return fmtprint(fp, "<%d>", v->ctype);
}
static char*
goopnames[] =
{
[OADDR] = "&",
[OADD] = "+",
[OADDSTR] = "+",
[OANDAND] = "&&",
[OANDNOT] = "&^",
[OAND] = "&",
......@@ -1165,44 +1196,42 @@ Jconv(Fmt *fp)
return 0;
}
// Flags for %S
// 'h' FmtShort -> just print the name
// '#' FmtSharp -> qualify with package prefix or @"path", depending on global flag packagequotes.
// (automatic when global flag exporting is set)
// 'l' FmtLong -> qualify with package name or "path" (automatic when global flag
// longsymnames is set (by typehash) or sym is not in localpkg)
int
Sconv(Fmt *fp)
{
Sym *s;
s = va_arg(fp->args, Sym*);
if(s == S) {
fmtstrcpy(fp, "<S>");
return 0;
}
if(s == S)
return fmtstrcpy(fp, "<S>");
if(fp->flags & FmtShort)
goto shrt;
if(exporting || (fp->flags & FmtSharp)) {
if(packagequotes)
fmtprint(fp, "\"%Z\"", s->pkg->path);
return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name);
else
fmtprint(fp, "%s", s->pkg->prefix);
fmtprint(fp, ".%s", s->name);
return 0;
return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name);
}
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;
if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1)
return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
}
shrt:
fmtstrcpy(fp, s->name);
return 0;
return fmtstrcpy(fp, s->name);
}
static char*
......@@ -1231,7 +1260,11 @@ basicnames[] =
[TBLANK] = "blank",
};
int
// Global flag exporting
// Global flag noargnames
// 'h' FmtShort
// 'l' FmtLong
static int
Tpretty(Fmt *fp, Type *t)
{
Type *t1;
......@@ -1255,9 +1288,7 @@ Tpretty(Fmt *fp, Type *t)
fmtprint(fp, "%hS", s);
else
fmtprint(fp, "%S", s);
if(s->pkg != localpkg)
return 0;
if(t->vargen)
if(s->pkg == localpkg && t->vargen)
fmtprint(fp, "·%d", t->vargen);
return 0;
}
......@@ -1401,8 +1432,6 @@ Tpretty(Fmt *fp, Type *t)
fmtprint(fp, "%T", t->type);
if(t->note) {
fmtprint(fp, " ");
if(exporting)
fmtprint(fp, ":");
fmtprint(fp, "\"%Z\"", t->note);
}
return 0;
......@@ -1416,115 +1445,58 @@ Tpretty(Fmt *fp, Type *t)
case TUNSAFEPTR:
if(exporting)
return fmtprint(fp, "\"unsafe\".Pointer");
return fmtprint(fp, "@\"unsafe\".Pointer");
return fmtprint(fp, "unsafe.Pointer");
default:
if(exporting)
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);
}
// Don't know how to handle - fall back to detailed prints.
fatal("not reached");
return -1;
}
// %T flags:
// '#' FmtSharp -> 'exporting' mode global flag, affects Tpretty and Sconv
// '-' FmtLeft -> 'noargnames' global flag, affects Tpretty
// 'h' FmtShort -> handled by Tpretty
// 'l' FmtLong -> handled by Tpretty
int
Tconv(Fmt *fp)
{
Type *t, *t1;
int r, et, sharp, minus;
sharp = (fp->flags & FmtSharp);
minus = (fp->flags & FmtLeft);
fp->flags &= ~(FmtSharp|FmtLeft);
Type *t;
int r,sharp, minus, sf;
t = va_arg(fp->args, Type*);
if(t == T)
return fmtstrcpy(fp, "<T>");
t->trecur++;
if(t->trecur > 5) {
fmtprint(fp, "...");
goto out;
if(t->trecur > 4) {
return fmtstrcpy(fp, "...");
}
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;
t->trecur++;
case TPTR32:
case TPTR64:
fmtprint(fp, "%T", t->type);
break;
}
sharp = (fp->flags & FmtSharp);
minus = (fp->flags & FmtLeft);
sf = fp->flags;
fp->flags &= ~(FmtSharp|FmtLeft);
out:
if(sharp)
exporting++;
if(minus)
noargnames++;
r = Tpretty(fp, t);
if(sharp)
exporting--;
if(minus)
noargnames--;
fp->flags = sf;
t->trecur--;
return 0;
return r;
}
int
......@@ -1541,11 +1513,11 @@ Nconv(Fmt *fp)
if(fp->flags & FmtSign) {
if(n->type == T)
fmtprint(fp, "%#N", n);
fmtprint(fp, "%#hN", n);
else if(n->type->etype == TNIL)
fmtprint(fp, "nil");
else
fmtprint(fp, "%#N (type %T)", n, n->type);
fmtprint(fp, "%#hN (type %T)", n, n->type);
goto out;
}
......
......@@ -21,31 +21,19 @@
#include "fmtdef.h"
/*
* format a string into the output buffer
* designed for formats which themselves call fmt,
* but ignore any width flags
* Format a string into the output buffer.
* Designed for formats which themselves call fmt.
* Flags, precision and width are preserved.
*/
int
fmtprint(Fmt *f, char *fmt, ...)
{
va_list va;
int n;
va_list va;
f->flags = 0;
f->width = 0;
f->prec = 0;
VA_COPY(va, f->args);
VA_END(f->args);
va_start(f->args, fmt);
n = dofmt(f, fmt);
va_end(f->args);
f->flags = 0;
f->width = 0;
f->prec = 0;
VA_COPY(f->args,va);
VA_END(va);
if(n >= 0)
return 0;
va_start(va, fmt);
n = fmtvprint(f, fmt, va);
va_end(va);
return n;
}
......@@ -22,31 +22,31 @@
/*
* format a string into the output buffer
* designed for formats which themselves call fmt,
* but ignore any width flags
* Format a string into the output buffer.
* Designed for formats which themselves call fmt.
* Flags, precision and width are preserved.
*/
int
fmtvprint(Fmt *f, char *fmt, va_list args)
{
va_list va;
int n;
int n, w, p;
unsigned long fl;
f->flags = 0;
f->width = 0;
f->prec = 0;
VA_COPY(va,f->args);
w = f->width;
p = f->prec;
fl = f->flags;
VA_COPY(va, f->args);
VA_END(f->args);
VA_COPY(f->args,args);
VA_COPY(f->args, args);
n = dofmt(f, fmt);
f->flags = 0;
f->width = 0;
f->prec = 0;
VA_END(f->args);
VA_COPY(f->args,va);
VA_COPY(f->args, va);
VA_END(va);
f->width = w;
f->prec = p;
f->flags = fl;
if(n >= 0)
return 0;
return n;
}
......@@ -142,6 +142,34 @@ func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, e
return
}
// Declare inserts a named object of the given kind in scope.
func (p *gcParser) declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object {
// a type may have been declared before - if it exists
// already in the respective package scope, return that
// type
if kind == ast.Typ {
if obj := scope.Lookup(name); obj != nil {
assert(obj.Kind == ast.Typ)
return obj
}
}
// any other object must be a newly declared object -
// create it and insert it into the package scope
obj := ast.NewObj(kind, name)
if scope.Insert(obj) != nil {
p.errorf("already declared: %v %s", kind, obj.Name)
}
// a new type object is a named type and may be referred
// to before the underlying type is known - set it up
if kind == ast.Typ {
obj.Type = &Name{Obj: obj}
}
return obj
}
// ----------------------------------------------------------------------------
// Error handling
......@@ -245,38 +273,14 @@ func (p *gcParser) parseDotIdent() string {
return ident
}
// ExportedName = ImportPath "." dotIdentifier .
// ExportedName = "@" ImportPath "." dotIdentifier .
//
func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
func (p *gcParser) parseExportedName() (*ast.Object, string) {
p.expect('@')
pkg := p.parsePkgId()
p.expect('.')
name := p.parseDotIdent()
// a type may have been declared before - if it exists
// already in the respective package scope, return that
// type
scope := pkg.Data.(*ast.Scope)
if kind == ast.Typ {
if obj := scope.Lookup(name); obj != nil {
assert(obj.Kind == ast.Typ)
return obj
}
}
// any other object must be a newly declared object -
// create it and insert it into the package scope
obj := ast.NewObj(kind, name)
if scope.Insert(obj) != nil {
p.errorf("already declared: %s", obj.Name)
}
// a new type object is a named type and may be referred
// to before the underlying type is known - set it up
if kind == ast.Typ {
obj.Type = &Name{Obj: obj}
}
return obj
return pkg, name
}
// ----------------------------------------------------------------------------
......@@ -333,7 +337,7 @@ func (p *gcParser) parseName() (name string) {
return
}
// Field = Name Type [ ":" string_lit ] .
// Field = Name Type [ string_lit ] .
//
func (p *gcParser) parseField() (fld *ast.Object, tag string) {
name := p.parseName()
......@@ -344,8 +348,7 @@ func (p *gcParser) parseField() (fld *ast.Object, tag string) {
p.errorf("anonymous field expected")
}
}
if p.tok == ':' {
p.next()
if p.tok == scanner.String {
tag = p.expect(scanner.String)
}
fld = ast.NewObj(ast.Var, name)
......@@ -380,7 +383,7 @@ func (p *gcParser) parseStructType() Type {
return &Struct{Fields: fields, Tags: tags}
}
// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
//
func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
name := p.parseName()
......@@ -393,8 +396,7 @@ func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
}
ptyp := p.parseType()
// ignore argument tag
if p.tok == ':' {
p.next()
if p.tok == scanner.String {
p.expect(scanner.String)
}
par = ast.NewObj(ast.Var, name)
......@@ -439,7 +441,7 @@ func (p *gcParser) parseSignature() *Func {
// optional result type
var results []*ast.Object
switch p.tok {
case scanner.Ident, scanner.String, '[', '*', '<':
case scanner.Ident, '[', '*', '<', '@':
// single, unnamed result
result := ast.NewObj(ast.Var, "_")
result.Type = p.parseType()
......@@ -456,16 +458,13 @@ func (p *gcParser) parseSignature() *Func {
return &Func{Params: params, Results: results, IsVariadic: isVariadic}
}
// MethodSpec = identifier Signature .
// MethodSpec = ( identifier | ExportedName ) Signature .
//
func (p *gcParser) parseMethodSpec() *ast.Object {
if p.tok == scanner.Ident {
p.expect(scanner.Ident)
} else {
// TODO(gri) should this be parseExportedName here?
p.parsePkgId()
p.expect('.')
p.parseDotIdent()
p.parseExportedName()
}
p.parseSignature()
......@@ -547,9 +546,10 @@ func (p *gcParser) parseType() Type {
case "chan":
return p.parseChanType()
}
case scanner.String:
case '@':
// TypeName
return p.parseExportedName(ast.Typ).Type.(Type)
pkg, name := p.parseExportedName()
return p.declare(pkg.Data.(*ast.Scope), ast.Typ, name).Type.(Type)
case '[':
p.next() // look ahead
if p.tok == ']' {
......@@ -643,7 +643,8 @@ func (p *gcParser) parseNumber() Const {
//
func (p *gcParser) parseConstDecl() {
p.expectKeyword("const")
obj := p.parseExportedName(ast.Con)
pkg, name := p.parseExportedName()
obj := p.declare(pkg.Data.(*ast.Scope), ast.Con, name)
var x Const
var typ Type
if p.tok != '=' {
......@@ -693,7 +694,8 @@ func (p *gcParser) parseConstDecl() {
//
func (p *gcParser) parseTypeDecl() {
p.expectKeyword("type")
obj := p.parseExportedName(ast.Typ)
pkg, name := p.parseExportedName()
obj := p.declare(pkg.Data.(*ast.Scope), ast.Typ, name)
// The type object may have been imported before and thus already
// have a type associated with it. We still need to parse the type
......@@ -712,20 +714,39 @@ func (p *gcParser) parseTypeDecl() {
//
func (p *gcParser) parseVarDecl() {
p.expectKeyword("var")
obj := p.parseExportedName(ast.Var)
pkg, name := p.parseExportedName()
obj := p.declare(pkg.Data.(*ast.Scope), ast.Var, name)
obj.Type = p.parseType()
}
// FuncDecl = "func" ExportedName Signature .
// FuncBody = "{" ... "}" .
//
func (p *gcParser) parseFuncBody() {
p.expect('{')
for i := 1; i > 0; p.next() {
switch p.tok {
case '{':
i++
case '}':
i--
}
}
}
// FuncDecl = "func" ExportedName Signature [ FuncBody ] .
//
func (p *gcParser) parseFuncDecl() {
// "func" already consumed
obj := p.parseExportedName(ast.Fun)
pkg, name := p.parseExportedName()
obj := p.declare(pkg.Data.(*ast.Scope), ast.Fun, name)
obj.Type = p.parseSignature()
if p.tok == '{' {
p.parseFuncBody()
}
}
// MethodDecl = "func" Receiver identifier Signature .
// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ].
//
func (p *gcParser) parseMethodDecl() {
// "func" already consumed
......@@ -734,6 +755,9 @@ func (p *gcParser) parseMethodDecl() {
p.expect(')')
p.expect(scanner.Ident)
p.parseSignature()
if p.tok == '{' {
p.parseFuncBody()
}
}
// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
......
......@@ -15,8 +15,8 @@ var (
_ = sum()
_ = sum(1.0, 2.0)
_ = sum(1.5) // ERROR "integer"
_ = sum("hello") // ERROR "string.*as type int|incompatible"
_ = sum([]int{1}) // ERROR "slice literal.*as type int|incompatible"
_ = sum("hello") // ERROR ".hello. .type string. as type int|incompatible"
_ = sum([]int{1}) // ERROR "\[\]int literal.*as type int|incompatible"
)
type T []T
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment