aboutsummaryrefslogtreecommitdiff
path: root/src/__OLD_parcom/parser.cr
blob: ca350df059e4da362e2e6fba5101a71dfec6375e (plain)
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