• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# nom, eating data byte by byte
2
3[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4[![Join the chat at https://gitter.im/Geal/nom](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Geal/nom?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5[![Build Status](https://github.com/Geal/nom/actions/workflows/ci.yml/badge.svg)](https://github.com/Geal/nom/actions/workflows/ci.yml)
6[![Coverage Status](https://coveralls.io/repos/github/Geal/nom/badge.svg?branch=master)](https://coveralls.io/github/Geal/nom?branch=master)
7[![Crates.io Version](https://img.shields.io/crates/v/nom.svg)](https://crates.io/crates/nom)
8[![Minimum rustc version](https://img.shields.io/badge/rustc-1.48.0+-lightgray.svg)](#rust-version-requirements)
9
10nom is a parser combinators library written in Rust. Its goal is to provide tools
11to build safe parsers without compromising the speed or memory consumption. To
12that end, it uses extensively Rust's *strong typing* and *memory safety* to produce
13fast and correct parsers, and provides functions, macros and traits to abstract most of the
14error prone plumbing.
15
16![nom logo in CC0 license, by Ange Albertini](https://raw.githubusercontent.com/Geal/nom/master/assets/nom.png)
17
18*nom will happily take a byte out of your files :)*
19
20## Example
21
22[Hexadecimal color](https://developer.mozilla.org/en-US/docs/Web/CSS/color) parser:
23
24```rust
25extern crate nom;
26use nom::{
27  IResult,
28  bytes::complete::{tag, take_while_m_n},
29  combinator::map_res,
30  sequence::tuple
31};
32
33#[derive(Debug,PartialEq)]
34pub struct Color {
35  pub red:   u8,
36  pub green: u8,
37  pub blue:  u8,
38}
39
40fn from_hex(input: &str) -> Result<u8, std::num::ParseIntError> {
41  u8::from_str_radix(input, 16)
42}
43
44fn is_hex_digit(c: char) -> bool {
45  c.is_digit(16)
46}
47
48fn hex_primary(input: &str) -> IResult<&str, u8> {
49  map_res(
50    take_while_m_n(2, 2, is_hex_digit),
51    from_hex
52  )(input)
53}
54
55fn hex_color(input: &str) -> IResult<&str, Color> {
56  let (input, _) = tag("#")(input)?;
57  let (input, (red, green, blue)) = tuple((hex_primary, hex_primary, hex_primary))(input)?;
58
59  Ok((input, Color { red, green, blue }))
60}
61
62fn main() {}
63
64#[test]
65fn parse_color() {
66  assert_eq!(hex_color("#2F14DF"), Ok(("", Color {
67    red: 47,
68    green: 20,
69    blue: 223,
70  })));
71}
72```
73
74## Documentation
75
76- [Reference documentation](https://docs.rs/nom)
77- [Various design documents and tutorials](https://github.com/Geal/nom/tree/master/doc)
78- [List of combinators and their behaviour](https://github.com/Geal/nom/blob/master/doc/choosing_a_combinator.md)
79
80If you need any help developing your parsers, please ping `geal` on IRC (libera, geeknode, oftc), go to `#nom-parsers` on Libera IRC, or on the [Gitter chat room](https://gitter.im/Geal/nom).
81
82## Why use nom
83
84If you want to write:
85
86### Binary format parsers
87
88nom was designed to properly parse binary formats from the beginning. Compared
89to the usual handwritten C parsers, nom parsers are just as fast, free from
90buffer overflow vulnerabilities, and handle common patterns for you:
91
92- [TLV](https://en.wikipedia.org/wiki/Type-length-value)
93- Bit level parsing
94- Hexadecimal viewer in the debugging macros for easy data analysis
95- Streaming parsers for network formats and huge files
96
97Example projects:
98
99- [FLV parser](https://github.com/rust-av/flavors)
100- [Matroska parser](https://github.com/rust-av/matroska)
101- [tar parser](https://github.com/Keruspe/tar-parser.rs)
102
103### Text format parsers
104
105While nom was made for binary format at first, it soon grew to work just as
106well with text formats. From line based formats like CSV, to more complex, nested
107formats such as JSON, nom can manage it, and provides you with useful tools:
108
109- Fast case insensitive comparison
110- Recognizers for escaped strings
111- Regular expressions can be embedded in nom parsers to represent complex character patterns succinctly
112- Special care has been given to managing non ASCII characters properly
113
114Example projects:
115
116- [HTTP proxy](https://github.com/sozu-proxy/sozu/blob/master/lib/src/protocol/http/parser.rs)
117- [TOML parser](https://github.com/joelself/tomllib)
118
119### Programming language parsers
120
121While programming language parsers are usually written manually for more
122flexibility and performance, nom can be (and has been successfully) used
123as a prototyping parser for a language.
124
125nom will get you started quickly with powerful custom error types, that you
126can leverage with [nom_locate](https://github.com/fflorent/nom_locate) to
127pinpoint the exact line and column of the error. No need for separate
128tokenizing, lexing and parsing phases: nom can automatically handle whitespace
129parsing, and construct an AST in place.
130
131Example projects:
132
133- [PHP VM](https://github.com/tagua-vm/parser)
134- eve language prototype
135- [xshade shading language](https://github.com/xshade-lang/xshade/)
136
137### Streaming formats
138
139While a lot of formats (and the code handling them) assume that they can fit
140the complete data in memory, there are formats for which we only get a part
141of the data at once, like network formats, or huge files.
142nom has been designed for a correct behaviour with partial data: If there is
143not enough data to decide, nom will tell you it needs more instead of silently
144returning a wrong result. Whether your data comes entirely or in chunks, the
145result should be the same.
146
147It allows you to build powerful, deterministic state machines for your protocols.
148
149Example projects:
150
151- [HTTP proxy](https://github.com/sozu-proxy/sozu/blob/master/lib/src/protocol/http/parser.rs)
152- [Using nom with generators](https://github.com/Geal/generator_nom)
153
154## Parser combinators
155
156Parser combinators are an approach to parsers that is very different from
157software like [lex](https://en.wikipedia.org/wiki/Lex_(software)) and
158[yacc](https://en.wikipedia.org/wiki/Yacc). Instead of writing the grammar
159in a separate file and generating the corresponding code, you use very
160small functions with very specific purpose, like "take 5 bytes", or
161"recognize the word 'HTTP'", and assemble them in meaningful patterns
162like "recognize 'HTTP', then a space, then a version".
163The resulting code is small, and looks like the grammar you would have
164written with other parser approaches.
165
166This has a few advantages:
167
168- The parsers are small and easy to write
169- The parsers components are easy to reuse (if they're general enough, please add them to nom!)
170- The parsers components are easy to test separately (unit tests and property-based tests)
171- The parser combination code looks close to the grammar you would have written
172- You can build partial parsers, specific to the data you need at the moment, and ignore the rest
173
174## Technical features
175
176nom parsers are for:
177- [x] **byte-oriented**: The basic type is `&[u8]` and parsers will work as much as possible on byte array slices (but are not limited to them)
178- [x] **bit-oriented**: nom can address a byte slice as a bit stream
179- [x] **string-oriented**: The same kind of combinators can apply on UTF-8 strings as well
180- [x] **zero-copy**: If a parser returns a subset of its input data, it will return a slice of that input, without copying
181- [x] **streaming**: nom can work on partial data and detect when it needs more data to produce a correct result
182- [x] **descriptive errors**: The parsers can aggregate a list of error codes with pointers to the incriminated input slice. Those error lists can be pattern matched to provide useful messages.
183- [x] **custom error types**: You can provide a specific type to improve errors returned by parsers
184- [x] **safe parsing**: nom leverages Rust's safe memory handling and powerful types, and parsers are routinely fuzzed and tested with real world data. So far, the only flaws found by fuzzing were in code written outside of nom
185- [x] **speed**: Benchmarks have shown that nom parsers often outperform many parser combinators library like Parsec and attoparsec, some regular expression engines and even handwritten C parsers
186
187Some benchmarks are available on [Github](https://github.com/Geal/nom_benchmarks).
188
189## Rust version requirements
190
191The 7.0 series of nom supports **Rustc version 1.48 or greater**. It is known to work properly on Rust 1.41.1 but there is no guarantee it will stay the case through this major release.
192
193The current policy is that this will only be updated in the next major nom release.
194
195## Installation
196
197nom is available on [crates.io](https://crates.io/crates/nom) and can be included in your Cargo enabled project like this:
198
199```toml
200[dependencies]
201nom = "7"
202```
203
204There are a few compilation features:
205
206* `alloc`: (activated by default) if disabled, nom can work in `no_std` builds without memory allocators. If enabled, combinators that allocate (like `many0`) will be available
207* `std`: (activated by default, activates `alloc` too) if disabled, nom can work in `no_std` builds
208
209You can configure those features like this:
210
211```toml
212[dependencies.nom]
213version = "7"
214default-features = false
215features = ["alloc"]
216```
217
218# Related projects
219
220- [Get line and column info in nom's input type](https://github.com/fflorent/nom_locate)
221- [Using nom as lexer and parser](https://github.com/Rydgel/monkey-rust)
222
223# Parsers written with nom
224
225Here is a (non exhaustive) list of known projects using nom:
226
227- Text file formats: [Ceph Crush](https://github.com/cholcombe973/crushtool),
228[Cronenberg](https://github.com/ayrat555/cronenberg),
229[XFS Runtime Stats](https://github.com/ChrisMacNaughton/xfs-rs),
230[CSV](https://github.com/GuillaumeGomez/csv-parser),
231[FASTA](https://github.com/TianyiShi2001/nom-fasta),
232[FASTQ](https://github.com/elij/fastq.rs),
233[INI](https://github.com/Geal/nom/blob/master/tests/ini.rs),
234[ISO 8601 dates](https://github.com/badboy/iso8601),
235[libconfig-like configuration file format](https://github.com/filipegoncalves/rust-config),
236[Web archive](https://github.com/sbeckeriv/warc_nom_parser),
237[PDB](https://github.com/TianyiShi2001/nom-pdb),
238[proto files](https://github.com/tafia/protobuf-parser),
239[Fountain screenplay markup](https://github.com/adamchalmers/fountain-rs),
240[vimwiki](https://github.com/chipsenkbeil/vimwiki-server/tree/master/vimwiki) & [vimwiki_macros](https://github.com/chipsenkbeil/vimwiki-server/tree/master/vimwiki_macros)
241- Programming languages:
242[PHP](https://github.com/tagua-vm/parser),
243[Basic Calculator](https://github.com/balajisivaraman/basic_calculator_rs),
244[GLSL](https://github.com/phaazon/glsl),
245[Lua](https://github.com/doomrobo/nom-lua53),
246[Python](https://github.com/ProgVal/rust-python-parser),
247[SQL](https://github.com/ms705/nom-sql),
248[Elm](https://github.com/cout970/Elm-interpreter),
249[SystemVerilog](https://github.com/dalance/sv-parser),
250[Turtle](https://github.com/vandenoever/rome/tree/master/src/io/turtle),
251[CSML](https://github.com/CSML-by-Clevy/csml-interpreter),
252[Wasm](https://github.com/Strytyp/wasm-nom),
253[Pseudocode](https://github.com/Gungy2/pseudocode)
254- Interface definition formats: [Thrift](https://github.com/thehydroimpulse/thrust)
255- Audio, video and image formats:
256[GIF](https://github.com/Geal/gif.rs),
257[MagicaVoxel .vox](https://github.com/davidedmonds/dot_vox),
258[midi](https://github.com/derekdreery/nom-midi-rs),
259[SWF](https://github.com/open-flash/swf-parser),
260[WAVE](http://github.com/noise-Labs/wave),
261[Matroska (MKV)](https://github.com/rust-av/matroska)
262- Document formats:
263[TAR](https://github.com/Keruspe/tar-parser.rs),
264[GZ](https://github.com/nharward/nom-gzip)
265- Cryptographic formats:
266[X.509](https://github.com/rusticata/x509-parser)
267- Network protocol formats:
268[Bencode](https://github.com/jbaum98/bencode.rs),
269[D-Bus](https://github.com/toshokan/misato),
270[DHCP](https://github.com/rusticata/dhcp-parser),
271[HTTP](https://github.com/sozu-proxy/sozu/tree/master/lib/src/protocol/http),
272[URI](https://github.com/santifa/rrp/blob/master/src/uri.rs),
273[IMAP](https://github.com/djc/tokio-imap),
274[IRC](https://github.com/Detegr/RBot-parser),
275[Pcap-NG](https://github.com/richo/pcapng-rs),
276[Pcap](https://github.com/ithinuel/pcap-rs),
277[Pcap + PcapNG](https://github.com/rusticata/pcap-parser),
278[IKEv2](https://github.com/rusticata/ipsec-parser),
279[NTP](https://github.com/rusticata/ntp-parser),
280[SNMP](https://github.com/rusticata/snmp-parser),
281[Kerberos v5](https://github.com/rusticata/kerberos-parser),
282[DER](https://github.com/rusticata/der-parser),
283[TLS](https://github.com/rusticata/tls-parser),
284[IPFIX / Netflow v10](https://github.com/dominotree/rs-ipfix),
285[GTP](https://github.com/fuerstenau/gorrosion-gtp),
286[SIP](https://github.com/armatusmiles/sipcore/tree/master/crates/sipmsg),
287[Prometheus](https://github.com/timberio/vector/blob/master/lib/prometheus-parser/src/line.rs)
288- Language specifications:
289[BNF](https://github.com/snewt/bnf)
290- Misc formats:
291[Gameboy ROM](https://github.com/MarkMcCaskey/gameboy-rom-parser),
292[ANT FIT](https://github.com/stadelmanma/fitparse-rs),
293[Version Numbers](https://github.com/fosskers/rs-versions),
294[Telcordia/Bellcore SR-4731 SOR OTDR files](https://github.com/JamesHarrison/otdrs),
295[MySQL binary log](https://github.com/PrivateRookie/boxercrab),
296[URI](https://github.com/Skasselbard/nom-uri),
297[Furigana](https://github.com/sachaarbonel/furigana.rs)
298
299Want to create a new parser using `nom`? A list of not yet implemented formats is available [here](https://github.com/Geal/nom/issues/14).
300
301Want to add your parser here? Create a pull request for it!
302
303# Contributors
304
305nom is the fruit of the work of many contributors over the years, many thanks for your help!
306
307<a href="https://github.com/geal/nom/graphs/contributors">
308  <img src="https://contributors-img.web.app/image?repo=geal/nom" />
309</a>
310