
(********************************************************************)
(*                                                                  *)
(*  forloop.s7i   For-loop and templates to define for-loop         *)
(*  Copyright (C) 1989 - 2013  Thomas Mertes                        *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library 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 the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


(**
 *  [[integer|Integer]] for-loop, looping from ''lowerLimit'' upward to ''upperLimit''.
 *  The variable ''aVar'' is initialized with ''lowerLimit''. The
 *  ''statements'' are executed repeatedly. After each repetition the
 *  variable ''aVar'' is incremented. After the ''statements'' were
 *  executed with ''upperLimit'' the for-loop is terminated. When
 *  ''lowerLimit'' is greater than ''upperLimit'' the ''statements'' are
 *  not executed at all.
 *)
const proc: for (inout integer: aVar) range (in integer: lowerLimit) to (in integer: upperLimit) do
              (in proc: statements)
            end for is                                                      action "PRC_FOR_TO";


(**
 *  [[integer|Integer]] for-loop, looping from ''upperLimit'' downward to ''lowerLimit''.
 *  The variable ''aVar'' is initialized with ''upperLimit''. The
 *  ''statements'' are executed repeatedly. After each repetition the
 *  variable ''aVar'' is decremented. After the ''statements'' were
 *  executed with ''lowerLimit'' the for-loop is terminated. When
 *  ''upperLimit'' is less than ''lowerLimit'' the ''statements'' are
 *  not executed at all.
 *)
const proc: for (inout integer: aVar) range (in integer: upperLimit) downto (in integer: lowerLimit) do
              (in proc: statements)
            end for is                                                      action "PRC_FOR_DOWNTO";


(**
 *  Template function to define for-loops with step for ''aType''.
 *  Defines an upward and a downward counting for-loop which
 *  increments/decrements the loop variable with ''incr_step''
 *  respectively ''decr_step''. The for-loops are only defined
 *  when ''aType'' supports the +:= respectively -:= operator.
 *)
const proc: FOR_STEP_DECLS (in type: aType) is func
  begin
    if getobj((inout aType param) +:= (in integer param)) <> NIL then

      const proc: for (inout aType: variable) range (in aType: lowerLimit) to (in aType: upperLimit)
          step (in integer: incr_step) do
          (in proc: statements) end for is func
        begin
          variable := lowerLimit;
          while variable <= upperLimit do
            statements;
            variable +:= incr_step;
          end while;
        end func;

    end if;
    if getobj((inout aType param) -:= (in integer param)) <> NIL then

      const proc: for (inout aType: variable) range (in aType: upperLimit) downto (in aType: lowerLimit)
          step (in integer: decr_step) do
          (in proc: statements) end for is func
        begin
          variable := upperLimit;
          while variable >= lowerLimit do
            statements;
            variable -:= decr_step;
          end while;
        end func;

    end if;
  end func;


(**
 *  Template function to define all for-loops for ''aType''.
 *  Defines upward and downward counting for-loops which
 *  increment/decrement the loop variable with 1 or with a
 *  given step value. The for-loops with step value are
 *  defined with the ''FOR_STEP_DECLS'' template.
 *)
const proc: FOR_DECLS (in type: aType) is func
  begin

    const proc: for (inout aType: variable) range (in aType: lowerLimit) to (in aType: upperLimit) do
        (in proc: statements) end for is func
      begin
        variable := lowerLimit;
        if variable <= upperLimit then
          statements;
          while variable < upperLimit do
            incr(variable);
            statements;
          end while;
        end if;
      end func;

    const proc: for (inout aType: variable) range (in aType: upperLimit) downto (in aType: lowerLimit) do
        (in proc: statements) end for is func
      begin
        variable := upperLimit;
        if variable >= lowerLimit then
          statements;
          while variable > lowerLimit do
            decr(variable);
            statements;
          end while;
        end if;
      end func;

    FOR_STEP_DECLS(aType);
  end func;


FOR_STEP_DECLS(integer);
FOR_DECLS(char);
FOR_DECLS(boolean);


(**
 *  For-loop which loops over the [[char|characters]] of a [[string]]
 *)
const proc: for (inout char: variable) range (in string: stri) do
              (in proc: statements)
            end for is func
  local
    var integer: number is 0;
  begin
    for number range 1 to length(stri) do
      variable := stri[number];
      statements;
    end for;
  end func;


(**
 *  For-loop which loops over the keys (indices) of a [[string]].
 *)
const proc: for key (inout integer: keyVar) range (in string: stri) do
              (in proc: statements)
            end for is func
  begin
    for keyVar range 1 to length(stri) do
      statements;
    end for;
  end func;


(**
 *  For-loop which loops over [[char|characters]] and keys (indices) of a [[string]].
 *)
const proc: for (inout char: variable) key (inout integer: keyVar) range (in string: stri) do
              (in proc: statements)
            end for is func
  begin
    for keyVar range 1 to length(stri) do
      variable := stri[keyVar];
      statements;
    end for;
  end func;
