handball2/src/parser.rs

108 lines
2.5 KiB
Rust

use std::iter::Peekable;
use logos::Logos;
use crate::{Ast, Kind};
type Error = String;
struct Parser<'s> {
lex: Peekable<Lexer<'s>>,
errors: Vec<Error>,
}
pub(crate) fn parse(s: &str) -> (Vec<Ast>, Vec<Error>) {
let lex = Lexer {
lex: Kind::lexer(s),
}
.peekable();
let mut parser = Parser {
lex,
errors: vec![],
};
let mut trees = Vec::new();
while parser.lex.peek().is_some() {
if let Some(t) = parser.parse() {
trees.push(t);
}
}
(trees, parser.errors)
}
impl<'s> Parser<'s> {
fn parse(&mut self) -> Option<Ast<'s>> {
let Token { kind, span, src } = self.next()?;
// match tok {
// Token::Lparen => todo!(),
// Token::Rparen => {
// self.errors.push(format!("Unexpected lparen "));
// self.parse()
// }
// Token::Symbol => Some(Ast::Leaf(self.lex.str())),
// Token::String => todo!(),
// Token::Error => todo!(),
// }
Some(match kind {
Kind::Lparen => {
let mut bits = Vec::new();
while self.lex.peek()?.kind != Kind::Rparen {
bits.push(self.parse()?);
}
let rp = self.next()?;
assert_eq!(rp.kind, Kind::Rparen);
Ast::Tree(bits)
}
Kind::Rparen => {
self.errors.push(format!("Unexpected `)` at {:?}", span));
// Keep going from the next token
return self.parse();
}
Kind::Symbol | Kind::String | Kind::Boolean => Ast::Leaf(src),
Kind::Error => unreachable!("Removed by Parser::next"),
})
}
fn next(&mut self) -> Option<Token<'s>> {
for tok in &mut self.lex {
if tok.kind == crate::Kind::Error {
self.errors
.push(format!("Bad token at {:?}: `{}`", tok.span, tok.src))
} else {
return Some(tok);
}
}
self.errors.push("Unexpected EOF".to_owned());
None
}
}
struct Lexer<'s> {
lex: logos::Lexer<'s, crate::Kind>,
}
impl<'s> Iterator for Lexer<'s> {
type Item = Token<'s>;
fn next(&mut self) -> Option<Self::Item> {
self.lex.next().map(|kind| Token {
kind,
span: self.lex.span(),
src: self.lex.slice(),
})
}
}
struct Token<'s> {
kind: Kind,
span: logos::Span,
src: &'s str,
}