Re-implemented nicer error reporting.

We lost this in the initial move to streaming parsing.  All
errors now (again) print out a line number and an error message.
This commit is contained in:
Nathan Vegdahl 2020-01-11 19:09:20 +09:00
parent 46d0ef3b28
commit 66dcbc2e7f
3 changed files with 103 additions and 29 deletions

View File

@ -40,7 +40,14 @@ mod timer;
// mod tracer; // mod tracer;
mod transform_stack; mod transform_stack;
use std::{fs::File, io, io::Read, mem, path::Path, str::FromStr}; use std::{
fs::File,
io,
io::{Read, Seek},
mem,
path::Path,
str::FromStr,
};
use clap::{App, Arg}; use clap::{App, Arg};
use nom::bytes::complete::take_until; use nom::bytes::complete::take_until;
@ -261,8 +268,8 @@ fn main() {
let ident = ident.map(|v| v.to_string()); let ident = ident.map(|v| v.to_string());
let scene = let scene =
parse_scene(&arena, &mut events, ident.as_deref()).unwrap_or_else(|e| { parse_scene(&arena, &mut events, ident.as_deref()).unwrap_or_else(|e| {
println!("Parse error: {}", e); print!("Parse error: ");
// e.print(&psy_contents); e.print(&mut io::BufReader::new(File::open(file_path).unwrap()));
panic!("Parse error."); panic!("Parse error.");
}); });

View File

@ -32,23 +32,22 @@ pub enum PsyError {
// The first usize for all errors is their byte offset // The first usize for all errors is their byte offset
// into the psy content where they occured. // into the psy content where they occured.
UnknownError(usize), UnknownError(usize),
UnknownVariant(usize, String), // Error message UnknownVariant(usize, String), // Error message
ExpectedInternalNode(usize, String), // Error message ExpectedInternalNode(usize, String), // Error message
ExpectedLeafNode(usize, String), // Error message ExpectedLeafNode(usize, String), // Error message
ExpectedIdent(usize, String), // Error message ExpectedIdent(usize, String), // Error message
MissingNode(usize, String), // Error message MissingNode(usize, String), // Error message
IncorrectLeafData(usize, String), // Error message IncorrectLeafData(usize, String), // Error message
WrongNodeCount(usize, String), // Error message WrongNodeCount(usize, String), // Error message
InstancedMissingData(usize, String, String), // Error message, data name ExpectedInternalNodeClose(usize, String), // Error message
ExpectedInternalNodeClose(usize, String),
ReaderError(data_tree::Error), ReaderError(data_tree::Error),
} }
impl PsyError { impl PsyError {
pub fn print(&self, psy_content: &str) { pub fn print(&self, psy_content: impl BufRead) {
match self { match self {
PsyError::UnknownError(offset) => { PsyError::UnknownError(offset) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!( println!(
"Line {}: Unknown parse error. If you get this message, please report \ "Line {}: Unknown parse error. If you get this message, please report \
it to the developers so they can improve the error messages.", it to the developers so they can improve the error messages.",
@ -57,46 +56,87 @@ impl PsyError {
} }
PsyError::UnknownVariant(offset, error) => { PsyError::UnknownVariant(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::ExpectedInternalNode(offset, error) => { PsyError::ExpectedInternalNode(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::ExpectedLeafNode(offset, error) => { PsyError::ExpectedLeafNode(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::ExpectedIdent(offset, error) => { PsyError::ExpectedIdent(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::MissingNode(offset, error) => { PsyError::MissingNode(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::IncorrectLeafData(offset, error) => { PsyError::IncorrectLeafData(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::WrongNodeCount(offset, error) => { PsyError::WrongNodeCount(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {}", line, error); println!("Line {}: {}", line, error);
} }
PsyError::InstancedMissingData(offset, error, data_name) => { PsyError::ExpectedInternalNodeClose(offset, error) => {
let line = line_count_to_byte_offset(psy_content, *offset); let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: {} Data name: '{}'", line, error, data_name); println!("Line {}: {}", line, error);
} }
_ => todo!(), PsyError::ReaderError(data_tree::Error::ExpectedTypeNameOrClose(offset)) => {
let line = byte_offset_to_line_char(psy_content, *offset);
println!(
"Line {}: Expected either a type name or a closing brace.",
line
);
}
PsyError::ReaderError(data_tree::Error::ExpectedOpenOrIdent(offset)) => {
let line = byte_offset_to_line_char(psy_content, *offset);
println!(
"Line {}: Expected either an opening brace/bracket or an ident.",
line
);
}
PsyError::ReaderError(data_tree::Error::ExpectedOpen(offset)) => {
let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: Expected an opening brace.", line);
}
PsyError::ReaderError(data_tree::Error::UnexpectedClose(offset)) => {
let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: Encountered an unexpected closing brace.", line);
}
PsyError::ReaderError(data_tree::Error::UnexpectedIdent(offset)) => {
let line = byte_offset_to_line_char(psy_content, *offset);
println!("Line {}: Encountered and unexpected ident.", line);
}
PsyError::ReaderError(data_tree::Error::UnexpectedEOF) => {
let line = byte_offset_to_line_char(psy_content, std::usize::MAX);
println!(
"Line {}: Unexpected end-of-stream, data tree incomplete.",
line
);
}
PsyError::ReaderError(data_tree::Error::IO(error)) => {
println!("IO error while parsing scene: {}", error);
}
} }
} }
} }
@ -115,8 +155,27 @@ impl From<data_tree::Error> for PsyError {
} }
} }
fn line_count_to_byte_offset(text: &str, offset: usize) -> usize { fn byte_offset_to_line_char(mut reader: impl BufRead, byte_offset: usize) -> usize {
text[..offset].matches('\n').count() + 1 let mut line_buf = String::new();
let mut bytes_read = 0;
let mut current_line = 1;
loop {
line_buf.clear();
if let Ok(_) = reader.read_line(&mut line_buf) {
if line_buf.is_empty() {
break;
}
bytes_read += line_buf.len();
if byte_offset < bytes_read {
return current_line;
}
current_line += 1;
} else {
todo!(); // Handle error properly.
}
}
return current_line;
} }
//---------------------------------------------------------------- //----------------------------------------------------------------

View File

@ -100,12 +100,20 @@ pub fn parse_assembly<'a>(
)); ));
} }
_ => { Event::InnerOpen {
type_name,
byte_offset,
..
} => {
return Err(PsyError::UnknownVariant( return Err(PsyError::UnknownVariant(
byte_offset, byte_offset,
"Unknown data type for Object.".into(), format!("Unknown data type '{}' for Object.", type_name),
)); ));
} }
_ => {
return Err(PsyError::UnknownError(byte_offset));
}
}; };
// Close object node. // Close object node.