src/parsnim

    Dark Mode
Search:
Group by:
  Source   Edit

Types

ParseError = object of ValueError
  Source   Edit
ParseFn[T; R] = proc (s: var State[T]): Result[R]
function defined to manipulate State for the next parser and return a result   Source   Edit
Parser[T; R] = object
  fn*: ParseFn[T, R]
  description*: string
central object to wrap all ParseFns in   Source   Edit
Result[T] = object of RootObj
  kind*: ResultType          ## states whether the result is a `Match` or `Failure`
  value*: Stream[T]          ## `Parser`s translate from one stream to another hence result values are `Stream`s
  start_index*, end_index*: int ## start and end indices for the value/expected
  tag*: seq[string]          ## an optional seq of strings that can be used to mark results for further processing
  description*: string       ## describes what the value would represent. used when erroring on failed parsing
  expected*: Stream[T]       ## for failures, what value wanted to be. used when erroring on failed parsing
  
Result objects are returned by all parsers   Source   Edit
ResultType = enum
  Match, Failure
  Source   Edit
State[T] = object
  index*: int
  stream*: Stream[T]
object passed to all parsers to track position and the stream being parsed   Source   Edit
Stream[T] = seq[T]
Stream is an alias for seq[T]   Source   Edit

Procs

proc `$`(parser: Parser): string
  Source   Edit
proc `$`(state: State): string
  Source   Edit
proc `and`[T, R](parser, other: Parser[T, R]): Parser[T, R]
parser and other must both match at the current position in the stream
let p = test_proc(proc(c: char): auto = parseInt($c)>2, "greater than 2") and test_proc(proc(c: char): auto = parseInt($c)<= 10, "less than or equal to 10")
echo p
echo p.parse("4")
# <Parser: greater than 2 and less than or equal to 10>
# @['4']
p.parse("1")
# Error: unhandled exception: failed to parse with error: Expected `greater than 2` got @['1'] @ 0:1 [ParseError]
  Source   Edit
proc `not`[T, R](parser: Parser[T, R]): Parser[T, R]
inverts a Result so that a failure is instead a match and vice-versa
let p = not test_char('c')
echo p
echo p.parse("p")
# <Parser: not char c>
# @['p']
  Source   Edit
proc `or`[T, R](parser, other: Parser[T, R]): Parser[T, R]
parser or other must match
let p = test_char('c') or test_char('p')
echo p
echo p.parse("p")
# <Parser: char c or char p>
# @['p']
  Source   Edit
proc anything[T]()
  Source   Edit
proc at_least(parser: Parser; n: int): auto
finds parser at least n times   Source   Edit
proc at_most(parser: Parser; n: int): auto
finds parser up to n times   Source   Edit
proc describe(parser: var Parser; desc: string): Parser
describe a parser   Source   Edit
proc failure[T](start_index, end_index: int; description: string): Result[T]
function to generate Failure Results without an expected value   Source   Edit
proc failure[T](start_index, end_index: int; expected: Stream[T];
                description: string): Result[T]
function to generate Failure Results with an expected value   Source   Edit
proc many(parser: Parser): Parser
finds parser until it doesn't
let t = (test_char('c')).many().then(test_char('p'))
echo t
echo t.parse("ccccp")
# <Parser: char c many times then char p>
# @['c', 'c', 'c', 'c', 'p']
  Source   Edit
proc map[T, R, NR](parser: Parser[T, R]; item: NR): Parser[T, NR]
takes a parser that goes from Stream[T]->Stream[R] and transforms it to Stream[T]->Stream[NR]   Source   Edit
proc map[T, R, NR](parser: Parser[T, R]; map_fn: proc (x: R): NR): Parser[T, NR]
takes a parser that goes from Stream[T]->Stream[R] and transforms it to Stream[T]->Stream[NR]   Source   Edit
proc map[T, R, NR](parser: Parser[T, R]; map_fn: proc (x: seq[R]): seq[NR]): Parser[
    T, NR]
takes a parser that goes from Stream[T]->Stream[R] and transforms it to Stream[T]->Stream[NR]   Source   Edit
proc nothing[T]()
  Source   Edit
proc optional(parser: Parser): auto
tries to find parser and if not continues   Source   Edit
proc pad(parser: Parser[char, char]): Parser[char, char] {.
    ...raises: [ValueError, RegexError], tags: [].}
optional whitespace
echo test_char('c').pad.parse("c    ")
# @['c']
  Source   Edit
proc pad(parser: Parser[char, string]): Parser[char, string] {.
    ...raises: [ValueError, RegexError], tags: [].}
optional whitespace
echo test_string("hello").pad.parse("hello    ")
# @["hello"]
  Source   Edit
proc parse[char, R](parser: Parser[char, R]; stream: string): Stream[R]
run a parser on a stream that is a string   Source   Edit
proc parse[T, R](parser: Parser[T, R]; stream: Stream[T]): Stream[R]
run a parser on a stream   Source   Edit
proc parse_partial[T, R](parser: Parser[T, R]; state: var State[T]): Result[R]
  Source   Edit
proc parse_partial[T, R](parser: Parser[T, R]; stream: Stream[T]): Result[R]
  Source   Edit
proc skip[T, R](parser, other: Parser[T, R]): Parser[T, R]
parses parser then other but ignores other result   Source   Edit
proc space(parser: Parser[char, char]): Parser[char, char] {.
    ...raises: [ValueError], tags: [].}
optional whitespace
echo test_char('c').space.parse("c ")
# @['c']
  Source   Edit
proc space(parser: Parser[char, string]): Parser[char, string] {.
    ...raises: [ValueError], tags: [].}
optional whitespace
let p = test_string("9").space
echo p.parse("9")
# @["9"]
  Source   Edit
proc str[T](parser: Parser[T, char]): Parser[T, string]
  Source   Edit
proc success[T](start_index, end_index: int; value: Stream[T];
                description: string): Result[T]
function to generate Match Results   Source   Edit
proc tag[T, R](parser: Parser[T, R]; tag: string): Parser[T, R]
creates a parser that tags parser results   Source   Edit
proc test_char(test: char): Parser[char, char] {....raises: [], tags: [].}
test if a char is next in the stream (usually a string for char test)   Source   Edit
proc test_item[T](test: T; description: string): auto
test if a single test item is next in the stream   Source   Edit
proc test_proc[T](test_proc_var: proc (x: T): bool; description: string): Parser[
    T, T]
tests a procedure against the next value in the stream
let p = test_proc(proc(c: char): auto = parseInt($c)>2, "greater than 2")
echo p
echo p.parse("4")
# <Parser: greater than 2>
# @['4']
  Source   Edit
proc test_proc[T](test_proc_var: proc (x: T): bool; description: string;
                  expected: T): Parser[T, T]
tests a procedure against the next value in the stream
let p = test_proc(proc(c: char): auto = c== '4', "the character '4'", "'4'")
echo p
echo p.parse("4")
# <Parser: the character '4'>
# @['4']
  Source   Edit
proc test_regex(pattern: Regex; description: string): Parser[char, string] {.
    ...raises: [ValueError], tags: [].}
tests if a regex pattern is next in a stream
let r = test_regex(re"[a-zA-Z_][a-zA-Z0-9_]*", "identifier")
echo r
echo r.parse("_hello1984")
# <Parser: regex identifier>
# @["_hello1984"]
  Source   Edit
proc test_regex_string(pattern: Regex; description: string): Parser[string,
    string] {....raises: [], tags: [].}
  Source   Edit
proc test_seq[T](test_seq: Stream[T]; description: string): Parser[T, T]
tests if the test_seq is the next sequence of the state's stream

let t = test_seq("abc".to_seq, "alphabet") echo t echo t.parse("abc") # <Parser: alphabet> # @['a', 'b', 'c']

  Source   Edit
proc test_string(test: string): auto {....raises: [ValueError], tags: [].}
tests if a string is next in a stream (special case of test_seq)

let t = test_string("abc") echo t echo t.parse("abc") # <Parser: string abc> # @["abc"]

  Source   Edit
proc then[T, R](parser, other: Parser[T, R]): Parser[T, R]
parses parser then other and rolls them together

let t = test_char('c').then(test_char('p')) echo t echo t.parse("cp") # <Parser: char c then char p> # @['c', 'p']

  Source   Edit
proc times[T, R](parser: Parser[T, R]; min: int; max: int = -1): Parser[T, R]
looks for parser to repeat >=min and <=max times
let t = (not test_char('c')).times(3)
echo t
echo t.parse("abd")
# <Parser: not char c 3 times>
# @['a', 'b', 'd']
  Source   Edit
proc until[T, R](self, parser: Parser[T, R]): Parser[T, R]
looks for the current parser self until parser matches
let p = (test_char('c')).until(test_char('p'))
echo p
echo p.parse("ccccp")
# <Parser: char c until not char c>
# @['c', 'c', 'c', 'c', 'p']
  Source   Edit

Converters

converter to_bool(res: Result): bool
Results are truthy/falsey   Source   Edit