Use codespan for *much* prettier error reporting.
This commit is contained in:
@@ -2,111 +2,44 @@ use lalrpop_util::lalrpop_mod;
|
||||
|
||||
mod token_stream;
|
||||
mod tokens;
|
||||
lalrpop_mod!(parser, "/syntax/parser.rs");
|
||||
lalrpop_mod!(
|
||||
#[allow(clippy::just_underscores_and_digits)]
|
||||
parser,
|
||||
"/syntax/parser.rs"
|
||||
);
|
||||
mod ast;
|
||||
|
||||
pub use crate::syntax::ast::*;
|
||||
use crate::syntax::parser::ProgramParser;
|
||||
use crate::syntax::token_stream::{LexerError, Location, TokenStream};
|
||||
use crate::syntax::tokens::Token;
|
||||
#[cfg(test)]
|
||||
use crate::util::istring::InternedString;
|
||||
use crate::syntax::token_stream::TokenStream;
|
||||
pub use crate::syntax::token_stream::{LexerError, Location};
|
||||
pub use crate::syntax::tokens::Token;
|
||||
use lalrpop_util::ParseError;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
#[cfg(test)]
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParserError {
|
||||
IOError(io::Error),
|
||||
ParseError(ParseError<Location, Token, LexerError>),
|
||||
}
|
||||
|
||||
impl fmt::Display for ParserError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ParserError::IOError(e) => write!(f, "IO error: {}", e),
|
||||
|
||||
ParserError::ParseError(ParseError::ExtraToken{ token: (loc, tok, _)}) => {
|
||||
write!(f, "{}: Unexpected additional token ({}) found at end of file", loc, tok)
|
||||
}
|
||||
ParserError::ParseError(ParseError::InvalidToken { location }) => {
|
||||
write!(f, "{}: Unexpected token encountered", location)
|
||||
}
|
||||
ParserError::ParseError(ParseError::UnrecognizedEOF { location, expected }) => {
|
||||
write!(f, "{}: Unexpected EOF{}", location, display_expected(expected))
|
||||
}
|
||||
ParserError::ParseError(ParseError::UnrecognizedToken { token: (location, tok, _), expected }) => {
|
||||
write!(f, "{}: Unexpected token {}{}", location, tok, display_expected(expected))
|
||||
}
|
||||
ParserError::ParseError(ParseError::User{ error }) => {
|
||||
write!(f, "{}: Couldn't process input (lexer error)", error.location)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn display_expected(expected: &Vec<String>) -> String {
|
||||
match expected.len() {
|
||||
0 => "".to_string(),
|
||||
1 => format!("; expected {}", expected[0]),
|
||||
2 => format!("; expected {} or {}", expected[0], expected[1]),
|
||||
n => format!("; expected {}or {}", comma_separate(&expected[0..n-1]), expected[n-1])
|
||||
}
|
||||
}
|
||||
|
||||
fn comma_separate(strings: &[String]) -> String {
|
||||
let mut result = String::new();
|
||||
|
||||
for s in strings.iter() {
|
||||
result.push_str(&s);
|
||||
result.push_str(", ");
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
impl From<io::Error> for ParserError {
|
||||
fn from(x: io::Error) -> Self {
|
||||
ParserError::IOError(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseError<Location, Token, LexerError>> for ParserError {
|
||||
fn from(x: ParseError<Location, Token, LexerError>) -> Self {
|
||||
ParserError::ParseError(x)
|
||||
}
|
||||
}
|
||||
type ParserError = ParseError<Location, Token, LexerError>;
|
||||
|
||||
impl Program {
|
||||
pub fn from_file(filename: &str) -> Result<Program, ParserError> {
|
||||
let metadata = fs::metadata(filename)?;
|
||||
let mut buffer = String::with_capacity(metadata.len() as usize);
|
||||
let lexer = TokenStream::from_file(filename, &mut buffer)?;
|
||||
Ok(ProgramParser::new().parse(lexer)?)
|
||||
}
|
||||
|
||||
fn parse(filename: &str, buffer: &mut String) -> Result<Program, ParserError> {
|
||||
let lexer = TokenStream::new(filename, buffer);
|
||||
Ok(ProgramParser::new().parse(lexer)?)
|
||||
pub fn parse(file_idx: usize, buffer: &str) -> Result<Program, ParserError> {
|
||||
let lexer = TokenStream::new(file_idx, buffer);
|
||||
ProgramParser::new().parse(lexer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl FromStr for Program {
|
||||
type Err = ParserError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Program, ParserError> {
|
||||
let mut s2 = s.to_string();
|
||||
Program::parse("<from_str>", &mut s2)
|
||||
Program::parse(0, s)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn order_of_operations() {
|
||||
let muladd1 = "1 + 2 * 3";
|
||||
let testfile = InternedString::new("<from_str>");
|
||||
let testfile = 0;
|
||||
assert_eq!(
|
||||
Program::from_str(muladd1).unwrap(),
|
||||
Program {
|
||||
|
||||
Reference in New Issue
Block a user