mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Some better error reporting.
This commit is contained in:
parent
fb5247e98f
commit
29aed2c997
13
example_errors/errors_test.ucg
Normal file
13
example_errors/errors_test.ucg
Normal 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 |=|;
|
@ -1,2 +0,0 @@
|
|||||||
assert |macro |;
|
|
||||||
assert |{ foo = hello world}|;
|
|
109
src/parse/mod.rs
109
src/parse/mod.rs
@ -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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user