home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
COMPILER
/
TRANS.SA
< prev
Wrap
Text File
|
1995-02-14
|
89KB
|
2,145 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". <----------
-- trans.sa: Transformation of code from TR to AM form.
-------------------------------------------------------------------
class TRANS is
-- The context for a code transformation from TR form to AM form.
attr prog:PROG; -- The program this code is from.
attr impl:IMPL; -- The implementation structure for the
-- type within which this transformation appears.
attr tp_con:TP_CONTEXT; -- The type context for interpreting
-- type specifiers.
attr cur_rout:AM_ROUT_DEF; -- The current routine or iter.
attr cur_loop:AM_LOOP_STMT; -- Current loop if any.
attr cur_yield_ind:INT; -- Index of the current yield.
attr active_locals:FLIST{AM_LOCAL_EXPR}; -- Locals in scope.
attr in_pre:BOOL; -- True if inside a `pre' clause.
attr in_post:BOOL; -- True if this code is inside
-- a "post" clause (and so can have initial expressions).
attr in_protect_body:BOOL; -- True if inside a `protect' body.
attr in_protect_then:BOOL; -- True if inside a `protect' `then' or
-- `else' clause.
attr ex_tp:$TP; -- Type of exception expr.
attr in_invariant:BOOL; -- True if inside an invariant body.
attr in_initial:BOOL; -- True if inside an `initial' expr.
attr init_stmts:$AM_STMT; -- The initial statments if any.
attr in_external:BOOL; -- True if inside an external class.
attr in_constant:BOOL; -- True if inside a constant or shared
-- initialization expression.
create(e:ELT):SAME
-- Create a new transformation context for the element e.
pre ~void(e) is
r::=new; r.prog:=e.prog; r.impl:=e.impl;
r.tp_con:=e.con;
if void(r.impl) or void(r.tp_con) then return void end;
return r end;
is_iter:BOOL is
-- True if we are working on an iter.
if void(cur_rout) then return false end;
return cur_rout.is_iter end;
local_with_name(n:IDENT):AM_LOCAL_EXPR
-- The local with the name `n', if any. Void otherwise.
pre ~void(cur_rout) is
loop r::=cur_rout.elt!;
if void(r) then
#OUT + "Compiler error, TRANS::local_with_name, void local.";
return void end;
if r.name=n then return r end end;
loop r::=active_locals.elt!;
if void(r) then
#OUT + "Compiler error, TRANS::local_with_name, void local.";
return void end;
if r.name=n then return r end end;
return void end;
add_local(l:AM_LOCAL_EXPR) is
-- Add the local variable `l'.
if void(cur_rout) then
#OUT + "Compiler error, TRANS::add_local, cur_rout=void.";
return end;
cur_rout.locals:=cur_rout.locals.push(l);
if ~void(l.name) then active_locals:=active_locals.push(l) end end;
tp_of(t:TR_TYPE_SPEC):$TP
-- The type object corresponding to the type specifier `t' in
-- this context. Void if `t' is void.
pre ~void(t) is
return tp_con.tp_of(t) end;
inline(call:AM_ROUT_CALL_EXPR):$AM_EXPR is
-- If `call' can be inlined, return the inlining expression,
-- otherwise just return it.
prog.prog_am_generate.output_sig(call.fun); -- Make sure it's been
-- generated.
itbl::=prog.prog_am_generate.inline_tbl;
in::=itbl.get_query(call.fun);
if void(in) then return call end;
return in.inline(call,self) end;
-----------
transform_elt(e:ELT):AM_ROUT_DEF
-- Transform the element `e' into AM form. Ignores self.
-- Should not be applied to void.
-- If there is a problem, returns void.
pre ~void(e) is
t:SAME:=#(e); if void(t) then return void end;
tr::=e.tr;
r:AM_ROUT_DEF;
typecase tr
when TR_CONST_DEF then r:=t.transform_const_elt(e,tr)
when TR_SHARED_DEF then r:=t.transform_shared_elt(e,tr)
when TR_ATTR_DEF then r:=t.transform_attr_elt(e,tr)
when TR_ROUT_DEF then r:=t.transform_rout_elt(e,tr)
end;
return r;
end;
transform_const_elt(e:ELT,tr:TR_CONST_DEF):AM_ROUT_DEF is
-- Transform the element `e' into AM form.
r:AM_ROUT_DEF:=#AM_ROUT_DEF(1,tr.source); cur_rout:=r;
r.srcsig:=e.srcsig;
r[0]:=#AM_LOCAL_EXPR(tr.source,prog.ident_builtin.self_ident,e.tp);
r.sig:=e.sig;
g:AM_GLOBAL_EXPR:=prog.global_tbl.get(e.name,impl.tp);
if void(g) then
g:=#AM_GLOBAL_EXPR(tr.source); g.name:=e.name;
g.tp_at:=e.ret; g.class_tp:=impl.tp; g.is_const:=true;
in_constant:=true;
g.init:=transform_expr(tr.init,g.tp_at);
in_constant:=false;
prog.global_tbl.insert(g) end;
ar::=#AM_RETURN_STMT(tr.source); ar.val:=g;
r.code:=ar; r.is_clean:=true;
return r end;
transform_shared_elt(e:ELT,tr:TR_SHARED_DEF):AM_ROUT_DEF is
-- Transform the element `e' into AM form.
if e.is_shared_reader then -- Shared reader.
r::=#AM_ROUT_DEF(1,tr.source); cur_rout:=r;
r.srcsig:=e.srcsig;
r[0]:=#AM_LOCAL_EXPR(tr.source, -- Local for self.
prog.ident_builtin.self_ident, e.tp);
r.sig:=e.sig;
g:AM_GLOBAL_EXPR:=prog.global_tbl.get(e.name,impl.tp);
if void(g) then
g:=#AM_GLOBAL_EXPR(tr.source); g.name:=e.name;
g.tp_at:=e.ret; g.class_tp:=impl.tp;
in_constant:=true;
g.init:=transform_expr(tr.init,g.tp);
in_constant:=false;
prog.global_tbl.insert(g) end;
g.tp_at:=e.sig.ret;
ar::=#AM_RETURN_STMT(tr.source); ar.val:=g;
r.code:=ar; r.is_clean:=true; return r
-- else -- Shared writer.
end; -- Shared writer. -- NLP
r::=#AM_ROUT_DEF(2,tr.source); cur_rout:=r;
r.srcsig:=e.srcsig;
r[0]:=#AM_LOCAL_EXPR(tr.source, -- Local for self.
prog.ident_builtin.self_ident, e.tp);
if void(e.sig.args) then
prog.err("Compiler error, TRANS::transform_shared_elt, "
"e.sig.args=void."); return void end;
r[1]:=#AM_LOCAL_EXPR(tr.source, e.name, e.sig.args[0]);
r.sig:=e.sig;
g:AM_GLOBAL_EXPR:=prog.global_tbl.get(e.name,impl.tp);
if void(g) then
g:=#AM_GLOBAL_EXPR(tr.source); g.name:=e.name;
g.class_tp:=impl.tp;
in_constant:=true;
g.init:=transform_expr(tr.init,g.tp);
in_constant:=false;
prog.global_tbl.insert(g) end;
g.tp_at:=e.sig.args[0];
ar::=#AM_ASSIGN_STMT(tr.source);
ar.dest:=g; ar.src:=r[1];
inv:AM_INVARIANT_STMT;
if ~e.is_private and ~in_invariant then
isig:SIG:=impl.invariant_sig;
if ~void(isig) then
inv:=#AM_INVARIANT_STMT(tr.source);
inv.sig:=isig;
icall::=#AM_ROUT_CALL_EXPR(1,tr.source);
icall.fun:=isig;
r.calls:=r.calls.push(icall) end end;
r.code:=ar;
if void(r.code) then r.code:=inv
else r.code.append(inv) end;
-- r.is_clean:=false; return r end end; -- NLP
r.is_clean:=false; return r; end; -- NLP
transform_attr_elt(e:ELT,tr:TR_ATTR_DEF):AM_ROUT_DEF is
-- Transform the element `e' into AM form.
r:AM_ROUT_DEF;
if e.is_attr_reader then -- Attribute reader.
r:=#AM_ROUT_DEF(1,tr.source);
r.srcsig:=e.srcsig;
r[0]:=#AM_LOCAL_EXPR(tr.source,prog.ident_builtin.self_ident,
e.tp);
r.sig:=e.sig;
ae::=#AM_ATTR_EXPR(tr.source);
ae.ob:=r[0]; ae.self_tp:=ae.ob.tp;
ae.at:=e.name; ae.tp_at:=tp_of(tr.tp);
if void(ae.tp_at) then
prog.err_loc(tr.tp); prog.err("Cannot translate type.");
return void end;
ar::=#AM_RETURN_STMT(tr.source);
ar.val:=ae; r.code:=ar; r.is_clean:=true;
else -- Attribute writer.
r:=#AM_ROUT_DEF(2,tr.source);
r.srcsig:=e.srcsig;
r[0]:=#AM_LOCAL_EXPR(tr.source, prog.ident_builtin.self_ident,
e.tp);
if void(e.sig.args) then
prog.err("Compiler error, TRANS::transform_attr_elt, "
"e.sig.args=void."); return void end;
r[1]:=#AM_LOCAL_EXPR(tr.source,e.name,e.sig.args[0]);
r.sig:=e.sig;
if prog.tp_kind(tp_con.same)=TP_KIND::val_tp then -- Value type.
av::=#AM_VATTR_ASSIGN_EXPR(tr.source);
av.ob:=r[0]; av.at:=e.name; av.val:=r[1];
ar::=#AM_RETURN_STMT(tr.source);
ar.val:=av; r.code:=ar;
else -- Reference type.
ae::=#AM_ATTR_EXPR(tr.source);
ae.ob:=r[0]; ae.self_tp:=ae.ob.tp;
ae.at:=e.name; ae.tp_at:=tp_of(tr.tp);
if void(ae.tp_at) then
prog.err_loc(tr.tp); prog.err("Cannot translate type.");
return void end;
ar::=#AM_ASSIGN_STMT(tr.source);
ar.dest:=ae; ar.src:=r[1]; r.code:=ar;
end;
inv:AM_INVARIANT_STMT;
if ~e.is_private and ~in_invariant then
isig:SIG:=impl.invariant_sig;
if ~void(isig) then
inv:=#AM_INVARIANT_STMT(tr.source);
inv.sig:=isig;
icall::=#AM_ROUT_CALL_EXPR(1,tr.source);
icall.fun:=isig;
r.calls:=r.calls.push(icall) end end;
if void(r.code) then r.code:=inv
else r.code.append(inv) end;
r.is_clean:=false; end;
return r end;
transform_rout_elt(e:ELT,tr:TR_ROUT_DEF):AM_ROUT_DEF is
-- Transform the element `e' into AM form.
-- Changed by MBK to emit code for "nomacro" built-ins when
-- necessary
if e.sig.is_builtin then
if ~prog.back_end.built_in_which_may_be_emitted_anyway(e.sig)
then return void end; -- added MBK.
end; -- Don't do it if builtin.
if e.is_invariant then in_invariant:=true else
in_invariant:=false end;
if tr.is_abstract then
if e.is_external then return void -- Don't do anything special for
-- abstract sigs in external classes.
else
prog.err_loc(tr);
prog.err("Compiler error, TRANS::tranform_rout_elt given "
"abstract"); return void end end;
check_return(tr);
r::=#AM_ROUT_DEF(1+e.sig.args.size,tr.source);
r.srcsig:=e.srcsig; r.sig:=e.sig;
if e.is_external then r.is_external:=true end;
r[0]:=#AM_LOCAL_EXPR(tr.source,prog.ident_builtin.self_ident, e.tp);
if e.sig.has_ret then
r.rres:=#AM_LOCAL_EXPR(tr.source,void,e.ret); -- For return.
r.locals:=r.locals.push(r.rres);
end;
i:INT:=0; na:TR_ARG_DEC:=tr.args_dec;
if na.size/=e.sig.args.size then
prog.err_loc(tr);
prog.err("Compiler error, TRANS::transform_rout_elt size bug.");
return void end;
loop while!(i<e.sig.args.size);
l::=#AM_LOCAL_EXPR(tr.source, na.name, e.sig.args[i]);
r[i+1]:=l;
i:=i+1; na:=na.next end;
cur_rout:=r;
pres:AM_PRE_STMT;
if ~void(tr.pre_e) then
in_pre:=true;
pres:=#AM_PRE_STMT(tr.source);
pres.tp:=impl.tp;
pres.test:=transform_expr(tr.pre_e,prog.tp_builtin.bool);
if void(pres.test) then pres:=void end;
in_pre:=false end;
posts:AM_POST_STMT;
if ~void(tr.post_e) then
in_post:=true;
posts:=#AM_POST_STMT(tr.source);
posts.tp:=impl.tp;
posts.test:=transform_expr(tr.post_e,prog.tp_builtin.bool);
if void(posts.test) then posts:=void end;
in_post:=false end;
code:$AM_STMT;
if is_array_sig(e.srcsig) then code:=transform_array_body(e)
else code:=transform_stmt_list(tr.stmts) end;
inv:AM_INVARIANT_STMT;
if ~e.is_private and ~in_invariant then
isig:SIG:=impl.invariant_sig;
if ~void(isig) then
inv:=#AM_INVARIANT_STMT(tr.source);
inv.sig:=isig;
icall::=#AM_ROUT_CALL_EXPR(1,tr.source);
icall.fun:=isig;
r.calls:=r.calls.push(icall) end end;
r.code:=init_stmts; -- First do the initial statments.
if void(r.code) then
r.code:=pres -- Then the pre statement.
else r.code.append(pres) end;
if void(r.code) then
r.code:=code -- Then the body statement.
else r.code.append(code) end;
if void(r.code) then
r.code:=posts -- Then the post statement.
else r.code.append(posts) end;
if void(r.code) then
r.code:=inv -- Then the invariant statement.
else r.code.append(inv) end;
return r;
end;
is_array_sig(s:SIG):BOOL is
-- True if `s' is `aset' or `aget' in AVAL or AREF.
if void(s) then return false end;
stp::=s.tp;
typecase stp
when TP_CLASS then
if stp.name/=prog.ident_builtin.AREF_ident and
stp.name/=prog.ident_builtin.AVAL_ident then return false end;
if void(stp.params) then return false end;
if stp.params.size/=1 then return false end;
if s.name/=prog.ident_builtin.aget_ident and
s.name/=prog.ident_builtin.aset_ident then return false end;
return true
-- else return false end end; -- NLP
else; end; return false; end; -- NLP
transform_array_body(e:ELT):$AM_STMT is
-- The statements implementing an array retrieval or assignment
-- assuming that `e' is `aset' or `aget' included from AVAL or AREF.
est::=e.srcsig.tp; stp:TP_CLASS;
typecase est when TP_CLASS then stp:=est end;
if stp.name=prog.ident_builtin.AREF_ident then -- from AREF
if e.srcsig.name=prog.ident_builtin.aget_ident then -- aget
r::=#AM_RETURN_STMT(e.tr.source);
aae::=#AM_ARR_EXPR(e.tr.source);
aae.ob:=cur_rout[0]; -- `self' is object to index into.
aae.ind:=cur_rout[1]; -- First arg is the index.
aae.tp_at:=stp.params[0]; -- Type of held element.
r.val:=aae;
return r
else -- aset
r::=#AM_ASSIGN_STMT(e.tr.source);
aae::=#AM_ARR_EXPR(e.tr.source);
aae.ob:=cur_rout[0]; -- `self' is object to index into.
aae.ind:=cur_rout[1]; -- First arg is the index.
aae.tp_at:=stp.params[0]; -- Type of held element.
r.dest:=aae;
r.src:=cur_rout[2]; -- New value is second argument.
return r end;
-- else -- from AVAL -- NLP
end; -- from AVAL -- NLP
if e.srcsig.name=prog.ident_builtin.aget_ident then -- aget
r::=#AM_RETURN_STMT(e.tr.source);
aae::=#AM_ARR_EXPR(e.tr.source);
aae.ob:=cur_rout[0]; -- `self' is object to index into.
aae.ind:=cur_rout[1]; -- First arg is the index.
aae.tp_at:=stp.params[0]; -- Type of held element.
r.val:=aae; return r
-- else -- aset -- NLP
end; -- aset -- NLP
r::=#AM_RETURN_STMT(e.tr.source);
avae::=#AM_VARR_ASSIGN_EXPR(e.tr.source);
avae.ob:=cur_rout[0];
avae.ind:=cur_rout[1];
avae.val:=cur_rout[2];
-- r.val:=avae; return r end end end; -- NLP
r.val:=avae; return r; end; -- NLP
-----------
transform_stmt_list(s:$TR_STMT):$AM_STMT is
-- A list of AM_STMT's which implements all the statements in
-- the source list `s'.
if void(s) then return void end;
osize:INT;
if ~void(active_locals) then osize:=active_locals.size end;
r:$AM_STMT;
loop while!(~void(s));
if void(r) then r:=transform_stmt(s)
else r.append(transform_stmt(s)) end;
s:=s.next end;
-- Close off the scope:
if ~void(active_locals) then
loop while!(active_locals.size>osize);
ignore::=active_locals.pop end;
end;
return r end;
transform_stmt(s:$TR_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if void(s) then return void end;
typecase s
when TR_DEC_STMT then return transform_dec_stmt(s)
when TR_ASSIGN_STMT then return transform_assign_stmt(s)
when TR_IF_STMT then return transform_if_stmt(s)
when TR_LOOP_STMT then return transform_loop_stmt(s)
when TR_RETURN_STMT then return transform_return_stmt(s)
when TR_YIELD_STMT then return transform_yield_stmt(s)
when TR_QUIT_STMT then return transform_quit_stmt(s)
when TR_CASE_STMT then return transform_case_stmt(s)
when TR_TYPECASE_STMT then return transform_typecase_stmt(s)
when TR_ASSERT_STMT then return transform_assert_stmt(s)
when TR_PROTECT_STMT then return transform_protect_stmt(s)
when TR_RAISE_STMT then return transform_raise_stmt(s)
-- when TR_EXPR_STMT then return transform_expr_stmt(s) end end; -- NLP
when TR_EXPR_STMT then return transform_expr_stmt(s) end; return void; end; -- NLP
-----------
transform_dec_stmt(s:TR_DEC_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
l:AM_LOCAL_EXPR:=local_with_name(s.name);
prog.err_loc(s);
if ~void(l) then
prog.err("This local variable declaration is in the scope of " +
l.name.str + ":" + l.tp_at.str +
" which has the same name."); return void end;
l:=#AM_LOCAL_EXPR(s.source, s.name, tp_of(s.tp));
l.needs_init:=true;
add_local(l);
return void end;
-----------
transform_assign_stmt(s:TR_ASSIGN_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if void(s.lhs_expr) then return transform_assign_dec_stmt(s) end;
lhs:$TR_EXPR:=s.lhs_expr; prog.err_loc(lhs);
typecase lhs
when TR_CALL_EXPR then
if lhs.is_array then
return transform_array_assign_stmt(lhs,s)
else return transform_call_assign_stmt(lhs,s) end;
when TR_SELF_EXPR then
prog.err("It is illegal to assign to `self'.");
when TR_VOID_EXPR then
prog.err("It is illegal to assign to `void'.");
when TR_IS_VOID_EXPR then
prog.err("It is illegal to assign to a `void' test expression.");
when TR_ARRAY_EXPR then
prog.err("It is illegal to assign to an array expression.");
when TR_CREATE_EXPR then
prog.err("It is illegal to assign to a creation expression.");
when TR_BOUND_CREATE_EXPR then
prog.err("It is illegal to assign to a bound create expression.");
when TR_AND_EXPR then
prog.err("It is illegal to assign to an `and' expression.");
when TR_OR_EXPR then
prog.err("It is illegal to assign to an `or' expression.");
when TR_EXCEPT_EXPR then
prog.err("It is illegal to assign to an `exception' expression.");
when TR_NEW_EXPR then
prog.err("It is illegal to assign to a `new' expression.");
when TR_INITIAL_EXPR then
prog.err("It is illegal to assign to an `initial' expression.");
when TR_BREAK_EXPR then
prog.err("It is illegal to assign to a `break!' expression.");
when TR_RESULT_EXPR then
prog.err("It is illegal to assign to a `result' expression.");
when TR_BOOL_LIT_EXPR then
prog.err("It is illegal to assign to a boolean literal.");
when TR_CHAR_LIT_EXPR then
prog.err("It is illegal to assign to a character literal.");
when TR_STR_LIT_EXPR then
prog.err("It is illegal to assign to a string literal.");
when TR_INT_LIT_EXPR then
prog.err("It is illegal to assign to an integer literal.");
when TR_FLT_LIT_EXPR then
prog.err("It is illegal to assign to a floating point literal.");
end;
return void end;
transform_assign_dec_stmt(s:TR_ASSIGN_STMT):$AM_STMT
-- A list of AM_STMT's which implements the source statement `s'.
-- This is an assignment which declares a local variable and
-- assigns to it.
pre void(s) or void(s.lhs_expr) is
if void(s) then return void end;
l:AM_LOCAL_EXPR:=local_with_name(s.name);
prog.err_loc(s);
if ~void(l) then
prog.err("This local variable declaration is in the scope of " +
l.name.str + ":" + l.tp_at.str +
" which has the same name."); return void end;
l:=#AM_LOCAL_EXPR(s.source,s.name,void);
if in_protect_body then l.is_volatile:=true end;
r:AM_ASSIGN_STMT;
if ~void(s.tp) then -- Explicitly specified type ":FOO:="
l.tp_at:=tp_of(s.tp);
if void(l.tp_at) then
prog.err_loc(s);
prog.err("Compiler error, TRANS::transform_assign_dec_stmt, "
"bad type.");
return void end;
add_local(l); -- Add it here since type is known.
r:=#AM_ASSIGN_STMT(s.source); r.dest:=l;
r.src:=transform_expr(s.rhs,l.tp);
if void(r.src) then return void end;
return r end;
-- If you get here, then the declared type is inferred.
rhs:$TR_EXPR:=s.rhs; prog.err_loc(s.rhs);
typecase rhs
when TR_VOID_EXPR then
prog.err("The right hand side of `::=' may not be `void'.");
return void;
when TR_CREATE_EXPR then
if void(rhs.tp) then
prog.err("Creation expressions on the right hand side "
"of `::=' must explicitly specify a type."); return void end;
when TR_ARRAY_EXPR then
prog.err("The right hand side of `::=' may not be an array "
"creation expression."); return void
else end;
r:=#AM_ASSIGN_STMT(s.source); r.dest:=l;
r.src:=transform_expr(s.rhs,void);
if void(r.src) then
l.tp_at:=prog.tp_builtin.dollar_ob; add_local(l); return void end;
l.tp_at:=r.src.tp; add_local(l); return r end;
transform_array_assign_stmt(l:TR_CALL_EXPR,s:TR_ASSIGN_STMT):$AM_STMT
-- A list of AM_STMT's which implements the source statement `s'.
-- This is an assignment to the call expression `l' which has
-- `is_array' equal to true. So we know it is one of the forms:
-- "[a,b,c]:=d" or "e[a,b,c]:=d" and should become "aset(a,b,c,d)"
-- or "e.aset(a,b,c,d).
pre l.is_array=true is
-- We change the call object by giving it the name "aset" adding
-- on the righthand side as an extra argument, transform it and
-- then change it back.
r::=#AM_EXPR_STMT(l.source);
l.name:=prog.ident_builtin.aset_ident; l.is_array:=false;
if void(l.args) then l.args:=s.rhs;
r.expr:=transform_call_expr(l,void,false);
l.args:=void;
else lst::=l.args; loop until!(void(lst.next)); lst:=lst.next end;
lst.next:=s.rhs;
r.expr:=transform_call_expr(l,void,false);
lst.next:=void;
end;
l.name:=void; l.is_array:=true;
return r end;
transform_call_assign_stmt(l:TR_CALL_EXPR,s:TR_ASSIGN_STMT):$AM_STMT
-- A list of AM_STMT's which implements the source statement `s'.
-- This is an assignment to the call expression `l' which has
-- `is_array' equal to false.
pre l.is_array=false is
if ~void(l.args) then -- One of the forms:
-- "a(5):=foo", "x.a(5):=foo", or "A::a(5):=foo"
prog.err_loc(l);
prog.err("It is illegal to assign to a call with arguments.");
return void end;
if void(l.ob) and void(l.tp) then
-- "a:=foo", This is the case that might be a local variable.
loc:AM_LOCAL_EXPR:=local_with_name(l.name);
if ~void(loc) then return transform_local_assign_stmt(loc,s)
end end;
-- At this point we are either of the form "a:=foo" and not a
-- local, "x.a:=foo" or "A::x:=foo".
-- We change the call object by adding on the righthand side as an
-- argument, transform it and then put it back to void:
l.args:=s.rhs;
r::=#AM_EXPR_STMT(l.source);
r.expr:=transform_call_expr(l,void,false);
l.args:=void; return r end;
transform_local_assign_stmt(loc:AM_LOCAL_EXPR,
s:TR_ASSIGN_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source assignment
-- `s'. At this point we know it is an assignment to the local
-- variable `loc'.
if loc.no_assign then
prog.err_loc(s);
prog.err("It is illegal to assign to the typecase variable.");
return void end;
r::=#AM_ASSIGN_STMT(s.source);
-- Does the assignment to the local.
r.dest:=loc; -- Make the local be the destination.
if in_protect_body then loc.is_volatile:=true end;
r.src:=transform_expr(s.rhs,loc.tp);
if void(r.src) then return void end; -- Type error.
return r end;
-----------
transform_if_stmt(s:TR_IF_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
r::=#AM_IF_STMT(s.source);
r.test:=transform_expr(s.test, prog.tp_builtin.bool);
if void(r.test) then return void end; -- Not a boolean.
r.if_true:=transform_stmt_list(s.then_part);
r.if_false:=transform_stmt_list(s.else_part);
return r end;
-----------
transform_loop_stmt(s:TR_LOOP_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
ol:AM_LOOP_STMT:=cur_loop; -- Save the old loop object, if any.
r::=#AM_LOOP_STMT(s.source);
cur_loop:=r; -- Any enclosed iters will add themselves.
r.body:=transform_stmt_list(s.body);
if ~void(ol) and ~void(r) then
ol.has_yield:=ol.has_yield or r.has_yield; -- Prop "has_yield".
end;
cur_loop:=ol; -- Restore the old loop object, if any.
return r end;
-----------
transform_return_stmt(s:TR_RETURN_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if is_iter then return_in_iter_err(s); return void end;
if ~void(s.next) then stmts_after_return_err(s) end;
rtp:$TP:=cur_rout.sig.ret; -- The return type if any.
if void(s.val) then -- No return value specified.
if ~void(rtp) then
missing_return_value_err(s,rtp); return void end;
return #AM_RETURN_STMT(s.source)
-- else -- with return value. -- NLP
end; -- with return value. -- NLP
if void(rtp) then
extra_return_value_err(s, cur_rout.sig); return void end;
r::=#AM_RETURN_STMT(s.source);
r.val:=transform_expr(s.val,rtp);
if void(r.val) then return void end; -- wrong type.
-- return r end end; -- NLP
return r; end; -- NLP
return_in_iter_err(s:TR_RETURN_STMT) is
prog.err_loc(s);
prog.err("`return' statements may not appear in iters.") end;
stmts_after_return_err(s:TR_RETURN_STMT) is
prog.err_loc(s);
prog.err("No statements may follow `return' in a statment list.");
end;
missing_return_value_err(s:TR_RETURN_STMT, tp:$TP) is
prog.err_loc(s);
prog.err("A return value of type: " + tp.str +
" must be specified.") end;
extra_return_value_err(s:TR_RETURN_STMT, sig:SIG) is
prog.err_loc(s);
prog.err("No return value should be provided for the signature: " +
sig.str + ".") end;
-----------
transform_yield_stmt(s:TR_YIELD_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if ~is_iter then yield_in_rout_err(s); return void end;
rtp:$TP:=cur_rout.sig.ret; -- The return type if any.
if void(s.val) then -- No return value specified.
if ~void(rtp) then
missing_yield_value_err(s,rtp); return void end;
y::=#AM_YIELD_STMT(s.source);
cur_yield_ind:=cur_yield_ind+1; y.ret:=cur_yield_ind;
cur_rout.num_yields:=cur_rout.num_yields+1;
if ~void(cur_loop) then cur_loop.has_yield:=true end;
return y
-- else -- with return value. -- NLP
end; -- with return value. -- NLP
if void(rtp) then
extra_yield_value_err(s, cur_rout.sig); return void end;
r::=#AM_YIELD_STMT(s.source);
r.val:=transform_expr(s.val,rtp);
if void(r.val) then return void end; -- wrong type.
cur_yield_ind:=cur_yield_ind+1; r.ret:=cur_yield_ind;
cur_rout.num_yields:=cur_rout.num_yields+1;
if ~void(cur_loop) then cur_loop.has_yield:=true end;
-- return r end end; -- NLP
return r; end; -- NLP
yield_in_rout_err(s:TR_YIELD_STMT) is
prog.err_loc(s);
prog.err("`yield' statements may not appear in routines.") end;
missing_yield_value_err(s:TR_YIELD_STMT, tp:$TP) is
prog.err_loc(s);
prog.err("A yield value of type: " + tp.str +
" must be specified.") end;
extra_yield_value_err(s:TR_YIELD_STMT, sig:SIG) is
prog.err_loc(s);
prog.err("No yield value should be provided for the signature: " +
sig.str + ".") end;
-----------
transform_quit_stmt(s:TR_QUIT_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if ~is_iter then quit_in_rout_err(s); return void end;
if ~void(s.next) then stmts_after_quit_err(s) end;
return #AM_RETURN_STMT(s.source) end;
quit_in_rout_err(s:TR_QUIT_STMT) is
prog.err_loc(s);
prog.err("`quit' statements may not appear in routines.") end;
stmts_after_quit_err(s:TR_QUIT_STMT) is
prog.err_loc(s);
prog.err("No statements may follow `quit' in a statment list.") end;
-----------
transform_case_stmt(s:TR_CASE_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if void(s) then return void end;
r::=#AM_ASSIGN_STMT(s.source);
-- Assign test to a local variable.
r.src:=transform_expr(s.test,void);
if void(r.src) then return void end;
l::=#AM_LOCAL_EXPR(s.source,void,r.src.tp);
add_local(l); r.dest:=l;
r.next:=transform_case_when(s,s.when_part,l);
return r end;
private const_to_switch(e:$AM_EXPR):$AM_CONST is
-- returns a constant expression that can be used in a
-- when clause of an AM_CASE_STMT, or void if it cannot
-- be used.
if void(e) then return void; end;
typecase e
when AM_CHAR_CONST then return e;
when AM_INT_CONST then return e;
when AM_GLOBAL_EXPR then return const_to_switch(e.init);
-- else return void; -- NLP
else; -- NLP
end;
return void; -- NLP
end;
transform_case_when(s:TR_CASE_STMT, cw:TR_CASE_WHEN,
l:AM_LOCAL_EXPR):$AM_STMT is
-- A list of AM_STMT's which implements the list of "when" clauses
-- and else clause in `s' starting at `cw'. `l' is the local variable
-- with the value to test against. This will generate
-- AM_CASE_STMT's for constants and AM_IF_STMT's otherwise.
if void(cw) then -- Just do the else clause.
if s.no_else then
r::=#AM_CASE_STMT(s.source);
r.test:=l; r.no_else:=true; return r
else
return transform_stmt_list(s.else_part) end end;
prog.err_loc(cw); -- In case of error.
ct:$CALL_TP:=call_tp_of_expr(cw.val); -- Call type of test expr.
v:$AM_EXPR; -- The value of test expr.
if void(ct) then v:=transform_expr(cw.val,void);
if void(v) then return void end; -- Error!
cv:$AM_CONST:=const_to_switch(v);
if ~void(cv) then
r::=#AM_CASE_STMT(cw.source);
r.test:=l;
last_then:$TR_STMT:=cw.then_part;
ls:FLIST{$AM_CONST}; ls:=ls.push(cv);
r.tgts:=r.tgts.push(ls);
r.stmts:=r.stmts.push(transform_stmt_list(cw.then_part));
loop cw:=cw.next;
if void(cw) then
if s.no_else then r.no_else:=true
else r.else_stmts:=transform_stmt_list(s.else_part) end;
return r end;
if ~void(call_tp_of_expr(cw.val)) then -- Do an if in else.
r.else_stmts:=transform_case_when(s,cw,l);
return r end;
v:=transform_expr(cw.val,void);
if void(v) then return void end; -- Error!
cv:=const_to_switch(v);
if ~void(cv) then
if SYS::ob_eq(last_then,cw.then_part) then
-- add to same stmt
ls:=r.tgts.pop; ls:=ls.push(cv);
r.tgts:=r.tgts.push(ls);
else -- Start a new "when" list
ls:=void; ls:=ls.push(cv); r.tgts:=r.tgts.push(ls);
r.stmts:=
r.stmts.push(transform_stmt_list(cw.then_part));
end;
else -- Do an if and put it in else.
r.else_stmts:=transform_case_when(s,cw,l);
return r
end; -- if
end; -- loop
end; -- if
end; -- if
-- At this point we need to generate an `if'. One of `ct' and
-- `v' is void, the other non-void.
cs::=#CALL_SIG;
cs.tp:=l.tp_at; cs.name:=prog.ident_builtin.is_eq_ident;
cs.has_ret:=true;
cs.args:=#ARRAY{$CALL_TP}(1);
if ~void(ct) then cs.args[0]:=ct else cs.args[0]:=v.tp end;
sig:SIG:=cs.lookup(tp_con.same=cs.tp); -- Arg true if in this class.
if void(sig) then return void end; -- Error!
if sig.ret/=prog.tp_builtin.bool then
prog.err("The `is_eq' routine corresponding to a `case' branch "
"must return a boolean."); return void end;
if void(v) then v:=transform_expr(cw.val,sig.args[0]) end;
if void(v) then return void end; -- Error!
-- Create the call on the routine `is_eq'.
arc::=#AM_ROUT_CALL_EXPR(2,cw.source);
arc.fun:=sig; arc[0]:=l; arc[1]:=v;
r::=#AM_IF_STMT(cw.source);
r.test:=inline(arc);
r.if_true:=transform_stmt_list(cw.then_part);
r.if_false:=transform_case_when(s,cw.next,l);
return r end;
-----------
transform_typecase_stmt(s:TR_TYPECASE_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
res:$AM_STMT;
l:AM_LOCAL_EXPR:=local_with_name(s.name);
if void(l) then typecase_local_err(s); return void end;
if cur_rout.local_is_hot(l) then
typecase_hot_local_err(s); return void end;
ono_assign:BOOL:=l.no_assign; -- Old value (if currently in typecase).
l.no_assign:=true; -- Freeze it for the current typecase.
ltp:$TP:=l.tp; -- The declared type of the local.
if ltp.is_abstract or ltp.is_bound then -- Do a full typecase.
r::=#AM_TYPECASE_STMT(s.source);
r.test:=l; wp:TR_TYPECASE_WHEN:=s.when_part;
loop while!(~void(wp));
tp:$TP:=tp_of(wp.tp); -- Type to compare against.
if tp.is_abstract or tp.is_bound or tp.is_subtype(ltp) then
-- Only these could possibly match.
if ltp.is_subtype(tp) then
if ~r.has_void_stmts then
r.has_void_stmts:=true;
r.void_stmts:=transform_stmt_list(wp.then_part) end
else -- Change declared type in the `then'.
l.tp_at:=tp;
end;
r.tgts:=r.tgts.push(tp);
r.stmts:=r.stmts.push(transform_stmt_list(wp.then_part));
l.tp_at:=ltp; -- Change the declared type back.
end;
wp:=wp.next end;
if s.no_else then r.no_else:=true;
else -- Do the else statements.
r.else_stmts:=transform_stmt_list(s.else_part) end;
if ~r.has_void_stmts then
r.has_void_stmts:=true;
r.void_stmts:=transform_stmt_list(s.else_part) end;
res:=r;
else -- Look for single matching branch, if any.
-- Always keep the type the same.
wp:TR_TYPECASE_WHEN:=s.when_part;
loop while!(~void(wp));
if ltp.is_subtype(tp_of(wp.tp)) then
res:=transform_stmt_list(wp.then_part);
l.no_assign:=ono_assign;
return res end;
wp:=wp.next end;
if s.no_else then -- No matching branches.
typecase_no_branch_err(s); return res
else -- Just output the else branch.
res:=transform_stmt_list(s.else_part) end end;
l.no_assign:=ono_assign; -- Put the local back the way it was.
return res end;
typecase_local_err(s:TR_TYPECASE_STMT) is
prog.err_loc(s);
prog.err("The name `" + s.name.str +
"' isn't a local variable.") end;
typecase_hot_local_err(s:TR_TYPECASE_STMT) is
prog.err_loc(s);
prog.err("The typecase test local `" + s.name.str +
"' must not be a `!' argument to an iter.") end;
typecase_no_branch_err(s:TR_TYPECASE_STMT) is
prog.err_loc(s);
prog.err("There are no matching branches in this typecase.") end;
-----------
transform_assert_stmt(s:TR_ASSERT_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
r::=#AM_ASSERT_STMT(s.source);
r.test:=transform_expr(s.test, prog.tp_builtin.bool);
if void(r.test) then return void end; -- Not a boolean.
return r end;
-----------
transform_protect_stmt(s:TR_PROTECT_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
-- Since registers are restored after a longjump, we have to make
-- sure that no local variables which could have been changed in
-- the protect and are used later are held in registers. We are
-- a bit conservative here and make any locals which are assigned
-- to in the protect body be volatile.
r::=#AM_PROTECT_STMT(s.source);
old_in_protect_body:BOOL:=in_protect_body; in_protect_body:=true;
r.body:=transform_stmt_list(s.stmts);
in_protect_body:=old_in_protect_body;
wp:TR_PROTECT_WHEN:=s.when_part;
loop while!(~void(wp));
tp:$TP:=tp_of(wp.tp); -- Type to compare against.
oex_tp:$TP:=ex_tp; ex_tp:=tp;
old_in_protect_then:BOOL:=in_protect_then; in_protect_then:=true;
r.tgts:=r.tgts.push(tp);
r.stmts:=r.stmts.push(transform_stmt_list(wp.then_part));
in_protect_then:=old_in_protect_then;
ex_tp:=oex_tp; -- Change exception type back.
wp:=wp.next end;
if s.no_else then -- Raise the same exception.
r.no_else:=true;
else -- Do the else statements.
oex_tp:$TP:=ex_tp; ex_tp:=prog.tp_builtin.dollar_ob;
old_in_protect_then:BOOL:=in_protect_then; in_protect_then:=true;
r.else_stmts:=transform_stmt_list(s.else_part);
in_protect_then:=old_in_protect_then;
ex_tp:=oex_tp; end;
return r end;
-----------
transform_raise_stmt(s:TR_RAISE_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
if ~void(s.next) then stmts_after_raise_err(s) end;
r::=#AM_RAISE_STMT(s.source);
r.val:=transform_expr(s.val,void);
if void(r.val) then return void end;
return r end;
stmts_after_raise_err(s:TR_RAISE_STMT) is
prog.err_loc(s);
prog.err("No statements may follow `raise' in a statment list.") end;
-----------
transform_expr_stmt(s:TR_EXPR_STMT):$AM_STMT is
-- A list of AM_STMT's which implements the source statement `s'.
e:$TR_EXPR:=s.e; -- The expression.
typecase e
when TR_BREAK_EXPR then
if void(cur_loop) then break_not_in_loop_err(s); return void end;
return #AM_BREAK_STMT(s.source)
when TR_CALL_EXPR then
r::=#AM_EXPR_STMT(s.source);
r.expr:=transform_call_expr(e,void,false);
if void(r.expr) then return void end;
return r
-- else expr_stmt_err(s); return void end end; -- NLP
else expr_stmt_err(s); end; return void; end; -- NLP
break_not_in_loop_err(s:TR_EXPR_STMT) is
prog.err_loc(s);
prog.err("`break!', `while!' and `until!' calls must appear "
"inside loops.") end;
expr_stmt_err(s:TR_EXPR_STMT) is
prog.err_loc(s);
prog.err("Expressions used as statements may not have return "
"values.") end;
-----------
call_tp_of_expr(e:$TR_EXPR):$CALL_TP is
-- Returns the call type of an expression, if it is one of the
-- special cases. Otherwise it returns void. (To get the
-- actual type, you have to do `transform_expr'.
if void(e) then
#OUT + "Compiler error, TRANS::call_tp_of_expr(void).";
return void end;
typecase e
when TR_VOID_EXPR then return #CALL_TP_VOID
when TR_CREATE_EXPR then
if void(e.tp) then return #CALL_TP_CREATE
else return void end
when TR_ARRAY_EXPR then return #CALL_TP_ARRAY
when TR_UNDERSCORE_ARG then
tua::=#CALL_TP_UNDERSCORE;
if ~void(e.tp) then tua.tp:=tp_of(e.tp) end;
return tua
-- else return void end end; -- NLP
else; end; return void; end; -- NLP
transform_expr(e:$TR_EXPR, tp:$TP):$AM_EXPR is
-- Return an expression which evaluates `e'. If `tp' is not void
-- then use it as the inferred type. Print an error message if
-- if is not a supertype of the expression type. In this case
-- return void. If `tp' is void then the expression must determine
-- its own type.
if void(e) then return void end;
typecase e
when TR_SELF_EXPR then return transform_self_expr(e,tp)
when TR_CALL_EXPR then return transform_call_expr(e,tp,true)
-- This is special since we need to know whether a return
-- value is used to resolve overloading. The only way the
-- return value won't be used is in an expression statement.
-- If we get to it from here, the value must be used.
when TR_VOID_EXPR then return transform_void_expr(e,tp)
when TR_IS_VOID_EXPR then return transform_is_void_expr(e,tp)
when TR_ARRAY_EXPR then return transform_array_expr(e,tp)
when TR_CREATE_EXPR then return transform_create_expr(e,tp)
when TR_BOUND_CREATE_EXPR then
return transform_bound_create_expr(e,tp)
when TR_AND_EXPR then return transform_and_expr(e,tp)
when TR_OR_EXPR then return transform_or_expr(e,tp)
when TR_EXCEPT_EXPR then return transform_except_expr(e,tp)
when TR_NEW_EXPR then return transform_new_expr(e,tp)
when TR_INITIAL_EXPR then return transform_initial_expr(e,tp)
when TR_BREAK_EXPR then return transform_break_expr(e,tp)
when TR_RESULT_EXPR then return transform_result_expr(e,tp)
when TR_BOOL_LIT_EXPR then return transform_bool_lit_expr(e,tp)
when TR_CHAR_LIT_EXPR then return transform_char_lit_expr(e,tp)
when TR_STR_LIT_EXPR then return transform_str_lit_expr(e,tp)
when TR_INT_LIT_EXPR then return transform_int_lit_expr(e,tp)
when TR_FLT_LIT_EXPR then
-- return transform_flt_lit_expr(e,tp) end end; -- NLP
return transform_flt_lit_expr(e,tp) end; return void; end; -- NLP
-----------
transform_self_expr(e:TR_SELF_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if in_constant then self_const_err(e); return void end;
sl:AM_LOCAL_EXPR:=cur_rout.self_local;
if ~void(tp) then
if ~sl.tp.is_subtype(tp) then
self_context_err(e,sl.tp,tp); return void end end;
return sl end;
self_const_err(e:TR_SELF_EXPR) is
prog.err_loc(e);
prog.err("`self' may not appear in a shared or constant "
"initialization expression.") end;
self_context_err(e:TR_SELF_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of self: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
-----------
transform_call_expr(e:TR_CALL_EXPR, tp:$TP, has_ret:BOOL):$AM_EXPR is
-- Expression implementing `e' in type context `tp'. `has_ret' says
-- whether the return value is used.
if void(cur_rout) and ~in_constant then
#OUT + "Compiler error, TRANS::transform_call_expr, "
"cur_rout=void."; return void end;
if void(e) then return void end;
r:$AM_EXPR; prog.err_loc(e);
r:=call_expr_check_local(e,tp); if ~void(r) then return r end;
stup:TUP{$AM_EXPR,$TP}:=call_self(e);
if void(stup) then return void end; -- Fail
self_val:$AM_EXPR:=stup.t1; self_tp:$TP:=stup.t2;
if void(self_tp) then return void end; -- Failure.
in_class:BOOL; if self_tp=tp_con.same then in_class:=true end;
call_sig::=#CALL_SIG; call_sig.has_ret:=has_ret;
call_sig.name:=call_expr_rout_name(e); call_sig.tp:=self_tp;
args:ARRAY{$AM_EXPR}; nargs:INT:=e.args_size;
if ~void(e.args) then args:=#ARRAY{$AM_EXPR}(nargs);
call_sig.args:=#ARRAY{$CALL_TP}(nargs) end;
sig:SIG:=call_expr_get_sig(e,call_sig,args,in_class);
if void(sig) then return void end;
cr:$AM_CALL_EXPR;
er:AM_EXT_CALL_EXPR; ir:AM_ITER_CALL_EXPR; rr:AM_ROUT_CALL_EXPR;
brr:AM_BND_ROUT_CALL_EXPR; bir:AM_BND_ITER_CALL_EXPR;
typecase self_tp
when TP_CLASS then
if prog.tp_kind(self_tp)=TP_KIND::ext_tp then
if in_constant then ext_call_const_err(e); return void end;
im:IMPL:=prog.impl_tbl.impl_of(self_tp);
if void(im) then
#OUT + "Compiler err, TRANS::transform_call_expr, "
"im=void."; return void end;
el:ELT:=im.elt_with_sig(sig);
if void(el) then
#OUT + "Compiler err, TRANS::transform_call_expr, "
"el=void.";
return void end;
er:=#AM_EXT_CALL_EXPR(nargs+1,e.source,name_for_ext(el));
er[0]:=self_val; er.fun:=sig;
if ~void(args) then
i:INT:=0;
loop while!(i<nargs); er[i+1]:=args[i]; i:=i+1 end;
end;
cr:=er;
elsif e.name.is_iter then
ir:=#AM_ITER_CALL_EXPR(nargs+1,e.source);
ir[0]:=self_val; ir.fun:=sig;
if ~void(args) then
i:INT:=0;
loop while!(i<nargs); ir[i+1]:=args[i]; i:=i+1 end;
end;
cr:=call_fix_iter(ir);
else rr:=#AM_ROUT_CALL_EXPR(nargs+1,e.source);
rr[0]:=self_val; rr.fun:=sig;
if ~void(args) then
i:INT:=0;
loop while!(i<nargs); rr[i+1]:=args[i]; i:=i+1 end;
end;
cr:=rr; end;
when TP_ROUT then
if in_constant then bnd_rout_call_const_err; return void end;
brr:=#AM_BND_ROUT_CALL_EXPR(nargs,e.source);
brr.br:=self_val;
if ~void(args) then
i:INT:=0;
loop while!(i<nargs); brr[i]:=args[i]; i:=i+1 end;
end;
cr:=brr;
when TP_ITER then
bir:=#AM_BND_ITER_CALL_EXPR(nargs,e.source);
bir.bi:=self_val;
if ~void(args) then
i:INT:=0;
loop while!(i<nargs); bir[i]:=args[i]; i:=i+1 end;
end;
cr:=call_fix_bnd_iter(bir,sig) end;
if void(cr) then return void end;
if ~void(tp) and ~void(cr.tp) then
if ~cr.tp.is_subtype(tp) then
call_context_err(e,cr.tp,tp); return void end end;
-- DPS: changed rest of function to attempt inline
ncr:$AM_EXPR:=cr;
typecase cr
when AM_ROUT_CALL_EXPR then ncr:=inline(cr);
else
end;
-- see if still an $AM_CALL_EXPR and add to list if so
if ~void(cur_rout) then
typecase ncr
when $AM_CALL_EXPR then cur_rout.calls:=cur_rout.calls.push(ncr)
else
end;
end;
return ncr end;
call_local_context_err(e:TR_CALL_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of this local variable: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
call_const_err(e:TR_CALL_EXPR) is
prog.err_loc(e);
prog.err("Illegal call for a shared or constant initialization "
"expression.") end;
call_expr_check_local(e:TR_CALL_EXPR,tp:$TP):AM_LOCAL_EXPR is
-- Check if the call `e' is a local variable reference.
-- If it is return the local.
if in_constant then return void end; -- No locals in initializers.
if void(e) then
prog.err("Compiler error, TRANS::call_expr_check_local on void.");
return void end;
self_tr:$TR_EXPR:=e.ob;
r:AM_LOCAL_EXPR;
if void(self_tr) and void(e.tp) and void(e.args) and
e.is_array=false then -- check for local.
r:=local_with_name(e.name);
if ~void(r) then
if ~void(tp) then
if ~r.tp.is_subtype(tp) then
call_local_context_err(e,r.tp,tp); return void
end
end;
end;
end;
return r end;
call_self(e:TR_CALL_EXPR):TUP{$AM_EXPR,$TP}
-- Return an expression for self and the type of self for the
-- call `e'.
pre ~void(e) is
self_tr:$TR_EXPR:=e.ob;
if ~void(self_tr) then -- Call made on an expr.
typecase self_tr
when TR_VOID_EXPR then call_self_void_err(e); return void
when TR_CREATE_EXPR then
if void(self_tr.tp) then
call_self_create_err(e); return void
else self_val:$AM_EXPR:=transform_expr(self_tr,void);
if void(self_val) then return void end;
return #TUP{$AM_EXPR,$TP}(self_val,self_val.tp) end;
when TR_ARRAY_EXPR then call_self_array_err(e); return void
when TR_UNDERSCORE_ARG then
call_self_underscore_err(e); return void
else self_val:$AM_EXPR:=transform_expr(self_tr,void);
if void(self_val) then return void end;
return #TUP{$AM_EXPR,$TP}(self_val,self_val.tp);
end;
elsif ~void(e.tp) then -- Double colon call.
av::=#AM_VOID_CONST(e.source);
av.tp_at:=tp_of(e.tp);
return #TUP{$AM_EXPR,$TP}(av,av.tp_at)
-- else -- Call on self. -- NLP
end; -- Call on self. -- NLP
self_val:$AM_EXPR;
if in_constant then -- Self is void in initializers.
av::=#AM_VOID_CONST(e.source);
av.tp_at:=tp_con.same; self_val:=av;
else
self_val:=cur_rout.self_local end;
if void(self_val) then
#OUT + "Compiler error, TRANS::call_self, self_val=void.";
return void end;
-- return #TUP{$AM_EXPR,$TP}(self_val,self_val.tp) end end; -- NLP
return #TUP{$AM_EXPR,$TP}(self_val,self_val.tp); end; -- NLP
call_self_void_err(e:TR_CALL_EXPR) is
prog.err_loc(e);
prog.err("Calls may not be made directly on `void'.") end;
call_self_create_err(e:TR_CALL_EXPR) is
prog.err_loc(e);
prog.err("Calls may not be made on create expressions which "
"don't specify the type of object being created.") end;
call_self_array_err(e:TR_CALL_EXPR) is
prog.err_loc(e);
prog.err("Calls may not be made on array expressions.") end;
call_self_underscore_err(e:TR_CALL_EXPR) is
prog.err_loc(e);
prog.err("Underscore arguments may not appear in this position.")
end;
call_context_err(e:TR_CALL_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the call: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
ext_call_const_err(e:TR_CALL_EXPR) is
prog.err_loc(e);
prog.err("External calls may not appear in shared or constant "
"initialization expressions.") end;
call_expr_get_sig(e:TR_CALL_EXPR, call_sig:CALL_SIG,
args:ARRAY{$AM_EXPR},in_class:BOOL):SIG is
-- Get the signature of the call with `call_sig' and if there
-- are arguments, put their expressions in `args'. If anything fails,
-- return void. If `in_class' is true then look at private routines
-- as well as public ones.
if void(args) then
if ~void(e.args) then
prog.err("Compiler error, TRANS::call_expr_get_sig, args size.");
return void end;
elsif args.size/=e.args_size or
call_sig.args.size/=e.args_size then
prog.err("Compiler error, TRANS::call_expr_get_sig, args size.");
return void end;
a:$TR_EXPR:=e.args; i:INT:=0;
ce:$AM_EXPR;
loop while!(~void(a));
ct:$CALL_TP:=call_tp_of_expr(a);
if void(ct) then ce:=transform_expr(a,void);
if void(ce) then return void
else ct:=ce.tp end;
else ce:=void end;
call_sig.args[i]:=ct; args[i]:=ce;
a:=a.next; i:=i+1 end;
prog.err_loc(e); r::=call_sig.lookup(in_class);
if void(r) then return void end; -- Failure.
if r.args.size/=e.args_size then
prog.err("Compiler error, TRANS::call_expr_get_sig, res size.");
return void end;
a:=e.args; i:=0;
loop while!(~void(a));
ce:=args[i]; at:$TP:=r.args[i];
if void(ce) then ce:=transform_expr(a,at) end;
if void(ce) then return void end;
args[i]:=ce;
a:=a.next; i:=i+1 end;
return r end;
call_expr_rout_name(e:TR_CALL_EXPR):IDENT
-- The name of the routine being called.
pre ~void(e) is
if e.is_array then return prog.ident_builtin.aget_ident
-- else return e.name end end; -- NLP
end; return e.name; end; -- NLP
call_fix_iter(ir:AM_ITER_CALL_EXPR):AM_ITER_CALL_EXPR
-- Move the once args out in the iter call `ir'.
pre ~void(ir) is
if in_constant then iter_call_const_err; return void end;
if void(cur_loop) then iter_call_out_of_loop_err; return void end;
ir.lp:=cur_loop;
if void(ir[0]) then
#OUT + "Compiler error, TRANS::call_fix_iter, ir[0]=void.";
return void end;
if void(ir.fun) then
#OUT + "Compiler error, TRANS::call_fix_iter, ir.fun=void.";
return void end;
if contains_iter_call(ir[0]) then -- iter in self expression.
iter_call_in_once_arg_err(0); return void end;
nl::=#AM_LOCAL_EXPR(ir.source, void, ir[0].tp);
add_local(nl);
ass::=#AM_ASSIGN_STMT(ir.source);
ass.dest:=nl;
ass.src:=ir[0]; ir[0]:=nl; ir.init:=ass;
i:INT:=0;
loop while!(i<ir.size-1);
if void(ir[i+1]) then
#OUT + "Compiler error, TRANS::call_fix_iter, ir[" + (i+1) +
"]=void."; return void end;
once:BOOL:=false;
if void(ir.fun.hot) then once:=true
elsif ~ir.fun.hot[i] then once:=true end;
if once then
if contains_iter_call(ir[i+1]) then
iter_call_in_once_arg_err(i+1); return void end;
nl:=#AM_LOCAL_EXPR(ir.source,void, ir[i+1].tp);
add_local(nl);
ass:=#AM_ASSIGN_STMT(ir.source); ass.dest:=nl;
ass.src:=ir[i+1]; ir[i+1]:=nl;
if void(ir.init) then ir.init:=ass
else ir.init.append(ass) end end;
i:=i+1 end;
cur_loop.its:=cur_loop.its.push(ir);
return ir end;
iter_call_const_err is
prog.err("Iter calls may not appear in shared or constant "
"initialization expressions.") end;
iter_call_out_of_loop_err is
prog.err("Iters may only be called within loop statements.") end;
contains_iter_call(e:$AM_EXPR):BOOL is
-- True if `e' contains an iter call. This is used to check for
-- iter calls in the expressions for once iter arguments.
if void(e) then return void end;
typecase e
when AM_ROUT_CALL_EXPR then
loop if contains_iter_call(e.elt!) then return true end end;
when AM_ITER_CALL_EXPR then return true
when AM_ARRAY_EXPR then
loop if contains_iter_call(e.elt!) then return true end end;
when AM_BND_CREATE_EXPR then
loop if contains_iter_call(e.elt!) then return true end end;
when AM_BND_ROUT_CALL_EXPR then
loop if contains_iter_call(e.elt!) then return true end end;
when AM_BND_ITER_CALL_EXPR then return true
when AM_IF_EXPR then
if contains_iter_call(e.test) or
contains_iter_call(e.if_true) or
contains_iter_call(e.if_false) then return true end
when AM_IS_VOID_EXPR then
if contains_iter_call(e.arg) then return true end
when AM_NEW_EXPR then
if contains_iter_call(e.asz) then return true end
when AM_ATTR_EXPR then
if contains_iter_call(e.ob) then return true end
when AM_ARR_EXPR then
if contains_iter_call(e.ob) or contains_iter_call(e.ind) then
return true end
when AM_EXT_CALL_EXPR then
loop if contains_iter_call(e.elt!) then return true end end;
else end;
return false end;
iter_call_in_once_arg_err(i:INT) is
if i=0 then
prog.err("The expression specifying `self' in this iter call, "
"itself contains an iter call.")
else prog.err("The expression for argument number " + i +
" in this iter call, itself contains an iter call.") end end;
bnd_rout_call_const_err is
prog.err("Bound routine calls may not appear in shared or "
"constant initialization expressions.") end;
call_fix_bnd_iter(bir:AM_BND_ITER_CALL_EXPR,
sig:SIG):AM_BND_ITER_CALL_EXPR is
-- Move the once args out in the bound iter call `bir' with
-- signature `sig'.
if void(bir) or void(sig) then return void end;
if in_constant then bnd_iter_call_const_err; return void end;
if void(cur_loop) then
bnd_iter_call_out_of_loop_err; return void end;
bir.lp:=cur_loop;
i:INT:=0;
loop while!(i<bir.size);
if void(bir[i]) then prog.err_loc(bir);
prog.err("Compiler error, TRANS::call_fix_bnd_iter, bir[" +
i + "]=void."); return void end;
once:BOOL:=false;
if void(sig.hot) then once:=true
elsif ~sig.hot[i] then once:=true end;
if once then
if contains_iter_call(bir[i]) then
bnd_iter_call_in_once_err(i); return void end;
nl::=#AM_LOCAL_EXPR(bir.source,void,bir[i].tp);
add_local(nl);
ass::=#AM_ASSIGN_STMT(bir.source);
ass.dest:=nl;
ass.src:=bir[i]; bir[i]:=nl;
if void(bir.init) then bir.init:=ass
else bir.init.append(ass) end end;
i:=i+1 end;
cur_loop.bits:=cur_loop.bits.push(bir);
return bir end;
bnd_iter_call_const_err is
prog.err("Bound iter calls may not appear in shared or constant "
"initialization expressions.") end;
bnd_iter_call_out_of_loop_err is
prog.err("Bound iters may only be called inside loop statements.")
end;
bnd_iter_call_in_once_err(i:INT) is
prog.err("Argument " + i + " of this bound iter call is " +
"a once argument, but an iter call appears in its expression.") end;
-----------
transform_void_expr(e:TR_VOID_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
r::=#AM_VOID_CONST(e.source);
if void(tp) then
prog.err_loc(e);
prog.err("Compiler error, no type for void."); return void end;
r.tp_at:=tp; return r end;
-----------
transform_is_void_expr(e:TR_IS_VOID_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if ~void(tp) then
if ~prog.tp_builtin.bool.is_subtype(tp) then
prog.err_loc(e);
prog.err("Void test expressions return BOOL objects which "
"are not subtypes of " + tp.str + "."); return void end end;
r::=#AM_IS_VOID_EXPR(e.source);
r.tp_at:=prog.tp_builtin.bool; prog.err_loc(e.arg);
earg::=e.arg;
typecase earg
when TR_VOID_EXPR then
prog.err("void(void) is not allowed."); return void
when TR_CREATE_EXPR then
if void(earg.tp) then
prog.err("void() on create expression without type.");
return void end;
when TR_ARRAY_EXPR then
prog.err("void() on array creation expression."); return void
when TR_UNDERSCORE_ARG then
prog.err("void(_) is illegal."); return void
else end;
r.arg:=transform_expr(e.arg,void);
if void(r.arg) then return void end;
return r end;
-----------
transform_array_expr(e:TR_ARRAY_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if void(tp) then array_tp_void_err(e); return void end;
pt:$TP;
typecase tp
when TP_CLASS then
if tp.name/=prog.ident_builtin.ARRAY_ident
or tp.params.size/=1 then
array_wrong_tp_err(e,tp); return void end;
pt:=tp.params[0]; -- The parameter type.
else array_wrong_tp_err(e,tp); return void end;
r::=#AM_ARRAY_EXPR(e.elts_size, e.source);
r.tp_at:=tp;
ae:$TR_EXPR:=e.elts; i:INT:=0;
loop while!(~void(ae));
tae:$AM_EXPR:=transform_expr(ae,pt);
if void(tae) then return void end;
r[i]:=tae;
ae:=ae.next; i:=i+1 end;
return r end;
array_tp_void_err(e:TR_ARRAY_EXPR) is
prog.err_loc(e);
prog.err("The type of this array creation expression cannot be "
"inferred from context.") end;
array_wrong_tp_err(e:TR_ARRAY_EXPR, tp:$TP) is
prog.err_loc(e);
prog.err("The inferred type: " + tp.str + " for this array " +
"creation expression is not of the form `ARRAY{T}'.") end;
-----------
transform_create_expr(e:TR_CREATE_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
at:$TP;
if in_constant then create_const_err(e); return void end;
if ~void(e.tp) then
at:=tp_of(e.tp);
if ~void(tp) then
if ~at.is_subtype(tp) then
create_context_err(e,at,tp); return void end end;
elsif void(tp) then
create_tp_spec_err(e); return void
else at:=tp end;
-- Now `at' has the type we are creating.
if at.is_abstract then prog.err_loc(e);
prog.err("Creation expressions may not specify abstract types.");
return void end;
na:INT:=e.elts_size; -- Number of arguments.
r::=#AM_ROUT_CALL_EXPR(na+1,e.source);
av::=#AM_VOID_CONST(e.source); av.tp_at:=at;
r[0]:=av;
cs::=#CALL_SIG;
if na>0 then cs.args:=#ARRAY{$CALL_TP}(na) end;
cs.tp:=at; cs.name:=prog.ident_builtin.create_ident;
cs.has_ret:=true; -- Creation expressions always return vals.
ce:$TR_EXPR:=e.elts; i:INT:=0;
loop while!(~void(ce));
cs.args[i]:=call_tp_of_expr(ce);
if void(cs.args[i]) then -- Not a type inference case.
r[i+1]:=transform_expr(ce,void); -- Compute arg expr.
if void(r[i+1]) then return void end;
cs.args[i]:=r[i+1].tp end; -- Get type from expr.
ce:=ce.next; i:=i+1 end;
prog.err_loc(e);
-- DPS: was: r.fun:=prog.ifc_tbl.ifc_of(at).sig_for_call(cs);
if at=tp_con.same then
r.fun:=prog.impl_tbl.impl_of(at).sig_for_internal_call(cs);
else
r.fun:=prog.ifc_tbl.ifc_of(at).sig_for_call(cs);
end;
-- DPS end of change
if void(r.fun) then return void end;
ce:=e.elts; i:=0;
loop while!(~void(ce));
if void(r[i+1]) then -- Need to compute by inference.
r[i+1]:=transform_expr(ce,r.fun.args[i]);
-- Here is where the type inference gets done. We tell
-- it to use the found signature type to evaluate ce.
if void(r[i+1]) then return void end end;
ce:=ce.next; i:=i+1 end;
if r.fun.ret/=at then
create_bad_return_type_err(e,r.fun.ret,at); return void end;
cur_rout.calls:=cur_rout.calls.push(r);
return inline(r) end;
create_const_err(e:TR_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Creation expressions may not appear in shared or "
"constant initialization expressions.") end;
create_context_err(e:TR_CREATE_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the creation expression: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
create_tp_spec_err(e:TR_CREATE_EXPR) is
prog.err_loc(e);
prog.err("This creation expression does not specify its type "
"and it cannot be inferred from context.") end;
create_bad_return_type_err(e:TR_CREATE_EXPR, rt,at:$TP) is
prog.err_loc(e);
prog.err("This creation expression returns the type: " + rt.str +
" rather than " + at.str + " as it must.") end;
-----------
transform_bound_create_expr(e:TR_BOUND_CREATE_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if in_constant then bound_create_in_const_err(e); return void end;
st::=bound_create_self(e); self_val::=st.t1; self_tp::=st.t2;
if void(self_tp) then return void end; -- Failure.
nbnd::=bound_create_num_bnd(self_val,e);
r::=#AM_BND_CREATE_EXPR(nbnd);
r.fun:=bound_create_sig(e,self_tp);
if void(r.fun) then return void end; -- Failure.
if e.is_iter and r.fun.is_iter.not then
bound_create_not_iter_err(e); return void
elsif ~e.is_iter and r.fun.is_iter then
bound_create_iter_err(e); return void end;
r.bnd_args:=bound_create_bnd_args(nbnd,e);
r.unbnd_args:=bound_create_unbnd_args(nbnd,e);
bind::=0; -- Index into bound arguments.
if ~void(self_val) then r[bind]:=self_val; bind:=bind+1;
if e.is_iter and contains_iter_call(self_val) then
bound_create_self_has_iter_err(e); return void end;
hot:BOOL;
a::=e.call.args;
loop while!(~void(a)); atp::=r.fun.args.elt!;
if ~void(r.fun.hot) then hot:=r.fun.hot.elt! end;
typecase a when TR_UNDERSCORE_ARG then else
r[bind]:=transform_expr(a,atp);
if void(r[bind]) then return void end;
if e.is_iter and ~hot and contains_iter_call(r[bind]) then
bound_create_iter_in_once_err(a); return void end;
bind:=bind+1 end;
a:=a.next;
end;
end;
bound_create_set_tp(r);
if ~void(tp) and ~r.tp.is_subtype(tp) then
bound_create_context_err(e,r.tp,tp); return void end;
cur_rout.calls:=cur_rout.calls.push(r);
return r end;
bound_create_in_const_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound creation expressions may not appear in shared or "
"constant initialization expressions.") end;
bound_create_self(e:TR_BOUND_CREATE_EXPR):TUP{$AM_EXPR,$TP} is
-- Return an expression for self and the type of self for the
-- bound create expression `e'. If `t1' is void, then it is a
-- call on underscore.
call::=e.call; self_tr::=call.ob;
self_val:$AM_EXPR;
if ~void(self_tr) then -- Call made on an expr.
typecase self_tr
when TR_VOID_EXPR then bound_create_self_void_err(e);
return #(void,void)
when TR_CREATE_EXPR then
if void(self_tr.tp) then bound_create_self_create_err(e);
return #(void,void)
else self_val:=transform_expr(self_tr,void);
return #(self_val,self_val.tp) end;
when TR_ARRAY_EXPR then bound_create_self_array_err(e);
return #(void,void)
when TR_UNDERSCORE_ARG then
-- `self_val' is void if self is an underscore expression.
if void(self_tr.tp) then return #(void,impl.tp)
else return #(void,tp_of(self_tr.tp)) end;
else self_val:=transform_expr(self_tr,void);
return #(self_val,self_val.tp) end;
elsif ~void(call.tp) then -- Double colon call.
res::=#AM_VOID_CONST(call.source);
res.tp_at:=tp_of(call.tp);
return #(res, res.tp_at);
else -- Call on self.
if void(call.args) then -- Might be a local.
l::=local_with_name(call.name);
if ~void(l) then
bound_create_self_local_err(e); return #(void,void)
else end end;
self_val:=cur_rout.self_local;
-- return #(self_val, self_val.tp) end end; -- NLP
end; return #(self_val, self_val.tp); end; -- NLP
bound_create_self_void_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound creation calls may not be made directly on `void'.")
end;
bound_create_self_create_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound creation calls may not be made on create "
"expressions which don't specify the type of object being "
"created.") end;
bound_create_self_array_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound creation calls may not be made on array "
"expressions.") end;
bound_create_self_local_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound creation calls must be calls on routines or iters, "
"not references to local variables.") end;
bound_create_sig(e:TR_BOUND_CREATE_EXPR, self_tp:$TP):SIG is
-- The signature of the call represented by `e' where the type of
-- self has been determined to be `self_tp'. Void if there
-- is a problem.
call_sig::=#CALL_SIG; call_sig.tp:=self_tp;
call_sig.name:=e.call.name;
call_sig.args:=#ARRAY{$CALL_TP}(e.call.args_size);
if ~void(e.ret) then call_sig.has_ret:=true else
call_sig.unknown_ret:=true end;
ca::=e.call.args;
loop while!(~void(ca)); atp::=call_tp_of_expr(ca);
if void(atp) then atp:=transform_expr(ca,void).tp end;
call_sig.args.set!(atp);
ca:=ca.next end;
-- At this point call_sig is complete.
prog.err_loc(e); -- Just in case.
return call_sig.lookup(self_tp=tp_con.same) end;
bound_create_not_iter_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound iters must be formed from iter calls.") end;
bound_create_iter_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("Bound routines must be formed from routine calls.") end;
bound_create_num_bnd(self_val:$AM_EXPR, e:TR_BOUND_CREATE_EXPR):INT is
-- The number of argument which are bound up (including self).
r:INT;
if void(self_val) then r:=0 else r:=1 end; -- Count self.
a::=e.call.args;
loop while!(~void(a));
typecase a when TR_UNDERSCORE_ARG then else r:=r+1 end;
a:=a.next end;
return r end;
bound_create_bnd_args(nbnd:INT,e:TR_BOUND_CREATE_EXPR):ARRAY{INT} is
-- An array of the indices of arguments which are bound up in
-- order. 0 is self. `nbnd' is the number of bound args.
r::=#ARRAY{INT}(nbnd);
rind::=0; -- Index into r.
st::=e.call.ob;
typecase st when TR_UNDERSCORE_ARG then
else r[rind]:=0; rind:=rind+1 end;
aind::=0; -- Index into argument list.
a::=e.call.args;
loop while!(~void(a)); aind:=aind+1;
typecase a when TR_UNDERSCORE_ARG then
else r[rind]:=aind; rind:=rind+1 end;
a:=a.next end;
return r end;
bound_create_unbnd_args(nbnd:INT,e:TR_BOUND_CREATE_EXPR):ARRAY{INT} is
-- An array of the indices of arguments which are not bound in
-- order. 0 is self. `nbnd' is the number of bound args.
r::=#ARRAY{INT}(1+e.call.args_size-nbnd);
rind::=0; -- Index into r.
st::=e.call.ob;
typecase st when TR_UNDERSCORE_ARG then
r[rind]:=0; rind:=rind+1 else end;
aind::=0; -- Index into argument list.
a::=e.call.args;
loop while!(~void(a)); aind:=aind+1;
typecase a when TR_UNDERSCORE_ARG then
r[rind]:=aind; rind:=rind+1 else end;
a:=a.next end;
return r end;
bound_create_self_has_iter_err(e:TR_BOUND_CREATE_EXPR) is
prog.err_loc(e);
prog.err("The expression for self in an iter call may not "
"itself contain an iter call.") end;
bound_create_iter_in_once_err(a:$TR_EXPR) is
prog.err_loc(a);
prog.err("Once arguments of iter calls may not themselves "
"contain iter calls.") end;
bound_create_set_tp(r:AM_BND_CREATE_EXPR) is
-- Set the type in `r', assuming everything else is there.
fun::=r.fun;
args::=#ARRAY{$TP}(r.unbnd_args.size);
t:$TP; h:BOOL;
if fun.is_iter then -- A bound iter.
hot::=#ARRAY{BOOL}(r.unbnd_args.size);
loop i::=r.unbnd_args.elt!;
if i=0 then t:=fun.tp else t:=fun.args[i-1] end;
args.set!(t);
if i=0 or void(fun.hot) then h:=false else
h:=fun.hot[i-1] end;
hot.set!(h) end;
r.tp_at:=prog.tp_tbl.tp_iter_for(args,hot,fun.ret)
else -- A bound routine.
loop i::=r.unbnd_args.elt!;
if i=0 then t:=fun.tp else t:=fun.args[i-1] end;
args.set!(t) end;
r.tp_at:=prog.tp_tbl.tp_rout_for(args,fun.ret) end end;
bound_create_context_err(e:TR_BOUND_CREATE_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the bound creation expression: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
-----------
transform_and_expr(e:TR_AND_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if ~void(tp) then
if ~prog.tp_builtin.bool.is_subtype(tp) then
and_context_err(e,tp); return void end end;
e1:$AM_EXPR:=transform_expr(e.e1, prog.tp_builtin.bool);
e2:$AM_EXPR:=transform_expr(e.e2, prog.tp_builtin.bool);
if void(e1) or void(e2) then return void end; -- Not booleans.
r::=#AM_IF_EXPR(e.source);
r.test:=e1; r.if_true:=e2;
abc::=#AM_BOOL_CONST(e.source);
abc.val:=false;
r.if_false:=abc;
r.tp_at:=prog.tp_builtin.bool;
return r end;
and_context_err(e:TR_AND_EXPR, tp:$TP) is
prog.err_loc(e);
prog.err("And expressions return BOOL objects which are " +
"not subtypes of " + tp.str + ".") end;
-----------
transform_or_expr(e:TR_OR_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if ~void(tp) then
if ~prog.tp_builtin.bool.is_subtype(tp) then
or_context_err(e,tp); return void end end;
e1:$AM_EXPR:=transform_expr(e.e1, prog.tp_builtin.bool);
e2:$AM_EXPR:=transform_expr(e.e2, prog.tp_builtin.bool);
if void(e1) or void(e2) then return void end; -- Not booleans.
r::=#AM_IF_EXPR(e.source);
r.test:=e1; r.if_false:=e2;
abc::=#AM_BOOL_CONST(e.source); abc.val:=true;
r.if_true:=abc;
r.tp_at:=prog.tp_builtin.bool;
return r end;
or_context_err(e:TR_OR_EXPR, tp:$TP) is
prog.err_loc(e);
prog.err("Or expressions return BOOL objects which are " +
"not subtypes of " + tp.str + ".") end;
-----------
transform_except_expr(e:TR_EXCEPT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if in_constant then except_const_err(e); return void end;
if in_protect_then=false then except_loc_err(e); return void end;
r::=#AM_EXCEPT_EXPR(ex_tp);
if ~void(tp) then
if ~r.tp.is_subtype(tp) then
except_context_err(e,r.tp,tp); return void end end;
return r end;
except_const_err(e:TR_EXCEPT_EXPR) is
prog.err_loc(e);
prog.err("`exception' expressions may not appear in shared "
"or constant initialization expressions.") end;
except_loc_err(e:TR_EXCEPT_EXPR) is
prog.err_loc(e);
prog.err("`exception' expressions may only appear in `then'"
"and `else' clauses of `protect' statements.") end;
except_context_err(e:TR_EXCEPT_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the exception expression: "+ stp.str +
" is not a subtype of " + tp.str + ".") end;
-----------
transform_new_expr(e:TR_NEW_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if in_constant then new_const_err(e); return void end;
t::=impl.tp; -- The type in which this appears.
k:INT:=prog.tp_kind(t);
if k/=TP_KIND::ref_tp then new_in_non_ref_err(e); return void end;
r:AM_NEW_EXPR;
if ~void(tp) then
if ~t.is_subtype(tp) then
new_context_err(e,t,tp); return void end end;
if ~void(e.arg) then -- Specifies asize.
if void(impl.arr) then new_arg_no_array_err(e); return void end;
r:=#AM_NEW_EXPR(e.source); r.tp_at:=t;
r.asz:=transform_expr(e.arg,prog.tp_builtin.int);
if void(r.asz) then return void end;
else -- Not an array class.
if ~void(impl.arr) then new_no_arg_array_err(e); return void end;
r:=#AM_NEW_EXPR(e.source); r.tp_at:=t end;
return r end;
new_const_err(e:TR_NEW_EXPR) is
prog.err_loc(e);
prog.err("`new' expressions may not appear in shared or constant "
"initialization expressions.") end;
new_in_non_ref_err(e:TR_NEW_EXPR) is
prog.err_loc(e);
prog.err("`new' expressions may only appear in reference classes.")
end;
new_context_err(e:TR_NEW_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the `new' expression: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
new_arg_no_array_err(e:TR_NEW_EXPR) is
prog.err_loc(e);
prog.err("`new' expressions only take an argument in classes "
"which have an include path to AREF.") end;
new_no_arg_array_err(e:TR_NEW_EXPR) is
prog.err_loc(e);
prog.err("`new' expressions must take an argument specifying "
"`asize' in classes which have an include path to AREF.") end;
-----------
transform_initial_expr(e:TR_INITIAL_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
-- Append initialization code to `init_stmts'.
if ~in_post then initial_out_of_post_err(e); return void end;
if in_initial then nested_initial_err(e); return void end;
in_initial:=true;
te:$AM_EXPR:=transform_expr(e.e,tp);
in_initial:=false;
if void(te) then return void end;
v::=#AM_LOCAL_EXPR(e.source, void,te.tp);
cur_rout.locals:=cur_rout.locals.push(v);
as::=#AM_ASSIGN_STMT(e.source);
as.src:=te; as.dest:=v;
inst::=#AM_INITIAL_STMT(e.source);
inst.tp:=impl.tp; inst.stmts:=as;
if void(init_stmts) then init_stmts:=inst
else init_stmts.append(inst) end;
return v end;
initial_out_of_post_err(e:TR_INITIAL_EXPR) is
prog.err_loc(e);
prog.err("`initial' expressions can only occur in `post' clauses.")
end;
nested_initial_err(e:TR_INITIAL_EXPR) is
prog.err_loc(e);
prog.err("`initial' expressions may not be nested.") end;
initial_context_err(e:TR_INITIAL_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the `initial' expression: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
-----------
transform_break_expr(e:TR_BREAK_EXPR, tp:$TP):$AM_EXPR is
-- Break's must always be handled in expression statements. If
-- we get here, something's wrong.
prog.err_loc(e);
prog.err("`break!' may not appear as a part of an expression.");
return void end;
-----------
transform_result_expr(e:TR_RESULT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if in_post=false then result_out_of_post_err(e); return void end;
if in_initial=true then result_in_initial_err(e); return void end;
if void(cur_rout.rres) then
if void(cur_rout.sig.ret) then
result_and_no_return_err(e); return void end;
cur_rout.rres:=#AM_LOCAL_EXPR(e.source,void,cur_rout.sig.ret) end;
if ~void(tp) then
if ~cur_rout.rres.tp.is_subtype(tp) then
result_context_err(e,cur_rout.rres.tp,tp); return void end end;
return cur_rout.rres end;
result_out_of_post_err(e:TR_RESULT_EXPR) is
prog.err_loc(e);
prog.err("`result' expressions can only occur in `post' clauses.")
end;
result_in_initial_err(e:TR_RESULT_EXPR) is
prog.err_loc(e);
prog.err("`result' expressions may not appear in `initial' "
"expressions.") end;
result_and_no_return_err(e:TR_RESULT_EXPR) is
prog.err_loc(e);
prog.err("`result' expressions may not appear in routines or "
"iters without return values.") end;
result_context_err(e:TR_RESULT_EXPR, stp,tp:$TP) is
prog.err_loc(e);
prog.err("The type of the `result' expression: " + stp.str +
" is not a subtype of " + tp.str + ".") end;
-----------
transform_bool_lit_expr(e:TR_BOOL_LIT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if ~void(tp) then
if ~prog.tp_builtin.bool.is_subtype(tp) then
bool_lit_context_err(e,tp); return void end end;
r::=#AM_BOOL_CONST(e.source);
r.tp_at:=prog.tp_builtin.bool;
r.val:=e.val;
return r end;
bool_lit_context_err(e:TR_BOOL_LIT_EXPR, tp:$TP) is
prog.err_loc(e);
prog.err("Boolean literals are not subtypes of " + tp.str + ".");
end;
-----------
transform_char_lit_expr(e:TR_CHAR_LIT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if ~void(tp) then
if ~prog.tp_builtin.char.is_subtype(tp) then
char_lit_context_err(e,tp); return void end end;
r::=#AM_CHAR_CONST(e);
r.tp_at:=prog.tp_builtin.char;
return r end;
char_lit_context_err(e:TR_CHAR_LIT_EXPR, tp:$TP) is
prog.err_loc(e);
prog.err("Character literals are not subtypes of " + tp.str + ".")
end;
-----------
transform_str_lit_expr(e:TR_STR_LIT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if ~void(tp) then
if ~prog.tp_builtin.str.is_subtype(tp) then
str_lit_context_err(e,tp); return void end end;
r::=#AM_STR_CONST(e); r.tp_at:=prog.tp_builtin.str;
return r end;
str_lit_context_err(e:TR_STR_LIT_EXPR, tp:$TP) is
prog.err_loc(e);
prog.err("String literals are not subtypes of " + tp.str + ".") end;
-----------
transform_int_lit_expr(e:TR_INT_LIT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
if e.is_inti then
ri::=#AM_INTI_CONST(e);
ri.tp_at:=prog.tp_builtin.inti;
if void(tp) then return ri
elsif ~ri.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of INTI."); return void
else return ri end;
-- else -- NLP
end; -- NLP
r::=#AM_INT_CONST(e);
r.tp_at:=prog.tp_builtin.int;
if void(tp) then return r
elsif ~r.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of INT."); return void
-- else return r end; -- NLP
end; return r; -- NLP
-- end; -- NLP
end;
-----------
transform_flt_lit_expr(e:TR_FLT_LIT_EXPR, tp:$TP):$AM_EXPR is
-- Expression implementing `e' in type context `tp'.
case e.tp
when TR_FLT_LIT_EXPR::flt then
rf::=#AM_FLT_CONST(e);
rf.tp_at:=prog.tp_builtin.flt;
if void(tp) then return rf
elsif ~rf.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of FLT."); return void
else return rf end;
when TR_FLT_LIT_EXPR::fltd then
rfd::=#AM_FLTD_CONST(e);
rfd.tp_at:=prog.tp_builtin.fltd;
if void(tp) then return rfd
elsif ~rfd.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of FLTD."); return void
else return rfd end;
when TR_FLT_LIT_EXPR::fltx then
rfx::=#AM_FLTX_CONST(e);
rfx.tp_at:=prog.tp_builtin.fltx;
if void(tp) then return rfx
elsif ~rfx.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of FLTX."); return void
else return rfx end;
when TR_FLT_LIT_EXPR::fltdx then
rfdx::=#AM_FLTDX_CONST(e);
rfdx.tp_at:=prog.tp_builtin.fltdx;
if void(tp) then return rfdx
elsif ~rfdx.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of FLTDX."); return void
else return rfdx end;
when TR_FLT_LIT_EXPR::flti then
rfi::=#AM_FLTI_CONST(e);
rfi.tp_at:=prog.tp_builtin.flti;
if void(tp) then return rfi
elsif ~rfi.tp_at.is_subtype(tp) then
prog.err_loc(e); prog.err("The type of the destination: " +
tp.str + " is not a supertype of FLTI."); return void
else return rfi end;
-- end end; -- NLP
end; return void; end; -- NLP
-----------
check_return(t:TR_ROUT_DEF) is
-- Check the routine `t' to make sure that if it has a return
-- value, then the last statement actually returns a value.
-- If not, then print an error.
if void(t) then return end;
if void(t.ret_dec) then return end; -- No return value.
if t.name.is_iter then return end; -- No check for iters.
prog.err_loc(t);
check_stmt_list_for_return(t.stmts) end;
check_stmt_list_for_return(t:$TR_STMT) is
-- `t' must either be a return statement, a raise statement
-- or terminate in one. If not, print an error.
if void(t) then return_err; return end;
s:$TR_STMT:=t; loop until!(void(s.next)); s:=s.next end;
prog.err_loc(s);
typecase s
when TR_DEC_STMT then return_err
when TR_ASSIGN_STMT then return_err
when TR_IF_STMT then check_stmt_list_for_return(s.then_part);
check_stmt_list_for_return(s.else_part);
when TR_LOOP_STMT then
-- Don't check anything if the last statement is a loop since
-- can't be sure. (Maybe later check whether there is a return
-- or raise somewhere in the loop.)
-- check_stmt_list_for_return(s.body);
when TR_RETURN_STMT then
when TR_YIELD_STMT then return_err
when TR_QUIT_STMT then return_err
when TR_CASE_STMT then
if ~s.no_else then
check_stmt_list_for_return(s.else_part) end;
wp:TR_CASE_WHEN:=s.when_part;
loop while!(~void(wp));
check_stmt_list_for_return(wp.then_part);
wp:=wp.next end;
when TR_TYPECASE_STMT then
if ~s.no_else then
check_stmt_list_for_return(s.else_part) end;
wp:TR_TYPECASE_WHEN:=s.when_part;
loop while!(~void(wp));
check_stmt_list_for_return(wp.then_part);
wp:=wp.next end;
when TR_ASSERT_STMT then return_err
when TR_PROTECT_STMT then
if ~s.no_else then
check_stmt_list_for_return(s.else_part) end;
wp:TR_PROTECT_WHEN:=s.when_part;
loop while!(~void(wp));
check_stmt_list_for_return(wp.then_part);
wp:=wp.next end;
when TR_RAISE_STMT then
when TR_EXPR_STMT then return_err
else #OUT +
"Compiler error, TRANS::check_stmt_list_for_return else branch."
end end;
return_err is
prog.err("Routine must terminate with a `return' statement or a "
"`raise' statement.") end;
name_for_ext(el:ELT):IDENT is
-- Name to use for an external class call.
if el.is_abstract then return el.sig.name;
-- else return prog.ident_for(el.tp.str+'_'+el.sig.name.str); -- NLP
end; return prog.ident_for(el.tp.str+'_'+el.sig.name.str); -- NLP
-- end; -- NLP
end;
end; -- class TRANS
-------------------------------------------------------------------