• Stars
    star
    127
  • Rank 282,790 (Top 6 %)
  • Language
    Rust
  • License
    MIT License
  • Created about 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Yet Another Parser library for Rust. A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing strings and slices.

Yap: Yet another (rust) parsing library

API docs

This small, zero-dependency crate helps you to parse input strings, slices and (some) iterators of tokens by building on the Iterator interface.

The aim of this crate is to provide the sorts of functions you'd come to expect from a parser combinator library, but without immersing you into a world of parser combinators, and forcing you to use a novel return type, library-provided errors or parser-combinator based control flow. It hopes to sacrifice conciseness in exchange for simplicity.

Some specific features/goals:

  • Lots of examples. Every function provided comes with example usage.
  • Prioritise simplicity at the cost of verbosity.
  • Be iterator-centric. Where applicable, combinators return iterators, so you can lean on the Iterator interface to parse as much or as little as you want from the input, and collect up the output however you wish.
  • Allow user defined errors to be returned anywhere that it might make sense. Some functions have _err variants incase you need error information when they don't otherwise hand back errors for simplicity.
  • Location information should always be available, so that you can tell users where something went wrong. see Tokens::offset
  • Backtracking by default. Coming from Haskell's Parsec, this feels like the sensible default. It means that if one of the provided parsing functions fails to parse what you asked for, it won't consume any input trying.
  • Expose all of the "low level" functions. You can save and rewind to locations as needed (see Token::location), and implement ant of the provided functions using these primitives.
  • Aims to be "fairly quick". Avoids allocations (and allows you to do the same via the iterator-centric interface). If you need "as fast as you can get", there are probably quicker alternatives.

Have a look at the Tokens trait for all of the parsing methods made available, and examples for each.

Have a look in the examples folder for more in depth examples.

Example

use yap::{
    // This trait has all of the parsing methods on it:
    Tokens,
    // Allows you to use `.into_tokens()` on strings and slices,
    // to get an instance of the above:
    IntoTokens
};

// Step 1: convert our input into something implementing `Tokens`
// ================================================================

let mut tokens = "10 + 2 x 12-4,foobar".into_tokens();

// Step 2: Parse some things from our tokens
// =========================================

#[derive(PartialEq,Debug)]
enum Op { Plus, Minus, Multiply }
#[derive(PartialEq,Debug)]
enum OpOrDigit { Op(Op), Digit(u32) }

// The `Tokens` trait builds on `Iterator`, so we get a `next` method.
fn parse_op(t: &mut impl Tokens<Item=char>) -> Option<Op> {
    match t.next()? {
        '-' => Some(Op::Minus),
        '+' => Some(Op::Plus),
        'x' => Some(Op::Multiply),
        _ => None
    }
}

// We also get other useful functions..
fn parse_digits(t: &mut impl Tokens<Item=char>) -> Option<u32> {
    let s: String = t
        .tokens_while(|c| c.is_digit(10))
        .collect();
    s.parse().ok()
}

// As well as combinator functions like `sep_by_all` and `surrounded_by`..
let op_or_digit = tokens.sep_by_all(
    |t| t.surrounded_by(
        |t| parse_digits(t).map(OpOrDigit::Digit),
        |t| { t.skip_tokens_while(|c| c.is_ascii_whitespace()); }
    ),
    |t| parse_op(t).map(OpOrDigit::Op)
);

// Now we've parsed our input into OpOrDigits, let's calculate the result..
let mut current_op = Op::Plus;
let mut current_digit = 0;
for d in op_or_digit {
    match d {
        OpOrDigit::Op(op) => {
            current_op = op
        },
        OpOrDigit::Digit(n) => {
            match current_op {
                Op::Plus => { current_digit += n },
                Op::Minus => { current_digit -= n },
                Op::Multiply => { current_digit *= n },
            }
        },
    }
}
assert_eq!(current_digit, 140);

// Step 3: do whatever you like with the rest of the input!
// ========================================================

// This is available on the concrete type that strings
// are converted into (rather than on the `Tokens` trait):
let remaining = tokens.remaining();

assert_eq!(remaining, ",foobar");

More Repositories

1

weave

A simple CLI router for wiring together several sources behind a single HTTP endpoint
Rust
141
star
2

angu

A small DSL/interpreter that can be used to evaluate simple expressions
TypeScript
122
star
3

wasm-fractal

A Rust (compiled to WASM) + JS multi-threaded in-browser fractal generator
JavaScript
77
star
4

seamless

An opinionated Rust library for creating simple JSON APIs that communicate over HTTP
Rust
24
star
5

fuss

A Functional CSS Preprocessor
Rust
14
star
6

git-backup

A tool to help you backup your git repositories from services like GitHub
Rust
12
star
7

jsdw.me

My homepage
Haskell
10
star
8

hs-commander

A nested command parsing tool for Haskell
Haskell
7
star
9

cpp-sequitur

A C++ implementation of the sequitur compression algorithm
C++
5
star
10

talklicker

A small Haskell+Elm event scheduling app
CSS
4
star
11

advent-of-code-2018

Solutions for Advent of Code 2018
Rust
3
star
12

depends

A small, versatile, and thread safe dependency injection library for Go
Go
3
star
13

highscore

A simple app for helping to track high scores
Rust
3
star
14

tl-asset-browser

A basic Elm implementation of a Third Light asset browser
JavaScript
3
star
15

folder-content-aggregator

A quick Go/Rust implementation of a robust aggregated folder watching tool
Rust
2
star
16

anagrammer

Find line-anagrams in an ASCII formatted text file (excluding lines where all words match)
Rust
2
star
17

undigits

A quick app to solve the NYTimes Digits puzzle
TypeScript
2
star
18

advent-of-code-2022

Rust
2
star
19

vault-inject

A utility for automatically pulling secrets out of vault and injecting them into shell commands
Rust
2
star
20

advent-of-code-2019

Solutions to AoC 2019
Rust
2
star
21

promiseWorker

Wrapping JS Web Workers into Promises for quick inline concurrent JS in modern browsers.
JavaScript
1
star
22

slackup

A quick tool to download/backup conversations from slack
Rust
1
star
23

hs-hipchat-to-websocket

Connects hipchat protocol with a simple websocket one. Provides addon information so that hipchat can install them. Multiple addons supported via config.
Haskell
1
star
24

boundvariable

My shot as the ICFP '06 programming challenge
Rust
1
star
25

gh-tools-project-sync

Sync Tools Team milestones to project boards
Rust
1
star
26

js-compression-machine

Compress files right in your browser and then decompress them again. An experiment in compression algorithms.
JavaScript
1
star
27

hs-websocket-bot2

Version 2 of my Websocket based Chatbot. Cleaner and better than the original.
Haskell
1
star