some improvements on parser
This commit is contained in:
parent
ebbc4be8f6
commit
290dcab5e9
2 changed files with 96 additions and 38 deletions
|
|
@ -1,52 +1,76 @@
|
|||
use super::types::*;
|
||||
use crate::ast;
|
||||
|
||||
fn parse_simple_expr(tokens: &mut Vec<LocatedToken>) -> Result<ast::Expr, Error> {
|
||||
let start = tokens.last()?;
|
||||
match start {
|
||||
Token::OpenParen => {
|
||||
tokens.pop();
|
||||
let expr = parse_expr(tokens)?;
|
||||
if Some(p) = tokens.pop_if(|t| t.token == Token::CloseParen) {
|
||||
Ok(expr)
|
||||
fn parse_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse_simple_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||
tokens.one_of(vec![
|
||||
|t| t.between(Token::OpenParen, Token::CloseParen, parse_expr),
|
||||
parse_number,
|
||||
|_| Err(Error::UnexpectedEndOfInput),
|
||||
])
|
||||
}
|
||||
|
||||
fn parse_string(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||
{
|
||||
if let Some(LocatedToken {
|
||||
token: Token::String(string),
|
||||
..
|
||||
}) = tokens.next_if(Token::String("".into()))
|
||||
{
|
||||
Ok(Some(ast::Expr::Value(ast::Value::String(string))))
|
||||
} else {
|
||||
Err(Error::UnexpectedToken { expected: Token::CloseParen, got: start})
|
||||
}
|
||||
|
||||
}
|
||||
Token::Number(n) => {
|
||||
tokens.pop();
|
||||
Ok(ast::Expr::Value(ast::Value::Number(n)))
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Error {
|
||||
UnexpectedToken{expected: Token, got: LocatedToken},
|
||||
UnexpectedToken(LocatedToken),
|
||||
UnexpectedEndOfInput,
|
||||
fn parse_number(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||
{
|
||||
if let Some(LocatedToken {
|
||||
token: Token::Number(number),
|
||||
..
|
||||
}) = tokens.next_if(Token::Number(0))
|
||||
{
|
||||
Ok(Some(ast::Expr::Value(ast::Value::Int(number.into()))))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_definition(tokens: &mut Vec<LocatedToken>) -> Result<ast::Definition, Error> {
|
||||
if let Some(start) = tokens.pop_if(|tok| tok.token == Token::Let) {
|
||||
fn parse_definition(tokens: &mut Tokens) -> Result<ast::Definition, Error> {
|
||||
if let Some(start) = tokens.next_if(Token::Let) {
|
||||
if let Some(LocatedToken {
|
||||
token: Token::Identifier(identifier),
|
||||
..
|
||||
}) = tokens.pop_if(|tok| match tok.token {
|
||||
Token::Identifier(_) => true,
|
||||
_ => false,
|
||||
}) {
|
||||
if let Some(_eq) = tokens.pop_if(|tok| tok.token == Token::Equals) {
|
||||
let expr = parse_expr(tokens)?;
|
||||
}) = tokens.next_if(Token::Identifier("".into()))
|
||||
{
|
||||
if let Some(_eq) = tokens.next_if(Token::Equals) {
|
||||
if let Some(expr) = parse_expr(tokens)? {
|
||||
Ok(ast::Definition {
|
||||
name: ast::Name(identifier),
|
||||
expr,
|
||||
})
|
||||
} else {
|
||||
Err(Error::UnexpectedToken{expected: Token::Equals, got: start})
|
||||
Err(Error::UnexpectedToken {
|
||||
expected: Token::Equals,
|
||||
got: start,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(Error::UnexpectedToken{expected: Token::Equals, got: start})
|
||||
Err(Error::UnexpectedToken {
|
||||
expected: Token::Equals,
|
||||
got: start,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(Error::UnexpectedToken {
|
||||
expected: Token::Equals,
|
||||
got: start,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(Error::UnexpectedEndOfInput)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ pub enum Token {
|
|||
Comma,
|
||||
Semicolon,
|
||||
Colon,
|
||||
Name(String),
|
||||
Number(u32),
|
||||
String(String),
|
||||
Identifier(String),
|
||||
|
|
@ -30,10 +29,45 @@ pub enum Token {
|
|||
pub struct Tokens(Vec<LocatedToken>);
|
||||
|
||||
impl Tokens {
|
||||
fn peek(&mut self) -> Option<LocatedToken> {
|
||||
self.last()
|
||||
pub fn peek(&mut self) -> Option<&LocatedToken> {
|
||||
self.0.last()
|
||||
}
|
||||
fn next(&mut self) -> Option<LocatedToken> {
|
||||
self.pop()
|
||||
pub fn next(&mut self) -> Option<LocatedToken> {
|
||||
self.0.pop()
|
||||
}
|
||||
pub fn next_if(&mut self, token: Token) -> Option<LocatedToken> {
|
||||
self.0.pop_if(|t| match (&t.token, &token) {
|
||||
(a, b) if a == b => true,
|
||||
(Token::Identifier(_), Token::Identifier(_)) => true,
|
||||
(Token::Number(_), Token::Number(_)) => true,
|
||||
(Token::String(_), Token::String(_)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
pub fn between<T>(&mut self, start: Token, end: Token, parser: Parser<T>) -> ParseResult<T> {
|
||||
let _start = self.next_if(start).ok_or(Error::UnexpectedEndOfInput)?;
|
||||
if let Some(result) = parser(self)? {
|
||||
let _end = self.next_if(end).ok_or(Error::UnexpectedEndOfInput)?;
|
||||
Ok(Some(result))
|
||||
} else {
|
||||
Err(Error::UnexpectedTokenForParser)
|
||||
}
|
||||
}
|
||||
pub fn one_of<T>(&mut self, parsers: Vec<Parser<T>>) -> ParseResult<T> {
|
||||
for parser in parsers {
|
||||
if let Some(result) = parser(self)? {
|
||||
return Ok(Some(result));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Parser<T> = fn(&mut Tokens) -> ParseResult<T>;
|
||||
pub type ParseResult<T> = Result<Option<T>, Error>;
|
||||
|
||||
pub enum Error {
|
||||
UnexpectedToken { expected: Token, got: LocatedToken },
|
||||
UnexpectedEndOfInput,
|
||||
UnexpectedTokenForParser,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue