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, Token
Constant Summary collapse
- VERSION =
"0.1.0"
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.
-
#label ⇒ Object
The parser’s label.
-
#label=(name) ⇒ Object
Assign label to parser.
-
#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.
635 636 637 638 |
# File 'lib/parsby.rb', line 635 def initialize(label = nil, &b) self.label = label if label @parser = b end |
Instance Method Details
#%(name) ⇒ Object
Set the label and return self.
736 737 738 739 |
# File 'lib/parsby.rb', line 736 def %(name) self.label = name self end |
#*(n) ⇒ Object
p * n, runs parser p n times, grouping results in an array.
711 712 713 714 715 |
# File 'lib/parsby.rb', line 711 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.
719 720 721 722 723 |
# File 'lib/parsby.rb', line 719 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.
688 689 690 |
# File 'lib/parsby.rb', line 688 def <(p) self.then {|r| p.then { pure r } } % "(#{label} < #{p.label})" end |
#<<(p) ⇒ Object
xs << x appends result of parser x to list result of parser xs.
726 727 728 729 730 731 732 733 |
# File 'lib/parsby.rb', line 726 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.
693 694 695 |
# File 'lib/parsby.rb', line 693 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
748 749 750 751 752 |
# File 'lib/parsby.rb', line 748 def fmap(&b) Parsby.new "#{label}.fmap" do |c| b.call parse c end end |
#label ⇒ Object
The parser’s label. It’s an “unknown” token by default.
622 623 624 |
# File 'lib/parsby.rb', line 622 def label @label || Token.new("unknown") end |
#label=(name) ⇒ Object
Assign label to parser. If given a symbol, it’ll be turned into a Parsby::Token.
628 629 630 |
# File 'lib/parsby.rb', line 628 def label=(name) @label = name.is_a?(Symbol) ? Token.new(name) : name end |
#parse(src) ⇒ Object
Parse a String or IO object.
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
# File 'lib/parsby.rb', line 641 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.
666 667 668 669 670 671 672 673 674 |
# File 'lib/parsby.rb', line 666 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")
789 790 791 792 793 794 795 796 797 798 799 800 801 |
# File 'lib/parsby.rb', line 789 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
Pass result of self parser to block to construct the next parser.
For example, instead of writing:
Parsby.new do |c|
x = foo.parse c
(x).parse c
end
you can write:
foo.then {|x| x }
This is analogous to Parsec’s >>= operator in Haskell, where you could write:
foo >>=
771 772 773 774 775 |
# File 'lib/parsby.rb', line 771 def then(&b) Parsby.new "#{label}.then" do |c| b.call(parse(c)).parse(c) end end |
#|(p) ⇒ Object
x | y tries y if x fails.
677 678 679 680 681 682 683 684 685 |
# File 'lib/parsby.rb', line 677 def |(p) Parsby.new "(#{self.label} | #{p.label})" do |c| begin parse c rescue Error p.parse c end end end |
#~ ⇒ Object
697 698 699 700 701 702 703 704 705 706 707 708 |
# File 'lib/parsby.rb', line 697 def ~ Parsby.new "(~ #{label})" do |c| begin parse c ensure c.parsed_ranges.children[0].splice_self! if c.parsed_ranges.parent c.parsed_ranges.splice_self! end end end end |