------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 1995 by International Computer Science Institute            --
-- This file is part of the GNU Sather package. It is free software; you may --
-- redistribute  and/or modify it under the terms of the  GNU General Public --
-- License (GPL)  as  published  by the  Free  Software  Foundation;  either --
-- version 2 of the license, or (at your option) any later version.          --
-- This  program  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/GPL for more details.        --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------

-- $AM_EXPR: Supertype of expression-like components.
-- AM_EXPR: Implementation to be included by $AM_EXPR nodes. 
-- AM_LOCAL_EXPR: Local variable expression.
-- AM_ARRAY_EXPR: An array creation expression.
-- AM_BND_CREATE_EXPR: Bound routine and iter creation expression.
-- AM_IF_EXPR: Conditional expression.
-- AM_NEW_EXPR: New expression.
-- AM_IS_VOID_EXPR: Test for "void".
-- AM_SHARED_EXPR: Global variable expression.
-- AM_ATTR_EXPR: An expression referencing an attribute of an object.
-- AM_VATTR_ASSIGN_EXPR: Assignment to an attribute of a value object.
-- AM_VARR_ASSIGN_EXPR: Assignment to an array element of a value object.   
-- AM_EXCEPT_EXPR: An expression referring to the exception global.
-- AM_STMT_EXPR: An expression with embedded statements.
-- AM_ASIZE_EXPR: the AREF asize read expression
--
-- AM_HERE_EXPR
-- AM_ANY_EXPR
-- AM_WHERE_EXPR
-- AM_NEAR_EXPR
-- AM_FAR_EXPR
-- AM_AT_EXPR
--
-- For zones only: AM_GLOBAL_EXPR
--
-- Although it belongs to pSather it is used in Sather as well (return 1)
-- AM_CLUSTER_EXPR
-- AM_CLUSTER_SIZE_EXPR

-------------------------------------------------------------------      
abstract class $AM_EXPR < $AM, $HASH is
   -- Supertype of expression-like components.

   tp:$TP;			    -- The type of the expression.
   source: SFILE_ID;
   source(set: SFILE_ID);
   
   copy:$AM_EXPR;
   is_near:BOOL;		    -- true if the expression returns a value
				    -- that is stored locally. (if the return type
				    -- is immutable or void, it is always true)
   near_depends_on:FLIST{AM_LOCAL_EXPR};  -- returns a list of locals. If all those locals
				    -- are near, the result is near too.
				    -- void means that the result is either near
				    -- or far, as defined by is_near.

end;
   
-------------------------------------------------------------------      
partial class AM_EXPR is 
   -- Supertype of expression-like components.
   include AM;
   stub tp:$TP;

   -- This is used to determine if two expressions are equal, and thus can
   -- be optimized out.
   is_eq(a:$OB):BOOL is
      -- Equality note: changed from "a:$AM_EXPR".       
      return SYS::ob_eq(self,a);
   end;

   -- This hash function might be used by the namespace manager, so return
   -- the object ID if no other hash function is defined.
   hash:INT is
      return SYS::id(self).hash;
   end;

   -- default version returns false unless the returntype is immutable
   is_near:BOOL is
      return tp.is_immutable;
   end;

   near_depends_on:FLIST{AM_LOCAL_EXPR} is return void; end;
end;
   
-------------------------------------------------------------------      
class AM_LOCAL_EXPR < $AM_EXPR is
   -- Local variable expression.
   include AM_EXPR;
   
   attr is_volatile:BOOL;       -- True if the variable must be declared
      -- "volatile". This is necessary in protect statments because
      -- otherwise longjmp will incorrectly restore the values of locals
      -- which happen to be held in registers.
   attr name:IDENT;		-- The name of the local in the Sather
      -- program, if any.
   attr tp_at:$TP;		-- The declared type of the variable.
   attr needs_init:BOOL;	-- True if this local must be initialized
      -- to 0 at the start of the routine. 
   attr no_assign:BOOL;		-- True if this variable may not be
      -- assigned to because it is currently being typecased on.
      -- (Used internally). 
   attr is_hot:BOOL;		-- set to one if this varaiable is a 
   				-- 'hot' argument of an iter.
				-- This is set by the optimizer!
				-- This attribute is also used for prefetch
				-- variables to indicate that they are actually
				-- used. A prefetch variable can never be 
				-- used as an argument of an iter.
   attr not_in_frame:BOOL;	-- true if the local should not be in
			        -- the iter frame
   attr is_always_near:BOOL;	-- true if there is no assignment that
				-- could make this local to be non near;
   attr check_near:BOOL;	-- true during evaluation of with near.
			        -- assignments are checked for nearness

   is_near:BOOL is return is_always_near or tp_at.is_immutable; end;
   near_depends_on:FLIST{AM_LOCAL_EXPR} is
      if is_near then return void; 
      else return FLIST{AM_LOCAL_EXPR}::push(self);
      end;
   end;


   create(src:SFILE_ID, name:IDENT, tp:$TP):SAME is
      r::=new; r.source:=src; r.name:=name; r.tp_at:=tp;
      return r end;

   create(src:SFILE_ID, name:IDENT, tp:$TP, as_tp:AS_TYPE_SPEC):SAME is
      r::=new; r.source:=src; r.name:=name; r.tp_at:=tp; r.as_type:=as_tp;
      return r end;
   
   is_named:BOOL is
      -- True if this is a named local variable.
      return ~void(name) end;

   tp:$TP is return tp_at end;
   attr as_type : AS_TYPE_SPEC;


   is_eq(a:$OB):BOOL is
      -- this is true because a namespace for locals is maintained in trans.sa
      return SYS::ob_eq(self,a);  
   end;

   hash:INT is
      -- this is true because a namespace for locals is maintained in trans.sa
      return SYS::id(self).hash;
   end;

   copy:SAME is return self; end;
end;
   
-------------------------------------------------------------------      
class AM_ARRAY_EXPR < $AM_EXPR is
   -- An array creation expression.
   include AM_EXPR create->;
   include ARRAY{$AM_EXPR} append->,merge_with_by-> ;	
      -- An array of the expressions 
      -- specifying the values of the array entries. These must be
      -- evaluated left to right. The number specifies the size of
      -- the created array.
   attr tp_at:$TP;			-- The type of the array.
   
   create(nargs:INT, source:SFILE_ID):SAME is
      -- A new definition for a routine or iter with `nargs' arguments
      -- (including self).
      r::=new(nargs); r.source:=source; return r end;
   
   tp:$TP is return tp_at end;   

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(size,source);
      loop
	 x::=elt!;
	 if ~void(x) then x:=x.copy; end;
         r.set!(x);
      end;
      r.tp_at:=tp_at;
      return r;
   end;

   is_near:BOOL is return true; end;
end;
   
-------------------------------------------------------------------      
class AM_BND_CREATE_EXPR < $AM_EXPR is
   -- Bound routine or iter creation expression.
   include AM_EXPR create->;
   include ARRAY{AM_CALL_ARG} append->,merge_with_by->; -- An array of expressions for the
      -- bound up arguments in order.
   
   attr fun:SIG;		-- The routine to bind up.
   attr bnd_args:ARRAY{INT};	-- The indices of the arguments 
      -- which are bound up in order. 0 is self.
   attr unbnd_args:ARRAY{INT};	-- The indices of the arguments 
      -- which are not bound in order. 0 is self.   
   attr tp_at:$TP;			-- The type of the bound expression.
   attr is_remote:BOOL;	-- true if this bound routine is used for
   			-- a remote procedure call in pSather
   attr clst:STR;       -- string that represents the variable that
   			-- stores the remote cluster
   
   create(nargs:INT, source:SFILE_ID):SAME is
      -- A new definition for a routine or iter with `nargs' arguments
      -- (including self).
      r::=new(nargs); r.source:=source; return r end;
   
   equals(a:AM_BND_CREATE_EXPR):BOOL is
      if fun/=a.fun or bnd_args.size/=a.bnd_args.size or
	 unbnd_args.size/=a.unbnd_args.size then 
	   return false;
      end;
      loop
	 if bnd_args.elt!/=a.bnd_args.elt! then return false; end;
      end;
      return true;
   end;

   tp:$TP is return tp_at end;   

   -- currently it is not possible to create a bound object
   -- on another cluster
   is_near:BOOL is return true; end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(size,source);
      r.fun:=fun;
      if ~void(unbnd_args) then r.unbnd_args:=unbnd_args.copy; end;
      if ~void(bnd_args) then r.bnd_args:=bnd_args.copy; end;
      r.tp_at:=tp_at;
      return r;
   end;
end;


-------------------------------------------------------------------      
class AM_IF_EXPR < $AM_EXPR is
   -- Conditional expression. Only one of the two branches will be
   -- executed.
   include AM_EXPR;
   
   attr test:$AM_EXPR;		-- The boolean expression to test.
   attr if_true:$AM_EXPR;	-- Expression with result if true.
   attr if_false:$AM_EXPR;	-- Expression with result if false.      
   attr tp_at:$TP;			-- The type. 


   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(test) then r.test:=test.copy; end;
      if ~void(if_true) then r.if_true:=if_true.copy; end;
      if ~void(if_false) then r.if_false:=if_false.copy; end;
      r.tp_at:=tp_at;
      return r;
   end;

   is_near:BOOL is return (void(if_true) or if_true.is_near) and (void(if_false) and if_false.is_near); end;

   near_depends_on:FLIST{AM_LOCAL_EXPR} is
      f:FLIST{AM_LOCAL_EXPR};
      if ~void(if_true) then
         f:=if_true.near_depends_on;
	 if void(f) and ~if_true.is_near then return void; end;
      end;
      if ~void(if_false) then
         g::=if_true.near_depends_on;
	 if void(g) and ~if_false.is_near then return void; end;
	 return f.append(g);
      end;
   end;

   is_eq(am:$OB):BOOL is
      -- Changed argument from $AM_EXPR
      typecase am 
      when AM_IF_EXPR then
         if void(test)/=void(am.test) or 
            void(if_true)/=void(am.if_true) or
	    void(if_false)/=void(am.if_false) or
	    tp_at/=am.tp_at then return false;end;
	 return (void(test) or test=am.test) and
	        (void(if_true) or if_true=am.if_true) and
		(void(if_false) or if_false=am.if_false);
      else return false;
      end;	
   end;
   
   tp:$TP is return tp_at end;   
end;
   
-------------------------------------------------------------------      
class AM_NEW_EXPR < $AM_EXPR is
   -- New expression.
   include AM_EXPR;
   
   attr tp_at:$TP;		-- The type of object to allocate. 
   attr asz:$AM_EXPR;		-- Number of array elements to 
      -- allocate for array descendants. 
   
   tp:$TP is return tp_at end;

   -- new is always near
   is_near:BOOL is return true; end; 

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      r.tp_at:=tp_at;
      if ~void(asz) then r.asz:=asz.copy; end;
      return r;
   end;
end;
   
-------------------------------------------------------------------
class AM_IS_VOID_EXPR < $AM_EXPR is
   -- Test for "void".
   include AM_EXPR;

   attr tp_at:$TP;		-- The type BOOL.
   
   attr arg:$AM_EXPR;		-- Expression to test for void.
   
   tp:$TP is return tp_at end;   

   is_near:BOOL is return true; end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(arg) then r.arg:=arg.copy; end;
      r.tp_at:=tp_at;
      return r;
   end;

   is_eq(a:$OB):BOOL is
      typecase a
      when AM_IS_VOID_EXPR then return arg.is_eq(a.arg);
      else return false;
      end;
   end;
   
   hash:INT is
      return arg.hash.bxor(0xf03);  -- just change it a bit
   end;
end;
   
-------------------------------------------------------------------      
class AM_SHARED_EXPR < $AM_EXPR is
   -- Global variable expression.
   include AM_EXPR;
   
   attr tp_at:$TP;		-- The declared type of the global.
   attr name:IDENT;		-- The Sather name, if any.
   attr class_tp:$TP;		-- The class this came from.
   attr init:$AM_EXPR;		-- The initialization expression, if
      -- any. This must consist of only the expression components
      -- which are legal for constant initializers.
   attr is_const:BOOL;		-- True if this is a constant.
   
   tp:$TP is return tp_at end;   
   attr as_type : AS_TYPE_SPEC;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      r.tp_at:=tp_at;
      r.name:=name;
      r.class_tp:=class_tp;
      if ~void(init) then r.init:=init.copy; end;
      r.is_const:=is_const;
      return r;
   end;


   is_eq(a:$OB):BOOL is
      typecase a 
      when AM_SHARED_EXPR then return name = a.name and class_tp = a.class_tp;
      else return false;  -- wrong type, this not equal 
      end;
   end;

   hash:INT is
      return name.hash.bxor(class_tp.hash);
   end;
end;
   
-------------------------------------------------------------------      
class AM_ATTR_EXPR < $AM_EXPR is
   -- An expression referencing an attribute of an object.
   include AM_EXPR;
   
   attr ob:$AM_EXPR;	-- The object.
   attr self_tp:$TP;	-- The type of self, perhaps different from ob.tp
			-- after inlining.
   attr at:IDENT;	-- The name of the attribute.   
   attr tp_at:$TP;	-- The type. 
   attr secure:BOOL;	-- if true, the generated code will not break if
                        -- ob is NULL. This is used when evaluating some 
			-- hoisted expressions and never if void check is
			-- used.
                       
   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(ob) then r.ob:=ob.copy; end;
      r.self_tp:=self_tp;
      r.at:=at;
      r.tp_at:=tp_at;
      r.secure:=secure;
      return r;
   end;
   
   tp:$TP is return tp_at end;
   attr as_type : AS_TYPE_SPEC;

-- equality and hashing functions for optimization purposes
   is_eq(a:$OB):BOOL is
      -- Changed argument from $AM_EXPR
      typecase a
      when AM_ATTR_EXPR then return (at = a.at) and (ob = a.ob);
      else return false;
      end;
   end;
   hash:INT is
      return at.hash.bxor(ob.hash);
   end;
end;
   
-------------------------------------------------------------------      
class AM_VATTR_ASSIGN_EXPR < $AM_EXPR is
   -- Assignment to an attribute of a value object.
   include AM_EXPR;

   attr ob:$AM_EXPR;		-- The value object.
   attr at:IDENT;		-- The name of the attribute.   
   attr val:$AM_EXPR;           -- The new value.
   attr real_tp:$TP;		-- declared type of object
   
   tp:$TP is return ob.tp end; -- Returns the object, so has same type.

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(ob) then r.ob:=ob.copy; end;
      r.at:=at;
      r.real_tp:=real_tp;
      if ~void(val) then r.val:=val.copy; end;
      return r;
   end;

end;
   
-------------------------------------------------------------------      
class AM_VARR_ASSIGN_EXPR < $AM_EXPR is
   -- Assignment to an array element of a value object.
   include AM_EXPR;

   attr ob:$AM_EXPR;		-- The value object.
   attr ind:$AM_EXPR;		-- The index of the array element.   
   attr val:$AM_EXPR;           -- The new value.
   
   tp:$TP is return ob.tp end; -- Returns the object, so has same type.

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(ob) then r.ob:=ob.copy; end;
      if ~void(ind) then r.ind:=ind.copy; end;
      if ~void(val) then r.val:=val.copy; end;
      return r;
   end;

end;
   
-------------------------------------------------------------------     
class AM_EXCEPT_EXPR < $AM_EXPR is
   -- An expression referring to the exception global.
   include AM_EXPR;
   
   attr tp_at:$TP;		-- The type.
   
   create(tp:$TP):SAME is
      r::=new; r.tp_at:=tp; return r end;
   
   tp:$TP is return tp_at end;   

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(tp_at);
      return r;
   end;
   
end;
   
-------------------------------------------------------------------        
class AM_STMT_EXPR < $AM_EXPR is
   -- An expression with embedded statements.   
   include AM_EXPR;
   
   attr stmts:$AM_STMT;		-- The statements to execute.
   attr expr:$AM_EXPR;		-- The expression.
   attr replaced:$AM_EXPR;	-- If this stmt_expr replaced some
				-- other code, this code may still be stored
				-- here for reference (used for inlined functions)

   is_near:BOOL is return expr.is_near; end;
   near_depends_on:FLIST{AM_LOCAL_EXPR} is return expr.near_depends_on; end;

   copy:SAME is -- does not copy the stuff used for inlining !
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(stmts) then r.stmts:=stmts.copy; end;
      if ~void(expr) then r.expr:=expr.copy; end;
      return r;
   end;
   -- The following needed by the inlined calls
   -- Ivin
    attr locals:FLIST{AM_LOCAL_EXPR}; -- Local variables stmts need.
    attr calls:FLIST{$AM_EXPR};  -- The calls that occur in the statements.
    -- Append this to the enclosing loop statement's corresponding fields.
    attr its:FLIST{AM_ITER_CALL_EXPR};
    attr bits:FLIST{AM_BND_ITER_CALL_EXPR};
    attr firsts:FLIST{AM_LOCAL_EXPR};
   
   tp:$TP is 
      if void(expr) then return void else return expr.tp end end;
end;

-------------------------------------------------------------------        

class AM_GLOBAL_EXPR < $AM_EXPR is
   -- Zones only.  There used to be another AM type called AM_GLOBAL_EXPR
   -- which is now called AM_SHARED_EXPR, which is closer to the Sather
   -- terminology.
   
   include AM_EXPR;
   
   create(src:SFILE_ID):SAME is
      -- Create a new here object with source `src'.
      r::=new; r.source:=src; return r end;

   is_eq(a:$OB):BOOL is
      return void(self) and void(a) 
             or ~void(self) and ~void(a) and SYS::tp(a)=SYS::tp(self);
   end;
      
   tp:$TP is return TP_BUILTIN::zone end;   

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      return r;
   end;
   
end;   

-------------------------------------------------------------------        

class AM_HERE_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   create(src:SFILE_ID, zones:BOOL):SAME is
      -- Create a new here object with source `src'.
      r::=new;
      r.source:=src;
      if zones then 
	 r.tp:=TP_BUILTIN::zone;
      else
	 r.tp:=TP_BUILTIN::int;
      end;
      return r
   end;

   is_eq(a:$OB):BOOL is
      return void(self) and void(a) 
             or ~void(self) and ~void(a) and SYS::tp(a)=SYS::tp(self);
   end;
      
   -- The type depends on whether zones are running or not, so this
   -- must be filled in during TRANS while there is a convenient 
   -- pointer to the prog object to check `prog.zones'.
   readonly attr tp:$TP;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      return r;
   end;
   
end;   

-------------------------------------------------------------------        

class AM_ANY_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   create(src:SFILE_ID):SAME is
      -- Create a new any object with source `src'.
      r::=new; r.source:=src; return r end;
   
   tp:$TP is return TP_BUILTIN::int end;   
   is_eq(a:$OB):BOOL is
      return void(self) and void(a) 
             or ~void(self) and ~void(a) and SYS::tp(a)=SYS::tp(self);
   end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      return r;
   end;
   
end;   
-------------------------------------------------------------------        

class AM_CLUSTER_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   create(src:SFILE_ID):SAME is
      -- Create a new cluster object with source `src'.
      r::=new; r.source:=src; return r end;
   
   is_eq(a:$OB):BOOL is
      return void(self) and void(a) 
             or ~void(self) and ~void(a) and SYS::tp(a)=SYS::tp(self);
   end;

   tp:$TP is return TP_BUILTIN::int end;   
   
   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      return r;
   end;
end;   

-------------------------------------------------------------------    

class AM_CLUSTER_SIZE_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   create(src:SFILE_ID):SAME is
      -- Create a new cluster object with source `src'.
      r::=new; r.source:=src; return r end;
   
   tp:$TP is return TP_BUILTIN::int end;   
   
   is_eq(a:$OB):BOOL is
      return void(self) and void(a) 
             or ~void(self) and ~void(a) and SYS::tp(a)=SYS::tp(self);
   end;
   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      return r;
   end;
end;   

-------------------------------------------------------------------    

class AM_WHERE_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   attr arg:$AM_EXPR;		-- Object for where.
   
   create(src:SFILE_ID, zones:BOOL):SAME is
      -- Create a new where object with source `src'.
      r::=new;
      r.source:=src;
      if zones then
	 r.tp:=TP_BUILTIN::zone;
      else
	 r.tp:=TP_BUILTIN::int;
      end;
      return r
   end;
   
   -- The type depends on whether zones are running or not, so this
   -- must be filled in during TRANS while there is a convenient 
   -- pointer to the prog object to check `prog.zones'.
   readonly attr tp:$TP;

   is_eq(a:$OB):BOOL is
      -- Changed argument from $AM_EXPR
      typecase a
      when AM_WHERE_EXPR then return arg = a.arg;
      else return false;
      end;
   end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(arg) then r.arg:=arg.copy; end;
      return r;
   end;
   
end;   

-------------------------------------------------------------------     
   
class AM_NEAR_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   attr arg:$AM_EXPR;		-- Object for near test.
   
   create(src:SFILE_ID):SAME is
      -- Create a new near object with source `src'.
      r::=new; r.source:=src; return r end;
      
   tp:$TP is return TP_BUILTIN::bool end;   

   is_eq(a:$OB):BOOL is
      -- Changed argument from $AM_EXPR
      typecase a
      when AM_NEAR_EXPR then return arg = a.arg;
      else return false;
      end;
   end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(arg) then r.arg:=arg.copy; end;
      return r;
   end;
   
end;   

-------------------------------------------------------------------   
     
class AM_FAR_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   attr arg:$AM_EXPR;		-- Object for far test.
   
   create(src:SFILE_ID):SAME is
      -- Create a new far object with source `src'.
      r::=new; r.source:=src; return r end;
      
   tp:$TP is return TP_BUILTIN::bool end;   

   is_eq(a:$OB):BOOL is
      -- Changed argument from $AM_EXPR
      typecase a
      when AM_FAR_EXPR then return arg = a.arg;
      else return false;
      end;
   end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(arg) then r.arg:=arg.copy; end;
      return r;
   end;
   
end;   

-------------------------------------------------------------------        

class AM_AT_EXPR < $AM_EXPR is
   -- pSather
   
   include AM_EXPR;
   
   attr at:$AM_EXPR;		 -- at value.
   attr e:$AM_EXPR;              -- Expression (in front of @)

   create(src:SFILE_ID):SAME is
      -- Create a new at object with source `src'.
      r::=new; r.source:=src; return r end;
   
   tp:$TP is return e.tp end;   

   is_eq(a:$OB):BOOL is
      -- Changed argument from $AM_EXPR
      typecase a
      when AM_AT_EXPR then return e = a.e and at=a.at;
      else return false;
      end;
   end;

   copy:SAME is
      if void(self) then return void; end;
      r::=#SAME(source);
      if ~void(at) then r.at:=at.copy; end;
      if ~void(e) then r.e:=e.copy; end;
      return r;
   end;
   
end;   



-- vim:sw=3:nosmartindent
