Skip to content

Commit

Permalink
parser(error): refactor codes
Browse files Browse the repository at this point in the history
  • Loading branch information
chanbengz committed Dec 6, 2024
1 parent b9cb11b commit 7c9402d
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 51 deletions.
78 changes: 37 additions & 41 deletions src/parser/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,50 @@
use std::fs::File;
use std::io::Read;
use colored::Colorize;
use spl_lexer::tokens::{Token, LexicalError};
use lalrpop_util::ErrorRecovery;

pub trait EmitError {
fn error(&self);
}

pub fn display_error(errors: &Vec<ErrorRecovery<usize, Token, LexicalError>>, input: &str, source_path: &str) {
let lines = input.lines().collect::<Vec<&str>>();
for error in errors {
let error = &error.error;
if let lalrpop_util::ParseError::User { error } = error { match error {
impl EmitError for LexicalError {
fn error(&self) {
let mut input = String::new();
let (span, error_msg) = match self {
LexicalError::UnknownLexeme(span) => {
(span, format!("{} unknown lexeme [{}]", "error:".red(), "A".red()))
},
LexicalError::MissingLexeme(span, token) => {
let lineno = input[..span.start].lines().count();
let lineno = if lineno == 0 { 1 } else { lineno };
let begin = input[..span.start].rfind('\n').unwrap_or(0);
line_error(
(span.start - begin, span.end - begin), lineno,
lines[lineno - 1],
&format!("{} missing {} [{}]",
"error:".red(), token.as_str(), "B".red()
),
source_path
);
(span, format!("{} missing {} [{}]", "error:".red(), token.as_str(), "B".red()))
},
LexicalError::UnknownLexeme(span) => {
let lineno = input[..span.start].lines().count();
let lineno = if lineno == 0 { 1 } else { lineno };
let begin = input[..span.start].rfind('\n').unwrap_or(0);
line_error(
(span.start - begin, span.end - begin), lineno,
lines[lineno - 1],
&format!("{} unknown lexeme [{}]",
"error:".red(), "A".red()
),
source_path,
);
}, _ => {} }
}
_ => { return; }
};

File::open(&span.source).unwrap().read_to_string(&mut input).unwrap();
let lineno = input[..span.start].lines().count();
let lineno = if lineno == 0 { 1.to_string() } else { lineno.to_string() };
let begin = input[..span.start].rfind('\n').unwrap_or(0);
let line_str = input.lines().nth(lineno.parse::<usize>().unwrap() - 1).unwrap();
let padding = " ".repeat(lineno.len() + 1);
let padding_msg = " ".repeat(span.start - begin);
let bar = "|".purple();

let mut indicator = "^".to_string();
indicator.push_str(&"~".repeat(span.end - span.start - 1));
println!("{} {}:{lineno}:{}: {error_msg}\n{padding}{}\n{} {} {line_str}\n{padding}{}{padding_msg}{}",
"-->".purple(), span.source, span.start, &bar, lineno.purple(), &bar,
bar, indicator.red());
}
}

fn line_error( span: (usize, usize), lineno: usize, line_str: &str, error_msg: &str, source_path: &str) {
let lineno = lineno.to_string();
let padding = " ".repeat(lineno.len() + 1);
let padding_msg = " ".repeat(span.0);
let mut indicator = "^".to_string();
indicator.push_str(&"~".repeat(span.1 - span.0 - 1));
println!("{} {}:{lineno}:{}: {error_msg}\n{padding}{}\n{} {} {line_str}\n\
{padding}{}{padding_msg}{}",
"-->".purple(), source_path, span.0, "|".purple(), lineno.purple(), "|".purple(),
"|".purple(), indicator.red()
)
pub fn emit_error(errors: &Vec<ErrorRecovery<usize, Token, LexicalError>>) {
for error in errors {
let error = &error.error;
if let lalrpop_util::ParseError::User { error } = error {
error.error();
}
}
}

pub fn format_errors(errors: &Vec<ErrorRecovery<usize, Token, LexicalError>>)
Expand Down
18 changes: 15 additions & 3 deletions src/parser/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ pub Stmt: tree::Statement = {
end: r
}, "semicolon ';'".to_string())
},
dropped_tokens: Vec::new(), // or specify the dropped tokens
dropped_tokens: Vec::new(),
};
errors.push(error);
}
Expand Down Expand Up @@ -528,7 +528,19 @@ WhileExpr: tree::Expr = {
}

ForExpr: tree::Expr = {
"for" "(" <init:VarManagement> ";" <cond:CondExpr> ";" <update:VarManagement> ")" "{" <body:Body> "}" => {
"for" "(" <init:VarManagement?> ";" <cond:CondExpr?> ";" <update:VarManagement?> ")" "{" <body:Body> "}" => {
let init = match init {
Some(init) => init,
None => tree::Expr::VarManagement(Vec::new())
};
let cond = match cond {
Some(cond) => cond,
None => Box::new(tree::CondExpr::Bool(true))
};
let update = match update {
Some(update) => update,
None => tree::Expr::VarManagement(Vec::new())
};
tree::Expr::Loop(
tree::Loop::ForExpr(
Box::new(init),
Expand Down Expand Up @@ -684,7 +696,7 @@ VarDec: tree::Variable = {
}

StructDec: tree::Variable = {
"." <ident: Identifier> ":" <val: CompExpr> => {
"." <ident: Identifier> "=" <val: CompExpr> => {
tree::Variable::VarAssignment(
Box::new(ident),
val,
Expand Down
14 changes: 7 additions & 7 deletions src/parser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::fmt::format;
use std::fs::File;
use lalrpop_util::{lalrpop_mod, ErrorRecovery};
use spl_lexer::tokens::{Token, LexicalError};

lalrpop_mod!(pub grammar); // synthesized by LALRPOP
use spl_ast::tree;
pub use crate::error::display_error;
pub use crate::error::emit_error;
use crate::grammar::ProgramParser;

pub mod error;
Expand All @@ -31,12 +32,11 @@ pub fn parse_from_file(source_path: &str) -> Result<tree::Program, String> {
let mut errors = Vec::new();
let lexer = spl_lexer::lexer::Lexer::new(&source);
let result = ProgramParser::new().parse(&mut errors, source_path, lexer);
match result {
Ok(ast) => Ok(ast),
Err(_) => {
display_error(&errors, &source, source_path);
Err(format!("\n{} syntax error(s) found", errors.len()))
}
if errors.len() == 0 && result.is_ok() {
Ok(result.unwrap())
} else {
emit_error(&errors);
Err(format!("\n{} syntax error(s) found", errors.len()))
}
}

Expand Down

0 comments on commit 7c9402d

Please sign in to comment.