mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
REFACTOR: Error handling to use BuildError throughout.
Also removed more extraneous error output. Contributes toward issue #45
This commit is contained in:
parent
e5f406d4e9
commit
85f239a566
@ -159,8 +159,7 @@ fn test_assert_just_keyword_compile_failures() {
|
|||||||
assert_build_failure(
|
assert_build_failure(
|
||||||
"assert ",
|
"assert ",
|
||||||
vec![
|
vec![
|
||||||
Regex::new(r"line: 1, column: 1").unwrap(),
|
Regex::new(r"Expected Tuple \{ok=<bool>, desc=<str>\} at <eval> line: 1, column: 8")
|
||||||
Regex::new(r"Expected Tuple \{ok=<bool>, desc=<str>\}: at <eval> line: 1, column: 8")
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -171,10 +170,9 @@ fn test_assert_partial_tuple_compile_failures() {
|
|||||||
assert_build_failure(
|
assert_build_failure(
|
||||||
"assert {",
|
"assert {",
|
||||||
vec![
|
vec![
|
||||||
Regex::new(r"line: 1, column: 1").unwrap(),
|
Regex::new(r"Expected Tuple \{ok=<bool>, desc=<str>\} at <eval> line: 1, column: 8")
|
||||||
Regex::new(r"Expected Tuple \{ok=<bool>, desc=<str>\}: at <eval> line: 1, column: 8")
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Regex::new(r"Expected \(\}\) but got \(\): at <eval> line: 1, column: 9").unwrap(),
|
Regex::new(r"Expected \(\}\) but got \(\) at <eval> line: 1, column: 9").unwrap(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -227,10 +225,7 @@ fn test_assert_partial_tuple_bad_desc_compile_failures() {
|
|||||||
fn test_import_missing_path_compile_failure() {
|
fn test_import_missing_path_compile_failure() {
|
||||||
assert_build_failure(
|
assert_build_failure(
|
||||||
"import ;",
|
"import ;",
|
||||||
vec![
|
vec![Regex::new(r"Expected import path at <eval> line: 1, column: 8").unwrap()],
|
||||||
Regex::new(r"Expected import path: at <eval> line: 1, column: 8").unwrap(),
|
|
||||||
Regex::new(r"Not a String: at <eval> line: 1, column: 8").unwrap(),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +233,7 @@ fn test_import_missing_path_compile_failure() {
|
|||||||
fn test_import_path_not_a_string_compile_failure() {
|
fn test_import_path_not_a_string_compile_failure() {
|
||||||
assert_build_failure(
|
assert_build_failure(
|
||||||
"import 1;",
|
"import 1;",
|
||||||
vec![
|
vec![Regex::new(r"Expected import path at <eval> line: 1, column: 8").unwrap()],
|
||||||
Regex::new(r"Expected import path: at <eval> line: 1, column: 8").unwrap(),
|
|
||||||
Regex::new(r"Not a String: at <eval> line: 1, column: 8").unwrap(),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +242,7 @@ fn test_binary_operator_missing_operand_compile_failure() {
|
|||||||
assert_build_failure(
|
assert_build_failure(
|
||||||
"1 +",
|
"1 +",
|
||||||
vec![
|
vec![
|
||||||
Regex::new(r"Missing operand for binary expression: at <eval> line: 1, column: 4")
|
Regex::new(r"Missing operand for binary expression at <eval> line: 1, column: 4")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -427,7 +419,6 @@ fn test_out_missing_type_compile_failure() {
|
|||||||
"out",
|
"out",
|
||||||
vec![
|
vec![
|
||||||
Regex::new(r"Expected converter name").unwrap(),
|
Regex::new(r"Expected converter name").unwrap(),
|
||||||
Regex::new(r"Not a Bareword").unwrap(),
|
|
||||||
Regex::new(r"at <eval> line: 1, column: 4").unwrap(),
|
Regex::new(r"at <eval> line: 1, column: 4").unwrap(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -328,16 +328,7 @@ where
|
|||||||
Some(val) => Ok(val),
|
Some(val) => Ok(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => Err(Box::new(err)),
|
||||||
let cause = Box::new(simple_error::SimpleError::new(err));
|
|
||||||
Err(error::BuildError::with_pos(
|
|
||||||
"Unable to parse input",
|
|
||||||
error::ErrorType::ParseError,
|
|
||||||
(&input).into(),
|
|
||||||
)
|
|
||||||
.wrap_cause(cause)
|
|
||||||
.to_boxed())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
src/error.rs
60
src/error.rs
@ -145,48 +145,28 @@ impl error::Error for BuildError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl<'a, C> std::convert::From<abortable_parser::Error<C>> for BuildError
|
||||||
pub struct StackPrinter<C: FilePositioned> {
|
where
|
||||||
pub err: abortable_parser::Error<C>,
|
C: FilePositioned + 'a,
|
||||||
|
C: abortable_parser::Offsetable + Debug,
|
||||||
|
{
|
||||||
|
fn from(e: abortable_parser::Error<C>) -> BuildError {
|
||||||
|
BuildError::from(&e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: FilePositioned> StackPrinter<C> {
|
impl<'a, C> std::convert::From<&'a abortable_parser::Error<C>> for BuildError
|
||||||
pub fn render(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
where
|
||||||
let mut curr_err = Some(&self.err);
|
C: FilePositioned + 'a,
|
||||||
let mut tabstop = "";
|
C: abortable_parser::Offsetable + Debug,
|
||||||
loop {
|
{
|
||||||
match curr_err {
|
fn from(e: &'a abortable_parser::Error<C>) -> BuildError {
|
||||||
// our exit condition;
|
let ctx = e.get_context();
|
||||||
None => break,
|
let position = Position::new(ctx.line(), ctx.column(), ctx.get_offset());
|
||||||
Some(err) => {
|
let err = BuildError::with_pos(e.get_msg(), ErrorType::ParseError, position);
|
||||||
let context = err.get_context();
|
match e.get_cause() {
|
||||||
let file = match context.file() {
|
None => err,
|
||||||
Some(ref pb) => pb.to_string_lossy().to_string(),
|
Some(cause) => err.wrap_cause(Box::new(BuildError::from(cause))),
|
||||||
None => "<eval>".to_string(),
|
|
||||||
};
|
|
||||||
writeln!(
|
|
||||||
w,
|
|
||||||
"{}{}: at {} line: {}, column: {}",
|
|
||||||
tabstop,
|
|
||||||
err.get_msg(),
|
|
||||||
file,
|
|
||||||
context.line(),
|
|
||||||
context.column(),
|
|
||||||
)?;
|
|
||||||
tabstop = "\t";
|
|
||||||
curr_err = err.get_cause();
|
|
||||||
if curr_err.is_some() {
|
|
||||||
writeln!(w, "Caused by:")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: FilePositioned> fmt::Display for StackPrinter<C> {
|
|
||||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.render(w)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ use abortable_parser::{Error, Peekable, Result};
|
|||||||
|
|
||||||
use self::precedence::op_expression;
|
use self::precedence::op_expression;
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::error::StackPrinter;
|
use crate::error::BuildError;
|
||||||
use crate::iter::OffsetStrIter;
|
use crate::iter::OffsetStrIter;
|
||||||
use crate::tokenizer::*;
|
use crate::tokenizer::*;
|
||||||
|
|
||||||
@ -857,7 +857,7 @@ fn statement(i: SliceIter<Token>) -> Result<SliceIter<Token>, Statement> {
|
|||||||
pub fn parse<'a>(
|
pub fn parse<'a>(
|
||||||
input: OffsetStrIter<'a>,
|
input: OffsetStrIter<'a>,
|
||||||
comment_map: Option<&mut CommentMap>,
|
comment_map: Option<&mut CommentMap>,
|
||||||
) -> std::result::Result<Vec<Statement>, String> {
|
) -> std::result::Result<Vec<Statement>, BuildError> {
|
||||||
match tokenize(input.clone(), comment_map) {
|
match tokenize(input.clone(), comment_map) {
|
||||||
Ok(tokenized) => {
|
Ok(tokenized) => {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
@ -871,20 +871,17 @@ pub fn parse<'a>(
|
|||||||
}
|
}
|
||||||
match statement(i.clone()) {
|
match statement(i.clone()) {
|
||||||
Result::Abort(e) => {
|
Result::Abort(e) => {
|
||||||
let ctx_err = StackPrinter { err: e };
|
return Err(BuildError::from(e));
|
||||||
return Err(format!("{}", ctx_err));
|
|
||||||
}
|
}
|
||||||
Result::Fail(e) => {
|
Result::Fail(e) => {
|
||||||
let ctx_err = StackPrinter { err: e };
|
return Err(BuildError::from(e));
|
||||||
return Err(format!("{}", ctx_err));
|
|
||||||
}
|
}
|
||||||
Result::Incomplete(_ei) => {
|
Result::Incomplete(_ei) => {
|
||||||
let err = abortable_parser::Error::new(
|
let err = abortable_parser::Error::new(
|
||||||
"Unexpected end of parse input",
|
"Unexpected end of parse input",
|
||||||
Box::new(i.clone()),
|
Box::new(i.clone()),
|
||||||
);
|
);
|
||||||
let ctx_err = StackPrinter { err: err };
|
return Err(BuildError::from(err));
|
||||||
return Err(format!("{}", ctx_err));
|
|
||||||
}
|
}
|
||||||
Result::Complete(rest, stmt) => {
|
Result::Complete(rest, stmt) => {
|
||||||
out.push(stmt);
|
out.push(stmt);
|
||||||
|
@ -260,11 +260,7 @@ fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> ParseResult<'a, Vec<Elemen
|
|||||||
// if we have successfully parsed an element and an operator then
|
// if we have successfully parsed an element and an operator then
|
||||||
// failing to parse a second expression is an abort since we know
|
// failing to parse a second expression is an abort since we know
|
||||||
// for sure now that the next expression is supposed to be there.
|
// for sure now that the next expression is supposed to be there.
|
||||||
let err = Error::caused_by(
|
let err = Error::new("Missing operand for binary expression", Box::new(_i));
|
||||||
"Missing operand for binary expression",
|
|
||||||
Box::new(e),
|
|
||||||
Box::new(_i),
|
|
||||||
);
|
|
||||||
return Result::Abort(err);
|
return Result::Abort(err);
|
||||||
}
|
}
|
||||||
return Result::Fail(e);
|
return Result::Fail(e);
|
||||||
|
@ -20,7 +20,7 @@ use abortable_parser::iter::SliceIter;
|
|||||||
use abortable_parser::{Error, Result};
|
use abortable_parser::{Error, Result};
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::error::StackPrinter;
|
use crate::error::BuildError;
|
||||||
use crate::iter::OffsetStrIter;
|
use crate::iter::OffsetStrIter;
|
||||||
|
|
||||||
pub type CommentGroup = Vec<Token>;
|
pub type CommentGroup = Vec<Token>;
|
||||||
@ -466,7 +466,7 @@ fn token<'a>(input: OffsetStrIter<'a>) -> Result<OffsetStrIter<'a>, Token> {
|
|||||||
pub fn tokenize<'a>(
|
pub fn tokenize<'a>(
|
||||||
input: OffsetStrIter<'a>,
|
input: OffsetStrIter<'a>,
|
||||||
mut comment_map: Option<&mut CommentMap>,
|
mut comment_map: Option<&mut CommentMap>,
|
||||||
) -> std::result::Result<Vec<Token>, String> {
|
) -> std::result::Result<Vec<Token>, BuildError> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
let mut i = input.clone();
|
let mut i = input.clone();
|
||||||
let mut comment_group = Vec::new();
|
let mut comment_group = Vec::new();
|
||||||
@ -477,28 +477,15 @@ pub fn tokenize<'a>(
|
|||||||
}
|
}
|
||||||
match token(i.clone()) {
|
match token(i.clone()) {
|
||||||
Result::Abort(e) => {
|
Result::Abort(e) => {
|
||||||
let err = abortable_parser::Error::caused_by(
|
return Err(BuildError::from(e));
|
||||||
"Invalid Token encountered",
|
|
||||||
Box::new(e),
|
|
||||||
Box::new(i.clone()),
|
|
||||||
);
|
|
||||||
let ctx_err = StackPrinter { err: err };
|
|
||||||
return Err(format!("{}", ctx_err));
|
|
||||||
}
|
}
|
||||||
Result::Fail(e) => {
|
Result::Fail(e) => {
|
||||||
let err = abortable_parser::Error::caused_by(
|
return Err(BuildError::from(e));
|
||||||
"Invalid Token encountered",
|
|
||||||
Box::new(e),
|
|
||||||
Box::new(i.clone()),
|
|
||||||
);
|
|
||||||
let ctx_err = StackPrinter { err: err };
|
|
||||||
return Err(format!("{}", ctx_err));
|
|
||||||
}
|
}
|
||||||
Result::Incomplete(_offset) => {
|
Result::Incomplete(_offset) => {
|
||||||
let err =
|
let err =
|
||||||
abortable_parser::Error::new("Invalid Token encountered", Box::new(i.clone()));
|
abortable_parser::Error::new("Invalid Token encountered", Box::new(i.clone()));
|
||||||
let ctx_err = StackPrinter { err: err };
|
return Err(BuildError::from(err));
|
||||||
return Err(format!("{}", ctx_err));
|
|
||||||
}
|
}
|
||||||
Result::Complete(rest, tok) => {
|
Result::Complete(rest, tok) => {
|
||||||
i = rest;
|
i = rest;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user