2024-06-01 23:57:10 +00:00
|
|
|
use super::ast::var_binding::VariableBinding;
|
2023-11-04 11:46:24 +00:00
|
|
|
use super::utils::{parse_token_type, try_operator};
|
2024-03-15 22:42:35 +00:00
|
|
|
use super::{expression, ParsingError, ParsingResult};
|
2023-03-15 21:33:00 +00:00
|
|
|
use crate::error_handling::SyntaxError;
|
2023-09-08 01:46:11 +00:00
|
|
|
use crate::lexic::token::{Token, TokenType};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2024-03-18 14:51:17 +00:00
|
|
|
/*
|
|
|
|
binding = val binding | var binding
|
|
|
|
val binding = "val", datatype?, binding remainder
|
|
|
|
| datatype, binding remainder
|
|
|
|
|
|
|
|
var binding = "var", datatype?, binding remainder
|
|
|
|
|
|
|
|
binding remainder = identifier, "=", expression
|
|
|
|
*/
|
2024-06-01 23:57:10 +00:00
|
|
|
pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParsingResult<VariableBinding> {
|
2023-09-17 22:58:56 +00:00
|
|
|
let mut current_pos = pos;
|
2023-11-04 11:52:46 +00:00
|
|
|
|
2023-03-28 14:53:26 +00:00
|
|
|
/*
|
2024-03-18 14:51:17 +00:00
|
|
|
* val/var keyword
|
2023-03-28 14:53:26 +00:00
|
|
|
*/
|
2024-03-18 14:51:17 +00:00
|
|
|
let (is_var, binding_token, next_pos) = 'token: {
|
|
|
|
// check for VAL
|
|
|
|
if let Ok((val_token, next_pos)) = parse_token_type(tokens, current_pos, TokenType::VAL) {
|
|
|
|
break 'token (false, Some(val_token), next_pos);
|
|
|
|
};
|
|
|
|
|
|
|
|
// check for VAR
|
|
|
|
match parse_token_type(tokens, current_pos, TokenType::VAR) {
|
|
|
|
Ok((var_token, next_pos)) => (true, Some(var_token), next_pos),
|
|
|
|
// If a VAR is not found it is still possible that the binding is an implicit VAL
|
|
|
|
_ => (false, None, current_pos),
|
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
|
|
|
|
2024-03-18 14:51:17 +00:00
|
|
|
/*
|
|
|
|
* datatype
|
|
|
|
*/
|
|
|
|
let (datatype, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Datatype) {
|
|
|
|
Ok((t, next)) => (Some(t), next),
|
|
|
|
_ => (None, current_pos),
|
|
|
|
};
|
|
|
|
current_pos = next_pos;
|
|
|
|
|
|
|
|
// Here:
|
|
|
|
// If the binding is None and the datatype is None, then we didn't match a binding
|
|
|
|
if binding_token.is_none() && datatype.is_none() {
|
|
|
|
return Err(ParsingError::Unmatched);
|
|
|
|
}
|
|
|
|
|
2023-03-28 14:53:26 +00:00
|
|
|
/*
|
|
|
|
* identifier
|
|
|
|
*/
|
2023-11-04 11:46:24 +00:00
|
|
|
let (identifier, next_pos) = match parse_token_type(tokens, current_pos, TokenType::Identifier)
|
|
|
|
{
|
2024-03-15 21:56:45 +00:00
|
|
|
Ok((t, n)) => (t, n),
|
|
|
|
Err(ParsingError::Mismatch(token)) => {
|
2023-03-16 18:31:24 +00:00
|
|
|
// The parser found a token, but it's not an identifier
|
2024-03-15 22:42:35 +00:00
|
|
|
return Err(ParsingError::Err(SyntaxError {
|
2023-11-04 10:41:16 +00:00
|
|
|
error_start: token.position,
|
|
|
|
error_end: token.get_end_position(),
|
2024-05-04 23:22:36 +00:00
|
|
|
reason: "There should be an identifier after a binding".into(),
|
2024-03-15 22:42:35 +00:00
|
|
|
}));
|
2023-11-04 10:41:16 +00:00
|
|
|
}
|
2023-10-06 01:26:47 +00:00
|
|
|
_ => {
|
2024-03-18 14:51:17 +00:00
|
|
|
// The parser didn't find an Identifier after VAL/VAR or the Datatype
|
|
|
|
match (binding_token, datatype) {
|
2024-05-04 23:22:36 +00:00
|
|
|
(Some(binding_token), None) => {
|
2024-03-18 14:51:17 +00:00
|
|
|
return Err(ParsingError::Err(SyntaxError {
|
|
|
|
reason: format!(
|
|
|
|
"There should be an identifier after a `{}` token",
|
2024-05-04 23:22:36 +00:00
|
|
|
if is_var { "var" } else { "val" }
|
2024-03-18 14:51:17 +00:00
|
|
|
),
|
|
|
|
error_start: binding_token.position,
|
|
|
|
error_end: binding_token.get_end_position(),
|
|
|
|
}));
|
|
|
|
}
|
2024-05-04 23:22:36 +00:00
|
|
|
(_, Some(datatype_token)) => {
|
2024-03-18 14:51:17 +00:00
|
|
|
return Err(ParsingError::Err(SyntaxError {
|
|
|
|
reason: "There should be an identifier after the datatype".into(),
|
|
|
|
error_start: datatype_token.position,
|
|
|
|
error_end: datatype_token.get_end_position(),
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
_ => {
|
2024-05-04 23:22:36 +00:00
|
|
|
unreachable!("Illegal parser state: binding_token and datatype are both None")
|
2024-03-18 14:51:17 +00:00
|
|
|
}
|
|
|
|
};
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
|
|
|
};
|
2023-10-06 01:26:47 +00:00
|
|
|
current_pos = next_pos;
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2023-03-28 14:53:26 +00:00
|
|
|
/*
|
|
|
|
* Equal (=) operator
|
|
|
|
*/
|
2023-11-04 11:46:24 +00:00
|
|
|
let equal_operator = match try_operator(tokens, current_pos, String::from("=")) {
|
2024-03-15 21:59:28 +00:00
|
|
|
Ok((t, _)) => t,
|
|
|
|
Err(ParsingError::Mismatch(t)) => {
|
2023-03-28 14:53:26 +00:00
|
|
|
// The parser found a token, but it's not the `=` operator
|
2024-03-15 22:42:35 +00:00
|
|
|
return Err(ParsingError::Err(SyntaxError {
|
2023-03-28 14:53:26 +00:00
|
|
|
reason: format!("There should be an equal sign `=` after the identifier"),
|
|
|
|
error_start: t.position,
|
|
|
|
error_end: t.get_end_position(),
|
2024-03-15 22:42:35 +00:00
|
|
|
}));
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
2024-03-15 21:59:28 +00:00
|
|
|
_ => {
|
2023-03-16 18:31:24 +00:00
|
|
|
// The parser didn't find the `=` operator after the identifier
|
2024-03-15 22:42:35 +00:00
|
|
|
return Err(ParsingError::Err(SyntaxError {
|
2023-03-16 18:31:24 +00:00
|
|
|
reason: format!("There should be an equal sign `=` after the identifier",),
|
|
|
|
error_start: identifier.position,
|
2023-03-28 14:53:26 +00:00
|
|
|
error_end: identifier.get_end_position(),
|
2024-03-15 22:42:35 +00:00
|
|
|
}));
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
|
|
|
};
|
2023-11-04 11:52:46 +00:00
|
|
|
current_pos += 1;
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2024-03-18 14:51:17 +00:00
|
|
|
/*
|
|
|
|
* Expression of the binding
|
|
|
|
*/
|
2023-11-04 11:52:46 +00:00
|
|
|
let (expression, next_pos) = match expression::try_parse(tokens, current_pos) {
|
2024-03-15 22:42:35 +00:00
|
|
|
Ok((exp, next)) => (exp, next),
|
2023-11-04 11:46:24 +00:00
|
|
|
_ => {
|
2024-03-15 22:42:35 +00:00
|
|
|
return Err(ParsingError::Err(SyntaxError {
|
2023-11-04 11:46:24 +00:00
|
|
|
reason: String::from("Expected an expression after the equal `=` operator"),
|
|
|
|
error_start: equal_operator.position,
|
|
|
|
error_end: equal_operator.get_end_position(),
|
2024-03-15 22:42:35 +00:00
|
|
|
}));
|
2023-11-04 11:46:24 +00:00
|
|
|
}
|
|
|
|
};
|
2023-11-04 11:52:46 +00:00
|
|
|
current_pos = next_pos;
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2024-06-01 23:57:10 +00:00
|
|
|
let binding = VariableBinding {
|
2024-03-18 14:51:17 +00:00
|
|
|
datatype,
|
2024-03-10 02:34:05 +00:00
|
|
|
identifier: &identifier,
|
2023-12-17 01:51:12 +00:00
|
|
|
expression,
|
2024-03-18 14:51:17 +00:00
|
|
|
is_mutable: is_var,
|
2023-03-14 21:10:43 +00:00
|
|
|
};
|
|
|
|
|
2024-03-15 22:42:35 +00:00
|
|
|
Ok((binding, current_pos))
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2024-03-15 21:56:45 +00:00
|
|
|
use crate::{lexic::get_tokens, syntax::utils::parse_token_type};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_parse_val_binding() {
|
2024-03-18 13:57:28 +00:00
|
|
|
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
2024-03-15 22:42:35 +00:00
|
|
|
let Ok((binding, _)) = try_parse(&tokens, 0) else {
|
2023-09-24 23:51:08 +00:00
|
|
|
panic!()
|
|
|
|
};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2024-03-10 02:34:05 +00:00
|
|
|
assert_eq!("identifier", format!("{}", binding.identifier.value));
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_parse_val() {
|
2024-03-18 13:57:28 +00:00
|
|
|
let tokens = get_tokens(&String::from("val")).unwrap();
|
|
|
|
let (token, _) = parse_token_type(&tokens, 0, TokenType::VAL).unwrap();
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2024-03-18 13:57:28 +00:00
|
|
|
assert_eq!(TokenType::VAL, token.token_type);
|
|
|
|
assert_eq!("val", token.value);
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_parse_identifier() {
|
|
|
|
let tokens = get_tokens(&String::from("identifier")).unwrap();
|
2024-03-15 21:56:45 +00:00
|
|
|
let (token, _) = parse_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();
|
2024-03-15 21:59:28 +00:00
|
|
|
let (token, _) = try_operator(&tokens, 0, String::from("=")).unwrap();
|
2023-01-08 23:09:06 +00:00
|
|
|
|
|
|
|
assert_eq!("=", token.value);
|
|
|
|
}
|
2023-03-14 21:10:43 +00:00
|
|
|
|
2023-02-15 21:17:50 +00:00
|
|
|
#[test]
|
2024-03-18 14:51:17 +00:00
|
|
|
fn should_parse_val_binding_with_datatype() {
|
|
|
|
let tokens = get_tokens(&String::from("val Int identifier = 20")).unwrap();
|
|
|
|
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
2023-02-15 21:17:50 +00:00
|
|
|
|
2024-03-18 14:51:17 +00:00
|
|
|
assert!(!binding.is_mutable);
|
|
|
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
|
|
|
assert_eq!("identifier", binding.identifier.value);
|
|
|
|
}
|
2023-03-14 21:10:43 +00:00
|
|
|
|
2024-03-18 14:51:17 +00:00
|
|
|
#[test]
|
|
|
|
fn should_parse_var_binding_with_datatype() {
|
|
|
|
let tokens = get_tokens(&String::from("var Int identifier = 20")).unwrap();
|
|
|
|
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
|
|
|
|
|
|
|
assert!(binding.is_mutable);
|
|
|
|
assert!(binding.datatype.is_some());
|
|
|
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
|
|
|
assert_eq!("identifier", binding.identifier.value);
|
|
|
|
}
|
2023-02-15 21:17:50 +00:00
|
|
|
|
2024-03-18 14:51:17 +00:00
|
|
|
#[test]
|
|
|
|
fn should_parse_implicit_val_binding() {
|
|
|
|
let tokens = get_tokens(&String::from("Int identifier = 20")).unwrap();
|
|
|
|
let (binding, _) = try_parse(&tokens, 0).unwrap();
|
|
|
|
|
|
|
|
assert!(!binding.is_mutable);
|
|
|
|
assert!(binding.datatype.is_some());
|
|
|
|
assert_eq!("Int", binding.datatype.unwrap().value);
|
|
|
|
assert_eq!("identifier", binding.identifier.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_return_error_on_implicit_val_binding() {
|
|
|
|
let tokens = get_tokens(&String::from("Int => 20")).unwrap();
|
|
|
|
let binding = try_parse(&tokens, 0);
|
|
|
|
|
|
|
|
match binding {
|
|
|
|
Err(ParsingError::Err(error)) => {
|
|
|
|
assert_eq!(4, error.error_start);
|
|
|
|
assert_eq!(6, error.error_end);
|
|
|
|
}
|
|
|
|
_ => panic!("Error expected"),
|
|
|
|
}
|
2023-02-15 21:17:50 +00:00
|
|
|
}
|
2023-03-15 21:33:00 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_return_correct_error() {
|
2024-03-18 13:57:28 +00:00
|
|
|
let tokens = get_tokens(&String::from("val")).unwrap();
|
|
|
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
2023-03-15 21:33:00 +00:00
|
|
|
assert_eq!(0, tokens[0].position);
|
2023-09-24 23:51:08 +00:00
|
|
|
let binding = try_parse(&tokens, 0);
|
2023-03-15 21:33:00 +00:00
|
|
|
|
|
|
|
match binding {
|
2024-03-15 22:42:35 +00:00
|
|
|
Err(ParsingError::Err(error)) => {
|
2023-03-15 21:33:00 +00:00
|
|
|
assert_eq!(0, error.error_start);
|
|
|
|
assert_eq!(3, error.error_end);
|
|
|
|
}
|
2023-03-16 18:31:24 +00:00
|
|
|
_ => panic!("Error expected"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_return_error_when_identifier_is_wrong() {
|
2024-03-18 13:57:28 +00:00
|
|
|
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
|
|
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
2023-03-16 18:31:24 +00:00
|
|
|
assert_eq!(0, tokens[0].position);
|
2023-09-24 23:51:08 +00:00
|
|
|
let binding = try_parse(&tokens, 0);
|
2023-03-16 18:31:24 +00:00
|
|
|
|
|
|
|
match binding {
|
2024-03-15 22:42:35 +00:00
|
|
|
Err(ParsingError::Err(error)) => {
|
2023-03-27 14:41:16 +00:00
|
|
|
assert_eq!(4, error.error_start);
|
|
|
|
assert_eq!(7, error.error_end);
|
|
|
|
}
|
2023-04-05 15:31:12 +00:00
|
|
|
_ => panic!("Error expected"),
|
2023-03-27 14:41:16 +00:00
|
|
|
}
|
|
|
|
|
2024-03-18 13:57:28 +00:00
|
|
|
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
|
2023-09-24 23:51:08 +00:00
|
|
|
let binding = try_parse(&tokens, 0);
|
2023-03-27 14:41:16 +00:00
|
|
|
|
|
|
|
match binding {
|
2024-03-15 22:42:35 +00:00
|
|
|
Err(ParsingError::Err(error)) => {
|
2023-03-27 14:41:16 +00:00
|
|
|
assert_eq!(4, error.error_start);
|
|
|
|
assert_eq!(11, error.error_end);
|
2024-06-01 23:57:10 +00:00
|
|
|
assert_eq!(
|
|
|
|
"There should be an identifier after a binding",
|
|
|
|
error.reason
|
|
|
|
);
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
2023-04-05 15:31:12 +00:00
|
|
|
_ => panic!("Error expected"),
|
2023-03-15 21:33:00 +00:00
|
|
|
}
|
|
|
|
}
|
2023-03-28 14:53:26 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_return_error_when_equal_op_is_wrong() {
|
2024-03-18 13:57:28 +00:00
|
|
|
let tokens = get_tokens(&String::from("val id \"error\"")).unwrap();
|
2023-09-24 23:51:08 +00:00
|
|
|
let binding = try_parse(&tokens, 0);
|
2023-03-28 14:53:26 +00:00
|
|
|
|
|
|
|
match binding {
|
2024-03-15 22:42:35 +00:00
|
|
|
Err(ParsingError::Err(error)) => {
|
2023-03-28 14:53:26 +00:00
|
|
|
assert_eq!(7, error.error_start);
|
|
|
|
assert_eq!(14, error.error_end);
|
|
|
|
}
|
2023-04-05 15:31:12 +00:00
|
|
|
_ => panic!("Error expected"),
|
2023-03-28 14:53:26 +00:00
|
|
|
}
|
|
|
|
}
|
2024-05-04 23:22:36 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_return_error_when_identifier_is_empty() {
|
|
|
|
let tokens = get_tokens(&String::from("val String ")).unwrap();
|
|
|
|
let binding = try_parse(&tokens, 0);
|
|
|
|
|
|
|
|
match binding {
|
|
|
|
Err(ParsingError::Err(error)) => {
|
|
|
|
assert_eq!(4, error.error_start);
|
|
|
|
assert_eq!(10, error.error_end);
|
2024-06-01 23:57:10 +00:00
|
|
|
assert_eq!(
|
|
|
|
"There should be an identifier after the datatype",
|
|
|
|
error.reason
|
|
|
|
);
|
2024-05-04 23:22:36 +00:00
|
|
|
}
|
|
|
|
_ => panic!("Error expected"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_return_error_when_identifier_is_empty_2() {
|
|
|
|
let tokens = get_tokens(&String::from("val ")).unwrap();
|
|
|
|
let binding = try_parse(&tokens, 0);
|
|
|
|
|
|
|
|
match binding {
|
|
|
|
Err(ParsingError::Err(error)) => {
|
|
|
|
assert_eq!(0, error.error_start);
|
|
|
|
assert_eq!(3, error.error_end);
|
2024-06-01 23:57:10 +00:00
|
|
|
assert_eq!(
|
|
|
|
"There should be an identifier after a `val` token",
|
|
|
|
error.reason
|
|
|
|
);
|
2024-05-04 23:22:36 +00:00
|
|
|
}
|
|
|
|
_ => panic!("Error expected"),
|
|
|
|
}
|
|
|
|
}
|
2024-05-04 23:34:44 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_error_when_equal_op_is_missing() {
|
|
|
|
let tokens = get_tokens(&String::from("val identifier ")).unwrap();
|
|
|
|
let binding = try_parse(&tokens, 0);
|
|
|
|
|
|
|
|
match binding {
|
|
|
|
Err(ParsingError::Err(error)) => {
|
|
|
|
assert_eq!(4, error.error_start);
|
|
|
|
assert_eq!(14, error.error_end);
|
2024-06-01 23:57:10 +00:00
|
|
|
assert_eq!(
|
|
|
|
"There should be an equal sign `=` after the identifier",
|
|
|
|
error.reason
|
|
|
|
);
|
2024-05-04 23:34:44 +00:00
|
|
|
}
|
|
|
|
_ => panic!("Error expected"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_error_when_exp_is_empty() {
|
|
|
|
let tokens = get_tokens(&String::from("val identifier = ")).unwrap();
|
|
|
|
let binding = try_parse(&tokens, 0);
|
|
|
|
|
|
|
|
match binding {
|
|
|
|
Err(ParsingError::Err(error)) => {
|
|
|
|
assert_eq!(15, error.error_start);
|
|
|
|
assert_eq!(16, error.error_end);
|
2024-06-01 23:57:10 +00:00
|
|
|
assert_eq!(
|
|
|
|
"Expected an expression after the equal `=` operator",
|
|
|
|
error.reason
|
|
|
|
);
|
2024-05-04 23:34:44 +00:00
|
|
|
}
|
|
|
|
_ => panic!("Error expected"),
|
|
|
|
}
|
|
|
|
}
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|