-- (C) Copyright International Business Machines Corporation 23 January 
-- 1990.  All Rights Reserved. 
--  
-- See the file USERAGREEMENT distributed with this software for full 
-- terms and conditions of use. 
-- File: cginsptbl.pp
-- Author: Andy Lowry
-- SCCS Info: @(#)cginsptbl.pp	1.11 3/13/90

-- This process generates code for INSPECT <selector> statement.  The
-- code is based on an 'exactlyOne' loop skeleton produced by
-- cgSelector.  No code is needed prior to the loop, and the loop body
-- is generated from the body clause associated with the INSPECT
-- statement. 

-- A 'scan' style loop ends up looking like this:
--
-- 	initget 	r,t
-- loop:get_or_err 	r,t
--	[additional tests, result in 'test']
--	bfalse 		test {loop}
--	[loop body]
--	endget		r,t
--

#include "typemark.h"
#include "codegen.h"

cgInspTbl: using (cgInternal, interpform)

process (Q: cgStmtQ)

declare
  args: cgStmt;
  tbl: objectname;		-- source table
  tblAddr: interpform!operand;	-- its LI address
  lk: lookupInfo;		-- describes lookup method used in loop
  endLoop: cgSelectorContinueFn; -- call this to tie off the loop
  inspElt: objectname;
  empty: empty;
begin
  receive args from Q;
  reveal args.stmt.qualifier.inspect_table;

  -- Get source table LI address
  tbl <- objectname#(AREF(tmp,args.stmt.operands,ZERO));
  tblAddr <- interpform!operand#(args.cgData.Proc.objAddr(tbl));

  -- Now generate the top part of the loop skeleton
  endLoop <- cgSelectorContinueFn#(FNS.cgSelector(
      args.stmt.qualifier.inspect_table.selector, args.cgData,
      typename#(args.cgData.Proc.objType(tbl)),
      selectorLoopType#'exactlyOne', lk, tblAddr));

  -- We force the selector element variable and the inpsect element
  -- variable to be aliased here to avoid a copy operation... in the
  -- current back-end this can never cause a problem. (famous last
  -- words!)  We also need to add a selectorInfo entry to the scratch
  -- pad for the inspect variable, with all the same info as for the
  -- selector element variable
  block declare
    selEltAddr: interpform!operand;
    selRoot: rootname;
    si: selectorInfoEntry;
  begin
    selEltAddr <- interpform!operand#(args.cgData.Proc.rootAddr(
	args.stmt.qualifier.inspect_table.selector.element,
	args.stmt.qualifier.inspect_table.selector.scope));
    new inspElt;		-- need to build objectname from rootid
    new inspElt.root;
    inspElt.root.root := args.stmt.qualifier.inspect_table.element;
    inspElt.root.scope := args.stmt.qualifier.inspect_table.scope;
    new inspElt.components;
    call args.cgData.Proc.setAddr(inspElt,selEltAddr);
    new selRoot;
    selRoot.root := args.stmt.qualifier.inspect_table.selector.element;
    selRoot.scope := args.stmt.qualifier.inspect_table.selector.scope;
    si := selectorInfoEntry#(args.cgData.scratch.selInfo[selRoot]);
    si.elt := inspElt.root;
    insert si into args.cgData.scratch.selInfo;
  end block;

  -- Now generate the loop body, supplied in the INSPECT statement
  -- qualifier 
  inspect proc in ABSPROG.programs[args.cgData.Proc.id] begin
    inspect scope in proc.executable_part.scopes
	[args.stmt.qualifier.inspect_table.scope] begin
      call FNS.cgClause(scope.clause, args.cgData);
    end inspect;
  end inspect;

  -- Undo the alias we set above
  block declare
    null: interpform!operand;
  begin
    new null;
    call args.cgData.Proc.setAddr(inspElt,null);
  end block;
  
  -- remove the selectorInfo entry we made for the inspect element
  block declare
    si: selectorInfoEntry;
  begin
    remove si from args.cgData.scratch.selInfo[inspElt.root];
  end block;

  -- Now finish up the loop skeleton
  call endLoop(args.cgData);

  return args;

end process
