FEATURE: Some better error reporting.

This commit is contained in:
Jeremy Wall 2018-08-30 21:00:28 -05:00
parent fb5247e98f
commit 29aed2c997
4 changed files with 93 additions and 45 deletions

View File

@ -0,0 +1,13 @@
assert |macro |;
assert |{ foo = hello world}|;
assert |{ foo = "hello world"|;
assert |{ = }|;
assert |let foo |;
assert |let |;
assert |import |;
assert |import foo |;
assert |out |;
assert |out "|;
assert |out json|;
assert |"|;
assert |=|;

View File

@ -1,2 +0,0 @@
assert |macro |;
assert |{ foo = hello world}|;

View File

@ -34,6 +34,26 @@ const ENABLE_TRACE: bool = true;
const ENABLE_TRACE: bool = false; const ENABLE_TRACE: bool = false;
type ParseResult<O> = Result<O, error::Error>; type ParseResult<O> = Result<O, error::Error>;
macro_rules! wrap_err {
($i:expr, $submac:ident, $msg:expr) => {
wrap_err!($i, call!($submac), $msg)
};
($i:expr, $submac:ident!( $($args:tt)* ), $msg:expr) => {{
let _i = $i.clone();
match $submac!(_i, $($args)*) {
IResult::Done(rest, mac) => IResult::Done(rest, mac),
IResult::Incomplete(i) => IResult::Incomplete(i),
IResult::Error(nom::ErrorKind::Custom(cause)) => {
let wrapper = error::Error::new_with_cause($msg, error::ErrorType::ParseError, cause);
IResult::Error(nom::ErrorKind::Custom(wrapper))
}
IResult::Error(e) => IResult::Error(e),
}
}};
}
macro_rules! trace_nom { macro_rules! trace_nom {
($i:expr, $rule:ident!( $($args:tt)* )) => { ($i:expr, $rule:ident!( $($args:tt)* )) => {
{ {
@ -143,7 +163,7 @@ macro_rules! alt_peek {
); );
(__inner $i:expr, $peekrule:ident => $($rest:tt)* ) => ( (__inner $i:expr, $peekrule:ident => $($rest:tt)* ) => (
alt_peek!(__inner $i, call!($peek) => $($rest)* ) alt_peek!(__inner $i, call!($peekrule) => $($rest)* )
); );
(__inner $i:expr, $peekrule:ident!( $($peekargs:tt)* ) => $parserule:ident!( $($parseargs:tt)* ) | $($rest:tt)* ) => ( (__inner $i:expr, $peekrule:ident!( $($peekargs:tt)* ) => $parserule:ident!( $($parseargs:tt)* ) | $($rest:tt)* ) => (
@ -273,7 +293,8 @@ named!(boolean_value<TokenIter, Value, error::Error>,
named!( named!(
field_value<TokenIter, (Token, Expression), error::Error>, field_value<TokenIter, (Token, Expression), error::Error>,
do_parse!( do_parse!(
field: alt!(match_type!(BAREWORD) | match_type!(STR)) >> field: wrap_err!(alt!(match_type!(BAREWORD) | match_type!(STR)),
"Field names must be a bareword or a string.") >>
punct!("=") >> punct!("=") >>
value: expression >> value: expression >>
(field, value) (field, value)
@ -343,20 +364,14 @@ named!(compound_value<TokenIter, Value, error::Error>,
) )
); );
named!(scalar_value<TokenIter, Value, error::Error>,
alt!(
trace_nom!(boolean_value) |
trace_nom!(empty_value) |
trace_nom!(number) |
trace_nom!(quoted_value)
)
);
named!(value<TokenIter, Value, error::Error>, named!(value<TokenIter, Value, error::Error>,
alt!( alt_peek!(
trace_nom!(selector_value) symbol_or_expression => trace_nom!(selector_value)
| trace_nom!(compound_value) | alt!(punct!("[") | punct!("{")) => trace_nom!(compound_value)
| trace_nom!(scalar_value) | match_type!(BOOLEAN) => trace_nom!(boolean_value)
| match_type!(EMPTY) => trace_nom!(empty_value)
| alt!(match_type!(DIGIT) | punct!(".")) => trace_nom!(number)
| trace_nom!(quoted_value)
) )
); );
@ -723,20 +738,40 @@ named!(list_op_expression<TokenIter, Expression, error::Error>,
) )
); );
fn unprefixed_expression(input: TokenIter) -> NomResult<Expression> {
let _input = input.clone();
let attempt = alt!(input,
trace_nom!(call_expression) |
trace_nom!(copy_expression) |
trace_nom!(format_expression));
match attempt {
IResult::Incomplete(i) => IResult::Incomplete(i),
IResult::Done(rest, expr) => IResult::Done(rest, expr),
IResult::Error(_) => trace_nom!(_input, simple_expression),
}
}
named!(non_op_expression<TokenIter, Expression, error::Error>, named!(non_op_expression<TokenIter, Expression, error::Error>,
alt!(trace_nom!(list_op_expression) | alt_peek!(
trace_nom!(macro_expression) | alt!(word!("map") | word!("filter")) => trace_nom!(list_op_expression) |
trace_nom!(format_expression) | word!("macro") => trace_nom!(macro_expression) |
trace_nom!(select_expression) | word!("select") => trace_nom!(select_expression) |
trace_nom!(grouped_expression) | punct!("(") => trace_nom!(grouped_expression) |
trace_nom!(call_expression) | trace_nom!(unprefixed_expression))
trace_nom!(copy_expression) |
trace_nom!(simple_expression))
); );
named!(expression<TokenIter, Expression, error::Error>, fn expression(input: TokenIter) -> NomResult<Expression> {
alt_complete!(trace_nom!(op_expression) | trace_nom!(non_op_expression)) let _input = input.clone();
); match trace_nom!(_input, op_expression) {
IResult::Incomplete(i) => IResult::Incomplete(i),
IResult::Error(_) => trace_nom!(input, non_op_expression),
IResult::Done(rest, expr) => IResult::Done(rest, expr),
}
}
//named!(expression<TokenIter, Expression, error::Error>,
// alt_complete!(trace_nom!(op_expression) | trace_nom!(non_op_expression))
//);
fn expression_to_statement(v: Expression) -> ParseResult<Statement> { fn expression_to_statement(v: Expression) -> ParseResult<Statement> {
Ok(Statement::Expression(v)) Ok(Statement::Expression(v))
@ -769,12 +804,12 @@ named!(let_stmt_body<TokenIter, Statement, error::Error>,
); );
named!(let_statement<TokenIter, Statement, error::Error>, named!(let_statement<TokenIter, Statement, error::Error>,
do_parse!( wrap_err!(do_parse!(
word!("let") >> word!("let") >>
pos: pos >> pos: pos >>
stmt: trace_nom!(let_stmt_body) >> stmt: trace_nom!(let_stmt_body) >>
(stmt) (stmt)
) ), "Invalid let statement")
); );
fn tuple_to_import(t: (Token, Token)) -> ParseResult<Statement> { fn tuple_to_import(t: (Token, Token)) -> ParseResult<Statement> {
@ -797,34 +832,34 @@ named!(import_stmt_body<TokenIter, Statement, error::Error>,
); );
named!(import_statement<TokenIter, Statement, error::Error>, named!(import_statement<TokenIter, Statement, error::Error>,
do_parse!( wrap_err!(do_parse!(
word!("import") >> word!("import") >>
// past this point we know this is supposed to be an import statement. // past this point we know this is supposed to be an import statement.
pos: pos >> pos: pos >>
stmt: trace_nom!(import_stmt_body) >> stmt: trace_nom!(import_stmt_body) >>
(stmt) (stmt)
) ), "Invalid import statement")
); );
named!(assert_statement<TokenIter, Statement, error::Error>, named!(assert_statement<TokenIter, Statement, error::Error>,
do_parse!( wrap_err!(do_parse!(
word!("assert") >> word!("assert") >>
pos: pos >> pos: pos >>
tok: match_type!(PIPEQUOTE) >> tok: match_type!(PIPEQUOTE) >>
punct!(";") >> punct!(";") >>
(Statement::Assert(tok.clone())) (Statement::Assert(tok.clone()))
) ), "Invalid assert statement")
); );
named!(out_statement<TokenIter, Statement, error::Error>, named!(out_statement<TokenIter, Statement, error::Error>,
do_parse!( wrap_err!(do_parse!(
word!("out") >> word!("out") >>
pos: pos >> pos: pos >>
typ: match_type!(BAREWORD) >> typ: match_type!(BAREWORD) >>
expr: expression >> expr: expression >>
punct!(";") >> punct!(";") >>
(Statement::Output(typ.clone(), expr.clone())) (Statement::Output(typ.clone(), expr.clone()))
) ), "Invalid out statement")
); );
//trace_macros!(true); //trace_macros!(true);
@ -889,10 +924,10 @@ pub fn parse(input: LocatedSpan<&str>) -> Result<Vec<Statement>, error::Error> {
return Ok(out); return Ok(out);
} }
Err(e) => { Err(e) => {
return Err(error::Error::new( return Err(error::Error::new_with_cause(
format!("Tokenization Error {:?}", e.1), format!("Tokenization Error"),
error::ErrorType::ParseError, error::ErrorType::ParseError,
e.0, e,
)); ));
} }
} }

View File

@ -392,7 +392,7 @@ named!(token( Span ) -> Token,
); );
/// Consumes an input Span and returns either a Vec<Token> or a nom::ErrorKind. /// Consumes an input Span and returns either a Vec<Token> or a nom::ErrorKind.
pub fn tokenize(input: Span) -> Result<Vec<Token>, (Position, nom::ErrorKind)> { pub fn tokenize(input: Span) -> Result<Vec<Token>, error::Error> {
let mut out = Vec::new(); let mut out = Vec::new();
let mut i = input; let mut i = input;
loop { loop {
@ -400,22 +400,24 @@ pub fn tokenize(input: Span) -> Result<Vec<Token>, (Position, nom::ErrorKind)> {
break; break;
} }
match token(i) { match token(i) {
nom::IResult::Error(e) => { nom::IResult::Error(_e) => {
return Err(( return Err(error::Error::new(
"Invalid Token encountered",
error::ErrorType::UnexpectedToken,
Position { Position {
line: i.line as usize, line: i.line as usize,
column: i.get_column() as usize, column: i.get_column() as usize,
}, },
e,
)); ));
} }
nom::IResult::Incomplete(_) => { nom::IResult::Incomplete(_) => {
return Err(( return Err(error::Error::new(
"Unexepcted end of Input",
error::ErrorType::UnexpectedToken,
Position { Position {
line: i.line as usize, line: i.line as usize,
column: i.get_column() as usize, column: i.get_column() as usize,
}, },
nom::ErrorKind::Complete,
)); ));
} }
nom::IResult::Done(rest, tok) => { nom::IResult::Done(rest, tok) => {