repeating.nim 1.94 KB
import petitparser

# An abstract parser that repeatedly parses between 'min' and 'max' instances of its delegate.
type
  RepeatingParser = ref object of DelegateParser
    min*: int
    max*: int

const UNBOUNDED = 1

proc newRepeatingParser*(delegate: Parser, min, max: int): RepeatingParser =
  if min < 0:
    raise newException(Exception, "Invalid min repetitions")
  if max != UNBOUNDED and min > max:
    raise newException(Exception, "Invalid max repetitions")
  RepeatingParser(delegate, min, max)


discard """   
  @Override
  public boolean hasEqualProperties(Parser other) {
    return super.hasEqualProperties(other) &&
        Objects.equals(min, ((RepeatingParser) other).min) &&
        Objects.equals(max, ((RepeatingParser) other).max);
  }

  @Override
  public String toString() {
    return super.toString() + "[" + min + ".." + (max == UNBOUNDED ? "*" : max) + "]";
  }
"""


# A greedy parser that repeatedly parses between 'min' and 'max' instances of its delegate.

type
  PossessiveRepeatingParser = ref object of RepeatingParser
  
proc newPossessiveRepeatingParser*(delegate: Parser, min, max: int): PossessiveRepeatingParser =
  PossessiveRepeatingParser(newRepeatingParser(delegate, min, max))

discard """
  @Override
  public Result parseOn(Context context) {
    Context current = context;
    List<Object> elements = new ArrayList<>();
    while (elements.size() < min) {
      Result result = delegate.parseOn(current);
      if (result.isFailure()) {
        return result;
      }
      elements.add(result.get());
      current = result;
    }
    while (max == UNBOUNDED || elements.size() < max) {
      Result result = delegate.parseOn(current);
      if (result.isFailure()) {
        return current.success(elements);
      }
      elements.add(result.get());
      current = result;
    }
    return current.success(elements);
  }

  @Override
  public Parser copy() {
    return new PossessiveRepeatingParser(delegate, min, max);
  }
"""