Skip to content

For Loops for non Ordinals

During my work on the other merge requests, I found it really annoying that for loops only work for ordinal types, as records wrapping some ordinal types (like tconstexprint in the compiler) are quite common for certain applications (also bigintegers)

The main problem is that for loops can not that easily be substituted with while or repeat loops. The main reason for this is that for loops make a copy of the target value, and they check for the final value to be overflow safe. So the simple conversion from:

  for i:=min to max do
    statement;

would be:

  i:=min;
  tmpmax:=max; { Must create copy, because max could change between accesses }
  if i<=tmpmax then
    repeat
      statement;
      { Can't do a while i<=tmpmax because of potential overflow }
      if i>=tmpmax then
        break
      else
        inc(i);
    until false;

Not to mention if there is a continue in the loop, there are a few options, first replace each continue with

  if i<=max then
    break
  else
    inc(i);
  continue;

or move the check to the beginning:

  i:=min;
  tmpmax:=max;
  firstiter:=true;
  if i<=tmpmax then
    repeat
      if fistiter then
        firstiter:=false
      else if i=tmpmax then
        break
      else
        inc(i);
      statement;
    until false;

or for convinience a try-finally can be used, which has other runtime implications:

  i:=min;
  tmpmax:=max;
  if i<=tmpmax then
    repeat
      try
        statement;
      finally
        if i>=tmpmax then
          break
        else
          inc(i);
      end;
    until false;

Long story short, emulating a for loop is very complicated to do manually (mainly because overflows are complicated) and very error prone. But custom types that emulate ordinal behavior are quite common.

So I've built a simple substitute, which will take above steps, to allow for-to syntax for any type that overloads <=, >= as well as the + operator for integers. This includes custom records types, like tconstexprint or the gmp integers, but also floats.

It does so by simply doing above substitutions automatically to transform a for loop into an if->repeat->statement->increment loop

Merge request reports

Loading