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) &