refactor: begin to implement new error interface
This commit is contained in:
parent
eed0bb8c76
commit
fef5ee8041
@ -6,18 +6,17 @@
|
|||||||
- Implement functions as first class citizens
|
- Implement functions as first class citizens
|
||||||
- Parse __more__ binary operators
|
- Parse __more__ binary operators
|
||||||
- Parse more complex bindings
|
- Parse more complex bindings
|
||||||
- Rework error messages
|
|
||||||
- Parse other language constructions
|
|
||||||
- Namespace identifiers in the symbol table
|
- Namespace identifiers in the symbol table
|
||||||
- Stdlib
|
- Stdlib
|
||||||
- Document code
|
- Document code
|
||||||
- Watch mode
|
- Watch mode
|
||||||
- Simple language server
|
- Simple language server
|
||||||
- Decide how to handle comments in the syntax (?)(should comments mean something like in rust?)
|
- Decide how to handle comments in the syntax (?)(should comments mean something like in rust?)
|
||||||
- Fix comment handling in the AST
|
|
||||||
- Abstract the parsing of datatypes, such that in the future generics can be implemented in a single place
|
- Abstract the parsing of datatypes, such that in the future generics can be implemented in a single place
|
||||||
- Begin work on the code formatter
|
- Begin work on the code formatter
|
||||||
- Remove all panic! and todo!
|
- Remove all panic! and todo!
|
||||||
|
- Change REPL to execute code only after `;;` is found
|
||||||
|
- Forward the code generated by the REPL to the PHP repl
|
||||||
|
|
||||||
## v0.1.2
|
## v0.1.2
|
||||||
|
|
||||||
@ -29,6 +28,7 @@
|
|||||||
- [x] Typecheck if/else if/else
|
- [x] Typecheck if/else if/else
|
||||||
- [x] Typecheck for loops
|
- [x] Typecheck for loops
|
||||||
- [x] Typecheck while loops
|
- [x] Typecheck while loops
|
||||||
|
- [x] Include Ariadne for error reporting
|
||||||
|
|
||||||
|
|
||||||
## v0.1.1
|
## v0.1.1
|
||||||
|
4
error_codes.yaml
Normal file
4
error_codes.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
-- A map of error codes to error messages
|
||||||
|
|
||||||
|
0x000001: Incomplete string
|
||||||
|
|
3
src/error_handling/error_messages.rs
Normal file
3
src/error_handling/error_messages.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
//! Contains constants that point to error messages
|
||||||
|
|
||||||
|
pub const LEX_INCOMPLETE_STRING: u32 = 0;
|
@ -7,14 +7,33 @@ pub mod semantic_error;
|
|||||||
mod syntax_error;
|
mod syntax_error;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub mod error_messages;
|
||||||
|
|
||||||
pub trait PrintableError {
|
pub trait PrintableError {
|
||||||
fn get_error_str(&self, chars: &Vec<char>) -> String;
|
fn get_error_str(&self, chars: &Vec<char>) -> String;
|
||||||
fn print_ariadne(&self, source: &String);
|
fn print_ariadne(&self, source: &String);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
pub struct ErrorContainer {
|
||||||
|
pub error_code: u32,
|
||||||
|
pub error_offset: usize,
|
||||||
|
pub labels: Vec<ErrorLabel>,
|
||||||
|
pub note: Option<String>,
|
||||||
|
pub help: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mirrors ariadne's Label
|
||||||
|
#[derive(Serialize, Debug)]
|
||||||
|
pub struct ErrorLabel {
|
||||||
|
pub message: String,
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub enum MistiError {
|
pub enum MistiError {
|
||||||
Lex(LexError),
|
Lex(ErrorContainer),
|
||||||
Syntax(SyntaxError),
|
Syntax(SyntaxError),
|
||||||
Semantic(SemanticError),
|
Semantic(SemanticError),
|
||||||
}
|
}
|
||||||
@ -37,7 +56,7 @@ pub struct SyntaxError {
|
|||||||
impl PrintableError for MistiError {
|
impl PrintableError for MistiError {
|
||||||
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Lex(err) => err.get_error_str(chars),
|
Self::Lex(err) => panic!("REMOVED: manually generating an error message"),
|
||||||
Self::Syntax(err) => err.get_error_str(chars),
|
Self::Syntax(err) => err.get_error_str(chars),
|
||||||
Self::Semantic(err) => err.get_error_str(chars),
|
Self::Semantic(err) => err.get_error_str(chars),
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ mod utils;
|
|||||||
|
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
|
||||||
use crate::error_handling::{LexError, MistiError};
|
use crate::error_handling::{ErrorContainer, ErrorLabel, LexError, MistiError};
|
||||||
use token::Token;
|
use token::Token;
|
||||||
|
|
||||||
use self::token::TokenType;
|
use self::token::TokenType;
|
||||||
@ -36,7 +36,7 @@ pub enum LexResult {
|
|||||||
/// Contains the last position, which should be the input lenght - 1
|
/// Contains the last position, which should be the input lenght - 1
|
||||||
None(usize),
|
None(usize),
|
||||||
/// An error was found while scanning.
|
/// An error was found while scanning.
|
||||||
Err(LexError),
|
Err(ErrorContainer),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scans and returns all the tokens in the input String
|
/// Scans and returns all the tokens in the input String
|
||||||
@ -151,16 +151,20 @@ fn next_token(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let error = LexError {
|
let label = ErrorLabel {
|
||||||
position: current_pos,
|
message: String::from("This character is not allowed"),
|
||||||
end_position: current_pos + 1,
|
start: current_pos,
|
||||||
reason: format!(
|
end: current_pos + 1,
|
||||||
"Illegal character `{}` (escaped: {})",
|
|
||||||
next_char,
|
|
||||||
next_char.escape_default().to_string(),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
LexResult::Err(error)
|
let error_container = ErrorContainer {
|
||||||
|
error_offset: current_pos,
|
||||||
|
error_code: 0x010001,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: Some(String::from("Remove this character")),
|
||||||
|
};
|
||||||
|
|
||||||
|
LexResult::Err(error_container)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,15 +200,15 @@ fn handle_indentation(
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Illegal state: Indentation error
|
// Illegal state: Indentation error
|
||||||
let error = LexError {
|
let econtaner = ErrorContainer {
|
||||||
position: current_pos,
|
error_code: 0,
|
||||||
end_position: current_pos + 1,
|
error_offset: current_pos,
|
||||||
reason: format!(
|
labels: vec![],
|
||||||
"Indentation error: expected {} spaces, found {}",
|
note: None,
|
||||||
new_top, spaces
|
help: None,
|
||||||
),
|
|
||||||
};
|
};
|
||||||
return LexResult::Err(error);
|
|
||||||
|
return LexResult::Err(econtaner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::error_handling::LexError;
|
use crate::error_handling::error_messages::LEX_INCOMPLETE_STRING;
|
||||||
|
use crate::error_handling::{ErrorContainer, ErrorLabel};
|
||||||
use crate::lexic::token::Token;
|
use crate::lexic::token::Token;
|
||||||
use crate::lexic::{utils, LexResult};
|
use crate::lexic::{utils, LexResult};
|
||||||
|
|
||||||
@ -26,11 +27,27 @@ pub fn scan_impl(chars: &Vec<char>, start_pos: usize, current: String) -> LexRes
|
|||||||
start_pos + 1,
|
start_pos + 1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Some(c) if *c == '\n' => LexResult::Err(LexError {
|
Some(c) if *c == '\n' => {
|
||||||
position: start_pos,
|
let string_start_pos = start_pos - (current.len() + 1);
|
||||||
end_position: start_pos + 1,
|
let label_2 = ErrorLabel {
|
||||||
reason: String::from("Unexpected new line inside a string."),
|
message: String::from("The line ends here"),
|
||||||
}),
|
start: start_pos,
|
||||||
|
end: start_pos + 1,
|
||||||
|
};
|
||||||
|
let label_1 = ErrorLabel {
|
||||||
|
message: String::from("The string starts here"),
|
||||||
|
start: string_start_pos,
|
||||||
|
end: string_start_pos + 1,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: LEX_INCOMPLETE_STRING,
|
||||||
|
error_offset: start_pos,
|
||||||
|
labels: vec![label_1, label_2],
|
||||||
|
note: Some(String::from("Strings cannot have newlines")),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
LexResult::Err(econtainer)
|
||||||
|
}
|
||||||
Some(c) if *c == '\\' => {
|
Some(c) if *c == '\\' => {
|
||||||
if let Some(escape) = test_escape_char(chars, start_pos + 1) {
|
if let Some(escape) = test_escape_char(chars, start_pos + 1) {
|
||||||
// This should only detect an escaped `"`
|
// This should only detect an escaped `"`
|
||||||
@ -40,11 +57,28 @@ pub fn scan_impl(chars: &Vec<char>, start_pos: usize, current: String) -> LexRes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(c) => scan_impl(chars, start_pos + 1, utils::str_append(current, *c)),
|
Some(c) => scan_impl(chars, start_pos + 1, utils::str_append(current, *c)),
|
||||||
None => LexResult::Err(LexError {
|
None => {
|
||||||
position: start_pos,
|
let string_start_pos = start_pos - (current.len() + 1);
|
||||||
end_position: start_pos + 1,
|
let label_1 = ErrorLabel {
|
||||||
reason: String::from("Incomplete string found"),
|
message: String::from("The string starts here"),
|
||||||
}),
|
start: string_start_pos,
|
||||||
|
end: string_start_pos + 1,
|
||||||
|
};
|
||||||
|
let label_2 = ErrorLabel {
|
||||||
|
message: String::from("The code ends here"),
|
||||||
|
start: start_pos,
|
||||||
|
end: start_pos + 1,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: LEX_INCOMPLETE_STRING,
|
||||||
|
error_offset: start_pos,
|
||||||
|
labels: vec![label_1, label_2],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
LexResult::Err(econtainer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,8 +141,8 @@ mod tests {
|
|||||||
fn should_not_scan_a_new_line() {
|
fn should_not_scan_a_new_line() {
|
||||||
let input = str_to_vec("\"Hello,\nworld!\"");
|
let input = str_to_vec("\"Hello,\nworld!\"");
|
||||||
let start_pos = 1;
|
let start_pos = 1;
|
||||||
if let LexResult::Err(reason) = scan(&input, start_pos) {
|
if let LexResult::Err(err) = scan(&input, start_pos) {
|
||||||
assert_eq!("Unexpected new line inside a string.", reason.reason)
|
assert_eq!(LEX_INCOMPLETE_STRING, err.error_code)
|
||||||
} else {
|
} else {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
@ -204,8 +238,8 @@ mod tests {
|
|||||||
let result = scan(&input, start_pos);
|
let result = scan(&input, start_pos);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
LexResult::Err(reason) => {
|
LexResult::Err(err) => {
|
||||||
assert_eq!("Incomplete string found", reason.reason)
|
assert_eq!(LEX_INCOMPLETE_STRING, err.error_code)
|
||||||
}
|
}
|
||||||
_ => panic!("expected an error"),
|
_ => panic!("expected an error"),
|
||||||
}
|
}
|
||||||
@ -217,8 +251,8 @@ mod tests {
|
|||||||
let result = scan(&input, 1);
|
let result = scan(&input, 1);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
LexResult::Err(reason) => {
|
LexResult::Err(err) => {
|
||||||
assert_eq!("Incomplete string found", reason.reason)
|
assert_eq!(LEX_INCOMPLETE_STRING, err.error_code)
|
||||||
}
|
}
|
||||||
_ => panic!("expected an error"),
|
_ => panic!("expected an error"),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user