1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
require "../parcom.cr"
module Parcom
# `Parser` is the base class of all parser objects and contains
# a handful of helper methods that can allow for cleaner syntax.
#
# The generic type `T` represents the type of tokens a parser will
# operate on (usually `Char`).
# The generic type `V` represents the type of value that a parser
# will return when parsing is successful.
abstract class Parser(T, V)
# Accepts a `Tokens(T)` and either retuns a `Result(T, V)`, or raises a
# `ParserFail` exception with a message providing context of where
# in the chain the parsing failed.
#
# The `V` in the returned `Result` is arbitrary, but the `Tokens(T)` in
# the returned result MUST contain the parser's input, with some tokens
# removed from the front proprtional to what was parsed.
#
# Example:
# ```
# hello = ParsesHello.new # inherits from Parser(Char, String)
# input = Tokens.from_string("Hello world!")
#
# result = hello.parse(input)
# result.value # => "Hello"
# result.tokens # => [' ', 'w', 'o', 'r', 'l', 'd', '!']
#
# bad_input = Tokens.from_string("Good evening world!")
# hello.parse(bad_input) # raises ParserFail
# ```
abstract def parse(tokens : Tokens(T)) : Result(T, V)
# Same as `#parse`, but returns `nil` instead of raising `ParserFail`.
def parse?(tokens : Tokens(T)) : Result(T, V)?
self.parse(tokens)
rescue ParserFail
return nil
end
# Constructs an `Alt` parser with `self` and `other`.
def |(other : Parser(T, V)) : Alt(T, V)
Alt.new(self, other)
end
# Constructs a `Plus` parser with `self` and `other`.
def +(other : Parser(T, U)) : Plus(T, V, U) forall U
Plus.new(self, other)
end
# Constructs a `Left` parser with `self` and `other`.
def <<(other : Parser(T, U)) : Left(T, V, U) forall U
Left.new(self, other)
end
# Constructs a `Right` parser with `self` and `other`.
def >>(other : Parser(T, U)) : Right(T, V, U) forall U
Right.new(self, other)
end
# Constructs an `Assert` parser with `self` and the given block.
def assert(&block : V -> Bool) : Assert(T, V)
Assert.new(self, &block)
end
# Constructs an `Assert` parser with `self` and the given proc.
def assert(f : V -> Bool) : Assert(T, V)
Assert.new(self, &f)
end
# Constructs a `Map` parser with `self` and the given block.
def map(&block : V -> U) : Map(T, V, U) forall U
Map.new(self, &block)
end
# Constructs a `Map` parser with `self` and the given proc.
def map(f : V -> U) : Map(T, V, U) forall U
Map.new(self, &f)
end
# Constructs a `Recover` parser with `self` and the given `V`.
def recover(default : V) : Recover(T, V)
Recover.new(self, default)
end
end
end
|