Add simple error reporting for lexical errors (rebase)
This commit is contained in:
parent
c83cd23d49
commit
d8ea08b28b
@ -11,7 +11,6 @@
|
||||
- [ ] Stdlib
|
||||
- [ ] Document code
|
||||
|
||||
|
||||
## v0.0.4
|
||||
|
||||
- Explicit datatype of variables
|
||||
@ -27,6 +26,11 @@
|
||||
|
||||
- Compilation of `val` and `var` bindings with a number, string or boolean as value.
|
||||
- Register symbols and datatypes in the Symbol table.
|
||||
- Add better error messages for lexical errors. Show:
|
||||
- Offending line
|
||||
- Pointer to offending character
|
||||
- Error message
|
||||
|
||||
|
||||
## v0.0.1
|
||||
|
||||
|
@ -1,29 +1,47 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::{collections::VecDeque, fmt::format};
|
||||
use super::{PrintableError, LexError};
|
||||
|
||||
impl PrintableError for LexError {
|
||||
// TODO: Count and show line number
|
||||
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
||||
String::from("D:")
|
||||
|
||||
let (erroneous_code, back_count) = get_line(chars, self.position);
|
||||
|
||||
let mut whitespace = Vec::<char>::new();
|
||||
for i in 0..back_count {
|
||||
whitespace.push(' ');
|
||||
}
|
||||
let whitespace = whitespace.iter().collect::<String>();
|
||||
|
||||
format!(
|
||||
"\n{}\n{}^\n\n{}{}",
|
||||
erroneous_code,
|
||||
whitespace,
|
||||
"Invalid character at pos ",
|
||||
self.position + 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts a line of code from `chars`. `pos` indicates a position,
|
||||
/// from where to extract the line.
|
||||
/// Extracts a line of code from `chars` and the number of characters in the back.
|
||||
/// `pos` indicates a position, from where to extract the line.
|
||||
///
|
||||
/// Ex. Given:
|
||||
/// - `input = "first line\nsecond line\nthird line"`
|
||||
/// - `pos = 15`
|
||||
///
|
||||
/// this function should return `"second line"`
|
||||
fn get_line(chars: &Vec<char>, pos: usize) -> String {
|
||||
/// this function should return `("second line", 4)`
|
||||
fn get_line(chars: &Vec<char>, pos: usize) -> (String, usize) {
|
||||
let mut result_chars = VecDeque::<char>::new();
|
||||
|
||||
// Push chars to the front until a new line is found
|
||||
// TODO: refactor
|
||||
let mut before_pos = pos;
|
||||
loop {
|
||||
let current_char = chars[before_pos];
|
||||
|
||||
if current_char == '\n' {
|
||||
before_pos += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -50,7 +68,7 @@ fn get_line(chars: &Vec<char>, pos: usize) -> String {
|
||||
after_pos += 1;
|
||||
}
|
||||
|
||||
result_chars.iter().collect::<String>()
|
||||
(result_chars.iter().collect::<String>(), pos - before_pos)
|
||||
}
|
||||
|
||||
|
||||
@ -61,7 +79,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
fn test_error_msg() {
|
||||
let input = String::from("val name' = 20");
|
||||
let result = lexic::get_tokens(&input);
|
||||
|
||||
@ -70,12 +88,16 @@ mod tests {
|
||||
Err(err_data) => {
|
||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
||||
let err_str = err_data.get_error_str(&chars);
|
||||
assert_ne!(
|
||||
"\n\
|
||||
val name' = 20\n\
|
||||
. ^\n\
|
||||
\n\
|
||||
Invalid character at line 1, pos 9",
|
||||
|
||||
// TODO: check for line number
|
||||
let expected_str = format!(
|
||||
"\n{}\n{}^\n\nInvalid character at pos 9",
|
||||
"val name' = 20",
|
||||
" "
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
expected_str,
|
||||
err_str,
|
||||
);
|
||||
}
|
||||
@ -87,16 +109,18 @@ mod tests {
|
||||
let input = String::from("first line\nsecond line\nthird line");
|
||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
||||
|
||||
let result = get_line(&chars, 15);
|
||||
let (result, back_count) = get_line(&chars, 15);
|
||||
|
||||
assert_eq!("second line", result);
|
||||
assert_eq!(4, back_count);
|
||||
|
||||
|
||||
let input = String::from("val binding = 322");
|
||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
||||
|
||||
let result = get_line(&chars, 6);
|
||||
let (result, back_count) = get_line(&chars, 6);
|
||||
|
||||
assert_eq!("val binding = 322", result);
|
||||
assert_eq!(6, back_count);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user