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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
module Parcom
VERSION = "0.1.0"
class ParserException < Exception
end
struct Result(T, V)
getter tokens, value
def initialize(@tokens : Array(T), @value : V)
end
end
abstract class Parser(T, V)
abstract def parse(tokens : Array(T)) : Result(T, V)
def assert(f : V -> Bool)
Assert.new(self, f)
end
def |(other : Parser(T, V)) : Parser(T, V)
Alt.new(self, other)
end
end
class Flunk(T, V) < Parser(T, V)
def parse(tokens) : Result(T, V)
raise ParserException.new("Flunk: parsing failed")
end
end
class AnyToken(T) < Parser(T, T)
def parse(tokens : Array(T)) : Result(T, T)
if tokens.empty?
raise ParserException.new("AnyToken: input was empty")
else
Result.new(tokens[1..], tokens[0])
end
end
end
class Eof(T) < Parser(T, Nil)
def parse(tokens : Array(T)) : Result(T, Nil)
if tokens.empty?
Result.new(tokens, nil)
else
raise ParserException.new("Eof: input was not empty")
end
end
end
class Peek(T, V) < Parser(T, V)
def initialize(@p : Parser(T, V))
end
def parse(tokens : Array(T)) : Result(T, V)
result = @p.parse(tokens)
Result.new(tokens, result.value)
end
end
class Assert(T, V) < Parser(T, V)
def initialize(@p : Parser(T, V), @f : V -> Bool)
end
def parse(tokens : Array(T)) : Result(T, V)
result = @p.parse(tokens)
unless @f.call(result.value)
raise ParserException.new("Assert: predicate failed")
end
result
end
end
class Satisfy(T) < Parser(T, T)
def initialize(@f : T -> Bool)
end
def parse(tokens : Array(T)) : Result(T, T)
AnyToken(T).new.assert(@f).parse(tokens)
end
end
class Token(T) < Parser(T, T)
def initialize(@expected : T)
end
def parse(tokens : Array(T)) : Result(T, T)
Satisfy(T).new(->(x : T) { x == @expected }).parse(tokens)
end
end
class Alt(T, V) < Parser(T, V)
def initialize(@p1 : Parser(T, V), @p2 : Parser(T, V))
end
def parse(tokens : Array(T)) : Result(T, V)
@p1.parse(tokens)
rescue ParserException
@p2.parse(tokens)
end
end
end
|