home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
COMPILER
/
IFC.SA
< prev
next >
Wrap
Text File
|
1994-11-15
|
10KB
|
290 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
-- ifc.sa: Type interfaces in the Sather compiler.
-------------------------------------------------------------------
-- IFC: The interface of a type.
-- IFC_TBL: A table of interfaces indexed by type.
-- IFC_ABS_CREATE: Create an interface for an abstract type.
-------------------------------------------------------------------
class IFC is
-- A type interface.
attr tp:$TP; -- The type whose interface this is.
attr sigs:SIG_TBL; -- The interface signatures.
create(sigs:SIG_TBL, tp:$TP):SAME is
-- An interface with the signatures `sigs' for the type `tp'.
-- Never gives void.
r::=new; r.sigs:=sigs; r.tp:=tp; return r end;
prog:PROG is
-- The program this interface belongs to.
return tp.prog end;
sig_conforming_to(s:SIG):SIG
-- A signature from the interface which conforms to `s' or void
-- if none. This will be unique if the interface has no conflicts.
pre ~void(self) and ~void(s) is
loop ts::=sigs.get_query!(s.name);
if ts.conforms_to(s) then return ts end end;
return void end;
sig_equal_to(s:SIG):SIG
-- A signature from self which is equal to `s' if present,
-- void if not.
pre ~void(self) and ~void(s) is
loop ts::=sigs.get_query!(s.name);
if ts.is_eq(s) then return ts end end;
return void end;
nonconforming_sig(i:IFC):SIG
-- If self conforms to `i' then return void, otherwise return
-- a signature in `i' for which there is no conforming signature
-- in self.
pre ~void(self) and ~void(i) is
loop s::=i.sigs.elt!;
if void(sig_conforming_to(s)) then return s end end;
return void end;
conforms_to(i:IFC):BOOL is
-- True if self conforms to `i'. This means that for every
-- signature in `i' there is a signature in self which conforms
-- to it.
return void(nonconforming_sig(i)) end;
conflicting_sigs:TUP{SIG,SIG}
-- If self has a conflict, return two conflicting signatures.
-- Otherwise, return #(void,void).
pre ~void(self) is
loop s::=sigs.elt!;
loop st::=sigs.get_query!(s.name);
if ~SYS::ob_eq(st,s) and st.conflicts_with(s) then
return #(s,st) end end end;
return #(void,void) end;
is_conflict_free:BOOL is
-- True if self is free of conflicting signatures.
return void(conflicting_sigs) end;
sig_for_call(c:CALL_SIG):SIG
-- A signature from the interface to which the call `c' conforms.
-- Void if none. Reports an error if the call is ambiguous
-- or missing (assumes that "err_loc" has been set).
-- If it is unknown whether there is a return value, then
-- choose the signature without one in case of conflict.
pre ~void(self) and ~void(c) is
r:SIG;
loop s::=sigs.get_query!(c.name);
if c.conforms_to(s) then
if void(r) then r:=s
elsif c.unknown_ret and void(r.ret) and ~void(s.ret) then
-- Keep this one.
elsif c.unknown_ret and ~void(r.ret) and void(s.ret) then
r:=s -- Choose the version with no return.
else c.prog.err("The call " + c.str +
" matches both the features: " + r.str +
" and " + s.str + "."); return void end end end;
if void(r) then
c.prog.err("No match for the call " + c.str + ".") end;
return r end;
ifc_for_rout(t:TP_ROUT):SAME
-- The interface of a bound routine type.
pre ~void(t) is
r::=new; r.tp:=t;
r.sigs:=r.sigs.insert(SIG::bound_routine_call(t));
return r end;
ifc_for_iter(t:TP_ITER):SAME
-- The interface of a bound iter type.
pre ~void(t) is
r::=new; r.tp:=t;
r.sigs:=r.sigs.insert(SIG::bound_iter_call(t));
return r end;
show is
-- Print the interface on OUT.
if void(self) then #OUT + "Interface=void\n"; return end;
if void(tp) then #OUT + "Interface tp=void\n"; return end;
#OUT + "Interface of " + tp.str + " = ";
if void(sigs) then #OUT + "void\n"; return end;
loop s::=sigs.elt!;
if ~void(s) then #OUT + " ".separate!(s.str) end end;
#OUT + "\n" end;
end; -- class IFC
-------------------------------------------------------------------
class IFC_TBL is
-- A table of interfaces indexed by type.
attr prog:PROG; -- The program this is for.
attr tbl:FMAP{$TP,IFC}; -- The table mapping types to their
-- interfaces.
attr abs_cur:FSET{TUP{IDENT,INT}}; -- The set of abstract class
-- names and number of parameters which are currently having
-- their interfaces worked out.
create(p:PROG):SAME is
-- A new table for the program `p'.
r::=new; r.prog:=p; return r end;
ifc_of(t:$TP):IFC
-- The interface corrponding to arg. Void if not computable.
-- Any caller of this should set the appropriate error location.
-- Never gives void.
pre ~void(t) is
r::=tbl.get(t); if ~void(r) then return r end;
typecase t
when TP_CLASS then
if t.is_abstract then
cq::=#TUP{IDENT,INT}(t.name,t.params.size);
if abs_cur.test(cq) then
cycle_err; abs_cur:=abs_cur.clear;
else abs_cur:=abs_cur.insert(cq);
r:=IFC_ABS_CREATE::ifc_of(t);
abs_cur:=abs_cur.delete(cq) end
else
im:IMPL:=prog.impl_tbl.impl_of(t);
if void(im) then r:=void
else r:=im.ifc end end;
when TP_ROUT then
r:=IFC::ifc_for_rout(t);
when TP_ITER then
r:=IFC::ifc_for_iter(t) end;
if void(r) then
prog.err("Compiler error, IFC_TBL::ifc_of=void") end;
tbl:=tbl.insert(t,r); return r end;
tup_str(t:TUP{IDENT,INT}):STR is
-- A string for the specified type of the form "FOO{_,_,_}".
r::=t.t1.str;
if t.t2=0 then return r end;
r:=r+"{";
loop t.t2.times!; r:=r+",".separate!("_") end;
r:=r+"}"; return r end;
cycle_err is
-- Print an error message about a cycle of include type names.
s:STR:="Cycle detected in `subtyping' clauses involving the types: ";
loop s:=s + ", ".separate!(tup_str(abs_cur.elt!)) end;
prog.err(s) end;
end; -- class IFC_TBL
-------------------------------------------------------------------
class IFC_ABS_CREATE is
-- Create an interface for an abstract type.
attr tp:TP_CLASS; -- The abstract type it is for.
attr con:TP_CONTEXT; -- The type context for tp.
attr tr:TR_CLASS_DEF; -- The definition tree for tp.
attr class_sigs:SIG_TBL; -- Table of signature explicitly
-- in the class.
attr supers:FLIST{IFC}; -- Interfaces of supertypes.
ifc_of(t:TP_CLASS):IFC
-- Compute the interface of the abstract type `t'.
pre ~void(t) is
if t.prog.show_ifc_abs_create then
#OUT + "(Abstract ifc create " + t.str + ") " end;
ic::=new; ic.tp:=t;
ic.con:=ic.prog.tp_context_for(t);
if void(ic.con) then return void end;
ic.tr:=ic.prog.tree_for(t.name,t.params.size);
if void(ic.tr) then
t.prog.err("Compiler error: IFC_ABS_CREATE:ifc_of tr=void for " +
t.str + "."); return void end;
ic.do_explicit_class_sigs;
ic.do_supers;
return IFC::create(ic.do_sigs,t) end;
prog:PROG is
-- The program this belongs to.
return tp.prog end;
do_explicit_class_sigs is
-- Compute `class_sigs'.
be:$TR_CLASS_ELT:=tr.body;
loop until!(void(be)); prog.err_loc(be);
typecase be
when TR_CONST_DEF then
prog.err("Abstract classes may not define constants.");
when TR_SHARED_DEF then
prog.err("Abstract classes may not define shareds.");
when TR_ATTR_DEF then
prog.err("Abstract classes may not define attributes.");
when TR_ROUT_DEF then
if ~be.is_abstract then prog.err(
"Abstract classes may only have abstract routines.") end;
ns:SIG:=SIG::rout_sig(be,be.name,con);
cs:SIG:=class_sigs.sig_conflicting_with(ns);
if ~void(cs) then
prog.err("The two explicitly defined signatures " +
ns.str + " and " + cs.str + " conflict.")
else class_sigs:=class_sigs.insert(ns) end;
when TR_INCLUDE_CLAUSE then
prog.err("Abstract classes may not have include clauses.");
end;
be:=be.next end end;
do_supers is
-- Compute `supers'.
ut:TR_TYPE_SPEC:=tr.under;
loop until!(void(ut));
tp:$TP:=con.tp_of(ut); prog.err_loc(ut);
typecase tp
when TP_CLASS then
if ~tp.is_abstract then
prog.err("Abstract types must have abstract supertypes.")
else
itp:IFC:=prog.ifc_tbl.ifc_of(tp);
supers:=supers.push(itp) end;
else
prog.err("Abstract types must have abstract supertypes.") end;
ut:=ut.next end end;
do_sigs:SIG_TBL is
-- The final sig table assuming everything else has been computed.
r:SIG_TBL;
loop r:=r.insert(class_sigs.elt!) end;
loop
if supers.is_empty then break!
else
si:IFC:=supers.pop;
loop sig::=si.sigs.elt!;
if ~void(r.sig_conflicting_with(sig)) then
-- included signature is overridden by explicit one
-- or we've already done this one.
else
i:INT:=0;
loop while!(i<supers.size);
cs:SIG:=supers[i].sigs.sig_conflicting_with(sig);
if ~void(cs) then
if ~cs.is_eq_but_tp(sig) then
prog.err_loc(tr);
prog.err("The signatures " + sig.str +
" and " + cs.str +
" must be disambiguated by an explicit sig.")
end end;
i:=i+1 end;
r:=r.insert(sig.with_new_type(tp))
end;
end;
end;
end;
return r end;
end; -- class IFC_ABS_CREATE
-------------------------------------------------------------------