thp/src/syntax/binding.rs

226 lines
7.3 KiB
Rust
Raw Normal View History

2023-12-17 01:51:12 +00:00
use super::ast::var_binding::Binding;
use super::utils::{parse_token_type, try_operator};
2023-09-24 23:51:08 +00:00
use super::{expression, ParseResult};
use crate::error_handling::SyntaxError;
2023-09-08 01:46:11 +00:00
use crate::lexic::token::{Token, TokenType};
use crate::utils::Result3;
2023-01-08 23:09:06 +00:00
2024-03-15 20:49:02 +00:00
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding> {
2023-09-17 22:58:56 +00:00
let mut current_pos = pos;
// TODO: Detect if the binding starts with a datatype
/*
* let keyword
*/
let (is_mutable, binding_token, next_pos) = {
let let_token = parse_token_type(tokens, current_pos, TokenType::LET);
match let_token {
ParseResult::Ok(let_token, next_let) => {
let mut_token = parse_token_type(tokens, next_let, TokenType::MUT);
match mut_token {
ParseResult::Ok(_mut_token, next_mut) => (true, let_token, next_mut),
_ => (false, let_token, next_let),
2023-02-09 23:44:31 +00:00
}
}
_ => return ParseResult::Unmatched,
2023-02-09 23:44:31 +00:00
}
};
2023-10-06 01:26:47 +00:00
current_pos = next_pos;
2023-01-08 23:09:06 +00:00
/*
* identifier
*/
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
{
2023-10-06 01:26:47 +00:00
ParseResult::Ok(t, n) => (t, n),
2023-11-04 10:41:16 +00:00
ParseResult::Mismatch(token) => {
// The parser found a token, but it's not an identifier
2023-11-04 10:41:16 +00:00
return ParseResult::Err(SyntaxError {
error_start: token.position,
error_end: token.get_end_position(),
reason: "??".into(),
});
2023-11-04 10:41:16 +00:00
}
ParseResult::Err(error) => {
2023-10-06 01:26:47 +00:00
return ParseResult::Err(error);
}
2023-10-06 01:26:47 +00:00
_ => {
// The parser didn't find an Identifier after VAL/VAR
2023-09-24 23:51:08 +00:00
return ParseResult::Err(SyntaxError {
reason: format!(
"There should be an identifier after a `{}` token",
if is_mutable { "val" } else { "var" }
),
error_start: binding_token.position,
error_end: binding_token.get_end_position(),
2023-09-24 23:51:08 +00:00
});
}
};
2023-10-06 01:26:47 +00:00
current_pos = next_pos;
2023-01-08 23:09:06 +00:00
/*
* Equal (=) operator
*/
let equal_operator = match try_operator(tokens, current_pos, String::from("=")) {
Result3::Ok(t) => t,
Result3::Err(t) => {
// The parser found a token, but it's not the `=` operator
2023-09-24 23:51:08 +00:00
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(),
2023-09-24 23:51:08 +00:00
});
}
Result3::None => {
// The parser didn't find the `=` operator after the identifier
2023-09-24 23:51:08 +00:00
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(),
2023-09-24 23:51:08 +00:00
});
}
};
current_pos += 1;
2023-01-08 23:09:06 +00:00
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
ParseResult::Ok(exp, next) => (exp, next),
_ => {
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(),
});
}
};
current_pos = next_pos;
2023-01-08 23:09:06 +00:00
2023-12-17 01:51:12 +00:00
let binding = Binding {
datatype: None,
identifier: &identifier,
2023-12-17 01:51:12 +00:00
expression,
is_mutable,
};
ParseResult::Ok(binding, current_pos)
2023-01-08 23:09:06 +00:00
}
#[cfg(test)]
mod tests {
use super::*;
2023-11-04 10:41:16 +00:00
use crate::{lexic::get_tokens, syntax::utils::try_token_type};
2023-01-08 23:09:06 +00:00
#[test]
fn should_parse_val_binding() {
let tokens = get_tokens(&String::from("let identifier = 20")).unwrap();
2023-12-17 01:51:12 +00:00
let ParseResult::Ok(binding, _) = try_parse(&tokens, 0) else {
2023-09-24 23:51:08 +00:00
panic!()
};
2023-01-08 23:09:06 +00:00
assert_eq!("identifier", format!("{}", binding.identifier.value));
2023-01-08 23:09:06 +00:00
}
#[test]
fn should_parse_val() {
let tokens = get_tokens(&String::from("let")).unwrap();
let token = *try_token_type(&tokens, 0, TokenType::LET).unwrap();
2023-01-08 23:09:06 +00:00
assert_eq!(TokenType::LET, token.token_type);
assert_eq!("let", token.value);
2023-01-08 23:09:06 +00:00
}
#[test]
fn should_parse_identifier() {
let tokens = get_tokens(&String::from("identifier")).unwrap();
let token = *try_token_type(&tokens, 0, TokenType::Identifier).unwrap();
2023-01-08 23:09:06 +00:00
assert_eq!("identifier", token.value);
}
#[test]
fn should_parse_operator() {
let tokens = get_tokens(&String::from("=")).unwrap();
let token = *try_operator(&tokens, 0, String::from("=")).unwrap();
2023-01-08 23:09:06 +00:00
assert_eq!("=", token.value);
}
2023-10-06 01:26:47 +00:00
/*
#[test]
fn should_parse_binding_with_datatype() {
let tokens = get_tokens(&String::from("Num val identifier = 20")).unwrap();
2023-09-24 23:51:08 +00:00
let ParseResult::Ok(Binding::Val(binding), _) = try_parse(&tokens, 0) else {
panic!()
};
2023-09-24 23:51:08 +00:00
assert_eq!(Some(String::from("Num")), binding.datatype);
assert_eq!("identifier", format!("{}", binding.identifier));
2023-09-24 23:51:08 +00:00
let tokens = get_tokens(&String::from("Bool var identifier = 20")).unwrap();
let ParseResult::Ok(Binding::Var(binding), _) = try_parse(&tokens, 0) else {
panic!()
};
2023-09-24 23:51:08 +00:00
assert_eq!(Some(String::from("Bool")), binding.datatype);
assert_eq!("identifier", format!("{}", binding.identifier));
}
2023-10-06 01:26:47 +00:00
*/
#[test]
fn should_return_correct_error() {
let tokens = get_tokens(&String::from("let")).unwrap();
assert_eq!(TokenType::LET, tokens[0].token_type);
assert_eq!(0, tokens[0].position);
2023-09-24 23:51:08 +00:00
let binding = try_parse(&tokens, 0);
match binding {
2023-09-24 23:51:08 +00:00
ParseResult::Err(error) => {
assert_eq!(0, error.error_start);
assert_eq!(3, error.error_end);
}
_ => panic!("Error expected"),
}
}
#[test]
fn should_return_error_when_identifier_is_wrong() {
let tokens = get_tokens(&String::from("let 322")).unwrap();
assert_eq!(TokenType::LET, tokens[0].token_type);
assert_eq!(0, tokens[0].position);
2023-09-24 23:51:08 +00:00
let binding = try_parse(&tokens, 0);
match binding {
2023-09-24 23:51:08 +00:00
ParseResult::Err(error) => {
assert_eq!(4, error.error_start);
assert_eq!(7, error.error_end);
}
2023-04-05 15:31:12 +00:00
_ => panic!("Error expected"),
}
let tokens = get_tokens(&String::from("let \"hello\"")).unwrap();
2023-09-24 23:51:08 +00:00
let binding = try_parse(&tokens, 0);
match binding {
2023-09-24 23:51:08 +00:00
ParseResult::Err(error) => {
assert_eq!(4, error.error_start);
assert_eq!(11, error.error_end);
}
2023-04-05 15:31:12 +00:00
_ => panic!("Error expected"),
}
}
#[test]
fn should_return_error_when_equal_op_is_wrong() {
let tokens = get_tokens(&String::from("let id \"error\"")).unwrap();
2023-09-24 23:51:08 +00:00
let binding = try_parse(&tokens, 0);
match binding {
2023-09-24 23:51:08 +00:00
ParseResult::Err(error) => {
assert_eq!(7, error.error_start);
assert_eq!(14, error.error_end);
}
2023-04-05 15:31:12 +00:00
_ => panic!("Error expected"),
}
}
2023-01-08 23:09:06 +00:00
}