diff --git a/rusty_parser/src/built_ins/line_input.rs b/rusty_parser/src/built_ins/line_input.rs index 01ab9c46..a0c0f7e5 100644 --- a/rusty_parser/src/built_ins/line_input.rs +++ b/rusty_parser/src/built_ins/line_input.rs @@ -3,17 +3,15 @@ use rusty_pc::*; use crate::built_ins::common::{encode_opt_file_handle_arg, opt_file_handle_comma_p}; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{BuiltInSub, ParserError, *}; // LINE INPUT variable$ // LINE INPUT #file-number%, variable$ pub fn parse() -> impl Parser { - seq4( + seq3( keyword_pair(Keyword::Line, Keyword::Input), - whitespace_ignoring(), - opt_file_handle_comma_p(), + demand_lead_ws(opt_file_handle_comma_p()), expression_pos_p().or_expected("#file-number or variable"), - |_, _, opt_file_number_pos, variable| { + |_, opt_file_number_pos, variable| { let mut args: Expressions = encode_opt_file_handle_arg(opt_file_number_pos); // add the LINE INPUT variable args.push(variable); diff --git a/rusty_parser/src/built_ins/open.rs b/rusty_parser/src/built_ins/open.rs index 8ebff331..44219716 100644 --- a/rusty_parser/src/built_ins/open.rs +++ b/rusty_parser/src/built_ins/open.rs @@ -1,10 +1,9 @@ use rusty_common::*; -use rusty_pc::and::IgnoringBothCombiner; use rusty_pc::*; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::{equal_sign_ws, whitespace_ignoring}; +use crate::tokens::equal_sign_ws; use crate::{BuiltInSub, ParserError, *}; pub fn parse() -> impl Parser { seq6( @@ -65,7 +64,7 @@ fn parse_file_number_p() -> impl Parser impl Parser { seq3( - whitespace_ignoring().and(keyword_ignoring(Keyword::Len), IgnoringBothCombiner), + lead_ws(keyword_ignoring(Keyword::Len)), equal_sign_ws(), expression_pos_p().or_expected("expression after LEN ="), |_, _, e| e, diff --git a/rusty_parser/src/core/declaration.rs b/rusty_parser/src/core/declaration.rs index 0009330e..998611e0 100644 --- a/rusty_parser/src/core/declaration.rs +++ b/rusty_parser/src/core/declaration.rs @@ -1,11 +1,9 @@ -use rusty_pc::and::opt_and_keep_right; use rusty_pc::*; use crate::core::name::{bare_name_p, name_p}; use crate::core::param_name::parameter_pos_p; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{ParserError, *}; // Declaration ::= DECLARE(FunctionDeclaration|SubDeclaration) @@ -53,12 +51,7 @@ pub fn sub_declaration_p() // result ::= "" | "(" ")" | "(" parameter (,parameter)* ")" fn declaration_parameters_p() -> impl Parser { - // TODO remove the need for the double .or_default() - opt_and_keep_right( - whitespace_ignoring(), - in_parenthesis(csv(parameter_pos_p()).or_default()), - ) - .or_default() + lead_opt_ws(in_parenthesis(csv(parameter_pos_p()).or_default())).or_default() } #[cfg(test)] diff --git a/rusty_parser/src/core/def_type.rs b/rusty_parser/src/core/def_type.rs index 1c207150..7d427207 100644 --- a/rusty_parser/src/core/def_type.rs +++ b/rusty_parser/src/core/def_type.rs @@ -3,7 +3,7 @@ use rusty_pc::*; use crate::error::ParserError; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::{TokenType, any_token_of, minus_sign, whitespace_ignoring}; +use crate::tokens::{TokenType, any_token_of, minus_sign}; use crate::{Keyword, LetterRange, TypeQualifier}; /// Represents a definition of default type, such as DEFINT A-Z. @@ -34,11 +34,10 @@ impl DefType { // Letter ::= [a-zA-Z] pub fn def_type_p() -> impl Parser { - seq3( + seq2( def_keyword_p(), - whitespace_ignoring(), - letter_ranges(), - |l, _, r| DefType::new(l, r), + demand_lead_ws(letter_ranges()), + DefType::new, ) } diff --git a/rusty_parser/src/core/do_loop.rs b/rusty_parser/src/core/do_loop.rs index 516012c7..d8b307b7 100644 --- a/rusty_parser/src/core/do_loop.rs +++ b/rusty_parser/src/core/do_loop.rs @@ -4,7 +4,6 @@ use crate::core::expression::ws_expr_pos_p; use crate::core::statements::zero_or_more_statements; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{ParserError, *}; pub fn do_loop_p() -> impl Parser { @@ -19,7 +18,7 @@ pub fn do_loop_p() -> impl Parser impl Parser { seq4( - whitespace_ignoring().and_keep_right(keyword_of!(Keyword::Until, Keyword::While)), + lead_ws(keyword_of!(Keyword::Until, Keyword::While)), ws_expr_pos_p().or_expected("expression"), zero_or_more_statements!(Keyword::Loop), keyword(Keyword::Loop), diff --git a/rusty_parser/src/core/expression.rs b/rusty_parser/src/core/expression.rs index 4ddecad8..f9f417cf 100644 --- a/rusty_parser/src/core/expression.rs +++ b/rusty_parser/src/core/expression.rs @@ -554,7 +554,6 @@ fn eager_expression_pos_p() -> impl Parser impl Parser { - // TODO this is difficult to understand - opt_and_tuple( - // read integer digits optionally (might start with . e.g. `.123`) - digits(), + // read integer digits optionally (might start with . e.g. `.123`) + digits() + .to_option() // read dot and demand digits after decimal point // if dot is missing, the parser returns an empty result // the "deal breaker" is therefore the dot - dot().and_keep_right(digits().to_fatal()), - ) - // and parse optionally a type qualifier such as `#` - .and_tuple(pound().to_option()) - // done parsing, flat map everything - .and_then(|((opt_integer_digits, frac_digits), opt_pound)| { - let left = opt_integer_digits - .map(|token| token.to_string()) - .unwrap_or_else(|| "0".to_owned()); - let s = format!("{}.{}", left, frac_digits.as_str()); - if opt_pound.is_some() { - match s.parse::() { - Ok(f) => Ok(Expression::DoubleLiteral(f)), - Err(err) => Err(err.into()), - } - } else { - match s.parse::() { - Ok(f) => Ok(Expression::SingleLiteral(f)), - Err(err) => Err(err.into()), + .and_keep_left(dot()) + // demand digits after decimal point + .and_tuple(digits().to_fatal()) + // and parse optionally a type qualifier such as `#` + .and_tuple(pound().to_option()) + // done parsing, flat map everything + .and_then(|((opt_integer_digits, frac_digits), opt_pound)| { + let left = opt_integer_digits + .map(|token| token.to_string()) + .unwrap_or_else(|| "0".to_owned()); + let s = format!("{}.{}", left, frac_digits.as_str()); + if opt_pound.is_some() { + match s.parse::() { + Ok(f) => Ok(Expression::DoubleLiteral(f)), + Err(err) => Err(err.into()), + } + } else { + match s.parse::() { + Ok(f) => Ok(Expression::SingleLiteral(f)), + Err(err) => Err(err.into()), + } } - } - }) - .with_pos() + }) + .with_pos() } } @@ -998,7 +997,7 @@ mod built_in_function_call { mod binary_expression { use rusty_common::Positioned; - use rusty_pc::and::{TupleCombiner, opt_and_keep_right}; + use rusty_pc::and::TupleCombiner; use rusty_pc::*; use super::{ @@ -1006,8 +1005,8 @@ mod binary_expression { }; use crate::error::ParserError; use crate::input::StringView; - use crate::pc_specific::{OrExpected, WithPos}; - use crate::tokens::{TokenType, any_token, whitespace_ignoring}; + use crate::pc_specific::{OrExpected, WithPos, lead_opt_ws, lead_ws}; + use crate::tokens::{TokenType, any_token}; use crate::*; // result ::= @@ -1078,14 +1077,9 @@ mod binary_expression { -> impl Parser, Error = ParserError> { IifParser::new( // no whitespace needed - opt_and_keep_right(whitespace_ignoring(), operator_p()), + lead_opt_ws(operator_p()), // whitespace needed - whitespace_ignoring() - .and_keep_right(operator_p()) - .or(opt_and_keep_right( - whitespace_ignoring(), - symbol_operator_p(), - )), + lead_ws(operator_p()).or(lead_opt_ws(symbol_operator_p())), ) } @@ -1201,7 +1195,7 @@ pub mod file_handle { use crate::error::ParserError; use crate::input::StringView; use crate::pc_specific::*; - use crate::tokens::{TokenType, any_token_of, pound, whitespace_ignoring}; + use crate::tokens::{TokenType, any_token_of, pound}; use crate::*; pub fn file_handle_p() @@ -1230,7 +1224,7 @@ pub mod file_handle { } fn ws_file_handle() -> impl Parser { - whitespace_ignoring().and_keep_right(file_handle_as_expression_pos_p()) + lead_ws(file_handle_as_expression_pos_p()) } } @@ -1239,8 +1233,8 @@ pub mod guard { use crate::ParserError; use crate::input::StringView; - use crate::pc_specific::WithExpected; - use crate::tokens::{any_symbol_of, any_token_of, whitespace_ignoring}; + use crate::pc_specific::{WithExpected, whitespace_ignoring}; + use crate::tokens::{any_symbol_of, any_token_of}; /// `result ::= " " | "("` /// diff --git a/rusty_parser/src/core/for_loop.rs b/rusty_parser/src/core/for_loop.rs index 38cb866a..36ce0928 100644 --- a/rusty_parser/src/core/for_loop.rs +++ b/rusty_parser/src/core/for_loop.rs @@ -6,7 +6,7 @@ use crate::core::statements::zero_or_more_statements; use crate::error::ParserError; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::{equal_sign_ws, whitespace_ignoring}; +use crate::tokens::equal_sign_ws; use crate::*; // FOR I = 0 TO 5 STEP 1 @@ -65,7 +65,7 @@ fn parse_for_p() } fn next_counter_p() -> impl Parser { - whitespace_ignoring().and_keep_right(property::parser()) + lead_ws(property::parser()) } #[cfg(test)] diff --git a/rusty_parser/src/core/global_statement.rs b/rusty_parser/src/core/global_statement.rs index 3bb48720..9d46f05d 100644 --- a/rusty_parser/src/core/global_statement.rs +++ b/rusty_parser/src/core/global_statement.rs @@ -159,7 +159,7 @@ fn main_program() -> impl Parser impl Parser { - next_statement().padded_by_ws().zero_or_more() + padded_by_ws(next_statement()).zero_or_more() } fn next_statement() -> impl Parser { diff --git a/rusty_parser/src/core/go_sub.rs b/rusty_parser/src/core/go_sub.rs index 6c6296ea..8498375c 100644 --- a/rusty_parser/src/core/go_sub.rs +++ b/rusty_parser/src/core/go_sub.rs @@ -3,7 +3,6 @@ use rusty_pc::*; use crate::core::name::bare_name_p; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{Keyword, ParserError, Statement}; pub fn statement_go_sub_p() -> impl Parser { @@ -13,13 +12,9 @@ pub fn statement_go_sub_p() -> impl Parser impl Parser { - seq2( - keyword(Keyword::Return), - whitespace_ignoring() - .and_keep_right(bare_name_p()) - .to_option(), - |_, name| Statement::Return(name), - ) + keyword(Keyword::Return) + .and_keep_right(lead_ws(bare_name_p()).to_option()) + .map(Statement::Return) } #[cfg(test)] diff --git a/rusty_parser/src/core/if_block.rs b/rusty_parser/src/core/if_block.rs index 2eb88abe..5cb52844 100644 --- a/rusty_parser/src/core/if_block.rs +++ b/rusty_parser/src/core/if_block.rs @@ -1,4 +1,3 @@ -use rusty_pc::and::IgnoringBothCombiner; use rusty_pc::*; use crate::core::comment::comment_p; @@ -9,7 +8,6 @@ use crate::core::single_line_statements::{ use crate::core::statements::zero_or_more_statements; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{ParserError, *}; pub fn if_block_p() -> impl Parser { @@ -58,14 +56,11 @@ fn single_line_if_else_p() -> impl Parser< } fn single_line_comment_p() -> impl Parser { - whitespace_ignoring() - .to_option() - .and(comment_p().with_pos(), |_, s| vec![s]) + lead_opt_ws(comment_p().with_pos()).map(|s| vec![s]) } fn single_line_else_p() -> impl Parser { - whitespace_ignoring() - .and(keyword(Keyword::Else), IgnoringBothCombiner) + lead_ws(keyword(Keyword::Else)) .and_keep_right(single_line_statements_p().or_expected("Statements for single line ELSE")) } diff --git a/rusty_parser/src/core/implementation.rs b/rusty_parser/src/core/implementation.rs index 3a1c25c6..26cf8393 100644 --- a/rusty_parser/src/core/implementation.rs +++ b/rusty_parser/src/core/implementation.rs @@ -1,12 +1,10 @@ -use rusty_pc::and::IgnoringBothCombiner; use rusty_pc::*; use crate::core::declaration::{function_declaration_p, sub_declaration_p}; use crate::core::statements::zero_or_more_statements; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; -use crate::{ParserError, *}; +use crate::{FunctionImplementation, GlobalStatement, Keyword, ParserError, SubImplementation}; // FunctionImplementation ::= eol eol ENDFUNCTION // SubImplementation ::= eol eol ENDSUB @@ -60,9 +58,7 @@ where } fn ws_static() -> impl Parser { - whitespace_ignoring() - .to_option() - .and(keyword(Keyword::Static), IgnoringBothCombiner) + lead_opt_ws(keyword_ignoring(Keyword::Static)) } #[cfg(test)] @@ -70,8 +66,10 @@ mod tests { use rusty_common::*; use super::*; - use crate::assert_parser_err; use crate::test_utils::*; + use crate::{ + Expression, ExpressionType, Operator, ParamType, Parameter, Statement, assert_parser_err, parse + }; #[test] fn test_function_implementation() { diff --git a/rusty_parser/src/core/on_error.rs b/rusty_parser/src/core/on_error.rs index 7383080d..b7d15c07 100644 --- a/rusty_parser/src/core/on_error.rs +++ b/rusty_parser/src/core/on_error.rs @@ -6,18 +6,15 @@ use crate::core::name::bare_name_p; use crate::error::ParserError; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{Expression, Keyword, OnErrorOption, Statement}; pub fn statement_on_error_go_to_p() -> impl Parser { - seq2( - keyword_pair(Keyword::On, Keyword::Error), - whitespace_ignoring(), - |_, _| (), - ) - .and_keep_right(next().or(goto()).or_expected("GOTO or RESUME")) - .map(Statement::OnError) + keyword_pair(Keyword::On, Keyword::Error) + .and_keep_right(demand_lead_ws( + next().or(goto()).or_expected("GOTO or RESUME"), + )) + .map(Statement::OnError) } fn next() -> impl Parser { diff --git a/rusty_parser/src/core/opt_second_expression.rs b/rusty_parser/src/core/opt_second_expression.rs index e6bdd973..cc3fb33d 100644 --- a/rusty_parser/src/core/opt_second_expression.rs +++ b/rusty_parser/src/core/opt_second_expression.rs @@ -4,8 +4,7 @@ use rusty_pc::{IifParser, Parser, ParserErrorTrait}; use crate::core::expression::ws_expr_pos_p; use crate::error::ParserError; use crate::input::StringView; -use crate::pc_specific::keyword; -use crate::tokens::whitespace_ignoring; +use crate::pc_specific::{keyword, whitespace_ignoring}; use crate::{ExpressionPos, Keyword}; /// Parses an optional second expression that follows the first expression diff --git a/rusty_parser/src/core/print.rs b/rusty_parser/src/core/print.rs index 8c6dc39b..0e36c472 100644 --- a/rusty_parser/src/core/print.rs +++ b/rusty_parser/src/core/print.rs @@ -9,7 +9,7 @@ use crate::error::ParserError; use crate::input::StringView; use crate::pc_specific::*; use crate::tokens::{ - TokenMatcher, any_symbol_of, any_symbol_of_ws, any_token_of, comma_ws, semicolon_ws, whitespace_ignoring + TokenMatcher, any_symbol_of, any_symbol_of_ws, any_token_of, comma_ws, semicolon_ws }; use crate::*; diff --git a/rusty_parser/src/core/resume.rs b/rusty_parser/src/core/resume.rs index 976b501b..0b5c9ba8 100644 --- a/rusty_parser/src/core/resume.rs +++ b/rusty_parser/src/core/resume.rs @@ -4,7 +4,6 @@ use crate::core::name::bare_name_p; use crate::core::statement_separator::peek_eof_or_statement_separator; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{Keyword, ParserError, ResumeOption, Statement}; // RESUME @@ -30,11 +29,11 @@ fn blank_resume() -> impl Parser impl Parser { - whitespace_ignoring().and(keyword_ignoring(Keyword::Next), |_, _| ResumeOption::Next) + lead_ws(keyword_ignoring(Keyword::Next)).map(|_| ResumeOption::Next) } fn resume_label() -> impl Parser { - whitespace_ignoring().and(bare_name_p(), |_, r| ResumeOption::Label(r)) + lead_ws(bare_name_p()).map(ResumeOption::Label) } #[cfg(test)] diff --git a/rusty_parser/src/core/select_case.rs b/rusty_parser/src/core/select_case.rs index 416bf7ca..e409362a 100644 --- a/rusty_parser/src/core/select_case.rs +++ b/rusty_parser/src/core/select_case.rs @@ -1,4 +1,3 @@ -use rusty_pc::and::opt_and_keep_right; use rusty_pc::*; use crate::core::expression::ws_expr_pos_p; @@ -6,7 +5,6 @@ use crate::core::statement_separator::comments_in_between_keywords; use crate::core::statements::zero_or_more_statements; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{ParserError, *}; // SELECT CASE expr ' comment @@ -88,17 +86,14 @@ fn case_block() -> impl Parser impl Parser { - opt_and_keep_right( - whitespace_ignoring(), - seq2( - OrParser::new(vec![ - Box::new(keyword(Keyword::Else).map(|_| vec![])), - Box::new(case_expression_list()), - ]), - zero_or_more_statements!(Keyword::Case, Keyword::End), - CaseBlock::new, - ), - ) + lead_opt_ws(seq2( + OrParser::new(vec![ + Box::new(keyword(Keyword::Else).map(|_| vec![])), + Box::new(case_expression_list()), + ]), + zero_or_more_statements!(Keyword::Case, Keyword::End), + CaseBlock::new, + )) } fn case_expression_list() @@ -108,14 +103,13 @@ fn case_expression_list() mod case_expression_parser { use rusty_common::Positioned; - use rusty_pc::and::opt_and_keep_right; use rusty_pc::*; use crate::core::expression::expression_pos_p; use crate::core::opt_second_expression::opt_second_expression_after_keyword; use crate::input::StringView; use crate::pc_specific::*; - use crate::tokens::{TokenType, any_token, whitespace_ignoring}; + use crate::tokens::{TokenType, any_token}; use crate::{CaseExpression, ExpressionTrait, Keyword, Operator, ParserError}; pub fn parser() -> impl Parser { @@ -125,10 +119,8 @@ mod case_expression_parser { fn case_is() -> impl Parser { seq3( keyword_ignoring(Keyword::Is), - opt_and_keep_right(whitespace_ignoring(), relational_operator_p()) - .or_expected("Operator after IS"), - opt_and_keep_right(whitespace_ignoring(), expression_pos_p()) - .or_expected("expression after IS operator"), + lead_opt_ws(relational_operator_p()).or_expected("Operator after IS"), + lead_opt_ws(expression_pos_p()).or_expected("expression after IS operator"), |_, Positioned { element, .. }, r| CaseExpression::Is(element, r), ) } diff --git a/rusty_parser/src/core/single_line_statements.rs b/rusty_parser/src/core/single_line_statements.rs index 4f4b5fcf..f44dc007 100644 --- a/rusty_parser/src/core/single_line_statements.rs +++ b/rusty_parser/src/core/single_line_statements.rs @@ -2,20 +2,20 @@ use rusty_pc::*; use crate::core::statement::{single_line_non_comment_statement_p, single_line_statement_p}; use crate::input::StringView; -use crate::pc_specific::WithPos; -use crate::tokens::{colon_ws, whitespace_ignoring}; +use crate::pc_specific::{WithPos, lead_ws}; +use crate::tokens::colon_ws; use crate::{ParserError, Statements}; pub fn single_line_non_comment_statements_p() -> impl Parser { - whitespace_ignoring().and_keep_right(delimited_by_colon( + lead_ws(delimited_by_colon( single_line_non_comment_statement_p().with_pos(), )) } pub fn single_line_statements_p() -> impl Parser { - whitespace_ignoring().and_keep_right(delimited_by_colon(single_line_statement_p().with_pos())) + lead_ws(delimited_by_colon(single_line_statement_p().with_pos())) } fn delimited_by_colon>( diff --git a/rusty_parser/src/core/statement.rs b/rusty_parser/src/core/statement.rs index c684fb22..49c53cfa 100644 --- a/rusty_parser/src/core/statement.rs +++ b/rusty_parser/src/core/statement.rs @@ -387,19 +387,16 @@ mod end { } mod system { - use rusty_pc::and::opt_and_tuple; use rusty_pc::*; use crate::core::statement_separator::peek_eof_or_statement_separator; use crate::input::StringView; use crate::pc_specific::*; - use crate::tokens::whitespace_ignoring; use crate::{Keyword, ParserError, Statement}; pub fn parse_system_p() -> impl Parser { keyword_ignoring(Keyword::System).and( - opt_and_tuple(whitespace_ignoring(), peek_eof_or_statement_separator()) - .or_expected("end-of-statement"), + lead_opt_ws(peek_eof_or_statement_separator()).or_expected("end-of-statement"), |_, _| Statement::System, ) } diff --git a/rusty_parser/src/core/statement_separator.rs b/rusty_parser/src/core/statement_separator.rs index d4db10ed..717ede1f 100644 --- a/rusty_parser/src/core/statement_separator.rs +++ b/rusty_parser/src/core/statement_separator.rs @@ -1,5 +1,5 @@ use rusty_common::*; -use rusty_pc::and::{IgnoringBothCombiner, opt_and}; +use rusty_pc::and::IgnoringBothCombiner; use rusty_pc::many::IgnoringManyCombiner; use rusty_pc::*; @@ -7,7 +7,7 @@ use crate::ParserError; use crate::core::comment::comment_as_string_p; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::{TokenMatcher, TokenType, any_token_of, peek_token, whitespace_ignoring}; +use crate::tokens::{TokenMatcher, TokenType, any_token_of, peek_token}; /// Parses a comment separator, which is the EOL, /// followed optionally by any number of EOL or whitespace tokens. @@ -40,14 +40,10 @@ fn eol_ws_zero_or_more() -> impl Parser impl Parser { - opt_and( - whitespace_ignoring(), - OrParser::new(vec![ - Box::new(eol_or_col_separator()), - Box::new(no_separator_needed_before_comment()), - ]), - IgnoringBothCombiner, - ) + lead_opt_ws(OrParser::new(vec![ + Box::new(eol_or_col_separator()), + Box::new(no_separator_needed_before_comment()), + ])) } /// EOL or colon, followed by any number of EOL or whitespace tokens. diff --git a/rusty_parser/src/core/user_defined_type.rs b/rusty_parser/src/core/user_defined_type.rs index 9fa08c2d..240e4059 100644 --- a/rusty_parser/src/core/user_defined_type.rs +++ b/rusty_parser/src/core/user_defined_type.rs @@ -10,7 +10,7 @@ use crate::core::statement_separator::comments_in_between_keywords; use crate::error::ParserError; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::{star_ws, whitespace_ignoring}; +use crate::tokens::star_ws; use crate::*; #[derive(Clone, Debug, PartialEq)] @@ -176,13 +176,12 @@ fn elements_p() -> impl Parser, Error = Par } fn element_pos_p() -> impl Parser { - seq5( + seq4( bare_name_without_dots(), - whitespace_ignoring(), - keyword_ws_p(Keyword::As), + demand_lead_ws(keyword_ws_p(Keyword::As)), element_type_p().or_expected("element type"), comments_in_between_keywords(), - |element, _, _, element_type, comments| Element::new(element, element_type, comments), + |element, _, element_type, comments| Element::new(element, element_type, comments), ) .with_pos() } diff --git a/rusty_parser/src/core/var_name.rs b/rusty_parser/src/core/var_name.rs index 788cb6ee..f8f09bf4 100644 --- a/rusty_parser/src/core/var_name.rs +++ b/rusty_parser/src/core/var_name.rs @@ -4,7 +4,6 @@ use rusty_pc::*; use crate::core::name::{bare_name_without_dots, name_p}; use crate::input::StringView; use crate::pc_specific::*; -use crate::tokens::whitespace_ignoring; use crate::{ ArrayDimensions, AsBareName, BareName, BareNamePos, DimType, ExpressionType, HasExpressionType, Keyword, Name, ParamType, ParserError, ToBareName, TypeQualifier }; @@ -176,7 +175,7 @@ where T: Default + VarType, BP: Parser, { - let extended_type_parser = extended_type_parser.to_fatal(); + let extended_type_parser = demand_lead_ws_ctx(extended_type_parser.to_fatal()); as_clause() .no_context() .and_keep_right(extended_type_parser) @@ -239,9 +238,7 @@ impl CreateArray for ParamType { } fn as_clause() -> impl Parser { - whitespace_ignoring() - .and_keep_right(keyword_ignoring(Keyword::As)) - .and_keep_left(whitespace_ignoring()) + lead_ws(keyword_ignoring(Keyword::As)) } pub(crate) fn user_defined_type() -> impl Parser diff --git a/rusty_parser/src/pc_specific/in_parenthesis.rs b/rusty_parser/src/pc_specific/in_parenthesis.rs index 54bd3385..1fa8bb94 100644 --- a/rusty_parser/src/pc_specific/in_parenthesis.rs +++ b/rusty_parser/src/pc_specific/in_parenthesis.rs @@ -4,15 +4,12 @@ use rusty_pc::*; use crate::ParserError; use crate::input::StringView; -use crate::pc_specific::PaddedByWs; +use crate::pc_specific::padded_by_ws; use crate::tokens::{any_symbol_of, any_token_of}; /// Parses the given parser around parenthesis and optional whitespace (inside the parenthesis). /// If the left side parenthesis is missing, parsing fails (soft). /// If the right side parenthesis is missing, parsing fails fatally. -/// -/// # Warning -/// The given parser cannot return a soft error. pub fn in_parenthesis

( parser: P, ) -> impl Parser @@ -21,18 +18,16 @@ where { surround( left_paren(), - parser.padded_by_ws(), + padded_by_ws(parser), right_paren(), SurroundMode::Mandatory, ) } fn left_paren() -> impl Parser { - // TODO add ignoring support for parenthesis any_symbol_of!('(') } fn right_paren() -> impl Parser { - // TODO add ignoring support for parenthesis any_symbol_of!(')') } diff --git a/rusty_parser/src/pc_specific/keyword.rs b/rusty_parser/src/pc_specific/keyword.rs index 05e8f875..7a751e39 100644 --- a/rusty_parser/src/pc_specific/keyword.rs +++ b/rusty_parser/src/pc_specific/keyword.rs @@ -4,8 +4,8 @@ use rusty_pc::and::IgnoringBothCombiner; use rusty_pc::*; use crate::input::StringView; -use crate::pc_specific::WithExpected; -use crate::tokens::{TokenMatcher, TokenType, any_token, whitespace_ignoring}; +use crate::pc_specific::{WithExpected, whitespace_ignoring}; +use crate::tokens::{TokenMatcher, TokenType, any_token}; use crate::{Keyword, ParserError}; // TODO review usages of TokenType::Keyword diff --git a/rusty_parser/src/pc_specific/mod.rs b/rusty_parser/src/pc_specific/mod.rs index 9f154cd4..dd578791 100644 --- a/rusty_parser/src/pc_specific/mod.rs +++ b/rusty_parser/src/pc_specific/mod.rs @@ -2,6 +2,7 @@ mod csv; mod in_parenthesis; mod keyword; mod keyword_map; +mod whitespace; #[cfg(debug_assertions)] pub mod logging; @@ -15,5 +16,6 @@ pub use self::in_parenthesis::*; pub use self::keyword::*; pub use self::keyword_map::*; pub use self::specific_trait::*; +pub use self::whitespace::*; pub use self::with_expected_message::*; pub use self::with_pos::*; diff --git a/rusty_parser/src/pc_specific/specific_trait.rs b/rusty_parser/src/pc_specific/specific_trait.rs index 330ba78a..66f7b51e 100644 --- a/rusty_parser/src/pc_specific/specific_trait.rs +++ b/rusty_parser/src/pc_specific/specific_trait.rs @@ -1,9 +1,8 @@ use rusty_pc::map_err::{MapErrParser, SoftErrorOverrider}; -use rusty_pc::{Parser, ParserErrorTrait, SurroundMode, surround}; +use rusty_pc::{Parser, ParserErrorTrait}; use crate::error::ParserError; use crate::input::StringView; -use crate::tokens::whitespace_ignoring; pub trait OrExpected: Parser where @@ -18,19 +17,3 @@ where } impl OrExpected for P where P: Parser {} - -pub trait PaddedByWs: Parser -where - Self: Sized, -{ - fn padded_by_ws(self) -> impl Parser { - surround( - whitespace_ignoring(), - self, - whitespace_ignoring(), - SurroundMode::Optional, - ) - } -} - -impl

PaddedByWs for P where P: Parser {} diff --git a/rusty_parser/src/pc_specific/whitespace.rs b/rusty_parser/src/pc_specific/whitespace.rs new file mode 100644 index 00000000..e0918fa4 --- /dev/null +++ b/rusty_parser/src/pc_specific/whitespace.rs @@ -0,0 +1,72 @@ +use rusty_pc::{Parser, SurroundMode, surround}; + +use crate::ParserError; +use crate::input::StringView; +use crate::tokens::{TokenType, any_token_of}; + +/// Parses a whitespace token dismissing it. +pub fn whitespace_ignoring() -> impl Parser { + any_token_of!(TokenType::Whitespace).map_to_unit() +} + +/// Parses optional leading and trailing whitespace around the given parser. +pub fn padded_by_ws

( + parser: P, +) -> impl Parser +where + P: Parser, +{ + surround( + whitespace_ignoring(), + parser, + whitespace_ignoring(), + SurroundMode::Optional, + ) +} + +/// Parses optional whitespace, dismissing the token. +/// This parser always succeeds. +pub fn opt_ws() -> impl Parser { + whitespace_ignoring().to_option().map_to_unit() +} + +/// Parses optional leading whitespace before the given parser. +pub fn lead_opt_ws

(parser: P) -> impl Parser +where + P: Parser, +{ + opt_ws().and_keep_right(parser) +} + +/// Parses leading whitespace before the given parser. +pub fn lead_ws

(parser: P) -> impl Parser +where + P: Parser, +{ + whitespace_ignoring().and_keep_right(parser) +} + +/// Parses mandatory whitespace. +pub fn demand_ws() -> impl Parser { + whitespace_ignoring().to_fatal() +} + +/// Parses mandatory leading whitespace before the given parser. +pub fn demand_lead_ws

( + parser: P, +) -> impl Parser +where + P: Parser, +{ + demand_ws().and_keep_right(parser) +} + +pub fn demand_lead_ws_ctx( + parser: P, +) -> impl Parser +where + P: Parser, + C: Clone, +{ + demand_ws().no_context().and_keep_right(parser) +} diff --git a/rusty_parser/src/tokens/any_token.rs b/rusty_parser/src/tokens/any_token.rs index b097cdd7..9995325a 100644 --- a/rusty_parser/src/tokens/any_token.rs +++ b/rusty_parser/src/tokens/any_token.rs @@ -1,5 +1,5 @@ use rusty_pc::and::StringCombiner; -use rusty_pc::many::{IgnoringManyCombiner, ManyCombiner, StringManyCombiner}; +use rusty_pc::many::{ManyCombiner, StringManyCombiner}; use rusty_pc::text::{many_str, many_str_with_combiner, one_char_to_str}; use rusty_pc::*; @@ -93,23 +93,11 @@ fn equals() -> impl Parser { /// Parses any number of whitespace characters, /// and returns them as a single token. -/// -/// This is one of the few functions that are public from this module, -/// allowing users to call it bypassing the `any_token` function, -/// if they want to. As whitespace isn't part of other tokens, -/// it should be safe to do so. -pub fn whitespace() -> impl Parser { +fn whitespace() -> impl Parser { whitespace_collecting(StringManyCombiner).to_token(TokenType::Whitespace) } -/// Parses any number of whitespace characters, but ignores the result. -/// Whitespace is often ignored, so this function optimizes as it doesn't -/// create a token or store the whitespace characters into a [String]. -pub fn whitespace_ignoring() -> impl Parser { - whitespace_collecting(IgnoringManyCombiner) -} - -pub fn whitespace_collecting( +fn whitespace_collecting( combiner: C, ) -> impl Parser where diff --git a/rusty_parser/src/tokens/any_token_of.rs b/rusty_parser/src/tokens/any_token_of.rs index 190594a0..02a47c55 100644 --- a/rusty_parser/src/tokens/any_token_of.rs +++ b/rusty_parser/src/tokens/any_token_of.rs @@ -87,13 +87,13 @@ macro_rules! any_symbol_of_ws { ( $($symbol:literal),+$(,)? ) => { - any_token_of!( + padded_by_ws(any_token_of!( types = ; symbols = $($symbol),+ ; mode = $crate::tokens::MatchMode::Include - ).padded_by_ws() + )) }; } diff --git a/rusty_parser/src/tokens/frequently_used.rs b/rusty_parser/src/tokens/frequently_used.rs index 90388be9..63fc4162 100644 --- a/rusty_parser/src/tokens/frequently_used.rs +++ b/rusty_parser/src/tokens/frequently_used.rs @@ -2,14 +2,14 @@ use rusty_pc::{Parser, Token}; use crate::ParserError; use crate::input::StringView; -use crate::pc_specific::PaddedByWs; +use crate::pc_specific::padded_by_ws; use crate::tokens::{TokenType, any_symbol_of, any_symbol_of_ws, any_token_of}; /// Equal sign, surrounded by optional whitespace. /// /// `? = ?` pub fn equal_sign_ws() -> impl Parser { - any_token_of!(TokenType::Equals).padded_by_ws() + padded_by_ws(any_token_of!(TokenType::Equals)) } /// Comma, surrounded by optional whitespace. diff --git a/rusty_pc/src/and.rs b/rusty_pc/src/and.rs index 89d0ea01..b92de24f 100644 --- a/rusty_pc/src/and.rs +++ b/rusty_pc/src/and.rs @@ -52,50 +52,6 @@ where } } -/// Parses the left side optionally and then the right side. -/// If the right side fails, the left side is reverted too. -/// The combiner function is used to create the final result. -pub fn opt_and( - left: impl Parser, - right: impl Parser, - combiner: F, -) -> impl Parser -where - I: InputTrait, - E: ParserErrorTrait, - F: Combiner, R, O>, -{ - left.to_option().and(right, combiner) -} - -/// Parses the left side optionally and then the right side. -/// If the right side fails, the left side is reverted too. -/// The result is a tuple of the (optional) left side and the right side. -pub fn opt_and_tuple( - left: impl Parser, - right: impl Parser, -) -> impl Parser, R), Error = E> -where - I: InputTrait, - E: ParserErrorTrait, -{ - opt_and(left, right, TupleCombiner) -} - -/// Parses the left side optionally and then the right side. -/// If the right side fails, the left side is reverted too. -/// The result is the right side only, the left is discarded. -pub fn opt_and_keep_right( - left: impl Parser, - right: impl Parser, -) -> impl Parser -where - I: InputTrait, - E: ParserErrorTrait, -{ - opt_and(left, right, KeepRightCombiner) -} - /// Combines two values into one. pub trait Combiner { /// Combines two values into one. diff --git a/rusty_pc/src/surround.rs b/rusty_pc/src/surround.rs index 5f1475f2..95ade08f 100644 --- a/rusty_pc/src/surround.rs +++ b/rusty_pc/src/surround.rs @@ -31,7 +31,6 @@ pub enum SurroundMode { /// If the right boundary is missing, a fatal error is returned. /// If the main content is missing, a fatal error is returned. Mandatory, - // TODO add MandatoryOrDefault to return the default content if it is missing } impl SurroundParser {