Comments (12)
From reddit https://www.reddit.com/r/rust/comments/6s792a/combine_250_and_300alpha1/dlcgy0l/
Macros vs traits is the most visible difference but that is for the most part just syntax. I think traits still increase compile times to some extent but I would argue it is fairly negligible at this point (barring a regression in rustc which happened ~1 week ago in rustc rust-lang/rust#43613).
That combine uses traits used to be awkward when writing small reusable parsers, but with addition of the parser! macro I would argue that has been more or less completely solved (and with impl Trait it will be completely solved)
For more qualitative differences. combine back in 1.0.0 used to be noticeably slower than nom since I aimed for it to produce good errors. That slowness was fixed almost entirely in 2.0.0 (without sacrificing any error information, modulo the bug which was fixed in 3.0.0) however with combine only being a few percent slower on the benchmarks I ran. From what I can gather, these few percents come down to combine generating more or just more complex drop glue compared to nom. With 3.0.0 combine will be able break even or overtake nom by a few percent (as long as nothing else changes) if one opts for cheaper/more specialized errors.
Due to combine not focusing on fast byte level parsers immediately it used to lack conveniences for that but I think it should be pretty close now that integer parsers are added. I believe nom also has bit-level parsers which is something that combine do not have.
nom has some facilities for writing state machines to feed input into the parser which combine do not have. I have never had a need for this so I didn't want to commit to a flawed and unused design. If someone needs something like that I would be interested in some discussion though!
combine has a lot better input reading facilities since it can handle everything between Iterator and std::io::Read to already in memory inputs such as&[T] or &str. nom on the other hand only supports &[T] (&[u8]?) and &str.
Just because I think it is worth mentioning again, combines error reporting is a lot better for the effort put in when writing parsers.
In combine
char('!').or(digit()).or(letter())
.parse("?")// Unexpected '?' expected '!', 'digit' or 'letter'.
char('!').or(digit()).or(letter())
.expected("something")
.parse("?")// Unexpected '?' expected 'something'
In nom you get one or several error codes which need to be returned manually and handled separately. Though you can probably get nice errors, it is not without a lot of work. (Please correct me if I have misunderstood anything about this)
https://github.com/Geal/nom/blob/master/doc/error_management.md#error-management
combine is a lot smaller than nom but its tutorial(s) could be expanded (Markdown).
$ tokei nom
-------------------------------------------------------------------------------
Language Files Lines Code Comments Blanks
--------------------------------51 2451 0 0
Rust 40 17646 13015 2934 1697
Plain Text 2 32 32 0 0
TOML 1 54 42 3 9
-------------------------------------------------------------------------------
Total 53 20183 15540 2937 1706
-------------------------------------------------------------------------------
$ tokei combine
-------------------------------------------------------------------------------
Language Files Lines Code Comments Blanks
-------------------------------------------------------------------------------
JSON 1 317 317 0 0
Markdown 2 271 271 0 0
Rust 16 8943 6053 2200 690
sh 1 8 6 1 1
Plain Text 1 494 494 0 0
TOML 2 53 37 1 15
-------------------------------------------------------------------------------
Total 23 10086 7178 2202 706
-------------------------------------------------------------------------------
nom has a lot of parsers already written in it which is something that should not be underestimated when deciding on a library https://github.com/Geal/nom#parsers-written-with-nom.
from combine.
I don't like macros, it's hard to read and understand, especially macros in macros.
I tried combine; but there is a lot of things that I don't know which situation should to use them.
from combine.
Its a bit short but I made this comment on reddit a while back https://www.reddit.com/r/rust/comments/58nmzg/combine200_now_a_fast_parser_combinator_library/d9343n3/. Might be worthwhile to make a more through comparison but I dunno.
from combine.
how does nom stack against parsers combinators based on structs ? , the author of pom claims they are inherently better .
from combine.
will combine continue to be dependant on the parser macro to do away with bloat ?
i am interested in parser combinators as a metaprogramming alternative to macros ( building a modular compiler based upon them ? )
from combine.
Both result in slower compilation that macro based ones ( due to reliance on zero abstractions to compile away intermediate data structures and traits , respectively ) , but which one will be benefited the most from rustc advancements ( caching compiler , more rust specific abstractions , other ones which have only been planed )
from combine.
how does nom stack against parsers combinators based on structs ? , the author of pom claims they are inherently better .
It is about the same, a few percent in either direction on equivalent parsers. Debugging should be better with structs though as it says in the POM readme.
will combine continue to be dependant on the parser macro to do away with bloat ?
Once impl Trait
gets to stable the macro will no longer be necessary. If you are fine with using nightly then you can just use impl Trait
today and ignore it.
i am interested in parser combinators as a metaprogramming alternative to macros ( building a modular compiler based upon them ? )
Since combines parsers need to be statically defined there are limits to its flexibilty in metaprogramming since you will need to define all parsers you may need at compile time.
Both result in slower compilation that macro based ones ( due to reliance on zero abstractions to compile away intermediate data structures and traits , respectively ) , but which one will be benefited the most from rustc advancements ( caching compiler , more rust specific abstractions , other ones which have only been planed )
They should get the same sort of speedups percentagewise of their current compile times (though since combine is slower to compile now, it will benefit more in absolute terms).
from combine.
Thanks for your quick response
from combine.
So combine will achieve the same with less code , and continue to improve its compilation time but end up slower ?
from combine.
I think combine and nom are fairly similar in how much code users need to write. What i meant above is that combine has a much smaller and approachable code base.
With equivalently constructed parser then combine will likely always be somewhat slower to compile due to typechecking. Only way it can be faster is that combine might let you construct a smaller parser (and thus less code to compile) than nom is able to.
Do consider that part of the reason that combine is slower to compile is that it has a lot more flexibility to how and what it parsers.
from combine.
" it has a lot more flexibility "
You mean compared to both nom and pom ? isn't the latter built with a different approach ( or am i miss understanding the implications of peg ? )
from combine.
You mean compared to both nom and pom ?
Yeah, nom and pom only handles &str
and &[T]
while gluon can handle anything implementing StreamOnce (and a few other Stream*
traits). This extra flexibility makes the instantiated types larger and thus it takes longer to compile.
from combine.
Related Issues (20)
- Is there a way to get `Stream<Token=char>` from `io::Read`? HOT 1
- Tools for debugging recursion problems? HOT 4
- Some issue with error reporting
- Errors include unprintable or awkwardly printed characters. HOT 6
- `expected` error strings always quote what was expected, even if it isn't a literal HOT 3
- How about offset into some data? HOT 3
- Outdated tutorial HOT 1
- Native/abstracted sub-parsers HOT 6
- XML parsing for React.js to Solid.js conversion HOT 4
- Comparison with LALRPOP
- Unbounded mutual recursion in Parser impl HOT 3
- Adivce on reducing code size in WASM target HOT 7
- Docs unclear whether `parser!` should be used on nightly rust HOT 2
- Parse `std::process::Child` stdout
- Successful parser will not clear the error stack HOT 1
- build failure
- Implement Pratt parsing or precedence climbing HOT 4
- Choice with Vec of parsers HOT 4
- Documentation request: no_partial
- Worse performance after parsing 2 large values HOT 9
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from combine.