Add functions for error handling (merge)

master
Araozu 2023-01-24 10:01:09 -05:00
parent f28e7394e9
commit c83cd23d49
9 changed files with 164 additions and 11 deletions

7
Cargo.lock generated
View File

@ -172,6 +172,7 @@ name = "misti"
version = "0.0.3"
dependencies = [
"chrono",
"owo-colors",
]
[[package]]
@ -199,6 +200,12 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "owo-colors"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "proc-macro2"
version = "1.0.47"

View File

@ -7,3 +7,4 @@ edition = "2021"
[dependencies]
chrono = "0.4.23"
owo-colors = "3.5.0"

View File

@ -0,0 +1,102 @@
use std::collections::VecDeque;
use super::{PrintableError, LexError};
impl PrintableError for LexError {
fn get_error_str(&self, chars: &Vec<char>) -> String {
String::from("D:")
}
}
/// Extracts a line of code from `chars`. `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 {
let mut result_chars = VecDeque::<char>::new();
// Push chars to the front until a new line is found
let mut before_pos = pos;
loop {
let current_char = chars[before_pos];
if current_char == '\n' {
break;
}
result_chars.push_front(current_char);
if before_pos == 0 {
break;
}
before_pos -= 1;
}
// Push chars to the end until a new line is found
let mut after_pos = pos + 1;
let char_count = chars.len();
while after_pos < char_count {
let current_char = chars[after_pos];
if current_char == '\n' {
break;
}
result_chars.push_back(current_char);
after_pos += 1;
}
result_chars.iter().collect::<String>()
}
#[cfg(test)]
mod tests {
use crate::lexic;
use super::*;
#[test]
fn test() {
let input = String::from("val name' = 20");
let result = lexic::get_tokens(&input);
match result {
Ok(_) => assert!(false),
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",
err_str,
);
}
}
}
#[test]
fn should_extract_line() {
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);
assert_eq!("second line", result);
let input = String::from("val binding = 322");
let chars: Vec<char> = input.chars().into_iter().collect();
let result = get_line(&chars, 6);
assert_eq!("val binding = 322", result);
}
}

27
src/error_handling/mod.rs Normal file
View File

@ -0,0 +1,27 @@
mod lex_error;
pub trait PrintableError {
fn get_error_str(&self, chars: &Vec<char>) -> String;
}
#[derive(Debug)]
pub enum MistiError {
Lex(LexError)
}
#[derive(Debug)]
pub struct LexError {
pub position: usize,
pub reason: String,
}
impl PrintableError for MistiError {
fn get_error_str(&self, chars: &Vec<char>) -> String {
match self {
Self::Lex(err) => err.get_error_str(chars)
}
}
}

View File

@ -1,8 +1,8 @@
mod utils;
mod scanner;
mod lex_error;
use super::token::{self, Token};
use lex_error::LexError;
use crate::error_handling::{MistiError, LexError};
type Chars = Vec<char>;
@ -34,7 +34,7 @@ pub enum LexResult {
/// Scans and returns all the tokens in the input String
pub fn get_tokens(input: &String) -> Result<Vec<Token>, LexError> {
pub fn get_tokens(input: &String) -> Result<Vec<Token>, MistiError> {
let chars: Vec<char> = input.chars().into_iter().collect();
let mut results = Vec::new();
let mut current_pos: usize = 0;
@ -48,7 +48,9 @@ pub fn get_tokens(input: &String) -> Result<Vec<Token>, LexError> {
LexResult::None(next_pos) => {
current_pos = next_pos;
},
LexResult::Err(reason) => return Err(reason),
LexResult::Err(error_info) => {
return Err(MistiError::Lex(error_info));
}
}
}

View File

@ -1,7 +1,8 @@
use crate::lexic::{
token::{self, Token},
utils, LexResult, lex_error::LexError,
utils, LexResult,
};
use crate::error_handling::LexError;
/// Function to scan a number
///

View File

@ -1,7 +1,8 @@
use crate::lexic::{
token,
utils, LexResult, lex_error::LexError,
utils, LexResult,
};
use crate::error_handling::LexError;
/// Function to scan a string
///

View File

@ -1,15 +1,25 @@
use std::io;
use chrono::{prelude::Utc, Datelike};
// Module to handle the repl and its compilation
mod repl;
mod syntax;
mod lexic;
// Defines the types of tokens and provides functions to create them
mod token;
// Module to handle lexical analysis
mod syntax;
// Module to handle syntactic analysis
mod lexic;
// Module to handle semantic analysis
mod semantic;
// Defines the AST
mod ast_types;
// Defines the Symbol table and operations within
mod symbol_table;
// Transforms an AST to JS
mod codegen;
mod error_handling;
const VERSION: &str = "0.0.1";
fn get_copyright() -> String {

View File

@ -1,5 +1,6 @@
use std::io::{self, Write};
use crate::error_handling::PrintableError;
use crate::symbol_table::SymbolTable;
use crate::token::Token;
@ -10,14 +11,15 @@ use super::codegen;
/// Executes Lexical analysis, handles errors and calls build_ast for the next phase
fn compile(input: &String) {
let _tokens = lexic::get_tokens(input);
let tokens = lexic::get_tokens(input);
match _tokens {
match tokens {
Ok(tokens) => {
build_ast(tokens);
},
Err(error) => {
eprintln!("Error scanning.\n{} at pos {}", error.reason, error.position)
let chars: Vec<char> = input.chars().into_iter().collect();
eprintln!("{}", error.get_error_str(&chars))
}
}