Add errors for lexer and parser
This commit is contained in:
parent
c7f11e5091
commit
9b7a31c988
51
src/ast.rs
51
src/ast.rs
@ -1,10 +1,13 @@
|
||||
use crate::{lexer::Token, token_stream::TokenStream};
|
||||
use crate::{
|
||||
lexer::{Token, TokenList},
|
||||
token_stream::{Error, TokenStream},
|
||||
};
|
||||
|
||||
pub trait Parse
|
||||
where
|
||||
Self: std::marker::Sized,
|
||||
{
|
||||
fn parse(stream: TokenStream) -> Result<Self, ()>;
|
||||
fn parse(stream: TokenStream) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -28,13 +31,13 @@ pub enum Expression {
|
||||
}
|
||||
|
||||
impl Parse for Expression {
|
||||
fn parse(mut stream: TokenStream) -> Result<Expression, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Expression, Error> {
|
||||
let lhs = parse_primary_expression(&mut stream)?;
|
||||
parse_binop_rhs(&mut stream, lhs, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_primary_expression(stream: &mut TokenStream) -> Result<Expression, ()> {
|
||||
fn parse_primary_expression(stream: &mut TokenStream) -> Result<Expression, Error> {
|
||||
if let Ok(exp) = stream.parse() {
|
||||
Ok(Expression::FunctionCall(Box::new(exp)))
|
||||
} else if let Ok(block) = stream.parse() {
|
||||
@ -48,10 +51,10 @@ fn parse_primary_expression(stream: &mut TokenStream) -> Result<Expression, ()>
|
||||
stream.expect(Token::ParenClose)?;
|
||||
exp
|
||||
}
|
||||
_ => Err(())?, // TODO: Add error raporting!
|
||||
_ => Err(stream.expected_err("identifier, constant or parentheses")?)?,
|
||||
})
|
||||
} else {
|
||||
Err(()) // TODO: Add error raporting!
|
||||
Err(stream.expected_err("expression")?)?
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +67,7 @@ fn parse_binop_rhs(
|
||||
stream: &mut TokenStream,
|
||||
mut lhs: Expression,
|
||||
expr_prec: i8,
|
||||
) -> Result<Expression, ()> {
|
||||
) -> Result<Expression, Error> {
|
||||
while let Some(token) = stream.peek() {
|
||||
let curr_token_prec = token.get_token_prec();
|
||||
|
||||
@ -89,7 +92,7 @@ fn parse_binop_rhs(
|
||||
lhs = match &token {
|
||||
Token::Plus => Expression::Binop(Add, Box::new(lhs), Box::new(rhs)),
|
||||
Token::Times => Expression::Binop(Mult, Box::new(lhs), Box::new(rhs)),
|
||||
_ => Err(())?, // TODO: Add error raporting!
|
||||
_ => Err(stream.expected_err(TokenList(vec![Token::Plus, Token::Times]))?)?, // TODO: Add error raporting!
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -101,7 +104,7 @@ fn parse_binop_rhs(
|
||||
pub struct FunctionCallExpression(String, Vec<Expression>);
|
||||
|
||||
impl Parse for FunctionCallExpression {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
if let Some(Token::Identifier(name)) = stream.next() {
|
||||
stream.expect(Token::ParenOpen)?;
|
||||
|
||||
@ -119,7 +122,7 @@ impl Parse for FunctionCallExpression {
|
||||
|
||||
Ok(FunctionCallExpression(name, args))
|
||||
} else {
|
||||
Err(())? // TODO: Add error raporting!
|
||||
Err(stream.expected_err("identifier")?)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,7 +131,7 @@ impl Parse for FunctionCallExpression {
|
||||
pub struct LetStatement(pub String, pub Expression);
|
||||
|
||||
impl Parse for LetStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<LetStatement, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<LetStatement, Error> {
|
||||
stream.expect(Token::LetKeyword)?;
|
||||
|
||||
if let Some(Token::Identifier(variable)) = stream.next() {
|
||||
@ -138,7 +141,7 @@ impl Parse for LetStatement {
|
||||
stream.expect(Token::Semi)?;
|
||||
Ok(LetStatement(variable, expression))
|
||||
} else {
|
||||
Err(()) // TODO: Add error raporting!
|
||||
Err(stream.expected_err("identifier")?)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,7 +150,7 @@ impl Parse for LetStatement {
|
||||
pub struct ImportStatement(Vec<String>);
|
||||
|
||||
impl Parse for ImportStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
stream.expect(Token::ImportKeyword)?;
|
||||
|
||||
let mut import_list = Vec::new();
|
||||
@ -158,11 +161,11 @@ impl Parse for ImportStatement {
|
||||
if let Some(Token::Identifier(name)) = stream.next() {
|
||||
import_list.push(name);
|
||||
} else {
|
||||
Err(())? // TODO: Add error raporting!
|
||||
Err(stream.expected_err("identifier")?)?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(())? // TODO: Add error raporting!
|
||||
Err(stream.expected_err("identifier")?)?
|
||||
}
|
||||
|
||||
stream.expect(Token::Semi)?;
|
||||
@ -175,7 +178,7 @@ impl Parse for ImportStatement {
|
||||
pub struct FunctionDefinition(pub FunctionSignature, pub Block);
|
||||
|
||||
impl Parse for FunctionDefinition {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
stream.expect(Token::FnKeyword)?;
|
||||
Ok(FunctionDefinition(stream.parse()?, stream.parse()?))
|
||||
}
|
||||
@ -187,13 +190,13 @@ pub struct FunctionSignature {
|
||||
}
|
||||
|
||||
impl Parse for FunctionSignature {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
if let Some(Token::Identifier(name)) = stream.next() {
|
||||
stream.expect(Token::ParenOpen)?;
|
||||
stream.expect(Token::ParenClose)?;
|
||||
Ok(FunctionSignature { name })
|
||||
} else {
|
||||
Err(()) // TODO: Add error raporting!
|
||||
Err(stream.expected_err("identifier")?)?
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,7 +205,7 @@ impl Parse for FunctionSignature {
|
||||
pub struct Block(pub Vec<BlockLevelStatement>, pub Option<Expression>);
|
||||
|
||||
impl Parse for Block {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
let mut statements = Vec::new();
|
||||
let mut return_stmt = None;
|
||||
stream.expect(Token::BraceOpen)?;
|
||||
@ -228,7 +231,7 @@ pub enum BlockLevelStatement {
|
||||
}
|
||||
|
||||
impl Parse for BlockLevelStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
use BlockLevelStatement as Stmt;
|
||||
Ok(match stream.peek() {
|
||||
Some(Token::LetKeyword) => Stmt::Let(stream.parse()?),
|
||||
@ -244,7 +247,7 @@ impl Parse for BlockLevelStatement {
|
||||
stream.expect(Token::Semi)?;
|
||||
Stmt::Expression(e)
|
||||
} else {
|
||||
Err(())? // TODO: Add error raporting!
|
||||
Err(stream.expected_err("expression")?)?
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -258,12 +261,14 @@ pub enum TopLevelStatement {
|
||||
}
|
||||
|
||||
impl Parse for TopLevelStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, ()> {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
use TopLevelStatement as Stmt;
|
||||
Ok(match stream.peek() {
|
||||
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
|
||||
Some(Token::FnKeyword) => Stmt::FunctionDefinition(stream.parse()?),
|
||||
_ => Err(())?, // TODO: Add error raporting!
|
||||
_ => {
|
||||
Err(stream.expected_err(TokenList(vec![Token::ImportKeyword, Token::FnKeyword]))?)?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
26
src/lexer.rs
26
src/lexer.rs
@ -54,6 +54,30 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for Token {
|
||||
fn into(self) -> String {
|
||||
format!("{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TokenList(pub Vec<Token>);
|
||||
|
||||
impl Into<String> for TokenList {
|
||||
fn into(self) -> String {
|
||||
self.0
|
||||
.iter()
|
||||
.map(|tok| tok.clone().into())
|
||||
.collect::<Vec<String>>()
|
||||
.join(" or ")
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TokenList> for &[Token] {
|
||||
fn into(self) -> TokenList {
|
||||
TokenList(self.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FullToken {
|
||||
pub token: Token,
|
||||
@ -79,11 +103,11 @@ pub struct Cursor<'a> {
|
||||
impl<'a> Cursor<'a> {
|
||||
fn next(&mut self) -> Option<char> {
|
||||
let next = self.char_stream.next();
|
||||
self.position.0 += 1;
|
||||
if let Some('\n') = next {
|
||||
self.position.1 += 1;
|
||||
self.position.0 = 0;
|
||||
}
|
||||
self.position.0 += 1;
|
||||
next
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ mod token_stream;
|
||||
pub enum ReidError {
|
||||
#[error(transparent)]
|
||||
LexerError(#[from] lexer::Error),
|
||||
#[error(transparent)]
|
||||
ParserError(#[from] token_stream::Error),
|
||||
}
|
||||
|
||||
pub fn compile(source: &str) -> Result<String, ReidError> {
|
||||
@ -28,7 +30,7 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
|
||||
let statement = token_stream.parse::<TopLevelStatement>().unwrap();
|
||||
let statement = token_stream.parse::<TopLevelStatement>()?;
|
||||
dbg!(&statement);
|
||||
statements.push(statement);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
ast::Parse,
|
||||
lexer::{FullToken, Token},
|
||||
lexer::{FullToken, Position, Token},
|
||||
};
|
||||
|
||||
pub struct TokenStream<'a, 'b> {
|
||||
@ -18,16 +18,24 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect(&mut self, token: Token) -> Result<(), ()> {
|
||||
pub fn expected_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
||||
Ok(Error::Expected(
|
||||
expected.into(),
|
||||
self.peek().unwrap_or(Token::Eof),
|
||||
self.get_next_position()?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn expect(&mut self, token: Token) -> Result<(), Error> {
|
||||
if let Some(peeked) = self.peek() {
|
||||
if token == peeked {
|
||||
self.position += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
Err(self.expected_err(token)?)
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
Err(self.expected_err(token)?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +57,7 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse<T: Parse>(&mut self) -> Result<T, ()> {
|
||||
pub fn parse<T: Parse>(&mut self) -> Result<T, Error> {
|
||||
let mut ref_pos = self.position;
|
||||
|
||||
let position = self.position;
|
||||
@ -67,6 +75,15 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_position(&self) -> Result<Position, Error> {
|
||||
if self.tokens.is_empty() {
|
||||
Err(Error::FileEmpty)
|
||||
} else {
|
||||
let token_idx = self.position.min(self.tokens.len() - 1);
|
||||
Ok(self.tokens[token_idx].position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TokenStream<'_, '_> {
|
||||
@ -76,3 +93,11 @@ impl Drop for TokenStream<'_, '_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
||||
Expected(String, Token, Position),
|
||||
#[error("Source file contains no tokens")]
|
||||
FileEmpty,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user