Module: Peg::Combinators::Implementation

Included in:
Peg::Combinators, Parser
Defined in:
lib/peg.backup/combinators/implementation.rb

Instance Method Summary collapse

Instance Method Details

#_debug(parser, name: nil) ⇒ Object



10
11
12
13
14
15
16
17
# File 'lib/peg.backup/combinators/implementation.rb', line 10

def _debug(parser, name: nil)
  Parser.new(parser.name) do |input, _name|
    puts "debugging #{name || parser.name}: #{input.inspect}"
    result = Parser.parse(parser, input)
    puts "debugging #{name || parser.name}: #{result}"
    result
  end
end

#_lookahead(parsers, name:) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/peg.backup/combinators/implementation.rb', line 19

def _lookahead(parsers, name:)
  parser = _select(parsers)
  Parser.new(name || "lookahead(#{parser.name})") do |input, name|
    case Parser.parse(parser, input)
    in {ok: true}
      {ok: true, ast: nil, input:}
    in error
      error
    end
  end
end

#_many(parser, max:, min:, name:) ⇒ Object



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
# File 'lib/peg.backup/combinators/implementation.rb', line 51

def _many(parser, max:, min:, name:)
  Parser.new(name) do |input, _name|
    total_ast = []
    original_input = input
    current_input = input
    match_count = 0
    loop do
      if current_input.empty?
        break Result.ok(ast: total_ast, input:) if match_count >= min
        break Result.nok(error: "many #{name} did not succeed the required #{min} times, but only #{match_count}", input: original_input, name:)
      end

      case Parser.parse(parser, current_input)
      in {ok: true, ast:, input:}
        raise InfiniteLoop, "must not parse zero width inside many in parser: #{parser.name}" if input.pos == current_input.pos
        current_input = input
        total_ast = [*total_ast, ast]
        match_count += 1
        break Result.ok(ast: total_ast, input:) if max && match_count >= max
      else
        break Result.ok(ast: total_ast, input:) if match_count >= min
        break Result.nok(error: "many #{name} did not succeed the required #{min} times, but only #{match_count}", input: original_input, name:)
      end
    end
  end
end

#_map_result(parser, name, mapper) ⇒ Object

def _map(parser, name, mapper)

name ||= "map(#{parser.name})"
Parser.new(name) do |input, _name|
  case Parser.parse(parser, input)
  in {ok: true, ast: ast, input: new_input}
    {ok: true, ast: mapper.(ast), input: new_input}
  in error
    error
  end
end

end



43
44
45
46
47
48
49
# File 'lib/peg.backup/combinators/implementation.rb', line 43

def _map_result(parser, name, mapper)
  Parser.new(name) do |input, name|
    result = Parser.parse(parser, input)
    # require "debug"; binding.break
    mapper.(result)
  end
end

#_satisfy(parser, name:, &satisfier) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/peg.backup/combinators/implementation.rb', line 78

def _satisfy(parser, name:, &satisfier)
  Parser.new(name || "satisfy(#{parser.name})") do |input, name|
    original_input = input
    case Parser.parse(parser, input)
    in {ok: false} => error
      error
    in {ok: true, ast:, input:} => result
      ok = satisfier.(ast)
      if ok == true
        result
      elsif ok
        {ok: true, ast: ok, input:}
      else
        {ok: false, input: original_input, error: "satisfier #{name} failed", name: name}
      end
    end
  end
end

#_select(*parsers, name: nil) ⇒ Object

Raises:

  • (ArgumentError)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/peg.backup/combinators/implementation.rb', line 97

def _select(*parsers, name: nil)
  parsers = parsers.flatten
  raise ArgumentError, "all parsers must be instances of Parser" unless parsers.all? { Parser === it }
  Parser.new(name || "select #{parsers.map(&:name).join(", ")}") do |input, name|
    result = {ok: false, error: "No parser matched in select named #{name}", input:}
    parsers.each do |parser|
      # case p(Parser.parse(parser, input))
      this_result = Parser.parse(parser, input)
      # require "debug"; binding.break
      case this_result
      in {ok: true} => result
        break result
      in _
        nil
      end
    end
    result
  end
end

#_sequence(parsers, name) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/peg.backup/combinators/implementation.rb', line 117

def _sequence(parsers, name)
  name ||= "seq(#{parsers.map(&:name).join(", ")})"
  Parser.new(name) do |input, _name|
    original_input = input
    result = parsers.reduce_while [input, []] do |(input, ast), parser|
      # require "debug"; binding.break
      parsed = Parser.parse(parser, input)
      # p parsed
      case parsed
      in {ok: true, ast: ast_node, input:}
        cont_reduce([input, [*ast, ast_node]])
      in {ok: false, error:}
        halt_reduce(Result.nok(input: original_input, error:, name: name))
      end
    end

    case result
    in {ok: false} => error
      error
    in [input, ast]
      Result.ok(ast:, input:)
    end
  end
end