2023-10-05 11:51:48 +00:00
|
|
|
use super::ast::var_binding::{Binding, ValBinding, VarBinding};
|
2023-09-20 01:06:38 +00:00
|
|
|
use super::utils::{try_operator, try_token_type};
|
2023-09-24 23:51:08 +00:00
|
|
|
use super::{expression, ParseResult};
|
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-03-16 18:31:24 +00:00
|
|
|
use crate::utils::Result3;
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2023-09-24 23:51:08 +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;
|
2023-02-15 21:17:50 +00:00
|
|
|
// Optional datatype annotation
|
|
|
|
let datatype_annotation = {
|
2023-09-17 22:58:56 +00:00
|
|
|
match try_token_type(tokens, current_pos, TokenType::Datatype) {
|
2023-03-16 18:31:24 +00:00
|
|
|
Result3::Ok(t) => {
|
2023-09-17 22:58:56 +00:00
|
|
|
current_pos += 1;
|
2023-02-15 21:17:50 +00:00
|
|
|
Some(String::from(&t.value))
|
|
|
|
}
|
2023-03-16 18:31:24 +00:00
|
|
|
Result3::Err(_) => None,
|
2023-10-05 11:51:48 +00:00
|
|
|
Result3::None => return ParseResult::Unmatched,
|
2023-02-15 21:17:50 +00:00
|
|
|
}
|
|
|
|
};
|
2023-03-14 21:10:43 +00:00
|
|
|
|
2023-03-28 14:53:26 +00:00
|
|
|
/*
|
|
|
|
* val/var keyword
|
|
|
|
*/
|
2023-03-15 21:33:00 +00:00
|
|
|
let (is_val, binding_token) = {
|
2023-09-17 22:58:56 +00:00
|
|
|
let res1 = try_token_type(tokens, current_pos, TokenType::VAL);
|
2023-02-09 23:44:31 +00:00
|
|
|
match res1 {
|
2023-03-16 18:31:24 +00:00
|
|
|
Result3::Ok(val_token) => (true, val_token),
|
|
|
|
_ => {
|
2023-09-17 22:58:56 +00:00
|
|
|
let res2 = try_token_type(tokens, current_pos, TokenType::VAR);
|
2023-02-09 23:44:31 +00:00
|
|
|
match res2 {
|
2023-03-16 18:31:24 +00:00
|
|
|
Result3::Ok(var_token) => (false, var_token),
|
2023-03-15 21:33:00 +00:00
|
|
|
// Neither VAL nor VAR were matched, the parser should try
|
|
|
|
// other constructs
|
2023-09-24 23:51:08 +00:00
|
|
|
_ => return ParseResult::Unmatched,
|
2023-02-09 23:44:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2023-03-28 14:53:26 +00:00
|
|
|
/*
|
|
|
|
* identifier
|
|
|
|
*/
|
2023-09-17 22:58:56 +00:00
|
|
|
let identifier = match try_token_type(tokens, current_pos + 1, TokenType::Identifier) {
|
2023-03-16 18:31:24 +00:00
|
|
|
Result3::Ok(t) => t,
|
|
|
|
Result3::Err(t) => {
|
|
|
|
// The parser found a token, but it's not an identifier
|
2023-09-24 23:51:08 +00:00
|
|
|
return ParseResult::Err(SyntaxError {
|
2023-03-16 18:31:24 +00:00
|
|
|
reason: format!(
|
|
|
|
"There should be an identifier after a `{}` token",
|
|
|
|
if is_val { "val" } else { "var" }
|
|
|
|
),
|
2023-03-27 14:41:16 +00:00
|
|
|
error_start: t.position,
|
2023-03-28 14:53:26 +00:00
|
|
|
error_end: t.get_end_position(),
|
2023-09-24 23:51:08 +00:00
|
|
|
});
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
|
|
|
Result3::None => {
|
|
|
|
// The parser didn't find an Identifier after VAL/VAR
|
2023-09-24 23:51:08 +00:00
|
|
|
return ParseResult::Err(SyntaxError {
|
2023-03-16 18:31:24 +00:00
|
|
|
reason: format!(
|
|
|
|
"There should be an identifier after a `{}` token",
|
|
|
|
if is_val { "val" } else { "var" }
|
|
|
|
),
|
|
|
|
error_start: binding_token.position,
|
2023-03-28 14:53:26 +00:00
|
|
|
error_end: binding_token.get_end_position(),
|
2023-09-24 23:51:08 +00:00
|
|
|
});
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
|
|
|
};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2023-03-28 14:53:26 +00:00
|
|
|
/*
|
|
|
|
* Equal (=) operator
|
|
|
|
*/
|
2023-09-17 22:58:56 +00:00
|
|
|
let equal_operator: &Token = match try_operator(tokens, current_pos + 2, String::from("=")) {
|
2023-03-16 18:31:24 +00:00
|
|
|
Result3::Ok(t) => t,
|
|
|
|
Result3::Err(t) => {
|
2023-03-28 14:53:26 +00:00
|
|
|
// The parser found a token, but it's not the `=` operator
|
2023-09-24 23:51:08 +00:00
|
|
|
return ParseResult::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(),
|
2023-09-24 23:51:08 +00:00
|
|
|
});
|
2023-03-16 18:31:24 +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 {
|
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(),
|
2023-09-24 23:51:08 +00:00
|
|
|
});
|
2023-03-16 18:31:24 +00:00
|
|
|
}
|
|
|
|
};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
2023-09-17 22:58:56 +00:00
|
|
|
let expression = expression::try_parse(tokens, current_pos + 3);
|
2023-03-14 21:10:43 +00:00
|
|
|
if expression.is_none() {
|
2023-09-24 23:51:08 +00:00
|
|
|
return ParseResult::Err(SyntaxError {
|
2023-03-28 15:06:23 +00:00
|
|
|
reason: String::from("Expected an expression after the equal `=` operator"),
|
|
|
|
error_start: equal_operator.position,
|
|
|
|
error_end: equal_operator.get_end_position(),
|
2023-09-24 23:51:08 +00:00
|
|
|
});
|
2023-03-14 21:10:43 +00:00
|
|
|
}
|
2023-01-08 23:09:06 +00:00
|
|
|
let expression = expression.unwrap();
|
|
|
|
|
2023-03-14 21:10:43 +00:00
|
|
|
let binding = if is_val {
|
|
|
|
Binding::Val(ValBinding {
|
2023-02-15 21:17:50 +00:00
|
|
|
datatype: datatype_annotation,
|
2023-09-08 01:32:59 +00:00
|
|
|
identifier: Box::new(identifier.value.clone()),
|
2023-02-09 23:44:31 +00:00
|
|
|
expression,
|
2023-03-14 21:10:43 +00:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Binding::Var(VarBinding {
|
2023-02-15 21:17:50 +00:00
|
|
|
datatype: datatype_annotation,
|
2023-09-08 01:32:59 +00:00
|
|
|
identifier: Box::new(identifier.value.clone()),
|
2023-02-09 23:44:31 +00:00
|
|
|
expression,
|
2023-03-14 21:10:43 +00:00
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2023-09-24 23:51:08 +00:00
|
|
|
ParseResult::Ok(binding, current_pos + 4)
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2023-09-17 22:58:56 +00:00
|
|
|
use crate::{lexic::get_tokens, syntax::ast::TopLevelDeclaration};
|
2023-01-08 23:09:06 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_parse_val_binding() {
|
|
|
|
let tokens = get_tokens(&String::from("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-01-08 23:09:06 +00:00
|
|
|
|
2023-09-24 23:51:08 +00:00
|
|
|
assert_eq!("identifier", format!("{}", binding.identifier));
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_parse_val() {
|
|
|
|
let tokens = get_tokens(&String::from("val")).unwrap();
|
2023-03-16 18:31:24 +00:00
|
|
|
let token = *try_token_type(&tokens, 0, TokenType::VAL).unwrap();
|
2023-01-08 23:09:06 +00:00
|
|
|
|
|
|
|
assert_eq!(TokenType::VAL, token.token_type);
|
|
|
|
assert_eq!("val", token.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_parse_identifier() {
|
|
|
|
let tokens = get_tokens(&String::from("identifier")).unwrap();
|
2023-03-16 18:31:24 +00:00
|
|
|
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();
|
2023-03-16 18:31:24 +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]
|
|
|
|
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-02-15 21:17:50 +00:00
|
|
|
|
2023-09-24 23:51:08 +00:00
|
|
|
assert_eq!(Some(String::from("Num")), binding.datatype);
|
|
|
|
assert_eq!("identifier", format!("{}", binding.identifier));
|
2023-03-14 21:10:43 +00:00
|
|
|
|
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-02-15 21:17:50 +00:00
|
|
|
|
2023-09-24 23:51:08 +00:00
|
|
|
assert_eq!(Some(String::from("Bool")), binding.datatype);
|
|
|
|
assert_eq!("identifier", format!("{}", binding.identifier));
|
2023-02-15 21:17:50 +00:00
|
|
|
}
|
2023-03-15 21:33:00 +00:00
|
|
|
|
|
|
|
#[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);
|
2023-09-24 23:51:08 +00:00
|
|
|
let binding = try_parse(&tokens, 0);
|
2023-03-15 21:33:00 +00:00
|
|
|
|
|
|
|
match binding {
|
2023-09-24 23:51:08 +00:00
|
|
|
ParseResult::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() {
|
|
|
|
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
|
|
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
|
|
|
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 {
|
2023-09-24 23:51:08 +00:00
|
|
|
ParseResult::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
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-09-24 23:51:08 +00:00
|
|
|
ParseResult::Err(error) => {
|
2023-03-27 14:41:16 +00:00
|
|
|
assert_eq!(4, error.error_start);
|
|
|
|
assert_eq!(11, error.error_end);
|
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() {
|
|
|
|
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 {
|
2023-09-24 23:51:08 +00:00
|
|
|
ParseResult::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
|
|
|
}
|
|
|
|
}
|
2023-01-08 23:09:06 +00:00
|
|
|
}
|