refactor: migrate syntax errors into new struct
This commit is contained in:
parent
b59d014383
commit
1a7dd72783
@ -6,4 +6,15 @@
|
|||||||
0x000004: Invalid floating point number
|
0x000004: Invalid floating point number
|
||||||
0x000005: Invalid scientific number
|
0x000005: Invalid scientific number
|
||||||
0x000006: Incomplete multiline comment
|
0x000006: Incomplete multiline comment
|
||||||
|
0x000007: Unfinished statement
|
||||||
|
0x000008: Unexpected tokens
|
||||||
|
0x000009: Incomplete arguments list
|
||||||
|
0x000010: Invalid variable declaration
|
||||||
|
0x000011: Incomplete parameter list
|
||||||
|
0x000012: Invalid parameter declaration
|
||||||
|
0x000013: Invalid while loop
|
||||||
|
0x000014: Invalid function declaration
|
||||||
|
0x000015: Invalid for loop
|
||||||
|
0x000016: Invalid if condition
|
||||||
|
0x000017: Incomplete block
|
||||||
|
|
||||||
|
@ -7,3 +7,19 @@ pub const LEX_INVALID_BINARY_NUMBER: u32 = 3;
|
|||||||
pub const LEX_INVALID_FLOATING_NUMBER: u32 = 4;
|
pub const LEX_INVALID_FLOATING_NUMBER: u32 = 4;
|
||||||
pub const LEX_INVALID_SCIENTIFIC_NUMBER: u32 = 5;
|
pub const LEX_INVALID_SCIENTIFIC_NUMBER: u32 = 5;
|
||||||
pub const LEX_INCOMPLETE_MULTILINE_COMMENT: u32 = 6;
|
pub const LEX_INCOMPLETE_MULTILINE_COMMENT: u32 = 6;
|
||||||
|
pub const SYNTAX_INCOMPLETE_STATEMENT: u32 = 7;
|
||||||
|
pub const SYNTAX_UNEXPECTED_TOKENS: u32 = 8;
|
||||||
|
pub const SYNTAX_INCOMPLETE_ARGUMENT_LIST: u32 = 9;
|
||||||
|
pub const SYNTAX_INVALID_VARIABLE_DECLARATION: u32 = 10;
|
||||||
|
pub const SYNTAX_INCOMPLETE_PARAMETER_LIST: u32 = 11;
|
||||||
|
pub const SYNTAX_INVALID_PARAMETER_DECLARATION: u32 = 12;
|
||||||
|
pub const SYNTAX_INVALID_WHILE_LOOP: u32 = 13;
|
||||||
|
pub const SYNTAX_INVALID_FUNCTION_DECLARATION: u32 = 14;
|
||||||
|
pub const SYNTAX_INVALID_FOR_LOOP: u32 = 15;
|
||||||
|
pub const SYNTAX_INVALID_IF_CONDITION: u32 = 16;
|
||||||
|
pub const SYNTAX_INCOMPLETE_BLOCK: u32 = 17;
|
||||||
|
|
||||||
|
/// Reads the error codes from the error code list
|
||||||
|
pub fn error_code_to_string() -> String {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
@ -37,7 +37,7 @@ pub struct ErrorLabel {
|
|||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub enum MistiError {
|
pub enum MistiError {
|
||||||
Lex(ErrorContainer),
|
Lex(ErrorContainer),
|
||||||
Syntax(SyntaxError),
|
Syntax(ErrorContainer),
|
||||||
Semantic(SemanticError),
|
Semantic(SemanticError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +89,14 @@ impl PrintableError for ErrorContainer {
|
|||||||
report = report.with_label(l)
|
report = report.with_label(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(help) = &self.help {
|
||||||
|
report = report.with_help(help);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(note) = &self.note {
|
||||||
|
report = report.with_help(note);
|
||||||
|
}
|
||||||
|
|
||||||
report
|
report
|
||||||
.with_code(self.error_code)
|
.with_code(self.error_code)
|
||||||
.finish()
|
.finish()
|
||||||
|
@ -83,6 +83,14 @@ pub enum BlockMember<'a> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParamsList<'a> {
|
pub struct ParamsList<'a> {
|
||||||
pub parameters: Vec<Parameter<'a>>,
|
pub parameters: Vec<Parameter<'a>>,
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Positionable for ParamsList<'_> {
|
||||||
|
fn get_position(&self) -> (usize, usize) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{error_messages::SYNTAX_INCOMPLETE_ARGUMENT_LIST, ErrorContainer, ErrorLabel},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{functions::ArgumentsList, Expression},
|
ast::{functions::ArgumentsList, Expression},
|
||||||
@ -58,18 +58,44 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<ArgumentsList
|
|||||||
Ok((t, next)) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label_1 = ErrorLabel {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
message: String::from("The argument list starts here"),
|
||||||
error_start: t.position,
|
start: opening_paren.position,
|
||||||
error_end: t.get_end_position(),
|
end: opening_paren.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: String::from("Expected a closing paren `)` here"),
|
||||||
|
start: t.position,
|
||||||
|
end: t.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_ARGUMENT_LIST,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label_1, label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label_1 = ErrorLabel {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
message: String::from("The argument list starts here"),
|
||||||
error_start: opening_paren.position,
|
start: opening_paren.position,
|
||||||
error_end: opening_paren.get_end_position(),
|
end: opening_paren.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let label_2 = ErrorLabel {
|
||||||
|
message: String::from("The code ends here without closing the argument list"),
|
||||||
|
start: current_pos,
|
||||||
|
end: current_pos + 1,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_ARGUMENT_LIST,
|
||||||
|
error_offset: current_pos,
|
||||||
|
labels: vec![label_1, label_2],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{
|
||||||
|
error_messages::{SYNTAX_INCOMPLETE_PARAMETER_LIST, SYNTAX_INVALID_PARAMETER_DECLARATION},
|
||||||
|
ErrorContainer, ErrorLabel,
|
||||||
|
},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{utils::parse_token_type, ParsingError, ParsingResult},
|
syntax::{utils::parse_token_type, ParsingError, ParsingResult},
|
||||||
};
|
};
|
||||||
@ -60,28 +63,61 @@ pub fn parse_params_list(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Param
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse closing paren
|
// Parse closing paren
|
||||||
let (_closing_paren, next_pos) =
|
let (closing_paren, next_pos) =
|
||||||
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
match parse_token_type(tokens, current_pos, TokenType::RightParen) {
|
||||||
Ok((t, next)) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label_1 = ErrorLabel {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
message: String::from("The parameter list starts here"),
|
||||||
error_start: t.position,
|
start: opening_paren.position,
|
||||||
error_end: t.get_end_position(),
|
end: opening_paren.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: String::from("Expected a closing paren `)` here"),
|
||||||
|
start: t.position,
|
||||||
|
end: t.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_PARAMETER_LIST,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label_1, label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label_1 = ErrorLabel {
|
||||||
reason: String::from("Expected a closing paren after the function identifier."),
|
message: String::from("The parameter list starts here"),
|
||||||
error_start: opening_paren.position,
|
start: opening_paren.position,
|
||||||
error_end: opening_paren.get_end_position(),
|
end: opening_paren.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let label_2 = ErrorLabel {
|
||||||
|
message: String::from("The code ends here without closing the parameter list"),
|
||||||
|
start: current_pos,
|
||||||
|
end: current_pos + 1,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_PARAMETER_LIST,
|
||||||
|
error_offset: current_pos,
|
||||||
|
labels: vec![label_1, label_2],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
Ok((ParamsList { parameters }, current_pos))
|
Ok((
|
||||||
|
ParamsList {
|
||||||
|
parameters,
|
||||||
|
start: opening_paren.position,
|
||||||
|
end: closing_paren.get_end_position(),
|
||||||
|
},
|
||||||
|
current_pos,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single parameter definition of the form:
|
/// Parse a single parameter definition of the form:
|
||||||
@ -112,19 +148,36 @@ fn parse_param_definition(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Para
|
|||||||
return Err(ParsingError::Err(err));
|
return Err(ParsingError::Err(err));
|
||||||
}
|
}
|
||||||
// However, if we fail to parse an identifier, it's an error
|
// However, if we fail to parse an identifier, it's an error
|
||||||
Err(ParsingError::Mismatch(_)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an identifier for the parameter."),
|
message: String::from("Expected an identifier here, found this instead"),
|
||||||
error_start: tokens[pos].position,
|
start: t.position,
|
||||||
error_end: tokens[pos].get_end_position(),
|
end: t.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_PARAMETER_DECLARATION,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let datatype_token = &tokens[pos];
|
||||||
reason: String::from("Expected an identifier for the parameter."),
|
let label = ErrorLabel {
|
||||||
error_start: tokens[pos].position,
|
message: String::from("Expected an identifier after this datatype"),
|
||||||
error_end: tokens[pos].get_end_position(),
|
start: datatype_token.position,
|
||||||
}))
|
end: datatype_token.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_PARAMETER_DECLARATION,
|
||||||
|
error_offset: datatype_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{error_handling::SyntaxError, lexic::token::Token};
|
use crate::{error_handling::ErrorContainer, lexic::token::Token};
|
||||||
|
|
||||||
/// The result of a parsing operation.
|
/// The result of a parsing operation.
|
||||||
/// On success, it contains the item and the position of the next token
|
/// On success, it contains the item and the position of the next token
|
||||||
@ -15,7 +15,7 @@ pub enum ParsingError<'a> {
|
|||||||
///
|
///
|
||||||
/// For example, when parsing a function declaration
|
/// For example, when parsing a function declaration
|
||||||
/// the `fun` token is found, but then no identifier
|
/// the `fun` token is found, but then no identifier
|
||||||
Err(SyntaxError),
|
Err(ErrorContainer),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a type that can be parsed using Recursive Descent
|
/// Represents a type that can be parsed using Recursive Descent
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{
|
||||||
|
error_messages::{SYNTAX_INCOMPLETE_STATEMENT, SYNTAX_INVALID_VARIABLE_DECLARATION},
|
||||||
|
ErrorContainer, ErrorLabel,
|
||||||
|
},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{var_binding::VariableBinding, Expression},
|
ast::{var_binding::VariableBinding, Expression},
|
||||||
@ -52,31 +55,57 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
|
|||||||
Ok((t, n)) => (t, n),
|
Ok((t, n)) => (t, n),
|
||||||
Err(ParsingError::Mismatch(token)) => {
|
Err(ParsingError::Mismatch(token)) => {
|
||||||
// The parser found a token, but it's not an identifier
|
// The parser found a token, but it's not an identifier
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: token.position,
|
message: String::from("Expected an identifier here"),
|
||||||
error_end: token.get_end_position(),
|
start: token.position,
|
||||||
reason: "There should be an identifier after a binding".into(),
|
end: token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_VARIABLE_DECLARATION,
|
||||||
|
error_offset: token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// The parser didn't find an Identifier after VAL/VAR or the Datatype
|
// The parser didn't find an Identifier after VAL/VAR or the Datatype
|
||||||
match (binding_token, datatype) {
|
match (binding_token, datatype) {
|
||||||
(Some(binding_token), None) => {
|
(Some(binding_token), None) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: format!(
|
message: format!(
|
||||||
"There should be an identifier after a `{}` token",
|
"There should be an identifier after this `{}` token",
|
||||||
if is_var { "var" } else { "val" }
|
if is_var { "var" } else { "val" }
|
||||||
),
|
),
|
||||||
error_start: binding_token.position,
|
start: binding_token.position,
|
||||||
error_end: binding_token.get_end_position(),
|
end: binding_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_VARIABLE_DECLARATION,
|
||||||
|
error_offset: binding_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
(_, Some(datatype_token)) => {
|
(_, Some(datatype_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: "There should be an identifier after the datatype".into(),
|
message: String::from(
|
||||||
error_start: datatype_token.position,
|
"There should be an identifier after this datatype",
|
||||||
error_end: datatype_token.get_end_position(),
|
),
|
||||||
}));
|
start: datatype_token.position,
|
||||||
|
end: datatype_token.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_VARIABLE_DECLARATION,
|
||||||
|
error_offset: datatype_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
@ -94,19 +123,37 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
|
|||||||
Ok((t, _)) => t,
|
Ok((t, _)) => t,
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
// The parser found a token, but it's not the `=` operator
|
// The parser found a token, but it's not the `=` operator
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: format!("There should be an equal sign `=` after the identifier"),
|
message: String::from(
|
||||||
error_start: t.position,
|
"Expected an equal sign `=` here, after the variable identifier",
|
||||||
error_end: t.get_end_position(),
|
),
|
||||||
}));
|
start: t.position,
|
||||||
|
end: t.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_VARIABLE_DECLARATION,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// The parser didn't find the `=` operator after the identifier
|
// The parser didn't find the `=` operator after the identifier
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: format!("There should be an equal sign `=` after the identifier",),
|
message: String::from("Expected an equal sign `=` after this identifier"),
|
||||||
error_start: identifier.position,
|
start: identifier.position,
|
||||||
error_end: identifier.get_end_position(),
|
end: identifier.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_VARIABLE_DECLARATION,
|
||||||
|
error_offset: identifier.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let next_pos = next_pos + 1;
|
let next_pos = next_pos + 1;
|
||||||
@ -117,11 +164,19 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
|
|||||||
let (expression, next_pos) = match Expression::try_parse(tokens, next_pos) {
|
let (expression, next_pos) = match Expression::try_parse(tokens, next_pos) {
|
||||||
Ok((exp, next)) => (exp, next),
|
Ok((exp, next)) => (exp, next),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an expression after the equal `=` operator"),
|
message: String::from("Expected an expression after this equal `=` operator"),
|
||||||
error_start: equal_operator.position,
|
start: equal_operator.position,
|
||||||
error_end: equal_operator.get_end_position(),
|
end: equal_operator.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_VARIABLE_DECLARATION,
|
||||||
|
error_offset: equal_operator.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,11 +185,19 @@ impl<'a> Parseable<'a> for VariableBinding<'a> {
|
|||||||
let next_pos = match parse_terminator(tokens, next_pos) {
|
let next_pos = match parse_terminator(tokens, next_pos) {
|
||||||
Ok((_, next)) => next,
|
Ok((_, next)) => next,
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: t.position,
|
message: String::from("Expected a new line here, found another token"),
|
||||||
error_end: t.get_end_position(),
|
start: t.position,
|
||||||
reason: format!("Unexpected token `{}`, expected a new line", t.value),
|
end: t.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_STATEMENT,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from("There may only be one statement per line")),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@ -229,8 +292,7 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_offset);
|
||||||
assert_eq!(6, error.error_end);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -245,8 +307,7 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(0, error.error_start);
|
assert_eq!(0, error.error_offset);
|
||||||
assert_eq!(3, error.error_end);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -261,8 +322,7 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_offset);
|
||||||
assert_eq!(7, error.error_end);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -272,12 +332,8 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_offset);
|
||||||
assert_eq!(11, error.error_end);
|
assert_eq!(error.error_code, SYNTAX_INVALID_VARIABLE_DECLARATION)
|
||||||
assert_eq!(
|
|
||||||
"There should be an identifier after a binding",
|
|
||||||
error.reason
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -290,8 +346,7 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(7, error.error_start);
|
assert_eq!(7, error.error_offset);
|
||||||
assert_eq!(14, error.error_end);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -304,12 +359,8 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_offset);
|
||||||
assert_eq!(10, error.error_end);
|
assert_eq!(error.error_code, SYNTAX_INVALID_VARIABLE_DECLARATION)
|
||||||
assert_eq!(
|
|
||||||
"There should be an identifier after the datatype",
|
|
||||||
error.reason
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -322,12 +373,8 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(0, error.error_start);
|
assert_eq!(0, error.error_offset);
|
||||||
assert_eq!(3, error.error_end);
|
assert_eq!(error.error_code, SYNTAX_INVALID_VARIABLE_DECLARATION)
|
||||||
assert_eq!(
|
|
||||||
"There should be an identifier after a `val` token",
|
|
||||||
error.reason
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -340,12 +387,8 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(4, error.error_start);
|
assert_eq!(4, error.error_offset);
|
||||||
assert_eq!(14, error.error_end);
|
assert_eq!(error.error_code, SYNTAX_INVALID_VARIABLE_DECLARATION)
|
||||||
assert_eq!(
|
|
||||||
"There should be an equal sign `=` after the identifier",
|
|
||||||
error.reason
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -358,12 +401,8 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(15, error.error_start);
|
assert_eq!(15, error.error_offset);
|
||||||
assert_eq!(16, error.error_end);
|
assert_eq!(error.error_code, SYNTAX_INVALID_VARIABLE_DECLARATION)
|
||||||
assert_eq!(
|
|
||||||
"Expected an expression after the equal `=` operator",
|
|
||||||
error.reason
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
@ -376,12 +415,8 @@ mod tests {
|
|||||||
|
|
||||||
match binding {
|
match binding {
|
||||||
Err(ParsingError::Err(error)) => {
|
Err(ParsingError::Err(error)) => {
|
||||||
assert_eq!(21, error.error_start);
|
assert_eq!(21, error.error_offset);
|
||||||
assert_eq!(26, error.error_end);
|
assert_eq!(error.error_code, SYNTAX_INCOMPLETE_STATEMENT)
|
||||||
assert_eq!(
|
|
||||||
"Unexpected token `print`, expected a new line",
|
|
||||||
error.reason
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Error expected"),
|
_ => panic!("Error expected"),
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{error_messages::SYNTAX_INCOMPLETE_BLOCK, ErrorContainer, ErrorLabel},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{Block, BlockMember, Expression, Statement},
|
ast::{Block, BlockMember, Expression, Statement},
|
||||||
@ -65,20 +65,34 @@ impl<'a> Parseable<'a> for Block<'a> {
|
|||||||
Ok((t, next)) => (t, next),
|
Ok((t, next)) => (t, next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a closing brace after the block body."),
|
message: String::from("Expected a closing brace `}` here"),
|
||||||
error_start: t.position,
|
start: t.position,
|
||||||
error_end: t.get_end_position(),
|
end: t.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_BLOCK,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a closing brace after the block body."),
|
message: String::from("Expected a closing brace `}` here"),
|
||||||
// TODO: use the last token (at pos current_pos) as guide for the error
|
start: current_pos,
|
||||||
// msg position
|
end: current_pos + 1,
|
||||||
error_start: opening_brace.position,
|
};
|
||||||
error_end: opening_brace.get_end_position(),
|
let econtainer = ErrorContainer {
|
||||||
}));
|
error_code: SYNTAX_INCOMPLETE_BLOCK,
|
||||||
|
error_offset: current_pos,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{error_messages::SYNTAX_INVALID_IF_CONDITION, ErrorContainer, ErrorLabel},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{Block, Condition, Conditional, Expression, Positionable},
|
ast::{Block, Condition, Conditional, Expression, Positionable},
|
||||||
@ -23,18 +23,34 @@ impl<'a> Parseable<'a> for Conditional<'a> {
|
|||||||
Ok(tuple) => tuple,
|
Ok(tuple) => tuple,
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an expression after the if token"),
|
message: String::from("Expected a Bool expression here"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an expression after the if token"),
|
message: String::from("Expected a Bool expression after this `if` keyword"),
|
||||||
error_start: if_token.position,
|
start: if_token.position,
|
||||||
error_end: if_token.get_end_position(),
|
end: if_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: if_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,19 +59,35 @@ impl<'a> Parseable<'a> for Conditional<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the condition"),
|
message: String::from("Expected a block here, after the condition"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
let (error_start, error_end) = if_expression.get_position();
|
let (error_start, error_end) = if_expression.get_position();
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the condition"),
|
message: String::from("Expected a block after this condition"),
|
||||||
error_start,
|
start: error_start,
|
||||||
error_end,
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,18 +119,34 @@ impl<'a> Parseable<'a> for Conditional<'a> {
|
|||||||
Ok(tuple) => tuple,
|
Ok(tuple) => tuple,
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an expression after the if token"),
|
message: String::from("Expected a Bool expression here"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an expression after the if token"),
|
message: String::from("Expected a Bool expression after this `if` keyword"),
|
||||||
error_start: if_token.position,
|
start: if_token.position,
|
||||||
error_end: if_token.get_end_position(),
|
end: if_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: if_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,19 +155,35 @@ impl<'a> Parseable<'a> for Conditional<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the condition"),
|
message: String::from("Expected a block here, after the condition"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
let (error_start, error_end) = condition.get_position();
|
let (error_start, error_end) = condition.get_position();
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the condition"),
|
message: String::from("Expected a block after this condition"),
|
||||||
error_start,
|
start: error_start,
|
||||||
error_end,
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,18 +204,36 @@ impl<'a> Parseable<'a> for Conditional<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the else keyword"),
|
message: String::from("Expected a block here, after the condition"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the else keyword"),
|
message: String::from(
|
||||||
error_start: else_token.position,
|
"Expected a block here, after this `else` keyword",
|
||||||
error_end: else_token.get_end_position(),
|
),
|
||||||
}));
|
start: else_token.position,
|
||||||
|
end: else_token.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_IF_CONDITION,
|
||||||
|
error_offset: else_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{error_messages::SYNTAX_INVALID_FOR_LOOP, ErrorContainer, ErrorLabel},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{loops::ForLoop, Block, Expression, Positionable},
|
ast::{loops::ForLoop, Block, Expression, Positionable},
|
||||||
@ -23,21 +23,34 @@ impl<'a> Parseable<'a> for ForLoop<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(ParsingError::Mismatch(e)) => {
|
Err(ParsingError::Mismatch(e)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: e.position,
|
message: String::from("Expected an identifier here, after the `for` keyword"),
|
||||||
error_end: e.get_end_position(),
|
start: e.position,
|
||||||
reason: format!(
|
end: e.get_end_position(),
|
||||||
"Expected an identifier after the `for` keyword, found {}",
|
};
|
||||||
e.value
|
let econtainer = ErrorContainer {
|
||||||
),
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
}))
|
error_offset: e.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: for_keyword.position,
|
message: String::from("Expected an identifier after this `for` keyword"),
|
||||||
error_end: for_keyword.get_end_position(),
|
start: for_keyword.position,
|
||||||
reason: format!("Expected an identifier after the `for` keyword"),
|
end: for_keyword.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: for_keyword.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,21 +68,38 @@ impl<'a> Parseable<'a> for ForLoop<'a> {
|
|||||||
Ok((second_id, next)) => (Some(second_id), next),
|
Ok((second_id, next)) => (Some(second_id), next),
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: t.position,
|
message: String::from("Expected an identifier here, after the comma"),
|
||||||
error_end: t.get_end_position(),
|
start: t.position,
|
||||||
reason: format!(
|
end: t.get_end_position(),
|
||||||
"Expected an identifier after the comma, found `{}`",
|
};
|
||||||
t.value
|
let econtainer = ErrorContainer {
|
||||||
),
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
}))
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"To iterate only over values, use `for identifier in ...`",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: comma.position,
|
message: String::from("Expected an identifier after this comma"),
|
||||||
error_end: comma.get_end_position(),
|
start: comma.position,
|
||||||
reason: format!("Expected an identifier after the comma"),
|
end: comma.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: comma.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"To iterate only over values, use `for identifier in ...`",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -79,11 +109,19 @@ impl<'a> Parseable<'a> for ForLoop<'a> {
|
|||||||
Ok(tuple) => tuple,
|
Ok(tuple) => tuple,
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: t.position,
|
message: String::from("Expected the `in` keyword here"),
|
||||||
error_end: t.get_end_position(),
|
start: t.position,
|
||||||
reason: format!("Expected the `in` keyword, found `{}`", t.value),
|
end: t.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
let previous_token = if second_id.is_none() {
|
let previous_token = if second_id.is_none() {
|
||||||
@ -91,11 +129,19 @@ impl<'a> Parseable<'a> for ForLoop<'a> {
|
|||||||
} else {
|
} else {
|
||||||
second_id.unwrap()
|
second_id.unwrap()
|
||||||
};
|
};
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: previous_token.position,
|
message: String::from("Expected the `in` keyword after this identifier"),
|
||||||
error_end: previous_token.get_end_position(),
|
start: previous_token.position,
|
||||||
reason: format!("Expected the `in` keyword"),
|
end: previous_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: previous_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,11 +150,19 @@ impl<'a> Parseable<'a> for ForLoop<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: in_keyword.position,
|
message: String::from("Expected an expression after this `in` keyword"),
|
||||||
error_end: in_keyword.get_end_position(),
|
start: in_keyword.position,
|
||||||
reason: format!("Expected an expression after the `in` keyword"),
|
end: in_keyword.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: in_keyword.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,19 +171,35 @@ impl<'a> Parseable<'a> for ForLoop<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the collection"),
|
message: String::from("Expected a block here"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
let (error_start, error_end) = expr.get_position();
|
let (error_start, error_end) = expr.get_position();
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the collection"),
|
message: String::from("Expected a block here, after the collection"),
|
||||||
error_start,
|
start: error_start,
|
||||||
error_end,
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FOR_LOOP,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{
|
||||||
|
error_messages::SYNTAX_INVALID_FUNCTION_DECLARATION, ErrorContainer, ErrorLabel,
|
||||||
|
},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{Block, FunctionDeclaration},
|
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},
|
||||||
@ -28,18 +30,34 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
Ok((id, next)) => (id, next),
|
Ok((id, next)) => (id, next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an identifier after the `fun` keyword."),
|
message: String::from("Expected an identifier here"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected an identifier after the `fun` keyword."),
|
message: String::from("Expected an identifier after this `fun` keyword"),
|
||||||
error_start: fun_keyword.position,
|
start: fun_keyword.position,
|
||||||
error_end: fun_keyword.get_end_position(),
|
end: fun_keyword.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: fun_keyword.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -50,22 +68,38 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
Ok((params, next_pos)) => (params, next_pos),
|
Ok((params, next_pos)) => (params, next_pos),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from(
|
message: String::from("Expected a parameter list here"),
|
||||||
"Expected an opening paren after the function identifier.",
|
start: wrong_token.position,
|
||||||
),
|
end: wrong_token.get_end_position(),
|
||||||
error_start: wrong_token.position,
|
};
|
||||||
error_end: wrong_token.get_end_position(),
|
let econtainer = ErrorContainer {
|
||||||
}));
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: wrong_token.get_end_position(),
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"If this function doesn't take any parameter, use an empty list `()`",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from(
|
message: String::from("Expected a parameter list after this identifier"),
|
||||||
"Expected an opening paren after the function identifier.",
|
start: identifier.position,
|
||||||
),
|
end: identifier.get_end_position(),
|
||||||
error_start: identifier.position,
|
};
|
||||||
error_end: identifier.get_end_position(),
|
let econtainer = ErrorContainer {
|
||||||
}));
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: identifier.get_end_position(),
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"If this function doesn't take any parameter, use an empty list `()`",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -83,18 +117,38 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
Ok((t, next)) => (Some(t), next),
|
Ok((t, next)) => (Some(t), next),
|
||||||
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
Err(ParsingError::Err(err)) => return Err(ParsingError::Err(err)),
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a datatype after the arrow operator."),
|
message: String::from("Expected a Datatype here"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"If you want a function without a return type, omit the arrow as well",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a datatype after the arrow operator."),
|
message: String::from("Expected a Datatype after this arrow `->` operator"),
|
||||||
error_start: arrow_op.position,
|
start: arrow_op.position,
|
||||||
error_end: arrow_op.get_end_position(),
|
end: arrow_op.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: arrow_op.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"If you want a function without a return type, omit the arrow as well",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -107,18 +161,41 @@ impl<'a> Parseable<'a> for FunctionDeclaration<'a> {
|
|||||||
return Err(ParsingError::Err(error));
|
return Err(ParsingError::Err(error));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Mismatch(wrong_token)) => {
|
Err(ParsingError::Mismatch(wrong_token)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
reason: String::from("Expected a block after the function declaration."),
|
message: String::from("Expected a block here, after the function declaration"),
|
||||||
error_start: wrong_token.position,
|
start: wrong_token.position,
|
||||||
error_end: wrong_token.get_end_position(),
|
end: wrong_token.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: wrong_token.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let (error_start, error_end) = {
|
||||||
reason: String::from("Expected a block after the function declaration."),
|
if let Some(return_type) = return_type {
|
||||||
error_start: identifier.position,
|
(return_type.position, return_type.get_end_position())
|
||||||
error_end: identifier.get_end_position(),
|
} else {
|
||||||
}));
|
params_list.get_position()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: String::from("Expected a block here, after the function declaration"),
|
||||||
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_FUNCTION_DECLARATION,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
@ -159,12 +236,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 4);
|
||||||
"Expected an identifier after the `fun` keyword."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 4);
|
|
||||||
assert_eq!(err.error_end, 5);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -173,12 +246,8 @@ mod tests {
|
|||||||
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!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 0);
|
||||||
"Expected an identifier after the `fun` keyword."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 0);
|
|
||||||
assert_eq!(err.error_end, 3);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -191,12 +260,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 7);
|
||||||
"Expected an opening paren after the function identifier."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 7);
|
|
||||||
assert_eq!(err.error_end, 8);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -205,12 +270,8 @@ mod tests {
|
|||||||
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!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 4);
|
||||||
"Expected an opening paren after the function identifier."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 4);
|
|
||||||
assert_eq!(err.error_end, 6);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -223,12 +284,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 7);
|
||||||
"Expected a closing paren after the function identifier."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 7);
|
|
||||||
assert_eq!(err.error_end, 8);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -237,12 +294,8 @@ mod tests {
|
|||||||
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!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 6);
|
||||||
"Expected a closing paren after the function identifier."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 6);
|
|
||||||
assert_eq!(err.error_end, 7);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -255,12 +308,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 0);
|
||||||
"Expected an identifier after the `fun` keyword."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 0);
|
|
||||||
assert_eq!(err.error_end, 3);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -271,12 +320,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 0);
|
||||||
"Expected an identifier after the `fun` keyword."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 0);
|
|
||||||
assert_eq!(err.error_end, 3);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -289,12 +334,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 9);
|
||||||
"Expected a block after the function declaration."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 9);
|
|
||||||
assert_eq!(err.error_end, 10);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -303,12 +344,8 @@ mod tests {
|
|||||||
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!(
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
err.reason,
|
assert_eq!(err.error_offset, 4);
|
||||||
"Expected a block after the function declaration."
|
|
||||||
);
|
|
||||||
assert_eq!(err.error_start, 4);
|
|
||||||
assert_eq!(err.error_end, 6);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -321,9 +358,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.reason, "Expected a closing brace after the block body.");
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_start, 9);
|
assert_eq!(err.error_offset, 9);
|
||||||
assert_eq!(err.error_end, 10);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -333,9 +369,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.reason, "Expected a closing brace after the block body.");
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_start, 9);
|
assert_eq!(err.error_offset, 9);
|
||||||
assert_eq!(err.error_end, 10);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -369,9 +404,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.reason, "Expected a datatype after the arrow operator.");
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_start, 12);
|
assert_eq!(err.error_offset, 9);
|
||||||
assert_eq!(err.error_end, 13);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
@ -384,9 +418,8 @@ mod tests {
|
|||||||
|
|
||||||
match fun_decl {
|
match fun_decl {
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!(err.reason, "Expected a datatype after the arrow operator.");
|
assert_eq!(err.error_code, SYNTAX_INVALID_FUNCTION_DECLARATION);
|
||||||
assert_eq!(err.error_start, 9);
|
assert_eq!(err.error_offset, 9);
|
||||||
assert_eq!(err.error_end, 11);
|
|
||||||
}
|
}
|
||||||
_ => panic!("Expected an error: {:?}", fun_decl),
|
_ => panic!("Expected an error: {:?}", fun_decl),
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{
|
||||||
|
error_messages::{SYNTAX_INCOMPLETE_STATEMENT, SYNTAX_UNEXPECTED_TOKENS},
|
||||||
|
ErrorContainer, ErrorLabel,
|
||||||
|
},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{Expression, ModuleAST, ModuleMembers, Statement},
|
ast::{Expression, ModuleAST, ModuleMembers, Statement},
|
||||||
@ -46,14 +49,23 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
|
|||||||
let next_pos = match parse_terminator(tokens, next_pos) {
|
let next_pos = match parse_terminator(tokens, next_pos) {
|
||||||
Ok((_, next)) => next,
|
Ok((_, next)) => next,
|
||||||
Err(ParsingError::Mismatch(t)) => {
|
Err(ParsingError::Mismatch(t)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: t.position,
|
message: String::from(
|
||||||
error_end: t.get_end_position(),
|
"Expected a new line here, found another token",
|
||||||
reason: format!(
|
|
||||||
"Unexpected token `{}`, expected a new line",
|
|
||||||
t.value
|
|
||||||
),
|
),
|
||||||
}))
|
start: t.position,
|
||||||
|
end: t.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INCOMPLETE_STATEMENT,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from(
|
||||||
|
"There may only be one statement per line",
|
||||||
|
)),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@ -78,14 +90,22 @@ impl<'a> Parseable<'a> for ModuleAST<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reached this point we didn't match any productions and fail
|
// If we reached this point we didn't match any productions and should fail
|
||||||
let t = &tokens[current_pos];
|
let t = &tokens[current_pos];
|
||||||
|
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: t.position,
|
message: String::from("This sequence of tokens couldn't be parsed"),
|
||||||
error_end: t.get_end_position(),
|
start: t.position,
|
||||||
reason: "Expected an statement or an expresion at the top level.".into(),
|
end: t.get_end_position(),
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_UNEXPECTED_TOKENS,
|
||||||
|
error_offset: t.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((ModuleAST { productions }, current_pos))
|
Ok((ModuleAST { productions }, current_pos))
|
||||||
@ -150,7 +170,7 @@ mod test {
|
|||||||
match result {
|
match result {
|
||||||
Ok(_) => panic!("Expected an error"),
|
Ok(_) => panic!("Expected an error"),
|
||||||
Err(ParsingError::Err(err)) => {
|
Err(ParsingError::Err(err)) => {
|
||||||
assert_eq!("Unexpected token `print`, expected a new line", err.reason);
|
assert_eq!(err.error_code, SYNTAX_INCOMPLETE_STATEMENT)
|
||||||
}
|
}
|
||||||
_ => panic!("Expected a parsing error"),
|
_ => panic!("Expected a parsing error"),
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::SyntaxError,
|
error_handling::{error_messages::SYNTAX_INVALID_WHILE_LOOP, ErrorContainer, ErrorLabel},
|
||||||
lexic::token::{Token, TokenType},
|
lexic::token::{Token, TokenType},
|
||||||
syntax::{
|
syntax::{
|
||||||
ast::{loops::WhileLoop, Block, Expression, Positionable},
|
ast::{loops::WhileLoop, Block, Expression, Positionable},
|
||||||
@ -23,21 +23,34 @@ impl<'a> Parseable<'a> for WhileLoop<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(ParsingError::Mismatch(e)) => {
|
Err(ParsingError::Mismatch(e)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: e.position,
|
message: String::from("Expected a Bool expression here"),
|
||||||
error_end: e.get_end_position(),
|
start: e.position,
|
||||||
reason: format!(
|
end: e.get_end_position(),
|
||||||
"Expected an expression after the `while` keyword, found {}",
|
};
|
||||||
e.value
|
let econtainer = ErrorContainer {
|
||||||
),
|
error_code: SYNTAX_INVALID_WHILE_LOOP,
|
||||||
}))
|
error_offset: e.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: while_keyword.position,
|
message: String::from("Expected a Bool expression after this `while` keyword"),
|
||||||
error_end: while_keyword.get_end_position(),
|
start: while_keyword.position,
|
||||||
reason: format!("Expected an identifier after the `while` keyword"),
|
end: while_keyword.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_WHILE_LOOP,
|
||||||
|
error_offset: while_keyword.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,18 +59,36 @@ impl<'a> Parseable<'a> for WhileLoop<'a> {
|
|||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
Err(ParsingError::Err(e)) => return Err(ParsingError::Err(e)),
|
||||||
Err(ParsingError::Mismatch(e)) => {
|
Err(ParsingError::Mismatch(e)) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let label = ErrorLabel {
|
||||||
error_start: e.position,
|
message: String::from("Expected a block here, after the condition"),
|
||||||
error_end: e.get_end_position(),
|
start: e.position,
|
||||||
reason: format!("Expected a block after the condition, found {}", e.value),
|
end: e.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_WHILE_LOOP,
|
||||||
|
error_offset: e.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
Err(ParsingError::Unmatched) => {
|
Err(ParsingError::Unmatched) => {
|
||||||
return Err(ParsingError::Err(SyntaxError {
|
let (error_start, error_end) = condition.get_position();
|
||||||
error_start: while_keyword.position,
|
|
||||||
error_end: while_keyword.get_end_position(),
|
let label = ErrorLabel {
|
||||||
reason: format!("Expected a block after the condition"),
|
message: String::from("Expected a block after this condition"),
|
||||||
}))
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SYNTAX_INVALID_WHILE_LOOP,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(ParsingError::Err(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,6 +72,8 @@ pub fn parse_token_type(
|
|||||||
|
|
||||||
match tokens.get(current_pos) {
|
match tokens.get(current_pos) {
|
||||||
Some(t) if t.token_type == token_type => Ok((t, current_pos + 1)),
|
Some(t) if t.token_type == token_type => Ok((t, current_pos + 1)),
|
||||||
|
// TODO: Why are we checking if the token is NewLine here? Arent all newlines filtered
|
||||||
|
// above?
|
||||||
Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => {
|
Some(t) if t.token_type == TokenType::EOF || t.token_type == TokenType::NewLine => {
|
||||||
Err(ParsingError::Unmatched)
|
Err(ParsingError::Unmatched)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user