Finish dirty first pass over parser
This commit is contained in:
parent
66ac57c5b8
commit
8d474fa489
@ -28,6 +28,7 @@ pub enum Kind
|
|||||||
UnexpectedToken,
|
UnexpectedToken,
|
||||||
EmptyExpression,
|
EmptyExpression,
|
||||||
ExpectedLogicalConnectiveArgument(String),
|
ExpectedLogicalConnectiveArgument(String),
|
||||||
|
ExpectedTerm,
|
||||||
MultipleComparisonOperators(crate::ComparisonOperator, crate::ComparisonOperator),
|
MultipleComparisonOperators(crate::ComparisonOperator, crate::ComparisonOperator),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +102,11 @@ impl Error
|
|||||||
Self::new(Kind::ExpectedLogicalConnectiveArgument(logical_connective_name), location)
|
Self::new(Kind::ExpectedLogicalConnectiveArgument(logical_connective_name), location)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_expected_term(location: Location) -> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::ExpectedTerm, location)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_multiple_comparison_operators(
|
pub(crate) fn new_multiple_comparison_operators(
|
||||||
comparison_operator_1: crate::ComparisonOperator,
|
comparison_operator_1: crate::ComparisonOperator,
|
||||||
comparison_operator_2: crate::ComparisonOperator, location: Location)
|
comparison_operator_2: crate::ComparisonOperator, location: Location)
|
||||||
@ -134,12 +140,13 @@ impl std::fmt::Debug for Error
|
|||||||
Kind::MixedImplicationDirections(_location_2) =>
|
Kind::MixedImplicationDirections(_location_2) =>
|
||||||
write!(formatter, "-> and <- implications may not be mixed within the same scope")?,
|
write!(formatter, "-> and <- implications may not be mixed within the same scope")?,
|
||||||
Kind::ExpectedVariableDeclaration =>
|
Kind::ExpectedVariableDeclaration =>
|
||||||
write!(formatter, "expected variable declaration")?,
|
write!(formatter, "expected a variable declaration")?,
|
||||||
Kind::UnexpectedToken => write!(formatter, "unexpected token")?,
|
Kind::UnexpectedToken => write!(formatter, "unexpected token")?,
|
||||||
Kind::EmptyExpression => write!(formatter, "empty expression")?,
|
Kind::EmptyExpression => write!(formatter, "empty expression")?,
|
||||||
Kind::ExpectedLogicalConnectiveArgument(ref logical_connective_name) =>
|
Kind::ExpectedLogicalConnectiveArgument(ref logical_connective_name) =>
|
||||||
write!(formatter, "this “{}” logical connective is missing an argument",
|
write!(formatter, "this “{}” logical connective is missing an argument",
|
||||||
logical_connective_name)?,
|
logical_connective_name)?,
|
||||||
|
Kind::ExpectedTerm => write!(formatter, "expected a term")?,
|
||||||
Kind::MultipleComparisonOperators(comparison_operator_1, comparison_operator_2) =>
|
Kind::MultipleComparisonOperators(comparison_operator_1, comparison_operator_2) =>
|
||||||
write!(formatter, "chained comparisons aren’t supported (found “{:?}” and “{:?}” in the same formula), consider separating them with “and”",
|
write!(formatter, "chained comparisons aren’t supported (found “{:?}” and “{:?}” in the same formula), consider separating them with “and”",
|
||||||
comparison_operator_1, comparison_operator_2)?,
|
comparison_operator_1, comparison_operator_2)?,
|
||||||
|
@ -68,28 +68,15 @@ impl<'i> FormulaStr<'i>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tokens(&self) -> Tokens<'i, impl FnMut(Token<'i>) -> Option<Token<'i>>>
|
|
||||||
{
|
|
||||||
Tokens::new_iter(self.input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn logical_connectives(&self) -> Tokens<'i, impl FnMut(Token<'i>) -> Option<LogicalConnective>>
|
fn logical_connectives(&self) -> Tokens<'i, impl FnMut(Token<'i>) -> Option<LogicalConnective>>
|
||||||
{
|
{
|
||||||
let functor = |token| match token
|
let functor = |token| match token
|
||||||
{
|
{
|
||||||
Token::Identifier(ref identifier) => match *identifier
|
Token::Identifier("and") => Some(LogicalConnective::And),
|
||||||
{
|
Token::Identifier("or") => Some(LogicalConnective::Or),
|
||||||
"and" => Some(LogicalConnective::And),
|
Token::Symbol(Symbol::ArrowLeft) => Some(LogicalConnective::ImpliesRightToLeft),
|
||||||
"or" => Some(LogicalConnective::Or),
|
Token::Symbol(Symbol::ArrowLeftAndRight) => Some(LogicalConnective::IfAndOnlyIf),
|
||||||
_ => None,
|
Token::Symbol(Symbol::ArrowRight) => Some(LogicalConnective::ImpliesLeftToRight),
|
||||||
},
|
|
||||||
Token::Symbol(ref symbol) => match symbol
|
|
||||||
{
|
|
||||||
Symbol::ArrowLeft => Some(LogicalConnective::ImpliesRightToLeft),
|
|
||||||
Symbol::ArrowLeftAndRight => Some(LogicalConnective::IfAndOnlyIf),
|
|
||||||
Symbol::ArrowRight => Some(LogicalConnective::ImpliesLeftToRight),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,19 +88,14 @@ impl<'i> FormulaStr<'i>
|
|||||||
{
|
{
|
||||||
let predicate = move |token: &_| match token
|
let predicate = move |token: &_| match token
|
||||||
{
|
{
|
||||||
Token::Identifier(ref identifier) => match *identifier
|
Token::Identifier("and") => logical_connective == LogicalConnective::And,
|
||||||
{
|
Token::Identifier("or") => logical_connective == LogicalConnective::Or,
|
||||||
"and" => logical_connective == LogicalConnective::And,
|
Token::Symbol(Symbol::ArrowLeft) =>
|
||||||
"or" => logical_connective == LogicalConnective::Or,
|
logical_connective == LogicalConnective::ImpliesRightToLeft,
|
||||||
_ => false,
|
Token::Symbol(Symbol::ArrowLeftAndRight) =>
|
||||||
},
|
logical_connective == LogicalConnective::IfAndOnlyIf,
|
||||||
Token::Symbol(ref symbol) => match symbol
|
Token::Symbol(Symbol::ArrowRight) =>
|
||||||
{
|
logical_connective == LogicalConnective::ImpliesLeftToRight,
|
||||||
Symbol::ArrowLeft => logical_connective == LogicalConnective::ImpliesRightToLeft,
|
|
||||||
Symbol::ArrowLeftAndRight => logical_connective == LogicalConnective::IfAndOnlyIf,
|
|
||||||
Symbol::ArrowRight => logical_connective == LogicalConnective::ImpliesLeftToRight,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,14 +229,38 @@ impl<'i> FormulaStr<'i>
|
|||||||
// Parse quantified formulas
|
// Parse quantified formulas
|
||||||
if let Some((identifier, input)) = identifier(input)
|
if let Some((identifier, input)) = identifier(input)
|
||||||
{
|
{
|
||||||
if identifier == "not"
|
match identifier
|
||||||
{
|
{
|
||||||
let input = input.trim_start();
|
"not" =>
|
||||||
println!("{} parsing “not” formula body: {}", indentation, input);
|
{
|
||||||
|
let input = input.trim_start();
|
||||||
|
println!("{} parsing “not” formula body: {}", indentation, input);
|
||||||
|
|
||||||
let argument = FormulaStr::new(input).parse(level + 1)?;
|
let argument = FormulaStr::new(input).parse(level + 1)?;
|
||||||
|
|
||||||
return Ok(crate::Formula::not(Box::new(argument)));
|
return Ok(crate::Formula::not(Box::new(argument)));
|
||||||
|
},
|
||||||
|
"true" =>
|
||||||
|
{
|
||||||
|
if !input.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(crate::Formula::true_());
|
||||||
|
},
|
||||||
|
"false" =>
|
||||||
|
{
|
||||||
|
if !input.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(crate::Formula::false_());
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let quantifier = match identifier
|
let quantifier = match identifier
|
||||||
@ -340,25 +346,19 @@ impl<'i> FormulaStr<'i>
|
|||||||
crate::PredicateDeclaration::new(predicate_name.to_string(), arguments.len());
|
crate::PredicateDeclaration::new(predicate_name.to_string(), arguments.len());
|
||||||
let declaration = std::rc::Rc::new(declaration);
|
let declaration = std::rc::Rc::new(declaration);
|
||||||
|
|
||||||
// TODO: handle unexpected input after end of parenthesized expression
|
|
||||||
|
|
||||||
return Ok(crate::Formula::predicate(declaration, arguments));
|
return Ok(crate::Formula::predicate(declaration, arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parenthesized formulas
|
// Parse parenthesized formulas
|
||||||
match parenthesized_expression(input)?
|
if let Some((parenthesized_expression, input)) = parenthesized_expression(input)?
|
||||||
{
|
{
|
||||||
Some((parenthesized_expression, input)) =>
|
if !input.trim().is_empty()
|
||||||
{
|
{
|
||||||
if !input.trim().is_empty()
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
{
|
crate::parse::error::Location::new(0, Some(0))));
|
||||||
return Err(crate::parse::Error::new_unexpected_token(
|
}
|
||||||
crate::parse::error::Location::new(0, Some(0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
return FormulaStr::new(parenthesized_expression).parse(level);
|
return FormulaStr::new(parenthesized_expression).parse(level + 1);
|
||||||
},
|
|
||||||
None => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(crate::parse::Error::new_unexpected_token(
|
Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
@ -49,6 +49,45 @@ fn variable_name(input: &str) -> Option<(&str, &str)>
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_function_name(identifier: &str) -> bool
|
||||||
|
{
|
||||||
|
if is_keyword(identifier)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut characters = identifier.chars();
|
||||||
|
|
||||||
|
while let Some(character) = characters.next()
|
||||||
|
{
|
||||||
|
match character
|
||||||
|
{
|
||||||
|
'_' => continue,
|
||||||
|
_ if character.is_ascii_lowercase() => return true,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_variable_name(identifier: &str) -> bool
|
||||||
|
{
|
||||||
|
let mut characters = identifier.chars();
|
||||||
|
|
||||||
|
while let Some(character) = characters.next()
|
||||||
|
{
|
||||||
|
match character
|
||||||
|
{
|
||||||
|
'_' => continue,
|
||||||
|
_ if character.is_ascii_uppercase() => return true,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn variable_declaration(input: &str) -> Option<(crate::VariableDeclaration, &str)>
|
pub(crate) fn variable_declaration(input: &str) -> Option<(crate::VariableDeclaration, &str)>
|
||||||
{
|
{
|
||||||
variable_name(input)
|
variable_name(input)
|
||||||
@ -96,45 +135,35 @@ pub(crate) fn variable_declarations(input: &str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub(crate) enum TermInfixOperator
|
pub(crate) enum ArithmeticOperatorClass
|
||||||
{
|
{
|
||||||
Add,
|
Exponential,
|
||||||
Divide,
|
Multiplicative,
|
||||||
Exponentiate,
|
Additive,
|
||||||
Modulo,
|
|
||||||
Multiply,
|
|
||||||
Subtract,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TermInfixOperator
|
impl ArithmeticOperatorClass
|
||||||
{
|
{
|
||||||
fn level(&self) -> usize
|
fn level(&self) -> usize
|
||||||
{
|
{
|
||||||
match self
|
match self
|
||||||
{
|
{
|
||||||
Self::Exponentiate => 1,
|
Self::Exponential => 1,
|
||||||
Self::Multiply
|
Self::Multiplicative => 2,
|
||||||
| Self::Divide
|
Self::Additive => 3,
|
||||||
| Self::Modulo => 2,
|
|
||||||
Self::Add
|
|
||||||
| Self::Subtract => 3,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for TermInfixOperator
|
impl std::fmt::Debug for ArithmeticOperatorClass
|
||||||
{
|
{
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
match &self
|
match &self
|
||||||
{
|
{
|
||||||
Self::Add => write!(formatter, "+"),
|
Self::Exponential => write!(formatter, "exponential"),
|
||||||
Self::Divide => write!(formatter, "/"),
|
Self::Multiplicative => write!(formatter, "multiplicative"),
|
||||||
Self::Exponentiate => write!(formatter, "**"),
|
Self::Additive => write!(formatter, "additive"),
|
||||||
// TODO: conflicts with single-line comments
|
|
||||||
Self::Modulo => write!(formatter, "%"),
|
|
||||||
Self::Multiply => write!(formatter, "*"),
|
|
||||||
Self::Subtract => write!(formatter, "-"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,15 +183,118 @@ impl<'i> TermStr<'i>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_infix_operators(&self) -> TermInfixOperatorIterator<'i>
|
fn arithmetic_operator_classes(&self) -> Tokens<'i, impl FnMut(Token<'i>)
|
||||||
|
-> Option<ArithmeticOperatorClass>>
|
||||||
{
|
{
|
||||||
TermInfixOperatorIterator::new(self.input)
|
let functor = |token| match token
|
||||||
|
{
|
||||||
|
Token::Symbol(Symbol::Exponentiation) => Some(ArithmeticOperatorClass::Exponential),
|
||||||
|
Token::Symbol(Symbol::Multiplication) => Some(ArithmeticOperatorClass::Multiplicative),
|
||||||
|
Token::Symbol(Symbol::Division) => Some(ArithmeticOperatorClass::Multiplicative),
|
||||||
|
Token::Symbol(Symbol::Percent) => Some(ArithmeticOperatorClass::Multiplicative),
|
||||||
|
Token::Symbol(Symbol::Plus) => Some(ArithmeticOperatorClass::Additive),
|
||||||
|
Token::Symbol(Symbol::Minus) => Some(ArithmeticOperatorClass::Additive),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: refactor so that self.input is always set correctly
|
||||||
|
Tokens::new_filter_map(self.input, functor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_at_infix_operator(&self, infix_operator: TermInfixOperator)
|
fn filter_by_arithmetic_operator_class(&self,
|
||||||
-> SplitTermAtInfixOperator<'i>
|
arithmetic_operator_class: ArithmeticOperatorClass)
|
||||||
|
-> Tokens<'i, impl FnMut(Token<'i>) -> Option<crate::BinaryOperator>>
|
||||||
{
|
{
|
||||||
SplitTermAtInfixOperator::new(self, infix_operator)
|
let functor = move |token| match token
|
||||||
|
{
|
||||||
|
Token::Symbol(Symbol::Exponentiation) =>
|
||||||
|
if arithmetic_operator_class == ArithmeticOperatorClass::Exponential
|
||||||
|
{
|
||||||
|
Some(crate::BinaryOperator::Exponentiate)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Token::Symbol(Symbol::Multiplication) =>
|
||||||
|
if arithmetic_operator_class == ArithmeticOperatorClass::Multiplicative
|
||||||
|
{
|
||||||
|
Some(crate::BinaryOperator::Multiply)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Token::Symbol(Symbol::Division) =>
|
||||||
|
if arithmetic_operator_class == ArithmeticOperatorClass::Multiplicative
|
||||||
|
{
|
||||||
|
Some(crate::BinaryOperator::Divide)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Token::Symbol(Symbol::Percent) =>
|
||||||
|
if arithmetic_operator_class == ArithmeticOperatorClass::Multiplicative
|
||||||
|
{
|
||||||
|
Some(crate::BinaryOperator::Modulo)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Token::Symbol(Symbol::Plus) =>
|
||||||
|
if arithmetic_operator_class == ArithmeticOperatorClass::Additive
|
||||||
|
{
|
||||||
|
Some(crate::BinaryOperator::Add)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Token::Symbol(Symbol::Minus) =>
|
||||||
|
if arithmetic_operator_class == ArithmeticOperatorClass::Additive
|
||||||
|
{
|
||||||
|
Some(crate::BinaryOperator::Subtract)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
None
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Tokens::new_filter_map(self.input, functor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top_level_arithmetic_operator_class(&self)
|
||||||
|
-> Result<Option<ArithmeticOperatorClass>, crate::parse::Error>
|
||||||
|
{
|
||||||
|
let mut top_level_arithmetic_operator_class = None;
|
||||||
|
|
||||||
|
for arithmetic_operator_class in self.arithmetic_operator_classes()
|
||||||
|
{
|
||||||
|
let (_, arithmetic_operator_class) = arithmetic_operator_class?;
|
||||||
|
|
||||||
|
top_level_arithmetic_operator_class = match top_level_arithmetic_operator_class
|
||||||
|
{
|
||||||
|
None => Some(arithmetic_operator_class),
|
||||||
|
Some(top_level_arithmetic_operator_class) =>
|
||||||
|
{
|
||||||
|
if arithmetic_operator_class.level()
|
||||||
|
> top_level_arithmetic_operator_class.level()
|
||||||
|
{
|
||||||
|
Some(arithmetic_operator_class)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Some(top_level_arithmetic_operator_class)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(top_level_arithmetic_operator_class)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&self, level: usize) -> Result<crate::Term, crate::parse::Error>
|
pub fn parse(&self, level: usize) -> Result<crate::Term, crate::parse::Error>
|
||||||
@ -172,181 +304,235 @@ impl<'i> TermStr<'i>
|
|||||||
|
|
||||||
let input = self.input.trim_start();
|
let input = self.input.trim_start();
|
||||||
|
|
||||||
// TODO: implement
|
match input.chars().next()
|
||||||
Ok(crate::Term::true_())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct TermInfixOperatorIterator<'i>
|
|
||||||
{
|
|
||||||
original_input: &'i str,
|
|
||||||
input: &'i str,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'i> TermInfixOperatorIterator<'i>
|
|
||||||
{
|
|
||||||
pub fn new(input: &'i str) -> Self
|
|
||||||
{
|
|
||||||
Self
|
|
||||||
{
|
{
|
||||||
original_input: input,
|
Some(')') => return Err(crate::parse::Error::new_unmatched_parenthesis(
|
||||||
input,
|
crate::parse::error::Location::new(0, Some(0)))),
|
||||||
|
// TODO: implement absolute value function
|
||||||
|
Some('|') => unimplemented!(),
|
||||||
|
None => return Err(crate::parse::Error::new_empty_expression(
|
||||||
|
crate::parse::error::Location::new(0, Some(0)))),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'i> std::iter::Iterator for TermInfixOperatorIterator<'i>
|
// Parse arithmetic infix operations
|
||||||
{
|
if let Some(top_level_arithmetic_operator_class) =
|
||||||
type Item = Result<(&'i str, &'i str, TermInfixOperator), crate::parse::Error>;
|
self.top_level_arithmetic_operator_class()?
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item>
|
|
||||||
{
|
|
||||||
loop
|
|
||||||
{
|
{
|
||||||
self.input = self.input.trim_start();
|
println!("{} parsing {:?} arithmetic term", indentation,
|
||||||
|
top_level_arithmetic_operator_class);
|
||||||
|
|
||||||
let first_character = match self.input.chars().next()
|
if top_level_arithmetic_operator_class == ArithmeticOperatorClass::Exponential
|
||||||
{
|
{
|
||||||
None => return None,
|
return exponentiate(
|
||||||
Some(first_character) => first_character,
|
self.filter_by_arithmetic_operator_class(top_level_arithmetic_operator_class)
|
||||||
};
|
.split(), level + 1);
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
if self.input.starts_with("|")
|
|
||||||
{
|
|
||||||
unimplemented!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.input.starts_with(")")
|
// Parse arguments of arithmetic infix operations
|
||||||
|
let mut argument_iterator =
|
||||||
|
self.filter_by_arithmetic_operator_class(top_level_arithmetic_operator_class);
|
||||||
|
|
||||||
|
let (first_argument, first_binary_operator) = argument_iterator.next().ok_or_else(||
|
||||||
|
crate::parse::Error::new_expected_term(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))??;
|
||||||
|
let first_argument = TermStr::new(first_argument).parse(level + 1)?;
|
||||||
|
// TODO: improve error handling if the terms between the operators are invalid
|
||||||
|
|
||||||
|
let (accumulator, last_binary_operator) =
|
||||||
|
argument_iterator.try_fold((first_argument, first_binary_operator),
|
||||||
|
|(accumulator, binary_operator), argument|
|
||||||
|
{
|
||||||
|
let (argument, next_binary_operator) = argument?;
|
||||||
|
let argument = TermStr::new(argument).parse(level + 1)?;
|
||||||
|
let binary_operation =
|
||||||
|
crate::BinaryOperation::new(binary_operator, Box::new(accumulator),
|
||||||
|
Box::new(argument));
|
||||||
|
let formula = crate::Term::BinaryOperation(binary_operation);
|
||||||
|
|
||||||
|
Ok((formula, next_binary_operator))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// The last item hasn’t been consumed yet, so it’s safe to unwrap it
|
||||||
|
let last_argument = argument_iterator.remaining_input().unwrap();
|
||||||
|
let last_argument = TermStr::new(last_argument).parse(level + 1)?;
|
||||||
|
let last_binary_operation =
|
||||||
|
crate::BinaryOperation::new(last_binary_operator, Box::new(accumulator),
|
||||||
|
Box::new(last_argument));
|
||||||
|
|
||||||
|
return Ok(crate::Term::BinaryOperation(last_binary_operation));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((number, input)) = number(input)?
|
||||||
|
{
|
||||||
|
if !input.trim().is_empty()
|
||||||
{
|
{
|
||||||
return Some(Err(crate::parse::Error::new_unmatched_parenthesis(
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
crate::parse::error::Location::new(0, Some(1)))));
|
crate::parse::error::Location::new(0, Some(0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
match parenthesized_expression(self.input)
|
return Ok(crate::Term::integer(number as i32));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((identifier, input)) = identifier(input)
|
||||||
|
{
|
||||||
|
match identifier
|
||||||
{
|
{
|
||||||
Ok(Some((_, remaining_input))) =>
|
"inf" =>
|
||||||
{
|
{
|
||||||
self.input = remaining_input;
|
if !input.trim().is_empty()
|
||||||
continue;
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(crate::Term::infimum());
|
||||||
},
|
},
|
||||||
Ok(None) => (),
|
"sup" =>
|
||||||
Err(error) => return Some(Err(error)),
|
|
||||||
}
|
|
||||||
|
|
||||||
match number(self.input)
|
|
||||||
{
|
|
||||||
Ok(Some((_, remaining_input))) =>
|
|
||||||
{
|
{
|
||||||
self.input = remaining_input;
|
if !input.trim().is_empty()
|
||||||
continue;
|
{
|
||||||
}
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
Ok(None) => (),
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
Err(error) => return Some(Err(error)),
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let index_left = self.input.as_ptr() as usize - self.original_input.as_ptr() as usize;
|
return Ok(crate::Term::supremum());
|
||||||
let input_left = self.original_input.split_at(index_left).0.trim_end();
|
},
|
||||||
|
"true" =>
|
||||||
if let Some((_, remaining_input)) = identifier(self.input)
|
|
||||||
{
|
|
||||||
self.input = remaining_input;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((symbol, remaining_input)) = symbol(self.input)
|
|
||||||
{
|
|
||||||
self.input = remaining_input;
|
|
||||||
|
|
||||||
match symbol
|
|
||||||
{
|
{
|
||||||
Symbol::Division => return Some(Ok((input_left, remaining_input,
|
if !input.trim().is_empty()
|
||||||
TermInfixOperator::Divide))),
|
{
|
||||||
Symbol::Exponentiation => return Some(Ok((input_left, remaining_input,
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
TermInfixOperator::Exponentiate))),
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
Symbol::Minus => return Some(Ok((input_left, remaining_input,
|
}
|
||||||
TermInfixOperator::Subtract))),
|
|
||||||
Symbol::Multiplication => return Some(Ok((input_left, remaining_input,
|
|
||||||
TermInfixOperator::Multiply))),
|
|
||||||
Symbol::Percent => return Some(Ok((input_left, remaining_input,
|
|
||||||
TermInfixOperator::Modulo))),
|
|
||||||
Symbol::Plus => return Some(Ok((input_left, remaining_input,
|
|
||||||
TermInfixOperator::Add))),
|
|
||||||
_ => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(Err(crate::parse::Error::new_character_not_allowed(first_character,
|
return Ok(crate::Term::true_());
|
||||||
crate::parse::error::Location::new(0, Some(0)))));
|
},
|
||||||
|
"false" =>
|
||||||
|
{
|
||||||
|
if !input.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(crate::Term::false_());
|
||||||
|
},
|
||||||
|
_ if is_variable_name(identifier) =>
|
||||||
|
{
|
||||||
|
if !input.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement look-up
|
||||||
|
let declaration = crate::VariableDeclaration::new(identifier.to_string());
|
||||||
|
let declaration = std::rc::Rc::new(declaration);
|
||||||
|
return Ok(crate::Term::variable(declaration));
|
||||||
|
},
|
||||||
|
_ if is_function_name(identifier) =>
|
||||||
|
{
|
||||||
|
let function_name = identifier;
|
||||||
|
println!("{} parsing function {}", indentation, function_name);
|
||||||
|
|
||||||
|
let input = input.trim_start();
|
||||||
|
|
||||||
|
// Parse arguments if there are any
|
||||||
|
let (arguments, input) = match parenthesized_expression(input)?
|
||||||
|
{
|
||||||
|
Some((parenthesized_expression, input)) =>
|
||||||
|
{
|
||||||
|
let functor = |token: &_| *token == Token::Symbol(Symbol::Comma);
|
||||||
|
let arguments = Tokens::new_filter(parenthesized_expression, functor).split()
|
||||||
|
.map(|argument| TermStr::new(argument?).parse(level + 1))
|
||||||
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
(arguments, input)
|
||||||
|
}
|
||||||
|
None => (vec![], input),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !input.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement look-up
|
||||||
|
let declaration =
|
||||||
|
crate::FunctionDeclaration::new(function_name.to_string(), arguments.len());
|
||||||
|
let declaration = std::rc::Rc::new(declaration);
|
||||||
|
|
||||||
|
return Ok(crate::Term::function(declaration, arguments));
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: parse negative value
|
||||||
|
|
||||||
|
// Parse parenthesized terms
|
||||||
|
if let Some((parenthesized_expression, input)) = parenthesized_expression(input)?
|
||||||
|
{
|
||||||
|
if !input.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TermStr::new(parenthesized_expression).parse(level + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(crate::parse::Error::new_unexpected_token(
|
||||||
|
crate::parse::error::Location::new(0, Some(0))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SplitTermAtInfixOperator<'i>
|
// TODO: refactor
|
||||||
|
fn exponentiate_inner<'i, T>(mut argument_iterator: T, level: usize)
|
||||||
|
-> Result<Option<crate::Term>, crate::parse::Error>
|
||||||
|
where
|
||||||
|
T: std::iter::Iterator<Item = Result<&'i str, crate::parse::Error>>
|
||||||
{
|
{
|
||||||
infix_operator_iterator: TermInfixOperatorIterator<'i>,
|
match argument_iterator.next()
|
||||||
infix_operator: TermInfixOperator,
|
|
||||||
previous_index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'i> SplitTermAtInfixOperator<'i>
|
|
||||||
{
|
|
||||||
pub fn new(input: &TermStr<'i>, infix_operator: TermInfixOperator)
|
|
||||||
-> Self
|
|
||||||
{
|
{
|
||||||
Self
|
Some(argument) =>
|
||||||
{
|
{
|
||||||
infix_operator_iterator: input.iter_infix_operators(),
|
// TODO: improve error handling if antecedent cannot be parsed
|
||||||
infix_operator,
|
let argument = TermStr::new(argument?).parse(level)?;
|
||||||
previous_index: 0,
|
match exponentiate_inner(argument_iterator, level)?
|
||||||
}
|
{
|
||||||
|
Some(next_argument) => Ok(Some(crate::Term::exponentiate(Box::new(argument),
|
||||||
|
Box::new(next_argument)))),
|
||||||
|
None => Ok(Some(argument)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'i> std::iter::Iterator for SplitTermAtInfixOperator<'i>
|
fn exponentiate<'i, T>(mut argument_iterator: T, level: usize)
|
||||||
|
-> Result<crate::Term, crate::parse::Error>
|
||||||
|
where
|
||||||
|
T: std::iter::Iterator<Item = Result<&'i str, crate::parse::Error>>
|
||||||
{
|
{
|
||||||
type Item = Result<&'i str, crate::parse::Error>;
|
match argument_iterator.next()
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item>
|
|
||||||
{
|
{
|
||||||
loop
|
Some(argument) =>
|
||||||
{
|
{
|
||||||
let (input_left, input_right, infix_operator) =
|
// TODO: improve error handling if antecedent cannot be parsed
|
||||||
match self.infix_operator_iterator.next()
|
let argument = TermStr::new(argument?).parse(level)?;
|
||||||
|
match exponentiate_inner(argument_iterator, level)?
|
||||||
{
|
{
|
||||||
Some(Err(error)) => return Some(Err(error)),
|
Some(next_argument) =>
|
||||||
Some(Ok(infix_operator_iterator_next)) => infix_operator_iterator_next,
|
Ok(crate::Term::exponentiate(Box::new(argument), Box::new(next_argument))),
|
||||||
None => break,
|
None => Err(crate::parse::Error::new_expected_term(
|
||||||
};
|
crate::parse::error::Location::new(0, Some(0)))),
|
||||||
|
|
||||||
if infix_operator == self.infix_operator
|
|
||||||
{
|
|
||||||
// TODO: refactor
|
|
||||||
let index = input_left.as_ptr() as usize
|
|
||||||
+ input_left.len()
|
|
||||||
- self.infix_operator_iterator.original_input.as_ptr() as usize;
|
|
||||||
let split_input = &self.infix_operator_iterator
|
|
||||||
.original_input[self.previous_index..index].trim();
|
|
||||||
self.previous_index = input_right.as_ptr() as usize
|
|
||||||
- self.infix_operator_iterator.original_input.as_ptr() as usize;
|
|
||||||
|
|
||||||
return Some(Ok(split_input));
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
None => Err(crate::parse::Error::new_expected_term(
|
||||||
let remaining_input = self.infix_operator_iterator
|
crate::parse::error::Location::new(0, Some(0)))),
|
||||||
.original_input[self.previous_index..].trim();
|
|
||||||
|
|
||||||
if remaining_input.is_empty()
|
|
||||||
{
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self.previous_index = self.infix_operator_iterator.original_input.len();
|
|
||||||
|
|
||||||
Some(Ok(remaining_input))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,10 @@ pub(crate) enum Keyword
|
|||||||
Exists,
|
Exists,
|
||||||
False,
|
False,
|
||||||
ForAll,
|
ForAll,
|
||||||
|
Infimum,
|
||||||
Not,
|
Not,
|
||||||
Or,
|
Or,
|
||||||
|
Supremum,
|
||||||
True,
|
True,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,8 +27,10 @@ impl std::fmt::Debug for Keyword
|
|||||||
Self::Exists => write!(formatter, "exists"),
|
Self::Exists => write!(formatter, "exists"),
|
||||||
Self::False => write!(formatter, "false"),
|
Self::False => write!(formatter, "false"),
|
||||||
Self::ForAll => write!(formatter, "forall"),
|
Self::ForAll => write!(formatter, "forall"),
|
||||||
|
Self::Infimum => write!(formatter, "inf"),
|
||||||
Self::Not => write!(formatter, "not"),
|
Self::Not => write!(formatter, "not"),
|
||||||
Self::Or => write!(formatter, "or"),
|
Self::Or => write!(formatter, "or"),
|
||||||
|
Self::Supremum => write!(formatter, "sup"),
|
||||||
Self::True => write!(formatter, "true"),
|
Self::True => write!(formatter, "true"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,8 +152,10 @@ pub(crate) fn is_keyword(identifier: &str) -> bool
|
|||||||
| "exists"
|
| "exists"
|
||||||
| "false"
|
| "false"
|
||||||
| "forall"
|
| "forall"
|
||||||
|
| "inf"
|
||||||
| "not"
|
| "not"
|
||||||
| "or"
|
| "or"
|
||||||
|
| "sup"
|
||||||
| "true" => true,
|
| "true" => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -467,7 +473,6 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let input_left = self.original_input[self.previous_index..index_left].trim();
|
let input_left = self.original_input[self.previous_index..index_left].trim();
|
||||||
assert!(!input_left.is_empty());
|
|
||||||
|
|
||||||
self.previous_index = index_right;
|
self.previous_index = index_right;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user