Compare commits
2 Commits
9225114658
...
b7d7244cfa
Author | SHA1 | Date | |
---|---|---|---|
b7d7244cfa | |||
2a52615153 |
@ -89,7 +89,7 @@ pub struct ParamsList<'a> {
|
|||||||
|
|
||||||
impl Positionable for ParamsList<'_> {
|
impl Positionable for ParamsList<'_> {
|
||||||
fn get_position(&self) -> (usize, usize) {
|
fn get_position(&self) -> (usize, usize) {
|
||||||
todo!()
|
(self.start, self.end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,10 @@ use crate::{
|
|||||||
ErrorContainer, ErrorLabel,
|
ErrorContainer, ErrorLabel,
|
||||||
},
|
},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{utils::parse_token_type, ParsingError, ParsingResult},
|
syntax::{
|
||||||
|
utils::{parse_token_type, Tokenizer},
|
||||||
|
ParsingError, ParsingResult,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
@ -93,14 +96,15 @@ pub fn parse_params_list(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Param
|
|||||||
start: opening_paren.position,
|
start: opening_paren.position,
|
||||||
end: opening_paren.get_end_position(),
|
end: opening_paren.get_end_position(),
|
||||||
};
|
};
|
||||||
|
let label_2_pos = tokens.code_position_from_idx(current_pos);
|
||||||
let label_2 = ErrorLabel {
|
let label_2 = ErrorLabel {
|
||||||
message: String::from("The code ends here without closing the parameter list"),
|
message: String::from("The code ends here without closing the parameter list"),
|
||||||
start: current_pos,
|
start: label_2_pos,
|
||||||
end: current_pos + 1,
|
end: label_2_pos + 1,
|
||||||
};
|
};
|
||||||
let econtainer = ErrorContainer {
|
let econtainer = ErrorContainer {
|
||||||
error_code: SYNTAX_INCOMPLETE_PARAMETER_LIST,
|
error_code: SYNTAX_INCOMPLETE_PARAMETER_LIST,
|
||||||
error_offset: current_pos,
|
error_offset: tokens.code_position_from_idx(current_pos),
|
||||||
labels: vec![label_1, label_2],
|
labels: vec![label_1, label_2],
|
||||||
note: None,
|
note: None,
|
||||||
help: None,
|
help: None,
|
||||||
@ -172,7 +176,7 @@ fn parse_param_definition(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Para
|
|||||||
};
|
};
|
||||||
let econtainer = ErrorContainer {
|
let econtainer = ErrorContainer {
|
||||||
error_code: SYNTAX_INVALID_PARAMETER_DECLARATION,
|
error_code: SYNTAX_INVALID_PARAMETER_DECLARATION,
|
||||||
error_offset: datatype_token.position,
|
error_offset: datatype_token.get_end_position(),
|
||||||
labels: vec![label],
|
labels: vec![label],
|
||||||
note: None,
|
note: None,
|
||||||
help: None,
|
help: None,
|
||||||
@ -290,4 +294,126 @@ mod tests {
|
|||||||
assert_eq!(second_param.datatype, "String");
|
assert_eq!(second_param.datatype, "String");
|
||||||
assert_eq!(second_param.identifier, "y");
|
assert_eq!(second_param.identifier, "y");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_incomplete_params_list() {
|
||||||
|
let tokens = get_tokens(&String::from(" ( ")).unwrap();
|
||||||
|
let result = parse_params_list(&tokens, 0);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(SYNTAX_INCOMPLETE_PARAMETER_LIST, err.error_code);
|
||||||
|
assert_eq!(err.error_offset, 4);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "The parameter list starts here");
|
||||||
|
assert_eq!(label.start, 3);
|
||||||
|
assert_eq!(label.end, 4);
|
||||||
|
|
||||||
|
let label = &err.labels[1];
|
||||||
|
assert_eq!(
|
||||||
|
label.message,
|
||||||
|
"The code ends here without closing the parameter list"
|
||||||
|
);
|
||||||
|
assert_eq!(label.start, 4);
|
||||||
|
assert_eq!(label.end, 5);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingError::Err"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_invalid_params_closing() {
|
||||||
|
let tokens = get_tokens(&String::from(" ( &")).unwrap();
|
||||||
|
let result = parse_params_list(&tokens, 0);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(SYNTAX_INCOMPLETE_PARAMETER_LIST, err.error_code);
|
||||||
|
assert_eq!(err.error_offset, 7);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "The parameter list starts here");
|
||||||
|
assert_eq!(label.start, 3);
|
||||||
|
assert_eq!(label.end, 4);
|
||||||
|
|
||||||
|
let label = &err.labels[1];
|
||||||
|
assert_eq!(label.message, "Expected a closing paren `)` here");
|
||||||
|
assert_eq!(label.start, 7);
|
||||||
|
assert_eq!(label.end, 8);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingError::Err"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_invalid_params_closing_2() {
|
||||||
|
let tokens = get_tokens(&String::from(" ( Int i &")).unwrap();
|
||||||
|
let result = parse_params_list(&tokens, 0);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(SYNTAX_INCOMPLETE_PARAMETER_LIST, err.error_code);
|
||||||
|
assert_eq!(err.error_offset, 13);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "The parameter list starts here");
|
||||||
|
assert_eq!(label.start, 3);
|
||||||
|
assert_eq!(label.end, 4);
|
||||||
|
|
||||||
|
let label = &err.labels[1];
|
||||||
|
assert_eq!(label.message, "Expected a closing paren `)` here");
|
||||||
|
assert_eq!(label.start, 13);
|
||||||
|
assert_eq!(label.end, 14);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingError::Err"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod params_tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::lexic::get_tokens;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_missing_identifier() {
|
||||||
|
let tokens = get_tokens(&String::from(" Int ")).unwrap();
|
||||||
|
let result = parse_param_definition(&tokens, 0);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(SYNTAX_INVALID_PARAMETER_DECLARATION, err.error_code);
|
||||||
|
assert_eq!(err.error_offset, 5);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "Expected an identifier after this datatype");
|
||||||
|
assert_eq!(label.start, 2);
|
||||||
|
assert_eq!(label.end, 5);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingError::Err"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_wrong_identifier() {
|
||||||
|
let tokens = get_tokens(&String::from(" Int 322")).unwrap();
|
||||||
|
let result = parse_param_definition(&tokens, 0);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(SYNTAX_INVALID_PARAMETER_DECLARATION, err.error_code);
|
||||||
|
assert_eq!(err.error_offset, 6);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(
|
||||||
|
label.message,
|
||||||
|
"Expected an identifier here, found this instead"
|
||||||
|
);
|
||||||
|
assert_eq!(label.start, 6);
|
||||||
|
assert_eq!(label.end, 9);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingError::Err"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
syntax::{
|
syntax::{
|
||||||
ast::{Block, BlockMember, Expression, Statement},
|
ast::{Block, BlockMember, Expression, Statement},
|
||||||
parseable::{Parseable, ParsingError, ParsingResult},
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
utils::parse_token_type,
|
utils::{parse_token_type, Tokenizer},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,15 +80,21 @@ impl<'a> Parseable<'a> for Block<'a> {
|
|||||||
return Err(ParsingError::Err(econtainer));
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
let label = ErrorLabel {
|
let label_1 = ErrorLabel {
|
||||||
message: String::from("Expected a closing brace `}` here"),
|
message: String::from("The block starts here"),
|
||||||
start: current_pos,
|
start: opening_brace.position,
|
||||||
end: current_pos + 1,
|
end: opening_brace.get_end_position(),
|
||||||
|
};
|
||||||
|
let label_2_pos = tokens.code_position_from_idx(current_pos);
|
||||||
|
let label_2 = ErrorLabel {
|
||||||
|
message: String::from("The code ends here without closing the block"),
|
||||||
|
start: label_2_pos,
|
||||||
|
end: label_2_pos + 1,
|
||||||
};
|
};
|
||||||
let econtainer = ErrorContainer {
|
let econtainer = ErrorContainer {
|
||||||
error_code: SYNTAX_INCOMPLETE_BLOCK,
|
error_code: SYNTAX_INCOMPLETE_BLOCK,
|
||||||
error_offset: current_pos,
|
error_offset: tokens.code_position_from_idx(current_pos),
|
||||||
labels: vec![label],
|
labels: vec![label_1, label_2],
|
||||||
note: None,
|
note: None,
|
||||||
help: None,
|
help: None,
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
ast::{Block, FunctionDeclaration, Positionable},
|
ast::{Block, FunctionDeclaration, Positionable},
|
||||||
functions::params_list::parse_params_list,
|
functions::params_list::parse_params_list,
|
||||||
parseable::{Parseable, ParsingError, ParsingResult},
|
parseable::{Parseable, ParsingError, ParsingResult},
|
||||||
utils::{parse_token_type, try_operator},
|
utils::{parse_token_type, try_operator, Tokenizer},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -184,13 +184,13 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let label = ErrorLabel {
|
let label = ErrorLabel {
|
||||||
message: String::from("Expected a block here, after the function declaration"),
|
message: String::from("Expected a block after this parameter list"),
|
||||||
start: error_start,
|
start: error_start,
|
||||||
end: error_end,
|
end: error_end,
|
||||||
};
|
};
|
||||||
let econtainer = ErrorContainer {
|
let econtainer = ErrorContainer {
|
||||||
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
error_offset: error_start,
|
error_offset: tokens.code_position_from_idx(current_pos),
|
||||||
labels: vec![label],
|
labels: vec![label],
|
||||||
note: None,
|
note: None,
|
||||||
help: None,
|
help: None,
|
||||||
@ -215,7 +215,12 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{error_handling::error_messages::SYNTAX_INCOMPLETE_BLOCK, lexic::get_tokens};
|
use crate::{
|
||||||
|
error_handling::error_messages::{
|
||||||
|
SYNTAX_INCOMPLETE_BLOCK, SYNTAX_INCOMPLETE_PARAMETER_LIST,
|
||||||
|
},
|
||||||
|
lexic::get_tokens,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -230,98 +235,125 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_identifier() {
|
fn should_fail_on_incomplete_1() {
|
||||||
let tokens = get_tokens(&String::from("fun = 20")).unwrap();
|
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
|
||||||
|
|
||||||
match fun_decl {
|
|
||||||
Err(ParsingError::Err(err)) => {
|
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
|
||||||
assert_eq!(err.error_offset, 4);
|
|
||||||
}
|
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun ")).unwrap();
|
let tokens = get_tokens(&String::from("fun ")).unwrap();
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
|
||||||
assert_eq!(err.error_offset, 0);
|
assert_eq!(err.error_offset, 0);
|
||||||
|
assert_eq!(SYNTAX_INVALID_FUNCTION_DECLARATION, err.error_code);
|
||||||
|
let first_label = &err.labels[0];
|
||||||
|
assert_eq!(first_label.start, 0);
|
||||||
|
assert_eq!(first_label.end, 3);
|
||||||
|
assert_eq!(
|
||||||
|
first_label.message,
|
||||||
|
"Expected an identifier after this `fun` keyword",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected a ParsingErr"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_parens() {
|
fn should_fail_on_invalid_identifier() {
|
||||||
|
let tokens = get_tokens(&String::from("fun 322")).unwrap();
|
||||||
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
|
match fun_decl {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(err.error_offset, 4);
|
||||||
|
assert_eq!(SYNTAX_INVALID_FUNCTION_DECLARATION, err.error_code);
|
||||||
|
let first_label = &err.labels[0];
|
||||||
|
assert_eq!(first_label.start, 4);
|
||||||
|
assert_eq!(first_label.end, 7);
|
||||||
|
assert_eq!(first_label.message, "Expected an identifier here",);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingErr"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_missing_params_list() {
|
||||||
|
let tokens = get_tokens(&String::from("fun id")).unwrap();
|
||||||
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
|
match fun_decl {
|
||||||
|
Err(ParsingError::Err(err)) => {
|
||||||
|
assert_eq!(err.error_offset, 6);
|
||||||
|
assert_eq!(SYNTAX_INVALID_FUNCTION_DECLARATION, err.error_code);
|
||||||
|
let first_label = &err.labels[0];
|
||||||
|
assert_eq!(first_label.start, 4);
|
||||||
|
assert_eq!(first_label.end, 6);
|
||||||
|
assert_eq!(
|
||||||
|
first_label.message,
|
||||||
|
"Expected a parameter list after this identifier",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a ParsingErr"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_invalid_params_list() {
|
||||||
let tokens = get_tokens(&String::from("fun id =")).unwrap();
|
let tokens = get_tokens(&String::from("fun id =")).unwrap();
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_offset, 7);
|
assert_eq!(err.error_offset, 8);
|
||||||
}
|
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id")).unwrap();
|
let label = &err.labels[0];
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
assert_eq!(label.start, 7);
|
||||||
match fun_decl {
|
assert_eq!(label.end, 8);
|
||||||
Err(ParsingError::Err(err)) => {
|
assert_eq!(label.message, "Expected a parameter list here");
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
|
||||||
assert_eq!(err.error_offset, 4);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error, got {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_without_closing_paren() {
|
fn should_fail_on_incomplete_params_list() {
|
||||||
let tokens = get_tokens(&String::from("fun id(=")).unwrap();
|
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
|
||||||
|
|
||||||
match fun_decl {
|
|
||||||
Err(ParsingError::Err(err)) => {
|
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
|
||||||
assert_eq!(err.error_offset, 7);
|
|
||||||
}
|
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id(")).unwrap();
|
let tokens = get_tokens(&String::from("fun id(")).unwrap();
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
assert_eq!(err.error_code, SYNTAX_INCOMPLETE_PARAMETER_LIST);
|
||||||
assert_eq!(err.error_offset, 6);
|
assert_eq!(err.error_offset, 7);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "The parameter list starts here");
|
||||||
|
assert_eq!(label.start, 6);
|
||||||
|
assert_eq!(label.end, 7);
|
||||||
|
|
||||||
|
let label = &err.labels[1];
|
||||||
|
assert_eq!(
|
||||||
|
label.message,
|
||||||
|
"The code ends here without closing the parameter list"
|
||||||
|
);
|
||||||
|
assert_eq!(label.start, 7);
|
||||||
|
assert_eq!(label.end, 8);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_parse_fun_when_missing_id() {
|
fn should_fail_on_missing_body() {
|
||||||
let tokens = get_tokens(&String::from("fun")).unwrap();
|
let tokens = get_tokens(&String::from("fun id() ")).unwrap();
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_offset, 0);
|
assert_eq!(err.error_offset, 8);
|
||||||
}
|
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun\n")).unwrap();
|
let label = &err.labels[0];
|
||||||
println!("{:?}", tokens);
|
assert_eq!(label.message, "Expected a block after this parameter list");
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
assert_eq!(label.start, 6);
|
||||||
|
assert_eq!(label.end, 8);
|
||||||
match fun_decl {
|
|
||||||
Err(ParsingError::Err(err)) => {
|
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
|
||||||
assert_eq!(err.error_offset, 0);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -336,16 +368,14 @@ mod tests {
|
|||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_offset, 9);
|
assert_eq!(err.error_offset, 9);
|
||||||
}
|
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id()")).unwrap();
|
let label = &err.labels[0];
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
assert_eq!(
|
||||||
match fun_decl {
|
label.message,
|
||||||
Err(ParsingError::Err(err)) => {
|
"Expected a block here, after the function declaration"
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
);
|
||||||
assert_eq!(err.error_offset, 4);
|
assert_eq!(label.start, 9);
|
||||||
|
assert_eq!(label.end, 10);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -359,18 +389,20 @@ mod tests {
|
|||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INCOMPLETE_BLOCK);
|
assert_eq!(err.error_code, SYNTAX_INCOMPLETE_BLOCK);
|
||||||
assert_eq!(err.error_offset, 9);
|
assert_eq!(err.error_offset, 10);
|
||||||
}
|
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
|
||||||
}
|
|
||||||
|
|
||||||
let tokens = get_tokens(&String::from("fun id() {")).unwrap();
|
let label = &err.labels[0];
|
||||||
let fun_decl = FunctionDeclaration::try_parse(&tokens, 0);
|
assert_eq!(label.message, "The block starts here");
|
||||||
|
assert_eq!(label.start, 9);
|
||||||
|
assert_eq!(label.end, 10);
|
||||||
|
|
||||||
match fun_decl {
|
let label = &err.labels[1];
|
||||||
Err(ParsingError::Err(err)) => {
|
assert_eq!(
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
label.message,
|
||||||
assert_eq!(err.error_offset, 9);
|
"The code ends here without closing the block"
|
||||||
|
);
|
||||||
|
assert_eq!(label.start, 10);
|
||||||
|
assert_eq!(label.end, 11);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -405,7 +437,12 @@ mod tests {
|
|||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_offset, 9);
|
assert_eq!(err.error_offset, 12);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "Expected a Datatype here");
|
||||||
|
assert_eq!(label.start, 12);
|
||||||
|
assert_eq!(label.end, 13);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -420,6 +457,14 @@ mod tests {
|
|||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_offset, 9);
|
assert_eq!(err.error_offset, 9);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(
|
||||||
|
label.message,
|
||||||
|
"Expected a Datatype after this arrow `->` operator"
|
||||||
|
);
|
||||||
|
assert_eq!(label.start, 9);
|
||||||
|
assert_eq!(label.end, 11);
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
|
|||||||
/// As this function parses the whole file, it ignores `current_pos` and
|
/// As this function parses the whole file, it ignores `current_pos` and
|
||||||
/// always starts from token 0.
|
/// always starts from token 0.
|
||||||
///
|
///
|
||||||
/// Its grammar is defined it the spec, at the webpage
|
/// Its grammar is defined at the spec, at the webpage
|
||||||
fn try_parse(tokens: &'a Vec<Token>, _current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
fn try_parse(tokens: &'a Vec<Token>, _current_pos: usize) -> ParsingResult<'a, Self::Item> {
|
||||||
let mut productions = Vec::<ModuleMembers>::new();
|
let mut productions = Vec::<ModuleMembers>::new();
|
||||||
let tokens_len = tokens.len();
|
let tokens_len = tokens.len();
|
||||||
|
@ -4,6 +4,7 @@ use super::{ParsingError, ParsingResult};
|
|||||||
|
|
||||||
pub trait Tokenizer {
|
pub trait Tokenizer {
|
||||||
fn get_significant<'a>(&'a self, index: usize) -> Option<(&'a Token, usize)>;
|
fn get_significant<'a>(&'a self, index: usize) -> Option<(&'a Token, usize)>;
|
||||||
|
fn code_position_from_idx(&self, idx: usize) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tokenizer for Vec<Token> {
|
impl Tokenizer for Vec<Token> {
|
||||||
@ -30,6 +31,30 @@ impl Tokenizer for Vec<Token> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the position in the code from the token idx.
|
||||||
|
///
|
||||||
|
/// If the token at `idx` exists, returns `tokens[idx].position`.
|
||||||
|
///
|
||||||
|
/// Otherwise returns `tokens[idx - 1].get_end_position()`
|
||||||
|
fn code_position_from_idx(&self, idx: usize) -> usize {
|
||||||
|
// try to get the token at idx
|
||||||
|
match self.get(idx) {
|
||||||
|
Some(t) if t.token_type == TokenType::EOF => {
|
||||||
|
// If idx points at EOF, return the end position of the previous token
|
||||||
|
// This shouldnt fail
|
||||||
|
self[idx - 1].get_end_position()
|
||||||
|
}
|
||||||
|
Some(t) => t.position,
|
||||||
|
None => {
|
||||||
|
// this should never happen.
|
||||||
|
// the token stream always ends with an EOF token,
|
||||||
|
// and the parser should never be able to go
|
||||||
|
// to a position after that EOF token
|
||||||
|
unreachable!("Compiler error: Tried to get an out of bound token. This means that somewhere a token beyond EOF was requested.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expects the token at `pos` to be an operator of value `operator`. Doesn't ignore whitespace or newlines
|
/// Expects the token at `pos` to be an operator of value `operator`. Doesn't ignore whitespace or newlines
|
||||||
|
Loading…
Reference in New Issue
Block a user