Skip to content

Commit

Permalink
revise readme once more
Browse files Browse the repository at this point in the history
  • Loading branch information
jolmg committed Sep 26, 2020
1 parent 2a59f75 commit dea8726
Showing 1 changed file with 40 additions and 34 deletions.
74 changes: 40 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Parser combinator library for Ruby, based on Haskell's Parsec.
- [Defining parsers as modules](#defining-parsers-as-modules)
- [`ExpectationFailed`](#expectationfailed)
- [Cleaning up the parse tree for the trace](#cleaning-up-the-parse-tree-for-the-trace)
- [`splicer.start` combinator](#splicerstart-combinator)
- [Recursive parsers with `lazy`](#recursive-parsers-with-lazy)
- [Parsing left-recursive languages with `reduce` combinator](#parsing-leftrecursive-languages-with-reduce-combinator)
- [`Parsby.new`](#parsbynew)
Expand Down Expand Up @@ -87,7 +86,8 @@ between(lit("<"), lit(">"), decimal).parse "<100>"
choice(lit("foo"), lit("bar")).parse "bar"
#=> "bar"

# Parses each argument in succesion and groups them in an array.
# Parse with each argument in succesion and group the results in an
# array.
group(lit("foo"), lit("bar")).parse "foobar"
#=> ["foo", "bar"]

Expand All @@ -99,17 +99,6 @@ between(lit("<"), lit(">"), decimal).parse "<100>"
(lit("foo") < lit("bar")).parse "foobar"
#=> "foo"

# Parse transform result according to block.
lit("foo").fmap {|x| x.upcase }.parse "foo"
#=> "FOO"

# 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?"

# Make parser optional
group(optional(lit("foo")), lit("bar")).parse "bar"
#=> [nil, "bar"]
Expand All @@ -120,7 +109,7 @@ between(lit("<"), lit(">"), decimal).parse "<100>"
#=> ["foo", "foo"]

# Parse many, but each separated by something. sep_by_1 requires at least
# one element.
# one element to be parsed.
sep_by(lit(","), lit("foo")).parse "foo,foo"
#=> ["foo", "foo"]

Expand All @@ -137,11 +126,26 @@ between(lit("<"), lit(">"), decimal).parse "<100>"
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 eof at end of parse
# Require end of input at end of parse.
(lit("foo") < eof).parse "foobar"
#=> Parsby::ExpectationFailed: line 1:
foobar
Expand All @@ -150,18 +154,24 @@ between(lit("<"), lit(">"), decimal).parse "<100>"
\|
| * failure: (lit("foo") < eof)

# join(p) is the same as p.fmap {|xs| xs.join}
join(sep_by(lit(","), lit("foo") | lit("bar"))).parse "foo,bar"
#=> "foobar"
# 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"
(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

If you look at the examples in this source, you'll notice that all
If you look at the examples in this source, you'll notice that almost all
combinators are defined with `define_combinator`. Strictly speaking, it's
not necessary to use that to define combinators. You can do it with
variable assignment or `def` syntax. Nevertheless, `define_combinator` is
Expand Down Expand Up @@ -328,16 +338,9 @@ as so. There are at least 6 ancestors/descendant parsers between `list` and
`sexp`. It'd be very much pointless to show them all. They convey little
additional information and their labels are very verbose.

### `splicer.start` combinator

The reason why they don't appear is because `splicer` is used to make the
tree look a little cleaner.

The name comes from JS's `Array.prototype.splice`, to which you can give a
starting position, and a count specifying the end, and it'll remove the
specified elements from an Array. We use `splicer` likewise, only it works
on parse trees. To show an example, here's a simplified definition of
`choice`:
The reason why they don't appear is because the `splicer.start` combinator
is used to make the tree look a little cleaner. To show an example of how
it works, here's a simplified definition of `choice`:

```ruby
define_combinator :choice do |*ps|
Expand Down Expand Up @@ -383,7 +386,8 @@ clearer. Let's use `splicer` to remove those:
end
```

Let's fail it, again:
This makes the `p` parsers appear as direct children of the `splicer.start`
parser in the trace. Let's fail it, again:

```
pry(main)> choice(lit("foo"), lit("bar"), lit("baz")).parse "qux"
Expand All @@ -397,9 +401,10 @@ Parsby::ExpectationFailed: line 1:
| * failure: choice(lit("foo"), lit("bar"), lit("baz"))
```

Now, the only issue left is that `define_combinator` wraps the result of
the parser in another parser. Let's disable that wrapping by passing `wrap:
false` to it:
Now, the only issue left is that `define_combinator` wraps the resulting
parser in another parser. It does this so you can see the label assigned to
the combinator and to its definition separately. Let's disable that
wrapping by passing `wrap: false` to it:

```ruby
define_combinator :choice, wrap: false do |*ps|
Expand All @@ -413,6 +418,7 @@ false` to it:
end
```

That causes it to overwrite the label to the resulting parser of the block.
Let's fail it, again:

```
Expand Down

0 comments on commit dea8726

Please sign in to comment.