Add slightly more readable error messages in the compiler
Previously, the CompileError error messages were just `Debug::fmt` written to stdout and there wasn't really a backtrace in the code included. Now, when there is an error in an imported file, it will display a backtrace of the files included that caused this error. These are not perfect error messages and are a bit rough around the edges but they are good enough for now. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -70,17 +70,44 @@ impl Scope {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub struct CompileError {
|
||||
pub line: Option<LineRange>,
|
||||
pub message: String,
|
||||
pub enum CompileError {
|
||||
Error {
|
||||
line: Option<LineRange>,
|
||||
source_path: String,
|
||||
message: String,
|
||||
},
|
||||
Import {
|
||||
error: Box<dyn std::error::Error>,
|
||||
line: LineRange,
|
||||
source_path: String,
|
||||
dest_path: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for CompileError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(line) = &self.line {
|
||||
write!(fmt, "line {:?}: {}", line, self.message)
|
||||
} else {
|
||||
write!(fmt, "{}", self.message)
|
||||
match self {
|
||||
CompileError::Error {
|
||||
line: Some((line, _)),
|
||||
source_path,
|
||||
message,
|
||||
} => write!(fmt, "{source_path}: line {line}: {message}"),
|
||||
CompileError::Error {
|
||||
line: None,
|
||||
source_path,
|
||||
message,
|
||||
} => write!(fmt, "{source_path}: {}", message),
|
||||
CompileError::Import {
|
||||
error,
|
||||
line: (line, _),
|
||||
source_path,
|
||||
dest_path,
|
||||
} => {
|
||||
write!(
|
||||
fmt,
|
||||
"error in {dest_path} (included from {source_path} on line {line}:\n\t{error}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,8 +165,9 @@ impl<'c> Compiler<'c> {
|
||||
|
||||
pub fn compile_path(self, path: impl AsRef<Path>) -> Result<Ptr<Module>> {
|
||||
let path_str = &path.as_ref().as_os_str().to_str().unwrap();
|
||||
let mut file = File::open(path.as_ref()).map_err(|e| CompileError {
|
||||
let mut file = File::open(path.as_ref()).map_err(|e| CompileError::Error {
|
||||
line: None,
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!("could not open {}: {}", path.as_ref().display(), e),
|
||||
})?;
|
||||
let mut contents = String::new();
|
||||
@@ -149,8 +177,9 @@ impl<'c> Compiler<'c> {
|
||||
let ast = parser.parse_all()?;
|
||||
|
||||
if parser.was_error() {
|
||||
return Err(CompileError {
|
||||
return Err(CompileError::Error {
|
||||
line: None,
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!("error in '{}'", path.as_ref().display()),
|
||||
}
|
||||
.into());
|
||||
@@ -217,8 +246,9 @@ impl<'c> Compiler<'c> {
|
||||
|
||||
let index = self.constants.len();
|
||||
if index > (ConstantId::MAX as usize) {
|
||||
return Err(CompileError {
|
||||
return Err(CompileError::Error {
|
||||
line: None,
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!("too many constants (maximum {})", ConstantId::MAX),
|
||||
}
|
||||
.into());
|
||||
@@ -243,8 +273,9 @@ impl<'c> Compiler<'c> {
|
||||
|
||||
let index = self.globals.len();
|
||||
if index > (GlobalId::MAX as usize) {
|
||||
return Err(CompileError {
|
||||
return Err(CompileError::Error {
|
||||
line: None,
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!("too many globals (maximum {})", GlobalId::MAX),
|
||||
}
|
||||
.into());
|
||||
@@ -302,8 +333,9 @@ impl<'c> Compiler<'c> {
|
||||
fn insert_local(&mut self, name: String) -> Result<&Local> {
|
||||
let index = self.chunk().locals.len();
|
||||
if index > (LocalIndex::MAX as usize) {
|
||||
return Err(CompileError {
|
||||
return Err(CompileError::Error {
|
||||
line: None,
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!("too many locals (maximum: {})", LocalIndex::MAX),
|
||||
}
|
||||
.into());
|
||||
@@ -327,8 +359,9 @@ impl<'c> Compiler<'c> {
|
||||
// get the last allocated slot and increment by one
|
||||
let last = &scope.scope.last().unwrap();
|
||||
if last.slot == LocalSlot::MAX {
|
||||
return Err(CompileError {
|
||||
return Err(CompileError::Error {
|
||||
line: None,
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!(
|
||||
"too many stack slots used by locals(maximum: {})",
|
||||
LocalSlot::MAX
|
||||
@@ -444,9 +477,11 @@ impl StmtVisitor for Compiler<'_> {
|
||||
// also into the modules cache
|
||||
let module = Compiler::new(path.clone(), self.constants, self.imported)
|
||||
.compile_path(&path)
|
||||
.map_err(|e| CompileError {
|
||||
line: Some(line),
|
||||
message: format!("while importing module '{}': {}", stmt.module.text, e),
|
||||
.map_err(|error| CompileError::Import {
|
||||
error,
|
||||
line,
|
||||
source_path: self.path.display().to_string(),
|
||||
dest_path: path_str.to_string(),
|
||||
})?;
|
||||
self.imported.insert(path_str.to_string(), module.clone());
|
||||
module
|
||||
@@ -684,8 +719,9 @@ impl ExprVisitor for Compiler<'_> {
|
||||
self.compile_expr(arg)?;
|
||||
}
|
||||
if expr.args.len() > (Argc::MAX as usize) {
|
||||
return Err(CompileError {
|
||||
return Err(CompileError::Error {
|
||||
line: Some(expr_line_number(expr)),
|
||||
source_path: self.path.display().to_string(),
|
||||
message: format!("too many function arguments (maximum: {})", Argc::MAX),
|
||||
}
|
||||
.into());
|
||||
@@ -718,8 +754,9 @@ impl ExprVisitor for Compiler<'_> {
|
||||
if let Some(local) = self.get_local(name) {
|
||||
self.emit(expr_line_number(expr), Op::GetLocal(local.index));
|
||||
} else {
|
||||
let global = self.get_global(name).ok_or_else(|| CompileError {
|
||||
let global = self.get_global(name).ok_or_else(|| CompileError::Error {
|
||||
line: Some(expr_line_number(expr)),
|
||||
source_path: self.path.display().to_string(),
|
||||
message: if self.is_global_scope() {
|
||||
format!("unknown global {}", name)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user