Module: Paco::Combinators
Defined Under Namespace
Modules: Char
Class Method Summary collapse
-
.alt(*parsers) ⇒ Paco::Parser
Accepts any number of parsers, and returns a parser that returns the value of the first parser that succeeds, backtracking in between.
-
.failed(message) ⇒ Paco::Parser
Returns a parser that doesn’t consume any input and always fails with passed ‘message`.
-
.index ⇒ Paco::Parser
Returns parser that returns ‘Paco::Index` representing the current offset into the parse without consuming the input.
-
.lazy(desc = "", &block) ⇒ Paco::Parser
Accepts a block that returns a parser, which is evaluated the first time the parser is used.
-
.lookahead(parser) ⇒ Paco::Parser
Returns a parser that runs the passed ‘parser` without consuming the input, and returns empty string.
-
.many(parser) ⇒ Paco::Parser
Expects ‘parser` zero or more times, and returns an array of the results.
-
.memoize(&block) ⇒ Object
Helper used for memoization.
-
.not_followed_by(parser) ⇒ Paco::Parser
Returns a parser that runs the passed ‘parser` without consuming the input, and returns `null` if the passed `parser` _does not match_ the input.
-
.optional(parser) ⇒ Paco::Parser
Returns parser that returns result of the passed ‘parser` or nil if `parser` fails.
-
.sep_by(parser, separator) ⇒ Paco::Parser
Returns a parser that expects zero or more matches for ‘parser`, separated by the parser `separator`.
-
.sep_by!(parser, separator) ⇒ Paco::Parser
(also: sep_by_1)
Returns a parser that expects one or more matches for ‘parser`, separated by the parser `separator`.
-
.seq(*parsers) ⇒ Paco::Parser
Accepts one or more parsers, and returns a parser that expects them to match in order, returns an array of all their results.
-
.succeed(result) ⇒ Paco::Parser
Returns a parser that doesn’t consume any input and always returns ‘result`.
-
.wrap(before, after, parser) ⇒ Paco::Parser
Expects the parser ‘before` before `parser` and `after` after `parser.
Methods included from Char
any_char, cr, crlf, digit, digits, end_of_line, eof, letter, letters, lf, newline, none_of, one_of, opt_digits, opt_letters, opt_ws, regexp, regexp_char, remainder, satisfy, spaced, string, take_while, ws
Class Method Details
.alt(*parsers) ⇒ Paco::Parser
Accepts any number of parsers, and returns a parser that returns the value of the first parser that succeeds, backtracking in between.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/paco/combinators.rb', line 61 def alt(*parsers) raise ArgumentError, "no parsers specified" if parsers.empty? Parser.new("alt(#{parsers.map(&:desc).join(", ")})") do |ctx| result = nil last_error = nil start_pos = ctx.pos parsers.each do |pars| break result = {value: pars._parse(ctx)} rescue ParseError => e last_error = e ctx.pos = start_pos next end raise last_error unless result result[:value] end end |
.failed(message) ⇒ Paco::Parser
Returns a parser that doesn’t consume any input and always fails with passed ‘message`.
41 42 43 |
# File 'lib/paco/combinators.rb', line 41 def failed() Parser.new() { |ctx, parser| parser.failure(ctx) } end |
.index ⇒ Paco::Parser
Returns parser that returns ‘Paco::Index` representing the current offset into the parse without consuming the input.
165 166 167 |
# File 'lib/paco/combinators.rb', line 165 def index Parser.new { |ctx| ctx.index } end |
.lazy(desc = "", &block) ⇒ Paco::Parser
Accepts a block that returns a parser, which is evaluated the first time the parser is used. This is useful for referencing parsers that haven’t yet been defined, and for implementing recursive parsers.
106 107 108 |
# File 'lib/paco/combinators.rb', line 106 def lazy(desc = "", &block) Parser.new(desc) { |ctx| block.call._parse(ctx) } end |
.lookahead(parser) ⇒ Paco::Parser
Returns a parser that runs the passed ‘parser` without consuming the input, and returns empty string.
49 50 51 52 53 54 55 56 |
# File 'lib/paco/combinators.rb', line 49 def lookahead(parser) Parser.new("lookahead(#{parser.desc})") do |ctx| start_pos = ctx.pos parser._parse(ctx) ctx.pos = start_pos "" end end |
.many(parser) ⇒ Paco::Parser
Expects ‘parser` zero or more times, and returns an array of the results.
143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/paco/combinators.rb', line 143 def many(parser) Parser.new("many(#{parser.desc})") do |ctx| results = [] loop do results << parser._parse(ctx) rescue ParseError break end results end end |
.memoize(&block) ⇒ Object
Helper used for memoization
170 171 172 |
# File 'lib/paco/combinators.rb', line 170 def memoize(&block) Memoizer.memoize(block.source_location, &block) end |
.not_followed_by(parser) ⇒ Paco::Parser
Returns a parser that runs the passed ‘parser` without consuming the input, and returns `null` if the passed `parser` _does not match_ the input. Fails otherwise.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/paco/combinators.rb', line 17 def not_followed_by(parser) Parser.new("not #{parser.desc}") do |ctx, pars| start_pos = ctx.pos begin parser._parse(ctx) rescue ParseError nil else pars.failure(ctx) ensure ctx.pos = start_pos end end end |
.optional(parser) ⇒ Paco::Parser
Returns parser that returns result of the passed ‘parser` or nil if `parser` fails.
158 159 160 |
# File 'lib/paco/combinators.rb', line 158 def optional(parser) alt(parser, succeed(nil)) end |
.sep_by(parser, separator) ⇒ Paco::Parser
Returns a parser that expects zero or more matches for ‘parser`, separated by the parser `separator`. Returns an array of `parser` results.
115 116 117 118 |
# File 'lib/paco/combinators.rb', line 115 def sep_by(parser, separator) alt(sep_by!(parser, separator), succeed([])) .with_desc("sep_by(#{parser.desc}, #{separator.desc})") end |
.sep_by!(parser, separator) ⇒ Paco::Parser Also known as: sep_by_1
Returns a parser that expects one or more matches for ‘parser`, separated by the parser `separator`. Returns an array of `parser` results.
125 126 127 128 |
# File 'lib/paco/combinators.rb', line 125 def sep_by!(parser, separator) seq(parser, many(separator.next(parser))) { |first, arr| [first] + arr } .with_desc("sep_by!(#{parser.desc}, #{separator.desc})") end |
.seq(*parsers) ⇒ Paco::Parser
Accepts one or more parsers, and returns a parser that expects them to match in order, returns an array of all their results. If ‘block` specified, passes results of the `parses` as an arguments to a `block`, and at the end returns its result.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/paco/combinators.rb', line 86 def seq(*parsers) raise ArgumentError, "no parsers specified" if parsers.empty? result = Parser.new("seq(#{parsers.map(&:desc).join(", ")})") do |ctx| start_pos = ctx.pos begin parsers.map { |parser| parser._parse(ctx) } rescue ParseError => e ctx.pos = start_pos raise e end end return result unless block_given? result.fmap { |results| yield(*results) } end |
.succeed(result) ⇒ Paco::Parser
Returns a parser that doesn’t consume any input and always returns ‘result`.
34 35 36 |
# File 'lib/paco/combinators.rb', line 34 def succeed(result) Parser.new("succeed(#{result})") { result } end |
.wrap(before, after, parser) ⇒ Paco::Parser
Expects the parser ‘before` before `parser` and `after` after `parser. Returns the result of the parser.
136 137 138 |
# File 'lib/paco/combinators.rb', line 136 def wrap(before, after, parser) before.next(parser).skip(after) end |