Skip to content

Commit 283ab8b

Browse files
committed
Better docs
1 parent f7b2c08 commit 283ab8b

1 file changed

Lines changed: 13 additions & 52 deletions

File tree

lib/nimble_parsec.ex

Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -471,10 +471,8 @@ defmodule NimbleParsec do
471471
472472
`parsec/2` is useful to implement recursive definitions.
473473
474-
Note, while `parsec/2` can be used to compose smaller combinators,
475-
the preferred mechanism for doing composition is via regular functions
476-
and not via `parsec/2`. Let's see a practical example. Imagine
477-
that you have this module:
474+
`parsec/2` is also useful to compile *large* combinators upfront,
475+
therefore reducing compilation time. Imagine that you have this module:
478476
479477
defmodule MyParser do
480478
import NimbleParsec
@@ -497,9 +495,8 @@ defmodule NimbleParsec do
497495
defparsec :datetime, date |> ignore(string("T")) |> concat(time), debug: true
498496
end
499497
500-
Now imagine that you want to break `date` and `time` apart
501-
into helper functions, as you use them in other occasions.
502-
Generally speaking, you should **NOT** do this:
498+
If you use `date` and `time` as combinators, over and over again,
499+
it may be beneficial to compile and reuse them:
503500
504501
defmodule MyParser do
505502
import NimbleParsec
@@ -523,52 +520,16 @@ defmodule NimbleParsec do
523520
parsec(:date) |> ignore(string("T")) |> concat(parsec(:time))
524521
end
525522
526-
The reason why the above is not recommended is because each
527-
`parsec/2` combinator ends-up adding a stacktrace entry during
528-
parsing, which affects the ability of `NimbleParsec` to optimize
529-
code. If the goal is to compose combinators, you can do so
530-
with modules and functions:
523+
While the `date` and `time` above are likely too small to be worthy
524+
of compiling into a separate combinator in practice, that's the general
525+
approach one should take. In practice, it is best to build your parser
526+
and combinators without `parsec/2`, and then, as compile-time increases,
527+
you find the largest combinators which are used multiple times and
528+
refactor them as `parsec/2`.
531529
532-
defmodule MyParser.Helpers do
533-
import NimbleParsec
534-
535-
def date do
536-
integer(4)
537-
|> ignore(string("-"))
538-
|> integer(2)
539-
|> ignore(string("-"))
540-
|> integer(2)
541-
end
542-
543-
def time do
544-
integer(2)
545-
|> ignore(string(":"))
546-
|> integer(2)
547-
|> ignore(string(":"))
548-
|> integer(2)
549-
|> optional(string("Z"))
550-
end
551-
end
552-
553-
defmodule MyParser do
554-
import NimbleParsec
555-
import MyParser.Helpers
556-
557-
defparsec :datetime,
558-
date() |> ignore(string("T")) |> concat(time())
559-
end
560-
561-
The implementation above will be able to compile to the most
562-
efficient format as possible without forcing new stacktrace
563-
entries.
564-
565-
The only situation where you should use `parsec/2` for composition
566-
is when a large parser is used over and over again in a way
567-
compilation times are high. In this sense, you can use `parsec/2`
568-
to improve compilation time at the cost of runtime performance.
569-
By using `parsec/2`, the tree size built at compile time will be
570-
reduced although runtime performance is degraded as `parsec`
571-
introduces a stacktrace entry.
530+
Overall, you can use `parsec/2` to improve compilation time at the cost
531+
of runtime performance. By using `parsec/2`, the tree size built at compile
532+
time will be reduced although runtime performance is slightly degraded.
572533
573534
## Remote combinators
574535

0 commit comments

Comments
 (0)