Fix bugs and improve error messages
This commit is contained in:
parent
5efcabbfc3
commit
0a22391bae
6
src/lexic/lex_error.rs
Executable file
6
src/lexic/lex_error.rs
Executable file
@ -0,0 +1,6 @@
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LexError {
|
||||
pub position: usize,
|
||||
pub reason: String,
|
||||
}
|
17
src/lexic/mod.rs
Normal file → Executable file
17
src/lexic/mod.rs
Normal file → Executable file
@ -1,6 +1,8 @@
|
||||
mod utils;
|
||||
mod scanner;
|
||||
mod lex_error;
|
||||
use super::token::{self, Token};
|
||||
use lex_error::LexError;
|
||||
|
||||
type Chars = Vec<char>;
|
||||
|
||||
@ -9,12 +11,12 @@ pub enum LexResult {
|
||||
Some(Token, usize),
|
||||
// No token was found, but there was no error (EOF)
|
||||
None(usize),
|
||||
Err(String),
|
||||
Err(LexError),
|
||||
}
|
||||
|
||||
|
||||
/// Scans and returns all the tokens in the input String
|
||||
pub fn get_tokens(input: &String) -> Result<Vec<Token>, String> {
|
||||
pub fn get_tokens(input: &String) -> Result<Vec<Token>, LexError> {
|
||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
||||
let mut results = Vec::new();
|
||||
let mut current_pos: usize = 0;
|
||||
@ -44,6 +46,11 @@ fn next_token(chars: &Chars, current_pos: usize) -> LexResult {
|
||||
return LexResult::None(current_pos)
|
||||
}
|
||||
|
||||
// Ignore new lines for now...
|
||||
if next_char == '\n' {
|
||||
return next_token(chars, current_pos + 1)
|
||||
}
|
||||
|
||||
// Handle whitespace recursively
|
||||
if next_char == ' ' {
|
||||
return next_token(chars, current_pos + 1)
|
||||
@ -57,7 +64,11 @@ fn next_token(chars: &Chars, current_pos: usize) -> LexResult {
|
||||
.or_else(|| scanner::operator(next_char, chars, current_pos))
|
||||
.or_else(|| scanner::grouping_sign(next_char, chars, current_pos))
|
||||
.unwrap_or_else(|| {
|
||||
LexResult::Err(format!("Unrecognized character: {}", next_char))
|
||||
let error = LexError {
|
||||
position: current_pos,
|
||||
reason: format!("Unrecognized character: {}", next_char),
|
||||
};
|
||||
LexResult::Err(error)
|
||||
})
|
||||
}
|
||||
|
||||
|
0
src/lexic/scanner/identifier.rs
Normal file → Executable file
0
src/lexic/scanner/identifier.rs
Normal file → Executable file
3
src/lexic/scanner/mod.rs
Normal file → Executable file
3
src/lexic/scanner/mod.rs
Normal file → Executable file
@ -40,7 +40,8 @@ pub fn grouping_sign(c: char, _: &Vec<char>, start_pos: usize) -> Option<LexResu
|
||||
|
||||
/// Attempts to scan an identifier. Returns None to be able to chain other scanner
|
||||
pub fn identifier(c: char, chars: &Vec<char>, start_pos: usize) -> Option<LexResult> {
|
||||
utils::is_lowercase(c).then(|| identifier::scan(c, chars, start_pos))
|
||||
(utils::is_lowercase(c) || c == '_')
|
||||
.then(|| identifier::scan(c, chars, start_pos))
|
||||
}
|
||||
|
||||
|
||||
|
32
src/lexic/scanner/number.rs
Normal file → Executable file
32
src/lexic/scanner/number.rs
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
use crate::lexic::{
|
||||
token::{self, Token},
|
||||
utils, LexResult,
|
||||
utils, LexResult, lex_error::LexError,
|
||||
};
|
||||
|
||||
/// Function to scan a number
|
||||
@ -47,7 +47,10 @@ fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> LexResult {
|
||||
let (t, next) = scan_hex_digits(chars, start_pos + 1, utils::str_append(current, *c));
|
||||
LexResult::Some(t, next)
|
||||
}
|
||||
_ => LexResult::Err(String::from("Tried to scan an incomplete hex value")),
|
||||
_ => LexResult::Err(LexError {
|
||||
position: start_pos,
|
||||
reason: String::from("Tried to scan an incomplete hex value"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,10 +63,16 @@ fn scan_hex(chars: &Vec<char>, start_pos: usize, current: String) -> LexResult {
|
||||
fn scan_double(chars: &Vec<char>, start_pos: usize, current: String) -> LexResult {
|
||||
match chars.get(start_pos) {
|
||||
Some(c) if utils::is_digit(*c) => scan_double_impl(chars, start_pos, current),
|
||||
Some(_) => LexResult::Err(String::from(
|
||||
Some(_) => LexResult::Err(LexError {
|
||||
position: start_pos,
|
||||
reason : String::from(
|
||||
"The character after the dot when scanning a double is not a number.",
|
||||
)),
|
||||
_ => LexResult::Err(String::from("EOF when scanning a double number.")),
|
||||
)
|
||||
}),
|
||||
_ => LexResult::Err(LexError {
|
||||
position: start_pos,
|
||||
reason: String::from("EOF when scanning a double number."),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,9 +107,12 @@ fn scan_scientific(chars: &Vec<char>, start_pos: usize, current: String) -> LexR
|
||||
let (t, next) = scan_digits(chars, start_pos + 2, new_value);
|
||||
LexResult::Some(t, next)
|
||||
}
|
||||
_ => LexResult::Err(String::from(
|
||||
_ => LexResult::Err(LexError {
|
||||
position: start_pos,
|
||||
reason: String::from(
|
||||
"The characters after 'e' are not + or -, or are not followed by a number",
|
||||
)),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,7 +229,7 @@ mod tests {
|
||||
let start_pos = 0;
|
||||
|
||||
match scan(&input, start_pos) {
|
||||
LexResult::Err(reason) => assert_eq!("Tried to scan an incomplete hex value", reason),
|
||||
LexResult::Err(reason) => assert_eq!("Tried to scan an incomplete hex value", reason.reason),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
@ -277,7 +289,7 @@ mod tests {
|
||||
match scan(&input, start_pos) {
|
||||
LexResult::Err(reason) => assert_eq!(
|
||||
"The character after the dot when scanning a double is not a number.",
|
||||
reason
|
||||
reason.reason
|
||||
),
|
||||
_ => panic!(),
|
||||
}
|
||||
@ -286,7 +298,7 @@ mod tests {
|
||||
let start_pos = 0;
|
||||
|
||||
match scan(&input, start_pos) {
|
||||
LexResult::Err(reason) => assert_eq!("EOF when scanning a double number.", reason),
|
||||
LexResult::Err(reason) => assert_eq!("EOF when scanning a double number.", reason.reason),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
2
src/lexic/scanner/operator.rs
Normal file → Executable file
2
src/lexic/scanner/operator.rs
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
use crate::lexic::{token::{Token, self}, utils, LexResult};
|
||||
use crate::lexic::{token, utils, LexResult};
|
||||
|
||||
|
||||
/// Function to scan an operator
|
||||
|
16
src/lexic/scanner/string.rs
Normal file → Executable file
16
src/lexic/scanner/string.rs
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
use crate::lexic::{
|
||||
token::{self, Token},
|
||||
utils, LexResult,
|
||||
token,
|
||||
utils, LexResult, lex_error::LexError,
|
||||
};
|
||||
|
||||
/// Function to scan a string
|
||||
@ -17,7 +17,10 @@ pub fn scan_impl(chars: &Vec<char>, start_pos: usize, current: String) -> LexRes
|
||||
LexResult::Some(token::new_string(current, start_pos as i32), start_pos + 1)
|
||||
}
|
||||
Some(c) if *c == '\n' => {
|
||||
LexResult::Err(String::from("Unexpected new line inside a string."))
|
||||
LexResult::Err(LexError {
|
||||
position: start_pos,
|
||||
reason: String::from("Unexpected new line inside a string.")
|
||||
})
|
||||
}
|
||||
Some(c) if *c == '\\' => {
|
||||
if let Some(escape) = test_escape_char(chars, start_pos + 1) {
|
||||
@ -44,7 +47,10 @@ pub fn scan_impl(chars: &Vec<char>, start_pos: usize, current: String) -> LexRes
|
||||
)
|
||||
}
|
||||
None => {
|
||||
LexResult::Err(String::from("Incomplete string found"))
|
||||
LexResult::Err(LexError {
|
||||
position: start_pos,
|
||||
reason: String::from("Incomplete string found")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,7 +114,7 @@ mod tests {
|
||||
let input = str_to_vec("\"Hello,\nworld!\"");
|
||||
let start_pos = 1;
|
||||
if let LexResult::Err(reason) = scan(&input, start_pos) {
|
||||
assert_eq!("Unexpected new line inside a string.", reason)
|
||||
assert_eq!("Unexpected new line inside a string.", reason.reason)
|
||||
}
|
||||
else {panic!()}
|
||||
}
|
||||
|
0
src/lexic/utils.rs
Normal file → Executable file
0
src/lexic/utils.rs
Normal file → Executable file
0
src/main.rs
Normal file → Executable file
0
src/main.rs
Normal file → Executable file
14
src/repl/mod.rs
Normal file → Executable file
14
src/repl/mod.rs
Normal file → Executable file
@ -4,6 +4,19 @@ use super::lexic;
|
||||
|
||||
fn compile(input: &String) {
|
||||
let _tokens = lexic::get_tokens(input);
|
||||
|
||||
match _tokens {
|
||||
Ok(tokens) => {
|
||||
for token in tokens {
|
||||
print!("[{}] ", token.value);
|
||||
}
|
||||
println!("");
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error scanning.\n{} at pos {}", error.reason, error.position)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn run() -> io::Result<()> {
|
||||
@ -23,7 +36,6 @@ pub fn run() -> io::Result<()> {
|
||||
break Ok(())
|
||||
},
|
||||
Ok(_) => {
|
||||
println!("{}", buffer);
|
||||
compile(&buffer);
|
||||
},
|
||||
Err(error) => {
|
||||
|
0
src/syntax/mod.rs
Normal file → Executable file
0
src/syntax/mod.rs
Normal file → Executable file
0
src/token.rs
Normal file → Executable file
0
src/token.rs
Normal file → Executable file
Loading…
Reference in New Issue
Block a user