[syntax] refactor bindings

master
Araozu 2023-09-24 18:51:08 -05:00
parent 1fbc353ebf
commit 2e9776de01
2 changed files with 40 additions and 52 deletions

View File

@ -1,6 +1,6 @@
use super::ast::{Binding, ValBinding, VarBinding};
use super::utils::{try_operator, try_token_type};
use super::{expression, SyntaxResult};
use super::{expression, ParseResult};
use crate::error_handling::SyntaxError;
use crate::lexic::token::{Token, TokenType};
use crate::utils::Result3;
@ -9,7 +9,7 @@ use crate::utils::Result3;
// - Success: binding parsed successfully
// - NotFound: the first token (var | val) was not found, so the parser should try other options
// - Error: token (var | val) was found, but then other expected tokens were not found
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult> {
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding, ()> {
let mut current_pos = pos;
// Optional datatype annotation
let datatype_annotation = {
@ -38,7 +38,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult>
Result3::Ok(var_token) => (false, var_token),
// Neither VAL nor VAR were matched, the parser should try
// other constructs
_ => return None,
_ => return ParseResult::Unmatched,
}
}
}
@ -51,25 +51,25 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult>
Result3::Ok(t) => t,
Result3::Err(t) => {
// The parser found a token, but it's not an identifier
return Some(SyntaxResult::Err(SyntaxError {
return ParseResult::Err(SyntaxError {
reason: format!(
"There should be an identifier after a `{}` token",
if is_val { "val" } else { "var" }
),
error_start: t.position,
error_end: t.get_end_position(),
}));
});
}
Result3::None => {
// The parser didn't find an Identifier after VAL/VAR
return Some(SyntaxResult::Err(SyntaxError {
return ParseResult::Err(SyntaxError {
reason: format!(
"There should be an identifier after a `{}` token",
if is_val { "val" } else { "var" }
),
error_start: binding_token.position,
error_end: binding_token.get_end_position(),
}));
});
}
};
@ -80,29 +80,29 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult>
Result3::Ok(t) => t,
Result3::Err(t) => {
// The parser found a token, but it's not the `=` operator
return Some(SyntaxResult::Err(SyntaxError {
return ParseResult::Err(SyntaxError {
reason: format!("There should be an equal sign `=` after the identifier"),
error_start: t.position,
error_end: t.get_end_position(),
}));
});
}
Result3::None => {
// The parser didn't find the `=` operator after the identifier
return Some(SyntaxResult::Err(SyntaxError {
return ParseResult::Err(SyntaxError {
reason: format!("There should be an equal sign `=` after the identifier",),
error_start: identifier.position,
error_end: identifier.get_end_position(),
}));
});
}
};
let expression = expression::try_parse(tokens, current_pos + 3);
if expression.is_none() {
return Some(SyntaxResult::Err(SyntaxError {
return ParseResult::Err(SyntaxError {
reason: String::from("Expected an expression after the equal `=` operator"),
error_start: equal_operator.position,
error_end: equal_operator.get_end_position(),
}));
});
}
let expression = expression.unwrap();
@ -120,10 +120,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult>
})
};
Some(SyntaxResult::Ok(
super::ast::TopLevelDeclaration::Binding(binding),
current_pos + 4,
))
ParseResult::Ok(binding, current_pos + 4)
}
#[cfg(test)]
@ -134,15 +131,12 @@ mod tests {
#[test]
fn should_parse_val_binding() {
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
let binding = try_parse(&tokens, 0).unwrap();
let ParseResult::Ok(Binding::Val(binding), _) = try_parse(&tokens, 0) else {
panic!()
};
match binding {
SyntaxResult::Ok(TopLevelDeclaration::Binding(Binding::Val(binding)), _) => {
assert_eq!("identifier", format!("{}", binding.identifier));
}
_ => panic!(),
}
}
#[test]
fn should_parse_val() {
@ -172,37 +166,31 @@ mod tests {
#[test]
fn should_parse_binding_with_datatype() {
let tokens = get_tokens(&String::from("Num val identifier = 20")).unwrap();
let binding = try_parse(&tokens, 0).unwrap();
let ParseResult::Ok(Binding::Val(binding), _) = try_parse(&tokens, 0) else {
panic!()
};
match binding {
SyntaxResult::Ok(TopLevelDeclaration::Binding(Binding::Val(binding)), _) => {
assert_eq!(Some(String::from("Num")), binding.datatype);
assert_eq!("identifier", format!("{}", binding.identifier));
}
_ => panic!(),
}
let tokens = get_tokens(&String::from("Bool var identifier = true")).unwrap();
let binding = try_parse(&tokens, 0).unwrap();
let tokens = get_tokens(&String::from("Bool var identifier = 20")).unwrap();
let ParseResult::Ok(Binding::Var(binding), _) = try_parse(&tokens, 0) else {
panic!()
};
match binding {
SyntaxResult::Ok(TopLevelDeclaration::Binding(Binding::Var(binding)), _) => {
assert_eq!(Some(String::from("Bool")), binding.datatype);
assert_eq!("identifier", format!("{}", binding.identifier));
}
_ => panic!("D: {:?}", binding),
}
}
#[test]
fn should_return_correct_error() {
let tokens = get_tokens(&String::from("val")).unwrap();
assert_eq!(TokenType::VAL, tokens[0].token_type);
assert_eq!(0, tokens[0].position);
let binding = try_parse(&tokens, 0).unwrap();
let binding = try_parse(&tokens, 0);
match binding {
SyntaxResult::Err(error) => {
ParseResult::Err(error) => {
assert_eq!(0, error.error_start);
assert_eq!(3, error.error_end);
}
@ -215,10 +203,10 @@ mod tests {
let tokens = get_tokens(&String::from("val 322")).unwrap();
assert_eq!(TokenType::VAL, tokens[0].token_type);
assert_eq!(0, tokens[0].position);
let binding = try_parse(&tokens, 0).unwrap();
let binding = try_parse(&tokens, 0);
match binding {
SyntaxResult::Err(error) => {
ParseResult::Err(error) => {
assert_eq!(4, error.error_start);
assert_eq!(7, error.error_end);
}
@ -226,10 +214,10 @@ mod tests {
}
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
let binding = try_parse(&tokens, 0).unwrap();
let binding = try_parse(&tokens, 0);
match binding {
SyntaxResult::Err(error) => {
ParseResult::Err(error) => {
assert_eq!(4, error.error_start);
assert_eq!(11, error.error_end);
}
@ -240,10 +228,10 @@ mod tests {
#[test]
fn should_return_error_when_equal_op_is_wrong() {
let tokens = get_tokens(&String::from("val id \"error\"")).unwrap();
let binding = try_parse(&tokens, 0).unwrap();
let binding = try_parse(&tokens, 0);
match binding {
SyntaxResult::Err(error) => {
ParseResult::Err(error) => {
assert_eq!(7, error.error_start);
assert_eq!(14, error.error_end);
}

View File

@ -5,7 +5,7 @@ use crate::{
};
use super::{
ast::{FunctionDeclaration, ParamsList},
ast::FunctionDeclaration,
block::parse_block,
params_list::parse_params_list,
utils::{parse_token_type, try_token_type},
@ -98,7 +98,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Function
#[cfg(test)]
mod tests {
use crate::{lexic::get_tokens, syntax::ast::TopLevelDeclaration};
use crate::lexic::get_tokens;
use super::*;
@ -317,7 +317,7 @@ mod tests {
#[cfg(test)]
mod whitespace_test {
use crate::{lexic::get_tokens, syntax::ast::TopLevelDeclaration};
use crate::lexic::get_tokens;
use super::*;