module loops88;  % Rlisp88 looping forms other than the FOR statement.
                
% Author: Anthony C. Hearn.

fluid '(!*blockp loopdelimslist!*);

global '(cursym!* repeatkeywords!* whilekeywords!*);


% ***** REPEAT STATEMENT *****

repeatkeywords!* := '(finally initially returns until with);

symbolic procedure repeatstat88;
  begin scalar body,!*blockp,x,y,z;
      loopdelimslist!* := repeatkeywords!* . loopdelimslist!*;
      flag(repeatkeywords!*,'delim);
      body := erroreval '(xread t);
      if not (cursym!* memq repeatkeywords!*) then symerr('repeat,t);
  a:  x := cursym!*;
      y := erroreval if x eq 'with then '(xread 'lambda)
		      else '(xread t);
      z := (x . y) . z;
      if cursym!* memq repeatkeywords!* then go to a;
      remflag(car loopdelimslist!*,'delim);
      loopdelimslist!* := cdr loopdelimslist!*;
      if loopdelimslist!* then flag(car loopdelimslist!*,'delim);
      return 'repeat . body . reversip z
   end;

symbolic macro procedure repeat88 u;
   begin scalar body,lab,xwith;
	body := cadr u; u := cddr u;
	xwith := atsoc('with,u);
	return sublis(pair('(!$locals !$do !$rets !$inits !$fins !$bool
			     !$label),
			   list(if xwith then cdr xwith else nil,
				body,
				x!-car x!-cdr atsoc('returns,u),
				mkfn(x!-cdr atsoc('initially,u),'progn),
				mkfn(x!-cdr atsoc('finally,u),'progn),
				x!-car x!-cdr atsoc('until,u),
				gensym())),
		      '(prog !$locals
			     !$inits
			!$label !$do
			     (cond (!$bool !$fins (return !$rets)))
			     (go !$label)))
   end;

symbolic procedure remcomma!* u; if null u then nil else remcomma cdr u;

symbolic procedure x!-car u; if atom u then u else car u;

symbolic procedure x!-cdr u; if null u then nil else list cdr u;

% flag('(repeat),'nochange);

symbolic procedure formrepeat88(u,vars,mode);
   begin scalar y,z;
      for each x in cddr u do
	 if car x eq 'with
	   then <<y := remcomma cdr x;
		  vars := nconc(for each j in y collect j . 'scalar,
				vars);
		  z := (car x . y) . z>>
%         else if car x eq 'until
%          then z := (car x . formbool(cdr x,vars,mode)) . z
	  else z := (car x . formc(cdr x,vars,mode)) . z;
      return 'repeat . formc(cadr u,vars,mode) . reversip z
   end;


% ***** WHILE STATEMENT *****

whilekeywords!* := '(collect do finally initially returns with);

symbolic procedure whilstat88;
   begin scalar !*blockp,bool1,x,y,z;
      loopdelimslist!* := whilekeywords!* . loopdelimslist!*;
      flag(whilekeywords!*,'delim);
      bool1 := erroreval '(xread t);
      if not (cursym!* memq whilekeywords!*) then symerr('while,t);
  a:  x := cursym!*;
      y := erroreval if x eq 'with then '(xread 'lambda)
		      else '(xread t);
      z := (x . y) . z;
      if cursym!* memq whilekeywords!* then go to a;
      remflag(car loopdelimslist!*,'delim);
      loopdelimslist!* := cdr loopdelimslist!*;
      if loopdelimslist!* then flag(car loopdelimslist!*,'delim);
      return 'while . bool1 . reversip z
   end;

symbolic macro procedure while88 u;
   begin scalar body,bool,lab,rets,vars;
      bool := cadr u; u := cddr u;
      rets := x!-car x!-cdr atsoc('returns,u);
      vars := x!-car x!-cdr atsoc('with,u);
      if body := atsoc('collect,u)
	then <<vars := gensym() . vars;
	       body := list('setq,
			    car vars,
			    list('cons,cdr body,car vars));
	       if rets then rederr "While loop value conflict";
	       rets := list('reversip,car vars)>>
       else if body := atsoc('do,u) then body := cdr body
       else rederr "Missing body in WHILE statement";
      return sublis(pair('(!$locals !$do !$rets !$inits !$fins !$bool
			   !$label),
			 list(vars,
			      body,
			      rets,
			      mkfn(x!-cdr atsoc('initially,u),'progn),
			      mkfn(x!-cdr atsoc('finally,u),'progn),
			      bool,
			      gensym())),
		    '(prog !$locals
			   !$inits
		      !$label
			   (cond ((not !$bool) !$fins (return !$rets)))
			   !$do
			   (go !$label)))
   end;

% flag('(while),'nochange);

symbolic procedure formwhile88(u,vars,mode);
   begin scalar y,z;
      for each x in cddr u do
	 if car x eq 'with
	   then <<y := remcomma cdr x;
		  vars := nconc(for each j in y collect j . 'scalar,
				vars);
		  z := (car x . y) . z>>
	  else z := (car x . formc(cdr x,vars,mode)) . z;
      return 'while . formc(cadr u,vars,mode) . reversip z
   end;

endmodule;

end;
