refactor syntax result pt2

master
Araozu 2024-03-15 16:44:29 -05:00
parent e43eb9e137
commit 98f67bd097
3 changed files with 63 additions and 85 deletions

View File

@ -1,68 +1,61 @@
use crate::{ use crate::{
error_handling::SyntaxError, error_handling::SyntaxError,
lexic::token::{Token, TokenType}, lexic::token::{Token, TokenType},
syntax::ParsingError, syntax::{ParsingError, ParsingResult},
utils::Result3,
}; };
use super::{ use super::{
super::{ super::{ast::FunctionDeclaration, block::parse_block, utils::parse_token_type, ParseResult},
ast::FunctionDeclaration,
block::parse_block,
utils::{parse_immediate_token_type, parse_token_type},
ParseResult,
},
params_list::parse_params_list, params_list::parse_params_list,
}; };
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<FunctionDeclaration> { pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<FunctionDeclaration> {
let mut current_pos = pos; let mut current_pos = pos;
// `fun` keyword // `fun` keyword
let fun_keyword = match parse_immediate_token_type(tokens, current_pos, TokenType::FUN) { let (fun_keyword, next_pos) = match parse_token_type(tokens, current_pos, TokenType::FUN) {
Result3::Ok(t) => t, ParseResult::Ok(t, next) => (t, next),
Result3::Err(_token) => return ParseResult::Unmatched, _ => return Err(ParsingError::Unmatched),
Result3::None => return ParseResult::Unmatched,
}; };
current_pos += 1; current_pos = next_pos;
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier) let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
{ {
ParseResult::Ok(id, next) => (id, next), ParseResult::Ok(id, next) => (id, next),
ParseResult::Err(err) => return ParseResult::Err(err), ParseResult::Err(err) => return Err(ParsingError::Err(err)),
ParseResult::Mismatch(wrong_token) => { ParseResult::Mismatch(wrong_token) => {
return ParseResult::Err(SyntaxError { return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an identifier after the `fun` keyword."), reason: String::from("Expected an identifier after the `fun` keyword."),
error_start: wrong_token.position, error_start: wrong_token.position,
error_end: wrong_token.get_end_position(), error_end: wrong_token.get_end_position(),
}); }));
} }
ParseResult::Unmatched => { ParseResult::Unmatched => {
return ParseResult::Err(SyntaxError { return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an identifier after the `fun` keyword."), reason: String::from("Expected an identifier after the `fun` keyword."),
error_start: fun_keyword.position, error_start: fun_keyword.position,
error_end: fun_keyword.get_end_position(), error_end: fun_keyword.get_end_position(),
}); }));
} }
}; };
current_pos = next_pos; current_pos = next_pos;
let (params_list, next_pos) = match parse_params_list(tokens, current_pos) { let (params_list, next_pos) = match parse_params_list(tokens, current_pos) {
Ok((params, next_pos)) => (params, next_pos), Ok((params, next_pos)) => (params, next_pos),
Err(ParsingError::Err(err)) => return ParseResult::Err(err), Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
Err(ParsingError::Mismatch(wrong_token)) => { Err(ParsingError::Mismatch(wrong_token)) => {
return ParseResult::Err(SyntaxError { return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an opening paren afted the function identifier."), reason: String::from("Expected an opening paren afted the function identifier."),
error_start: wrong_token.position, error_start: wrong_token.position,
error_end: wrong_token.get_end_position(), error_end: wrong_token.get_end_position(),
}); }));
} }
Err(ParsingError::Unmatched) => { Err(ParsingError::Unmatched) => {
return ParseResult::Err(SyntaxError { return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected an opening paren afted the function identifier."), reason: String::from("Expected an opening paren afted the function identifier."),
error_start: identifier.position, error_start: identifier.position,
error_end: identifier.get_end_position(), error_end: identifier.get_end_position(),
}); }));
} }
}; };
current_pos = next_pos; current_pos = next_pos;
@ -70,34 +63,34 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Function
let (block, next_pos) = match parse_block(tokens, current_pos) { let (block, next_pos) = match parse_block(tokens, current_pos) {
ParseResult::Ok(block, next_pos) => (block, next_pos), ParseResult::Ok(block, next_pos) => (block, next_pos),
ParseResult::Err(error) => { ParseResult::Err(error) => {
return ParseResult::Err(error); return Err(ParsingError::Err(error));
} }
ParseResult::Mismatch(wrong_token) => { ParseResult::Mismatch(wrong_token) => {
return ParseResult::Err(SyntaxError { return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a block after the function declaration."), reason: String::from("Expected a block after the function declaration."),
error_start: wrong_token.position, error_start: wrong_token.position,
error_end: wrong_token.get_end_position(), error_end: wrong_token.get_end_position(),
}); }));
} }
ParseResult::Unmatched => { ParseResult::Unmatched => {
return ParseResult::Err(SyntaxError { return Err(ParsingError::Err(SyntaxError {
reason: String::from("Expected a block after the function declaration."), reason: String::from("Expected a block after the function declaration."),
error_start: identifier.position, error_start: identifier.position,
error_end: identifier.get_end_position(), error_end: identifier.get_end_position(),
}); }));
} }
}; };
current_pos = next_pos; current_pos = next_pos;
// Construct and return the function declaration // Construct and return the function declaration
ParseResult::Ok( Ok((
FunctionDeclaration { FunctionDeclaration {
identifier: &identifier, identifier: &identifier,
params_list: Box::new(params_list), params_list: Box::new(params_list),
block: Box::new(block), block: Box::new(block),
}, },
current_pos, current_pos,
) ))
} }
#[cfg(test)] #[cfg(test)]
@ -111,7 +104,7 @@ mod tests {
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap(); let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
let ParseResult::Unmatched = fun_decl else { let Err(ParsingError::Unmatched) = fun_decl else {
panic!("Expected an unmatched result: {:?}", fun_decl); panic!("Expected an unmatched result: {:?}", fun_decl);
}; };
} }
@ -122,7 +115,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected an identifier after the `fun` keyword." "Expected an identifier after the `fun` keyword."
@ -136,7 +129,7 @@ mod tests {
let tokens = get_tokens(&String::from("fun")).unwrap(); let tokens = get_tokens(&String::from("fun")).unwrap();
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected an identifier after the `fun` keyword." "Expected an identifier after the `fun` keyword."
@ -154,7 +147,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected an opening paren afted the function identifier." "Expected an opening paren afted the function identifier."
@ -168,7 +161,7 @@ mod tests {
let tokens = get_tokens(&String::from("fun id")).unwrap(); let tokens = get_tokens(&String::from("fun id")).unwrap();
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected an opening paren afted the function identifier." "Expected an opening paren afted the function identifier."
@ -186,7 +179,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected a closing paren after the function identifier." "Expected a closing paren after the function identifier."
@ -200,7 +193,7 @@ mod tests {
let tokens = get_tokens(&String::from("fun id(")).unwrap(); let tokens = get_tokens(&String::from("fun id(")).unwrap();
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected a closing paren after the function identifier." "Expected a closing paren after the function identifier."
@ -218,7 +211,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected an identifier after the `fun` keyword." "Expected an identifier after the `fun` keyword."
@ -234,7 +227,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected an identifier after the `fun` keyword." "Expected an identifier after the `fun` keyword."
@ -252,7 +245,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected a block after the function declaration." "Expected a block after the function declaration."
@ -266,7 +259,7 @@ mod tests {
let tokens = get_tokens(&String::from("fun id()")).unwrap(); let tokens = get_tokens(&String::from("fun id()")).unwrap();
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!( assert_eq!(
err.reason, err.reason,
"Expected a block after the function declaration." "Expected a block after the function declaration."
@ -284,7 +277,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!(err.reason, "Expected a closing brace after the block body."); assert_eq!(err.reason, "Expected a closing brace after the block body.");
assert_eq!(err.error_start, 11); assert_eq!(err.error_start, 11);
assert_eq!(err.error_end, 13); assert_eq!(err.error_end, 13);
@ -296,7 +289,7 @@ mod tests {
let fun_decl = try_parse(&tokens, 0); let fun_decl = try_parse(&tokens, 0);
match fun_decl { match fun_decl {
ParseResult::Err(err) => { Err(ParsingError::Err(err)) => {
assert_eq!(err.reason, "Expected a closing brace after the block body."); assert_eq!(err.reason, "Expected a closing brace after the block body.");
assert_eq!(err.error_start, 9); assert_eq!(err.error_start, 9);
assert_eq!(err.error_end, 10); assert_eq!(err.error_end, 10);
@ -308,9 +301,7 @@ mod tests {
#[test] #[test]
fn should_parse_simple_function_declaration() { fn should_parse_simple_function_declaration() {
let tokens = get_tokens(&String::from("fun id() {}")).unwrap(); let tokens = get_tokens(&String::from("fun id() {}")).unwrap();
let ParseResult::Ok(function_declaration, _) = try_parse(&tokens, 0) else { let (function_declaration, _) = try_parse(&tokens, 0).unwrap();
panic!("Expected a function declaration.")
};
assert_eq!(function_declaration.identifier.value, String::from("id")); assert_eq!(function_declaration.identifier.value, String::from("id"));
} }
@ -325,9 +316,7 @@ mod whitespace_test {
#[test] #[test]
fn should_ignore_whitespace_1() { fn should_ignore_whitespace_1() {
let tokens = get_tokens(&String::from("fun\nid() {}")).unwrap(); let tokens = get_tokens(&String::from("fun\nid() {}")).unwrap();
let ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else { let (declaration, _) = try_parse(&tokens, 0).unwrap();
panic!("Expected a function declaration.")
};
assert_eq!(declaration.identifier.value, (String::from("id"))); assert_eq!(declaration.identifier.value, (String::from("id")));
} }
@ -335,9 +324,7 @@ mod whitespace_test {
#[test] #[test]
fn should_ignore_whitespace_2() { fn should_ignore_whitespace_2() {
let tokens = get_tokens(&String::from("fun\nid\n() {}")).unwrap(); let tokens = get_tokens(&String::from("fun\nid\n() {}")).unwrap();
let ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else { let (declaration, _) = try_parse(&tokens, 0).unwrap();
panic!("Expected a function declaration.")
};
assert_eq!(declaration.identifier.value, (String::from("id"))); assert_eq!(declaration.identifier.value, (String::from("id")));
} }
@ -345,9 +332,7 @@ mod whitespace_test {
#[test] #[test]
fn should_ignore_whitespace_3() { fn should_ignore_whitespace_3() {
let tokens = get_tokens(&String::from("fun\nid\n(\n) {}")).unwrap(); let tokens = get_tokens(&String::from("fun\nid\n(\n) {}")).unwrap();
let ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else { let (declaration, _) = try_parse(&tokens, 0).unwrap();
panic!("Expected a function declaration.")
};
assert_eq!(declaration.identifier.value, (String::from("id"))); assert_eq!(declaration.identifier.value, (String::from("id")));
} }
@ -355,18 +340,14 @@ mod whitespace_test {
#[test] #[test]
fn should_ignore_whitespace_4() { fn should_ignore_whitespace_4() {
let tokens = get_tokens(&String::from("fun id\n(\n)\n{}")).unwrap(); let tokens = get_tokens(&String::from("fun id\n(\n)\n{}")).unwrap();
let ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else { let (declaration, _) = try_parse(&tokens, 0).unwrap();
panic!("Expected a function declaration.")
};
assert_eq!(declaration.identifier.value, (String::from("id"))); assert_eq!(declaration.identifier.value, (String::from("id")));
} }
#[test] #[test]
fn should_ignore_whitespace_5() { fn should_ignore_whitespace_5() {
let tokens = get_tokens(&String::from("fun\nid() \n{\n}")).unwrap(); let tokens = get_tokens(&String::from("fun\nid() \n{\n}")).unwrap();
let ParseResult::Ok(declaration, _) = try_parse(&tokens, 0) else { let (declaration, _) = try_parse(&tokens, 0).unwrap();
panic!("Expected a function declaration.")
};
assert_eq!(declaration.identifier.value, (String::from("id"))); assert_eq!(declaration.identifier.value, (String::from("id")));
} }
} }

View File

@ -33,6 +33,7 @@ pub enum ParseResult<'a, A> {
pub type ParsingResult<'a, A> = Result<(A, usize), ParsingError<'a>>; pub type ParsingResult<'a, A> = Result<(A, usize), ParsingError<'a>>;
#[derive(Debug)]
pub enum ParsingError<'a> { pub enum ParsingError<'a> {
/// Some other token was found than the expected one /// Some other token was found than the expected one
Mismatch(&'a Token), Mismatch(&'a Token),
@ -60,11 +61,11 @@ pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError
} }
match next_construct(tokens, current_pos) { match next_construct(tokens, current_pos) {
ParseResult::Ok(module, next_pos) => { Ok((module, next_pos)) => {
top_level_declarations.push(module); top_level_declarations.push(module);
current_pos = next_pos; current_pos = next_pos;
} }
ParseResult::Err(err) => return Err(MistiError::Syntax(err)), Err(ParsingError::Err(err)) => return Err(MistiError::Syntax(err)),
_ => { _ => {
return Err(MistiError::Syntax(SyntaxError { return Err(MistiError::Syntax(SyntaxError {
reason: String::from("PARSER couldn't parse any construction"), reason: String::from("PARSER couldn't parse any construction"),
@ -84,27 +85,21 @@ pub fn construct_ast<'a>(tokens: &'a Vec<Token>) -> Result<ModuleAST, MistiError
fn next_construct<'a>( fn next_construct<'a>(
tokens: &'a Vec<Token>, tokens: &'a Vec<Token>,
current_pos: usize, current_pos: usize,
) -> ParseResult<TopLevelDeclaration> { ) -> ParsingResult<TopLevelDeclaration> {
None.or_else( // Try to parse a function declaration
|| match functions::function_declaration::try_parse(tokens, current_pos) { match functions::function_declaration::try_parse(tokens, current_pos) {
ParseResult::Ok(declaration, next_pos) => Some(ParseResult::Ok( Ok((declaration, next_pos)) => {
return Ok((
TopLevelDeclaration::FunctionDeclaration(declaration), TopLevelDeclaration::FunctionDeclaration(declaration),
next_pos, next_pos,
)), ))
ParseResult::Err(err) => Some(ParseResult::Err(err)), }
_ => None, Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
}, _ => {}
) }
.or_else(|| match expression::try_parse(tokens, current_pos) {
ParseResult::Ok(expression, next_pos) => Some(ParseResult::Ok( // No top level construct was found, return unmatched
TopLevelDeclaration::Expression(expression), Err(ParsingError::Unmatched)
next_pos,
)),
ParseResult::Err(_) => todo!(),
ParseResult::Mismatch(_) => todo!(),
ParseResult::Unmatched => todo!(),
})
.unwrap_or_else(|| ParseResult::Unmatched)
} }
#[cfg(test)] #[cfg(test)]
@ -113,7 +108,7 @@ mod tests {
#[test] #[test]
fn should_parse_top_level_construct_with_trailing_newline() { fn should_parse_top_level_construct_with_trailing_newline() {
let input = String::from("fun f1(){}\n"); let input = String::from(" fun f1(){}\n");
let tokens = crate::lexic::get_tokens(&input).unwrap(); let tokens = crate::lexic::get_tokens(&input).unwrap();
let declarations = construct_ast(&tokens).unwrap().declarations; let declarations = construct_ast(&tokens).unwrap().declarations;

View File

@ -65,7 +65,9 @@ pub fn try_operator(tokens: &Vec<Token>, pos: usize, operator: String) -> Result
/// Expects the token at `pos` to be of type `token_type`, and returns the token and the next position. /// Expects the token at `pos` to be of type `token_type`, and returns the token and the next position.
/// ///
/// Ignores all whitespace and newlines /// Ignores all whitespace and newlines.
///
/// Only returns: Ok, Unmatched, Mismatched
pub fn parse_token_type( pub fn parse_token_type(
tokens: &Vec<Token>, tokens: &Vec<Token>,
pos: usize, pos: usize,