#token-stream #logo #lexer #parser #integration #error #buffered-lexer

辛库

一个用于编写在标记流上工作的解析器的轻量级库

1 个不稳定版本

0.1.0 2020年5月16日

#20 in #token-stream

MIT 许可协议

36KB
400 行代码(不包括注释)

概述

辛库 是一个基于标记流的解析器库。它为使用 logos crate 创建的词法分析器提供集成,但同时也提供基于特质的灵活接口以与其他标记流集成。

示例

以下是一个使用此库和 Logos crate 实现的基本解析器的示例。

use logos::Logos;
use hinku::{
    logos::BufferedLexer,
    Either,
    ParseError,
    ParseResult,
    TokenStream,
    TokenStreamExt,
};

#[derive(Logos, Debug, Clone, PartialEq)]
enum Token {
    #[token("foo")]
    Foo,

    #[token("bar")]
    Bar,

    #[error]
    #[regex(r"[ \n\r\f\t]+", logos::skip)]
    Error,
}

/// A function that either consumes a Foo token or returns an error.
fn foo(stream: &mut dyn TokenStream<Token>) -> ParseResult<Token, String> {
    match stream.advance() {
        None => Err(ParseError::EndOfStream),
        Some((Token::Foo, _)) => Ok(Token::Foo),
        Some((other, span)) => Err(ParseError::custom(span, "expected a foo".into())),
    }
}

/// A function that either consumes a Bar token or returns an error.
fn bar(stream: &mut dyn TokenStream<Token>) -> ParseResult<Token, String> {
    match stream.advance() {
        None => Err(ParseError::EndOfStream),
        Some((Token::Bar, _)) => Ok(Token::Bar),
        Some((other, span)) => Err(ParseError::custom(span, "expected a bar".into())),
    }
}

/// A function that consumes either one of the tokens.
fn foo_or_bar(mut stream: &mut dyn TokenStream<Token>) -> ParseResult<Token, String> {
    stream.either(foo, bar)
        .map(Either::merge)
        .expected("expected either a foo or a bar")
}

/// A function that expects a Foo token, followed by a Bar token.
fn foobar(mut stream: &mut dyn TokenStream<Token>) -> ParseResult<(Token, Token), String> {
    let f = stream.take(foo)?;
    let b = stream.take(bar)?;

    Ok((f, b))
}

let lex = Token::lexer("foo bar bar foo bar");
let mut stream = BufferedLexer::new(lex);

assert_eq!(stream.take(foo), Ok(Token::Foo));
assert_eq!(stream.take(bar), Ok(Token::Bar));
assert_eq!(stream.take(foo_or_bar), Ok(Token::Bar));
assert_eq!(stream.take(foobar), Ok((Token::Foo, Token::Bar)));

依赖项

~0–365KB