ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/limbo/decls.b/
storename := array[Dend] of
{
Dtype => "type",
Dfn => "function",
Dglobal => "global",
Darg => "argument",
Dlocal => "local",
Dconst => "con",
Dfield => "field",
Dtag => "pick tag",
Dimport => "import",
Dunbound => "unbound",
Dundef => "undefined",
Dwundef => "undefined",
};
storeart := array[Dend] of
{
Dtype => "a ",
Dfn => "a ",
Dglobal => "a ",
Darg => "an ",
Dlocal => "a ",
Dconst => "a ",
Dfield => "a ",
Dtag => "a ",
Dimport => "an ",
Dunbound => "",
Dundef => "",
Dwundef => "",
};
storespace := array[Dend] of
{
Dtype => 0,
Dfn => 0,
Dglobal => 1,
Darg => 1,
Dlocal => 1,
Dconst => 0,
Dfield => 1,
Dtag => 0,
Dimport => 0,
Dunbound => 0,
Dundef => 0,
Dwundef => 0,
};
impdecl: ref Decl;
impdecls: ref Dlist;
scopes := array[MaxScope] of ref Decl;
tails := array[MaxScope] of ref Decl;
scopekind := array[MaxScope] of byte;
scopenode := array[MaxScope] of ref Node;
iota: ref Decl;
zdecl: Decl;
popscopes()
{
d: ref Decl;
#
# clear out any decls left in syms
#
while(scope >= ScopeBuiltin){
for(d = scopes[scope--]; d != nil; d = d.next){
if(d.sym != nil){
d.sym.decl = d.old;
d.old = nil;
}
}
}
for(id := impdecls; id != nil; id = id.next){
for(d = id.d.ty.ids; d != nil; d = d.next){
d.sym.decl = nil;
d.old = nil;
}
}
impdecls = nil;
scope = ScopeBuiltin;
scopes[ScopeBuiltin] = nil;
tails[ScopeBuiltin] = nil;
}
declstart()
{
iota = mkids(nosrc, enter("iota", 0), tint, nil);
iota.init = mkconst(nosrc, big 0);
scope = ScopeNils;
scopes[ScopeNils] = nil;
tails[ScopeNils] = nil;
nildecl = mkdecl(nosrc, Dglobal, tany);
nildecl.sym = enter("nil", 0);
installids(Dglobal, nildecl);
d := mkdecl(nosrc, Dglobal, tstring);
d.sym = enterstring("");
installids(Dglobal, d);
scope = ScopeGlobal;
scopes[ScopeGlobal] = nil;
tails[ScopeGlobal] = nil;
}
redecl(d: ref Decl)
{
old := d.sym.decl;
if(old.store == Dwundef)
return;
error(d.src.start, "redeclaration of "+declconv(d)+", previously declared as "+storeconv(old)+" on line "+
lineconv(old.src.start));
}
checkrefs(d: ref Decl)
{
id, m: ref Decl;
refs: int;
for(; d != nil; d = d.next){
if(d.das != byte 0)
d.refs--;
case d.store{
Dtype =>
refs = d.refs;
if(d.ty.kind == Tadt){
for(id = d.ty.ids; id != nil; id = id.next){
d.refs += id.refs;
if(id.store != Dfn)
continue;
if(id.init == nil && id.link == nil && d.importid == nil)
error(d.src.start, "function "+d.sym.name+"."+id.sym.name+" not defined");
if(superwarn && !id.refs && d.importid == nil)
warn(d.src.start, "function "+d.sym.name+"."+id.sym.name+" not referenced");
}
}
if(d.ty.kind == Tmodule){
for(id = d.ty.ids; id != nil; id = id.next){
refs += id.refs;
if(id.iface != nil)
id.iface.refs += id.refs;
if(id.store == Dtype){
for(m = id.ty.ids; m != nil; m = m.next){
refs += m.refs;
if(m.iface != nil)
m.iface.refs += m.refs;
}
}
}
d.refs = refs;
}
if(superwarn && !refs && d.importid == nil)
warn(d.src.start, declconv(d)+" not referenced");
Dglobal =>
if(superwarn && !d.refs && d.sym != nil && d.sym.name[0] != '.')
warn(d.src.start, declconv(d)+" not referenced");
Dlocal or
Darg =>
if(!d.refs && d.sym != nil && d.sym.name != nil && d.sym.name[0] != '.')
warn(d.src.start, declconv(d)+" not referenced");
Dconst =>
if(superwarn && !d.refs && d.sym != nil)
warn(d.src.start, declconv(d)+" not referenced");
Dfn =>
if(d.init == nil && d.importid == nil)
error(d.src.start, declconv(d)+" not defined");
if(superwarn && !d.refs)
warn(d.src.start, declconv(d)+" not referenced");
Dimport =>
if(superwarn && !d.refs)
warn(d.src.start, declconv(d)+" not referenced");
}
if(d.das != byte 0)
d.refs++;
}
}
vardecl(ids: ref Decl, t: ref Type): ref Node
{
n := mkn(Ovardecl, mkn(Oseq, nil, nil), nil);
n.decl = ids;
n.ty = t;
return n;
}
vardecled(n: ref Node)
{
store := Dlocal;
if(scope == ScopeGlobal)
store = Dglobal;
if(n.ty.kind == Texception && n.ty.cons == byte 1){
store = Dconst;
fatal("Texception in vardecled");
}
ids := n.decl;
installids(store, ids);
t := n.ty;
for(last := ids; ids != nil; ids = ids.next){
ids.ty = t;
last = ids;
}
n.left.decl = last;
}
condecl(ids: ref Decl, init: ref Node): ref Node
{
n := mkn(Ocondecl, mkn(Oseq, nil, nil), init);
n.decl = ids;
return n;
}
condecled(n: ref Node)
{
ids := n.decl;
installids(Dconst, ids);
for(last := ids; ids != nil; ids = ids.next){
ids.ty = tunknown;
last = ids;
}
n.left.decl = last;
}
exdecl(ids: ref Decl, tids: ref Decl): ref Node
{
n: ref Node;
t: ref Type;
t = mktype(ids.src.start, ids.src.stop, Texception, nil, tids);
t.cons = byte 1;
n = mkn(Oexdecl, mkn(Oseq, nil, nil), nil);
n.decl = ids;
n.ty = t;
return n;
}
exdecled(n: ref Node)
{
ids, last: ref Decl;
t: ref Type;
ids = n.decl;
installids(Dconst, ids);
t = n.ty;
for(last = ids; ids != nil; ids = ids.next){
ids.ty = t;
last = ids;
}
n.left.decl = last;
}
importdecl(m: ref Node, ids: ref Decl): ref Node
{
n := mkn(Oimport, mkn(Oseq, nil, nil), m);
n.decl = ids;
return n;
}
importdecled(n: ref Node)
{
ids := n.decl;
installids(Dimport, ids);
for(last := ids; ids != nil; ids = ids.next){
ids.ty = tunknown;
last = ids;
}
n.left.decl = last;
}
mkscope(body: ref Node): ref Node
{
n := mkn(Oscope, nil, body);
if(body != nil)
n.src = body.src;
return n;
}
fndecl(n: ref Node, t: ref Type, body: ref Node): ref Node
{
n = mkbin(Ofunc, n, body);
n.ty = t;
return n;
}
fndecled(n: ref Node)
{
left := n.left;
if(left.op == Oname){
d := left.decl.sym.decl;
if(d == nil || d.store == Dimport){
d = mkids(left.src, left.decl.sym, n.ty, nil);
installids(Dfn, d);
}
left.decl = d;
d.refs++;
}
if(left.op == Odot)
pushscope(nil, Sother);
if(n.ty.polys != nil){
pushscope(nil, Sother);
installids(Dtype, n.ty.polys);
}
pushscope(nil, Sother);
installids(Darg, n.ty.ids);
n.ty.ids = popscope();
if(n.ty.val != nil)
mergepolydecs(n.ty);
if(n.ty.polys != nil)
n.ty.polys = popscope();
if(left.op == Odot)
popscope();
}
#
# check the function declaration only
# the body will be type checked later by fncheck
#
fnchk(n: ref Node): ref Decl
{
bad := 0;
d := n.left.decl;
if(n.left.op == Odot)
d = n.left.right.decl;
if(d == nil)
fatal("decl() fnchk nil");
n.left.decl = d;
if(d.store == Dglobal || d.store == Dfield)
d.store = Dfn;
if(d.store != Dfn || d.init != nil){
nerror(n, "redeclaration of function "+dotconv(d)+", previously declared as "
+storeconv(d)+" on line "+lineconv(d.src.start));
if(d.store == Dfn && d.init != nil)
bad = 1;
}
d.init = n;
t := n.ty;
inadt := d.dot;
if(inadt != nil && (inadt.store != Dtype || inadt.ty.kind != Tadt))
inadt = nil;
if(n.left.op == Odot){
pushscope(nil, Sother);
adtp := outerpolys(n.left);
if(adtp != nil)
installids(Dtype, adtp);
if(!polyequal(adtp, n.decl))
nerror(n, "adt polymorphic type mismatch");
n.decl = nil;
}
t = validtype(t, inadt);
if(n.left.op == Odot)
popscope();
if(debug['d'])
print("declare function %s ty %s newty %s\n", dotconv(d), typeconv(d.ty), typeconv(t));
t = usetype(t);
if(!polyequal(d.ty.polys, t.polys))
nerror(n, "function polymorphic type mismatch");
if(!tcompat(d.ty, t, 0))
nerror(n, "type mismatch: "+dotconv(d)+" defined as "
+typeconv(t)+" declared as "+typeconv(d.ty)+" on line "+lineconv(d.src.start));
else if(!raisescompat(d.ty.eraises, t.eraises))
nerror(n, "raises mismatch: " + dotconv(d));
if(t.varargs != byte 0)
nerror(n, "cannot define functions with a '*' argument, such as "+dotconv(d));
t.eraises = d.ty.eraises;
d.ty = t;
d.offset = idoffsets(t.ids, MaxTemp, IBY2WD);
d.src = n.src;
d.locals = nil;
n.ty = t;
if(bad)
return nil;
return d;
}
globalas(dst: ref Node, v: ref Node, valok: int): ref Node
{
if(v == nil)
return nil;
if(v.op == Oas || v.op == Odas){
v = globalas(v.left, v.right, valok);
if(v == nil)
return nil;
}else if(valok && !initable(dst, v, 0))
return nil;
case dst.op{
Oname =>
if(dst.decl.init != nil)
nerror(dst, "duplicate assignment to "+expconv(dst)+", previously assigned on line "
+lineconv(dst.decl.init.src.start));
if(valok)
dst.decl.init = v;
return v;
Otuple =>
if(valok && v.op != Otuple)
fatal("can't deal with "+nodeconv(v)+" in tuple case of globalas");
tv := v.left;
for(dst = dst.left; dst != nil; dst = dst.right){
globalas(dst.left, tv.left, valok);
if(valok)
tv = tv.right;
}
return v;
}
fatal("can't deal with "+nodeconv(dst)+" in globalas");
return nil;
}
needsstore(d: ref Decl): int
{
if(!d.refs)
return 0;
if(d.importid != nil)
return 0;
if(storespace[d.store])
return 1;
return 0;
}
#
# return the list of all referenced storage variables
#
vars(d: ref Decl): ref Decl
{
while(d != nil && !needsstore(d))
d = d.next;
for(v := d; v != nil; v = v.next){
while(v.next != nil){
n := v.next;
if(needsstore(n))
break;
v.next = n.next;
}
}
return d;
}
#
# declare variables from the left side of a := statement
#
recdasdecl(n: ref Node, store: int, nid: int): (int, int)
{
r: int;
case n.op{
Otuple =>
ok := 1;
for(n = n.left; n != nil; n = n.right){
(r, nid) = recdasdecl(n.left, store, nid);
ok &= r;
}
return (ok, nid);
Oname =>
if(n.decl == nildecl)
return (1, -1);
d := mkids(n.src, n.decl.sym, nil, nil);
installids(store, d);
n.decl = d;
old := d.old;
if(old != nil
&& old.store != Dfn
&& old.store != Dwundef
&& old.store != Dundef)
warn(d.src.start, "redeclaration of "+declconv(d)+", previously declared as "
+storeconv(old)+" on line "+lineconv(old.src.start));
d.refs++;
d.das = byte 1;
if(nid >= 0)
nid++;
return (1, nid);
}
return (0, nid);
}
recmark(n: ref Node, nid: int): int
{
case(n.op){
Otuple =>
for(n = n.left; n != nil; n = n.right)
nid = recmark(n.left, nid);
Oname =>
n.decl.nid = byte nid;
nid = 0;
}
return nid;
}
dasdecl(n: ref Node): int
{
ok: int;
nid := 0;
store := Dlocal;
if(scope == ScopeGlobal)
store = Dglobal;
(ok, nid) = recdasdecl(n, store, nid);
if(!ok)
nerror(n, "illegal declaration expression "+expconv(n));
if(ok && store == Dlocal && nid > 1)
recmark(n, nid);
return ok;
}
#
# declare global variables in nested := expressions
#
gdasdecl(n: ref Node)
{
if(n == nil)
return;
if(n.op == Odas){
gdasdecl(n.right);
dasdecl(n.left);
}else{
gdasdecl(n.left);
gdasdecl(n.right);
}
}
undefed(src: Src, s: ref Sym): ref Decl
{
d := mkids(src, s, tnone, nil);
error(src.start, s.name+" is not declared");
installids(Dwundef, d);
return d;
}
# inloop() : int
# {
# for (i := scope; i > 0; i--)
# if (int scopekind[i] == Sloop)
# return 1;
# return 0;
# }
nested() : int
{
for (i := scope; i > 0; i--)
if (int scopekind[i] == Sscope || int scopekind[i] == Sloop)
return 1;
return 0;
}
decltozero(n : ref Node)
{
if ((scop := scopenode[scope]) != nil) {
if (n.right != nil && errors == 0)
fatal("Ovardecl/Oname/Otuple has right field\n");
n.right = scop.left;
scop.left = n;
}
}
pushscope(scp : ref Node, kind : int)
{
if(scope >= MaxScope)
fatal("scope too deep");
scope++;
scopes[scope] = nil;
tails[scope] = nil;
scopenode[scope] = scp;
scopekind[scope] = byte kind;
}
curscope(): ref Decl
{
return scopes[scope];
}
#
# revert to old declarations for each symbol in the currect scope.
# remove the effects of any imported adt types
# whenever the adt is imported from a module,
# we record in the type's decl the module to use
# when calling members. the process is reversed here.
#
popscope(): ref Decl
{
for(id := scopes[scope]; id != nil; id = id.next){
if(id.sym != nil){
id.sym.decl = id.old;
id.old = nil;
}
if(id.importid != nil)
id.importid.refs += id.refs;
t := id.ty;
if(id.store == Dtype
&& t.decl != nil
&& t.decl.timport == id)
t.decl.timport = id.timport;
if(id.store == Dlocal)
freeloc(id);
}
return scopes[scope--];
}
#
# make a new scope,
# preinstalled with some previously installed identifiers
# don't add the identifiers to the scope chain,
# so they remain separate from any newly installed ids
#
# these routines assume no ids are imports
#
repushids(ids: ref Decl)
{
if(scope >= MaxScope)
fatal("scope too deep");
scope++;
scopes[scope] = nil;
tails[scope] = nil;
scopenode[scope] = nil;
scopekind[scope] = byte Sother;
for(; ids != nil; ids = ids.next){
if(ids.scope != scope
&& (ids.dot == nil || !isimpmod(ids.dot.sym)
|| ids.scope != ScopeGlobal || scope != ScopeGlobal + 1))
fatal("repushids scope mismatch");
s := ids.sym;
if(s != nil && ids.store != Dtag){
if(s.decl != nil && s.decl.scope >= scope)
ids.old = s.decl.old;
else
ids.old = s.decl;
s.decl = ids;
}
}
}
#
# pop a scope which was started with repushids
# return any newly installed ids
#
popids(ids: ref Decl): ref Decl
{
for(; ids != nil; ids = ids.next){
if(ids.sym != nil && ids.store != Dtag){
ids.sym.decl = ids.old;
ids.old = nil;
}
}
return popscope();
}
installids(store: int, ids: ref Decl)
{
last : ref Decl = nil;
for(d := ids; d != nil; d = d.next){
d.scope = scope;
if(d.store == Dundef)
d.store = store;
s := d.sym;
if(s != nil){
if(s.decl != nil && s.decl.scope >= scope){
redecl(d);
d.old = s.decl.old;
}else
d.old = s.decl;
s.decl = d;
}
last = d;
}
if(ids != nil){
d = tails[scope];
if(d == nil)
scopes[scope] = ids;
else
d.next = ids;
tails[scope] = last;
}
}
lookup(sym: ref Sym): ref Decl
{
s: int;
d: ref Decl;
for(s = scope; s >= ScopeBuiltin; s--){
for(d = scopes[s]; d != nil; d = d.next){
if(d.sym == sym)
return d;
}
}
return nil;
}
mkids(src: Src, s: ref Sym, t: ref Type, next: ref Decl): ref Decl
{
d := ref zdecl;
d.src = src;
d.store = Dundef;
d.ty = t;
d.next = next;
d.sym = s;
d.nid = byte 1;
return d;
}
mkdecl(src: Src, store: int, t: ref Type): ref Decl
{
d := ref zdecl;
d.src = src;
d.store = store;
d.ty = t;
d.nid = byte 1;
return d;
}
dupdecl(old: ref Decl): ref Decl
{
d := ref *old;
d.next = nil;
return d;
}
dupdecls(old: ref Decl): ref Decl
{
d, nd, first, last: ref Decl;
first = last = nil;
for(d = old; d != nil; d = d.next){
nd = dupdecl(d);
if(first == nil)
first = nd;
else
last.next = nd;
last = nd;
}
return first;
}
appdecls(d: ref Decl, dd: ref Decl): ref Decl
{
if(d == nil)
return dd;
for(t := d; t.next != nil; t = t.next)
;
t.next = dd;
return d;
}
revids(id: ref Decl): ref Decl
{
next : ref Decl;
d : ref Decl = nil;
for(; id != nil; id = next){
next = id.next;
id.next = d;
d = id;
}
return d;
}
idoffsets(id: ref Decl, offset: int, al: int): int
{
algn := 1;
for(; id != nil; id = id.next){
if(storespace[id.store]){
usedty(id.ty);
if(id.store == Dlocal && id.link != nil){
# id.nid always 1
id.offset = id.link.offset;
continue;
}
a := id.ty.align;
if(id.nid > byte 1){
for(d := id.next; d != nil && d.nid == byte 0; d = d.next)
if(d.ty.align > a)
a = d.ty.align;
algn = a;
}
offset = align(offset, a);
id.offset = offset;
offset += id.ty.size;
if(id.nid == byte 0 && (id.next == nil || id.next.nid != byte 0))
offset = align(offset, algn);
}
}
return align(offset, al);
}
idindices(id: ref Decl): int
{
i := 0;
for(; id != nil; id = id.next){
if(storespace[id.store]){
usedty(id.ty);
id.offset = i++;
}
}
return i;
}
declconv(d: ref Decl): string
{
if(d.sym == nil)
return storename[d.store] + " " + "<???>";
return storename[d.store] + " " + d.sym.name;
}
storeconv(d: ref Decl): string
{
return storeart[d.store] + storename[d.store];
}
dotconv(d: ref Decl): string
{
s: string;
if(d.dot != nil && !isimpmod(d.dot.sym)){
s = dotconv(d.dot);
if(d.dot.ty != nil && d.dot.ty.kind == Tmodule)
s += ".";
else
s += ".";
}
s += d.sym.name;
return s;
}
#
# merge together two sorted lists, yielding a sorted list
#
namemerge(e, f: ref Decl): ref Decl
{
d := rock := ref Decl;
while(e != nil && f != nil){
if(e.sym.name <= f.sym.name){
d.next = e;
e = e.next;
}else{
d.next = f;
f = f.next;
}
d = d.next;
}
if(e != nil)
d.next = e;
else
d.next = f;
return rock.next;
}
#
# recursively split lists and remerge them after they are sorted
#
recnamesort(d: ref Decl, n: int): ref Decl
{
if(n <= 1)
return d;
m := n / 2 - 1;
dd := d;
for(i := 0; i < m; i++)
dd = dd.next;
r := dd.next;
dd.next = nil;
return namemerge(recnamesort(d, n / 2),
recnamesort(r, (n + 1) / 2));
}
#
# sort the ids by name
#
namesort(d: ref Decl): ref Decl
{
n := 0;
for(dd := d; dd != nil; dd = dd.next)
n++;
return recnamesort(d, n);
}
printdecls(d: ref Decl)
{
for(; d != nil; d = d.next)
print("%d: %s %s ref %d\n", d.offset, declconv(d), typeconv(d.ty), d.refs);
}
mergepolydecs(t: ref Type)
{
n, nn: ref Node;
id, ids, ids1: ref Decl;
for(n = t.val; n != nil; n = n.right){
nn = n.left;
for(ids = nn.decl; ids != nil; ids = ids.next){
id = ids.sym.decl;
if(id == nil){
undefed(ids.src, ids.sym);
break;
}
if(id.store != Dtype){
error(ids.src.start, declconv(id) + " is not a type");
break;
}
if(id.ty.kind != Tpoly){
error(ids.src.start, declconv(id) + " is not a polymorphic type");
break;
}
if(id.ty.ids != nil)
error(ids.src.start, declconv(id) + " redefined");
pushscope(nil, Sother);
fielddecled(nn.left);
id.ty.ids = popscope();
for(ids1 = id.ty.ids; ids1 != nil; ids1 = ids1.next){
ids1.dot = id;
bindtypes(ids1.ty);
if(ids1.ty.kind != Tfn){
error(ids1.src.start, "only function types expected");
id.ty.ids = nil;
}
}
}
}
t.val = nil;
}
adjfnptrs(d: ref Decl, polys1: ref Decl, polys2: ref Decl)
{
n: int;
id, idt, idf, arg: ref Decl;
n = 0;
for(id = d.ty.ids; id != nil; id = id.next)
n++;
for(idt = polys1; idt != nil; idt = idt.next)
for(idf = idt.ty.ids; idf != nil; idf = idf.next)
n -= 2;
for(idt = polys2; idt != nil; idt = idt.next)
for(idf = idt.ty.ids; idf != nil; idf = idf.next)
n -= 2;
for(arg = d.ty.ids; --n >= 0; arg = arg.next)
;
for(idt = polys1; idt != nil; idt = idt.next){
for(idf = idt.ty.ids; idf != nil; idf = idf.next){
idf.link = arg;
arg = arg.next.next;
}
}
for(idt = polys2; idt != nil; idt = idt.next){
for(idf = idt.ty.ids; idf != nil; idf = idf.next){
idf.link = arg;
arg = arg.next.next;
}
}
}
addptrs(polys: ref Decl, fps: ref Decl, last: ref Decl, link: int, src: Src): (ref Decl, ref Decl)
{
for(idt := polys; idt != nil; idt = idt.next){
for(idf := idt.ty.ids; idf != nil; idf = idf.next){
fp := mkdecl(src, Darg, tany);
fp.sym = idf.sym;
if(link)
idf.link = fp;
if(fps == nil)
fps = fp;
else
last.next = fp;
last = fp;
fp = mkdecl(src, Darg, tint);
fp.sym = idf.sym;
last.next = fp;
last = fp;
}
}
return (fps, last);
}
addfnptrs(d: ref Decl, link: int)
{
fps, last, polys: ref Decl;
polys = encpolys(d);
if(int(d.ty.flags&FULLARGS)){
if(link)
adjfnptrs(d, d.ty.polys, polys);
return;
}
d.ty.flags |= FULLARGS;
fps = last = nil;
(fps, last) = addptrs(d.ty.polys, fps, last, link, d.src);
(fps, last) = addptrs(polys, fps, last, link, d.src);
for(last = d.ty.ids; last != nil && last.next != nil; last = last.next)
;
if(last != nil)
last.next = fps;
else
d.ty.ids = fps;
d.offset = idoffsets(d.ty.ids, MaxTemp, IBY2WD);
}
rmfnptrs(d: ref Decl)
{
n: int;
id, idt, idf: ref Decl;
if(int(d.ty.flags&FULLARGS))
d.ty.flags &= ~FULLARGS;
else
return;
n = 0;
for(id = d.ty.ids; id != nil; id = id.next)
n++;
for(idt = d.ty.polys; idt != nil; idt = idt.next)
for(idf = idt.ty.ids; idf != nil; idf = idf.next)
n -= 2;
for(idt = encpolys(d); idt != nil; idt = idt.next)
for(idf = idt.ty.ids; idf != nil; idf = idf.next)
n -= 2;
if(n == 0){
d.ty.ids = nil;
return;
}
for(id = d.ty.ids; --n > 0; id = id.next)
;
id.next = nil;
d.offset = idoffsets(d.ty.ids, MaxTemp, IBY2WD);
}
local(d: ref Decl): int
{
for(d = d.dot; d != nil; d = d.dot)
if(d.store == Dtype && d.ty.kind == Tmodule)
return 0;
return 1;
}
lmodule(d: ref Decl): ref Decl
{
for(d = d.dot; d != nil; d = d.dot)
if(d.store == Dtype && d.ty.kind == Tmodule)
return d;
return nil;
}
outerpolys(n: ref Node): ref Decl
{
d: ref Decl;
if(n.op == Odot){
d = n.right.decl;
if(d == nil)
fatal("decl() outeradt nil");
d = d.dot;
if(d != nil && d.store == Dtype && d.ty.kind == Tadt)
return d.ty.polys;
}
return nil;
}
encpolys(d: ref Decl): ref Decl
{
if((d = d.dot) == nil)
return nil;
return d.ty.polys;
}
fnlookup(s: ref Sym, t: ref Type): (ref Decl, ref Node)
{
id: ref Decl;
mod: ref Node;
id = nil;
mod = nil;
if(t.kind == Tpoly || t.kind == Tmodule)
id = namedot(t.ids, s);
else if(t.kind == Tref){
t = t.tof;
if(t.kind == Tadt){
id = namedot(t.ids, s);
if(t.decl != nil && t.decl.timport != nil)
mod = t.decl.timport.eimport;
}
else if(t.kind == Tadtpick){
id = namedot(t.ids, s);
if(t.decl != nil && t.decl.timport != nil)
mod = t.decl.timport.eimport;
t = t.decl.dot.ty;
if(id == nil)
id = namedot(t.ids, s);
if(t.decl != nil && t.decl.timport != nil)
mod = t.decl.timport.eimport;
}
}
if(id == nil){
id = lookup(s);
if(id != nil)
mod = id.eimport;
}
return (id, mod);
}
isimpmod(s: ref Sym): int
{
d: ref Decl;
for(d = impmods; d != nil; d = d.next)
if(d.sym == s)
return 1;
return 0;
}
dequal(d1: ref Decl, d2: ref Decl, full: int): int
{
return d1.sym == d2.sym &&
d1.store == d2.store &&
d1.implicit == d2.implicit &&
d1.cyc == d2.cyc &&
(!full || tequal(d1.ty, d2.ty)) &&
(!full || d1.store == Dfn || sametree(d1.init, d2.init));
}
tzero(t: ref Type): int
{
return t.kind == Texception || tmustzero(t);
}
isptr(t: ref Type): int
{
return t.kind == Texception || tattr[t.kind].isptr;
}
# can d share the same stack location as another local ?
shareloc(d: ref Decl)
{
z: int;
t, tt: ref Type;
dd, res: ref Decl;
if(d.store != Dlocal || d.nid != byte 1)
return;
t = d.ty;
res = nil;
for(dd = fndecls; dd != nil; dd = dd.next){
if(d == dd)
fatal("d==dd in shareloc");
if(dd.store != Dlocal || dd.nid != byte 1 || dd.link != nil || dd.tref != 0)
continue;
tt = dd.ty;
if(t.size != tt.size || t.align != tt.align)
continue;
z = tzero(t)+tzero(tt);
if(z > 0)
continue; # for now
if(t == tt || tequal(t, tt))
res = dd;
else{
if(z == 1)
continue;
if(z == 0 || isptr(t) || isptr(tt) || mktdesc(t) == mktdesc(tt))
res = dd;
}
if(res != nil){
d.link = res;
res.tref = 1;
return;
}
}
return;
}
freeloc(d: ref Decl)
{
if(d.link != nil)
d.link.tref = 0;
}