lexpar 0.1.0

Lexer and parser crate for stable Rust. This implementation favors compile-time over run-time for generating grammars.
Documentation
#[macro_use]
extern crate lexpar;

use lexpar::lexer::Lexer;

#[derive(Debug, PartialEq)]
enum Kw {
    Fn,
    Let
}

impl Kw {
    fn pattern() -> &'static str {
        "fn|let"
    }
}

impl<'a> ::std::convert::From<&'a str> for Kw {
    fn from(s: &'a str) -> Kw {
        match s {
            "fn" => Kw::Fn,
            "let" => Kw::Let,
            _ => unreachable!()
        }
    }
}

#[derive(Debug, PartialEq)]
enum Token {
    Whitespace(String),
    Comment(String),
    Keyword(Kw),
    Ident(String),
    Float(f32),
    Integer(i32),
    Text(String),
    LParen,
    RParen,
    LBracket,
    RBracket,
    LBrace,
    RBrace,
    Plus,
    Minus,
    Asterisk,
    FSlash,
    Arrow,
    Assign,
    Unknown(String)
}
use self::Token::*;

#[test]
fn some_tokens() {
    let lex = Lexer::new(lex_rules![
        r"[ \t\n]+"                 => |span, text, _| (span, Whitespace(text.to_owned())),
        r"/\*[^(?:*/)]*\*/"         => |span, text, _| (span, Comment(text[2..text.len() - 2].to_owned())),
        r"//[^\n]*"                 => |span, text, _| (span, Comment(text[2..].to_owned())),
        Kw::pattern()               => |span, text, _| (span, Keyword(Kw::from(text))),
        r"[_a-zA-Z][_a-zA-Z0-9]*"   => |span, text, _| (span, Ident(text.to_owned())),
        r"-?[0-9]+\.[0-9]*"         => |span, text, _| (span, Float(text.parse().unwrap())),
        r"-?[0-9]+"                 => |span, text, _| (span, Integer(text.parse().unwrap())),
        r#""(.*)""#                 => |span, _, caps| (span, Text(caps[0].to_owned())),
        r"->"                       => |span, _, _| (span, Arrow),
        r"="                        => |span, _, _| (span, Assign),
        r"\("                       => |span, _, _| (span, LParen),
        r"\)"                       => |span, _, _| (span, RParen),
        r"\["                       => |span, _, _| (span, LBracket),
        r"\]"                       => |span, _, _| (span, RBracket),
        r"\{"                       => |span, _, _| (span, LBrace),
        r"\}"                       => |span, _, _| (span, RBrace),
        r"\+"                       => |span, _, _| (span, Plus),
        r"\-"                       => |span, _, _| (span, Minus),
        r"\*"                       => |span, _, _| (span, Asterisk),
        r"/"                        => |span, _, _| (span, FSlash)
    ], |span, text| (span, Unknown(text.to_owned())));

    let tokens = lex.src_iter(
        r#"
        {*/}[+(he
        _llo)-12.5h3]/*multi
        line
        comment
        */
        "string"
        -10 5
        //hello fdsf
        //|
        "#).collect::<Vec<_>>();

    assert_eq!(tokens[2].1, Token::Asterisk);
    assert_eq!(tokens[12].1, Token::Float(-12.5));
    assert_eq!(tokens[17].1, Token::Text("string".to_owned()));
    assert_eq!(tokens[19].1, Token::Integer(-10));
    assert_eq!(tokens[21].1, Token::Integer(5));
}

#[test]
fn unknown_token() {
    let lex = Lexer::new(lex_rules![
        "test" => |_, _, _| Unknown("test".to_owned())
    ], |_, text| Unknown(text.to_owned()));

    let tokens = lex.src_iter(r#"|"#).collect::<Vec<_>>();

    assert_eq!(tokens[0], Token::Unknown(String::from("|")));
}