Class: Parsby
- Inherits:
-
Object
- Object
- Parsby
- Includes:
- Combinators
- Defined in:
- lib/parsby.rb,
lib/parsby/version.rb,
lib/parsby/combinators.rb
Defined Under Namespace
Modules: Combinators, Example, Tree Classes: BackedIO, Backup, Context, Error, ExpectationFailed, ParsedRange, PosRange, Splicer
Constant Summary collapse
- VERSION =
"1.1.2"
Instance Attribute Summary collapse
-
#label ⇒ Object
The parser’s label.
Instance Method Summary collapse
-
#%(name) ⇒ Object
Set the label and return self.
-
#*(n) ⇒ Object
p * n, runs parser p n times, grouping results in an array.
-
#+(p) ⇒ Object
x + y does + on the results of x and y.
-
#<(p) ⇒ Object
x < y runs parser x then y and returns x.
-
#<<(p) ⇒ Object
xs << x appends result of parser x to list result of parser xs.
-
#>(p) ⇒ Object
x > y runs parser x then y and returns y.
-
#fmap(&b) ⇒ Object
Like map for arrays, this lets you work with the value “inside” the parser, i.e.
-
#initialize(label = nil, &b) ⇒ Parsby
constructor
Initialize parser with optional label argument, and parsing block.
-
#parse(src) ⇒ Object
Parse a String or IO object.
-
#peek(src) ⇒ Object
Parses without consuming input.
-
#that_fails(p) ⇒ Object
(also: #that_fail)
x.that_fails(y)will tryy, fail ifysucceeds, or parse withxifyfails. -
#then(&b) ⇒ Object
Pass result of self parser to block to construct the next parser.
-
#|(p) ⇒ Object
x | ytries y if x fails. - #~ ⇒ Object
Methods included from Combinators
Methods included from Combinators::ModuleMethods
Constructor Details
#initialize(label = nil, &b) ⇒ Parsby
Initialize parser with optional label argument, and parsing block. The parsing block is given an IO as argument, and its result is the result when parsing.
607 608 609 610 |
# File 'lib/parsby.rb', line 607 def initialize(label = nil, &b) self.label = label if label @parser = b end |
Instance Attribute Details
#label ⇒ Object
The parser’s label. It’s an “unknown” token by default.
598 599 600 |
# File 'lib/parsby.rb', line 598 def label @label || "unknown" end |
Instance Method Details
#%(name) ⇒ Object
Set the label and return self.
710 711 712 713 |
# File 'lib/parsby.rb', line 710 def %(name) self.label = name self end |
#*(n) ⇒ Object
p * n, runs parser p n times, grouping results in an array.
685 686 687 688 689 |
# File 'lib/parsby.rb', line 685 def *(n) Parsby.new "(#{label} * #{n})" do |c| n.times.map { parse c } end end |
#+(p) ⇒ Object
x + y does + on the results of x and y. This is mostly meant to be used with arrays, but it would work with numbers and strings too.
693 694 695 696 697 |
# File 'lib/parsby.rb', line 693 def +(p) group(self, p) .fmap {|(x, y)| x + y } .tap {|r| r.label = "(#{label} + #{p.label})" } end |
#<(p) ⇒ Object
x < y runs parser x then y and returns x.
660 661 662 663 664 |
# File 'lib/parsby.rb', line 660 def <(p) ~splicer.start do |m| m.end(self).then {|r| m.end(p).then { pure r } } end % "(#{label} < #{p.label})" end |
#<<(p) ⇒ Object
xs << x appends result of parser x to list result of parser xs.
700 701 702 703 704 705 706 707 |
# File 'lib/parsby.rb', line 700 def <<(p) Parsby.new "(#{label} << #{p.label})" do |c| x = parse c y = p.parse c # like x << y, but without modifying x. x + [y] end end |
#>(p) ⇒ Object
x > y runs parser x then y and returns y.
667 668 669 |
# File 'lib/parsby.rb', line 667 def >(p) self.then { p } % "(#{label} > #{p.label})" end |
#fmap(&b) ⇒ Object
Like map for arrays, this lets you work with the value “inside” the parser, i.e. the result.
Example:
decimal.fmap {|x| x + 1}.parse("2")
=> 3
722 723 724 725 726 |
# File 'lib/parsby.rb', line 722 def fmap(&b) Parsby.new "#{label}.fmap" do |c| b.call parse c end end |
#parse(src) ⇒ Object
Parse a String or IO object.
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 |
# File 'lib/parsby.rb', line 613 def parse(src) ctx = src.is_a?(Context) ? src : Context.new(src) parsed_range = ParsedRange.new(ctx.bio.pos, ctx.bio.pos, label) ctx.parsed_ranges << parsed_range if ctx.parsed_ranges parent_parsed_range = ctx.parsed_ranges ctx.parsed_ranges = parsed_range begin r = @parser.call ctx rescue ExpectationFailed => e ctx.parsed_ranges.end = ctx.bio.pos ctx.parsed_ranges.failed = true ctx.bio.restore_to ctx.parsed_ranges.start raise else ctx.parsed_ranges.end = ctx.bio.pos r ensure # Keep the root one for use in ExceptionFailed#message if parent_parsed_range ctx.parsed_ranges = parent_parsed_range end end end |
#peek(src) ⇒ Object
Parses without consuming input.
638 639 640 641 642 643 644 645 646 |
# File 'lib/parsby.rb', line 638 def peek(src) ctx = src.is_a?(Context) ? src : Context.new(src) starting_pos = ctx.bio.pos begin parse ctx ensure ctx.bio.restore_to starting_pos end end |
#that_fails(p) ⇒ Object Also known as: that_fail
x.that_fails(y) will try y, fail if y succeeds, or parse with x if y fails.
Example:
decimal.that_fails(string("10")).parse "3"
=> 3
decimal.that_fails(string("10")).parse "10"
Parsby::ExpectationFailed: line 1:
10
\/ expected: (not "10")
763 764 765 766 767 768 769 770 771 772 773 774 775 |
# File 'lib/parsby.rb', line 763 def that_fails(p) Parsby.new "#{label}.that_fails(#{p.label})" do |c| orig_pos = c.bio.pos begin r = p.parse c.bio rescue Error c.bio.restore_to orig_pos parse c.bio else raise ExpectationFailed.new c end end end |
#then(&b) ⇒ Object
745 746 747 748 749 |
# File 'lib/parsby.rb', line 745 def then(&b) Parsby.new "#{label}.then" do |c| b.call(parse(c)).parse(c) end end |