// Copyright 2017 Jeremy Wall // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! The Parsing stage of the ucg compiler. use std::borrow::Borrow; use std::str::FromStr; use nom; use nom::IResult; use nom::InputLength; use nom_locate::LocatedSpan; use ast::*; use error; use tokenizer::*; type NomResult<'a, O> = nom::IResult, O, error::Error>; #[cfg(feature = "tracing")] const ENABLE_TRACE: bool = true; #[cfg(not(feature = "tracing"))] const ENABLE_TRACE: bool = false; type ParseResult = Result; macro_rules! trace_nom { ($i:expr, $rule:ident!( $($args:tt)* )) => { { if ENABLE_TRACE { eprintln!("Entering Rule: {:?} {:?}", stringify!($rule), $i); } let result = $rule($i, $($args)* ); if ENABLE_TRACE { eprintln!("Exiting Rule: {:?}", stringify!($rule)); } result } }; ($i:expr, $rule:ident) => { { if ENABLE_TRACE { eprintln!("Entering Rule: {:?} {:?}", stringify!($rule), $i); } let result = call!($i, $rule); if ENABLE_TRACE { eprintln!("Exiting Rule: {:?}", stringify!($rule)); } result } }; } fn symbol_to_value(s: &Token) -> ParseResult { Ok(Value::Symbol(value_node!( s.fragment.to_string(), s.pos.clone() ))) } // symbol is a bare unquoted field. named!(symbol, match_type!(BAREWORD => symbol_to_value) ); fn str_to_value(s: &Token) -> ParseResult { Ok(Value::Str(value_node!( s.fragment.to_string(), s.pos.clone() ))) } // quoted_value is a quoted string. named!(quoted_value, match_type!(STR => str_to_value) ); // Helper function to make the return types work for down below. fn triple_to_number(v: (Option, Option, Option)) -> ParseResult { let (pref, mut pref_pos) = match v.0 { None => ("", Position::new(0, 0)), Some(ref bs) => (bs.fragment.borrow(), bs.pos.clone()), }; let has_dot = v.1.is_some(); if v.0.is_some() && !has_dot && v.2.is_none() { let i = match FromStr::from_str(pref) { Ok(i) => i, Err(_) => { return Err(error::Error::new( format!("Not an integer! {}", pref), error::ErrorType::UnexpectedToken, pref_pos, )) } }; return Ok(Value::Int(value_node!(i, pref_pos))); } if v.0.is_none() && has_dot { pref_pos = v.1.unwrap().pos; } let (maybepos, suf) = match v.2 { None => (None, "".to_string()), Some(bs) => (Some(bs.pos), bs.fragment), }; let to_parse = pref.to_string() + "." + &suf; // TODO(jwall): if there is an error we should report where that error occured. let f = match FromStr::from_str(&to_parse) { Ok(f) => f, Err(_) => { return Err(error::Error::new( format!("Not a float! {}", to_parse), error::ErrorType::UnexpectedToken, maybepos.unwrap(), )) } }; return Ok(Value::Float(value_node!(f, pref_pos))); } macro_rules! alt_peek { (__inner $i:expr, $peekrule:ident!( $($peekargs:tt)* ) => $parserule:ident | $($rest:tt)* ) => ( alt_peek!(__inner $i, $peekrule!($($peekargs)*) => call!($parserule) | $($rest)* ) ); (__inner $i:expr, $peekrule:ident => $($rest:tt)* ) => ( alt_peek!(__inner $i, call!($peek) => $($rest)* ) ); (__inner $i:expr, $peekrule:ident!( $($peekargs:tt)* ) => $parserule:ident!( $($parseargs:tt)* ) | $($rest:tt)* ) => ( { let _i = $i.clone(); let pre_res = peek!(_i, $peekrule!($($peekargs)*)); match pre_res { // if the peek was incomplete then it might still match so return incomplete. nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i), // If the peek was in error then try the next peek => parse pair. nom::IResult::Error(_) => { alt_peek!(__inner $i, $($rest)*) }, // If the peek was successful then return the result of the parserule // regardless of it's result. nom::IResult::Done(_i, _) => { $parserule!(_i, $($parseargs)*) }, } } ); // These are our no fallback termination cases. (__inner $i:expr, $peekrule:ident!( $($peekargs:tt)* ) => $parserule:ident, __end ) => ( alt_peek!(__inner $i, $peekrule!($($peekargs)*) => call!($parserule), __end ) ); (__inner $i:expr, $peekrule:ident!( $($peekargs:tt)* ) => $parserule:ident!( $($parseargs:tt)* ), __end ) => ( { let _i = $i.clone(); let pre_res = peek!(_i, $peekrule!($($peekargs)*)); match pre_res { // if the peek was incomplete then it might still match so return incomplete. nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i), // If the peek was in error then try the next peek => parse pair. nom::IResult::Error(_) => { alt_peek!(__inner $i, __end) }, // If the peek was successful then return the result of the parserule // regardless of it's result. nom::IResult::Done(_i, _) => { $parserule!(_i, $($parseargs)*) }, } } ); // These are our fallback termination cases. (__inner $i:expr, $fallback:ident, __end) => ( { let _i = $i.clone(); call!(_i, $fallback) } ); // In the case of a fallback rule with no peek we just return whatever // the fallback rule returns. (__inner $i:expr, $fallback:ident!( $($args:tt)* ), __end) => ( { let _i = $i.clone(); $fallback!(_i, $($args)*) } ); // This is our default termination case. // If there is no fallback then we return an Error. (__inner $i:expr, __end) => { // FIXME(jwall): We should do a better custom error here. nom::IResult::Error(error_position!(nom::ErrorKind::Alt,$i)) }; // alt_peek entry_point. ($i:expr, $($rest:tt)*) => { // We use __end to define the termination token the recursive rule should consume. alt_peek!(__inner $i, $($rest)*, __end) }; } // trace_macros!(true); // NOTE(jwall): HERE THERE BE DRAGONS. The order for these matters // alot. We need to process alternatives in order of decreasing // specificity. Unfortunately this means we are required to go in a // decreasing size order which messes with alt!'s completion logic. To // work around this we have to force Incomplete to be Error so that // alt! will try the next in the series instead of aborting. // // *IMPORTANT* // It also means this combinator is risky when used with partial // inputs. So handle with care. named!(number, map_res!(alt!( complete!(do_parse!( // 1.0 prefix: match_type!(DIGIT) >> has_dot: punct!(".") >> suffix: match_type!(DIGIT) >> (Some(prefix.clone()), Some(has_dot.clone()), Some(suffix.clone())) )) | complete!(do_parse!( // 1. prefix: match_type!(DIGIT) >> has_dot: punct!(".") >> (Some(prefix.clone()), Some(has_dot.clone()), None) )) | complete!(do_parse!( // .1 has_dot: punct!(".") >> suffix: match_type!(DIGIT) >> (None, Some(has_dot.clone()), Some(suffix.clone())) )) | do_parse!( // 1 prefix: match_type!(DIGIT) >> (Some(prefix.clone()), None, None) )), triple_to_number ) ); // trace_macros!(false); named!(boolean_value, do_parse!( b: match_type!(BOOLEAN) >> (Value::Boolean(Positioned{ val: b.fragment == "true", pos: b.pos, })) ) ); named!( field_value, do_parse!( field: match_type!(BAREWORD) >> punct!("=") >> value: expression >> (field, value) ) ); // Helper function to make the return types work for down below. fn vec_to_tuple(t: (Position, Option)) -> ParseResult { Ok(Value::Tuple(value_node!( t.1.unwrap_or(Vec::new()), t.0.line as usize, t.0.column as usize ))) } named!(field_list, separated_list!(punct!(","), field_value) ); named!( #[doc="Capture a tuple of named fields with values. {=,...}"], tuple, map_res!( do_parse!( pos: pos >> punct!("{") >> v: field_list >> opt_res!(punct!(",")) >> // nom's opt! macro doesn't preserve error types properly but this one does. punct!("}") >> (pos, Some(v)) ), vec_to_tuple ) ); fn tuple_to_list>(t: (Sp, Vec)) -> ParseResult { return Ok(Value::List(ListDef { elems: t.1, pos: t.0.into(), })); } named!(list_value, map_res!( do_parse!( start: punct!("[") >> elements: separated_list!(punct!(","), expression) >> opt_res!(punct!(",")) >> // nom's opt! macro doesn't preserve error types properly but this one does. punct!("]") >> (start.pos, elements) ), tuple_to_list ) ); named!(empty_value, do_parse!( pos: pos >> match_type!(EMPTY) >> (Value::Empty(pos)) ) ); named!(pub compound_value, alt_peek!( punct!("[") => trace_nom!(list_value) | punct!("{") => trace_nom!(tuple) ) ); named!(scalar_value, alt!( trace_nom!(boolean_value) | trace_nom!(empty_value) | trace_nom!(number) | trace_nom!(quoted_value) ) ); named!(pub value, alt!( trace_nom!(selector_value) | trace_nom!(compound_value) | trace_nom!(scalar_value) ) ); fn value_to_expression(v: Value) -> ParseResult { Ok(Expression::Simple(v)) } named!(simple_expression, map_res!( trace_nom!(value), value_to_expression ) ); fn tuple_to_binary_expression( tpl: (Position, BinaryExprType, Expression, Expression), ) -> ParseResult { Ok(Expression::Binary(BinaryOpDef { kind: tpl.1, left: Box::new(tpl.2), right: Box::new(tpl.3), pos: Position::new(tpl.0.line as usize, tpl.0.column as usize), })) } /// do_binary_expr implements precedence based parsing where the more tightly bound /// parsers are passed in as lowerrule parsers. We default to any non_op_expression /// as the most tightly bound expressions. macro_rules! do_binary_expr { ($i:expr, $oprule:ident!( $($args:tt)* )) => { do_binary_expr!($i, $oprule!($($args)*), non_op_expression) }; ($i:expr, $oprule:ident!( $($args:tt)* ), $lowerrule:ident) => { do_binary_expr!($i, $oprule!($($args)*), call!($lowerrule)) }; ($i:expr, $oprule:ident!( $($args:tt)* ), $lowerrule:ident!( $($lowerargs:tt)* )) => { map_res!($i, do_parse!( pos: pos >> left: $lowerrule!($($lowerargs)*) >> typ: $oprule!($($args)*) >> right: $lowerrule!($($lowerargs)*) >> (pos, typ, left, right) ), tuple_to_binary_expression ) }; } // Matches an operator token to a BinaryExprType named!(math_op_type, alt!( do_parse!(punct!("+") >> (BinaryExprType::Add)) | do_parse!(punct!("-") >> (BinaryExprType::Sub)) | do_parse!(punct!("*") >> (BinaryExprType::Mul)) | do_parse!(punct!("/") >> (BinaryExprType::Div)) ) ); // trace_macros!(true); named!(sum_expression, do_binary_expr!( alt_peek!( punct!("+") => math_op_type | punct!("-") => math_op_type), alt!(trace_nom!(product_expression) | trace_nom!(simple_expression) | trace_nom!(grouped_expression))) ); named!(product_expression, do_binary_expr!( alt_peek!( punct!("*") => math_op_type | punct!("/") => math_op_type) ) ); named!(math_expression, alt!(trace_nom!(sum_expression) | trace_nom!(product_expression)) ); // TODO(jwall): Change comparison operators to use the do_binary_expr! with precedence? fn tuple_to_compare_expression( tpl: (Position, CompareType, Expression, Expression), ) -> ParseResult { Ok(Expression::Compare(ComparisonDef { kind: tpl.1, left: Box::new(tpl.2), right: Box::new(tpl.3), pos: Position::new(tpl.0.line as usize, tpl.0.column as usize), })) } named!(compare_op_type, alt!( do_parse!(punct!("==") >> (CompareType::Equal)) | do_parse!(punct!("!=") >> (CompareType::NotEqual)) | do_parse!(punct!("<=") >> (CompareType::LTEqual)) | do_parse!(punct!(">=") >> (CompareType::GTEqual)) | do_parse!(punct!("<") >> (CompareType::LT)) | do_parse!(punct!(">") >> (CompareType::GT)) ) ); named!(compare_expression, map_res!( do_parse!( pos: pos >> left: alt!(trace_nom!(math_expression) | trace_nom!(non_op_expression)) >> typ: compare_op_type >> right: alt!(trace_nom!(math_expression) | trace_nom!(non_op_expression)) >> (pos, typ, left, right) ), tuple_to_compare_expression ) ); // FIXME(jwall): This is really *really* slow. named!(op_expression, alt!(trace_nom!(math_expression) | trace_nom!(compare_expression)) ); fn expression_to_grouped_expression(e: Expression) -> ParseResult { Ok(Expression::Grouped(Box::new(e))) } named!(grouped_expression, map_res!( preceded!(punct!("("), terminated!(trace_nom!(expression), punct!(")"))), expression_to_grouped_expression ) ); fn symbol_or_expression(input: TokenIter) -> NomResult { let scalar_head = do_parse!(input, sym: alt!(symbol | compound_value) >> (sym)); match scalar_head { IResult::Incomplete(i) => IResult::Incomplete(i), IResult::Error(_) => grouped_expression(input), IResult::Done(rest, val) => { let res = peek!(rest.clone(), punct!(".")); match val { Value::Tuple(_) => { if res.is_done() { IResult::Done(rest, Expression::Simple(val)) } else { return IResult::Error(nom::ErrorKind::Custom(error::Error::new( "Expected (.) but no dot found".to_string(), error::ErrorType::IncompleteParsing, val.pos().clone(), ))); } } Value::List(_) => { if res.is_done() { IResult::Done(rest, Expression::Simple(val)) } else { return IResult::Error(nom::ErrorKind::Custom(error::Error::new( "Expected (.) but no dot found".to_string(), error::ErrorType::IncompleteParsing, val.pos().clone(), ))); } } _ => IResult::Done(rest, Expression::Simple(val)), } } } } fn selector_list(input: TokenIter) -> NomResult { let (rest, head) = match symbol_or_expression(input) { IResult::Done(rest, val) => (rest, val), IResult::Error(e) => { return IResult::Error(e); } IResult::Incomplete(i) => { return IResult::Incomplete(i); } }; let (rest, is_dot) = match punct!(rest, ".") { IResult::Done(rest, tok) => (rest, Some(tok)), IResult::Incomplete(i) => { return IResult::Incomplete(i); } IResult::Error(_) => (rest, None), }; let (rest, list) = if is_dot.is_some() { let (rest, list) = match separated_list!( rest, punct!("."), alt!(match_type!(BAREWORD) | match_type!(DIGIT)) ) { IResult::Done(rest, val) => (rest, val), IResult::Incomplete(i) => { return IResult::Incomplete(i); } IResult::Error(e) => { return IResult::Error(e); } }; if list.is_empty() { return IResult::Error(nom::ErrorKind::Custom(error::Error::new( "(.) with no selector fields after".to_string(), error::ErrorType::IncompleteParsing, is_dot.unwrap().pos, ))); } else { (rest, Some(list)) } } else { (rest, None) }; let sel_list = SelectorList { head: Box::new(head), tail: list, }; return IResult::Done(rest, sel_list); } fn tuple_to_copy(t: (SelectorDef, FieldList)) -> ParseResult { let pos = t.0.pos.clone(); Ok(Expression::Copy(CopyDef { selector: t.0, fields: t.1, pos: pos, })) } named!(copy_expression, map_res!( do_parse!( pos: pos >> selector: trace_nom!(selector_list) >> punct!("{") >> fields: trace_nom!(field_list) >> opt_res!(punct!(",")) >> // noms opt! macro does not preserve error types properly but this one does. punct!("}") >> (SelectorDef::new(selector, pos.line, pos.column as usize), fields) ), tuple_to_copy ) ); fn tuple_to_macro(mut t: (Position, Vec, Value)) -> ParseResult { match t.2 { Value::Tuple(v) => Ok(Expression::Macro(MacroDef { argdefs: t.1 .drain(0..) .map(|s| Positioned { pos: s.pos().clone(), val: s.to_string(), }) .collect(), fields: v.val, pos: t.0, })), val => Err(error::Error::new( format!("Expected Tuple Got {:?}", val), error::ErrorType::UnexpectedToken, t.0, )), } } named!(arglist, error::Error>, separated_list!(punct!(","), symbol)); named!(macro_expression, map_res!( do_parse!( pos: pos >> word!("macro") >> punct!("(") >> arglist: trace_nom!(arglist) >> punct!(")") >> punct!("=>") >> map: trace_nom!(tuple) >> (pos, arglist, map) ), tuple_to_macro ) ); fn tuple_to_select(t: (Position, Expression, Expression, Value)) -> ParseResult { match t.3 { Value::Tuple(v) => Ok(Expression::Select(SelectDef { val: Box::new(t.1), default: Box::new(t.2), tuple: v.val, pos: t.0, })), val => Err(error::Error::new( format!("Expected Tuple Got {:?}", val), error::ErrorType::UnexpectedToken, t.0, )), } } named!(select_expression, map_res!( do_parse!( start: word!("select") >> val: terminated!(trace_nom!(expression), punct!(",")) >> default: terminated!(trace_nom!(expression), punct!(",")) >> map: trace_nom!(tuple) >> (start.pos.clone(), val, default, map) ), tuple_to_select ) ); fn tuple_to_format(t: (Token, Vec)) -> ParseResult { Ok(Expression::Format(FormatDef { template: t.0.fragment.to_string(), args: t.1, pos: t.0.pos, })) } named!(format_expression, map_res!( do_parse!( tmpl: match_type!(STR) >> punct!("%") >> punct!("(") >> args: separated_list!(punct!(","), trace_nom!(expression)) >> punct!(")") >> (tmpl, args) ), tuple_to_format ) ); fn tuple_to_call(t: (Position, Value, Vec)) -> ParseResult { if let Value::Selector(def) = t.1 { Ok(Expression::Call(CallDef { macroref: def, arglist: t.2, pos: Position::new(t.0.line as usize, t.0.column as usize), })) } else { Err(error::Error::new( format!("Expected Selector Got {:?}", t.0), error::ErrorType::UnexpectedToken, Position::new(t.0.line as usize, t.0.column as usize), )) } } fn vec_to_selector_value(t: (Position, SelectorList)) -> ParseResult { Ok(Value::Selector(SelectorDef::new( t.1, t.0.line as usize, t.0.column as usize, ))) } named!(selector_value, map_res!( do_parse!( sl: trace_nom!(selector_list) >> (sl.head.pos().clone(), sl) ), vec_to_selector_value ) ); named!(call_expression, map_res!( do_parse!( macroname: trace_nom!(selector_value) >> punct!("(") >> args: separated_list!(punct!(","), trace_nom!(expression)) >> punct!(")") >> (macroname.pos().clone(), macroname, args) ), tuple_to_call ) ); fn symbol_or_list(input: TokenIter) -> NomResult { let sym = do_parse!(input, sym: symbol >> (sym)); match sym { IResult::Incomplete(i) => { return IResult::Incomplete(i); } IResult::Error(_) => match list_value(input) { IResult::Incomplete(i) => { return IResult::Incomplete(i); } IResult::Error(e) => { return IResult::Error(e); } IResult::Done(i, val) => { return IResult::Done(i, val); } }, IResult::Done(rest, val) => { return IResult::Done(rest, val); } } } fn tuple_to_list_op(tpl: (Position, Token, Value, Value)) -> ParseResult { let pos = tpl.0; let t = if &tpl.1.fragment == "map" { ListOpType::Map } else if &tpl.1.fragment == "filter" { ListOpType::Filter } else { return Err(error::Error::new( format!( "Expected one of 'map' or 'filter' but got '{}'", tpl.1.fragment ), error::ErrorType::UnexpectedToken, pos, )); }; let macroname = tpl.2; let list = tpl.3; if let Value::Selector(mut def) = macroname { // First of all we need to assert that this is a selector of at least // two sections. let fieldname: String = match &mut def.sel.tail { &mut None => { return Err(error::Error::new( format!("Missing a result field for the macro"), error::ErrorType::IncompleteParsing, pos, )); } &mut Some(ref mut tl) => { if tl.len() < 1 { return Err(error::Error::new( format!("Missing a result field for the macro"), error::ErrorType::IncompleteParsing, def.pos.clone(), )); } let fname = tl.pop(); fname.unwrap().fragment } }; if let Value::List(ldef) = list { return Ok(Expression::ListOp(ListOpDef { typ: t, mac: def, field: fieldname, target: ldef, pos: pos, })); } return Err(error::Error::new( format!("Expected a list but got {}", list.type_name()), error::ErrorType::UnexpectedToken, pos, )); } return Err(error::Error::new( format!("Expected a selector but got {}", macroname.type_name()), error::ErrorType::UnexpectedToken, pos, )); } named!(list_op_expression, map_res!( do_parse!( pos: pos >> optype: alt!(word!("map") | word!("filter")) >> macroname: trace_nom!(selector_value) >> list: trace_nom!(symbol_or_list) >> (pos, optype, macroname, list) ), tuple_to_list_op ) ); named!(pub non_op_expression, alt!(trace_nom!(list_op_expression) | trace_nom!(macro_expression) | trace_nom!(format_expression) | trace_nom!(select_expression) | trace_nom!(grouped_expression) | trace_nom!(call_expression) | trace_nom!(copy_expression) | trace_nom!(simple_expression)) ); // TODO(jwall): Because we have to parse an op_expression before a non_op_expression // this parser is really slow. The reason is that the op_expression is unable to fail // quickly enough and wastes a lot of parsing time before it realizes that this is not // an operator expression. Fixing this probably means hand rolling this parsing // function so we can identify early whether this is an op_expression or not. named!(pub expression, alt_complete!(trace_nom!(op_expression) | trace_nom!(non_op_expression)) ); fn expression_to_statement(v: Expression) -> ParseResult { Ok(Statement::Expression(v)) } named!(pub expression_statement, map_res!( terminated!(trace_nom!(expression), punct!(";")), expression_to_statement ) ); fn tuple_to_let(t: (Token, Expression)) -> ParseResult { Ok(Statement::Let(LetDef { name: t.0, value: t.1, })) } named!(let_stmt_body, map_res!( do_parse!( name: match_type!(BAREWORD) >> punct!("=") >> val: trace_nom!(expression) >> punct!(";") >> (name, val)), tuple_to_let ) ); named!(let_statement, do_parse!( word!("let") >> pos: pos >> stmt: add_return_error!( nom::ErrorKind::Custom( error::Error::new( "Invalid syntax for let binding", error::ErrorType::ParseError, pos)), trace_nom!(let_stmt_body)) >> (stmt) ) ); fn tuple_to_import(t: (Token, Token)) -> ParseResult { Ok(Statement::Import(ImportDef { path: t.0, name: t.1, })) } named!(import_stmt_body, map_res!( do_parse!( path: match_type!(STR) >> word!("as") >> name: match_type!(BAREWORD) >> punct!(";") >> (path, name)), tuple_to_import ) ); named!(import_statement, do_parse!( word!("import") >> // past this point we know this is supposed to be an import statement. pos: pos >> stmt: add_return_error!( nom::ErrorKind::Custom( error::Error::new( "Invalid syntax for import", error::ErrorType::ParseError, pos)), trace_nom!(import_stmt_body)) >> (stmt) ) ); named!(assert_statement, do_parse!( word!("assert") >> pos: pos >> tok: add_return_error!( nom::ErrorKind::Custom( error::Error::new( "Invalid syntax for assert", error::ErrorType::ParseError, pos)), match_type!(STR)) >> punct!(";") >> (Statement::Assert(tok.clone())) ) ); //trace_macros!(true); fn statement(i: TokenIter) -> nom::IResult { return alt_peek!(i, word!("assert") => trace_nom!(assert_statement) | word!("import") => trace_nom!(import_statement) | word!("let") => trace_nom!(let_statement) | trace_nom!(expression_statement) ); } //trace_macros!(false); /// Parses a LocatedSpan into a list of Statements or an error::Error. pub fn parse(input: LocatedSpan<&str>) -> Result, error::Error> { match tokenize(input) { Ok(tokenized) => { let mut out = Vec::new(); let mut i_ = TokenIter { source: tokenized.as_slice(), }; loop { let i = i_.clone(); if i[0].typ == TokenType::END { break; } match statement(i) { IResult::Error(nom::ErrorKind::Custom(e)) => { return Err(e); } IResult::Error(e) => { return Err(error::Error::new_with_errorkind( "Statement Parse error", error::ErrorType::ParseError, Position { line: i_[0].pos.line, column: i_[0].pos.column, }, e, )); } IResult::Incomplete(ei) => { return Err(error::Error::new( format!("Unexpected end of parsing input: {:?}", ei), error::ErrorType::IncompleteParsing, Position { line: i_[0].pos.line, column: i_[0].pos.column, }, )); } IResult::Done(rest, stmt) => { out.push(stmt); i_ = rest; if i_.input_len() == 0 { break; } } } } return Ok(out); } Err(e) => { return Err(error::Error::new( format!("Tokenization Error {:?}", e.1), error::ErrorType::ParseError, e.0, )); } } } #[cfg(test)] mod test;