[syntax] refactor bindings
This commit is contained in:
parent
1fbc353ebf
commit
2e9776de01
@ -1,6 +1,6 @@
|
|||||||
use super::ast::{Binding, ValBinding, VarBinding};
|
use super::ast::{Binding, ValBinding, VarBinding};
|
||||||
use super::utils::{try_operator, try_token_type};
|
use super::utils::{try_operator, try_token_type};
|
||||||
use super::{expression, SyntaxResult};
|
use super::{expression, ParseResult};
|
||||||
use crate::error_handling::SyntaxError;
|
use crate::error_handling::SyntaxError;
|
||||||
use crate::lexic::token::{Token, TokenType};
|
use crate::lexic::token::{Token, TokenType};
|
||||||
use crate::utils::Result3;
|
use crate::utils::Result3;
|
||||||
@ -9,7 +9,7 @@ use crate::utils::Result3;
|
|||||||
// - Success: binding parsed successfully
|
// - Success: binding parsed successfully
|
||||||
// - NotFound: the first token (var | val) was not found, so the parser should try other options
|
// - 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
|
// - 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;
|
let mut current_pos = pos;
|
||||||
// Optional datatype annotation
|
// Optional datatype annotation
|
||||||
let 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),
|
Result3::Ok(var_token) => (false, var_token),
|
||||||
// Neither VAL nor VAR were matched, the parser should try
|
// Neither VAL nor VAR were matched, the parser should try
|
||||||
// other constructs
|
// 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::Ok(t) => t,
|
||||||
Result3::Err(t) => {
|
Result3::Err(t) => {
|
||||||
// The parser found a token, but it's not an identifier
|
// The parser found a token, but it's not an identifier
|
||||||
return Some(SyntaxResult::Err(SyntaxError {
|
return ParseResult::Err(SyntaxError {
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"There should be an identifier after a `{}` token",
|
"There should be an identifier after a `{}` token",
|
||||||
if is_val { "val" } else { "var" }
|
if is_val { "val" } else { "var" }
|
||||||
),
|
),
|
||||||
error_start: t.position,
|
error_start: t.position,
|
||||||
error_end: t.get_end_position(),
|
error_end: t.get_end_position(),
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
Result3::None => {
|
Result3::None => {
|
||||||
// The parser didn't find an Identifier after VAL/VAR
|
// The parser didn't find an Identifier after VAL/VAR
|
||||||
return Some(SyntaxResult::Err(SyntaxError {
|
return ParseResult::Err(SyntaxError {
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"There should be an identifier after a `{}` token",
|
"There should be an identifier after a `{}` token",
|
||||||
if is_val { "val" } else { "var" }
|
if is_val { "val" } else { "var" }
|
||||||
),
|
),
|
||||||
error_start: binding_token.position,
|
error_start: binding_token.position,
|
||||||
error_end: binding_token.get_end_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::Ok(t) => t,
|
||||||
Result3::Err(t) => {
|
Result3::Err(t) => {
|
||||||
// The parser found a token, but it's not the `=` operator
|
// 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"),
|
reason: format!("There should be an equal sign `=` after the identifier"),
|
||||||
error_start: t.position,
|
error_start: t.position,
|
||||||
error_end: t.get_end_position(),
|
error_end: t.get_end_position(),
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
Result3::None => {
|
Result3::None => {
|
||||||
// The parser didn't find the `=` operator after the identifier
|
// 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",),
|
reason: format!("There should be an equal sign `=` after the identifier",),
|
||||||
error_start: identifier.position,
|
error_start: identifier.position,
|
||||||
error_end: identifier.get_end_position(),
|
error_end: identifier.get_end_position(),
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let expression = expression::try_parse(tokens, current_pos + 3);
|
let expression = expression::try_parse(tokens, current_pos + 3);
|
||||||
if expression.is_none() {
|
if expression.is_none() {
|
||||||
return Some(SyntaxResult::Err(SyntaxError {
|
return ParseResult::Err(SyntaxError {
|
||||||
reason: String::from("Expected an expression after the equal `=` operator"),
|
reason: String::from("Expected an expression after the equal `=` operator"),
|
||||||
error_start: equal_operator.position,
|
error_start: equal_operator.position,
|
||||||
error_end: equal_operator.get_end_position(),
|
error_end: equal_operator.get_end_position(),
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
let expression = expression.unwrap();
|
let expression = expression.unwrap();
|
||||||
|
|
||||||
@ -120,10 +120,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> Option<SyntaxResult>
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(SyntaxResult::Ok(
|
ParseResult::Ok(binding, current_pos + 4)
|
||||||
super::ast::TopLevelDeclaration::Binding(binding),
|
|
||||||
current_pos + 4,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -134,14 +131,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_val_binding() {
|
fn should_parse_val_binding() {
|
||||||
let tokens = get_tokens(&String::from("val identifier = 20")).unwrap();
|
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 {
|
assert_eq!("identifier", format!("{}", binding.identifier));
|
||||||
SyntaxResult::Ok(TopLevelDeclaration::Binding(Binding::Val(binding)), _) => {
|
|
||||||
assert_eq!("identifier", format!("{}", binding.identifier));
|
|
||||||
}
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -172,26 +166,20 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_parse_binding_with_datatype() {
|
fn should_parse_binding_with_datatype() {
|
||||||
let tokens = get_tokens(&String::from("Num val identifier = 20")).unwrap();
|
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 {
|
assert_eq!(Some(String::from("Num")), binding.datatype);
|
||||||
SyntaxResult::Ok(TopLevelDeclaration::Binding(Binding::Val(binding)), _) => {
|
assert_eq!("identifier", format!("{}", binding.identifier));
|
||||||
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 tokens = get_tokens(&String::from("Bool var identifier = 20")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0).unwrap();
|
let ParseResult::Ok(Binding::Var(binding), _) = try_parse(&tokens, 0) else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
|
||||||
match binding {
|
assert_eq!(Some(String::from("Bool")), binding.datatype);
|
||||||
SyntaxResult::Ok(TopLevelDeclaration::Binding(Binding::Var(binding)), _) => {
|
assert_eq!("identifier", format!("{}", binding.identifier));
|
||||||
assert_eq!(Some(String::from("Bool")), binding.datatype);
|
|
||||||
assert_eq!("identifier", format!("{}", binding.identifier));
|
|
||||||
}
|
|
||||||
_ => panic!("D: {:?}", binding),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -199,10 +187,10 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("val")).unwrap();
|
let tokens = get_tokens(&String::from("val")).unwrap();
|
||||||
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
||||||
assert_eq!(0, tokens[0].position);
|
assert_eq!(0, tokens[0].position);
|
||||||
let binding = try_parse(&tokens, 0).unwrap();
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
SyntaxResult::Err(error) => {
|
ParseResult::Err(error) => {
|
||||||
assert_eq!(0, error.error_start);
|
assert_eq!(0, error.error_start);
|
||||||
assert_eq!(3, error.error_end);
|
assert_eq!(3, error.error_end);
|
||||||
}
|
}
|
||||||
@ -215,10 +203,10 @@ mod tests {
|
|||||||
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
let tokens = get_tokens(&String::from("val 322")).unwrap();
|
||||||
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
assert_eq!(TokenType::VAL, tokens[0].token_type);
|
||||||
assert_eq!(0, tokens[0].position);
|
assert_eq!(0, tokens[0].position);
|
||||||
let binding = try_parse(&tokens, 0).unwrap();
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
SyntaxResult::Err(error) => {
|
ParseResult::Err(error) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_start);
|
||||||
assert_eq!(7, error.error_end);
|
assert_eq!(7, error.error_end);
|
||||||
}
|
}
|
||||||
@ -226,10 +214,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
|
let tokens = get_tokens(&String::from("val \"hello\"")).unwrap();
|
||||||
let binding = try_parse(&tokens, 0).unwrap();
|
let binding = try_parse(&tokens, 0);
|
||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
SyntaxResult::Err(error) => {
|
ParseResult::Err(error) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_start);
|
||||||
assert_eq!(11, error.error_end);
|
assert_eq!(11, error.error_end);
|
||||||
}
|
}
|
||||||
@ -240,10 +228,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_error_when_equal_op_is_wrong() {
|
fn should_return_error_when_equal_op_is_wrong() {
|
||||||
let tokens = get_tokens(&String::from("val id \"error\"")).unwrap();
|
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 {
|
match binding {
|
||||||
SyntaxResult::Err(error) => {
|
ParseResult::Err(error) => {
|
||||||
assert_eq!(7, error.error_start);
|
assert_eq!(7, error.error_start);
|
||||||
assert_eq!(14, error.error_end);
|
assert_eq!(14, error.error_end);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ast::{FunctionDeclaration, ParamsList},
|
ast::FunctionDeclaration,
|
||||||
block::parse_block,
|
block::parse_block,
|
||||||
params_list::parse_params_list,
|
params_list::parse_params_list,
|
||||||
utils::{parse_token_type, try_token_type},
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{lexic::get_tokens, syntax::ast::TopLevelDeclaration};
|
use crate::lexic::get_tokens;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -317,7 +317,7 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod whitespace_test {
|
mod whitespace_test {
|
||||||
use crate::{lexic::get_tokens, syntax::ast::TopLevelDeclaration};
|
use crate::lexic::get_tokens;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user