Commit 3f64a3722a78b3adead8a524775629809b5a9c1e

Authored by Göran Krampe
0 parents

First commit

combinators.nim 0 → 100644
  1 +++ a/combinators.nim
  1 +import petitparser, context
  2 +
  3 +# DelegateParser
  4 +type
  5 + DelegateParser* = ref object of Parser
  6 + delegate*: Parser
  7 +
  8 +proc newDelegateParser*(delegate: Parser not nil): DelegateParser =
  9 + DelegateParser(delegate: delegate)
  10 +
  11 +method parseOn*(self: DelegateParser, context: Context): Result =
  12 + self.delegate.parseOn(context)
  13 +
  14 +method replace*(self: DelegateParser, source, target: Parser) =
  15 + procCall(Parser(self).replace(source, target))
  16 + if delegate == source:
  17 + delegate = target
  18 +
  19 +method getChildren(self: DelegateParser): seq[Parser] =
  20 + @[delegate]
  21 +
  22 +method copy(self: DelegateParser): Parser =
  23 + newDelegateParser(self.delegate)
  24 +
  25 +
  26 +## A parser that optionally parsers its delegate, or answers nil.
  27 +type
  28 + OptionalParser* = ref object of DelegateParser
  29 + otherwise*: RootRef
  30 +
  31 +proc newOptionalParser*(delegate: Parser, otherwise: RootRef): OptionalParser =
  32 + OptionalParser(delegate: delegate, otherwise: otherwise)
  33 +
  34 +# public OptionalParser(Parser delegate, Object otherwise) {
  35 +# super(delegate);
  36 +# this.otherwise = otherwise;
  37 +# }
  38 +
  39 +method parseOn*(self: OptionalParser, context: Context): Result =
  40 + result = self.delegate.parseOn(context)
  41 + if result.isSuccess:
  42 + return
  43 + current.success(elements)
  44 +
  45 +
  46 +# public Result parseOn(Context context) {
  47 +# Result result = delegate.parseOn(context);
  48 +# if (result.isSuccess()) {
  49 +# return result;
  50 +# } else {
  51 +# return context.success(otherwise);
  52 +# }
  53 +# }
  54 +
  55 +method hasEqualProperties*(self: OptionalParser, other: Parser): bool =
  56 + return true
  57 +
  58 +# protected boolean hasEqualProperties(Parser other) {
  59 +# return super.hasEqualProperties(other) &&
  60 +# Objects.equals(otherwise, ((OptionalParser) other).otherwise);
  61 +# }
  62 +
  63 +method copy*(self: OptionalParser): Parser =
  64 + newOptionalParser(self.delegate, self.otherwise)
  65 +
  66 +# @Override
  67 +# public Parser copy() {
  68 +# return new OptionalParser(delegate, otherwise);
  69 +# }
  70 +
  71 +
  72 +
  73 +# Abstract parser that parses a list of things in some way (to be specified by the subclasses).
  74 +type
  75 + ListParser* = ref object of Parser
  76 + parsers*: seq[Parser]
  77 +
  78 +#proc newListParser*(parsers: seq[Parser] not nil): ListParser =
  79 +# ListParser(parsers: parsers)
  80 +
  81 +method replace*(self: ListParser, source, target: Parser) =
  82 + procCall(Parser(self).replace(source, target))
  83 + for i in 0..high(parsers):
  84 + if parsers[i] == source:
  85 + parsers[i] = target
  86 +
  87 +# public void replace(Parser source, Parser target) {
  88 +# super.replace(source, target);
  89 +# for (int i = 0; i < parsers.length; i++) {
  90 +# if (parsers[i] == source) {
  91 +# parsers[i] = target;
  92 +# }
  93 +# }
  94 +# }
  95 +
  96 +method getChildren(self: ListParser): seq[Parser] =
  97 + self.parsers
  98 +
  99 +# public List<Parser> getChildren() {
  100 +# return Arrays.asList(parsers);
  101 +# }
  102 +
  103 +
  104 +# A parser that parses a sequence of parsers.
  105 +type
  106 + SequenceParser* = ref object of ListParser
  107 +
  108 +method parseOn*(self: SequenceParser, context: Context): Result =
  109 + var
  110 + current = context
  111 + elements = newSeq[auto](self.parsers.len)
  112 + for parser in self.parsers:
  113 + result = parser.parseOn(current)
  114 + if result.isFailure:
  115 + return
  116 + elements.add(result.get())
  117 + current = result
  118 + current.success(elements)
  119 +
  120 +# public Result parseOn(Context context) {
  121 +# Context current = context;
  122 +# List<Object> elements = new ArrayList<>(parsers.length);
  123 +# for (Parser parser : parsers) {
  124 +# Result result = parser.parseOn(current);
  125 +# if (result.isFailure()) {
  126 +# return result;
  127 +# }
  128 +# elements.add(result.get());
  129 +# current = result;
  130 +# }
  131 +# return current.success(elements);
  132 +# }
  133 +
  134 +method seq*(self: SequenceParser, others: varargs[Parser]): Parser =
  135 + newSequenceParser(self.parsers & others)
  136 +# let all = newSeq[Parser](self.parsers.len + others.len)
  137 +
  138 +# public Parser seq(Parser... others) {
  139 +# Parser[] array = Arrays.copyOf(parsers, parsers.length + others.length);
  140 +# System.arraycopy(others, 0, array, parsers.length, others.length);
  141 +# return new SequenceParser(array);
  142 +# }
  143 +
  144 +method copy*(self: SequenceParser): Parser =
  145 + newSequenceParser(@[] & self.parsers)
  146 +
  147 +
  148 +# @Override
  149 +# public Parser copy() {
  150 +# return new SequenceParser(Arrays.copyOf(parsers, parsers.length));
  151 +# }
  152 +#}
... ...
context.nim 0 → 100644
  1 +++ a/context.nim
  1 +import hashes
  2 +
  3 +# Converts the position index in a buffer to a line and column tuple.
  4 +# This code is an adaptation of splitLines.
  5 +proc findLineAndColumn(s: string, position: int): tuple[line, col: int] =
  6 + var first = 0
  7 + var last = 0
  8 + var line = 0
  9 + while true:
  10 + while s[last] notin {'\0', '\c', '\l'}: inc(last)
  11 + # First line found
  12 + inc(line)
  13 + if last > position:
  14 + let col = position - first
  15 + return (line, col)
  16 + # skip newlines:
  17 + if s[last] == '\l': inc(last)
  18 + elif s[last] == '\c':
  19 + inc(last)
  20 + if s[last] == '\l': inc(last)
  21 + else: break # was '\0'
  22 + first = last
  23 +
  24 +
  25 +# Context
  26 +type
  27 + Context* = ref object of RootObj
  28 + buffer*: string
  29 + position*: int
  30 +
  31 +proc newContext*(buffer: string, position: int): Context =
  32 + Context(buffer: buffer, position: position)
  33 +
  34 +
  35 +# Result
  36 +type
  37 + Result* = ref object of Context
  38 +
  39 +# Success
  40 +type
  41 + Success*[T] = ref object of Result
  42 + result*: T
  43 +
  44 +proc newSuccess*[T](buffer: string, position: int, value: T): Success =
  45 + Success(buffer: buffer, position: position, result: value)
  46 +
  47 +# Failure
  48 +type
  49 + Failure* = ref object of Result
  50 + message*: string
  51 +
  52 +proc newFailure*(buffer: string, position: int, message: string): Failure =
  53 + Failure(buffer: buffer, position: position, message: message)
  54 +
  55 +# ParseError Exception
  56 +type
  57 + ParseError* = object of Exception
  58 + failure*: Failure
  59 +
  60 +proc newParseError*(failure: Failure): ref ParseError =
  61 + new(result)
  62 + result.failure = failure
  63 + result.msg = failure.message
  64 +
  65 +# Token
  66 +type
  67 + Token* = ref object of RootObj
  68 + buffer*: string
  69 + start*: int
  70 + stop*: int
  71 + value*: RootRef
  72 +
  73 +proc newToken*(buffer: string, start, stop: int, value: RootRef): Token =
  74 + Token(buffer: buffer, start: start, stop: stop, value: value)
  75 +
  76 +method getInput*(self: Token): string =
  77 + self.buffer.substr(self.start, self.stop)
  78 +
  79 +method getLength*(self: Token): int =
  80 + self.stop - self.stop
  81 +
  82 +method getLine*(self: Token): int =
  83 + self.buffer.findLineAndColumn(self.start)[0]
  84 +
  85 +method getColumn*(self: Token): int =
  86 + self.buffer.findLineAndColumn(self.start)[1]
  87 +
  88 +method `$`*(self: Token): string =
  89 + let (line, col) = findLineAndColumn(self.buffer, self.start);
  90 + "Token[" & $line & ":" & $col & "]: " & repr(self.value) # $self.value
  91 +
  92 +method hash*(self: Token): THash =
  93 + result = self.buffer.hash !& self.start.hash !& self.stop.hash #!& self.value.hash
  94 + result = !$result
  95 +
  96 +# We do not need to redefine ==, the generic one works fine.
  97 +# But let's see if we can
  98 +#method `==`(self, other: Token): bool =
  99 +# if (addr(self) == addr(other)):
  100 +# return true
  101 +# if other.isNil or self.isNil:
  102 +# return false
  103 +# self[] == other[]
  104 +
  105 +
  106 +method success*[T](self: Context, value: T, position: int): Success =
  107 + newSuccess(self.buffer, position, value)
  108 +
  109 +method success*[T](self: Context, value: T): Success =
  110 + self.success(value, self.position)
  111 +
  112 +method failure*(self: Context, message: string, position: int): Failure =
  113 + newFailure(self.buffer, position, message)
  114 +
  115 +method failure*(self: Context, message: string): Failure =
  116 + self.failure(message, self.position)
  117 +
  118 +
  119 +method isSuccess*(self: Result): bool =
  120 + false
  121 +
  122 +method isFailure*(self: Result): bool =
  123 + false
  124 +
  125 +# An abstract method, hmmm, which you can't really do
  126 +# in nim. Normally I would like to throw exception here,
  127 +# but we need to return a T for compiler to be happy...
  128 +method get*[T](self: Result): T =
  129 + discard result
  130 + # Dirty trick to make compiler realize I return a T
  131 + # T(self)
  132 +
  133 +method get*[T](self: Failure): T =
  134 + raise newParseError(self)
  135 +
  136 +method get*[T](self: Success): T =
  137 + self.result
  138 +
  139 +
  140 +method getMessage*(self: Failure): string =
  141 + self.message
  142 +
  143 +method isSuccess*(self: Success): bool =
  144 + true
  145 +
  146 +method name*(self: Result): string =
  147 + "Result"
  148 +
  149 +method name*(self: Success): string =
  150 + "Success"
  151 +
  152 +method name*(self: Failure): string =
  153 + "Failure"
  154 +
  155 +
  156 +method `$`*(self: Result): string =
  157 + let (line, col) = findLineAndColumn(self.buffer, self.position)
  158 + self.name & "[" & $line & ":" & $col & "]"
  159 +
  160 +
  161 +method `$`*(self: Success): string =
  162 + procCall($(Result(self))) & ": " & repr(self.result)
  163 +
  164 +
  165 +method isFailure*(self: Failure): bool =
  166 + true
  167 +
  168 +method `$`*(self: Failure): string =
  169 + procCall($(Result(self))) & ": " & self.message
  170 +
  171 +# The simplest form of unit tests
  172 +#when isMainModule:
  173 +
... ...
context2.nim 0 → 100644
  1 +++ a/context2.nim
  1 +import hashes
  2 +
  3 +# Converts the position index in a buffer to a line and column tuple.
  4 +# This code is an adaptation of splitLines.
  5 +proc findLineAndColumn(s: string, position: int): tuple[line, col: int] =
  6 + var first = 0
  7 + var last = 0
  8 + var line = 0
  9 + while true:
  10 + while s[last] notin {'\0', '\c', '\l'}: inc(last)
  11 + # First line found
  12 + inc(line)
  13 + if last > position:
  14 + let col = position - first
  15 + return (line, col)
  16 + # skip newlines:
  17 + if s[last] == '\l': inc(last)
  18 + elif s[last] == '\c':
  19 + inc(last)
  20 + if s[last] == '\l': inc(last)
  21 + else: break # was '\0'
  22 + first = last
  23 +
  24 +type
  25 + ContextKind = enum ckContext, ckSuccess, ckFailure
  26 +
  27 +# Context
  28 +type
  29 + Context* = object
  30 + buffer*: string
  31 + position*: int
  32 + case kind: ContextKind
  33 + of ckContext:
  34 + nil
  35 + of ckSuccess:
  36 + value*: RootRef
  37 + of ckFailure:
  38 + message*: string
  39 +
  40 +
  41 +type Success = distinct Context
  42 +type Failure = distinct Context
  43 +
  44 +proc newContext*(buffer: string, position: int): Context =
  45 + Context(kind: ckContext, buffer: buffer, position: position)
  46 +
  47 +proc newSuccess*(buffer: string, position: int, value: RootRef): Success =
  48 + Success(Context(kind: ckSuccess, buffer: buffer, position: position, value: value))
  49 +
  50 +proc newFailure*(buffer: string, position: int, message: string): Failure =
  51 + Failure(Context(kind: ckFailure, buffer: buffer, position: position, message: message))
  52 +
  53 +# ParseError Exception
  54 +type
  55 + ParseError* = object of Exception
  56 + failure*: Failure
  57 +
  58 +proc newParseError*(failure: Failure): ref ParseError =
  59 + new(result)
  60 + result.failure = failure
  61 + result.msg = failure.message
  62 +
  63 +# Token
  64 +type
  65 + Token* = ref object of RootObj
  66 + buffer*: string
  67 + start*: int
  68 + stop*: int
  69 + value*: RootRef
  70 +
  71 +proc newToken*(buffer: string, start, stop: int, value: RootRef): Token =
  72 + Token(buffer: buffer, start: start, stop: stop, value: value)
  73 +
  74 +method getInput*(self: Token): string =
  75 + self.buffer.substr(self.start, self.stop)
  76 +
  77 +method getLength*(self: Token): int =
  78 + self.stop - self.stop
  79 +
  80 +method getLine*(self: Token): int =
  81 + self.buffer.findLineAndColumn(self.start)[0]
  82 +
  83 +method getColumn*(self: Token): int =
  84 + self.buffer.findLineAndColumn(self.start)[1]
  85 +
  86 +method `$`*(self: Token): string =
  87 + let (line, col) = findLineAndColumn(self.buffer, self.start);
  88 + "Token[" & $line & ":" & $col & "]: " & repr(self.value) # $self.value
  89 +
  90 +method hash*(self: Token): THash =
  91 + result = self.buffer.hash !& self.start.hash !& self.stop.hash #!& self.value.hash
  92 + result = !$result
  93 +
  94 +# We do not need to redefine ==, the generic one works fine.
  95 +# But let's see if we can
  96 +#method `==`(self, other: Token): bool =
  97 +# if (addr(self) == addr(other)):
  98 +# return true
  99 +# if other.isNil or self.isNil:
  100 +# return false
  101 +# self[] == other[]
  102 +
  103 +
  104 +method success[T]*(self: Context, value: T, position: int): Success =
  105 + newSuccess[T](self.buffer, position, value)
  106 +
  107 +method success[T]*(self: Context, value: T): Success =
  108 + self.success[T](value, self.position)
  109 +
  110 +method failure*(self: Context, message: string, position: int): Failure =
  111 + newFailure(self.buffer, position, message)
  112 +
  113 +method failure*(self: Context, message: string): Failure =
  114 + self.failure(message, self.position)
  115 +
  116 +
  117 +method isSuccess*(self: Context): bool =
  118 + false
  119 +
  120 +method isFailure*(self: Context): bool =
  121 + false
  122 +
  123 +# An abstract method, hmmm, which you can't really do
  124 +# in nim. Normally I would like to throw exception here,
  125 +# but we need to return a T for compiler to be happy...
  126 +method get*(self: Result): =
  127 + discard result
  128 + # Dirty trick to make compiler realize I return a T
  129 + # T(self)
  130 +
  131 +method get*(self: Failure): RootRef =
  132 + raise newParseError(self)
  133 +
  134 +method get*(self: Success): RootRef =
  135 + self.result
  136 +
  137 +
  138 +method getMessage*(self: Failure): string =
  139 + self.message
  140 +
  141 +method isSuccess*(self: Success): bool =
  142 + true
  143 +
  144 +method `$`*(self: Result): string =
  145 + let (line, col) = findLineAndColumn(self.buffer, self.position)
  146 + self.name & "[" & $line & ":" & $col & "]"
  147 +
  148 +
  149 +method `$`*(self: Success): string =
  150 + procCall($(Result(self))) & ": " & repr(self.result)
  151 +
  152 +
  153 +method isFailure*(self: Failure): bool =
  154 + true
  155 +
  156 +method `$`*(self: Failure): string =
  157 + procCall($(Result(self))) & ": " & self.message
  158 +
  159 +# The simplest form of unit tests
  160 +#when isMainModule:
  161 +
... ...
functions.nim 0 → 100644
  1 +++ a/functions.nim
  1 +import sequtils
  2 +
  3 +proc firstOfList*[T](): proc(list: seq[T]): T =
  4 + # Returns a function that returns the first value of a seq.
  5 + result = proc (list: seq[T]): T = list[0]
  6 +
  7 +assert(firstOfList[int]()(@[1, 2]) == 1)
  8 +
  9 +# public static <T> Function<List<T>, T> firstOfList() {
  10 +# return (list) -> list.get(0);
  11 +# }
  12 +
  13 +proc lastOfList*[T](): proc(list: seq[T]): T =
  14 + # Returns a function that returns the last value of a seq.
  15 + result = proc (list: seq[T]): T = list[high(list)]
  16 +
  17 +assert(lastOfList[int]()(@[1, 2]) == 2)
  18 +
  19 +# public static <T> Function<List<T>, T> lastOfList() {
  20 +# return (list) -> list.get(list.size() - 1);
  21 +# }
  22 +
  23 +proc nthOfList*[T](index: int): proc(list: seq[T]): T =
  24 + ## Returns a function that returns the value at the given index. Negative indexes are counted from
  25 + ## the end of the list.
  26 + result = proc (list: seq[T]): T =
  27 + if index < 0:
  28 + result = list[list.len + index]
  29 + else:
  30 + result = list[index]
  31 +
  32 +assert(nthOfList[int](1)(@[1, 2]) == 2)
  33 +assert(nthOfList[int](-1)(@[1, 2]) == 2)
  34 +assert(nthOfList[int](-2)(@[1, 2]) == 1)
  35 +
  36 +# public static <T> Function<List<T>, T> nthOfList(int index) {
  37 +# return (list) -> list.get(index < 0 ? list.size() + index : index);
  38 +# }
  39 +
  40 +proc permutationOfList*[T](indexes: varargs[int]): proc(list: seq[T]): seq[T] =
  41 + ## Returns a function that returns the permutation of a given list. Negative indexes are counted
  42 + ## from the end of the list.
  43 + let inds = @indexes # Copying varargs (an array) to a seq so that the proc below can capture it
  44 + result = proc (list: seq[T]): seq[T] =
  45 + newSeq(result, 0)
  46 + for index in inds:
  47 + if index < 0:
  48 + result.add(list[list.len + index])
  49 + else:
  50 + result.add(list[index])
  51 +
  52 +assert(permutationOfList[int](1,0)(@[1, 2]) == @[2, 1])
  53 +assert(permutationOfList[int](0,1)(@[1, 2]) == @[1, 2])
  54 +
  55 +# public static <T> Function<List<T>, List<T>> permutationOfList(int... indexes) {
  56 +# return (list) -> {
  57 +# List<T> result = new ArrayList<>(indexes.length);
  58 +# for (int index : indexes) {
  59 +# result.add(list.get(index < 0 ? list.size() + index : index));
  60 +# }
  61 +# return result;
  62 +# };
  63 +# }
  64 +
  65 +proc withoutSeparators*[T](): proc(list: seq[T]): seq[T] =
  66 + ## Returns a function that skips the separators of a given list.
  67 + result = proc (list: seq[T]): seq[T] =
  68 + newSeq(result, 0)
  69 + for i in countup(0, high(list), 2):
  70 + result.add(list[i])
  71 +
  72 +# public static <T> Function<List<T>, List<T>> withoutSeparators() {
  73 +# return (list) -> {
  74 +# List<T> result = new ArrayList<>();
  75 +# for (int i = 0; i < list.size(); i += 2) {
  76 +# result.add(list.get(i));
  77 +# }
  78 +# return result;
  79 +# };
  80 +# }
  81 +
  82 +proc constant*[T,A](output: T): proc(input: A): T =
  83 + ## Returns a function that returns a constant value.
  84 + result = proc (input: A): T = output
  85 +
  86 +# public static <T> Function<Object, T> constant(T output) {
  87 +# return (input) -> output;
  88 +# }
  89 +
  90 +
  91 +assert(constant[string, string]("hey")("hy") == "hey")
... ...
parser.nim 0 → 100644
  1 +++ a/parser.nim
  1 +# Parser
  2 +type
  3 + Parser* = ref object of RootObj
... ...
petitparser.nim 0 → 100644
  1 +++ a/petitparser.nim
  1 +import context, functions
  2 +
  3 +# Parser
  4 +type
  5 + Parser* = ref object of RootObj
  6 +
  7 +
  8 +method parseOn*(self: Parser, context: Context): Result =
  9 + raise newException(Exception, "should be implemented by subclass")
  10 +
  11 +method parse*(self: Parser, input: string): Result =
  12 + self.parseOn(newContext(input, 0))
  13 +
  14 +method accept*(self: Parser, input: string): bool =
  15 + self.parse(input).isSuccess
  16 +
  17 +method matches*[T](self: Parser, input: string): seq[T] =
  18 + result = @[]
  19 + self.andd.map(result.add).seq(any).orr(any).star.parse(input)
  20 +
  21 +method getChildren*(self: Parser): seq[Parser] =
  22 + @[]
  23 +
  24 +method hasEqualProperties*(self, other: Parser): bool =
  25 + true
  26 +
  27 +method replace*(self, source, target: Parser) =
  28 + # no referring parsers
  29 + discard
  30 +
  31 +method name*(self: Parser): string =
  32 + "Parser"
  33 +
  34 +method `$`*(self: Parser): string =
  35 + self.name
  36 +
  37 +# public String toString() {
  38 +# return getClass().getSimpleName();
  39 +# }
  40 +
  41 +
  42 +# DelegateParser
  43 +type
  44 + DelegateParser* = ref object of Parser
  45 + delegate*: Parser
  46 +
  47 +proc newDelegateParser*(delegate: Parser): DelegateParser =
  48 + DelegateParser(delegate: delegate)
  49 +
  50 +method parseOn*(self: DelegateParser, context: Context): Result =
  51 + self.delegate.parseOn(context)
  52 +
  53 +method replace*(self: DelegateParser, source, target: Parser) =
  54 + procCall(Parser(self).replace(source, target))
  55 + if self.delegate == source:
  56 + self.delegate = target
  57 +
  58 +method getChildren(self: DelegateParser): seq[Parser] =
  59 + @[self.delegate]
  60 +
  61 +method copy(self: DelegateParser): Parser =
  62 + newDelegateParser(self.delegate)
  63 +
  64 +method name*(self: DelegateParser): string =
  65 + "DelegateParser"
  66 +
  67 +## A parser that optionally parsers its delegate, or answers nil.
  68 +type
  69 + OptionalParser*[T] = ref object of DelegateParser
  70 + otherwise*: T
  71 +
  72 +proc newOptionalParser*[T](delegate: Parser, otherwise: T): OptionalParser =
  73 + OptionalParser(delegate: delegate, otherwise: otherwise)
  74 +
  75 +# public OptionalParser(Parser delegate, Object otherwise) {
  76 +# super(delegate);
  77 +# this.otherwise = otherwise;
  78 +# }
  79 +
  80 +method parseOn*(self: OptionalParser, context: Context): Result =
  81 + result = self.delegate.parseOn(context)
  82 + if result.isSuccess:
  83 + return
  84 + return context.success(self.otherwise)
  85 +
  86 +
  87 +# public Result parseOn(Context context) {
  88 +# Result result = delegate.parseOn(context);
  89 +# if (result.isSuccess()) {
  90 +# return result;
  91 +# } else {
  92 +# return context.success(otherwise);
  93 +# }
  94 +# }
  95 +
  96 +method hasEqualProperties*(self: OptionalParser, other: OptionalParser): bool =
  97 + procCall(Parser(self).hasEqualProperties(Parser(other))) and self.otherwise == other.otherwise
  98 +
  99 +# protected boolean hasEqualProperties(Parser other) {
  100 +# return super.hasEqualProperties(other) &&
  101 +# Objects.equals(otherwise, ((OptionalParser) other).otherwise);
  102 +# }
  103 +
  104 +method copy*(self: OptionalParser): Parser =
  105 + newOptionalParser(self.delegate, self.otherwise)
  106 +
  107 +# @Override
  108 +# public Parser copy() {
  109 +# return new OptionalParser(delegate, otherwise);
  110 +# }
  111 +
  112 +method name*(self: OptionalParser): string =
  113 + "OptionalParser"
  114 +
  115 +# An abstract parser that repeatedly parses between 'min' and 'max' instances of its delegate.
  116 +type
  117 + RepeatingParser* = ref object of DelegateParser
  118 + min*: int
  119 + max*: int
  120 +
  121 +const UNBOUNDED = 1
  122 +
  123 +proc newRepeatingParser*(delegate: Parser, min: int, max: int): RepeatingParser =
  124 + if min < 0:
  125 + raise newException(Exception, "Invalid min repetitions")
  126 + if max != UNBOUNDED and min > max:
  127 + raise newException(Exception, "Invalid max repetitions")
  128 + RepeatingParser(delegate: delegate, min: min, max: max)
  129 +
  130 +method hasEqualProperties*(self: RepeatingParser, other: RepeatingParser): bool =
  131 + # No super implementation in DelegateParser
  132 + procCall(Parser(self).hasEqualProperties(Parser(other))) and self.min == other.min and self.max == other.max
  133 +
  134 +method name*(self: RepeatingParser): string =
  135 + "RepeatingParser"
  136 +
  137 +method `$`*(self: RepeatingParser): string =
  138 + result = procCall($Parser(self)) & "[" & $self.min & ".."
  139 + if self.max == UNBOUNDED:
  140 + result = result & "*]"
  141 + else:
  142 + result = result & $self.max & "]"
  143 +
  144 +# public String toString() {
  145 +# return super.toString() + "[" + min + ".." + (max == UNBOUNDED ? "*" : max) + "]";
  146 +# }
  147 +
  148 +# A greedy parser that repeatedly parses between 'min' and 'max' instances of its delegate.
  149 +type
  150 + PossessiveRepeatingParser = ref object of RepeatingParser
  151 +
  152 +proc newPossessiveRepeatingParser*(delegate: Parser, min, max: int): PossessiveRepeatingParser =
  153 + PossessiveRepeatingParser(newRepeatingParser(delegate, min, max))
  154 +
  155 +method name*(self: PossessiveRepeatingParser): string =
  156 + "PossessiveRepeatingParser"
  157 +
  158 +
  159 +method copy*(self: PossessiveRepeatingParser): Parser =
  160 + newPossessiveRepeatingParser(self.delegate, self.min, self.max)
  161 +
  162 +method parseOn*[T](self: PossessiveRepeatingParser, context: Context): Result =
  163 + var
  164 + current = context
  165 + elements = newSeq[T]()
  166 + while elements.len < self.min:
  167 + result = self.delegate.parseOn(current)
  168 + if result.isFailure:
  169 + return
  170 + elements.add(get[T](result))
  171 + current = result
  172 + while self.max == UNBOUNDED or elements.len < max:
  173 + result = self.delegate.parseOn(current)
  174 + if result.isFailure:
  175 + return current.success[T](elements)
  176 + elements.add(get[T](result))
  177 + current = result
  178 + current.success[T](elements)
  179 +
  180 +
  181 +# Abstract parser that parses a list of things in some way (to be specified by the subclasses).
  182 +type
  183 + ListParser* = ref object of Parser
  184 + parsers*: seq[Parser]
  185 +
  186 +#proc newListParser*(parsers: seq[Parser] not nil): ListParser =
  187 +# ListParser(parsers: parsers)
  188 +
  189 +method replace*(self: ListParser, source, target: Parser) =
  190 + procCall(Parser(self).replace(source, target))
  191 + for i in 0..high(self.parsers):
  192 + if self.parsers[i] == source:
  193 + self.parsers[i] = target
  194 +
  195 +# public void replace(Parser source, Parser target) {
  196 +# super.replace(source, target);
  197 +# for (int i = 0; i < parsers.length; i++) {
  198 +# if (parsers[i] == source) {
  199 +# parsers[i] = target;
  200 +# }
  201 +# }
  202 +# }
  203 +
  204 +method getChildren(self: ListParser): seq[Parser] =
  205 + self.parsers
  206 +
  207 +# public List<Parser> getChildren() {
  208 +# return Arrays.asList(parsers);
  209 +# }
  210 +
  211 +
  212 +method name*(self: ListParser): string =
  213 + "ListParser"
  214 +
  215 +
  216 +# A parser that parses a sequence of parsers.
  217 +type
  218 + SequenceParser* = ref object of ListParser
  219 +
  220 +proc newSequenceParser*(parsers: seq[Parser]): SequenceParser =
  221 + SequenceParser(parsers: parsers)
  222 +
  223 +method parseOn*[T](self: SequenceParser, context: Context): Result =
  224 + var
  225 + current = context
  226 + elements = newSeq[T](self.parsers.len)
  227 + for parser in self.parsers:
  228 + result = parser.parseOn(current)
  229 + if result.isFailure:
  230 + return
  231 + elements.add(get[T](result))
  232 + current = result
  233 + current.success[T](elements)
  234 +
  235 +# public Result parseOn(Context context) {
  236 +# Context current = context;
  237 +# List<Object> elements = new ArrayList<>(parsers.length);
  238 +# for (Parser parser : parsers) {
  239 +# Result result = parser.parseOn(current);
  240 +# if (result.isFailure()) {
  241 +# return result;
  242 +# }
  243 +# elements.add(result.get());
  244 +# current = result;
  245 +# }
  246 +# return current.success(elements);
  247 +# }
  248 +
  249 +method seq*(self: SequenceParser, others: varargs[Parser]): Parser =
  250 + newSequenceParser(self.parsers & @others)
  251 +# let all = newSeq[Parser](self.parsers.len + others.len)
  252 +
  253 +# public Parser seq(Parser... others) {
  254 +# Parser[] array = Arrays.copyOf(parsers, parsers.length + others.length);
  255 +# System.arraycopy(others, 0, array, parsers.length, others.length);
  256 +# return new SequenceParser(array);
  257 +# }
  258 +
  259 +method copy*(self: SequenceParser): Parser =
  260 + var parsersCopy = self.parsers
  261 + newSequenceParser(parsersCopy)
  262 +
  263 +
  264 +# public Parser copy() {
  265 +# return new SequenceParser(Arrays.copyOf(parsers, parsers.length));
  266 +# }
  267 +
  268 +method name*(self: SequenceParser): string =
  269 + "SequenceParser"
  270 +
  271 +# An abstract parser that repeatedly parses between 'min' and 'max' instances of its delegate and
  272 +# that requires the input to be completed with a specified parser 'limit'. Subclasses provide
  273 +# repeating behavior as typically seen in regular expression implementations (non-blind).
  274 +type
  275 + LimitedRepeatingParser* = ref object of RepeatingParser
  276 + limit*: Parser
  277 +
  278 +proc newLimitedRepeatingParser*(delegate: Parser, limit: Parser not nil, min, max: int): LimitedRepeatingParser =
  279 + LimitedRepeatingParser(delegate: delegate, limit: limit, min: min, max: max)
  280 +
  281 +method getChildren(self: LimitedRepeatingParser): seq[Parser] =
  282 + @[self.delegate, self.limit]
  283 +
  284 +method replace*(self: LimitedRepeatingParser, source, target: Parser) =
  285 + procCall(DelegateParser(self).replace(source, target))
  286 + if self.limit == source:
  287 + self.limit = target
  288 +
  289 +method name*(self: LimitedRepeatingParser): string =
  290 + "LimitedRepeatingParser"
  291 +
  292 +
  293 +# A greedy repeating parser, commonly seen in regular expression implementations. It aggressively
  294 +# consumes as much input as possible and then backtracks to meet the 'limit' condition.
  295 +type
  296 + GreedyRepeatingParser* = ref object of LimitedRepeatingParser
  297 +
  298 +proc newGreedyRepeatingParser*(delegate, limit: Parser, min, max: int): GreedyRepeatingParser =
  299 + GreedyRepeatingParser(delegate: delegate, limit: limit, min: min, max: max)
  300 +
  301 +method copy*(self: GreedyRepeatingParser): Parser =
  302 + newGreedyRepeatingParser(self.delegate, self.limit, self.min, self.max)
  303 +
  304 +#method parseOn*[T](self: GreedyRepeatingParser, context: Context): Result =
  305 +# result = self.delegate.parseOn(context)
  306 +# if result.isSuccess:
  307 +# return context.success(get[T](result))
  308 +
  309 +method parseOn*[T](self: GreedyRepeatingParser, context: Context): Result =
  310 + var
  311 + current = context
  312 + elements = newSeq[T]()
  313 + while elements.len < self.min:
  314 + result = self.delegate.parseOn(current)
  315 + if result.isFailure:
  316 + return
  317 + elements.add(get[T](result))
  318 + current = result
  319 + var contexts = newSeq[Context]()
  320 + contexts.add(current)
  321 + while self.max == UNBOUNDED or elements.len < max:
  322 + result = self.delegate.parseOn(current)
  323 + if result.isFailure:
  324 + break
  325 + elements.add(get[T](result))
  326 + contexts.add(current = result)
  327 + while true:
  328 + var stop = self.limit.parseOn(contexts[contexts.high])
  329 + if stop.isSuccess:
  330 + return contexts[contexts.high].success(elements)
  331 + if elements.len == 0:
  332 + return stop
  333 + contexts.pop()
  334 + elements.pop()
  335 + if contexts.len == 0:
  336 + return stop
  337 +
  338 +
  339 +discard """
  340 +
  341 + public Result parseOn(Context context) {
  342 + Context current = context;
  343 + List<Object> elements = new ArrayList<>();
  344 + while (elements.size() < min) {
  345 + Result result = delegate.parseOn(current);
  346 + if (result.isFailure()) {
  347 + return result;
  348 + }
  349 + elements.add(result.get());
  350 + current = result;
  351 + }
  352 + List<Context> contexts = new ArrayList<>();
  353 + contexts.add(current);
  354 + while (max == UNBOUNDED || elements.size() < max) {
  355 + Result result = delegate.parseOn(current);
  356 + if (result.isFailure()) {
  357 + break;
  358 + }
  359 + elements.add(result.get());
  360 + contexts.add(current = result);
  361 + }
  362 + while (true) {
  363 + Result stop = limit.parseOn(contexts.get(contexts.size() - 1));
  364 + if (stop.isSuccess()) {
  365 + return contexts.get(contexts.size() - 1).success(elements);
  366 + }
  367 + if (elements.isEmpty()) {
  368 + return stop;
  369 + }
  370 + contexts.remove(contexts.size() - 1);
  371 + elements.remove(elements.size() - 1);
  372 + if (contexts.isEmpty()) {
  373 + return stop;
  374 + }
  375 + }
  376 + }
  377 +
  378 +}
  379 +"""
  380 +
  381 +# A parser that uses the first parser that succeeds.
  382 +type
  383 + ChoiceParser* = ref object of ListParser
  384 +
  385 +proc newChoiceParser*(parsers: varargs[Parser]): ChoiceParser =
  386 + ChoiceParser(parsers: @parsers)
  387 +
  388 +method orr*(self: ChoiceParser, others: varargs[Parser]): Parser =
  389 + ## Returns a parser that accepts the receiver or `other`. The resulting parser returns the
  390 + ## parse result of the receiver, if the receiver fails it returns the parse result of `other`
  391 + ## (exclusive ordered choice).
  392 + newChoiceParser(self.parsers & @others)
  393 +
  394 +method copy*(self: ChoiceParser): Parser =
  395 + let parsersCopy = self.parsers
  396 + newChoiceParser(parsersCopy)
  397 +
  398 +method parseOn*(self: ChoiceParser, context: Context): Result =
  399 + for parser in self.parsers:
  400 + result = parser.parseOn(context)
  401 + if result.isSuccess:
  402 + return
  403 +
  404 +# public Result parseOn(Context context) {
  405 +# Result result = null;
  406 +# for (Parser parser : parsers) {
  407 +# result = parser.parseOn(context);
  408 +# if (result.isSuccess()) {
  409 +# return result;
  410 +# }
  411 +# }
  412 +# return result;
  413 +# }
  414 +
  415 +# The and-predicate, a parser that succeeds whenever its delegate does, but does not consume the
  416 +# input stream [Parr 1994, 1995].
  417 +type
  418 + AndParser* = ref object of DelegateParser
  419 +
  420 +proc newAndParser*(delegate: Parser): AndParser =
  421 + AndParser(delegate)
  422 +
  423 +method parseOn*[T](self: AndParser, context: Context): Result =
  424 + result = self.delegate.parseOn(context)
  425 + if result.isSuccess:
  426 + return context.success(get[T](result))
  427 +
  428 +method copy*(self: AndParser): Parser =
  429 + newAndParser(self.delegate)
  430 +
  431 +# Testing a type class to match the Java interface
  432 +# This means, a ContinuationHandler is any type which
  433 +# you can call `apply` on, with the given arguments.
  434 +type
  435 + ContinuationHandler = generic handler
  436 + handler.callParseOn(Parser, Context) is Result
  437 + #handler.apply(proc(c: Context): Result, Context) is Result
  438 +
  439 +# Just a sample ContinuationHandler type
  440 +type
  441 + Sammy = ref object
  442 +proc callParseOn*(self: Sammy, p: Parser, c: Context): Result =
  443 + p.parseOn(c)
  444 +
  445 +# Continuation parser that when activated captures a continuation function and passes it together
  446 +# with the current context into the handler.
  447 +type
  448 + ContinuationParser*[T] = ref object of DelegateParser
  449 + handler*: T
  450 +
  451 +proc newContinuationParser*(delegate: Parser, handler: ContinuationHandler): ContinuationParser =
  452 + ContinuationParser(delegate: delegate, handler: handler)
  453 +
  454 +# TODO
  455 +method parseOn*(self: ContinuationParser, context: Context): Result =
  456 + self.handler.callParseOn(self, context)
  457 +
  458 +method copy*(self: ContinuationParser): Parser =
  459 + newContinuationParser(self.delegate, self.handler)
  460 +
  461 +method hasEqualProperties*(self: ContinuationParser, other: ContinuationParser): bool =
  462 + procCall(Parser(self).hasEqualProperties(Parser(other))) and self.handler == other.handler
  463 +
  464 +
  465 +
  466 +# The not-predicate, a parser that succeeds whenever its delegate does not, but consumes no input [Parr 1994, 1995].
  467 +type
  468 + NotParser* = ref object of DelegateParser
  469 + message*: string
  470 +
  471 +proc newNotParser*(delegate: Parser, message: string): NotParser =
  472 + NotParser(delegate: delegate, message: message)
  473 +
  474 +method parseOn*[T](self: NotParser, context: Context): Result =
  475 + if self.delegate.parseOn(context).isFailure:
  476 + return context.success(nil)
  477 + else:
  478 + return context.failure(self.message)
  479 +
  480 +method hasEqualProperties*(self: NotParser, other: NotParser): bool =
  481 + procCall(Parser(self).hasEqualProperties(Parser(other))) and self.message == other.message
  482 +
  483 +method copy*(self: NotParser): NotParser =
  484 + newNotParser(self.delegate, self.message)
  485 +
  486 +method `$`*(self: NotParser): string =
  487 + procCall($Parser(self)) & "[" & self.message & "]"
  488 +
  489 +
  490 +
  491 +
  492 +
  493 +# Parses a single character.
  494 +type
  495 + CharacterParser* = ref object of Parser
  496 +
  497 +proc newCharacterParser*(predicate: CharacterPredicate, message: string): Parser =
  498 + CharacterParser(predicate, message)
  499 +
  500 +proc off*(predicate: CharacterPredicate, message: string): Parser =
  501 + newCharacterParser(predicate, message)
  502 +
  503 +discard """
  504 + /**
  505 + * Returns a parser that accepts a specific {@link CharacterPredicate}.
  506 + */
  507 + public static Parser of(CharacterPredicate predicate, String message) {
  508 + return new CharacterParser(predicate, message);
  509 + }
  510 +
  511 + /**
  512 + * Returns a parser that accepts a specific {@code character}.
  513 + */
  514 + public static Parser of(char character) {
  515 + return of(character, "'" + character + "' expected");
  516 + }
  517 +
  518 + public static Parser of(char character, String message) {
  519 + return of(CharacterPredicate.of(character), message);
  520 + }
  521 +
  522 + /**
  523 + * Returns a parser that accepts any character.
  524 + */
  525 + public static Parser any() {
  526 + return any("any character expected");
  527 + }
  528 +
  529 + public static Parser any(String message) {
  530 + return of(CharacterPredicate.any(), message);
  531 + }
  532 +
  533 + /**
  534 + * Returns a parser that accepts any of the provided characters.
  535 + */
  536 + public static Parser anyOf(String chars) {
  537 + return anyOf(chars, "any of '" + chars + "' expected");
  538 + }
  539 +
  540 + public static Parser anyOf(String chars, String message) {
  541 + return of(CharacterPredicate.anyOf(chars), message);
  542 + }
  543 +
  544 + /**
  545 + * Returns a parser that accepts no character.
  546 + */
  547 + public static Parser none() {
  548 + return none("no character expected");
  549 + }
  550 +
  551 + public static Parser none(String message) {
  552 + return of(CharacterPredicate.none(), message);
  553 + }
  554 +
  555 + /**
  556 + * Returns a parser that accepts none of the provided characters.
  557 + */
  558 + public static Parser noneOf(String chars) {
  559 + return noneOf(chars, "none of '" + chars + "' expected");
  560 + }
  561 +
  562 + public static Parser noneOf(String chars, String message) {
  563 + return of(CharacterPredicate.noneOf(chars), message);
  564 + }
  565 +
  566 + /**
  567 + * Returns a parser that accepts a single digit.
  568 + */
  569 + public static Parser digit() {
  570 + return digit("digit expected");
  571 + }
  572 +
  573 + public static Parser digit(String message) {
  574 + return new CharacterParser(Character::isDigit, message);
  575 + }
  576 +
  577 + /**
  578 + * Returns a parser that accepts a single letter.
  579 + */
  580 + public static Parser letter() {
  581 + return letter("letter expected");
  582 + }
  583 +
  584 + public static Parser letter(String message) {
  585 + return of(Character::isLetter, message);
  586 + }
  587 +
  588 + /**
  589 + * Returns a parser that accepts an lower-case letter.
  590 + */
  591 + public static Parser lowerCase() {
  592 + return lowerCase("lowercase letter expected");
  593 + }
  594 +
  595 + public static Parser lowerCase(String message) {
  596 + return of(Character::isLowerCase, message);
  597 + }
  598 +
  599 + /**
  600 + * Returns a parser that accepts a specific character pattern.
  601 + * <p>
  602 + * Characters match themselves. A dash {@code -} between two characters matches the range of those
  603 + * characters. A caret {@code ^} at the beginning negates the pattern.
  604 + */
  605 + public static Parser pattern(String pattern) {
  606 + return pattern(pattern, "[" + pattern + "] expected");
  607 + }
  608 +
  609 + public static Parser pattern(String pattern, String message) {
  610 + return of(CharacterPredicate.pattern(pattern), message);
  611 + }
  612 +
  613 + /**
  614 + * Returns a parser that accepts a specific character range.
  615 + */
  616 + public static Parser range(char start, char stop) {
  617 + return range(start, stop, start + ".." + stop + " expected");
  618 + }
  619 +
  620 + public static Parser range(char start, char stop, String message) {
  621 + return of(CharacterPredicate.range(start, stop), message);
  622 + }
  623 +
  624 + /**
  625 + * Returns a parser that accepts an upper-case letter.
  626 + */
  627 + public static Parser upperCase() {
  628 + return upperCase("uppercase letter expected");
  629 + }
  630 +
  631 + public static Parser upperCase(String message) {
  632 + return of(Character::isUpperCase, message);
  633 + }
  634 +
  635 + /**
  636 + * Returns a parser that accepts a single whitespace.
  637 + */
  638 + public static Parser whitespace() {
  639 + return whitespace("whitespace expected");
  640 + }
  641 +
  642 + public static Parser whitespace(String message) {
  643 + return of(Character::isWhitespace, message);
  644 + }
  645 +
  646 + /**
  647 + * Returns a parser that accepts a single letter or digit.
  648 + */
  649 + public static Parser word() {
  650 + return word("letter or digit expected");
  651 + }
  652 +
  653 + public static Parser word(String message) {
  654 + return of(Character::isLetterOrDigit, message);
  655 + }
  656 +
  657 + private final CharacterPredicate matcher;
  658 + private final String message;
  659 +
  660 + private CharacterParser(CharacterPredicate matcher, String message) {
  661 + this.matcher = Objects.requireNonNull(matcher, "Undefined matcher");
  662 + this.message = Objects.requireNonNull(message, "Undefined message");
  663 + }
  664 +
  665 + @Override
  666 + public Result parseOn(Context context) {
  667 + String buffer = context.getBuffer();
  668 + int position = context.getPosition();
  669 + if (position < buffer.length()) {
  670 + char result = buffer.charAt(position);
  671 + if (matcher.test(result)) {
  672 + return context.success(result, position + 1);
  673 + }
  674 + }
  675 + return context.failure(message);
  676 + }
  677 +
  678 + @Override
  679 + public Parser neg(String message) {
  680 + return of(matcher.not(), message);
  681 + }
  682 +
  683 + @Override
  684 + protected boolean hasEqualProperties(Parser other) {
  685 + return super.hasEqualProperties(other) &&
  686 + Objects.equals(matcher, ((CharacterParser) other).matcher) &&
  687 + Objects.equals(message, ((CharacterParser) other).message);
  688 + }
  689 +
  690 + @Override
  691 + public Parser copy() {
  692 + return of(matcher, message);
  693 + }
  694 +
  695 + @Override
  696 + public String toString() {
  697 + return super.toString() + "[" + message + "]";
  698 + }
  699 +"""
  700 +
  701 +
  702 +
  703 +# /**
  704 +# * Returns a list of all successful overlapping parses of the {@code input}.
  705 +# */
  706 +# @SuppressWarnings("unchecked")
  707 +# public <T> List<T> matches(String input) {
  708 +# List<Object> list = new ArrayList<>();
  709 +# this.and().map(list::add).seq(any()).or(any()).star().parse(input);
  710 +# return (List<T>) list;
  711 +# }
  712 +
  713 +method matchesSkipping*[T](self: Parser, input: string): seq[T] =
  714 + result = @[]
  715 + self.map(result.add).`or`(any).star.parse(input)
  716 +
  717 +# /**
  718 +# * Returns a list of all successful non-overlapping parses of the {@code input}.
  719 +# */
  720 +# @SuppressWarnings("unchecked")
  721 +# public <T> List<T> matchesSkipping(String input) {
  722 +# List<Object> list = new ArrayList<>();
  723 +# this.map(list::add).or(any()).star().parse(input);
  724 +# return (List<T>) list;
  725 +# }
  726 +
  727 +
  728 +method repeat*(self: Parser, min, max: int): Parser =
  729 + ## Returns a parser that accepts the receiver between `min` and `max` times. The
  730 + ## resulting parser returns a list of the parse results of the receiver.
  731 + ##
  732 + ## This is a greedy and blind implementation that tries to consume as much input as possible and
  733 + ## that does not consider what comes afterwards.
  734 + newPossessiveRepeatingParser(self, min, max)
  735 +
  736 +# public Parser repeat(int min, int max) {
  737 +# return new PossessiveRepeatingParser(this, min, max);
  738 +# }
  739 +
  740 +
  741 +method optional*[T](self: Parser, otherwise: T): Parser =
  742 + ## Returns new parser that accepts the receiver, if possible.
  743 + ## The returned value can be provided as `otherwise`.
  744 + newOptionalParser(self, otherwise)
  745 +
  746 +# public Parser optional(Object otherwise) {
  747 +# return new OptionalParser(this, otherwise);
  748 +# }
  749 +
  750 +method optional*[T](self: Parser): Parser =
  751 + ## Returns new parser that accepts the receiver, if possible. The resulting parser returns the
  752 + ## result of the receiver, or `nil` if not applicable.
  753 + optional[T](self, nil)
  754 +
  755 +# public Parser optional() {
  756 +# return optional(null);
  757 +# }
  758 +
  759 +method start*(self: Parser): Parser =
  760 + ## Returns a parser that accepts the receiver zero or more times. The resulting parser returns a
  761 + ## list of the parse results of the receiver.
  762 + ##
  763 + ## This is a greedy and blind implementation that tries to consume as much input as possible and
  764 + ## that does not consider what comes afterwards.
  765 + self.repeat(0, UNBOUNDED)
  766 +
  767 +# public Parser star() {
  768 +# return repeat(0, RepeatingParser.UNBOUNDED);
  769 +# }
  770 +
  771 +# Forward dec
  772 +method repeatGreedy*(self, limit: Parser, min, max: int): Parser
  773 +
  774 +method starGreedy*(self, limit: Parser): Parser =
  775 + ## Returns a parser that parses the receiver zero or more times until it reaches a `limit`.
  776 + ## This is a greedy non-blind implementation of the `star <#star>`_ operator.
  777 + ## The `limit` is not consumed.
  778 + self.repeatGreedy(limit, 0, UNBOUNDED)
  779 +
  780 +# public Parser starGreedy(Parser limit) {
  781 +# return repeatGreedy(limit, 0, RepeatingParser.UNBOUNDED);
  782 +# }
  783 +method repeatLazy*(self, limit: Parser, min, max: int): Parser
  784 +method starLazy*(self, limit: Parser): Parser =
  785 + ## Returns a parser that parses the receiver zero or more times until it reaches a `limit`.
  786 + ## This is a lazy non-blind implementation of the `star <#star>`_ operator.
  787 + ## The `limit` is not consumed.
  788 + self.repeatLazy(limit, 0, UNBOUNDED)
  789 +
  790 +
  791 +# public Parser starLazy(Parser limit) {
  792 +# return repeatLazy(limit, 0, RepeatingParser.UNBOUNDED);
  793 +# }
  794 +
  795 +method plus*(self: Parser): Parser =
  796 + ## Returns a parser that accepts the receiver one or more times. The resulting parser returns a
  797 + ## list of the parse results of the receiver.
  798 + ##
  799 + ## This is a greedy and blind implementation that tries to consume as much input as possible and
  800 + ## that does not consider what comes afterwards.
  801 + self.repeat(1, UNBOUNDED)
  802 +
  803 +# public Parser plus() {
  804 +# return repeat(1, RepeatingParser.UNBOUNDED);
  805 +# }
  806 +
  807 +
  808 +method plusGreedy*(self, limit: Parser): Parser =
  809 + ## Returns a parser that parses the receiver one or more times until it reaches `limit`.
  810 + ## This is a reedy non-blind implementation of the `plus <#plus>`_ operator.
  811 + ## The `limit` is not consumed.
  812 + self.repeatGreedy(limit, 1, UNBOUNDED)
  813 +
  814 +# public Parser plusGreedy(Parser limit) {
  815 +# return repeatGreedy(limit, 1, RepeatingParser.UNBOUNDED);
  816 +# }
  817 +
  818 +
  819 +method plusLazy*(self, limit: Parser): Parser =
  820 + ## Returns a parser that parses the receiver one or more times until it reaches a `limit`.
  821 + ## This is a lazy non-blind implementation of the `plus <#plus>`_ operator.
  822 + ## The `limit` is not consumed.
  823 + self.repeatLazy(limit, 1, UNBOUNDED)
  824 +
  825 +
  826 +# public Parser plusLazy(Parser limit) {
  827 +# return repeatLazy(limit, 1, RepeatingParser.UNBOUNDED);
  828 +# }
  829 +
  830 +
  831 +method repeatGreedy*(self, limit: Parser, min, max: int): Parser =
  832 + ## Returns a parser that parses the receiver at least `min` and at most `max` times
  833 + ## until it reaches a {@code limit}. This is a greedy non-blind implementation of the
  834 + ## `repeat <#repeat>`_ operator. The `limit` is not consumed.
  835 + newGreedyRepeatingParser(self, limit, min, max)
  836 +
  837 +# public Parser repeatGreedy(Parser limit, int min, int max) {
  838 +# return new GreedyRepeatingParser(this, limit, min, max);
  839 +# }
  840 +
  841 +
  842 +method repeatLazy*(self, limit: Parser, min, max: int): Parser =
  843 + ## Returns a parser that parses the receiver at least `min` and at most `max` times
  844 + ## until it reaches a `limit`. This is a lazy non-blind implementation of the
  845 + ## `repeat <#repeat>`_ operator. The `limit` is not consumed.
  846 + newGreedyRepeatingParser(self, limit, min, max)
  847 +
  848 +# public Parser repeatLazy(Parser limit, int min, int max) {
  849 +# return new LazyRepeatingParser(this, limit, min, max);
  850 +# }
  851 +
  852 +method times*(self: Parser, count: int): Parser =
  853 + ## Returns a parser that accepts the receiver exactly `count` times.
  854 + ## The resulting parser returns a list of the parse results of the receiver.
  855 + self.repeat(count, count)
  856 +
  857 +# public Parser times(int count) {
  858 +# return repeat(count, count);
  859 +# }
  860 +
  861 +
  862 +method seq*(self: Parser, others: varargs[Parser]): Parser =
  863 + ## Returns a parser that accepts the receiver followed by `others`. The resulting parser
  864 + ## returns a list of the parse result of the receiver followed by the parse result of `others`.
  865 + ## Calling this method on an existing sequence code not nest this sequence into a new one,
  866 + ## but instead augments the existing sequence with `others`.
  867 +
  868 + # Alternative low level version of addFirst
  869 + #var s = newSeq[Parser](others.len + 1)
  870 + #s[0] = self
  871 + #var j = 1
  872 + #for p in others:
  873 + # s[j] = p
  874 + # inc(j)
  875 + #newSequenceParser(s)
  876 +
  877 + # Quick version of addFirst
  878 + newSequenceParser(@[self] & @others)
  879 +
  880 +# public Parser seq(Parser... others) {
  881 +# Parser[] parsers = new Parser[1 + others.length];
  882 +# parsers[0] = this;
  883 +# System.arraycopy(others, 0, parsers, 1, others.length);
  884 +# return new SequenceParser(parsers);
  885 +# }
  886 +
  887 +method orr*(self: Parser, others: varargs[Parser]): Parser =
  888 + ## Returns a parser that accepts the receiver or `other`. The resulting parser returns the
  889 + ## parse result of the receiver, if the receiver fails it returns the parse result of `other`
  890 + ## (exclusive ordered choice).
  891 + newChoiceParser(@[self] & @others)
  892 +
  893 +# public Parser or(Parser... others) {
  894 +# Parser[] parsers = new Parser[1 + others.length];
  895 +# parsers[0] = this;
  896 +# System.arraycopy(others, 0, parsers, 1, others.length);
  897 +# return new ChoiceParser(parsers);
  898 +# }
  899 +
  900 +method andd*(self: Parser): Parser =
  901 + ## Returns a parser (logical and-predicate) that succeeds whenever the receiver does, but never
  902 + ## consumes input.
  903 + newAndParser(self)
  904 +
  905 +# public Parser and() {
  906 +# return new AndParser(this);
  907 +# }
  908 +
  909 +method callCC*(self: Parser, handler: ContinuationHandler): Parser =
  910 + ## Returns a parser that is called with its current continuation.
  911 + newContinuationParser(self, handler)
  912 +
  913 +# public Parser callCC(ContinuationParser.ContinuationHandler handler) {
  914 +# return new ContinuationParser(this, handler);
  915 +# }
  916 +
  917 +method nott*(self: Parser): Parser =
  918 + ## Returns a parser (logical not-predicate) that succeeds whenever the receiver fails, but never
  919 + ## consumes input.
  920 + raise newException(Exception, "unexpected call to nott")
  921 +
  922 +# public Parser not() {
  923 +# return not("unexpected");
  924 +# }
  925 +
  926 +method nott*(self: Parser, message: string): Parser =
  927 + ## Returns a parser (logical not-predicate) that succeeds whenever the receiver fails, but never
  928 + ## consumes input.
  929 + newNotParser(self, message)
  930 +
  931 +# public Parser not(String message) {
  932 +# return new NotParser(this, message);
  933 +# }
  934 +
  935 +method neg*(self: Parser, message: string): Parser =
  936 + ## Returns a parser that consumes any input token (character), but the receiver.
  937 + self.nott(message).seq(CharacterParser.any()).pick(1)
  938 +
  939 +# public Parser neg(String message) {
  940 +# return not(message).seq(CharacterParser.any()).pick(1);
  941 +# }
  942 +
  943 +method neg*(self: Parser): Parser =
  944 + ## Returns a parser that consumes any input token (character), but the receiver.
  945 + self.neg($self & " not expected")
  946 +
  947 +# public Parser neg() {
  948 +# return neg(this + " not expected");
  949 +# }
  950 +
  951 +method flatten*(self: Parser): Parser =
  952 + ## Returns a parser that discards the result of the receiver, and returns a sub-string of the
  953 + ## consumed range in the string/list being parsed.
  954 + newFlattenParser(self)
  955 +
  956 +# public Parser flatten() {
  957 +# return new FlattenParser(this);
  958 +# }
  959 +
  960 +method token*(self: Parser): Parser =
  961 + ## Returns a parser that returns a {@link Token}. The token carries the parsed value of the
  962 + ## receiver {@link Token#getValue()}, as well as the consumed input {@link Token#getInput()} from
  963 + ## {@link Token#getStart()} to {@link Token#getStop()} of the input being parsed.
  964 + newTokenParser(self)
  965 +
  966 +# public Parser token() {
  967 +# return new TokenParser(this);
  968 +# }
  969 +
  970 +method trim*(self: Parser): Parser =
  971 + ## Returns a parser that consumes whitespace before and after the receiver.
  972 + self.trim(CharacterParser.whitespace())
  973 +
  974 +# public Parser trim() {
  975 +# return trim(CharacterParser.whitespace());
  976 +# }
  977 +
  978 +method trim*(self: Parser, both: Parser): Parser =
  979 + ## Returns a parser that consumes input on `both` sides of the receiver.
  980 + self.trim(both, both)
  981 +
  982 +# public Parser trim(Parser both) {
  983 +# return trim(both, both);
  984 +# }
  985 +
  986 +method trim*(self, before, after: Parser): Parser =
  987 + ## Returns a parser that consumes input {@code before} and {@code after} the receiver.
  988 + newTrimmingParser(self, before, after)
  989 +
  990 +# public Parser trim(Parser before, Parser after) {
  991 +# return new TrimmingParser(this, before, after);
  992 +# }
  993 +
  994 +method endd*(self: Parser): Parser =
  995 + ## Returns a parser that succeeds only if the receiver consumes the complete input.
  996 + self.endd("end of input expected")
  997 +
  998 +# public Parser end() {
  999 +# return end("end of input expected");
  1000 +# }
  1001 +
  1002 +method endd*(self: Parser, message: string): Parser =
  1003 + ## Returns a parser that succeeds only if the receiver consumes the complete input, otherwise
  1004 + ## return a failure with the {@code message}.
  1005 + newEndOfInputParser(self, message)
  1006 +
  1007 +# public Parser end(String message) {
  1008 +# return new EndOfInputParser(this, message);
  1009 +# }
  1010 +
  1011 +method settable*(self: Parser): SettableParser =
  1012 + ## Returns a parser that points to the receiver, but can be changed to point to something else at
  1013 + ## a later point in time.
  1014 + newSettableParserWith(self)
  1015 +
  1016 +# public SettableParser settable() {
  1017 +# return SettableParser.with(this);
  1018 +# }
  1019 +
  1020 +method map*[A, B](self: Parser, function: proc (x: A): B {.closure.}): Parser =
  1021 + ## Returns a parser that evaluates a {@code function} as the production action on success of the
  1022 + ## receiver.
  1023 + newActionParser(self, function)
  1024 +
  1025 +# public <A, B> Parser map(Function<A, B> function) {
  1026 +# return new ActionParser<>(this, function);
  1027 +# }
  1028 +
  1029 +method pick*(self: Parser, index: int): Parser =
  1030 + ## Returns a parser that transform a successful parse result by returning the element at {@code
  1031 + ## index} of a list. A negative index can be used to access the elements from the back of the
  1032 + ## list.
  1033 + self.map(nthOfList(index))
  1034 +
  1035 +# public Parser pick(int index) {
  1036 +# return map(Functions.nthOfList(index));
  1037 +# }
  1038 +
  1039 +method permute*(self: Parser, indexes: varargs[int]): Parser =
  1040 + ## Returns a parser that transforms a successful parse result by returning the permuted elements
  1041 + ## at {@code indexes} of a list. Negative indexes can be used to access the elements from the back
  1042 + ## of the list.
  1043 + self.map(permutationOfList(indexes))
  1044 +
  1045 +
  1046 +# public Parser permute(int... indexes) {
  1047 +# return this.map(Functions.permutationOfList(indexes));
  1048 +# }
  1049 +
  1050 + ## Returns a new parser that parses the receiver one or more times, separated
  1051 + ## by a {@code separator}.
  1052 + newSequenceParser(self, newSequenceParser(separator, self).star())
  1053 + .map(
  1054 +
  1055 +# public Parser separatedBy(Parser separator) {
  1056 +# return new SequenceParser(this, new SequenceParser(separator, this).star())
  1057 +# .map(new Function<List<List<List<Object>>>, List<Object>>() {
  1058 +# @Override
  1059 +# public List<Object> apply(List<List<List<Object>>> input) {
  1060 +# List<Object> result = new ArrayList<>();
  1061 +# result.add(input.get(0));
  1062 +# input.get(1).forEach(result::addAll);
  1063 +# return result;
  1064 +# }
  1065 +# });
  1066 +# }
  1067 +
  1068 +discard """
  1069 + /**
  1070 + * Returns a new parser that parses the receiver one or more times, separated
  1071 + * and possibly ended by a {@code separator}."
  1072 + */
  1073 + public Parser delimitedBy(Parser separator) {
  1074 + return separatedBy(separator)
  1075 + .seq(separator.optional())
  1076 + .map(new Function<List<List<Object>>, List<Object>>() {
  1077 + @Override
  1078 + public List<Object> apply(List<List<Object>> input) {
  1079 + List<Object> result = new ArrayList<>(input.get(0));
  1080 + if (input.get(1) != null) {
  1081 + result.add(input.get(1));
  1082 + }
  1083 + return result;
  1084 + }
  1085 + });
  1086 + }
  1087 +
  1088 + /**
  1089 + * Returns a shallow copy of the receiver.
  1090 + */
  1091 + public abstract Parser copy();
  1092 +
  1093 + /**
  1094 + * Recursively tests for structural similarity of two parsers.
  1095 + *
  1096 + * The code can automatically deals with recursive parsers and parsers that refer to other
  1097 + * parsers. This code is supposed to be overridden by parsers that add other state.
  1098 + */
  1099 + public boolean isEqualTo(Parser other) {
  1100 + return isEqualTo(other, new HashSet<>());
  1101 + }
  1102 +
  1103 + /**
  1104 + * Recursively tests for structural similarity of two parsers.
  1105 + */
  1106 + protected boolean isEqualTo(Parser other, Set<Parser> seen) {
  1107 + if (this.equals(other) || seen.contains(this)) {
  1108 + return true;
  1109 + }
  1110 + seen.add(this);
  1111 + return getClass().equals(other.getClass())
  1112 + && hasEqualProperties(other)
  1113 + && hasEqualChildren(other, seen);
  1114 + }
  1115 +
  1116 + /**
  1117 + * Compares the properties of two parsers.
  1118 + *
  1119 + * Override this method in all subclasses that add new state.
  1120 + */
  1121 + protected boolean hasEqualProperties(Parser other) {
  1122 + return true;
  1123 + }
  1124 +
  1125 + /**
  1126 + * Compares the children of two parsers.
  1127 + *
  1128 + * Normally subclasses should not override this method, but instead {@link #getChildren()}.
  1129 + */
  1130 + protected boolean hasEqualChildren(Parser other, Set<Parser> seen) {
  1131 + List<Parser> thisChildren = this.getChildren();
  1132 + List<Parser> otherChildren = other.getChildren();
  1133 + if (thisChildren.size() != otherChildren.size()) {
  1134 + return false;
  1135 + }
  1136 + for (int i = 0; i < thisChildren.size(); i++) {
  1137 + if (!thisChildren.get(i).isEqualTo(otherChildren.get(i), seen)) {
  1138 + return false;
  1139 + }
  1140 + }
  1141 + return true;
  1142 + }
  1143 +"""
... ...
repeating.nim 0 → 100644
  1 +++ a/repeating.nim
  1 +import petitparser
  2 +
  3 +# An abstract parser that repeatedly parses between 'min' and 'max' instances of its delegate.
  4 +type
  5 + RepeatingParser = ref object of DelegateParser
  6 + min*: int
  7 + max*: int
  8 +
  9 +const UNBOUNDED = 1
  10 +
  11 +proc newRepeatingParser*(delegate: Parser, min, max: int): RepeatingParser =
  12 + if min < 0:
  13 + raise newException(Exception, "Invalid min repetitions")
  14 + if max != UNBOUNDED and min > max:
  15 + raise newException(Exception, "Invalid max repetitions")
  16 + RepeatingParser(delegate, min, max)
  17 +
  18 +
  19 +discard """
  20 + @Override
  21 + public boolean hasEqualProperties(Parser other) {
  22 + return super.hasEqualProperties(other) &&
  23 + Objects.equals(min, ((RepeatingParser) other).min) &&
  24 + Objects.equals(max, ((RepeatingParser) other).max);
  25 + }
  26 +
  27 + @Override