use winnow::combinator::{alt, delimited, opt, preceded, separated};
use winnow::error::StrContext;
use winnow::prelude::*;
use crate::ast::BinaryConnective;
use crate::ast::common::AtomicWord;
use crate::ast::tff::{
DefinedType, TFFAtomicFormula, TFFFormula, TFFLetBody, TFFLetDef, TFFStatement, TFFTerm,
TFFType, TFFTyping, TFFVariable, TypeQuantifier, TypedSymbol,
};
use crate::ast::thf::{LogicProperty, LogicSpecification, LogicValue, NonClassicalOperator};
use crate::lexer::{
PResult, atomic_word, check_cancel, defined_word, distinct_object, number, single_quoted,
system_word, upper_word, ws,
};
use crate::parser::common::{nonassoc_connective, quantifier};
fn tff_equality_op(input: &mut &str) -> PResult<Option<bool>> {
if input.starts_with("!=") {
"!=".parse_next(input)?;
return Ok(Some(true));
}
if input.starts_with("=") && !input.starts_with("=>") {
'='.parse_next(input)?;
return Ok(Some(false));
}
Ok(None)
}
fn term_to_formula<'a>(term: TFFTerm<'a>) -> TFFFormula<'a> {
match term {
TFFTerm::FormulaAsTerm(f) => TFFFormula::Parens(f),
TFFTerm::Parens(t) => TFFFormula::Parens(Box::new(term_to_formula(*t))),
TFFTerm::Variable(v) => TFFFormula::Atomic(TFFAtomicFormula::Variable(v)),
TFFTerm::Function(name, args) => TFFFormula::Atomic(TFFAtomicFormula::Plain(name, args)),
TFFTerm::DefinedFunction(name, args) => {
TFFFormula::Atomic(TFFAtomicFormula::Defined(name, args))
}
TFFTerm::SystemFunction(name, args) => {
TFFFormula::Atomic(TFFAtomicFormula::System(name, args))
}
TFFTerm::Conditional {
condition,
then_branch,
else_branch,
} => TFFFormula::Conditional {
condition,
then_branch: Box::new(term_to_formula(*then_branch)),
else_branch: Box::new(term_to_formula(*else_branch)),
},
TFFTerm::Let { definitions, body } => TFFFormula::Let {
definitions,
body: Box::new(TFFLetBody::Formula(term_to_formula(*body))),
},
other => TFFFormula::Atomic(TFFAtomicFormula::Plain(
AtomicWord::Lower("_term"),
vec![other],
)),
}
}
pub fn tff_statement<'a>(input: &mut &'a str) -> PResult<TFFStatement<'a>> {
alt((
tff_logic_specification.map(TFFStatement::Logic),
delimited(('(', ws), tff_typing, (ws, ')')).map(TFFStatement::Typing),
tff_typing.map(TFFStatement::Typing),
tff_sequent.map(|(l, r)| TFFStatement::Sequent(l, r)),
tff_formula.map(TFFStatement::Logical),
))
.context(StrContext::Label("tff_statement"))
.parse_next(input)
}
fn tff_typing<'a>(input: &mut &'a str) -> PResult<TFFTyping<'a>> {
let symbol = alt((
defined_word.map(TypedSymbol::Defined),
atomic_word.map(TypedSymbol::Atom),
))
.parse_next(input)?;
ws.parse_next(input)?;
':'.parse_next(input)?;
ws.parse_next(input)?;
let typ = tff_top_level_type.parse_next(input)?;
Ok(TFFTyping { symbol, typ })
}
fn tff_sequent<'a>(input: &mut &'a str) -> PResult<(Vec<TFFFormula<'a>>, Vec<TFFFormula<'a>>)> {
let left = tff_formula_tuple.parse_next(input)?;
ws.parse_next(input)?;
"-->".parse_next(input)?;
ws.parse_next(input)?;
let right = tff_formula_tuple.parse_next(input)?;
Ok((left, right))
}
fn tff_logic_specification<'a>(input: &mut &'a str) -> PResult<LogicSpecification<'a>> {
let has_parens = opt('(').parse_next(input)?.is_some();
if has_parens {
ws.parse_next(input)?;
}
let logic_family = tff_logic_key.parse_next(input)?;
ws.parse_next(input)?;
"==".parse_next(input)?;
ws.parse_next(input)?;
let properties = tff_logic_property_list.parse_next(input)?;
if has_parens {
ws.parse_next(input)?;
')'.parse_next(input)?;
}
Ok(LogicSpecification {
logic_family,
properties,
})
}
fn tff_logic_property_list<'a>(input: &mut &'a str) -> PResult<Vec<LogicProperty<'a>>> {
delimited(
('[', ws),
separated(0.., tff_logic_property, (ws, ',', ws)),
(ws, ']'),
)
.parse_next(input)
}
fn tff_logic_property<'a>(input: &mut &'a str) -> PResult<LogicProperty<'a>> {
let key = tff_logic_key.parse_next(input)?;
ws.parse_next(input)?;
"==".parse_next(input)?;
ws.parse_next(input)?;
let value = tff_logic_value.parse_next(input)?;
ws.parse_next(input)?;
match value {
LogicValue::List(values) => {
let props: Vec<LogicProperty<'a>> = values
.into_iter()
.filter_map(|v| match v {
LogicValue::Property { name, value } => Some(LogicProperty::KeyValue {
key: name,
value: *value,
}),
LogicValue::Atom(a) => Some(LogicProperty::KeyValue {
key: a,
value: LogicValue::Atom(a),
}),
_ => None,
})
.collect();
if props.is_empty() {
Ok(LogicProperty::KeyValue {
key,
value: LogicValue::List(vec![]),
})
} else {
Ok(LogicProperty::KeyList { key, values: props })
}
}
other => Ok(LogicProperty::KeyValue { key, value: other }),
}
}
fn tff_logic_key<'a>(input: &mut &'a str) -> PResult<&'a str> {
alt((
|i: &mut &'a str| {
let start = *i;
'$'.parse_next(i)?;
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(i)?;
let len = i.as_ptr() as usize - start.as_ptr() as usize;
Ok(&start[..len])
},
|i: &mut &'a str| {
let word = atomic_word(i)?;
match word {
AtomicWord::Lower(s) => Ok(s),
AtomicWord::SingleQuoted(s) => Ok(s),
}
},
))
.parse_next(input)
}
fn tff_logic_value<'a>(input: &mut &'a str) -> PResult<LogicValue<'a>> {
alt((
tff_logic_value_list.map(LogicValue::List),
tff_logic_value_property,
single_quoted.map(LogicValue::String),
|i: &mut &'a str| {
let start = *i;
'$'.parse_next(i)?;
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(i)?;
let len = i.as_ptr() as usize - start.as_ptr() as usize;
Ok(LogicValue::Atom(&start[..len]))
},
|i: &mut &'a str| {
let word = atomic_word(i)?;
match word {
AtomicWord::Lower(s) => Ok(LogicValue::Atom(s)),
AtomicWord::SingleQuoted(s) => Ok(LogicValue::String(s)),
}
},
))
.parse_next(input)
}
fn tff_logic_value_list<'a>(input: &mut &'a str) -> PResult<Vec<LogicValue<'a>>> {
delimited(
('[', ws),
separated(
0..,
|i: &mut &'a str| {
let v = tff_logic_value(i)?;
ws.parse_next(i)?;
Ok(v)
},
(ws, ',', ws),
),
(ws, ']'),
)
.parse_next(input)
}
fn tff_logic_value_property<'a>(input: &mut &'a str) -> PResult<LogicValue<'a>> {
let name = tff_logic_key.parse_next(input)?;
ws.parse_next(input)?;
"==".parse_next(input)?;
ws.parse_next(input)?;
let value = tff_logic_value.parse_next(input)?;
Ok(LogicValue::Property {
name,
value: Box::new(value),
})
}
fn tff_formula_tuple<'a>(input: &mut &'a str) -> PResult<Vec<TFFFormula<'a>>> {
delimited(
('[', ws),
separated(
0..,
|i: &mut &'a str| {
let f = tff_formula(i)?;
ws.parse_next(i)?;
Ok(f)
},
(ws, ',', ws),
),
(ws, ']'),
)
.parse_next(input)
}
pub fn tff_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
check_cancel(input)?;
tff_binary_formula.parse_next(input)
}
fn tff_binary_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
let left = tff_or_formula.parse_next(input)?;
ws.parse_next(input)?;
let result = opt((nonassoc_connective, ws, tff_or_formula)).parse_next(input)?;
match result {
Some((conn, _, right)) => Ok(TFFFormula::Binary {
left: Box::new(left),
connective: conn,
right: Box::new(right),
}),
None => Ok(left),
}
}
fn tff_or_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
let mut result = tff_and_formula.parse_next(input)?;
loop {
let checkpoint = *input;
ws.parse_next(input)?;
if input.as_bytes().first() != Some(&b'|') {
*input = checkpoint;
break;
}
*input = &input[1..];
ws.parse_next(input)?;
let right = tff_and_formula.parse_next(input)?;
result = TFFFormula::Binary {
left: Box::new(result),
connective: BinaryConnective::Or,
right: Box::new(right),
};
}
Ok(result)
}
fn tff_and_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
let mut result = tff_unary_formula.parse_next(input)?;
loop {
let checkpoint = *input;
ws.parse_next(input)?;
if input.as_bytes().first() != Some(&b'&') {
*input = checkpoint;
break;
}
*input = &input[1..];
ws.parse_next(input)?;
let right = tff_unary_formula.parse_next(input)?;
result = TFFFormula::Binary {
left: Box::new(result),
connective: BinaryConnective::And,
right: Box::new(right),
};
}
Ok(result)
}
fn tff_unary_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
alt((
preceded(('~', ws), tff_unary_formula).map(|f| TFFFormula::Negation(Box::new(f))),
tff_unit_formula,
))
.parse_next(input)
}
fn tff_unit_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
alt((
alt((
tff_quantified_formula,
tff_type_quantified_formula,
tff_infix_or_atomic,
tff_paren_or_infix,
tff_conditional,
tff_let,
tff_nonclassical,
tff_short_box,
tff_short_diamond,
)),
alt((tff_alt_short_box, tff_alt_short_diamond)),
))
.parse_next(input)
}
fn tff_paren_or_infix<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'('.parse_next(input)?;
ws.parse_next(input)?;
let inner_formula = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::FormulaAsTerm(Box::new(inner_formula));
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
None => {
Ok(TFFFormula::Parens(Box::new(inner_formula)))
}
}
}
fn tff_infix_or_atomic<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
let start_char = input
.chars()
.next()
.ok_or_else(|| winnow::error::ErrMode::Backtrack(winnow::error::ContextError::new()))?;
match start_char {
'A'..='Z' => {
let var = upper_word.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::Variable(var);
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
None => {
Ok(TFFFormula::Atomic(TFFAtomicFormula::Variable(var)))
}
}
}
'a'..='z' | '\'' => {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let args: Option<Vec<TFFTerm<'a>>> = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::Function(name, args.unwrap_or_default());
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
None => {
Ok(TFFFormula::Atomic(TFFAtomicFormula::Plain(
name,
args.unwrap_or_default(),
)))
}
}
}
'$' => {
if let Some(rest) = input.strip_prefix("$true")
&& rest
.chars()
.next()
.is_none_or(|c| !c.is_ascii_alphanumeric() && c != '_')
{
*input = rest;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::FormulaAsTerm(Box::new(TFFFormula::Atomic(
TFFAtomicFormula::True,
)));
return Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
});
}
None => return Ok(TFFFormula::Atomic(TFFAtomicFormula::True)),
}
}
if let Some(rest) = input.strip_prefix("$false")
&& rest
.chars()
.next()
.is_none_or(|c| !c.is_ascii_alphanumeric() && c != '_')
{
*input = rest;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::FormulaAsTerm(Box::new(TFFFormula::Atomic(
TFFAtomicFormula::False,
)));
return Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
});
}
None => return Ok(TFFFormula::Atomic(TFFAtomicFormula::False)),
}
}
if input.starts_with("$ite") {
let cond_term = tff_conditional_term.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
Ok(if is_neg {
TFFFormula::Inequality(cond_term, right)
} else {
TFFFormula::Equality(cond_term, right)
})
}
None => {
if let TFFTerm::Conditional {
condition,
then_branch,
else_branch,
} = cond_term
{
Ok(TFFFormula::Conditional {
condition,
then_branch: Box::new(term_to_formula(*then_branch)),
else_branch: Box::new(term_to_formula(*else_branch)),
})
} else {
unreachable!(
"tff_conditional_term should always return TFFTerm::Conditional"
)
}
}
}
}
else if input.starts_with("$let") {
let let_term = tff_let_term.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
Ok(if is_neg {
TFFFormula::Inequality(let_term, right)
} else {
TFFFormula::Equality(let_term, right)
})
}
None => {
Err(winnow::error::ErrMode::Backtrack(
winnow::error::ContextError::new(),
))
}
}
} else {
let name = defined_word.parse_next(input)?;
ws.parse_next(input)?;
let args: Option<Vec<TFFTerm<'a>>> = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::DefinedFunction(name, args.unwrap_or_default());
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
None => {
Ok(TFFFormula::Atomic(TFFAtomicFormula::Defined(
name,
args.unwrap_or_default(),
)))
}
}
}
}
_ if input.starts_with("$$") => {
let name = system_word.parse_next(input)?;
ws.parse_next(input)?;
let args: Option<Vec<TFFTerm<'a>>> = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let left = TFFTerm::SystemFunction(name, args.unwrap_or_default());
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
None => {
Ok(TFFFormula::Atomic(TFFAtomicFormula::System(
name,
args.unwrap_or_default(),
)))
}
}
}
'0'..='9' | '+' | '-' => {
let left = number.map(TFFTerm::Number).parse_next(input)?;
ws.parse_next(input)?;
let is_neg = alt(("!=".value(true), "=".value(false))).parse_next(input)?;
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
'"' => {
let left = distinct_object
.map(TFFTerm::DistinctObject)
.parse_next(input)?;
ws.parse_next(input)?;
let is_neg = alt(("!=".value(true), "=".value(false))).parse_next(input)?;
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
Ok(if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
})
}
_ => Err(winnow::error::ErrMode::Backtrack(
winnow::error::ContextError::new(),
)),
}
}
fn tff_nonclassical<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'{'.parse_next(input)?;
let _prefix = alt(('#', '$')).parse_next(input)?;
let op_name: &str =
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(input)?;
let index = opt(alt((
delimited(
('(', ws, '#'),
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_'),
(ws, ')'),
),
preceded(
':',
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_'),
),
)))
.parse_next(input)?;
'}'.parse_next(input)?;
ws.parse_next(input)?;
let operator = match op_name {
"box" => NonClassicalOperator::Box,
"dia" => NonClassicalOperator::Diamond,
"always" => NonClassicalOperator::Always,
"eventually" => NonClassicalOperator::Eventually,
"knows" => match index {
Some(idx) => NonClassicalOperator::Custom {
name: "knows",
index: Some(idx),
},
None => NonClassicalOperator::Knows,
},
"believes" => match index {
Some(idx) => NonClassicalOperator::Custom {
name: "believes",
index: Some(idx),
},
None => NonClassicalOperator::Believes,
},
_ => NonClassicalOperator::Custom {
name: op_name,
index,
},
};
let formula = alt((
preceded((ws, '@', ws), tff_unary_formula),
delimited(('(', ws), tff_formula, (ws, ')')),
))
.parse_next(input)?;
Ok(TFFFormula::NonClassical {
operator,
formula: Box::new(formula),
})
}
fn tff_short_box<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'['.parse_next(input)?;
let operator = alt((
"..".value(NonClassicalOperator::Box),
'.'.value(NonClassicalOperator::Box),
|i: &mut &'a str| {
'#'.parse_next(i)?;
let name: &str =
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(i)?;
Ok(NonClassicalOperator::ShortBox(Some(name)))
},
))
.parse_next(input)?;
']'.parse_next(input)?;
ws.parse_next(input)?;
let formula = alt((
delimited(('(', ws), tff_formula, (ws, ')')),
tff_unary_formula,
))
.parse_next(input)?;
Ok(TFFFormula::NonClassical {
operator,
formula: Box::new(formula),
})
}
fn tff_short_diamond<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'<'.parse_next(input)?;
let operator = alt((
"..".value(NonClassicalOperator::Diamond),
'.'.value(NonClassicalOperator::Diamond),
|i: &mut &'a str| {
'#'.parse_next(i)?;
let name: &str =
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(i)?;
Ok(NonClassicalOperator::ShortDiamond(Some(name)))
},
))
.parse_next(input)?;
'>'.parse_next(input)?;
ws.parse_next(input)?;
let formula = alt((
delimited(('(', ws), tff_formula, (ws, ')')),
tff_unary_formula,
))
.parse_next(input)?;
Ok(TFFFormula::NonClassical {
operator,
formula: Box::new(formula),
})
}
fn tff_alt_short_box<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'/'.parse_next(input)?;
let operator = alt((
"..".value(NonClassicalOperator::Box),
'.'.value(NonClassicalOperator::Box),
|i: &mut &'a str| {
'#'.parse_next(i)?;
let name: &str =
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(i)?;
Ok(NonClassicalOperator::ShortBox(Some(name)))
},
))
.parse_next(input)?;
'\\'.parse_next(input)?;
ws.parse_next(input)?;
let formula = alt((
delimited(('(', ws), tff_formula, (ws, ')')),
tff_unary_formula,
))
.parse_next(input)?;
Ok(TFFFormula::NonClassical {
operator,
formula: Box::new(formula),
})
}
fn tff_alt_short_diamond<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'\\'.parse_next(input)?;
let operator = alt((
"..".value(NonClassicalOperator::Diamond),
'.'.value(NonClassicalOperator::Diamond),
|i: &mut &'a str| {
'#'.parse_next(i)?;
let name: &str =
winnow::token::take_while(1.., |c: char| c.is_ascii_alphanumeric() || c == '_')
.parse_next(i)?;
Ok(NonClassicalOperator::ShortDiamond(Some(name)))
},
))
.parse_next(input)?;
'/'.parse_next(input)?;
ws.parse_next(input)?;
let formula = alt((
delimited(('(', ws), tff_formula, (ws, ')')),
tff_unary_formula,
))
.parse_next(input)?;
Ok(TFFFormula::NonClassical {
operator,
formula: Box::new(formula),
})
}
fn tff_quantified_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
let q = quantifier.parse_next(input)?;
ws.parse_next(input)?;
'['.parse_next(input)?;
ws.parse_next(input)?;
let vars: Vec<TFFVariable<'a>> =
separated(1.., tff_variable, (ws, ',', ws)).parse_next(input)?;
ws.parse_next(input)?;
']'.parse_next(input)?;
ws.parse_next(input)?;
':'.parse_next(input)?;
ws.parse_next(input)?;
let formula = tff_unary_formula.parse_next(input)?;
Ok(TFFFormula::Quantified {
quantifier: q,
variables: vars,
formula: Box::new(formula),
})
}
fn tff_type_quantified_formula<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
let q = alt((
"!>".value(TypeQuantifier::ForallType),
"?*".value(TypeQuantifier::ExistsType),
))
.parse_next(input)?;
ws.parse_next(input)?;
'['.parse_next(input)?;
ws.parse_next(input)?;
let type_vars: Vec<&'a str> = separated(
1..,
|i: &mut &'a str| {
let v = upper_word(i)?;
ws.parse_next(i)?;
opt((':', ws, "$tType")).parse_next(i)?;
ws.parse_next(i)?;
Ok(v)
},
(ws, ',', ws),
)
.parse_next(input)?;
ws.parse_next(input)?;
']'.parse_next(input)?;
ws.parse_next(input)?;
':'.parse_next(input)?;
ws.parse_next(input)?;
let formula = tff_unary_formula.parse_next(input)?;
Ok(TFFFormula::TypeQuantified {
quantifier: q,
type_variables: type_vars,
formula: Box::new(formula),
})
}
pub fn tff_variable<'a>(input: &mut &'a str) -> PResult<TFFVariable<'a>> {
let name = upper_word.parse_next(input)?;
ws.parse_next(input)?;
let typ = opt(preceded((':', ws), tff_type)).parse_next(input)?;
Ok(TFFVariable { name, typ })
}
fn tff_conditional<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
"$ite".parse_next(input)?;
ws.parse_next(input)?;
'('.parse_next(input)?;
ws.parse_next(input)?;
let condition = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let then_branch = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let else_branch = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
Ok(TFFFormula::Conditional {
condition: Box::new(condition),
then_branch: Box::new(then_branch),
else_branch: Box::new(else_branch),
})
}
fn tff_let<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
"$let".parse_next(input)?;
ws.parse_next(input)?;
'('.parse_next(input)?;
ws.parse_next(input)?;
let type_specs = alt((
tff_let_type_spec.map(|s| vec![s]),
delimited(
('[', ws),
separated(1.., tff_let_type_spec, (ws, ',', ws)),
(ws, ']'),
),
))
.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let bindings = alt((
tff_let_tuple_binding,
tff_let_binding.map(|b| vec![b]),
delimited(
('[', ws),
separated(1.., tff_let_binding, (ws, ',', ws)),
(ws, ']'),
),
))
.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let body = alt((
tff_formula.map(TFFLetBody::Formula),
tff_term.map(TFFLetBody::Term),
))
.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
let definitions = type_specs
.into_iter()
.zip(bindings)
.map(|((name, typ), (_bind_name, value))| TFFLetDef {
symbol: name,
type_args: vec![],
params: vec![],
typ: Some(typ),
definition: value,
})
.collect();
Ok(TFFFormula::Let {
definitions,
body: Box::new(body),
})
}
fn tff_let_type_spec<'a>(input: &mut &'a str) -> PResult<(AtomicWord<'a>, TFFType<'a>)> {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let _params: Option<Vec<&str>> = opt(delimited(
('(', ws),
separated(
0..,
|i: &mut &'a str| {
let v = upper_word(i)?;
ws.parse_next(i)?;
Ok(v)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
ws.parse_next(input)?;
':'.parse_next(input)?;
ws.parse_next(input)?;
let typ = tff_type.parse_next(input)?;
ws.parse_next(input)?;
Ok((name, typ))
}
fn tff_let_tuple_binding<'a>(
input: &mut &'a str,
) -> PResult<Vec<(AtomicWord<'a>, TFFLetBody<'a>)>> {
let names: Vec<AtomicWord<'a>> = delimited(
('[', ws),
separated(
1..,
|i: &mut &'a str| {
let n = atomic_word.parse_next(i)?;
ws.parse_next(i)?;
Ok(n)
},
(ws, ',', ws),
),
(ws, ']'),
)
.parse_next(input)?;
ws.parse_next(input)?;
":=".parse_next(input)?;
ws.parse_next(input)?;
let value = alt((
tff_term.map(TFFLetBody::Term),
tff_formula.map(TFFLetBody::Formula),
))
.parse_next(input)?;
ws.parse_next(input)?;
Ok(names
.into_iter()
.map(|name| (name, value.clone()))
.collect())
}
fn tff_let_binding<'a>(input: &mut &'a str) -> PResult<(AtomicWord<'a>, TFFLetBody<'a>)> {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let _params: Option<Vec<&str>> = opt(delimited(
('(', ws),
separated(
0..,
|i: &mut &'a str| {
let v = upper_word(i)?;
ws.parse_next(i)?;
Ok(v)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
ws.parse_next(input)?;
":=".parse_next(input)?;
ws.parse_next(input)?;
let value = alt((
tff_term.map(TFFLetBody::Term),
tff_formula.map(TFFLetBody::Formula),
))
.parse_next(input)?;
ws.parse_next(input)?;
Ok((name, value))
}
pub fn tff_atomic_formula<'a>(input: &mut &'a str) -> PResult<TFFAtomicFormula<'a>> {
alt((
tff_plain_atomic,
upper_word.map(TFFAtomicFormula::Variable),
tff_defined_atomic,
tff_system_atomic,
"$true".value(TFFAtomicFormula::True),
"$false".value(TFFAtomicFormula::False),
))
.parse_next(input)
}
fn tff_plain_atomic<'a>(input: &mut &'a str) -> PResult<TFFAtomicFormula<'a>> {
let pred = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFAtomicFormula::Plain(pred, args.unwrap_or_default()))
}
fn tff_defined_atomic<'a>(input: &mut &'a str) -> PResult<TFFAtomicFormula<'a>> {
let pred = defined_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFAtomicFormula::Defined(pred, args.unwrap_or_default()))
}
fn tff_system_atomic<'a>(input: &mut &'a str) -> PResult<TFFAtomicFormula<'a>> {
let pred = system_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFAtomicFormula::System(pred, args.unwrap_or_default()))
}
pub fn tff_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
alt((
alt((
upper_word.map(TFFTerm::Variable),
tff_function_term,
number.map(TFFTerm::Number),
distinct_object.map(TFFTerm::DistinctObject),
tff_conditional_term,
tff_let_term,
tff_defined_term,
tff_system_term,
tff_quantified_as_term,
)),
alt((
tff_negation_as_term,
tff_formula_as_term,
tff_tuple,
)),
))
.parse_next(input)
}
fn tff_let_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
"$let".parse_next(input)?;
ws.parse_next(input)?;
'('.parse_next(input)?;
ws.parse_next(input)?;
let type_specs = alt((
tff_let_type_spec.map(|s| vec![s]),
delimited(
('[', ws),
separated(1.., tff_let_type_spec, (ws, ',', ws)),
(ws, ']'),
),
))
.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let bindings = alt((
tff_let_tuple_binding_term,
tff_let_binding_term.map(|b| vec![b]),
delimited(
('[', ws),
separated(1.., tff_let_binding_term, (ws, ',', ws)),
(ws, ']'),
),
))
.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let body = tff_term.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
let definitions = type_specs
.into_iter()
.zip(bindings)
.map(|((name, typ), (_bind_name, value))| TFFLetDef {
symbol: name,
type_args: vec![],
params: vec![],
typ: Some(typ),
definition: value,
})
.collect();
Ok(TFFTerm::Let {
definitions,
body: Box::new(body),
})
}
fn tff_let_tuple_binding_term<'a>(
input: &mut &'a str,
) -> PResult<Vec<(AtomicWord<'a>, TFFLetBody<'a>)>> {
let names: Vec<AtomicWord<'a>> = delimited(
('[', ws),
separated(
1..,
|i: &mut &'a str| {
let n = atomic_word.parse_next(i)?;
ws.parse_next(i)?;
Ok(n)
},
(ws, ',', ws),
),
(ws, ']'),
)
.parse_next(input)?;
ws.parse_next(input)?;
":=".parse_next(input)?;
ws.parse_next(input)?;
let value = alt((
tff_term.map(TFFLetBody::Term),
tff_formula.map(TFFLetBody::Formula),
))
.parse_next(input)?;
ws.parse_next(input)?;
Ok(names
.into_iter()
.map(|name| (name, value.clone()))
.collect())
}
fn tff_let_binding_term<'a>(input: &mut &'a str) -> PResult<(AtomicWord<'a>, TFFLetBody<'a>)> {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let _params: Option<Vec<&str>> = opt(delimited(
('(', ws),
separated(
0..,
|i: &mut &'a str| {
let v = upper_word(i)?;
ws.parse_next(i)?;
Ok(v)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
ws.parse_next(input)?;
":=".parse_next(input)?;
ws.parse_next(input)?;
let value = alt((
tff_term.map(TFFLetBody::Term),
tff_formula.map(TFFLetBody::Formula),
))
.parse_next(input)?;
ws.parse_next(input)?;
Ok((name, value))
}
fn tff_conditional_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
"$ite".parse_next(input)?;
ws.parse_next(input)?;
'('.parse_next(input)?;
ws.parse_next(input)?;
let condition = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let then_branch = tff_term.parse_next(input)?;
ws.parse_next(input)?;
','.parse_next(input)?;
ws.parse_next(input)?;
let else_branch = tff_term.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
Ok(TFFTerm::Conditional {
condition: Box::new(condition),
then_branch: Box::new(then_branch),
else_branch: Box::new(else_branch),
})
}
fn tff_arg_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let left = tff_simple_term.parse_next(input)?;
ws.parse_next(input)?;
let infix_op = tff_equality_op(input)?;
match infix_op {
Some(is_neg) => {
ws.parse_next(input)?;
let right = tff_simple_term.parse_next(input)?;
let formula = if is_neg {
TFFFormula::Inequality(left, right)
} else {
TFFFormula::Equality(left, right)
};
Ok(TFFTerm::FormulaAsTerm(Box::new(formula)))
}
None => {
Ok(left)
}
}
}
fn tff_simple_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
alt((
alt((
upper_word.map(TFFTerm::Variable),
tff_function_term_simple,
number.map(TFFTerm::Number),
distinct_object.map(TFFTerm::DistinctObject),
tff_conditional_term,
tff_let_term,
tff_defined_term_simple,
tff_system_term_simple,
tff_quantified_as_term_simple,
)),
alt((
tff_negation_as_term_simple,
tff_formula_as_term_simple,
tff_tuple_simple,
)),
))
.parse_next(input)
}
fn tff_function_term_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFTerm::Function(name, args.unwrap_or_default()))
}
fn tff_defined_term_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let name = defined_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFTerm::DefinedFunction(name, args.unwrap_or_default()))
}
fn tff_system_term_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let name = system_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFTerm::SystemFunction(name, args.unwrap_or_default()))
}
fn tff_tuple_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
delimited(
('[', ws),
separated(
0..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ']'),
)
.map(TFFTerm::Tuple)
.parse_next(input)
}
fn tff_quantified_as_term_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let f = tff_quantified_formula.parse_next(input)?;
Ok(TFFTerm::FormulaAsTerm(Box::new(f)))
}
fn tff_negation_as_term_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
'~'.parse_next(input)?;
ws.parse_next(input)?;
let f = tff_unary_formula_simple.parse_next(input)?;
Ok(TFFTerm::FormulaAsTerm(Box::new(TFFFormula::Negation(
Box::new(f),
))))
}
fn tff_unary_formula_simple<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
alt((
tff_atomic_formula.map(TFFFormula::Atomic),
tff_quantified_formula,
tff_negation_simple,
tff_conditional,
tff_let,
tff_parens_formula_simple,
))
.parse_next(input)
}
fn tff_negation_simple<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'~'.parse_next(input)?;
ws.parse_next(input)?;
let inner = tff_unary_formula_simple.parse_next(input)?;
Ok(TFFFormula::Negation(Box::new(inner)))
}
fn tff_parens_formula_simple<'a>(input: &mut &'a str) -> PResult<TFFFormula<'a>> {
'('.parse_next(input)?;
ws.parse_next(input)?;
let f = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
Ok(TFFFormula::Parens(Box::new(f)))
}
fn tff_formula_as_term_simple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
'('.parse_next(input)?;
ws.parse_next(input)?;
let f = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
Ok(TFFTerm::FormulaAsTerm(Box::new(f)))
}
fn tff_quantified_as_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let f = tff_quantified_formula.parse_next(input)?;
Ok(TFFTerm::FormulaAsTerm(Box::new(f)))
}
fn tff_negation_as_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
'~'.parse_next(input)?;
ws.parse_next(input)?;
let f = tff_unary_formula.parse_next(input)?;
Ok(TFFTerm::FormulaAsTerm(Box::new(TFFFormula::Negation(
Box::new(f),
))))
}
fn tff_formula_as_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
'('.parse_next(input)?;
ws.parse_next(input)?;
let f = tff_formula.parse_next(input)?;
ws.parse_next(input)?;
')'.parse_next(input)?;
Ok(TFFTerm::FormulaAsTerm(Box::new(f)))
}
fn tff_tuple<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
delimited(
('[', ws),
separated(
0..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ']'),
)
.map(TFFTerm::Tuple)
.parse_next(input)
}
fn tff_function_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFTerm::Function(name, args.unwrap_or_default()))
}
fn tff_defined_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let name = defined_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFTerm::DefinedFunction(name, args.unwrap_or_default()))
}
fn tff_system_term<'a>(input: &mut &'a str) -> PResult<TFFTerm<'a>> {
let name = system_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_arg_term(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
Ok(TFFTerm::SystemFunction(name, args.unwrap_or_default()))
}
pub fn tff_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
alt((tff_mapping_type, tff_arrow_type)).parse_next(input)
}
pub fn tff_top_level_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
alt((tff_quantified_type, tff_type)).parse_next(input)
}
fn tff_quantified_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
"!>".parse_next(input)?;
ws.parse_next(input)?;
'['.parse_next(input)?;
ws.parse_next(input)?;
let vars: Vec<&'a str> = separated(
1..,
|i: &mut &'a str| {
let v = upper_word(i)?;
ws.parse_next(i)?;
opt((':', ws, "$tType", ws)).parse_next(i)?;
Ok(v)
},
(ws, ',', ws),
)
.parse_next(input)?;
ws.parse_next(input)?;
']'.parse_next(input)?;
ws.parse_next(input)?;
':'.parse_next(input)?;
ws.parse_next(input)?;
let typ = tff_type.parse_next(input)?;
Ok(TFFType::Quantified {
variables: vars,
typ: Box::new(typ),
})
}
fn tff_mapping_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
let args = alt((
delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_atomic_type(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, '*', ws),
),
(ws, ')'),
),
tff_atomic_type.map(|t| vec![t]),
))
.parse_next(input)?;
ws.parse_next(input)?;
'>'.parse_next(input)?;
ws.parse_next(input)?;
let result = tff_type.parse_next(input)?;
Ok(TFFType::Function {
args,
result: Box::new(result),
})
}
fn tff_arrow_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
let first = tff_atomic_type.parse_next(input)?;
ws.parse_next(input)?;
let result = opt(preceded(('>', ws), tff_type)).parse_next(input)?;
match result {
Some(ret) => Ok(TFFType::Function {
args: vec![first],
result: Box::new(ret),
}),
None => Ok(first),
}
}
fn tff_atomic_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
alt((
tff_defined_type,
tff_tuple_type,
delimited(('(', ws), tff_type, (ws, ')')).map(|t| TFFType::Parens(Box::new(t))),
upper_word.map(TFFType::Variable),
tff_atomic_type_with_args,
))
.parse_next(input)
}
fn tff_tuple_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
delimited(
('[', ws),
separated(
0..,
|i: &mut &'a str| {
let t = tff_type(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ']'),
)
.map(TFFType::Tuple)
.parse_next(input)
}
fn tff_defined_type<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
alt((
"$tType".value(TFFType::Defined(DefinedType::TType)),
"$int".value(TFFType::Defined(DefinedType::Int)),
"$rat".value(TFFType::Defined(DefinedType::Rat)),
"$real".value(TFFType::Defined(DefinedType::Real)),
"$o".value(TFFType::Defined(DefinedType::O)),
"$i".value(TFFType::Defined(DefinedType::I)),
))
.parse_next(input)
}
fn tff_atomic_type_with_args<'a>(input: &mut &'a str) -> PResult<TFFType<'a>> {
let name = atomic_word.parse_next(input)?;
ws.parse_next(input)?;
let args = opt(delimited(
('(', ws),
separated(
1..,
|i: &mut &'a str| {
let t = tff_type(i)?;
ws.parse_next(i)?;
Ok(t)
},
(ws, ',', ws),
),
(ws, ')'),
))
.parse_next(input)?;
match args {
Some(type_args) => Ok(TFFType::Application(
Box::new(TFFType::Atomic(name)),
type_args,
)),
None => Ok(TFFType::Atomic(name)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tff_type() {
assert!(tff_type.parse_peek("$i").is_ok());
assert!(tff_type.parse_peek("$o").is_ok());
assert!(tff_type.parse_peek("$tType").is_ok());
assert!(tff_type.parse_peek("nat").is_ok());
}
#[test]
fn test_tff_function_type() {
let result = tff_top_level_type.parse_peek("$i > $o");
assert!(result.is_ok());
}
#[test]
fn test_tff_tuple_type() {
let result = tff_type.parse_peek("[ $i, $i ]");
assert!(result.is_ok(), "Failed to parse [ $i, $i ]: {:?}", result);
let result2 = tff_type.parse_peek("[ tt, $i ]");
assert!(result2.is_ok(), "Failed to parse [ tt, $i ]: {:?}", result2);
}
#[test]
fn test_tff_complex_function_type() {
let result = tff_top_level_type.parse_peek("( $i * [ $i, tt, $i ] ) > [ tt, $i ]");
assert!(
result.is_ok(),
"Failed to parse complex function type: {:?}",
result
);
}
#[test]
fn test_tff_formula() {
assert!(tff_formula.parse_peek("p").is_ok());
assert!(tff_formula.parse_peek("![X: $i]: p(X)").is_ok());
assert!(
tff_formula
.parse_peek("![X: nat, Y: nat]: eq(X, Y)")
.is_ok()
);
}
#[test]
fn test_tff_typing() {
let result = tff_statement.parse_peek("nat: $tType");
assert!(result.is_ok());
let result2 = tff_statement.parse_peek("zero: nat");
assert!(result2.is_ok());
}
#[test]
fn test_tff_nested_function_type() {
let result = tff_type.parse_peek("( ( $i * [ $i, tt, $i ] ) > [ tt, $i ] )");
assert!(
result.is_ok(),
"Failed to parse nested function type: {:?}",
result
);
}
}