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 super::types::*;
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
|
|
||||||
fn parse_simple_expr(tokens: &mut Vec<LocatedToken>) -> Result<ast::Expr, Error> {
|
fn parse_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||||
let start = tokens.last()?;
|
todo!()
|
||||||
match start {
|
}
|
||||||
Token::OpenParen => {
|
|
||||||
tokens.pop();
|
fn parse_simple_expr(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||||
let expr = parse_expr(tokens)?;
|
tokens.one_of(vec![
|
||||||
if Some(p) = tokens.pop_if(|t| t.token == Token::CloseParen) {
|
|t| t.between(Token::OpenParen, Token::CloseParen, parse_expr),
|
||||||
Ok(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 {
|
} else {
|
||||||
Err(Error::UnexpectedToken { expected: Token::CloseParen, got: start})
|
Ok(None)
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Token::Number(n) => {
|
|
||||||
tokens.pop();
|
|
||||||
Ok(ast::Expr::Value(ast::Value::Number(n)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Error {
|
fn parse_number(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||||
UnexpectedToken{expected: Token, got: LocatedToken},
|
{
|
||||||
UnexpectedToken(LocatedToken),
|
if let Some(LocatedToken {
|
||||||
UnexpectedEndOfInput,
|
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> {
|
fn parse_definition(tokens: &mut Tokens) -> Result<ast::Definition, Error> {
|
||||||
if let Some(start) = tokens.pop_if(|tok| tok.token == Token::Let) {
|
if let Some(start) = tokens.next_if(Token::Let) {
|
||||||
if let Some(LocatedToken {
|
if let Some(LocatedToken {
|
||||||
token: Token::Identifier(identifier),
|
token: Token::Identifier(identifier),
|
||||||
..
|
..
|
||||||
}) = tokens.pop_if(|tok| match tok.token {
|
}) = tokens.next_if(Token::Identifier("".into()))
|
||||||
Token::Identifier(_) => true,
|
{
|
||||||
_ => false,
|
if let Some(_eq) = tokens.next_if(Token::Equals) {
|
||||||
}) {
|
if let Some(expr) = parse_expr(tokens)? {
|
||||||
if let Some(_eq) = tokens.pop_if(|tok| tok.token == Token::Equals) {
|
|
||||||
let expr = parse_expr(tokens)?;
|
|
||||||
Ok(ast::Definition {
|
Ok(ast::Definition {
|
||||||
name: ast::Name(identifier),
|
name: ast::Name(identifier),
|
||||||
expr,
|
expr,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedToken{expected: Token::Equals, got: start})
|
Err(Error::UnexpectedToken {
|
||||||
|
expected: Token::Equals,
|
||||||
|
got: start,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
Err(Error::UnexpectedEndOfInput)
|
Err(Error::UnexpectedEndOfInput)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ pub enum Token {
|
||||||
Comma,
|
Comma,
|
||||||
Semicolon,
|
Semicolon,
|
||||||
Colon,
|
Colon,
|
||||||
Name(String),
|
|
||||||
Number(u32),
|
Number(u32),
|
||||||
String(String),
|
String(String),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
|
|
@ -30,10 +29,45 @@ pub enum Token {
|
||||||
pub struct Tokens(Vec<LocatedToken>);
|
pub struct Tokens(Vec<LocatedToken>);
|
||||||
|
|
||||||
impl Tokens {
|
impl Tokens {
|
||||||
fn peek(&mut self) -> Option<LocatedToken> {
|
pub fn peek(&mut self) -> Option<&LocatedToken> {
|
||||||
self.last()
|
self.0.last()
|
||||||
}
|
}
|
||||||
fn next(&mut self) -> Option<LocatedToken> {
|
pub fn next(&mut self) -> Option<LocatedToken> {
|
||||||
self.pop()
|
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