another step toward interface subtypes
put explicit ./ on some runtime tests
R=r
OCL=17839
CL=17839
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
index 39e0b95..8070af4 100644
--- a/src/cmd/6g/obj.c
+++ b/src/cmd/6g/obj.c
@@ -455,84 +455,122 @@
return strcmp(a->name, b->name);
}
+static Addr at, ao, ac, ad;
+static int wi, ot;
+
void
-dumpsignatures(void)
+ginsatoa(int fscale, int toffset)
+{
+ Prog *p;
+
+ p = pc;
+ ot = rnd(ot, fscale);
+
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = fscale;
+ p->to = ao;
+ p->to.offset = toffset;
+ ot += fscale;
+}
+
+void
+gensatac(int fscale, int toffset)
+{
+ Prog *p;
+
+ p = pc;
+ ot = rnd(ot, fscale);
+
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = fscale;
+ p->to = ac;
+ p->to.offset = toffset;
+ ot += fscale;
+}
+
+void
+gensatad(Sym *s)
+{
+ Prog *p;
+
+ p = pc;
+ ot = rnd(ot, widthptr);
+
+ gins(ADATA, N, N);
+ p->from = at;
+ p->from.offset = ot;
+ p->from.scale = widthptr;
+ p->to = ad;
+ p->to.sym = s;
+ ot += widthptr;
+}
+
+void
+gentramp(Type *t, Sig *b)
+{
+ Sym *e;
+ int c, d;
+
+ e = lookup(b->name);
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(e, t, d);
+ if(c == 1)
+ goto out;
+ }
+ fatal("gentramp");
+
+out:
+ print("gentramp %d\n", d);
+ print(" t = %lT\n", t);
+ print(" name = %s\n", b->name);
+ print(" sym = %S\n", b->sym);
+ print(" hash = 0x%ux\n", b->hash);
+
+ for(c=d-1; c>=0; c--) {
+ print(" %d %d %S\n",
+ dotlist[c].ptr,
+ dotlist[c].offset,
+ dotlist[c].sym);
+ }
+
+//TEXT main·S_test2(SB),7,$0
+// MOVQ 8(SP), AX
+// MOVQ XX(AX), AX
+// ADDQ $XX, AX
+// MOVQ AX, 8(SP)
+// JMP main·Sub_test2(SB)
+}
+
+void
+dumpsigt(void)
{
Dcl *d, *x;
Type *t, *f;
Sym *s1, *s;
- int et, o, wi, ot;
+ int et, o;
Sig *a, *b;
- Addr at, ao, ac, ad;
Prog *p;
char *sp;
char buf[NSYMB];
- // copy externdcl list to signatlist
- for(d=externdcl; d!=D; d=d->forw) {
- if(d->op != OTYPE)
- continue;
-
- t = d->dtype;
- if(t == T)
- continue;
-
- s = signame(t, 0);
- if(s == S)
- continue;
-
- x = mal(sizeof(*d));
- x->op = OTYPE;
- x->dsym = d->dsym;
- x->dtype = d->dtype;
- x->forw = signatlist;
- x->block = 0;
- signatlist = x;
-//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
- }
-
/*
* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
-
- memset(&at, 0, sizeof(at));
- memset(&ao, 0, sizeof(ao));
- memset(&ac, 0, sizeof(ac));
- memset(&ad, 0, sizeof(ad));
-
- // sig structure
- at.type = D_EXTERN;
- at.index = D_NONE;
- at.sym = S; // fill in
- at.offset = 0; // fill in
-
- // $string
- ao.type = D_ADDR;
- ao.index = D_STATIC;
- ao.etype = TINT32;
- ao.sym = symstringo;
- ao.offset = 0; // fill in
-
- // constant
- ac.type = D_CONST;
- ac.index = D_NONE;
- ac.offset = 0; // fill in
-
- // $method
- ad.type = D_ADDR;
- ad.index = D_EXTERN;
- ad.sym = S; // fill in
- ad.offset = 0;
-
- wi = types[TINT32]->width;
-
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
+ et = t->etype;
+ if(et == TINTER)
+ continue;
+
at.sym = signame(t, d->block);
if(at.sym == S)
continue;
@@ -542,10 +580,6 @@
continue;
at.sym->local = 2;
-//print("SIGNAME = %lS\n", at.sym);
-
- et = t->etype;
-
s = d->dsym;
if(s == S)
continue;
@@ -556,14 +590,157 @@
if(strcmp(s->opackage, package) != 0)
continue;
+ expandmeth(s, t);
+
a = nil;
o = 0;
+ for(f=t->method; f!=T; f=f->down) {
+ if(f->type->etype != TFUNC)
+ continue;
- f = t->method;
- if(et == TINTER)
- f = t->type;
+ if(f->etype != TFIELD)
+ fatal("dumpsignatures: not field");
- for(; f!=T; f=f->down) {
+ s1 = f->sym;
+ if(s1 == nil)
+ continue;
+
+ b = mal(sizeof(*b));
+ b->link = a;
+ a = b;
+
+ a->name = s1->name;
+ a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
+ a->perm = o;
+ snprint(namebuf, sizeof(namebuf), "%s_%s",
+ at.sym->name+5, f->sym->name);
+ a->sym = lookup(namebuf);
+ a->offset = f->embedded; // need trampoline
+
+ o++;
+ }
+
+ a = lsort(a, sigcmp);
+ ot = 0;
+ ot = rnd(ot, maxround); // base structure
+
+ // sigi[0].name = ""
+ ginsatoa(widthptr, stringo);
+
+ // save type name for runtime error message.
+ // TODO(rsc): the * is a botch but right more often than not.
+ snprint(buf, sizeof buf, "*%#T", t);
+ datastring(buf, strlen(buf)+1);
+
+ // first field of an type signature contains
+ // the element parameters and is not a real entry
+
+ t = d->dtype;
+ if(t->methptr & 2)
+ t = types[tptr];
+
+ // sigi[0].hash = elemalg
+ gensatac(wi, algtype(t));
+
+ // sigi[0].offset = width
+ gensatac(wi, t->width);
+
+ // skip the function
+ gensatac(widthptr, 0);
+
+ for(b=a; b!=nil; b=b->link) {
+ ot = rnd(ot, maxround); // base structure
+
+ // sigx[++].name = "fieldname"
+ ginsatoa(widthptr, stringo);
+
+ // sigx[++].hash = hashcode
+ gensatac(wi, b->hash);
+
+ // sigt[++].offset = of embeded struct
+ gensatac(wi, 0);
+
+ // sigt[++].fun = &method
+ gensatad(b->sym);
+
+ datastring(b->name, strlen(b->name)+1);
+
+ if(b->offset)
+ gentramp(d->dtype, b);
+ }
+
+ // nil field name at end
+ ot = rnd(ot, maxround);
+ gensatac(widthptr, 0);
+
+ p = pc;
+ gins(AGLOBL, N, N);
+ p->from = at;
+ p->to = ac;
+ p->to.offset = ot;
+ }
+
+ if(stringo > 0) {
+ p = pc;
+ gins(AGLOBL, N, N);
+ p->from = ao;
+ p->to = ac;
+ p->to.offset = stringo;
+ }
+
+}
+
+void
+dumpsigi(void)
+{
+ Dcl *d, *x;
+ Type *t, *f;
+ Sym *s1, *s;
+ int et, o;
+ Sig *a, *b;
+ Prog *p;
+ char *sp;
+ char buf[NSYMB];
+
+ /*
+ * put all the names into a linked
+ * list so that it may be generated in sorted order.
+ * the runtime will be linear rather than quadradic
+ */
+
+ for(d=signatlist; d!=D; d=d->forw) {
+ if(d->op != OTYPE)
+ continue;
+
+ t = d->dtype;
+ et = t->etype;
+ if(et != TINTER)
+ continue;
+
+ at.sym = signame(t, d->block);
+ if(at.sym == S)
+ continue;
+
+ // make unique
+ if(at.sym->local != 1)
+ continue;
+ at.sym->local = 2;
+
+ s = d->dsym;
+ if(s == S)
+ continue;
+
+ if(s->name[0] == '_')
+ continue;
+
+ if(strcmp(s->opackage, package) != 0)
+ continue;
+
+//print("sigi: %S\n", s);
+
+ a = nil;
+ o = 0;
+ for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
@@ -597,162 +774,47 @@
a = lsort(a, sigcmp);
ot = 0;
+ ot = rnd(ot, maxround); // base structure
// sigi[0].name = ""
- ot = rnd(ot, maxround); // array of structures
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = widthptr;
- p->to = ao;
- p->to.offset = stringo;
- ot += widthptr;
+ ginsatoa(widthptr, stringo);
// save type name for runtime error message.
// TODO(rsc): the * is a botch but right more often than not.
- if(et == TINTER)
- snprint(buf, sizeof buf, "%#T", t);
- else
- snprint(buf, sizeof buf, "*%#T", t);
+ snprint(buf, sizeof buf, "%#T", t);
datastring(buf, strlen(buf)+1);
- if(et == TINTER) {
- // first field of an interface signature
- // contains the count and is not a real entry
- o = 0;
- for(b=a; b!=nil; b=b->link)
- o++;
+ // first field of an interface signature
+ // contains the count and is not a real entry
- // sigi[0].hash = 0
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = 0;
- ot += wi;
+ // sigi[0].hash = 0
+ gensatac(wi, 0);
- // sigi[0].offset = count
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = o;
- ot += wi;
-
- } else {
- // first field of an type signature contains
- // the element parameters and is not a real entry
-
- t = d->dtype;
- if(t->methptr & 2)
- t = types[tptr];
-
- // sigi[0].hash = elemalg
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = algtype(t);
- ot += wi;
-
- // sigi[0].offset = width
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = t->width;
- ot += wi;
-
- // skip the function
- ot = rnd(ot, widthptr);
- ot += widthptr;
- }
+ // sigi[0].offset = count
+ o = 0;
+ for(b=a; b!=nil; b=b->link)
+ o++;
+ gensatac(wi, o);
for(b=a; b!=nil; b=b->link) {
+//print(" %s\n", b->name);
+ ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
- ot = rnd(ot, maxround); // array of structures
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = widthptr;
- p->to = ao;
- p->to.offset = stringo;
- ot += widthptr;
+ ginsatoa(widthptr, stringo);
// sigx[++].hash = hashcode
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = b->hash;
- ot += wi;
+ gensatac(wi, b->hash);
- if(et == TINTER) {
- // sigi[++].perm = mapped offset of method
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = b->perm;
- ot += wi;
- } else {
- // sigt[++].offset = of embeded struct
- ot = rnd(ot, wi);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = wi;
- p->to = ac;
- p->to.offset = b->offset;
- ot += wi;
+ // sigi[++].perm = mapped offset of method
+ gensatac(wi, b->perm);
- // sigt[++].fun = &method
- ot = rnd(ot, widthptr);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = widthptr;
- p->to = ad;
- p->to.sym = b->sym;
- ot += widthptr;
- }
datastring(b->name, strlen(b->name)+1);
-
}
// nil field name at end
ot = rnd(ot, maxround);
- p = pc;
- gins(ADATA, N, N);
- p->from = at;
- p->from.offset = ot;
- p->from.scale = widthptr;
- p->to = ac;
- p->to.offset = 0;
- ot += widthptr;
+ gensatac(widthptr, 0);
p = pc;
gins(AGLOBL, N, N);
@@ -769,3 +831,67 @@
p->to.offset = stringo;
}
}
+
+void
+dumpsignatures(void)
+{
+ Dcl *d, *x;
+ Type *t;
+ Sym *s;
+
+ memset(&at, 0, sizeof(at));
+ memset(&ao, 0, sizeof(ao));
+ memset(&ac, 0, sizeof(ac));
+ memset(&ad, 0, sizeof(ad));
+
+ wi = types[TINT32]->width;
+
+ // sig structure
+ at.type = D_EXTERN;
+ at.index = D_NONE;
+ at.sym = S; // fill in
+ at.offset = 0; // fill in
+
+ // $string
+ ao.type = D_ADDR;
+ ao.index = D_STATIC;
+ ao.etype = TINT32;
+ ao.sym = symstringo;
+ ao.offset = 0; // fill in
+
+ // constant
+ ac.type = D_CONST;
+ ac.index = D_NONE;
+ ac.offset = 0; // fill in
+
+ // $method
+ ad.type = D_ADDR;
+ ad.index = D_EXTERN;
+ ad.sym = S; // fill in
+ ad.offset = 0;
+
+ // copy externdcl list to signatlist
+ for(d=externdcl; d!=D; d=d->forw) {
+ if(d->op != OTYPE)
+ continue;
+
+ t = d->dtype;
+ if(t == T)
+ continue;
+
+ s = signame(t, 0);
+ if(s == S)
+ continue;
+
+ x = mal(sizeof(*d));
+ x->op = OTYPE;
+ x->dsym = d->dsym;
+ x->dtype = d->dtype;
+ x->forw = signatlist;
+ x->block = 0;
+ signatlist = x;
+//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
+ }
+ dumpsigi();
+ dumpsigt();
+}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 25e92bc..b8250b1 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -208,6 +208,7 @@
uchar exported; // exported
uchar sym; // huffman encoding in object file
uchar local; // created in this file
+ uchar uniq; // imbedded field name first found
char* opackage; // original package name
char* package; // package name
@@ -398,6 +399,16 @@
char* cp; // used for content when bin==nil
};
+typedef struct Dlist Dlist;
+struct Dlist
+{
+ Sym* sym;
+ uchar ptr;
+ int offset;
+};
+
+EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
+
EXTERN Io curio;
EXTERN Io pushedio;
EXTERN int32 lineno;
@@ -631,6 +642,13 @@
int Wconv(Fmt*);
int Zconv(Fmt*);
+int lookdot0(Sym*, Type*);
+int adddot1(Sym*, Type*, int);
+Node* adddot(Node*);
+void expand0(Type*);
+void expand1(Type*, int);
+void expandmeth(Sym*, Type*);
+
/*
* dcl.c
*/
@@ -748,7 +766,6 @@
Node* maplit(Node*);
Node* selectas(Node*, Node*);
Node* old2new(Node*, Type*);
-Node* adddot(Node*);
/*
* const.c
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 50223cc..710c12f 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -2377,3 +2377,251 @@
{
return *getinarg(t);
}
+
+/*
+ * code to resolve elided DOTs
+ * in embedded types
+ */
+
+// search depth 0 --
+// return count of fields+methods
+// found with a given name
+int
+lookdot0(Sym *s, Type *t)
+{
+ 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)
+ c++;
+ }
+ u = methtype(t);
+ if(u != T) {
+ for(f=u->method; f!=T; f=f->down)
+ if(f->sym == s && f->embedded == 0)
+ 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 *f, *u;
+ int c, a;
+
+ if(t->trecur)
+ return 0;
+ t->trecur = 1;
+
+ if(d == 0) {
+ c = lookdot0(s, t);
+ 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);
+ if(a != 0 && c == 0) {
+ dotlist[d].sym = f->sym;
+ dotlist[d].offset = f->width;
+ dotlist[d].ptr = 0;
+ if(isptr[f->type->etype])
+ dotlist[d].ptr = 1;
+ }
+ 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;
+ Node *l;
+ int c, d;
+
+ walktype(n->left, Erv);
+ t = n->left->type;
+ if(t == T)
+ return n;
+
+ if(n->right->op != ONAME)
+ return n;
+ s = n->right->sym;
+ if(s == S)
+ return n;
+
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(s, t, d);
+ if(c > 0)
+ goto out;
+ }
+ return n;
+
+out:
+ if(c > 1)
+ yyerror("ambiguous DOT reference %S", s);
+
+ // rebuild elided dots
+ for(c=d-1; c>=0; c--) {
+ n = nod(ODOT, n, n->right);
+ n->left->right = newname(dotlist[c].sym);
+ }
+ 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;
+ Symlink* link;
+};
+static Symlink* slist;
+
+void
+expand0(Type *t)
+{
+ Type *f, *u;
+ Symlink *sl;
+
+ u = t;
+ if(isptr[u->etype])
+ u = u->type;
+
+ u = methtype(t);
+ if(u != T) {
+ for(f=u->method; f!=T; f=f->down) {
+ if(f->sym->uniq)
+ continue;
+ f->sym->uniq = 1;
+ sl = mal(sizeof(*sl));
+ sl->field = f;
+ sl->link = slist;
+ slist = sl;
+ }
+ }
+}
+
+void
+expand1(Type *t, int d)
+{
+ Type *f, *u;
+
+ if(t->trecur)
+ return;
+ if(d == 0)
+ return;
+ t->trecur = 1;
+
+ if(d != nelem(dotlist)-1)
+ expand0(t);
+
+ u = t;
+ if(isptr[u->etype])
+ 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);
+ }
+
+out:
+ t->trecur = 0;
+}
+
+void
+expandmeth(Sym *s, Type *t)
+{
+ Symlink *sl;
+ Type *f;
+ int c, d;
+
+ if(s == S)
+ return;
+ if(t == T)
+ return;
+ if(strcmp(s->name, "S") != 0)
+ return;
+
+ // generate all reachable methods
+ slist = nil;
+ expand1(t, nelem(dotlist)-1);
+
+ // check each method to be uniquely reachable
+ for(sl=slist; sl!=nil; sl=sl->link) {
+ for(d=0; d<nelem(dotlist); d++) {
+ c = adddot1(sl->field->sym, t, d);
+ if(c == 0)
+ continue;
+ if(c == 1)
+ sl->good = 1;
+ break;
+ }
+ }
+
+//print("expand %S: %lT", s, t);
+ 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
+
+ f->down = t->method;
+ t->method = f;
+
+//print(" %T", f);
+ }
+ }
+//print("\n");
+}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 1b7c1d3..094c4e3 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -3203,116 +3203,3 @@
r = listnext(&saver);
goto loop;
}
-
-static int prdot = 0;
-
-int
-lookdot0(Sym *s, Type *t)
-{
- 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)
- c++;
- }
- u = methtype(t);
- if(u != T) {
- for(f=u->method; f!=T; f=f->down)
- if(f->sym == s)
-{
-if(prdot)
-print("found method %S\n", s);
- c++;
-}
- }
- return c;
-}
-
-enum { maxembed = 10 }; // max depth search for embedded types
-static Sym* dotlist[maxembed+1]; // maxembed..1
-
-int
-adddot1(Sym *s, Type *t, int d)
-{
- Type *f, *u;
- int c, a;
-
- if(d == 0)
- return lookdot0(s, t);
-
- u = t;
- if(isptr[u->etype])
- u = u->type;
- if(u->etype != TSTRUCT && u->etype != TINTER)
- return 0;
-
- c = 0;
- for(f=u->type; f!=T; f=f->down) {
- if(!f->embedded)
- continue;
- if(f->sym == S)
- continue;
- a = adddot1(s, f->type, d-1);
- if(a != 0 && c == 0)
- dotlist[d] = f->sym;
- c += a;
- }
- return c;
-}
-
-Node*
-adddot(Node *n)
-{
- Type *t;
- Sym *s;
- Node *l;
- int c, d;
-
- walktype(n->left, Erv);
- t = n->left->type;
- if(t == T)
- return n;
-
- if(n->right->op != ONAME)
- return n;
- s = n->right->sym;
- if(s == S)
- return n;
-
- for(d=0; d<maxembed; d++) {
- c = adddot1(s, t, d);
- if(c > 0)
- goto out;
- }
-if(prdot) {
-print("missed");
-dump("", n);
-}
- return n;
-
-out:
- if(c > 1)
- yyerror("ambiguous DOT reference %S", s);
-
-if(prdot)
-if(d > 0)
-print("add dots:");
- // rebuild elided dots
- for(c=d; c>0; c--) {
- n = nod(ODOT, n, n->right);
- n->left->right = newname(dotlist[c]);
-if(prdot)
-print(" %S", dotlist[c]);
- }
-if(prdot)
-if(d > 0)
-print("\n");
- return n;
-}