diff --git a/README.md b/README.md index bc9412d..97dfc28 100644 --- a/README.md +++ b/README.md @@ -63,110 +63,110 @@ between(lit("<"), lit(">"), decimal).parse "<100>" ## Some commonly used combinators ```ruby - # Parse argument string literally - lit("foo").parse "foo" - #=> "foo" - - # Case insensitive lit - ilit("Foo").parse "fOo" - #=> "fOo" - - # Make any value into a parser that results in that value without - # consuming input. - pure("foo").parse "" - #=> "foo" - - # Parse foo or bar - (lit("foo") | lit("bar")).parse "bar" - #=> "bar" - - # Like `|`, parse one of foo or bar. `choice` is better when you have - # many choices to chose from. You can pass it any number of parsers or - # array of parsers. - choice(lit("foo"), lit("bar")).parse "bar" - #=> "bar" - - # Parse with each argument in succesion and group the results in an - # array. - group(lit("foo"), lit("bar")).parse "foobar" - #=> ["foo", "bar"] - - # Parse foo and bar, returning bar. - (lit("foo") > lit("bar")).parse "foobar" - #=> "bar" - - # Parse foo and bar, returning foo. - (lit("foo") < lit("bar")).parse "foobar" - #=> "foo" - - # Make parser optional - group(optional(lit("foo")), lit("bar")).parse "bar" - #=> [nil, "bar"] - - # Use parser zero or more times, grouping results in array. many_1, does - # the same, but requires parsing at least once. - many(lit("foo")).parse "foofoo" - #=> ["foo", "foo"] - - # Parse many, but each separated by something. sep_by_1 requires at least - # one element to be parsed. - sep_by(lit(","), lit("foo")).parse "foo,foo" - #=> ["foo", "foo"] - - # `whitespace` (alias `ws`) is zero or more whitespace characters. - # `whitespace_1` (alias `ws_1`) is one or more whitespace characters. - # `spaced` allows a parser to be surrounded by optional whitespace. - # `whitespace_1` is the base definition. If you extend it to e.g. add the - # parsing of comments, the other combinators will also recognize that - # change. - (whitespace > lit("foo")).parse " foo" - #=> "foo" - group(lit("foo"), ws_1 > lit("bar")).parse "foo bar" - #=> ["foo", "bar"] - spaced(lit("foo")).parse " foo " - #=> "foo" - - # Parse transform result according to block. - lit("foo").fmap {|x| x.upcase }.parse "foo" - #=> "FOO" - - # join(p) is the same as p.fmap {|xs| xs.join } - join(sep_by(lit(","), lit("foo") | lit("bar"))).parse "foo,bar" - #=> "foobar" - - # Parse a character from the choices in a set of strings or ranges - char_in(" \t\r\n").parse "\t" - #=> "\t" - typical_identifier_characters = ['a'..'z', 'A'..'Z', 0..9, "_"] - join(many(char_in("!?", typical_identifier_characters))).parse "foo23? bar" - #=> "foo23?" - - # Parse any one character - any_char.parse "foo" - #=> "f" - - # Require end of input at end of parse. - (lit("foo") < eof).parse "foobar" - #=> Parsby::ExpectationFailed: line 1: - foobar - | * failure: eof - \-/ *| success: lit("foo") - \| - | * failure: (lit("foo") < eof) - - # Parse only when other parser fails. - join(many(any_char.that_fails(whitespace_1))).parse "foo bar" - #=> "foo" - - # single(p) is the same as p.fmap {|x| [x] } - single(lit("foo")).parse "foo" - #=> ["foo"] - - # p1 + p2 is the same as group(p1, p2).fmap {|(r1, r2)| r1 + r2 } - (lit("foo") + (ws > lit("bar"))).parse "foo bar" - #=> "foobar" - (single(lit("foo")) + many(ws > lit("bar"))).parse "foo bar bar" - #=> ["foo", "bar", "bar"] +# Parse argument string literally +lit("foo").parse "foo" +#=> "foo" + +# Case insensitive lit +ilit("Foo").parse "fOo" +#=> "fOo" + +# Make any value into a parser that results in that value without +# consuming input. +pure("foo").parse "" +#=> "foo" + +# Parse foo or bar +(lit("foo") | lit("bar")).parse "bar" +#=> "bar" + +# Like `|`, parse one of foo or bar. `choice` is better when you have +# many choices to chose from. You can pass it any number of parsers or +# array of parsers. +choice(lit("foo"), lit("bar")).parse "bar" +#=> "bar" + +# Parse with each argument in succesion and group the results in an +# array. +group(lit("foo"), lit("bar")).parse "foobar" +#=> ["foo", "bar"] + +# Parse foo and bar, returning bar. +(lit("foo") > lit("bar")).parse "foobar" +#=> "bar" + +# Parse foo and bar, returning foo. +(lit("foo") < lit("bar")).parse "foobar" +#=> "foo" + +# Make parser optional +group(optional(lit("foo")), lit("bar")).parse "bar" +#=> [nil, "bar"] + +# Use parser zero or more times, grouping results in array. many_1, does +# the same, but requires parsing at least once. +many(lit("foo")).parse "foofoo" +#=> ["foo", "foo"] + +# Parse many, but each separated by something. sep_by_1 requires at least +# one element to be parsed. +sep_by(lit(","), lit("foo")).parse "foo,foo" +#=> ["foo", "foo"] + +# `whitespace` (alias `ws`) is zero or more whitespace characters. +# `whitespace_1` (alias `ws_1`) is one or more whitespace characters. +# `spaced` allows a parser to be surrounded by optional whitespace. +# `whitespace_1` is the base definition. If you extend it to e.g. add the +# parsing of comments, the other combinators will also recognize that +# change. +(whitespace > lit("foo")).parse " foo" +#=> "foo" +group(lit("foo"), ws_1 > lit("bar")).parse "foo bar" +#=> ["foo", "bar"] +spaced(lit("foo")).parse " foo " +#=> "foo" + +# Parse transform result according to block. +lit("foo").fmap {|x| x.upcase }.parse "foo" +#=> "FOO" + +# join(p) is the same as p.fmap {|xs| xs.join } +join(sep_by(lit(","), lit("foo") | lit("bar"))).parse "foo,bar" +#=> "foobar" + +# Parse a character from the choices in a set of strings or ranges +char_in(" \t\r\n").parse "\t" +#=> "\t" +typical_identifier_characters = ['a'..'z', 'A'..'Z', 0..9, "_"] +join(many(char_in("!?", typical_identifier_characters))).parse "foo23? bar" +#=> "foo23?" + +# Parse any one character +any_char.parse "foo" +#=> "f" + +# Require end of input at end of parse. +(lit("foo") < eof).parse "foobar" +#=> Parsby::ExpectationFailed: line 1: + foobar + | * failure: eof + \-/ *| success: lit("foo") + \| + | * failure: (lit("foo") < eof) + +# Parse only when other parser fails. +join(many(any_char.that_fails(whitespace_1))).parse "foo bar" +#=> "foo" + +# single(p) is the same as p.fmap {|x| [x] } +single(lit("foo")).parse "foo" +#=> ["foo"] + +# p1 + p2 is the same as group(p1, p2).fmap {|(r1, r2)| r1 + r2 } +(lit("foo") + (ws > lit("bar"))).parse "foo bar" +#=> "foobar" +(single(lit("foo")) + many(ws > lit("bar"))).parse "foo bar bar" +#=> ["foo", "bar", "bar"] ``` ## Defining combinators @@ -200,7 +200,7 @@ def between(left, right, p) end between(lit("<"), lit(">"), lit("foo")).label -=> '((lit("<") > lit("foo")) < lit(">"))' +#=> '((lit("<") > lit("foo")) < lit(">"))' ``` If we're to wrap that parser in a new one, then the label would be simply @@ -212,7 +212,7 @@ def between(left, right, p) end between(lit("<"), lit(">"), lit("foo")).label.to_s -=> "unknown" +#=> "unknown" ``` ## Defining parsers as modules