8 个版本 (4 个稳定版)
新 1.1.0 | 2024 年 8 月 20 日 |
---|---|
1.0.2 | 2024 年 8 月 19 日 |
0.1.2 | 2024 年 8 月 11 日 |
0.0.0 | 2024 年 3 月 15 日 |
#2030 在 解析器实现 中
每月 483 次下载
24KB
290 行
ketchup
一个可以与您的编程语言 ketch - up 的解析器。
示例
有关完整实现/示例,请检查 examples
目录
use ketchup::{error::KError, node::Node, parser::Parser, OperInfo, Space, Span};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Error {
#[default]
UnexpectedCharacter,
EmptyParentheses,
UnclosedParentheses,
UnexpectedToken,
}
/// A simple logos lexer
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
Number(u32),
Plus,
Minus,
Star,
Slash,
}
/// The operations / nodes that will be used
#[derive(Debug, Clone)]
pub enum Oper {
Num(u32),
Add,
Sub,
Mul,
Div,
Neg,
Pos,
}
fn oper_generator(token: Token, tokens: &mut impl Iterator<Item = (Result<Token, Error>, Span)>, double_space: bool) -> Result<Option<(OperInfo<Oper>, Option<(Result<Token, Error>, Span)>)>, Vec<KError<Error>>> {
use Token as T;
use Oper as O;
// precedence determines the order of operations, lower the precedence the 'smaller' it is
// space determines how much many input nodes it takes, eg `Space::None` is `x`, `Space::Single` is `x input`, `Space::Double` is `input1 x input2`
// oper is just the kind of operation it is, like a number, addition, etc
let (precedence, space, oper) = match (token, double_space) {
// no space
(T::Number(x), _) => (0, Space::None, O::Num(x)),
// single space
(T::Plus, false) => (1, Space::Single, O::Pos),
(T::Minus, false) => (1, Space::Single, O::Neg),
// double space
(T::Plus, true) => (3, Space::Double, O::Add),
(T::Minus, true) => (3, Space::Double, O::Sub),
(T::Star, _) => (2, Space::Double, O::Mul),
(T::Slash, _) => (2, Space::Double, O::Div),
};
Ok(Some((OperInfo {
oper,
span: 0..0, // should be used with logos to get the actual span
space,
precedence,
}, tokens.next())))
}
fn throw(error: KError<Error>) {
println!("err: {error:?}");
}
fn main() {
let mut tokens = [(Ok(Token::Number(1)), 0..1), (Ok(Token::Plus), 1..2), (Ok(Token::Number(2)), 2..3), (Ok(Token::Star), 3..4), (Ok(Token::Number(3)), 4..5)].into_iter();
let first_tok = tokens.next();
let parser = Parser::<'_, Token, Oper, _, Vec<Node<Oper>>, _, Error>::new(&mut tokens, oper_generator);
// handle errors
let (asa, trailing_tok) = match parser.parse(first_tok) {
Ok(asa) => asa,
Err(errs) => {
for err in errs {
throw(err);
} panic!("an error occured");
},
};
// make sure that there aren't any tokens that haven't been consumed
if let Some((_, span)) = trailing_tok {
throw(KError::Other(span, Error::UnexpectedToken));
panic!("an error occured");
}
// print abstract syntax array
println!("{asa:?}");
}