Skip to content

Commit f7b2c08

Browse files
committed
Document performance considerations, closes #149
1 parent cc7bbfd commit f7b2c08

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ clauses with binary matching. This provides the following benefits:
2626
the possibility to compile parsers and do not impose a dependency on
2727
users of your library
2828

29-
* No footprints: `NimbleParsec` only needs to be imported in your modules.
30-
There is no need for `use NimbleParsec`, leaving no footprints on your
31-
modules
32-
3329
The goal of this library is to focus on a set of primitives for writing
3430
efficient parser combinators. The composition aspect means you should be
3531
able to use those primitives to implement higher level combinators.
@@ -113,6 +109,31 @@ hand-written parsers. This gives `NimbleParsec` an order of magnitude
113109
performance gains compared to other parser combinators. Further performance
114110
can be gained by giving the `inline: true` option to `defparsec/3`.
115111

112+
## Performance considerations
113+
114+
This library works by aggressively inlining code. For example, when we defined `date` and `time` combinators above, if you happen to use them in different occasions as follows, they will be inlined and compiled multiple times:
115+
116+
```elixir
117+
date_then_time = concat(date, time)
118+
time_then_date = concat(time, date)
119+
defparsec :combinations, choice([date_then_time, time_then_date])
120+
```
121+
122+
Because each `date` and `time` node appears twice, they will be compiled twice. This means that reusing combinators over and over again can lead to memory usage during compilation as well as high compile times.
123+
124+
To address this, `NimbleParsec` allows you to encapsulate combinators and reuse them, using `defpcombinatorp`:
125+
126+
```elixir
127+
defcombinatorp :date, ...
128+
defcombinatorp :time, ...
129+
130+
date_then_time = concat(parsec(:date), parsec(:time))
131+
time_then_date = concat(parsec(:time), parsec(:date))
132+
defparsec :combinations, choice([date_then_time, time_then_date])
133+
```
134+
135+
By using `parsec(:date)` and `parsec(:time)`, we point to previously defined and compiled combinators, leading to better compile-time performance.
136+
116137
<!-- MDOC !-->
117138

118139
## Installation

0 commit comments

Comments
 (0)