home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
COMPILER
/
TP.SA
< prev
next >
Wrap
Text File
|
1995-02-13
|
35KB
|
905 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". <----------
-- tp.sa: Classes relating to types in the Sather compiler.
-------------------------------------------------------------------
-- $TP: Abstract interface to Sather types.
-- TP_CLASS: Reference, value, abstract, or external types.
-- TP_ROUT: Bound routine types.
-- TP_ITER: Bound iter types.
-- TP_CONTEXT: Context for TR_TYPE_SPEC -> $TP conversion.
-- TP_TBL: Table of all types.
-- TP_CLASS_TBL: Table of class types.
-- TP_ROUT_TBL: Table of bound routine types.
-- TP_ITER_TBL: Table of bound iter types.
-- TP_GRAPH: Computes the type graph.
-- TP_GRAPH_ANC: Computes a type's '>' ancestors.
-- TP_GRAPH_DES: Computes a type's '<' descendants.
-- TP_BUILTIN: Cache of the type objects for builtin types.
-------------------------------------------------------------------
type $TP < $CALL_TP is
-- Abstract interface to classes representing Sather types.
-- Descendants are TP_CLASS, TP_ROUT, and TP_ITER.
prog:PROG; -- This type's program object.
str:STR; -- The string representation of self.
-- Uses no whitespace, eg: "FOO{A,B{C},D}".
is_abstract:BOOL; -- True if self is abstract.
is_value:BOOL; -- True is self is a value type.
is_atomic:BOOL; -- Does the implementation use pointers
-- that may affect garbage collection?
is_bound:BOOL; -- True if self is a bound type.
is_subtype(t:$TP):BOOL; -- True if self is a subtype of `t'.
is_eq(t:$TP):BOOL; -- Equality test.
is_neq(t:$TP):BOOL; -- Inequality test.
hash:INT; -- Hash value.
kind:INT; -- One of TP_KIND::missing_tp,
-- TP_KIND::val_tp, TP_KIND::ref_tp, TP_KIND::abs_tp,
-- TP_KIND::ext_tp, TP_KIND::rout_tp, TP_KIND::iter_tp.
end; -- type $TP
-------------------------------------------------------------------
class TP_KIND is
-- A set of constants defining the different kinds of types.
const missing_tp,
val_tp, -- Value types.
ref_tp, -- Reference types.
abs_tp, -- Abstract types.
ext_tp, -- External types.
rout_tp, -- Bound routine types.
iter_tp; -- Bound iter types.
end; -- class TP_KIND
-------------------------------------------------------------------
class TP is
-- Implementation to be included by $TP objects.
attr prog:PROG; -- This type's program object.
is_value:BOOL is
-- True if a value type.
return kind=TP_KIND::val_tp; end;
is_atomic:BOOL is
-- Conservative answer
return false;
end;
kind:INT is
raise "kind is expected to be redefined"; end;
is_eq(t:$TP):BOOL is
-- True if self equals `t'.
return SYS::ob_eq(self,t) end;
is_neq(t:$TP):BOOL is
-- True if self is not equal to `t'.
return ~SYS::ob_eq(self,t) end;
hash:INT is
-- A hash value for this type.
return SYS::id(self) end;
end; -- class TP
-------------------------------------------------------------------
class TP_CLASS < $TP is
-- Representation of reference, value, abstract, and external types.
include TP;
attr name:IDENT; -- The name of the type.
attr params:ARRAY{$TP}; -- Specifiers for the type
-- parameters in order, void if none.
private attr str_cache:STR; -- Cache for string representation.
private attr kind_cache:INT; -- Cache for the kind of class this is
private attr atomic_cache:BOOL;
private attr use_cached_atomic:BOOL;
create(name:IDENT, params:ARRAY{$TP}, prog:PROG):SAME is
-- A class type object with the specified attributes.
r::=new; r.name:=name; r.params:=params; r.prog:=prog;
r.kind_cache:=TP_KIND::missing_tp;
r.use_cached_atomic:=false;
return r end;
str:STR is
-- The string version of the type represented by self. Uses no
-- whitespace, eg: "FOO{A,B{C},D}".
if ~void(str_cache) then return str_cache end;
if void(self) then return "void" end;
if void(params) then str_cache:=name.str
else s::=#FSTR + name.str + '{';
loop s:=s+",".separate!(params.elt!.str) end;
s:=s+'}'; str_cache:=s.str end;
return str_cache end;
is_abstract:BOOL is
-- True if self is abstract.
if void(self) then return false end;
return name.str[0]='$' end;
is_bound:BOOL is
-- Returns false.
return false end;
is_subtype(t:$TP):BOOL is
-- True if self is a subtype of `t'.
if void(self) then return false end;
if self=t then return true
else
typecase t
when TP_CLASS then
if t.is_abstract then return prog.abs_subtype_test(self,t)
else return false end;
-- else return false end end end; -- NLP
else; end; end; return false; end; -- NLP
kind:INT is
-- One of TP_KIND::missing_tp, TP_KIND::val_tp, TP_KIND::ref_tp,
-- TP_KIND::abs_tp, TP_KIND::ext_tp, TP_KIND::rout_tp,
-- TP_KIND::iter_tp.
if kind_cache=TP_KIND::missing_tp then
kind_cache:=prog.tp_kind(self);
end;
return kind_cache end;
private is_atomic_implementation:BOOL is
-- figure out if we can be allocated atomically.
builtin ::= prog.tp_builtin;
if self = builtin.bool then
return true;
elsif self = builtin.char then
return true;
elsif self = builtin.int then
return true;
elsif self = builtin.flt then
return true
elsif self = builtin.fltd then
return true
elsif self = builtin.fltx then
return true
elsif self = builtin.fltx then
return true
elsif self = builtin.fltdx then
return true;
elsif self = builtin.flti then
return true;
elsif self = builtin.str then
return true;
elsif self = builtin.sys then
return false;
elsif self = builtin.str then
return true;
elsif self = builtin.ext_ob then
return false;
elsif self = builtin.dollar_ob then
return false;
end;
imp ::= prog.impl_tbl.impl_of(self);
return imp.is_atomic;
end;
is_atomic:BOOL is
-- mbk
if void(self) then return false end; --
if ~use_cached_atomic then
atomic_cache := is_atomic_implementation;
use_cached_atomic := true;
end;
return atomic_cache;
end;
end; -- class TP_CLASS
-------------------------------------------------------------------
class TP_ROUT < $TP is
-- Representation of bound routine types.
include TP;
attr args:ARRAY{$TP}; -- Specifiers for the argument types
-- in order, void if none.
attr ret:$TP; -- The return type, void if none.
create(args:ARRAY{$TP}, ret:$TP, prog:PROG):SAME is
-- A bound routine type object with the specified attributes.
r::=new; r.args:=args; r.ret:=ret; r.prog:=prog; return r end;
private attr str_cache:STR; -- Cache for string representation.
str:STR is
-- The string version of the type represented by self. Uses no
-- whitespace, eg: "ROUT{A,B{C},D}:E".
if void(self) then return "void" end;
if ~void(str_cache) then -- Don't need to do anything.
elsif void(args) and void(ret) then str_cache:="ROUT"
else s::=#FSTR + "ROUT";
if ~void(args) then
s:=s + '{';
loop s:=s+",".separate!(args.elt!.str) end;
s:=s + '}' end;
if ~void(ret) then s:=s + ':' + ret.str end;
str_cache:=s.str end;
return str_cache end;
is_abstract:BOOL is
-- Returns false.
return false end;
is_bound:BOOL is
-- Returns true.
return true end;
is_subtype(t:$TP):BOOL is
-- True if self is a subtype of `t'.
if void(self) then return false end;
typecase t
when TP_CLASS then
if ~t.is_abstract then return false
else return prog.abs_subtype_test(self,t) end;
when TP_ROUT then
-- Test for contravariant conformance. This means:
-- 1) Self and `t' have the same number of arguments.
-- 2) The type of each argument of `t' must conform to the
-- corresponding argument of self.
-- 3) Both have a return value or both do not.
-- 4) The return type of self msut conform to that of `t' if
-- they do.
if args.size/=t.args.size then return false end;
loop
if ~t.args.elt!.is_subtype(args.elt!)
then return false end end;
if has_ret/=t.has_ret then return false end;
if has_ret and ~ret.is_subtype(t.ret) then return false end;
return true
-- else return false end end; -- NLP
else; end; return false; end; -- NLP
has_ret:BOOL is
-- True if self has a return value.
return ~void(ret) end;
kind:INT is
-- The kind of this type.
return TP_KIND::rout_tp end;
end; -- class TP_ROUT
-------------------------------------------------------------------
class TP_ITER < $TP is
-- Representation of bound iter types.
include TP;
attr args:ARRAY{$TP}; -- Specifiers for the argument types
-- in order, void if none.
attr hot:ARRAY{BOOL}; -- Treu for each arg which is marked
-- with a "!". None are hot if this array is void.
attr ret:$TP; -- The return type, void if none.
create(args:ARRAY{$TP}, hot:ARRAY{BOOL}, ret:$TP, prog:PROG):SAME is
-- A bound routine type object with the specified attributes.
r::=new; r.args:=args; r.hot:=hot; r.ret:=ret; r.prog:=prog;
return r end;
attr str_cache:STR; -- Cache for string representation.
str:STR is
-- The string version of the type represented by self. Uses no
-- whitespace, eg: "ITER{A!,B{C},D}:E".
-- If self is void, returns "void".
if void(self) then return "void" end;
if ~void(str_cache) then -- Don't need to do anything.
elsif void(args) and void(ret) then str_cache:="ITER"
else s::=#FSTR + "ITER";
if ~void(args) then
s:=s + '{';
loop s:=s+",".separate!(args.elt!.str);
if ~void(hot) and hot.elt! then s:=s + '!' end end;
s:=s + '}' end;
if ~void(ret) then s:=s + ':' + ret.str end;
str_cache:=s.str end;
return str_cache end;
is_abstract:BOOL is
-- Returns false.
return false end;
is_bound:BOOL is
-- Returns true.
return true end;
is_subtype(t:$TP):BOOL is
-- True if self is a subtype of `t'.
if void(self) then return false end;
typecase t
when TP_CLASS then
if ~t.is_abstract then return false
else return prog.abs_subtype_test(self,t) end;
when TP_ITER then
-- Test for contravariant conformance. This means:
-- 1) Self and `t' have the same number of arguments.
-- 2) The type of each argument of `t' must conform to the
-- corresponding argument of self.
-- 3) Corresponding args must either both be hot or both not.
-- 4) Both have a return value or both do not.
-- 5) The return type of self msut conform to that of `t' if
-- they do.
if args.size/=t.args.size then return false end;
loop
if ~t.args.elt!.is_subtype(args.elt!)
then return false end end;
if hot.size/=t.hot.size then return false end;
loop
if hot.elt!/=t.hot.elt! then return false end end;
if has_ret/=t.has_ret then return false end;
if has_ret and ~ret.is_subtype(t.ret) then
return false end;
return true
-- else return false end end; -- NLP
else; end; return false; end; -- NLP
has_ret:BOOL is
-- True if self has a return value.
if void(self) then return false end;
return ~void(ret) end;
kind:INT is
-- The kind of this type.
return TP_KIND::iter_tp end;
end; -- class TP_ITER
-------------------------------------------------------------------
class TP_CONTEXT is
-- A context for converting TR_TYPE_SPEC trees into $TP objects.
attr same:TP_CLASS; -- The type that replaces "SAME",
attr pnames:ARRAY{IDENT}; -- Type parameter names, if any.
attr ptypes:ARRAY{$TP}; -- Type parameter values, if any.
attr is_abs:BOOL; -- True if in an abstract class.
attr prog:PROG; -- The program this is for.
create(same:TP_CLASS, pnames:ARRAY{IDENT}, ptypes:ARRAY{$TP},
prog:PROG):SAME is
-- A type context object with the specified attributes.
r::=new; r.same:=same; r.pnames:=pnames; r.ptypes:=ptypes;
r.prog:=prog; return r end;
value_of_param(s:IDENT):$TP is
-- The value of the parameter named by `s'. If `s' doesn't
-- name a parameter, returns void.
if void(pnames) then return void end;
loop i::=pnames.ind!;
if s=pnames[i] then return ptypes[i] end end;
return void end;
tp_of(t:TR_TYPE_SPEC):$TP is
-- The type object corresponding to the type specifier `t' in
-- this context. Void if `t' is void.
if void(t) then return void end;
case t.kind
when TR_TYPE_SPEC::ord then return tp_class_of(t)
when TR_TYPE_SPEC::rt then return tp_rout_of(t)
when TR_TYPE_SPEC::it then return tp_iter_of(t)
when TR_TYPE_SPEC::same then
if is_abs then prog.err_loc(t);
prog.err("SAME is not allowed in abstract classes.") end;
-- return same end end; -- NLP
return same; end; return void; end; -- NLP
tp_class_of(t:TR_TYPE_SPEC):$TP
-- The type object corresponding to the class type specifier
-- `t' in this context.
pre ~void(t) and t.kind=t.ord and void(t.ret) is
if void(t.params) then
pv::=value_of_param(t.name);
if ~void(pv) then return pv end; -- A parameter reference.
return prog.tp_tbl.tp_class_for(t.name, void) end;
ptps::=#ARRAY{$TP}(t.params.size);
tpe::=t.params;
loop until!(void(tpe)); ptps.set!(tp_of(tpe)); tpe:=tpe.next end;
return prog.tp_tbl.tp_class_for(t.name, ptps) end;
tp_rout_of(t:TR_TYPE_SPEC):$TP
-- The type object corresponding to the bound routine type
-- specifier `t' in this context.
pre ~void(t) and t.kind=t.rt is
if void(t.params) then
return prog.tp_tbl.tp_rout_for(void, tp_of(t.ret)) end;
args::=#ARRAY{$TP}(t.params.size);
tpe::=t.params;
loop until!(void(tpe)); args.set!(tp_of(tpe)); tpe:=tpe.next end;
return prog.tp_tbl.tp_rout_for(args, tp_of(t.ret)) end;
tp_iter_of(t:TR_TYPE_SPEC):$TP
-- The type object corresponding to the bound iter type
-- specifier `t' in this context.
pre ~void(t) and t.kind=t.it is
if void(t.params) then
return prog.tp_tbl.tp_iter_for(void, void, tp_of(t.ret)) end;
args::=#ARRAY{$TP}(t.params.size);
tpa::=t.params;
loop until!(void(tpa)); args.set!(tp_of(tpa)); tpa:=tpa.next end;
hot::=#ARRAY{BOOL}(args.size);
tpa:=t.params;
loop until!(void(tpa)); hot.set!(tpa.is_hot); tpa:=tpa.next end;
if ~hot.contains(true) then hot:=void end;
return prog.tp_tbl.tp_iter_for(args, hot, tp_of(t.ret)) end;
type_spec_has_same(t:TR_TYPE_SPEC):BOOL
-- True if the type spec `t' contains "SAME".
pre ~void(t) is
if t.kind=t.same then return true end;
p::=t.params;
loop while!(~void(p));
if type_spec_has_same(p) then return true end;
p:=p.next end;
if type_spec_has_same(t.ret) then return true end;
return false end;
type_spec_is_param(t:TR_TYPE_SPEC):BOOL
-- True if `t' is a type specifier which is just a type
-- parameter.
pre ~void(t) is
if t.kind/=t.ord or ~void(t.params) then return false end;
return pnames.contains(t.name) end;
end; -- class TP_CONTEXT
-------------------------------------------------------------------
class TP_TBL is
-- A table of types in a program. This ensures that each type
-- is only represented by a single object so that object
-- equality can be used to test for type equality.
attr prog:PROG; -- The program this belongs to.
attr class_tbl:TP_CLASS_TBL; -- Types defined by classes.
attr rout_tbl:TP_ROUT_TBL; -- Bound routine types.
attr iter_tbl:TP_ITER_TBL; -- Bound iter types.
create(prog:PROG):SAME is
-- A table of type for the program `prog'.
r::=new; r.prog:=prog; return r end;
tp_class_for(name:IDENT, params:ARRAY{$TP}):TP_CLASS is
-- Return the class type object for the name `name' and the
-- parameters (if any) `params'. If this has already been
-- accessed, return the old object, otherwise create a new
-- one using the array `params'.
r::=class_tbl.get_query(#(name,params));
if void(r) then r:=#(name,params,prog);
class_tbl:=class_tbl.insert(r) end;
return r end;
tp_rout_for(args:ARRAY{$TP}, ret:$TP):TP_ROUT is
-- Return the bound routine type object for the argument
-- types `args' (if any) and the return type `ret' (if any).
-- If this has already been accessed, return the old object,
-- otherwise create a new one using the array `args'.
r::=rout_tbl.get_query(#(args,ret));
if void(r) then r:=#(args,ret,prog);
rout_tbl:=rout_tbl.insert(r) end;
return r end;
tp_iter_for(args:ARRAY{$TP}, hot:ARRAY{BOOL}, ret:$TP):TP_ITER is
-- Return the bound iter type object for the argument
-- types `args' (if any), marked according to `hot' (if any)
-- and with return type `ret' (if any). If this has already
-- been accessed, return the old object, otherwise create a
-- new one using the arrays `args' and `hot'.
r::=iter_tbl.get_query(#(args,hot,ret));
if void(r) then r:=#(args,hot,ret,prog);
iter_tbl:=iter_tbl.insert(r) end;
return r end;
test(t:$TP):BOOL is
-- True if the type `t' is in the table.
typecase t
when TP_CLASS then return class_tbl.test(t)
when TP_ROUT then return rout_tbl.test(t)
-- when TP_ITER then return iter_tbl.test(t) end end; -- NLP
when TP_ITER then return iter_tbl.test(t); end; return false; end; -- NLP
insert(t:$TP) is
-- Insert the type `t' into the table.
typecase t
when TP_CLASS then class_tbl:=class_tbl.insert(t)
when TP_ROUT then rout_tbl:=rout_tbl.insert(t)
when TP_ITER then iter_tbl:=iter_tbl.insert(t) end end;
delete(t:$TP) is
-- Delete the type `t' from the table.
typecase t
when TP_CLASS then class_tbl:=class_tbl.delete(t)
when TP_ROUT then rout_tbl:=rout_tbl.delete(t)
when TP_ITER then iter_tbl:=iter_tbl.delete(t) end end;
end; -- class TP_TBL
-------------------------------------------------------------------
class TP_CLASS_TBL is
-- Table of types defined by classes: abstract, reference,
-- value, and external types.
--
-- `get_query(TUP{IDENT,ARRAY{$TP}}):TP_CLASS' looks up a type.
-- `test(TP_CLASS):BOOL' tests for a type.
-- `insert(TP_CLASS):SAME' inserts a type.
-- `delete(TP_CLASS):SAME' deletes a type.
include FQSET{TUP{IDENT,ARRAY{$TP}},TP_CLASS};
query_test(q:TUP{IDENT,ARRAY{$TP}}, t:TP_CLASS):BOOL is
-- True if `t' is the type described by `q'.
if void(t) then return false end;
if q.t1/=t.name then return false end;
if q.t2.size/=t.params.size then return false end;
loop if q.t2.elt!/=t.params.elt! then return false end end;
return true end;
query_hash(q:TUP{IDENT,ARRAY{$TP}}):INT is
-- A hash value computed from the query types.
s::=3;
r::=q.t1.hash; -- Make depend on name.
loop s:=s+98; r:=r.bxor(SYS::id(q.t2.elt!)*s) end; -- And on params.
return r end;
elt_hash(e:TP_CLASS):INT is
-- Hash on the types in `e'.
s::=3;
r::=e.name.hash; -- Make depend on name.
loop s:=s+98; r:=r.bxor(SYS::id(e.params.elt!)*s) end; -- On params.
return r end;
end; -- class TP_CLASS_TBL
-------------------------------------------------------------------
class TP_ROUT_TBL is
-- Tables of bound routine types.
--
-- `get_query(TUP{ARRAY{$TP},$TP}):TP_ROUT' look up a type.
-- `test(TP_ROUT):BOOL' tests for a type.
-- `insert(TP_ROUT):SAME' inserts a type.
-- `delete(TP_ROUT):SAME' deletes a type.
include FQSET{TUP{ARRAY{$TP},$TP}, TP_ROUT};
query_test(q:TUP{ARRAY{$TP},$TP}, t:TP_ROUT):BOOL is
-- True if `t' is a bound routine with arg and return types as
-- listed in `q'.
if void(t) then return false end;
if void(q.t2) then if ~void(t.ret) then return false end
elsif q.t2/=t.ret then return false end;
if q.t1.size/=t.args.size then return false end;
loop if q.t1.elt!/=t.args.elt! then return false end end;
return true end;
query_hash(q:TUP{ARRAY{$TP},$TP}):INT is
-- A hash value computed from the query types.
s::=3;
r::=0;
if ~void(q.t2) then r:=SYS::id(q.t2); end; -- Make depend on return type.
loop r:=r.bxor(SYS::id(q.t1.elt!)*s); s:=s+98 end; -- Arg types.
return r end;
elt_hash(e:TP_ROUT):INT is
-- Hash on the types in `e'.
s::=3;
r::=0;
if ~void(e.ret) then r:=SYS::id(e.ret); end;-- Make depend on return type.
loop r:=r.bxor(SYS::id(e.args.elt!)*s); s:=s+98 end; -- Arg types.
return r end;
end; -- class TP_ROUT_TBL
-------------------------------------------------------------------
class TP_ITER_TBL is
-- Tables of bound iter types.
--
-- `get_query(TUP{ARRAY{$TP},ARRAY{BOOL},$TP}):TP_ITER' look up a type.
-- `test(TP_ITER):BOOL' tests for a type.
-- `insert(TP_ITER):SAME' inserts a type.
-- `delete(TP_ITER):SAME' deletes a type.
include FQSET{TUP{ARRAY{$TP},ARRAY{BOOL},$TP}, TP_ITER};
query_test(q:TUP{ARRAY{$TP},ARRAY{BOOL},$TP}, t:TP_ITER):BOOL is
-- True if `t' is a bound iter with arg types, arg hotness and
-- return type as listed in `q'.
if void(t) then return false end;
if q.t3/=t.ret then return false end;
if q.t1.size/=t.args.size then return false end;
loop if q.t1.elt!/=t.args.elt! then return false end end;
if q.t2.size/=t.hot.size then return false end;
loop if q.t2.elt!/=t.hot.elt! then return false end end;
return true end;
query_hash(q:TUP{ARRAY{$TP},ARRAY{BOOL},$TP}):INT is
-- A hash value computed from the query types.
s::=3;
r::=SYS::id(q.t3); -- Make depend on return type.
loop r:=r.bxor(SYS::id(q.t1.elt!)*s); s:=s+98 end; -- Arg types.
loop r:=r.bxor(SYS::id(q.t2.elt!)*s); s:=s+98 end; -- Hotness.
return r end;
elt_hash(e:TP_ITER):INT is
-- Hash on the types in `e'.
s::=3;
r::=SYS::id(e.ret); -- Make depend on return type.
loop r:=r.bxor(SYS::id(e.args.elt!)*s); s:=s+98 end; -- Arg types.
loop r:=r.bxor(SYS::id(e.hot.elt!)*s); s:=s+98 end; -- Hotness.
return r end;
end; -- class TP_ITER_TBL
-------------------------------------------------------------------
class TP_GRAPH is
-- Objects which represent Sather type graphs.
-- The tables do not explicitly represent the edges between
-- bound objects and they separately represent edges due to
-- "subtype" ("<") and "supertype" (">") clauses.
attr prog:PROG;
attr anc:TP_GRAPH_ANC; -- Table of '<' ancestors.
attr des:TP_GRAPH_DES; -- Table of '>' descendants.
create(prog:PROG):SAME is
-- A type graph for the program `prog'.
r::=new; r.prog:=prog; r.anc:=#(prog); r.des:=#(prog);
return r end;
abs_subtype_test(t:$TP, at:TP_CLASS):BOOL
-- True if the type `t' is a subtype of the abstract type `at'.
pre at.is_abstract is
if t=at or at=prog.tp_builtin.dollar_ob then return true end;
typecase t
when TP_CLASS then
if anc.get_anc(t).test(at) then return true end;
else end;
if des.get_des(at).test(t) then return true end;
return false end;
end; -- class TP_GRAPH
-------------------------------------------------------------------
class TP_GRAPH_ANC is
-- Table of "<" ancestors for each class type.
attr prog:PROG; -- The program this table belongs to.
attr par_tbl:FMAP{TP_CLASS,FSET{TP_CLASS}}; -- Map from each class
-- type to the direct supertypes (from the "<" clause).
attr anc_tbl:FMAP{TP_CLASS,FSET{TP_CLASS}}; -- Map from each class
-- type to its ancestors due to "<".
attr cur:FSET{TUP{IDENT,INT}}; -- The set of type names
-- and number of parameters which are in the process of
-- determining their ancestors. Used to detect loops.
create(prog:PROG):SAME is
-- An ancestor table for the program `prog'.
r::=new; r.prog:=prog; return r end;
get_parents(t:TP_CLASS):FSET{TP_CLASS} is
-- The set of "<" parents for `t', void if none. Don't modify
-- the returned list.
p::=par_tbl.get_pair(t); if ~void(p.t1) then return p.t2 end;
tr::=prog.tree_head_for(t.name, t.params.size);
if void(tr) or void(tr.under) then return void end;
con::=prog.tp_context_for(t); r:FSET{TP_CLASS};
ts::=tr.under;
loop until!(void(ts)); prog.err_loc(ts); tp::=con.tp_of(ts);
typecase tp
when TP_CLASS then
if ~tp.is_abstract then
prog.err("In type " + t.str + " the type " + tp.str +
" appears in the supertype list but is not abstract.")
else r:=r.insert(tp) end;
else prog.err("In type " + t.str + " the type " + tp.str +
" appears in the supertype list but is a bound type.") end;
ts:=ts.next end;
par_tbl:=par_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;
get_anc(t:TP_CLASS):FSET{TP_CLASS} is
-- The set of "<" ancestors for `t'. Void if none. $OB is not
-- explicitly included. Do not modify the returned table.
-- Reports an error if there is a loop. All returned types
-- should be abstract.
p::=anc_tbl.get_pair(t); if ~void(p.t1) then return p.t2 end;
par::=get_parents(t);
if void(par) then return void end;
cq::=#TUP{IDENT,INT}(t.name,t.params.size);
if cur.test(cq) then
tr::=prog.tree_head_for(t.name, t.params.size);
prog.err_loc(tr);
s::=#FSTR + "Subtype cycle detected involving the types: ";
loop s:=s+", ".separate!(tup_str(cur.elt!)) end;
prog.err(s.str);
anc_tbl:=anc_tbl.insert(t,void); cur:=cur.delete(cq);
return void end;
r:FSET{TP_CLASS}; cur:=cur.insert(cq);
loop t2::=par.elt!;
r:=r.insert(t2); r:=r.to_union(get_anc(t2)) end;
anc_tbl:=anc_tbl.insert(t,r); cur:=cur.delete(cq); return r end;
end; -- class TP_GRAPH_ANC
-------------------------------------------------------------------
class TP_GRAPH_DES is
-- Table of ">" descendants for each abstract type.
attr prog:PROG; -- The program this table belongs to.
attr child_tbl:FMAP{TP_CLASS,FSET{$TP}}; -- Map from each abstract
-- type to any explicit children due to ">".
attr des_tbl:FMAP{TP_CLASS,FSET{$TP}}; -- Table of ">" descendants
-- for each abstract type.
attr cur:FSET{TUP{IDENT,INT}}; -- The set of types which are
-- in the process of determining their "descendants". Used to
-- detect loops.
create(prog:PROG):SAME is
-- A descendant table for the program `prog'.
r::=new; r.prog:=prog; return r end;
get_children(t:TP_CLASS):FSET{$TP} is
-- The set of ">" children for `t', void if none. Don't modify
-- the returned table.
r:FSET{$TP};
if ~t.is_abstract then return void end; -- Non-abstract
-- types don't have explicit subtypes.
p::=child_tbl.get_pair(t); if ~void(p.t1) then return p.t2 end;
tr::=prog.tree_head_for(t.name, t.params.size);
if void(tr) or void(tr.over) then return void end;
con::=prog.tp_context_for(t);
ts::=tr.over;
loop until!(void(ts)); prog.err_loc(ts); tp::=con.tp_of(ts);
typecase tp when TP_CLASS then
if prog.tp_kind(tp)=TP_KIND::ext_tp then
prog.err("The type " + t.str +
" lists the external type " +
tp.str + " in its subtype list.")
else r:=r.insert(tp) end
else r:=r.insert(tp) end;
ts:=ts.next end;
child_tbl:=child_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;
get_des(t:TP_CLASS):FSET{$TP} is
-- The set of ">" descendants for `t'. Void if none.
-- Do not modify the returned table. Reports an error if there
-- is a loop.
p::=des_tbl.get_pair(t); if ~void(p.t1) then return p.t2 end;
cld::=get_children(t); if void(cld) then return void end;
cq::=#TUP{IDENT,INT}(t.name,t.params.size);
if cur.test(cq) then
tr::=prog.tree_head_for(t.name, t.params.size);
prog.err_loc(tr);
s::=#FSTR + "Supertype cycle detected involving the types with "
"the following names and number of parameters: ";
loop s:=s+", ".separate!(tup_str(cur.elt!)) end;
prog.err(s.str);
des_tbl:=des_tbl.insert(t,void); cur:=cur.delete(cq);
return void end;
r:FSET{$TP}; cur:=cur.insert(cq);
loop t2::=cld.elt!;
r:=r.insert(t2);
typecase t2
when TP_CLASS then r:=r.to_union(get_des(t2))
else end end;
des_tbl:=des_tbl.insert(t,r); cur:=cur.delete(cq); return r end;
end; -- class TP_GRAPH_DES
-------------------------------------------------------------------
class TP_GRAPH_ABS_DES is
-- Table of all concrete descendants of abstract types.
attr prog:PROG; -- The program this table belongs to.
attr tbl:FMAP{TP_CLASS,FSET{$TP}}; -- Table of concrete descendants
-- of each abstract type.
create(prog:PROG):SAME is
-- Compute an abstract descendant table for the program `prog',
-- from the explicit ancestor and descendant tables `anc' and
-- `des'.
r::=new; r.prog:=prog; return r end;
do_tbl is
-- Compute the table assuming that `prog.tp_graph' and
-- `prog.find_types' are done.
do_dollar_ob; do_anc; do_des end;
do_dollar_ob is
-- Put in all concrete types under $OB.
dob:TP_CLASS:=prog.tp_builtin.dollar_ob;
tt:FSET{$TP}:=prog.prog_find_types.tp_done;
if void(tt) then return end;
loop tp::=tt.elt!;
if ~tp.is_abstract then add(dob,tp) end end end;
do_anc is
-- Put entries in the table based on the subtype edges.
loop p::=prog.tp_graph.anc.anc_tbl.pairs!;
if ~p.t1.is_abstract then
loop add(p.t2.elt!,p.t1) end end end end;
do_des is
-- Put entries in the table based on the supertype edges.
loop p::=prog.tp_graph.des.des_tbl.pairs!;
loop ct::=p.t2.elt!;
if ~ct.is_abstract then add(p.t1,ct) end end end end;
add(at:TP_CLASS,ct:$TP) is
-- Add the concrete type `ct' as one of the descendants of the
-- abstract type `at'.
s::=tbl.get(at); s:=s.insert(ct); tbl:=tbl.insert(at,s) end;
des_of(tp:TP_CLASS):FSET{$TP} is
-- A table of the concrete descendants of the abstract type
-- `tp'. Void if none.
return tbl.get(tp) end;
end; -- class TP_GRAPH_ABS_DES
-------------------------------------------------------------------
class TP_BUILTIN is
-- Cache for quick access to the type objects for builtin types.
attr dollar_ob, bool, char, int, inti, flt, fltd, fltx, fltdx, flti,
str, sys, ext_ob, dollar_rehash, arr_of_str:TP_CLASS;
attr rout:TP_ROUT;
-- The type objects representing the named types.
create(prog:PROG):SAME is
-- A table of builtin types for the program `prog'.
t:TP_TBL:=prog.tp_tbl;
r::=new;
r.dollar_ob:=t.tp_class_for(prog.ident_for("$OB"),void);
r.bool:=t.tp_class_for(prog.ident_for("BOOL"),void);
r.char:=t.tp_class_for(prog.ident_for("CHAR"),void);
r.int:=t.tp_class_for(prog.ident_for("INT"),void);
r.inti:=t.tp_class_for(prog.ident_for("INTI"),void);
r.flt:=t.tp_class_for(prog.ident_for("FLT"),void);
r.fltd:=t.tp_class_for(prog.ident_for("FLTD"),void);
r.fltx:=t.tp_class_for(prog.ident_for("FLTX"),void);
r.fltdx:=t.tp_class_for(prog.ident_for("FLTDX"),void);
r.flti:=t.tp_class_for(prog.ident_for("FLTI"),void);
r.str:=t.tp_class_for(prog.ident_for("STR"),void);
r.sys:=t.tp_class_for(prog.ident_for("SYS"),void);
r.ext_ob:=t.tp_class_for(prog.ident_for("EXT_OB"),void);
r.dollar_rehash:=t.tp_class_for(prog.ident_for("$REHASH"),void);
r.rout:=t.tp_rout_for(void,void); -- ROUT
arr:ARRAY{$TP}:=ARRAY{$TP}::create(1); arr[0]:=r.str;
r.arr_of_str:=t.tp_class_for(prog.ident_for("ARRAY"),arr);
return r end;
end; -- class TP_BUILTIN
-------------------------------------------------------------------