250 lines
6.7 KiB
Rust
250 lines
6.7 KiB
Rust
|
|
#![allow(dead_code)]
|
||
|
|
use crate::syn::{ast::*, error::*, lexer::Lexer, span::*, token::*};
|
||
|
|
use std::{convert::TryFrom, mem};
|
||
|
|
|
||
|
|
const EXPR_START: &'static [TokenKind] = &[
|
||
|
|
TokenKind::Ident,
|
||
|
|
TokenKind::Num,
|
||
|
|
TokenKind::Str,
|
||
|
|
TokenKind::Sym,
|
||
|
|
TokenKind::LParen,
|
||
|
|
TokenKind::LBracket,
|
||
|
|
TokenKind::LBrace,
|
||
|
|
// TODO unary tokens
|
||
|
|
];
|
||
|
|
|
||
|
|
const VALUE_EXPR_START: &'static [TokenKind] = &[
|
||
|
|
TokenKind::Ident,
|
||
|
|
TokenKind::Num,
|
||
|
|
TokenKind::Str,
|
||
|
|
TokenKind::Sym,
|
||
|
|
];
|
||
|
|
|
||
|
|
pub struct Parser<'t> {
|
||
|
|
lexer: Lexer<'t>,
|
||
|
|
curr_token: Option<Token>,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'t> Parser<'t> {
|
||
|
|
pub fn new(lexer: Lexer<'t>) -> Result<Self> {
|
||
|
|
let mut parser = Parser {
|
||
|
|
lexer,
|
||
|
|
curr_token: None,
|
||
|
|
};
|
||
|
|
parser.adv_token()?;
|
||
|
|
Ok(parser)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn is_eof(&self) -> bool {
|
||
|
|
self.lexer.is_eof()
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn pos(&self) -> Pos {
|
||
|
|
self.span().start
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
// Parsing functions
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
pub fn next_expr(&mut self) -> Result<Expr> {
|
||
|
|
self.next_bin_expr()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn next_bin_expr(&mut self) -> Result<Expr> {
|
||
|
|
let lhs = self.next_un_expr()?;
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn next_un_expr(&mut self) -> Result<Expr> {
|
||
|
|
todo!()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn next_base_expr(&mut self) -> Result<Expr> {
|
||
|
|
let token =
|
||
|
|
self.expect_token_where(|t| VALUE_EXPR_START.contains(&t.kind()), "base expression")?;
|
||
|
|
let expr: Expr = match token.kind() {
|
||
|
|
TokenKind::Ident => BaseExpr {
|
||
|
|
kind: BaseExprKind::Ident,
|
||
|
|
span: token.span(),
|
||
|
|
}
|
||
|
|
.into(),
|
||
|
|
TokenKind::Num => BaseExpr {
|
||
|
|
kind: BaseExprKind::Num,
|
||
|
|
span: token.span(),
|
||
|
|
}
|
||
|
|
.into(),
|
||
|
|
TokenKind::Str => BaseExpr {
|
||
|
|
kind: BaseExprKind::Str,
|
||
|
|
span: token.span(),
|
||
|
|
}
|
||
|
|
.into(),
|
||
|
|
TokenKind::Sym => BaseExpr {
|
||
|
|
kind: BaseExprKind::Sym,
|
||
|
|
span: token.span(),
|
||
|
|
}
|
||
|
|
.into(),
|
||
|
|
_ => unreachable!(),
|
||
|
|
};
|
||
|
|
|
||
|
|
Ok(expr)
|
||
|
|
}
|
||
|
|
|
||
|
|
fn next_list(&mut self) -> Result<Expr> {
|
||
|
|
let start_token = self.expect_token_where(|t| t.kind() == TokenKind::LBracket, "start of list (left bracket)")?;
|
||
|
|
let mut list_items = Vec::new();
|
||
|
|
|
||
|
|
while ! matches!(self.curr_token.map(|t| t.kind()), Some(TokenKind::RBrace) | None) {
|
||
|
|
let expr = self.next_expr()?;
|
||
|
|
}
|
||
|
|
|
||
|
|
let end_token = self.expect_token_where(
|
||
|
|
|t| t.kind() == TokenKind::RBracket,
|
||
|
|
"end of list (right bracket)",
|
||
|
|
)?;
|
||
|
|
let expr = BaseExpr {
|
||
|
|
kind: BaseExprKind::List(list_items),
|
||
|
|
span: start_token.span().union(end_token.span()),
|
||
|
|
};
|
||
|
|
|
||
|
|
Ok(expr.into())
|
||
|
|
}
|
||
|
|
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
// Token matching functions
|
||
|
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
fn adv_token(&mut self) -> Result<Option<Token>> {
|
||
|
|
let next_token = self.lexer.next_token()?;
|
||
|
|
Ok(mem::replace(&mut self.curr_token, next_token))
|
||
|
|
}
|
||
|
|
|
||
|
|
fn match_token_where<P>(&mut self, pred: P) -> Result<Option<Token>>
|
||
|
|
where
|
||
|
|
P: Fn(Token) -> bool,
|
||
|
|
{
|
||
|
|
match self.curr_token {
|
||
|
|
Some(curr) if (pred)(curr) => self.adv_token(),
|
||
|
|
_ => Ok(None),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn expect_token_where<P>(&mut self, pred: P, expected: impl ToString) -> Result<Token>
|
||
|
|
where
|
||
|
|
P: Fn(Token) -> bool,
|
||
|
|
{
|
||
|
|
self.match_token_where(pred)?
|
||
|
|
.ok_or_else(|| Error::ExpectedGot {
|
||
|
|
expected: expected.to_string(),
|
||
|
|
got: self
|
||
|
|
.curr_token
|
||
|
|
.map(|token| token.kind().to_string())
|
||
|
|
.unwrap_or_else(|| "EOF".to_string()),
|
||
|
|
pos: self.pos(),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'t> Spanned for Parser<'t> {
|
||
|
|
fn span(&self) -> Span {
|
||
|
|
self.curr_token
|
||
|
|
.as_ref()
|
||
|
|
.map(Spanned::span)
|
||
|
|
.unwrap_or(Span::default())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'t> TryFrom<Lexer<'t>> for Parser<'t> {
|
||
|
|
type Error = Error;
|
||
|
|
|
||
|
|
fn try_from(lexer: Lexer<'t>) -> Result<Self> {
|
||
|
|
Parser::new(lexer)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'t> TryFrom<&'t str> for Parser<'t> {
|
||
|
|
type Error = Error;
|
||
|
|
|
||
|
|
fn try_from(text: &'t str) -> Result<Self> {
|
||
|
|
Parser::new(Lexer::new(text))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod test {
|
||
|
|
use super::*;
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_adv_token() {
|
||
|
|
const EXPECTED: &'static [TokenKind] = &[
|
||
|
|
TokenKind::Num,
|
||
|
|
TokenKind::Ident,
|
||
|
|
TokenKind::Sym,
|
||
|
|
TokenKind::Str,
|
||
|
|
];
|
||
|
|
let mut parser = Parser::try_from("1 ident :sym 'string'").unwrap();
|
||
|
|
|
||
|
|
for expected in EXPECTED.iter().copied() {
|
||
|
|
let token = parser.adv_token().unwrap();
|
||
|
|
let kind = token.unwrap().kind();
|
||
|
|
assert_eq!(kind, expected);
|
||
|
|
}
|
||
|
|
assert!(parser.is_eof());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_match_token_where() {
|
||
|
|
let mut parser = Parser::try_from("1 ident :sym 'string'").unwrap();
|
||
|
|
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Num),
|
||
|
|
Ok(Some(_))
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Num),
|
||
|
|
Ok(None)
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Ident),
|
||
|
|
Ok(Some(_))
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Ident),
|
||
|
|
Ok(None)
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Sym),
|
||
|
|
Ok(Some(_))
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Sym),
|
||
|
|
Ok(None)
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Str),
|
||
|
|
Ok(Some(_))
|
||
|
|
));
|
||
|
|
assert!(matches!(
|
||
|
|
parser.match_token_where(|token| token.kind() == TokenKind::Str),
|
||
|
|
Ok(None)
|
||
|
|
));
|
||
|
|
assert!(parser.is_eof());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_base_expr() {
|
||
|
|
let mut parser = Parser::try_from("1").unwrap();
|
||
|
|
assert!(matches!(
|
||
|
|
parser.next_base_expr(),
|
||
|
|
Ok(
|
||
|
|
Expr::Base(
|
||
|
|
BaseExpr {
|
||
|
|
kind: BaseExprKind::Num,
|
||
|
|
..
|
||
|
|
}
|
||
|
|
)
|
||
|
|
)
|
||
|
|
));
|
||
|
|
}
|
||
|
|
}
|