Skip to content

X-FRI/fringer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

+---------+
| Fringer |
+---------+

A lightweight parser-combinator library operating on `&str`.  
This crate provides a small set of basic parser primitives and combinators, 
allowing you to build complex parsers by composing simple ones.

Contents
--------
1. Overview  
2. Installation  
3. Usage Examples  
4. API Reference  
   4.1. Core Types  
   4.2. Primitives  
   4.3. Combinators  
   4.4. Initializers  
5. Testing  
6. Contributing  
7. License

1. Overview
-----------
This library defines:
- A `Parser<'a, T>` type: a boxed closure that consumes an `&'a str` and returns either a parsed value of type `T` plus the remaining input, or an error message.
- A `ParseResult<'a, T>` alias for `Result<(T, &'a str), String>`.
- A set of parser primitives (`parse_char`, `any_of`) for matching characters.
- A suite of combinators (`and_then`, `or_else`, `map`, `bind`, `apply`, `many`, `many1`, `opt`, `left`, `right`, `between`, `sep_by1`, `sep_by`) to build and transform parsers.
- Initializer functions (`lift2`, `sequence`, `choice`, `pure`) to lift functions and collections of parsers into composable units.

2. Installation
---------------
Add this library as a dependency in your `Cargo.toml`:

    [dependencies]
    fringer = "0.4.0"

3. Usage Examples
-----------------
Basic character parsing:

    use parser_combinators::primitives::ParserPrimitives;
    use parser_combinators::combinators::ParserCombinator;

    Parser::parse_char('a').run("abc")

Sequencing and choice:

    use parser_combinators::initializer::ParserInitializer;
    use parser_combinators::primitives::ParserPrimitives;
    use parser_combinators::combinators::ParserCombinator;

    // parse a b in sequence
    Parser::sequence(vec![Parser::parse_char('a'), Parser::parse_char('b')]).run("abcd")

    // parse either 'ab' or 'cd'
    Parser::choice(vec![
        Parser::parse_char('a')
            .and_then(Parser::parse_char('b'))
            .map(|(x, y)| format!("AB: {}{}", x, y)),
        Parser::parse_char('c')
            .and_then(Parser::parse_char('d'))
            .map(|(x, y)| format!("CD: {}{}", x, y)),
    ])

Combining functions:

    // lift a two-argument function
    let pair = Parser::lift2(|x,y| (x,y),
                             Parser::parse_char('x'),
                             Parser::parse_char('y'));

Repetition and optional:

    let many_a = Parser::parse_char('a').many();    // zero or more 'a'
    let some_a = Parser::parse_char('a').many1();   // one or more 'a'
    let opt_a  = Parser::parse_char('a').opt();     // optional 'a'

Separated lists:

    let comma_sep = Parser::parse_char(','); 
    let list1 = Parser::parse_char('a').sep_by1(comma_sep.clone());
    let list0 = Parser::parse_char('a').sep_by(comma_sep);

4. API Reference
----------------

4.1 Core Types
    type ParseResult<'a, T> = Result<(T, &'a str), String>
      - On success: `Ok((parsed_value, remaining_input))`
      - On failure: `Err(error_message)`

    struct Parser<'a, T>(Box<dyn Fn(&'a str) -> ParseResult<'a, T> + 'a>)
      - Wraps a closure implementing the parsing logic.
      - Construct with `Parser::new(f)`.

    Method:
      run(&self, input: &'a str) -> ParseResult<'a, T>

4.2 Primitives (`ParserPrimitives`)
    fn parse_char(expected: char) -> Parser<'a, char>
      - Matches exactly one character.
      - Error if no input or mismatch.

    fn any_of(chars: Vec<char>) -> Parser<'a, char>
      - Matches any one character from the provided set.
      - Error if no input or character not in set.

4.3 Combinators (`ParserCombinator`)
    fn and_then<B>(self, p: Parser<'a, B>) -> Parser<'a, (A, B)>

    fn or_else(self, p: Parser<'a, A>) -> Parser<'a, A>

    fn map<B, F>(self, f: F) -> Parser<'a, B> where F: Fn(A) -> B
    
    fn bind<B, F>(self, f: F) -> Parser<'a, B> where F: Fn(A) -> Parser<'a, B>
    
    fn apply<B, C>(self, pa: Parser<'a, B>) -> Parser<'a, C> where A: Fn(B) -> C
    
    fn many(self) -> Parser<'a, Vec<A>>

    fn many1(self) -> Parser<'a, Vec<A>>

    fn opt(self)   -> Parser<'a, Option<A>>

    fn left<B>(self, pb: Parser<'a, B>)  -> Parser<'a, A>

    fn right<B>(self, pb: Parser<'a, B>) -> Parser<'a, B>

    fn between<B, C>(self, p2: Parser<'a, B>, p3: Parser<'a, C>) -> Parser<'a, B>
    
    fn sep_by1<S>(self, sep: Parser<'a, S>) -> Parser<'a, Vec<A>>
    
    fn sep_by<S>(self, sep: Parser<'a, S>)  -> Parser<'a, Vec<A>>

4.4 Initializers (`ParserInitializer`)
    fn lift2<B, C, F>(f: F, pa: Parser<'a, A>, pb: Parser<'a, B>) -> Parser<'a, C> where F: Fn(A, B) -> C

    fn sequence(parsers: Vec<Parser<'a, A>>) -> Parser<'a, Vec<A>>

    fn choice(parsers: Vec<Parser<'a, A>>) -> Parser<'a, A>
      - Panics if the vector is empty.

    fn pure<F>(f: F) -> Parser<'a, A> where F: Fn() -> A
      - Always succeeds without consuming input.

5. Testing
----------
Unit tests are provided in `src/lib.rs`. Run them with:

    cargo test

They cover basic combinators, primitives, initializers, and error cases.

6. Contributing
---------------
Contributions, bug reports, and pull requests are welcome.  
Please follow standard Rust formatting (`rustfmt`) and ensure all tests pass.

7. License
----------
This project is licensed under the MIT License. See `LICENSE` for details.

About

A lightweight parser-combinator library operating on `&str`.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages