From 834194d40a213e9cf5a14840a52030be018706b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Tue, 28 Apr 2020 02:02:20 +0200 Subject: [PATCH] Work in progress --- src/parse/formulas.rs | 121 +++++++++++---------- src/parse/tokens.rs | 240 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 268 insertions(+), 93 deletions(-) diff --git a/src/parse/formulas.rs b/src/parse/formulas.rs index 0817f9e..f9f30e0 100644 --- a/src/parse/formulas.rs +++ b/src/parse/formulas.rs @@ -71,23 +71,46 @@ impl<'i> FormulaStr<'i> } } - fn iter_tokens(&self) -> TokenIterator<'i> + fn tokens(&self) -> Tokens<'i, impl FnMut(Token<'i>) -> Option>> { - TokenIterator::new(self.input) + Tokens::new_iter(self.input) } - fn filter_logical_connective(&self, logical_connective: LogicalConnective) - -> std::iter::Filter, impl FnMut(&Result<(usize, usize, Token<'i>), crate::parse::Error>) -> bool> + fn logical_connectives(&self) -> Tokens<'i, impl FnMut(Token<'i>) -> Option> { - let token_selector = move |token: &_| match token + let functor = |token| match token { - Ok((_, _, Token::Identifier(ref identifier))) => match *identifier + Token::Identifier(ref identifier) => match *identifier + { + "and" => Some(LogicalConnective::And), + "or" => Some(LogicalConnective::Or), + _ => None, + }, + Token::Symbol(ref symbol) => match symbol + { + Symbol::ArrowLeft => Some(LogicalConnective::ImpliesRightToLeft), + Symbol::ArrowLeftAndRight => Some(LogicalConnective::IfAndOnlyIf), + Symbol::ArrowRight => Some(LogicalConnective::ImpliesLeftToRight), + _ => None, + }, + _ => None, + }; + + Tokens::new_filter_map(self.input, functor) + } + + fn split_at_logical_connective(&self, logical_connective: LogicalConnective) + -> TokenSplit) -> Option>>> + { + let predicate = move |token: &_| match token + { + Token::Identifier(ref identifier) => match *identifier { "and" => logical_connective == LogicalConnective::And, "or" => logical_connective == LogicalConnective::Or, _ => false, }, - Ok((_, _, Token::Symbol(ref symbol))) => match symbol + Token::Symbol(ref symbol) => match symbol { Symbol::ArrowLeft => logical_connective == LogicalConnective::ImpliesRightToLeft, Symbol::ArrowLeftAndRight => logical_connective == LogicalConnective::IfAndOnlyIf, @@ -97,7 +120,7 @@ impl<'i> FormulaStr<'i> _ => false, }; - self.iter_tokens().filter(token_selector) + Tokens::new_filter(self.input, predicate).split() } pub fn top_level_logical_connective(&self) @@ -121,16 +144,13 @@ impl<'i> FormulaStr<'i> _ => None, }; + let logical_connectives = Tokens::new_filter_map(self.input, logical_connective); + let mut top_level_logical_connective = None; - for token in self.iter_tokens() + for logical_connective in logical_connectives { - let (_, _, token) = token?; - let logical_connective = match logical_connective(token) - { - Some(logical_connective) => logical_connective, - None => continue, - }; + let (_, logical_connective) = logical_connective?; top_level_logical_connective = match top_level_logical_connective { @@ -162,39 +182,25 @@ impl<'i> FormulaStr<'i> Ok(top_level_logical_connective) } - fn filter_comparison_operators(&self) - -> std::iter::FilterMap, impl FnMut(Result<(usize, usize, Token<'i>), crate::parse::Error>) - -> Option>> + fn comparison_operators(&self) -> Tokens<'i, impl FnMut(Token<'i>) + -> Option> { - let token_functor = |token| match token + let functor = |token| match token { - Ok((input_left, remaining_input, Token::Symbol(symbol))) => match symbol + Token::Symbol(symbol) => match symbol { - Symbol::Greater => - return Some(Ok((input_left, remaining_input, - crate::ComparisonOperator::Greater))), - Symbol::GreaterOrEqual => - return Some(Ok((input_left, remaining_input, - crate::ComparisonOperator::GreaterOrEqual))), - Symbol::Less => - return Some(Ok((input_left, remaining_input, - crate::ComparisonOperator::Less))), - Symbol::LessOrEqual => - return Some(Ok((input_left, remaining_input, - crate::ComparisonOperator::LessOrEqual))), - Symbol::Equal => - return Some(Ok((input_left, remaining_input, - crate::ComparisonOperator::Equal))), - Symbol::NotEqual => - return Some(Ok((input_left, remaining_input, - crate::ComparisonOperator::NotEqual))), + Symbol::Greater => Some(crate::ComparisonOperator::Greater), + Symbol::GreaterOrEqual => Some(crate::ComparisonOperator::GreaterOrEqual), + Symbol::Less => Some(crate::ComparisonOperator::Less), + Symbol::LessOrEqual => Some(crate::ComparisonOperator::LessOrEqual), + Symbol::Equal => Some(crate::ComparisonOperator::Equal), + Symbol::NotEqual => Some(crate::ComparisonOperator::NotEqual), _ => None, }, - Err(error) => Some(Err(error)), _ => None, }; - self.iter_tokens().filter_map(token_functor) + Tokens::new_filter_map(self.input, functor) } pub fn parse(&self, level: usize) -> Result @@ -222,8 +228,7 @@ impl<'i> FormulaStr<'i> let arguments_n_ary = || { // TODO: improve error handling if the formulas between the operators are invalid - TokenSplit::new(self.filter_logical_connective(top_level_logical_connective), - self.input) + self.split_at_logical_connective(top_level_logical_connective) .map(|subformula| FormulaStr::new(subformula?).parse(level + 1)) .collect::, _>>() }; @@ -236,10 +241,7 @@ impl<'i> FormulaStr<'i> return Ok(crate::Formula::if_and_only_if(arguments_n_ary()?)), LogicalConnective::ImpliesLeftToRight => return implication_left_to_right( - TokenSplit::new( - self.filter_logical_connective(top_level_logical_connective), - self.input), - level + 1), + self.split_at_logical_connective(top_level_logical_connective), level + 1), /*LogicalConnective::ImpliesRightToLeft => unimplemented!(),*/ _ => { @@ -270,17 +272,17 @@ impl<'i> FormulaStr<'i> } } - let mut comparison_operators = self.filter_comparison_operators(); + let mut comparison_operators = self.comparison_operators(); // Parse comparisons if let Some(comparison_operator) = comparison_operators.next() { - let (_, _, comparison_operator) = comparison_operator?; + let (_, comparison_operator) = comparison_operator?; // Comparisons with more than one comparison operator aren’t supported if let Some(next_comparison_operator) = comparison_operators.next() { - let (_, _, next_comparison_operator) = next_comparison_operator?; + let (_, next_comparison_operator) = next_comparison_operator?; return Err(crate::parse::Error::new_multiple_comparison_operators( comparison_operator, next_comparison_operator, @@ -289,8 +291,7 @@ impl<'i> FormulaStr<'i> println!("{} parsing “{:?}” comparison: {}", indentation, comparison_operator, input); - let mut comparison_operator_split = - TokenSplit::new(self.filter_comparison_operators(), self.input); + let mut comparison_operator_split = self.comparison_operators().split(); // There’s exactly one comparison operator in this formula, as we have verified above. // Hence, the split is guaranteed to generate exactly these two elements @@ -371,19 +372,18 @@ impl std::fmt::Debug for Quantifier } // TODO: refactor -fn implication_left_to_right_inner<'i, T>( - mut split_formula_at_logical_connective: TokenSplit<'i, T, Token<'i>>, level: usize) +fn implication_left_to_right_inner<'i, T>(mut logical_connective_iterator: T, level: usize) -> Result, crate::parse::Error> where - T: std::iter::Iterator), crate::parse::Error>> + T: std::iter::Iterator> { - match split_formula_at_logical_connective.next() + match logical_connective_iterator.next() { Some(argument) => { // TODO: improve error handling if antecedent cannot be parsed let argument = FormulaStr::new(argument?).parse(level)?; - match implication_left_to_right_inner(split_formula_at_logical_connective, level)? + match implication_left_to_right_inner(logical_connective_iterator, level)? { Some(next_argument) => Ok(Some(crate::Formula::implies( crate::ImplicationDirection::LeftToRight, Box::new(argument), @@ -395,19 +395,18 @@ where } } -fn implication_left_to_right<'i, T>( - mut split_formula_at_logical_connective: TokenSplit<'i, T, Token<'i>>, level: usize) +fn implication_left_to_right<'i, T>(mut logical_connective_iterator: T, level: usize) -> Result where - T: std::iter::Iterator), crate::parse::Error>> + T: std::iter::Iterator> { - match split_formula_at_logical_connective.next() + match logical_connective_iterator.next() { Some(argument) => { // TODO: improve error handling if antecedent cannot be parsed let argument = FormulaStr::new(argument?).parse(level)?; - match implication_left_to_right_inner(split_formula_at_logical_connective, level)? + match implication_left_to_right_inner(logical_connective_iterator, level)? { Some(next_argument) => Ok(crate::Formula::implies( crate::ImplicationDirection::LeftToRight, Box::new(argument), diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 705cfc4..2dc4a3a 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -308,12 +308,216 @@ pub(crate) fn parenthesized_expression(input: &str) crate::parse::error::Location::new(0, Some(1)))) } -pub(crate) trait OriginalInput<'i> +pub(crate) struct Tokens<'i, F> { - fn original_input(&self) -> &'i str; + original_input: &'i str, + input: &'i str, + previous_index: usize, + reached_end_of_stream: bool, + functor: F, } -pub(crate) struct TokenIterator<'i> +impl<'i> Tokens<'i, ()> +{ + pub fn new_iter(input: &'i str) -> Tokens<'i, impl FnMut(Token<'i>) -> Option>> + { + Tokens::new_filter_map(input, |x| Some(x)) + } + + pub fn new_filter

(input: &'i str, mut predicate: P) + -> Tokens<'i, impl FnMut(Token<'i>) -> Option>> + where + P: FnMut(&Token<'i>) -> bool + { + Tokens::new_filter_map(input, + move |x| + { + if predicate(&x) + { + Some(x) + } + else + { + None + } + }) + } +} + +impl<'i, F> Tokens<'i, F> +{ + pub fn new_filter_map(input: &'i str, functor: F) -> Self + { + Self + { + original_input: input, + input, + previous_index: 0, + reached_end_of_stream: false, + functor, + } + } + + fn next_token(&mut self) -> Option), crate::parse::Error>> + { + self.input = self.input.trim_start(); + let index_left = substring_offset(self.input, self.original_input); + + let first_character = match self.input.chars().next() + { + None => return None, + Some(first_character) => first_character, + }; + + if self.input.starts_with(")") + { + return Some(Err(crate::parse::Error::new_unmatched_parenthesis( + crate::parse::error::Location::new(0, Some(1))))); + } + + match parenthesized_expression(self.input) + { + Ok(Some((parenthesized_expression, remaining_input))) => + { + self.input = remaining_input; + let index_right = substring_offset(self.input, self.original_input); + + return Some(Ok((index_left, index_right, + Token::ParenthesizedExpression(parenthesized_expression)))); + }, + Ok(None) => (), + Err(error) => return Some(Err(error)), + } + + match number(self.input) + { + Ok(Some((number, remaining_input))) => + { + self.input = remaining_input; + let index_right = substring_offset(self.input, self.original_input); + + return Some(Ok((index_left, index_right, Token::Number(number)))); + }, + Ok(None) => (), + Err(error) => return Some(Err(error)), + } + + if let Some((identifier, remaining_input)) = identifier(self.input) + { + self.input = remaining_input; + let index_right = substring_offset(self.input, self.original_input); + + return Some(Ok((index_left, index_right, Token::Identifier(identifier)))); + } + + if let Some((symbol, remaining_input)) = symbol(self.input) + { + self.input = remaining_input; + let index_right = substring_offset(self.input, self.original_input); + + return Some(Ok((index_left, index_right, Token::Symbol(symbol)))); + } + + return Some(Err(crate::parse::Error::new_character_not_allowed(first_character, + crate::parse::error::Location::new(0, Some(0))))); + } + + pub fn remaining_input(&mut self) -> Option<&'i str> + { + if self.reached_end_of_stream + { + return None; + } + + let remaining_input = self.original_input[self.previous_index..].trim(); + self.reached_end_of_stream = true; + + Some(remaining_input) + } + + pub fn split(self) -> TokenSplit + { + TokenSplit::new(self) + } +} + +impl<'i, F, G> std::iter::Iterator for Tokens<'i, F> +where + F: FnMut(Token<'i>) -> Option, +{ + type Item = Result<(&'i str, G), crate::parse::Error>; + + fn next(&mut self) -> Option + { + if self.previous_index == self.original_input.len() + { + return None; + } + + loop + { + match self.next_token() + { + Some(Ok((index_left, index_right, token))) => + { + let token = match (self.functor)(token) + { + None => continue, + Some(token) => token, + }; + + let input_left = self.original_input[self.previous_index..index_left].trim(); + assert!(!input_left.is_empty()); + + self.previous_index = index_right; + + return Some(Ok((input_left, token))); + }, + Some(Err(error)) => return Some(Err(error)), + None => return None, + } + } + } +} + +pub(crate) struct TokenSplit +{ + tokens: T, +} + +impl TokenSplit<()> +{ + pub fn new(tokens: T) -> TokenSplit + { + TokenSplit + { + tokens, + } + } +} + +impl<'i, F, G> std::iter::Iterator for TokenSplit> +where + F: FnMut(Token<'i>) -> Option, +{ + type Item = Result<&'i str, crate::parse::Error>; + + fn next(&mut self) -> Option + { + match self.tokens.next() + { + Some(Ok((input_before, _))) => Some(Ok(input_before)), + Some(Err(error)) => Some(Err(error)), + None => match self.tokens.remaining_input() + { + Some(remaining_input) => Some(Ok(remaining_input)), + None => None, + }, + } + } +} + +/*pub(crate) struct TokenIterator<'i> { original_input: &'i str, input: &'i str, @@ -329,36 +533,8 @@ impl<'i> TokenIterator<'i> input, } } - - /*pub fn filter

(self, pattern: P) -> TokenFilter<'i, P> - where - P: FnMut(&Token<'i>) -> bool, - { - TokenFilter::new(self, pattern) - } - - pub fn split(self) -> TokenSplit<'i, Self> - { - TokenSplit::new(self) - }*/ } -/*impl<'i> OriginalInput<'i> for TokenIterator<'i> -{ - fn original_input(&self) -> &'i str - { - self.original_input - } -} - -impl<'i, P> OriginalInput<'i> for std::iter::Filter, P> -{ - fn original_input(&self) -> &'i str - { - self.iter.original_input - } -}*/ - impl<'i> std::iter::Iterator for TokenIterator<'i> { type Item = Result<(usize, usize, Token<'i>), crate::parse::Error>; @@ -491,7 +667,7 @@ where } } } -} +}*/ #[cfg(test)] mod tests