20 breaking releases

new 0.21.0 Jan 28, 2025
0.19.0 Jan 15, 2025
0.16.0 Dec 29, 2024
0.14.0 Jun 27, 2024
0.6.0 Dec 19, 2023

#91 in Parser tooling

Download history 1/week @ 2024-10-29 2/week @ 2024-11-05 2/week @ 2024-12-10 258/week @ 2024-12-24 8/week @ 2024-12-31 157/week @ 2025-01-07 241/week @ 2025-01-14 131/week @ 2025-01-21

552 downloads per month
Used in html-string

MIT license

24KB
495 lines

bparse

A combinatorial approach to matching slices, especially useful for writing lexers and tokenizers.

The crate borrows concepts from other parser-combinator crates but heavily simplifies things by eschewing error management and focusing exclusively on parsing in-memory buffers.


lib.rs:

Overview

Parsing usually involves going through a sequence of items and branching off based on the element that was seen. This crate simplifies the task of recognizing complex patterns in a slices. It works with any type of slice.

It is made up of three parts:

  1. The Pattern trait: represents the pattern to be recognized.
  2. A list of common functions and combinators for composing Patterns together.
  3. The SliceReader struct; a Cursor-like wrapper around an input slice that uses patterns to advance its position.

Example

Recognizing JSON numbers can get tricky. The spec allows for numbers like 12, -398.42, and even 12.4e-3. Here we incrementally build up a pattern called number that can recognizes all JSON number forms.

use bparse::{SliceReader, Pattern, range, at_least, optional, byte::oneof};

let sign = optional(oneof(b"-+"));
let onenine = range(b'1', b'9');
let digit = "0".or(onenine);
let digits = at_least(1, digit);
let fraction = optional(".".then(digits));
let exponent = optional("E".then(sign).then(digits).or("e".then(sign).then(digits)));
let integer = onenine
    .then(digits)
    .or("-".then(onenine).then(digits))
    .or("-".then(digit))
    .or(digit);
let number = integer.then(fraction).then(exponent);

let input = b"234||344.5||0.43e12";

let mut reader = SliceReader::new(input);

let Some(b"234") = reader.parse(number) else {
    panic!();
};

assert!(reader.accept("||"));

let Some(b"344.5") = reader.parse(number) else {
    panic!();
};

assert!(reader.accept("||"));

let Some(b"0.43e12") = reader.parse(number) else {
    panic!();
};

assert!(reader.eof());

No runtime deps