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