Clean up and prettify parsing errors
This commit is contained in:
parent
c0791ebb83
commit
7c809fa764
@ -49,7 +49,7 @@ pub use self::{
|
||||
|
||||
use crate::{
|
||||
context::Context,
|
||||
error::{Error, RuntimeError, ValidationError},
|
||||
error::{DustError, RuntimeError, ValidationError},
|
||||
Value,
|
||||
};
|
||||
|
||||
@ -110,7 +110,7 @@ impl AbstractTree {
|
||||
self,
|
||||
context: &mut Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Option<Value>, Vec<Error>> {
|
||||
) -> Result<Option<Value>, Vec<DustError>> {
|
||||
let valid_statements = self.validate(context, manage_memory)?;
|
||||
let mut previous_value = None;
|
||||
|
||||
@ -125,7 +125,7 @@ impl AbstractTree {
|
||||
_ => {}
|
||||
},
|
||||
Err(runtime_error) => {
|
||||
return Err(vec![Error::Runtime {
|
||||
return Err(vec![DustError::Runtime {
|
||||
error: runtime_error,
|
||||
position,
|
||||
}]);
|
||||
@ -140,7 +140,7 @@ impl AbstractTree {
|
||||
self,
|
||||
context: &mut Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Vec<Statement>, Vec<Error>> {
|
||||
) -> Result<Vec<Statement>, Vec<DustError>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut valid_statements = Vec::new();
|
||||
|
||||
@ -148,7 +148,7 @@ impl AbstractTree {
|
||||
let validation = statement.validate(context, manage_memory);
|
||||
|
||||
if let Err(validation_error) = validation {
|
||||
errors.push(Error::Validation {
|
||||
errors.push(DustError::Validation {
|
||||
error: validation_error,
|
||||
position: statement.position(),
|
||||
})
|
||||
@ -158,7 +158,7 @@ impl AbstractTree {
|
||||
let run = statement.evaluate(context, true);
|
||||
|
||||
if let Err(runtime_error) = run {
|
||||
errors.push(Error::Runtime {
|
||||
errors.push(DustError::Runtime {
|
||||
error: runtime_error,
|
||||
position,
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
pub enum DustError {
|
||||
Lex {
|
||||
expected: String,
|
||||
span: (usize, usize),
|
||||
@ -30,9 +30,9 @@ pub enum Error {
|
||||
},
|
||||
}
|
||||
|
||||
impl From<Rich<'_, char>> for Error {
|
||||
impl From<Rich<'_, char>> for DustError {
|
||||
fn from(error: Rich<'_, char>) -> Self {
|
||||
Error::Lex {
|
||||
DustError::Lex {
|
||||
expected: error.expected().map(|error| error.to_string()).collect(),
|
||||
span: (error.span().start(), error.span().end()),
|
||||
reason: error.reason().to_string(),
|
||||
@ -40,9 +40,9 @@ impl From<Rich<'_, char>> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> From<Rich<'_, Token<'src>>> for Error {
|
||||
impl<'src> From<Rich<'_, Token<'src>>> for DustError {
|
||||
fn from(error: Rich<'_, Token<'src>>) -> Self {
|
||||
Error::Parse {
|
||||
DustError::Parse {
|
||||
expected: error.expected().map(|error| error.to_string()).collect(),
|
||||
span: (error.span().start(), error.span().end()),
|
||||
found: error.found().map(|token| token.to_string()),
|
||||
|
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::error::DustError;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Token<'src> {
|
||||
@ -187,7 +187,7 @@ impl Display for Control {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lex<'src>(source: &'src str) -> Result<Vec<(Token<'src>, SimpleSpan)>, Vec<Error>> {
|
||||
pub fn lex<'src>(source: &'src str) -> Result<Vec<(Token<'src>, SimpleSpan)>, Vec<DustError>> {
|
||||
lexer()
|
||||
.parse(source)
|
||||
.into_result()
|
||||
|
@ -16,7 +16,7 @@ use abstract_tree::{AbstractTree, Type};
|
||||
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
||||
use chumsky::prelude::*;
|
||||
use context::Context;
|
||||
use error::{Error, RuntimeError, TypeConflict, ValidationError};
|
||||
use error::{DustError, RuntimeError, TypeConflict, ValidationError};
|
||||
use lexer::{lex, Token};
|
||||
use parser::{parse, parser};
|
||||
use rayon::prelude::*;
|
||||
@ -155,7 +155,7 @@ impl<'a> Interpreter<'a> {
|
||||
.into_result()
|
||||
.map_err(|errors| InterpreterError {
|
||||
source_id: source_id.clone(),
|
||||
errors: errors.into_iter().map(Error::from).collect(),
|
||||
errors: errors.into_iter().map(DustError::from).collect(),
|
||||
});
|
||||
let abstract_tree = match parse_result {
|
||||
Ok(statements) => AbstractTree::new(statements),
|
||||
@ -185,22 +185,26 @@ impl<'a> Interpreter<'a> {
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct InterpreterError {
|
||||
source_id: Arc<str>,
|
||||
errors: Vec<Error>,
|
||||
errors: Vec<DustError>,
|
||||
}
|
||||
|
||||
impl InterpreterError {
|
||||
pub fn errors(&self) -> &Vec<Error> {
|
||||
pub fn errors(&self) -> &Vec<DustError> {
|
||||
&self.errors
|
||||
}
|
||||
}
|
||||
|
||||
impl InterpreterError {
|
||||
pub fn build_reports<'a>(self) -> Vec<Report<'a, (Arc<str>, Range<usize>)>> {
|
||||
let token_color = Color::Yellow;
|
||||
let type_color = Color::Green;
|
||||
let identifier_color = Color::Blue;
|
||||
|
||||
let mut reports = Vec::new();
|
||||
|
||||
for error in self.errors {
|
||||
let (mut builder, validation_error) = match error {
|
||||
Error::Lex {
|
||||
DustError::Lex {
|
||||
expected,
|
||||
span,
|
||||
reason,
|
||||
@ -226,7 +230,7 @@ impl InterpreterError {
|
||||
None,
|
||||
)
|
||||
}
|
||||
Error::Parse {
|
||||
DustError::Parse {
|
||||
expected,
|
||||
span,
|
||||
found,
|
||||
@ -236,7 +240,7 @@ impl InterpreterError {
|
||||
} else {
|
||||
format!("Expected {expected}.")
|
||||
};
|
||||
let found = found.unwrap_or_else(|| "End of input".to_string());
|
||||
let found = found.unwrap_or_else(|| "End of input".to_string()).fg(token_color);
|
||||
|
||||
(
|
||||
Report::build(
|
||||
@ -253,7 +257,7 @@ impl InterpreterError {
|
||||
None,
|
||||
)
|
||||
}
|
||||
Error::Validation { error, position } => (
|
||||
DustError::Validation { error, position } => (
|
||||
Report::build(
|
||||
ReportKind::Custom("Validation Error", Color::Magenta),
|
||||
self.source_id.clone(),
|
||||
@ -263,7 +267,7 @@ impl InterpreterError {
|
||||
.with_note("This error was detected by the interpreter before running the code."),
|
||||
Some(error),
|
||||
),
|
||||
Error::Runtime { error, position } => (
|
||||
DustError::Runtime { error, position } => (
|
||||
Report::build(
|
||||
ReportKind::Custom("Runtime Error", Color::Red),
|
||||
self.source_id.clone(),
|
||||
@ -287,9 +291,6 @@ impl InterpreterError {
|
||||
),
|
||||
};
|
||||
|
||||
let type_color = Color::Green;
|
||||
let identifier_color = Color::Blue;
|
||||
|
||||
if let Some(validation_error) = validation_error {
|
||||
match validation_error {
|
||||
|
||||
|
@ -4,7 +4,7 @@ use chumsky::{input::SpannedInput, pratt::*, prelude::*};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::*,
|
||||
error::Error,
|
||||
error::DustError,
|
||||
identifier::Identifier,
|
||||
lexer::{Control, Keyword, Operator, Token},
|
||||
};
|
||||
@ -14,15 +14,17 @@ pub type ParserInput<'src> =
|
||||
|
||||
pub type ParserExtra<'src> = extra::Err<Rich<'src, Token<'src>, SimpleSpan>>;
|
||||
|
||||
pub fn parse<'src>(tokens: &'src [(Token<'src>, SimpleSpan)]) -> Result<AbstractTree, Vec<Error>> {
|
||||
pub fn parse<'src>(
|
||||
tokens: &'src [(Token<'src>, SimpleSpan)],
|
||||
) -> Result<AbstractTree, Vec<DustError>> {
|
||||
let statements = parser(false)
|
||||
.parse(tokens.spanned((tokens.len()..tokens.len()).into()))
|
||||
.into_result()
|
||||
.map_err(|errors| {
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|error| Error::from(error))
|
||||
.collect::<Vec<Error>>()
|
||||
.map(|error| DustError::from(error))
|
||||
.collect::<Vec<DustError>>()
|
||||
})?;
|
||||
|
||||
Ok(AbstractTree::new(statements))
|
||||
@ -224,9 +226,9 @@ pub fn parser<'src>(
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.at_least(1)
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.or_not(),
|
||||
.collect(),
|
||||
)
|
||||
.or_not()
|
||||
.then(
|
||||
identifier
|
||||
.clone()
|
||||
@ -744,8 +746,8 @@ mod tests {
|
||||
.map_err(|errors| {
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|error| Error::from(error))
|
||||
.collect::<Vec<Error>>()
|
||||
.map(|error| DustError::from(error))
|
||||
.collect::<Vec<DustError>>()
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -763,8 +765,8 @@ mod tests {
|
||||
.map_err(|errors| {
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|error| Error::from(error))
|
||||
.collect::<Vec<Error>>()
|
||||
.map(|error| DustError::from(error))
|
||||
.collect::<Vec<DustError>>()
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
@ -6,7 +6,7 @@ fn function_call_with_type_argument() {
|
||||
interpret(
|
||||
"test",
|
||||
"
|
||||
foobar = fn (T)(x : T) T { x }
|
||||
foobar = fn T (x: T) -> T { x }
|
||||
foobar::(int)::(42)
|
||||
",
|
||||
),
|
||||
@ -20,7 +20,7 @@ fn function_call() {
|
||||
interpret(
|
||||
"test",
|
||||
"
|
||||
foobar = fn (message : str) str { message }
|
||||
foobar = fn (message: str) -> str { message }
|
||||
foobar('Hiya')
|
||||
",
|
||||
),
|
||||
@ -34,10 +34,10 @@ fn callback() {
|
||||
interpret(
|
||||
"test",
|
||||
"
|
||||
foobar = fn (cb: fn() -> str) str {
|
||||
foobar = fn (cb: fn () -> str) -> str {
|
||||
cb()
|
||||
}
|
||||
foobar(fn () str { 'Hiya' })
|
||||
foobar(fn () -> str { 'Hiya' })
|
||||
",
|
||||
),
|
||||
Ok(Some(Value::string("Hiya".to_string())))
|
||||
@ -55,8 +55,8 @@ fn function_context_captures_values() {
|
||||
interpret(
|
||||
"test",
|
||||
"
|
||||
bar = fn () int { 2 }
|
||||
foo = fn () int { bar() }
|
||||
bar = fn () -> int { 2 }
|
||||
foo = fn () -> int { bar() }
|
||||
foo()
|
||||
"
|
||||
),
|
||||
@ -70,7 +70,7 @@ fn recursion() {
|
||||
interpret(
|
||||
"test",
|
||||
"
|
||||
fib = fn (i: int) int {
|
||||
fib = fn (i: int) -> int {
|
||||
if i <= 1 {
|
||||
1
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
abstract_tree::{Type, WithPos},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
error::{DustError, TypeConflict, ValidationError},
|
||||
identifier::Identifier,
|
||||
interpret, Value,
|
||||
};
|
||||
@ -49,7 +49,7 @@ fn field_type_error() {
|
||||
)
|
||||
.unwrap_err()
|
||||
.errors(),
|
||||
&vec![Error::Validation {
|
||||
&vec![DustError::Validation {
|
||||
error: ValidationError::TypeCheck {
|
||||
conflict: TypeConflict {
|
||||
actual: Type::String,
|
||||
@ -109,7 +109,7 @@ fn undefined_struct() {
|
||||
)
|
||||
.unwrap_err()
|
||||
.errors(),
|
||||
&vec![Error::Validation {
|
||||
&vec![DustError::Validation {
|
||||
error: ValidationError::VariableNotFound {
|
||||
identifier: Identifier::new("Foo"),
|
||||
position: (17, 20).into()
|
||||
|
@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use dust_lang::{
|
||||
abstract_tree::{Type, WithPos},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
error::{DustError, TypeConflict, ValidationError},
|
||||
identifier::Identifier,
|
||||
*,
|
||||
};
|
||||
@ -141,7 +141,7 @@ fn map_type_errors() {
|
||||
interpret("test", "{ foo : bool = 'bar' }")
|
||||
.unwrap_err()
|
||||
.errors(),
|
||||
&vec![Error::Validation {
|
||||
&vec![DustError::Validation {
|
||||
error: ValidationError::TypeCheck {
|
||||
conflict: TypeConflict {
|
||||
actual: Type::String,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
abstract_tree::{Block, Expression, Statement, Type, WithPos},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
error::{DustError, TypeConflict, ValidationError},
|
||||
identifier::Identifier,
|
||||
*,
|
||||
};
|
||||
@ -27,7 +27,7 @@ fn set_variable_with_type_error() {
|
||||
interpret("test", "foobar: str = true")
|
||||
.unwrap_err()
|
||||
.errors(),
|
||||
&vec![Error::Validation {
|
||||
&vec![DustError::Validation {
|
||||
error: ValidationError::TypeCheck {
|
||||
conflict: TypeConflict {
|
||||
actual: Type::Boolean,
|
||||
|
@ -60,7 +60,19 @@ fn main() {
|
||||
let mut interpreter = Interpreter::new(context.clone());
|
||||
|
||||
if !args.no_std {
|
||||
interpreter.load_std().unwrap();
|
||||
let load_std_result = interpreter.load_std();
|
||||
|
||||
if let Err(error) = load_std_result {
|
||||
eprintln!("Failed to load standard library");
|
||||
|
||||
for report in error.build_reports() {
|
||||
report
|
||||
.write_for_stdout(sources(interpreter.sources()), stderr())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let (source_id, source): (Arc<str>, Arc<str>) = if let Some(path) = args.path {
|
||||
|
Loading…
Reference in New Issue
Block a user