use crate::jbo_syntax::*;
use crate::jbo_prop::{JboFragment, JboRel, JboTerm, JboModalOp, JboQuantifier, JboPred, JboMex, JboOperator, Texticule};
use crate::logic::Prop;
use crate::parse_m::{ParseState, VariableDomain, Bridi, PreProp, jbo_rel_to_bridi, bridi_to_jbo_vpred, apply_transform_list_to_bridi, apply_transform_list};
pub type JboProp = Prop<JboRel, JboTerm, String, JboModalOp, JboQuantifier>;
fn with_questions_scoped<P, F>(top: bool, state: &mut ParseState, f: F) -> Result<P, String>
where
P: PreProp,
F: FnOnce(&mut ParseState) -> Result<P, String>,
{
let saved_questions = state.questions.clone();
state.questions.clear();
let result = f(state)?;
let result = crate::parse_m::do_questions(top, state, result);
let remaining_questions = std::mem::take(&mut state.questions);
state.questions = saved_questions;
state.questions.extend(remaining_questions);
Ok(result)
}
fn with_questions_scoped_bridi<F>(top: bool, state: &mut ParseState, f: F) -> Result<Bridi, String>
where
F: FnOnce(&mut ParseState) -> Result<Bridi, String>,
{
let saved_questions = state.questions.clone();
state.questions.clear();
let bridi = f(state)?;
let qinfos = crate::parse_m::de_kau(top, state);
let remaining_questions = std::mem::take(&mut state.questions);
state.questions = saved_questions;
state.questions.extend(remaining_questions);
Ok(Box::new(move |args| {
qinfos.iter().cloned().fold(bridi(args), |prop, qinfo| {
crate::parse_m::do_q_info(qinfo, prop)
})
}))
}
#[derive(Clone)]
pub enum JboRelClause {
JRRestrictive(JboPred),
JRIncidental(JboPred),
JRAssign(Result<SumtiAtom, JboTerm>),
}
pub fn replace_last_term_in_prop<F>(f: std::sync::Arc<F>, prop: JboProp) -> JboProp
where
F: Fn(JboTerm) -> JboTerm + Send + Sync + 'static,
{
replace_last_term_in_prop_with_status(f, prop).0
}
fn replace_last_term_in_prop_with_status<F>(f: std::sync::Arc<F>, prop: JboProp) -> (JboProp, bool)
where
F: Fn(JboTerm) -> JboTerm + Send + Sync + 'static,
{
match prop {
Prop::Eet => (Prop::Eet, false),
Prop::Not(p) => {
let (p, changed) = replace_last_term_in_prop_with_status(f, *p);
(Prop::Not(Box::new(p)), changed)
}
Prop::Connected(c, p1, p2) => {
let (p1, changed1) = replace_last_term_in_prop_with_status(f.clone(), *p1);
let (p2, changed2) = replace_last_term_in_prop_with_status(f, *p2);
(Prop::Connected(c, Box::new(p1), Box::new(p2)), changed1 || changed2)
}
Prop::NonLogConnected(c, p1, p2) => {
let (p1, changed1) = replace_last_term_in_prop_with_status(f.clone(), *p1);
let (p2, changed2) = replace_last_term_in_prop_with_status(f, *p2);
(Prop::NonLogConnected(c, Box::new(p1), Box::new(p2)), changed1 || changed2)
}
Prop::Modal(o, p) => {
let (p, changed) = replace_last_term_in_prop_with_status(f, *p);
(Prop::Modal(o, Box::new(p)), changed)
}
Prop::Quantified(q, restriction, body) => {
let changed = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let restriction = restriction.map(|restriction| {
let f = f.clone();
let changed = changed.clone();
std::sync::Arc::new(move |v| {
let (prop, did_change) = replace_last_term_in_prop_with_status(f.clone(), restriction(v));
changed.fetch_or(did_change, std::sync::atomic::Ordering::Relaxed);
prop
}) as std::sync::Arc<dyn Fn(i32) -> JboProp + Send + Sync>
});
let body = {
let f = f.clone();
let changed = changed.clone();
std::sync::Arc::new(move |v| {
let (prop, did_change) = replace_last_term_in_prop_with_status(f.clone(), body(v));
changed.fetch_or(did_change, std::sync::atomic::Ordering::Relaxed);
prop
}) as std::sync::Arc<dyn Fn(i32) -> JboProp + Send + Sync>
};
let prop = Prop::Quantified(q, restriction, body);
if let Prop::Quantified(_, restriction, body) = &prop {
if let Some(restriction) = restriction {
restriction(1);
}
body(1);
};
(prop, changed.load(std::sync::atomic::Ordering::Relaxed))
}
Prop::Rel(r, mut ts) => {
if !ts.is_empty() {
let last = ts.pop().unwrap();
ts.push(f(last));
(Prop::Rel(r, ts), true)
} else {
(Prop::Rel(r, ts), false)
}
}
}
}
pub fn mex_exists() -> Mex {
use crate::jbo_syntax::{Mex, Numeral};
Mex::MexNumeralString(vec![Numeral::PA("su'o".to_string())])
}
pub fn mex_forall() -> Mex {
use crate::jbo_syntax::{Mex, Numeral};
Mex::MexNumeralString(vec![Numeral::PA("ro".to_string())])
}
pub fn null_mex() -> Mex {
use crate::jbo_syntax::{Mex, Numeral};
Mex::MexNumeralString(vec![Numeral::PA("tu'o".to_string())])
}
fn terp_jbo_mex_as_quantifier_from_jbo(m: &JboMex) -> JboQuantifier {
use crate::jbo_prop::JboMex;
if let JboMex::MexNumeralString(numerals) = m {
if numerals.len() == 1 {
if let crate::jbo_syntax::Numeral::PA(cmavo) = &numerals[0] {
match cmavo.as_str() {
"ro" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Forall),
"su'o" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exists),
"no" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(0)),
"pa" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(1)),
"re" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(2)),
"ci" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(3)),
"vo" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(4)),
"mu" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(5)),
"xa" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(6)),
"ze" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(7)),
"bi" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(8)),
"so" => return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(9)),
_ => {}
}
}
}
}
if let JboMex::MexInt(n) = m {
return JboQuantifier::LojQuantifier(crate::logic::LojQuantifier::Exactly(*n));
}
JboQuantifier::MexQuantifier(m.clone())
}
pub fn nonveridicial_pred(p: crate::jbo_prop::JboPred) -> crate::jbo_prop::JboPred {
std::sync::Arc::new(move |t: &JboTerm| {
Prop::Modal(JboModalOp::NonVeridical, Box::new(p(t)))
})
}
pub fn is_discursive_free(free: &Free) -> bool {
matches!(free, Free::Discursive(_))
}
pub fn tu_is_buha(tu: &TanruUnit) -> bool {
if let TanruUnit::TUGOhA(g, _) = tu {
g == "bu'a" || g == "bu'e" || g == "bu'i"
} else {
false
}
}
pub fn statement_frees(stmt: &Statement) -> Vec<Free> {
let mut frees = stmt.frees.clone();
frees.extend(statement1_frees(&stmt.body));
frees
}
pub fn statement1_frees(stmt1: &Statement1) -> Vec<Free> {
match stmt1 {
Statement1::StatementSentence { frees, .. } => frees.clone(),
Statement1::ConnectedStatement(_, s1, s2) => {
let mut result = statement1_frees(s1);
result.extend(statement1_frees(s2));
result
}
Statement1::StatementParas { .. } => vec![],
}
}
pub fn strip_fore_restrictives(rels: &[JboRelClause]) -> (Vec<&JboPred>, Vec<JboRelClause>) {
let mut split = 0;
while matches!(rels.get(split), Some(JboRelClause::JRRestrictive(_))) {
split += 1;
}
let restrictives = rels[..split]
.iter()
.filter_map(|rel| match rel {
JboRelClause::JRRestrictive(pred) => Some(pred),
_ => None,
})
.collect();
(restrictives, rels[split..].to_vec())
}
pub fn segregate_rels(rels: &[JboRelClause]) -> (Vec<&JboPred>, Vec<&JboPred>, Vec<&Result<SumtiAtom, JboTerm>>) {
let mut restrictives = Vec::new();
let mut incidentals = Vec::new();
let mut assignments = Vec::new();
for rel in rels {
match rel {
JboRelClause::JRRestrictive(pred) => restrictives.push(pred),
JboRelClause::JRIncidental(pred) => incidentals.push(pred),
JboRelClause::JRAssign(assign) => assignments.push(assign),
}
}
(restrictives, incidentals, assignments)
}
pub fn parse_connective(conn: &Connective) -> Connective {
conn.clone()
}
pub fn map_rels_in_bridi<F>(f: F, bridi: crate::parse_m::Bridi) -> crate::parse_m::Bridi
where
F: Fn(JboRel) -> JboRel + Send + Sync + 'static,
{
let f = std::sync::Arc::new(f);
Box::new(move |args: &crate::parse_m::Args| {
let prop = bridi(args);
let f = f.clone();
crate::logic::terp_prop(
move |r: &JboRel, ts: &[JboTerm]| Prop::Rel(f(r.clone()), ts.to_vec()),
|o: &JboModalOp| o.clone(),
|q: &JboQuantifier| q.clone(),
&prop,
)
})
}
#[derive(Debug, Clone)]
pub struct SemanticResult {
pub prop: JboProp,
pub veridical: Vec<JboProp>,
pub non_veridical: Vec<JboProp>,
pub side_props: Vec<JboProp>,
pub side_texticules: Vec<Texticule>,
pub lojban_output: String,
}
pub fn eval_text(text: &Text) -> Vec<SemanticResult> {
eval_text_with_options(text, false)
}
pub fn eval_text_with_options(text: &Text, indicator_texticules: bool) -> Vec<SemanticResult> {
eval_text_with_full_parser(text, indicator_texticules)
}
fn eval_text_with_full_parser(text: &Text, indicator_texticules: bool) -> Vec<SemanticResult> {
let mut state = ParseState::new();
state.indicator_texticules = indicator_texticules;
let mut results = vec![];
let all_items: Vec<&FragmentOrStatement> = text.text_paras.iter().flat_map(|p| p.iter()).collect();
for (i, item) in all_items.iter().enumerate() {
match item {
FragmentOrStatement::Statement(stmt) => {
let merged_stmt = if i == 0 && !text.text_frees.is_empty() {
let mut merged_frees = text.text_frees.clone();
merged_frees.extend(stmt.frees.clone());
Statement {
frees: merged_frees,
prenex: stmt.prenex.clone(),
body: stmt.body.clone(),
}
} else {
stmt.clone()
};
if let Some(result) = eval_statement_full(&mut state, &merged_stmt) {
results.push(result);
}
}
FragmentOrStatement::Fragment(frag) => {
if i == 0 && !text.text_frees.is_empty() {
let _ = do_frees(&text.text_frees, &mut state);
}
if let Some(result) = eval_fragment_full(&mut state, frag) {
results.push(result);
}
}
}
}
let side_texticules = state.take_side_texticules();
let side_props = side_texticules_to_props(side_texticules.clone());
let side_texticules = side_texticules.into_iter().map(prop_texticule_to_jbo).collect::<Vec<_>>();
if !side_props.is_empty() {
if let Some(first) = results.first_mut() {
first.side_props = side_props;
first.side_texticules = side_texticules;
first.veridical.clear();
first.non_veridical.clear();
split_side_props(&first.side_props, &mut first.veridical, &mut first.non_veridical);
first.lojban_output = match &first.prop {
Prop::Rel(JboRel::Brivla(name), terms) if name == "fragment" => {
crate::jbo_show::build_lojban_output_from_fragment(terms, &first.side_props)
}
_ => build_lojban_output_from_texticules(&first.prop, &first.side_texticules),
};
}
}
results
}
fn eval_texticules(text: &Text) -> Vec<Texticule> {
let mut state = ParseState::new();
let mut result = Vec::new();
let all_items: Vec<&FragmentOrStatement> = text.text_paras.iter().flat_map(|p| p.iter()).collect();
for (i, item) in all_items.iter().enumerate() {
let item_frees = if i == 0 { &text.text_frees } else { &Vec::new() };
match item {
FragmentOrStatement::Statement(stmt) => {
let merged_stmt = if i == 0 && !item_frees.is_empty() {
let mut merged_frees = item_frees.clone();
merged_frees.extend(stmt.frees.clone());
Statement {
frees: merged_frees,
prenex: stmt.prenex.clone(),
body: stmt.body.clone(),
}
} else {
stmt.clone()
};
if let Some(semantic) = eval_statement_full(&mut state, &merged_stmt) {
result.push(Texticule::TexticuleProp(semantic.prop));
}
}
FragmentOrStatement::Fragment(frag) => {
if i == 0 && !item_frees.is_empty() {
let _ = do_frees(item_frees, &mut state);
}
match frag {
Fragment::FragTerms(terms) => {
let mut bridi_state = crate::parse_m::BridiParseState::new();
state.non_veridical_props.clear();
if let Ok(parsed_terms) = parse_terms(terms, &mut bridi_state, &mut state) {
result.push(Texticule::TexticuleFrag(JboFragment::JboFragTerms(parsed_terms)));
} else {
result.push(Texticule::TexticuleFrag(JboFragment::JboFragUnparsed(frag.clone())));
}
}
_ => result.push(Texticule::TexticuleFrag(JboFragment::JboFragUnparsed(frag.clone()))),
}
}
}
}
let side_texticules = state.take_side_texticules();
let mut with_sides: Vec<Texticule> = side_texticules.into_iter().map(prop_texticule_to_jbo).collect();
with_sides.extend(result);
with_sides
}
fn eval_statement_full(state: &mut ParseState, stmt: &Statement) -> Option<SemanticResult> {
state.non_veridical_props.clear();
let prop = parse_statement(stmt, state).ok()?;
let discursives = statement_frees(stmt)
.into_iter()
.filter(is_discursive_free)
.collect::<Vec<_>>();
let prop = if discursives.is_empty() {
prop
} else {
let sides = process_discursive_frees(&discursives, state).ok()?;
if sides.is_empty() {
prop
} else {
let sides_for_term = sides.clone();
let f = std::sync::Arc::new(move |term| JboTerm::TermWithSides(Box::new(term), sides_for_term.clone()));
let (prop, changed) = replace_last_term_in_prop_with_status(f, prop);
if !changed {
for side in sides {
state.add_side_texticule(prop_texticule_to_parse(side).ok()?);
}
}
prop
}
};
let prop = crate::parse_m::do_questions(true, state, prop);
let prop = state.apply_transforms(prop);
let side_props = vec![];
let veridical = Vec::new();
let non_veridical = Vec::new();
let lojban_output = build_lojban_output_from_prop(&prop, &side_props);
Some(SemanticResult {
prop,
veridical,
non_veridical,
side_props,
side_texticules: Vec::new(),
lojban_output,
})
}
fn eval_sentence_full(state: &mut ParseState, sentence: &Sentence) -> Option<SemanticResult> {
state.non_veridical_props.clear();
let mut bridi_state = crate::parse_m::BridiParseState::new();
let _all_terms = parse_terms(&sentence.terms, &mut bridi_state, state).ok()?;
let bridi = parse_bridi_tail(&sentence.tail, &mut bridi_state, state).ok()?;
let bridi = crate::parse_m::apply_transforms_to_bridi(bridi, state);
let prop = bridi(&bridi_state.arglist.args);
let side_props = vec![];
let veridical = Vec::new();
let non_veridical = Vec::new();
let lojban_output = build_lojban_output_from_prop(&prop, &side_props);
Some(SemanticResult {
prop,
veridical,
non_veridical,
side_props,
side_texticules: Vec::new(),
lojban_output,
})
}
fn prop_texticule_to_prop(texticule: crate::parse_m::Texticule) -> JboProp {
match texticule {
crate::parse_m::Texticule::TexticuleProp(prop) => prop,
crate::parse_m::Texticule::TexticuleSide(_, inner) => prop_texticule_to_prop(*inner),
}
}
fn prop_texticule_to_jbo(texticule: crate::parse_m::Texticule) -> Texticule {
match texticule {
crate::parse_m::Texticule::TexticuleProp(prop) => Texticule::TexticuleProp(prop),
crate::parse_m::Texticule::TexticuleSide(side_type, inner) => {
Texticule::TexticuleSide(side_type, Box::new(prop_texticule_to_jbo(*inner)))
}
}
}
fn prop_texticule_to_parse(texticule: Texticule) -> Result<crate::parse_m::Texticule, String> {
match texticule {
Texticule::TexticuleProp(prop) => Ok(crate::parse_m::Texticule::TexticuleProp(prop)),
Texticule::TexticuleSide(side_type, inner) => Ok(crate::parse_m::Texticule::TexticuleSide(
side_type,
Box::new(prop_texticule_to_parse(*inner)?),
)),
Texticule::TexticuleFrag(_) => Err("Unexpected fragment side texticule".to_string()),
}
}
fn side_texticules_to_props(side_texticules: Vec<crate::parse_m::Texticule>) -> Vec<JboProp> {
side_texticules
.into_iter()
.map(prop_texticule_to_prop)
.collect()
}
fn split_side_props(side_props: &[JboProp], veridical: &mut Vec<JboProp>, non_veridical: &mut Vec<JboProp>) {
for prop in side_props {
match prop {
Prop::Modal(JboModalOp::NonVeridical, inner) => non_veridical.push(inner.as_ref().clone()),
_ => extract_veridical_props(prop, veridical),
}
}
}
fn extract_veridical_props(prop: &JboProp, result: &mut Vec<JboProp>) {
match prop {
Prop::Modal(JboModalOp::NonVeridical, _) => {}
Prop::Rel(_, _) => result.push(prop.clone()),
Prop::Connected(_, p1, p2) => {
extract_veridical_props(p1, result);
extract_veridical_props(p2, result);
}
Prop::Quantified(_, _, _) => {}
_ => {}
}
}
fn extract_non_veridical_pairs(prop: &JboProp, result: &mut Vec<(JboRel, JboTerm)>) {
match prop {
Prop::Modal(JboModalOp::NonVeridical, inner) => {
extract_rel_term_pairs(inner, result);
}
Prop::Connected(_, p1, p2) => {
extract_non_veridical_pairs(p1, result);
extract_non_veridical_pairs(p2, result);
}
Prop::Rel(_, _) => {}
_ => {}
}
}
fn extract_rel_term_pairs(prop: &JboProp, result: &mut Vec<(JboRel, JboTerm)>) {
match prop {
Prop::Rel(rel, terms) => {
if let Some(term) = terms.first() {
result.push((rel.clone(), term.clone()));
}
}
Prop::Connected(_, p1, p2) => {
extract_rel_term_pairs(p1, result);
extract_rel_term_pairs(p2, result);
}
Prop::Quantified(_, _, _) => {}
_ => {}
}
}
fn eval_fragment_full(state: &mut ParseState, frag: &Fragment) -> Option<SemanticResult> {
match frag {
Fragment::FragTerms(terms) => {
let mut bridi_state = crate::parse_m::BridiParseState::new();
let saved_arglist = bridi_state.arglist.clone();
state.non_veridical_props.clear();
let result = match parse_terms(terms, &mut bridi_state, state) {
Ok(parsed_terms) if !parsed_terms.is_empty() => {
let lojban_output = crate::jbo_show::build_lojban_output_from_fragment(
&parsed_terms,
&[]
);
Some(SemanticResult {
prop: Prop::Rel(JboRel::Brivla("fragment".to_string()), parsed_terms.clone()),
veridical: vec![],
non_veridical: vec![],
side_props: vec![],
side_texticules: Vec::new(),
lojban_output,
})
}
Ok(_) => Some(SemanticResult {
prop: Prop::Rel(JboRel::Brivla("fragment".to_string()), vec![]),
veridical: vec![],
non_veridical: vec![],
side_props: vec![],
side_texticules: Vec::new(),
lojban_output: String::new(),
}),
Err(_) => Some(unparsed_fragment_result(frag)),
};
bridi_state.arglist = saved_arglist;
result
}
_ => Some(unparsed_fragment_result(frag)),
}
}
fn unparsed_fragment_result(frag: &Fragment) -> SemanticResult {
let lojban_output = match frag {
Fragment::FragLaName(name) => name.clone(),
Fragment::FragCon(_)
| Fragment::FragPrenex(_)
| Fragment::FragQuantifier(_)
| Fragment::FragNA(_)
| Fragment::FragRels(_)
| Fragment::FragLinks(_)
| Fragment::FragTerms(_) => "li'o".to_string(),
};
SemanticResult {
prop: Prop::Rel(JboRel::Brivla("unparsed-fragment".to_string()), vec![]),
veridical: vec![],
non_veridical: vec![],
side_props: vec![],
side_texticules: Vec::new(),
lojban_output,
}
}
pub fn null_op() -> Operator {
Operator::OpVUhU("ge'a".to_string())
}
fn strip_nulls(ms: Vec<JboMex>) -> Vec<JboMex> {
let mut result = Vec::new();
for m in ms {
match &m {
JboMex::Operation(op, os) if is_null_op(op) => {
result.extend(strip_nulls(os.clone()));
}
_ if is_null_mex(&m) => {
}
_ => {
result.push(m);
}
}
}
result
}
fn is_null_mex(m: &JboMex) -> bool {
matches!(m, JboMex::MexNumeralString(ns) if ns.len() == 1 && matches!(&ns[0], Numeral::PA(s) if s == "tu'o"))
}
fn is_null_op(op: &JboOperator) -> bool {
matches!(op, JboOperator::OpVUhU(s) if s == "ge'a")
}
fn apply_jbo_operator(op: JboOperator, os: Vec<JboMex>) -> JboMex {
match op {
JboOperator::OpPermuted(s, inner_op) => {
let stripped = strip_nulls(os);
let swapped = crate::util::swap_finite_with_default(
null_jbo_mex(),
&stripped,
0,
(s - 1) as usize,
);
apply_jbo_operator(*inner_op, swapped)
}
op if is_null_op(&op) => {
if let Some(JboMex::Operation(inner_op, inner_os)) = os.first() {
let mut merged = inner_os.clone();
let os_clone = os.clone();
merged.extend(os_clone.into_iter().skip(1));
apply_jbo_operator((**inner_op).clone(), merged)
} else {
JboMex::Operation(Box::new(op), strip_nulls(os))
}
}
_ => JboMex::Operation(Box::new(op), strip_nulls(os)),
}
}
fn null_jbo_mex() -> JboMex {
JboMex::MexNumeralString(vec![Numeral::PA("tu'o".to_string())])
}
fn logical_connected_mex_branches(m: &JboMex) -> Option<(crate::jbo_syntax::LogJboConnective, JboMex, JboMex)> {
match m {
JboMex::ConnectedMex(_, Connective::JboConnLog(_, lcon), m1, m2) => {
Some((*lcon, (**m1).clone(), (**m2).clone()))
}
JboMex::Operation(op, args) => match op.as_ref() {
JboOperator::ConnectedOperator(_, Connective::JboConnLog(_, lcon), op1, op2) => Some((
*lcon,
apply_jbo_operator((**op1).clone(), args.clone()),
apply_jbo_operator((**op2).clone(), args.clone()),
)),
_ => args.iter().enumerate().find_map(|(i, arg)| {
let (lcon, left_arg, right_arg) = logical_connected_mex_branches(arg)?;
let mut left_args = args.clone();
left_args[i] = left_arg;
let mut right_args = args.clone();
right_args[i] = right_arg;
Some((
lcon,
apply_jbo_operator((**op).clone(), left_args),
apply_jbo_operator((**op).clone(), right_args),
))
}),
},
_ => None,
}
}
pub fn parse_mex(m: &Mex, state: &mut ParseState) -> Result<JboMex, String> {
let parsed = parse_mex_inner(m, state)?;
Ok(reduce_mex(parsed))
}
fn reduce_mex(m: JboMex) -> JboMex {
match m {
JboMex::Operation(op, ms) => apply_jbo_operator(*op, ms),
_ => m,
}
}
fn parse_mex_inner(m: &Mex, state: &mut ParseState) -> Result<JboMex, String> {
match m {
Mex::ConnectedMex(fore, con @ AbsConnective::JboConnLog(_, _), m1, m2) => {
do_connective(
*fore,
con,
|state| parse_mex_inner(m1, state),
|state| parse_mex_inner(m2, state),
state,
)
}
Mex::ConnectedMex(fore, con @ AbsConnective::JboConnJoik(_, _), m1, m2) => {
let parsed_con = parse_connective(con);
let parsed_m1 = parse_mex_inner(m1, state)?;
let parsed_m2 = parse_mex_inner(m2, state)?;
Ok(JboMex::ConnectedMex(*fore, parsed_con, Box::new(parsed_m1), Box::new(parsed_m2)))
}
Mex::Operation(op, ms) => {
let parsed_op = parse_operator(op, state)?;
let parsed_ms: Result<Vec<_>, _> = ms.iter()
.map(|m| parse_mex_inner(m, state))
.collect();
Ok(JboMex::Operation(Box::new(parsed_op), parsed_ms?))
}
Mex::MexArray(ms) => {
let parsed_ms: Result<Vec<_>, _> = ms.iter()
.map(|m| parse_mex_inner(m, state))
.collect();
Ok(JboMex::MexArray(parsed_ms?))
}
Mex::QualifiedMex(q, m) => {
let parsed_m = parse_mex_inner(m, state)?;
Ok(JboMex::QualifiedMex(q.clone(), Box::new(parsed_m)))
}
Mex::MexSelbri(sb) => {
let vpred = selbri_to_vpred(sb, state)?;
Ok(JboMex::MexSelbri(Box::new(vpred)))
}
Mex::MexSumti(s) => {
let parsed_s = parse_sumti(s, state)?;
Ok(JboMex::MexSumti(Box::new(parsed_s)))
}
Mex::MexInt(n) => Ok(JboMex::MexInt(*n)),
Mex::MexNumeralString(ns) => Ok(JboMex::MexNumeralString(ns.clone())),
Mex::MexLerfuString(ls) => Ok(JboMex::MexLerfuString(ls.clone())),
}
}
pub fn parse_operator(op: &Operator, state: &mut ParseState) -> Result<JboOperator, String> {
match op {
Operator::ConnectedOperator(fore, con @ AbsConnective::JboConnLog(_, _), o1, o2) => {
do_connective(
*fore,
con,
|state| parse_operator(o1, state),
|state| parse_operator(o2, state),
state,
)
}
Operator::ConnectedOperator(fore, con @ AbsConnective::JboConnJoik(_, _), o1, o2) => {
let parsed_con = parse_connective(con);
let parsed_o1 = parse_operator(o1, state)?;
let parsed_o2 = parse_operator(o2, state)?;
Ok(JboOperator::ConnectedOperator(*fore, parsed_con, Box::new(parsed_o1), Box::new(parsed_o2)))
}
Operator::OpPermuted(s, o) => {
let parsed_o = parse_operator(o, state)?;
Ok(JboOperator::OpPermuted(*s, Box::new(parsed_o)))
}
Operator::OpScalarNegated(n, o) => {
let parsed_o = parse_operator(o, state)?;
Ok(JboOperator::OpScalarNegated(n.clone(), Box::new(parsed_o)))
}
Operator::OpMex(m) => {
let parsed_m = parse_mex_inner(m, state)?;
Ok(JboOperator::OpMex(Box::new(parsed_m)))
}
Operator::OpSelbri(sb) => {
let vpred = selbri_to_vpred(sb, state)?;
Ok(JboOperator::OpSelbri(Box::new(vpred)))
}
Operator::OpVUhU(v) => Ok(JboOperator::OpVUhU(v.clone())),
}
}
fn do_connective_prop<F1, F2>(
is_forethought: bool,
con: &Connective,
f1: F1,
f2: F2,
state: &mut ParseState,
) -> Result<JboProp, String>
where
F1: FnOnce(&mut ParseState) -> Result<JboProp, String>,
F2: FnOnce(&mut ParseState) -> Result<JboProp, String>,
{
let mut outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let mut left_state = state.clone();
let mut right_state = state.clone();
let mtag = match con {
Connective::JboConnLog(mtag, _) => mtag.as_ref(),
Connective::JboConnJoik(mtag, _) => mtag.as_ref(),
};
let outer_transform_start = state.pending_prop_transforms.len();
if let Some(tag) = mtag {
let v = quantify_helper(
&crate::jbo_syntax::Mex::MexNumeralString(vec![
crate::jbo_syntax::Numeral::PA("su'o".to_string())
]),
None,
state,
)?;
outer_transforms.extend(state.pending_prop_transforms.split_off(outer_transform_start));
left_state.next_fresh_var = state.next_fresh_var;
left_state.variable_domains = state.variable_domains.clone();
right_state.next_fresh_var = state.next_fresh_var;
right_state.variable_domains = state.variable_domains.clone();
if is_forethought {
let jtag = parse_tag_helper(tag, state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else if is_tense_tag(tag) {
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else {
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v.clone()), &mut left_state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v), &mut right_state);
}
}
let left_prop = f1(&mut left_state)?;
let left_transforms = left_state.pending_prop_transforms.drain(..).collect::<Vec<_>>();
right_state.sumbasti_bindings = left_state.sumbasti_bindings.clone();
right_state.backcount_stack = left_state.backcount_stack.clone();
right_state.bribasti_bindings = left_state.bribasti_bindings.clone();
right_state.next_fresh_var = left_state.next_fresh_var;
right_state.next_fresh_rvar = left_state.next_fresh_rvar;
right_state.variable_domains = left_state.variable_domains.clone();
right_state.next_fresh_constant = left_state.next_fresh_constant;
right_state.referenced_vars = left_state.referenced_vars.clone();
right_state.questions = left_state.questions.clone();
right_state.lambdas = left_state.lambdas.clone();
right_state.side_texticules = left_state.side_texticules.clone();
right_state.non_veridical_props = left_state.non_veridical_props.clone();
let right_prop = f2(&mut right_state)?;
let right_transforms = right_state.pending_prop_transforms.drain(..).collect::<Vec<_>>();
let left_prop = apply_transform_list(left_transforms, left_prop);
let right_prop = apply_transform_list(right_transforms, right_prop);
*state = right_state;
let prop = match con {
Connective::JboConnLog(_, lcon) => crate::jbo_prop::conn_to_fol(lcon, left_prop, right_prop),
Connective::JboConnJoik(_, joik) => crate::jbo_prop::joik_to_fol(joik.clone(), left_prop, right_prop),
};
Ok(apply_transform_list(outer_transforms, prop))
}
trait ConnectiveResult: Sized {
fn combine_connective(is_forethought: bool, con: Connective, left: Self, right: Self) -> Self;
}
impl ConnectiveResult for JboMex {
fn combine_connective(is_forethought: bool, con: Connective, left: Self, right: Self) -> Self {
JboMex::ConnectedMex(is_forethought, con, Box::new(left), Box::new(right))
}
}
impl ConnectiveResult for JboOperator {
fn combine_connective(is_forethought: bool, con: Connective, left: Self, right: Self) -> Self {
JboOperator::ConnectedOperator(is_forethought, con, Box::new(left), Box::new(right))
}
}
fn do_connective<T, F1, F2>(
is_forethought: bool,
con: &Connective,
f1: F1,
f2: F2,
state: &mut ParseState,
) -> Result<T, String>
where
T: ConnectiveResult,
F1: FnOnce(&mut ParseState) -> Result<T, String>,
F2: FnOnce(&mut ParseState) -> Result<T, String>,
{
let mtag = match con {
Connective::JboConnLog(mtag, _) => mtag.as_ref(),
Connective::JboConnJoik(mtag, _) => mtag.as_ref(),
};
let outer_transform_start = state.pending_prop_transforms.len();
let mut outer_transforms = Vec::new();
let mut left_state = state.clone();
let mut right_state = state.clone();
if let Some(tag) = mtag {
let v = quantify_helper(
&crate::jbo_syntax::Mex::MexNumeralString(vec![
crate::jbo_syntax::Numeral::PA("su'o".to_string())
]),
None,
state,
)?;
outer_transforms.extend(state.pending_prop_transforms.split_off(outer_transform_start));
left_state.next_fresh_var = state.next_fresh_var;
left_state.variable_domains = state.variable_domains.clone();
right_state.next_fresh_var = state.next_fresh_var;
right_state.variable_domains = state.variable_domains.clone();
if is_forethought {
let jtag = parse_tag_helper(tag, state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else if is_tense_tag(tag) {
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else {
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v.clone()), &mut left_state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v), &mut right_state);
}
}
let left = f1(&mut left_state)?;
right_state.sumbasti_bindings = left_state.sumbasti_bindings.clone();
right_state.backcount_stack = left_state.backcount_stack.clone();
right_state.bribasti_bindings = left_state.bribasti_bindings.clone();
right_state.next_fresh_var = left_state.next_fresh_var;
right_state.next_fresh_rvar = left_state.next_fresh_rvar;
right_state.variable_domains = left_state.variable_domains.clone();
right_state.next_fresh_constant = left_state.next_fresh_constant;
right_state.referenced_vars = left_state.referenced_vars.clone();
right_state.questions = left_state.questions.clone();
right_state.lambdas = left_state.lambdas.clone();
right_state.side_texticules = left_state.side_texticules.clone();
right_state.non_veridical_props = left_state.non_veridical_props.clone();
let right = f2(&mut right_state)?;
*state = right_state;
state.pending_prop_transforms.splice(0..0, outer_transforms);
Ok(T::combine_connective(is_forethought, parse_connective(con), left, right))
}
fn do_connective_with_bridi<F1, F2>(
is_forethought: bool,
con: &Connective,
f1: F1,
f2: F2,
bridi_state: &mut crate::parse_m::BridiParseState,
state: &mut ParseState,
) -> Result<Bridi, String>
where
F1: FnOnce(&mut crate::parse_m::BridiParseState, &mut ParseState) -> Result<Bridi, String>,
F2: FnOnce(&mut crate::parse_m::BridiParseState, &mut ParseState) -> Result<Bridi, String>,
{
let mut outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let mut left_bridi_state = bridi_state.clone();
let mut left_state = state.clone();
let mut right_bridi_state = bridi_state.clone();
let mut right_state = state.clone();
let mtag = match con {
Connective::JboConnLog(mtag, _) => mtag.as_ref(),
Connective::JboConnJoik(mtag, _) => mtag.as_ref(),
};
let outer_transform_start = state.pending_prop_transforms.len();
if let Some(tag) = mtag {
let v = quantify_helper(
&crate::jbo_syntax::Mex::MexNumeralString(vec![
crate::jbo_syntax::Numeral::PA("su'o".to_string())
]),
None,
state,
)?;
outer_transforms.extend(state.pending_prop_transforms.split_off(outer_transform_start));
left_state.next_fresh_var = state.next_fresh_var;
left_state.variable_domains = state.variable_domains.clone();
right_state.next_fresh_var = state.next_fresh_var;
right_state.variable_domains = state.variable_domains.clone();
if is_forethought {
let jtag = parse_tag_helper(tag, state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else if is_tense_tag(tag) {
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else {
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v.clone()), &mut left_state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v), &mut right_state);
}
}
let left_bridi = f1(&mut left_bridi_state, &mut left_state)?;
let left_args = left_bridi_state.arglist.args.clone();
right_state.sumbasti_bindings = left_state.sumbasti_bindings.clone();
right_state.backcount_stack = left_state.backcount_stack.clone();
right_state.bribasti_bindings = left_state.bribasti_bindings.clone();
right_state.next_fresh_var = left_state.next_fresh_var;
right_state.next_fresh_rvar = left_state.next_fresh_rvar;
right_state.variable_domains = left_state.variable_domains.clone();
right_state.next_fresh_constant = left_state.next_fresh_constant;
right_state.referenced_vars = left_state.referenced_vars.clone();
right_state.questions = left_state.questions.clone();
right_state.lambdas = left_state.lambdas.clone();
right_state.side_texticules = left_state.side_texticules.clone();
right_state.non_veridical_props = left_state.non_veridical_props.clone();
let right_bridi = f2(&mut right_bridi_state, &mut right_state)?;
let right_args = right_bridi_state.arglist.args.clone();
let left_transforms = left_state.pending_prop_transforms.drain(..).collect::<Vec<_>>();
let right_transforms = right_state.pending_prop_transforms.drain(..).collect::<Vec<_>>();
let left_bridi = apply_transform_list_to_bridi(left_bridi, left_transforms);
let right_bridi = apply_transform_list_to_bridi(right_bridi, right_transforms);
*bridi_state = right_bridi_state;
*state = right_state;
let con = con.clone();
Ok(Box::new(move |args| {
let continuation_args = continuation_args_after_branch(args, &right_args);
let left_prop = left_bridi(&crate::parse_m::join_args(&continuation_args, &left_args));
let right_prop = right_bridi(&crate::parse_m::join_args(&continuation_args, &right_args));
let prop = match &con {
Connective::JboConnLog(_, lcon) => crate::jbo_prop::conn_to_fol(lcon, left_prop, right_prop),
Connective::JboConnJoik(_, joik) => crate::jbo_prop::joik_to_fol(joik.clone(), left_prop, right_prop),
};
apply_transform_list(outer_transforms.clone(), prop)
}))
}
fn continuation_args_after_branch(
final_args: &crate::parse_m::Args,
branch_args: &crate::parse_m::Args,
) -> crate::parse_m::Args {
let mut used_branch_terms = branch_args.values().cloned().collect::<Vec<_>>();
let mut continuation_terms = Vec::new();
for (_, term) in sorted_args(final_args) {
if let Some(idx) = used_branch_terms.iter().position(|branch_term| branch_term == term) {
used_branch_terms.remove(idx);
} else {
continuation_terms.push(term.clone());
}
}
continuation_terms
.into_iter()
.enumerate()
.map(|(idx, term)| (crate::parse_m::ArgPos::UnfilledPos(idx as i32), term))
.collect()
}
fn sorted_args(args: &crate::parse_m::Args) -> Vec<(&crate::parse_m::ArgPos, &JboTerm)> {
let mut items = args.iter().collect::<Vec<_>>();
items.sort_by_key(|(a, _)| *a);
items
}
fn is_tense_tag(tag: &Tag) -> bool {
match tag {
Tag::DecoratedTagUnits(dtus) => {
dtus.iter().any(|dtu| matches!(
&dtu.tag_unit,
TagUnit::TenseCmavo(_)
| TagUnit::FAhA { .. }
| TagUnit::TAhE_ZAhO { .. }
))
}
Tag::ConnectedTag(_, _, _) => false,
}
}
fn parse_tag_helper(tag: &Tag, state: &mut ParseState) -> Result<crate::jbo_prop::JboTag, String> {
match tag {
Tag::ConnectedTag(con, tag1, tag2) => {
let jcon = parse_connective_helper(con, state)?;
let jtag1 = parse_tag_helper(tag1, state)?;
let jtag2 = parse_tag_helper(tag2, state)?;
Ok(crate::jbo_prop::JboTag::ConnectedTag(
Box::new(jcon),
Box::new(jtag1),
Box::new(jtag2),
))
}
Tag::DecoratedTagUnits(dtus) => {
let jdtus: Result<Vec<_>, String> = dtus
.iter()
.map(|dtu| {
let jtu = parse_tag_unit_helper(&dtu.tag_unit, state)?;
Ok(crate::jbo_prop::DecoratedTagUnit {
nahe: dtu.tag_nahe.clone(),
se: dtu.tag_se,
nai: dtu.tag_nai,
tag_unit: jtu,
})
})
.collect();
Ok(crate::jbo_prop::JboTag::DecoratedTagUnits(jdtus?))
}
}
}
fn parse_tag_unit_helper(
tu: &TagUnit,
state: &mut ParseState,
) -> Result<crate::jbo_prop::JboTagUnit, String> {
match tu {
TagUnit::TenseCmavo(c) => Ok(crate::jbo_prop::JboTagUnit::TenseCmavo(c.clone())),
TagUnit::CAhA(c) => Ok(crate::jbo_prop::JboTagUnit::CAhA(c.clone())),
TagUnit::BAI(c) => Ok(crate::jbo_prop::JboTagUnit::BAI(c.clone())),
TagUnit::FAhA { faha_has_mohi, faha_cmavo } => {
Ok(crate::jbo_prop::JboTagUnit::FAhA(Some(*faha_has_mohi), faha_cmavo.clone()))
}
TagUnit::TAhE_ZAhO { tahe_zohe_is_space, tahe_zaho_cmavo } => {
Ok(crate::jbo_prop::JboTagUnit::TAhE_ZAhO(*tahe_zohe_is_space, tahe_zaho_cmavo.clone()))
}
TagUnit::ROI { roiroi, roi_is_space, roi_quantifier } => {
let jq = parse_mex_helper(roi_quantifier, state)?;
Ok(crate::jbo_prop::JboTagUnit::ROI(roiroi.clone(), *roi_is_space, jq))
}
TagUnit::FIhO(sb) => {
let vpred = selbri_to_vpred(sb, state)?;
Ok(crate::jbo_prop::JboTagUnit::FIhO(vpred))
}
TagUnit::KI => Ok(crate::jbo_prop::JboTagUnit::KI),
TagUnit::CUhE(c) => Ok(crate::jbo_prop::JboTagUnit::CUhE(c.clone())),
}
}
fn parse_connective_helper(
con: &Connective,
state: &mut ParseState,
) -> Result<crate::jbo_prop::JboConnective, String> {
match con {
Connective::JboConnLog(mtag, lcon) => {
let mtag_parsed = match mtag {
Some(tag) => Some(parse_tag_helper(tag, state)?),
None => None,
};
Ok(crate::jbo_prop::JboConnective::JboConnLog(
mtag_parsed.map(Box::new),
*lcon,
))
}
Connective::JboConnJoik(mtag, joik) => {
let mtag_parsed = match mtag {
Some(tag) => Some(parse_tag_helper(tag, state)?),
None => None,
};
Ok(crate::jbo_prop::JboConnective::JboConnJoik(
mtag_parsed.map(Box::new),
joik.clone(),
))
}
}
}
fn do_modal_helper(op: &crate::jbo_prop::JboModalOp, state: &mut ParseState) {
state.map_prop(crate::parse_m::PropTransform::ApplyModal(op.clone()));
}
fn append_tags(left: crate::jbo_prop::JboTag, right: crate::jbo_prop::JboTag) -> crate::jbo_prop::JboTag {
match (left, right) {
(crate::jbo_prop::JboTag::DecoratedTagUnits(mut left), crate::jbo_prop::JboTag::DecoratedTagUnits(right)) => {
left.extend(right);
crate::jbo_prop::JboTag::DecoratedTagUnits(left)
}
(left, right) => crate::jbo_prop::JboTag::ConnectedTag(
Box::new(crate::jbo_prop::JboConnective::JboConnJoik(None, "jo'u".to_string())),
Box::new(left),
Box::new(right),
),
}
}
fn do_tag_helper(
jtag: &crate::jbo_prop::JboTag,
mt: Option<JboTerm>,
state: &mut ParseState,
) -> Result<(), String> {
match jtag {
crate::jbo_prop::JboTag::ConnectedTag(conn, tag1, tag2) if mt.is_none() => {
match conn.as_ref() {
crate::jbo_prop::JboConnective::JboConnLog(_, _) => {
let start = state.pending_prop_transforms.len();
do_tag_helper(tag1, None, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
do_tag_helper(tag2, None, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
state.map_prop(crate::parse_m::PropTransform::ConnectTagBranches {
conn: conn.as_ref().clone(),
left_transforms,
right_transforms,
});
Ok(())
}
crate::jbo_prop::JboConnective::JboConnJoik(_, _) => {
let modal = crate::jbo_prop::JboModalOp::Tagged(jtag.clone(), mt);
do_modal_helper(&modal, state);
Ok(())
}
}
}
crate::jbo_prop::JboTag::DecoratedTagUnits(dtus) if mt.is_some() => {
let modal = crate::jbo_prop::JboModalOp::Tagged(jtag.clone(), mt);
do_modal_helper(&modal, state);
Ok(())
}
crate::jbo_prop::JboTag::DecoratedTagUnits(dtus) => {
if dtus.is_empty() {
return Ok(());
}
for dtu in dtus {
let scalar = tag_nai_is_scalar(&dtu.tag_unit);
if dtu.nai && !scalar {
state.map_prop(crate::parse_m::PropTransform::Negate);
}
let modal = crate::jbo_prop::JboModalOp::Tagged(
crate::jbo_prop::JboTag::DecoratedTagUnits(vec![
crate::jbo_prop::DecoratedTagUnit {
nahe: dtu.nahe.clone(),
se: dtu.se,
nai: dtu.nai && scalar,
tag_unit: dtu.tag_unit.clone(),
},
]),
None,
);
do_modal_helper(&modal, state);
}
Ok(())
}
_ => {
let modal = crate::jbo_prop::JboModalOp::Tagged(jtag.clone(), mt);
do_modal_helper(&modal, state);
Ok(())
}
}
}
fn tag_nai_is_scalar(tu: &crate::jbo_prop::JboTagUnit) -> bool {
matches!(
tu,
crate::jbo_prop::JboTagUnit::ROI(_, _, _)
| crate::jbo_prop::JboTagUnit::TAhE_ZAhO(_, _)
| crate::jbo_prop::JboTagUnit::CAhA(_)
)
}
fn parse_mex_helper(m: &crate::jbo_syntax::Mex, state: &mut ParseState) -> Result<JboMex, String> {
parse_mex_inner(m, state)
}
fn quantify_helper(
m: &crate::jbo_syntax::Mex,
r: Option<JboPred>,
state: &mut ParseState,
) -> Result<JboTerm, String> {
let jm = parse_mex_helper(m, state)?;
quantify(&jm, r, state)
}
fn do_connective_results<T: ConnectiveResult>(
is_forethought: bool,
con: &Connective,
r1: T,
r2: T,
state: &mut ParseState,
) -> Result<T, String> {
do_connective(
is_forethought,
con,
|_| Ok(r1),
|_| Ok(r2),
state,
)
}
fn selbri_to_vpred(sb: &Selbri, state: &mut ParseState) -> Result<crate::jbo_prop::JboVPred, String> {
let mut bridi_state = crate::parse_m::BridiParseState::new();
bridi_state.is_sub_bridi = true;
let outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let bridi_result = parse_selbri(sb, &mut bridi_state, state);
let transforms = std::mem::take(&mut state.pending_prop_transforms);
state.pending_prop_transforms = outer_transforms;
let bridi = bridi_result?;
let bridi = crate::parse_m::apply_transform_list_to_bridi(bridi, transforms);
parsed_selbri_to_vpred(bridi, bridi_state.arglist.args)
}
fn parsed_selbri_to_vpred(bridi: Bridi, captured_args: crate::parse_m::Args) -> Result<crate::jbo_prop::JboVPred, String> {
let resolved: Bridi = Box::new(move |extra_args: &crate::parse_m::Args| {
let combined_args = crate::parse_m::join_args(extra_args, &captured_args);
bridi(&combined_args)
});
Ok(bridi_to_jbo_vpred(resolved))
}
fn selbri_to_seltau_rel(sb: &Selbri, state: &mut ParseState) -> Result<JboRel, String> {
let vpred = selbri_to_vpred(sb, state)?;
match vpred(&[JboTerm::BoundVar(0)]) {
Prop::Rel(rel, terms) => Ok(JboRel::AppliedRel(Box::new(rel), terms)),
_ => Err("Selbri is not a simple relation".to_string()),
}
}
fn parse_selbri(sb: &Selbri, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
Ok(match sb {
Selbri::Negated(inner_sb) => {
state.map_prop(crate::parse_m::PropTransform::Negate);
parse_selbri(inner_sb, bridi_state, state)?
}
Selbri::TaggedSelbri(tag, inner_sb) => {
let tag_parsed = parse_tag_helper(tag, state)?;
do_bare_tag(&tag_parsed, state)?;
parse_selbri(inner_sb, bridi_state, state)?
}
Selbri::Selbri2(sb2) => parse_selbri2(sb2, bridi_state, state)?,
})
}
fn parse_selbri2(sb2: &Selbri2, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
match sb2 {
Selbri2::SBInverted(sb3, sb2_inner) => {
let seltau_bridi = parse_seltau_selbri2(sb2_inner, bridi_state, state)?;
let tertau_bridi = parse_selbri3(sb3, bridi_state, state)?;
apply_seltau(seltau_bridi, tertau_bridi)
}
Selbri2::Selbri3(sb3) => parse_selbri3(sb3, bridi_state, state),
}
}
fn parse_seltau_selbri2(sb2: &Selbri2, bridi_state: &crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
parse_seltau_bridi(bridi_state, state, |sub_state, state| parse_selbri2(sb2, sub_state, state))
}
fn parse_seltau_selbri3(sb3: &Selbri3, bridi_state: &crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
parse_seltau_bridi(bridi_state, state, |sub_state, state| parse_selbri3(sb3, sub_state, state))
}
fn parse_seltau_bridi<F>(
bridi_state: &crate::parse_m::BridiParseState,
state: &mut ParseState,
f: F,
) -> Result<Bridi, String>
where
F: FnOnce(&mut crate::parse_m::BridiParseState, &mut ParseState) -> Result<Bridi, String>,
{
let mut sub_state = bridi_state.clone();
sub_state.arglist = crate::parse_m::Arglist::new();
sub_state.is_sub_bridi = true;
let transform_start = state.pending_prop_transforms.len();
let bridi = f(&mut sub_state, state)?;
let transforms = state.pending_prop_transforms.split_off(transform_start);
let bridi = crate::parse_m::apply_transform_list_to_bridi(bridi, transforms);
let linkargs = sub_state.arglist.args.clone();
Ok(Box::new(move |extra_args: &crate::parse_m::Args| {
let combined_args = crate::parse_m::join_args(extra_args, &linkargs);
bridi(&combined_args)
}))
}
fn brodv_alias(sb3: &Selbri3) -> Option<TanruUnit> {
if let Selbri3::TanruHead(frees, tu, terms) = sb3 {
if frees.is_empty() && terms.is_empty() {
if let TanruUnit::TUBrivla(bv) = tu.as_ref() {
if matches!(bv.as_str(), "broda" | "brode" | "brodi" | "brodo" | "brodu") {
return Some(TanruUnit::TUBrivla(bv.clone()));
}
}
}
}
None
}
fn bridi_binding_alias(sb3: &Selbri3) -> Option<TanruUnit> {
match sb3 {
Selbri3::BridiBinding(left, right) => brodv_alias(right).or_else(|| brodv_alias(left)),
Selbri3::TanruHead(_, tu, _) => match tu.as_ref() {
TanruUnit::TUSelbri3(inner) => bridi_binding_alias(inner),
_ => None,
},
_ => None,
}
}
fn bridi_binding_primary(sb3: &Selbri3) -> Option<&Selbri3> {
match sb3 {
Selbri3::BridiBinding(left, right) => {
if brodv_alias(right).is_some() {
Some(left)
} else if brodv_alias(left).is_some() {
Some(right)
} else {
None
}
}
Selbri3::TanruHead(_, tu, _) => match tu.as_ref() {
TanruUnit::TUSelbri3(inner) => bridi_binding_primary(inner),
_ => None,
},
_ => None,
}
}
fn parse_selbri3(sb3: &Selbri3, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
match sb3 {
Selbri3::SBTanru(sb_left, sb_right) => {
let alias = bridi_binding_alias(sb_right);
let seltau_bridi = parse_seltau_selbri3(sb_left, bridi_state, state)?;
let tertau_bridi = parse_selbri3(sb_right, bridi_state, state)?;
let bridi = apply_seltau(seltau_bridi, tertau_bridi)?;
if let Some(alias) = alias {
let shared: crate::parse_m::StoredBridi = std::sync::Arc::new(move |args| bridi(args));
state.bribasti_bindings.insert(alias, shared.clone());
Ok(Box::new(move |args| shared(args)))
} else {
Ok(bridi)
}
}
Selbri3::ConnectedSB(_fore, con, sb, sb3) => {
let p = selbri_to_seltau_rel(sb, state)?;
let p_prime = selbri_to_seltau_rel(&crate::jbo_syntax::Selbri::Selbri2(
crate::jbo_syntax::Selbri2::Selbri3(*sb3.clone()),
), state)?;
Ok(jbo_rel_to_bridi(JboRel::TanruConnective(
con.clone(),
Box::new(p),
Box::new(p_prime),
)))
}
Selbri3::BridiBinding(sb3_left, sb3_right) => {
if let Some(alias) = brodv_alias(sb3_right) {
let bridi = parse_selbri3(sb3_left, bridi_state, state)?;
let shared: crate::parse_m::StoredBridi = std::sync::Arc::new(move |args| bridi(args));
state.bribasti_bindings.insert(alias, shared.clone());
Ok(Box::new(move |args| shared(args)))
} else if let Some(alias) = brodv_alias(sb3_left) {
let bridi = parse_selbri3(sb3_right, bridi_state, state)?;
let shared: crate::parse_m::StoredBridi = std::sync::Arc::new(move |args| bridi(args));
state.bribasti_bindings.insert(alias, shared.clone());
Ok(Box::new(move |args| shared(args)))
} else {
let bridi = parse_selbri3(sb3_left, bridi_state, state)?;
let _ = parse_selbri3(sb3_right, bridi_state, state)?;
Ok(bridi)
}
}
Selbri3::ScalarNegatedSB(nahe, sb3_inner) => {
let closed_bridi = parsed_selbri_to_new_selbri(bridi_state, state, |sub_state, state| {
parse_selbri3(sb3_inner, sub_state, state)
})?;
let nahe_owned = nahe.clone();
Ok(map_rels_in_bridi(
move |rel| JboRel::ScalarNegatedRel(nahe_owned.clone(), Box::new(rel)),
closed_bridi,
))
}
Selbri3::TanruHead(frees, tu, terms) => {
crate::parse_m::advance_arg_pos_to_selbri(bridi_state);
let bridi = parse_tu(tu, bridi_state, state)?;
parse_terms(terms, bridi_state, state)?;
do_frees_in_parse_m(frees, state)?;
Ok(bridi)
}
}
}
fn parse_tu(tu: &TanruUnit, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
match tu {
TanruUnit::TUBrivla(_) => {
Ok(crate::parse_m::get_bribasti_binding(&state.bribasti_bindings, tu))
}
TanruUnit::TUZei(vs) => {
let compound = vs.join("-zei-");
Ok(jbo_rel_to_bridi(JboRel::Brivla(compound)))
}
TanruUnit::TUGOhA(goha, _n) => {
if goha == "du" {
Ok(jbo_rel_to_bridi(JboRel::Equal))
} else if tu_is_buha(tu) {
let m = JboMex::MexNumeralString(vec![crate::jbo_syntax::Numeral::PA("su'o".to_string())]);
let rel = do_buha(&m, tu, state)?;
Ok(jbo_rel_to_bridi(rel))
} else {
let bridi = crate::parse_m::get_bribasti_binding(&state.bribasti_bindings, tu);
Ok(bridi)
}
}
TanruUnit::TUBridiQ(kau) => {
let kau_depth = *kau;
let rel = state.add_bridi_question(kau_depth);
Ok(jbo_rel_to_bridi(rel))
}
TanruUnit::TUMe(s) => {
let o = parse_sumti(s, state)?;
Ok(jbo_rel_to_bridi(JboRel::Among(Box::new(o))))
}
TanruUnit::TUMoi(s, moi) => {
let o = parse_sumti(s, state)?;
Ok(jbo_rel_to_bridi(JboRel::Moi(Box::new(o), moi.clone())))
}
TanruUnit::TUAbstraction(crate::jbo_syntax::Abstractor::NegatedAbstractor(inner), ss) => {
state.map_prop(crate::parse_m::PropTransform::Negate);
parse_tu(&TanruUnit::TUAbstraction(*inner.clone(), ss.clone()), bridi_state, state)
}
TanruUnit::TUAbstraction(crate::jbo_syntax::Abstractor::LogConnectedAbstractor(lcon, abs1, abs2), ss) => {
let left = parse_tu(&TanruUnit::TUAbstraction(*abs1.clone(), ss.clone()), bridi_state, state)?;
let right = parse_tu(&TanruUnit::TUAbstraction(*abs2.clone(), ss.clone()), bridi_state, state)?;
let lcon = *lcon;
Ok(Box::new(move |args| {
crate::jbo_prop::conn_to_fol(&lcon, left(args), right(args))
}))
}
TanruUnit::TUAbstraction(crate::jbo_syntax::Abstractor::JoiConnectedAbstractor(joik, abs1, abs2), ss) => {
let left = parse_tu(&TanruUnit::TUAbstraction(*abs1.clone(), ss.clone()), bridi_state, state)?;
let right = parse_tu(&TanruUnit::TUAbstraction(*abs2.clone(), ss.clone()), bridi_state, state)?;
let joik = joik.clone();
Ok(Box::new(move |args| {
crate::jbo_prop::joik_to_fol(joik.clone(), left(args), right(args))
}))
}
TanruUnit::TUAbstraction(abs, ss) => {
let abs_name = match abs {
crate::jbo_syntax::Abstractor::NU(cmavo) => cmavo.clone(),
_ => "nu".to_string(),
};
match abs_name.as_str() {
"ka" | "ni" => {
let mut sub_bridi_state = crate::parse_m::BridiParseState::new();
sub_bridi_state.is_sub_bridi = true;
let outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let bridi_result = with_questions_scoped_bridi(false, state, |state| {
crate::parse_m::shunt_lambdas(state, 1);
parse_subsentence(ss, &mut sub_bridi_state, state)
});
state.pending_prop_transforms = outer_transforms;
let bridi = bridi_result?;
let saved_args = sub_bridi_state.arglist.args.clone();
let partial_bridi: Bridi = Box::new(move |extra_args| {
let joined = crate::parse_m::join_args(extra_args, &saved_args);
bridi(&joined)
});
let vpred = crate::parse_m::bridi_to_jbo_vpred(partial_bridi);
let npred = crate::parse_m::do_lambdas(vpred, state);
Ok(jbo_rel_to_bridi(JboRel::AbsPred(abs_name, npred)))
}
"poi'i" => {
let pred = with_questions_scoped(false, state, |state| subsent_to_pred(ss, state))?;
Ok(jbo_rel_to_bridi(JboRel::AbsPred(abs_name, crate::jbo_prop::pred_to_n_pred(pred))))
}
_ => {
let mut sub_bridi_state = crate::parse_m::BridiParseState::new();
sub_bridi_state.is_sub_bridi = true;
let outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let bridi_result = with_questions_scoped_bridi(false, state, |state| {
parse_subsentence(ss, &mut sub_bridi_state, state)
});
state.pending_prop_transforms.extend(outer_transforms);
let bridi = bridi_result?;
let saved_args = sub_bridi_state.arglist.args.clone();
let prop = bridi(&crate::parse_m::join_args(&crate::parse_m::Args::new(), &saved_args));
Ok(jbo_rel_to_bridi(JboRel::AbsProp(abs_name, Box::new(prop))))
}
}
}
TanruUnit::TUPermuted(n, inner_tu) => {
let inner_bridi = parse_tu(inner_tu, bridi_state, state)?;
let n_copy = *n;
Ok(Box::new(move |args: &crate::parse_m::Args| {
let swapped_args = crate::parse_m::swap_args(
&crate::parse_m::ArgPos::NPos(1),
&crate::parse_m::ArgPos::NPos(n_copy),
args,
);
inner_bridi(&swapped_args)
}))
}
TanruUnit::TUJai(tag_opt, inner_tu) => {
let inner_bridi = parse_tu(inner_tu, bridi_state, state)?;
let jai_bridi = if let Some(tag) = tag_opt {
let jtag = parse_tag_helper(tag, state)?;
crate::parse_m::with_jai_as_tag(jtag, inner_bridi)
} else {
crate::parse_m::with_jai_as_raising(inner_bridi)
};
Ok(Box::new(move |args: &crate::parse_m::Args| {
let swapped_args = crate::parse_m::swap_args(
&crate::parse_m::ArgPos::NPos(1),
&crate::parse_m::ArgPos::JaiPos,
args,
);
jai_bridi(&swapped_args)
}))
}
TanruUnit::TUOperator(op) => {
let jbo_op = parse_operator(op, state)?;
Ok(jbo_rel_to_bridi(JboRel::OperatorRel(Box::new(jbo_op))))
}
TanruUnit::TUXOhI(tag) => {
let jtag = parse_tag_helper(tag, state)?;
Ok(jbo_rel_to_bridi(JboRel::TagRel(jtag)))
}
TanruUnit::TUSelbri3(sb3) => {
parse_selbri3(sb3, bridi_state, state)
}
}
}
fn fill_terms_in_prop(prop: JboProp, terms: &[JboTerm]) -> JboProp {
match prop {
Prop::Rel(rel, _) => Prop::Rel(rel, terms.to_vec()),
Prop::Not(p) => Prop::Not(Box::new(fill_terms_in_prop(*p, terms))),
Prop::Connected(c, p1, p2) => Prop::Connected(
c,
Box::new(fill_terms_in_prop(*p1, terms)),
Box::new(fill_terms_in_prop(*p2, terms)),
),
Prop::NonLogConnected(j, p1, p2) => Prop::NonLogConnected(
j,
Box::new(fill_terms_in_prop(*p1, terms)),
Box::new(fill_terms_in_prop(*p2, terms)),
),
Prop::Modal(m, p) => Prop::Modal(m, Box::new(fill_terms_in_prop(*p, terms))),
Prop::Quantified(q, pred_opt, body_fn) => {
Prop::Quantified(q, pred_opt, body_fn)
}
Prop::Eet => Prop::Eet,
}
}
fn apply_linkargs_to_bridi(bridi: Bridi, linkargs: crate::parse_m::Args) -> Bridi {
Box::new(move |args: &crate::parse_m::Args| {
let combined_args = crate::parse_m::join_args(args, &linkargs);
bridi(&combined_args)
})
}
fn apply_seltau(seltau: Bridi, tertau: Bridi) -> Result<Bridi, String> {
let stpred = crate::parse_m::bridi_to_jbo_vpred(seltau);
let seltau_rel = JboRel::VPredRel(stpred);
Ok(Box::new(move |args: &crate::parse_m::Args| {
let tertau_prop = tertau(args);
apply_tanru_rel_to_prop(seltau_rel.clone(), tertau_prop)
}))
}
fn apply_tanru_rel_to_prop(seltau_rel: JboRel, prop: JboProp) -> JboProp {
match prop {
Prop::Rel(rel, terms) => {
let tanru_rel = JboRel::Tanru(
Box::new(seltau_rel),
Box::new(rel)
);
Prop::Rel(tanru_rel, terms)
}
Prop::Not(p) => Prop::Not(Box::new(apply_tanru_rel_to_prop(seltau_rel, *p))),
Prop::Connected(c, p1, p2) => {
Prop::Connected(
c,
Box::new(apply_tanru_rel_to_prop(seltau_rel.clone(), *p1)),
Box::new(apply_tanru_rel_to_prop(seltau_rel, *p2)),
)
}
Prop::NonLogConnected(j, p1, p2) => {
Prop::NonLogConnected(
j,
Box::new(apply_tanru_rel_to_prop(seltau_rel.clone(), *p1)),
Box::new(apply_tanru_rel_to_prop(seltau_rel, *p2)),
)
}
Prop::Modal(m, p) => Prop::Modal(m, Box::new(apply_tanru_rel_to_prop(seltau_rel, *p))),
Prop::Quantified(q, pred_opt, body_fn) => {
let seltau_for_restriction = seltau_rel.clone();
let seltau_for_body = seltau_rel.clone();
let new_pred = pred_opt.map(move |pred| {
let seltau_rel = seltau_for_restriction.clone();
std::sync::Arc::new(move |v| apply_tanru_rel_to_prop(seltau_rel.clone(), pred(v))) as std::sync::Arc<dyn Fn(i32) -> JboProp + Send + Sync>
});
Prop::Quantified(q, new_pred, std::sync::Arc::new(move |v| apply_tanru_rel_to_prop(seltau_for_body.clone(), body_fn(v))))
}
Prop::Eet => Prop::Eet,
}
}
fn map_rels_in_prop<F>(f: F, prop: JboProp) -> JboProp
where
F: Fn(JboRel) -> JboRel + Clone + Send + Sync + 'static,
{
match prop {
Prop::Rel(rel, terms) => Prop::Rel(f(rel), terms),
Prop::Not(p) => Prop::Not(Box::new(map_rels_in_prop(f.clone(), *p))),
Prop::Connected(c, p1, p2) => Prop::Connected(
c,
Box::new(map_rels_in_prop(f.clone(), *p1)),
Box::new(map_rels_in_prop(f, *p2)),
),
Prop::NonLogConnected(j, p1, p2) => Prop::NonLogConnected(
j,
Box::new(map_rels_in_prop(f.clone(), *p1)),
Box::new(map_rels_in_prop(f, *p2)),
),
Prop::Modal(m, p) => Prop::Modal(m, Box::new(map_rels_in_prop(f, *p))),
Prop::Quantified(q, pred_opt, body_fn) => {
let f_for_restriction = f.clone();
let f_for_body = f.clone();
let new_pred = pred_opt.map(move |pred| {
let f = f_for_restriction.clone();
std::sync::Arc::new(move |v| map_rels_in_prop(f.clone(), pred(v))) as std::sync::Arc<dyn Fn(i32) -> JboProp + Send + Sync>
});
Prop::Quantified(q, new_pred, std::sync::Arc::new(move |v| map_rels_in_prop(f_for_body.clone(), body_fn(v))))
}
Prop::Eet => Prop::Eet,
}
}
fn swap_arg_positions(mut perm: Vec<usize>, i: usize, j: usize) -> Vec<usize> {
if i < perm.len() && j < perm.len() {
perm.swap(i, j);
}
perm
}
fn parse_sumti(s: &Sumti, state: &mut ParseState) -> Result<JboTerm, String> {
let (mut o, jrels) = match s {
Sumti::ConnectedSumti(forethought, conn, sumti1, sumti2, rels) => {
let o = match conn {
Connective::JboConnLog(mtag, lcon) => {
let fresh = state.get_fresh_var(VariableDomain::UnrestrictedDomain);
let start = state.pending_prop_transforms.len();
let (o1, left_transforms, o2, right_transforms) = if let Some(tag) = mtag {
let v = quantify_helper(
&crate::jbo_syntax::Mex::MexNumeralString(vec![
crate::jbo_syntax::Numeral::PA("su'o".to_string())
]),
None,
state,
)?;
let start = state.pending_prop_transforms.len();
if *forethought {
let jtag = parse_tag_helper(tag, state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), state);
let o1 = parse_sumti(sumti1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
do_tag_helper(&jtag, Some(v), state)?;
let o2 = parse_sumti(sumti2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(o1, left_transforms, o2, right_transforms)
} else if is_tense_tag(tag) {
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), state);
let o1 = parse_sumti(sumti1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v), state)?;
let o2 = parse_sumti(sumti2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(o1, left_transforms, o2, right_transforms)
} else {
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v.clone()), state)?;
let o1 = parse_sumti(sumti1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v), state);
let o2 = parse_sumti(sumti2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(o1, left_transforms, o2, right_transforms)
}
} else {
let o1 = parse_sumti(sumti1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
let o2 = parse_sumti(sumti2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(o1, left_transforms, o2, right_transforms)
};
if let JboTerm::Var(n) = &fresh {
state.variable_domains.insert(*n, VariableDomain::FiniteDomain(vec![o1.clone(), o2.clone()]));
}
state.map_prop(crate::parse_m::PropTransform::LogicalConnectBranches {
conn: *lcon,
fresh: fresh.clone(),
left_term: o1,
left_transforms,
right_term: o2,
right_transforms,
});
fresh
}
Connective::JboConnJoik(mtag, joik) => {
if mtag.is_some() {
}
let o1 = parse_sumti(sumti1, state)?;
let o2 = parse_sumti(sumti2, state)?;
JboTerm::JoikedTerms(joik.clone(), Box::new(o1), Box::new(o2))
}
};
let jrels = parse_rels(rels, state)?;
(o, jrels)
}
Sumti::QAtom { frees, quant, rels, atom } => {
let non_discursive: Vec<Free> = frees
.iter()
.filter(|f| !is_discursive_free(f))
.cloned()
.collect();
do_frees_in_parse_m(&non_discursive, state)?;
let mm = if let Some(q) = quant {
Some(parse_mex(q, state)?)
} else {
None
};
let (mut o, mut jrels_from_atom) = match atom.as_ref() {
SumtiAtom::Variable(_) => {
let jrels = parse_rels(rels, state)?;
let (rps, jrels_rest) = strip_fore_restrictives(&jrels);
let rps: Vec<JboPred> = rps.into_iter().cloned().collect();
let o = parse_variable(atom, &rps, mm.as_ref(), state)?;
(o, jrels_rest)
}
SumtiAtom::SumtiQ(kau) => {
let jrels = parse_rels(rels, state)?;
let (rps, jrels_rest) = strip_fore_restrictives(&jrels);
let dom = crate::jbo_prop::and_m_pred(rps.into_iter().cloned().collect());
let o = crate::parse_m::add_sumti_question(*kau, dom.as_ref(), state);
(o, jrels_rest)
}
_ => {
let (o, ijrels) = parse_sumti_atom(atom, state)?;
let mut all_jrels = ijrels;
all_jrels.extend(parse_rels(rels, state)?);
(o, all_jrels)
}
};
if !matches!(atom.as_ref(), SumtiAtom::Variable(_)) {
if let Some(m) = mm.as_ref() {
let is_null = matches!(m, JboMex::MexNumeralString(ref ns)
if ns.len() == 1 && matches!(&ns[0], crate::jbo_syntax::Numeral::PA(s) if s == "tu'o"));
if !is_null {
let (rps, jrels_rest) = strip_fore_restrictives(&jrels_from_atom);
let mut all_preds = vec![crate::jbo_prop::is_among(o.clone())];
all_preds.extend(rps.into_iter().cloned());
crate::parse_m::update_referenced(&o, state);
let and_pred = crate::jbo_prop::and_m_pred(all_preds);
o = quantify(m, and_pred, state)?;
jrels_from_atom = jrels_rest;
}
}
}
let sei_frees: Vec<Free> = frees
.iter()
.filter(|f| is_discursive_free(f))
.cloned()
.collect();
if !sei_frees.is_empty() {
let sei_sides = process_discursive_frees(&sei_frees, state)?;
if !sei_sides.is_empty() {
o = JboTerm::TermWithSides(Box::new(o), sei_sides);
}
}
(o, jrels_from_atom)
}
Sumti::QSelbri { quant, rels, selbri } => {
let m = match quant {
Mex::ConnectedMex(fore, con @ Connective::JboConnLog(Some(_), _), m1, m2) => {
let jm1 = parse_mex(m1, state)?;
let jm2 = parse_mex(m2, state)?;
JboMex::ConnectedMex(*fore, parse_connective(con), Box::new(jm1), Box::new(jm2))
}
_ => parse_mex(quant, state)?,
};
let sr = with_questions_scoped(true, state, |state| selbri_to_pred(selbri, state))?;
let parsed_rels = parse_rels(rels, state)?;
let (rps, jrels) = strip_fore_restrictives(&parsed_rels);
let mut all_preds = vec![sr];
all_preds.extend(rps.into_iter().cloned());
let and_pred = crate::jbo_prop::and_m_pred(all_preds);
let o = quantify(&m, and_pred, state)?;
(o, jrels)
}
};
for jrel in jrels {
o = do_rel(o, jrel, state)?;
}
crate::parse_m::update_referenced(&o, state);
Ok(o)
}
fn selbri_to_pred(sb: &Selbri, state: &mut ParseState) -> Result<JboPred, String> {
let vpred = selbri_to_vpred(sb, state)?;
Ok(crate::jbo_prop::v_pred_to_pred(vpred))
}
fn parse_sumti_atom(sa: &SumtiAtom, state: &mut ParseState) -> Result<(JboTerm, Vec<JboRelClause>), String> {
if gets_ri(sa) {
state.push_backcount();
}
let jrels = match sa {
SumtiAtom::Description(gadri, _mis, _miq, _ssb, rels, _inner_rels) => {
if gadri.len() > 1 && gadri.chars().nth(1) == Some('a') {
vec![]
} else {
parse_rels(rels, state)?
}
}
SumtiAtom::QualifiedSumti(_, rels, _) => parse_rels(rels, state)?,
SumtiAtom::Name(_, rels, _) => parse_rels(rels, state)?,
_ => vec![],
};
let mut o = match sa {
SumtiAtom::Description(
gadri,
inner_sumti,
inner_quant,
selbri_or_sumti,
rels,
inner_rels,
) => {
let extra_irels = if gadri.len() > 1 && gadri.chars().nth(1) == Some('a') {
parse_rels(rels, state)?
} else {
vec![]
};
let mmr: Option<JboPred> = if let Some(iq) = inner_quant {
let m = parse_mex(iq, state)?;
Some(std::sync::Arc::new(move |o: &JboTerm| -> JboProp {
Prop::Rel(
JboRel::Moi(Box::new(JboTerm::Value(m.clone())), "mei".to_string()),
vec![o.clone()],
)
}))
} else {
None
};
let sr = with_questions_scoped(true, state, |state| match selbri_or_sumti {
crate::jbo_syntax::EitherSelbriSumti::Selbri(sb) => selbri_to_pred(sb, state),
crate::jbo_syntax::EitherSelbriSumti::Sumti(s) => {
let parsed_s = parse_sumti(s, state)?;
Ok(crate::jbo_prop::is_among(parsed_s))
}
})?;
let mut all_inner = extra_irels;
all_inner.extend(parse_rels(inner_rels, state)?);
if let Some(is) = inner_sumti {
let inner_term = Term::Sumti(Tagged::Untagged, *is.clone());
if let Some(jrel) = parse_goi_rel("ne", &inner_term, state, |p| JboRelClause::JRIncidental(p))? {
all_inner.push(jrel);
}
}
let mut restrictive_preds = Vec::new();
let mut incidental_preds = Vec::new();
let mut ias = Vec::new();
for rel in all_inner {
match rel {
JboRelClause::JRRestrictive(p) => restrictive_preds.push(p),
JboRelClause::JRIncidental(p) => incidental_preds.push(p),
JboRelClause::JRAssign(a) => ias.push(a),
}
}
let mut xorlo_ps = vec![sr];
if let Some(mmr) = mmr {
xorlo_ps.push(mmr);
}
xorlo_ps.extend(restrictive_preds);
xorlo_ps.extend(incidental_preds);
let gadri_char = gadri.chars().nth(1).unwrap_or('o');
let o = match gadri_char {
'o' => {
let o = state.get_fresh_constant();
crate::parse_m::do_incidentals(o, &xorlo_ps, state)
}
'e' => {
let o = state.get_fresh_constant();
let pred = nonveridicial_pred(crate::jbo_prop::and_pred(xorlo_ps));
crate::parse_m::do_incidentals(o, &[pred], state)
}
'a' => {
JboTerm::PredNamed(crate::jbo_prop::and_pred(xorlo_ps))
}
_ => return Err(format!("Unknown gadri: {}", gadri)),
};
for ia in ias {
let assign = match ia {
Ok(atom) => crate::parse_m::Either::Left(atom),
Err(term) => crate::parse_m::Either::Right(term),
};
crate::parse_m::do_assign(o.clone(), &assign, state);
}
o
}
SumtiAtom::QualifiedSumti(qualifier, _, sumti) => {
let inner = parse_sumti(sumti, state)?;
JboTerm::QualifiedTerm(qualifier.clone(), Box::new(inner))
}
SumtiAtom::MexLi(m) => match m {
Mex::ConnectedMex(forethought, Connective::JboConnLog(mtag, lcon), m1, m2) => {
let fresh = state.get_fresh_var(VariableDomain::UnrestrictedDomain);
let start = state.pending_prop_transforms.len();
let (jm1, left_transforms, jm2, right_transforms) = if let Some(tag) = mtag {
let v = quantify_helper(
&crate::jbo_syntax::Mex::MexNumeralString(vec![
crate::jbo_syntax::Numeral::PA("su'o".to_string())
]),
None,
state,
)?;
let start = state.pending_prop_transforms.len();
if *forethought {
let jtag = parse_tag_helper(tag, state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), state);
let jm1 = parse_mex(m1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
do_tag_helper(&jtag, Some(v), state)?;
let jm2 = parse_mex(m2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(jm1, left_transforms, jm2, right_transforms)
} else if is_tense_tag(tag) {
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), state);
let jm1 = parse_mex(m1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v), state)?;
let jm2 = parse_mex(m2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(jm1, left_transforms, jm2, right_transforms)
} else {
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v.clone()), state)?;
let jm1 = parse_mex(m1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v), state);
let jm2 = parse_mex(m2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(jm1, left_transforms, jm2, right_transforms)
}
} else {
let jm1 = parse_mex(m1, state)?;
let left_transforms = state.pending_prop_transforms.split_off(start);
let jm2 = parse_mex(m2, state)?;
let right_transforms = state.pending_prop_transforms.split_off(start);
(jm1, left_transforms, jm2, right_transforms)
};
if let JboTerm::Var(n) = &fresh {
state.variable_domains.insert(
*n,
VariableDomain::FiniteDomain(vec![
JboTerm::Value(jm1.clone()),
JboTerm::Value(jm2.clone()),
]),
);
}
state.map_prop(crate::parse_m::PropTransform::LogicalConnectBranches {
conn: *lcon,
fresh: fresh.clone(),
left_term: JboTerm::Value(jm1),
left_transforms,
right_term: JboTerm::Value(jm2),
right_transforms,
});
fresh
}
_ => {
let parsed_m = parse_mex(m, state)?;
if let Some((conn, left_m, right_m)) = logical_connected_mex_branches(&parsed_m) {
let fresh = state.get_fresh_var(VariableDomain::FiniteDomain(vec![
JboTerm::Value(left_m.clone()),
JboTerm::Value(right_m.clone()),
]));
state.map_prop(crate::parse_m::PropTransform::LogicalConnectBranches {
conn,
fresh: fresh.clone(),
left_term: JboTerm::Value(left_m),
left_transforms: Vec::new(),
right_term: JboTerm::Value(right_m),
right_transforms: Vec::new(),
});
fresh
} else {
JboTerm::Value(parsed_m)
}
}
},
SumtiAtom::MexMex(m) => JboTerm::TheMex(m.clone()),
SumtiAtom::RelVar(n) => {
state.var_bindings.get(sa).cloned().unwrap_or(JboTerm::Var(*n))
}
SumtiAtom::LambdaVar(lambda, number) => {
state.put_lambda(*lambda, *number)
}
SumtiAtom::Ri(_n) => {
state.get_sumbasti(sa)
}
SumtiAtom::Ra(_cmavo) => {
state.get_sumbasti(sa)
}
SumtiAtom::Assignable(_n) => {
state.get_sumbasti(sa)
}
SumtiAtom::LerfuString(_ls) => {
state.get_sumbasti(sa)
}
SumtiAtom::MainBridiSumbasti(_n) => {
state.get_sumbasti(sa)
}
SumtiAtom::Zohe => {
state.get_fresh_constant()
}
SumtiAtom::NonAnaphoricProsumti(ps) => {
JboTerm::NonAnaph(ps.clone())
}
SumtiAtom::Name(_gadri, _, name) => {
JboTerm::Named(name.clone())
}
SumtiAtom::Quote(text) => {
JboTerm::JboQuote(eval_texticules(text))
}
SumtiAtom::ErrorQuote(vs) => {
JboTerm::JboErrorQuote(vs.clone())
}
SumtiAtom::NonJboQuote(s) => {
JboTerm::JboNonJboQuote(s.clone())
}
SumtiAtom::Word(s) => {
JboTerm::Valsi(s.clone())
}
SumtiAtom::Variable(_n) => {
return Err("Variable should be handled in parse_sumti".to_string());
}
SumtiAtom::SumtiQ(_kau) => {
return Err("SumtiQ should be handled in parse_sumti".to_string());
}
SumtiAtom::SelbriVar => {
JboTerm::Unfilled
}
};
if let SumtiAtom::Description(gadri, ..) | SumtiAtom::Name(gadri, ..) = sa {
if gadri.len() > 2 {
let suffix = &gadri[2..];
if suffix == "i" || suffix == "'i" {
let o_prime = state.get_fresh_constant();
let collector = if suffix == "i" {
JboRel::Brivla("gunma".to_string())
} else {
JboRel::Brivla("selcmi".to_string())
};
let o_clone = o.clone();
let pred: JboPred = std::sync::Arc::new(move |x| {
Prop::Rel(collector.clone(), vec![x.clone(), o_clone.clone()])
});
o = crate::parse_m::do_incidentals(o_prime, &[pred], state);
}
}
}
state.update_sumbasti_with_sumti_atom(sa, &o);
Ok((o, jrels))
}
pub fn gets_ri(sa: &SumtiAtom) -> bool {
crate::jbo_syntax::gets_ri(sa)
}
fn quantify(
m: &JboMex,
r: Option<JboPred>,
state: &mut ParseState,
) -> Result<JboTerm, String> {
let domain = match &r {
Some(pred) => VariableDomain::PredDomain(pred.clone()),
None => VariableDomain::UnrestrictedDomain,
};
let fresh = state.get_fresh_var(domain);
let restriction = r.map(|pred| {
std::sync::Arc::new(move |v: i32| pred(&JboTerm::BoundVar(v))) as std::sync::Arc<dyn Fn(i32) -> crate::parse_m::JboProp + Send + Sync>
});
match m {
JboMex::ConnectedMex(forethought, Connective::JboConnLog(mtag, lcon), m1, m2) => {
if let Some(tag) = mtag {
let jtag = parse_tag_helper(tag, state)?;
let is_tense = is_tense_tag(tag);
let event = if *forethought || is_tense {
state.get_fresh_var(VariableDomain::UnrestrictedDomain)
} else {
fresh.clone()
};
let (event_fresh, left_modal, right_modal) = if *forethought || is_tense {
(
Some(event.clone()),
Some(crate::jbo_prop::JboModalOp::WithEventAs(event.clone())),
Some(crate::jbo_prop::JboModalOp::Tagged(jtag, Some(event.clone()))),
)
} else {
(
None,
Some(crate::jbo_prop::JboModalOp::Tagged(jtag, Some(event.clone()))),
Some(crate::jbo_prop::JboModalOp::WithEventAs(event.clone())),
)
};
state.map_prop(crate::parse_m::PropTransform::ConnectQuantifyTagged {
conn: *lcon,
fresh: fresh.clone(),
left_quant: terp_jbo_mex_as_quantifier_from_jbo(m1),
right_quant: terp_jbo_mex_as_quantifier_from_jbo(m2),
restriction,
event_fresh,
left_modal,
right_modal,
});
} else {
state.map_prop(crate::parse_m::PropTransform::ConnectQuantify {
conn: *lcon,
fresh: fresh.clone(),
left_quant: terp_jbo_mex_as_quantifier_from_jbo(m1),
right_quant: terp_jbo_mex_as_quantifier_from_jbo(m2),
restriction,
});
}
}
_ => {
state.map_prop(crate::parse_m::PropTransform::Quantify(
fresh.clone(),
terp_jbo_mex_as_quantifier_from_jbo(m),
restriction,
));
}
}
Ok(fresh)
}
fn rquantify(
m: &JboMex,
state: &mut ParseState,
) -> Result<JboRel, String> {
let fresh = state.get_fresh_rvar();
let quantifier = terp_jbo_mex_as_quantifier_from_jbo(m);
let rel_quantifier = JboQuantifier::RelQuantifier(Box::new(quantifier));
state.map_prop(crate::parse_m::PropTransform::RQuantify(
fresh.clone(),
rel_quantifier,
));
Ok(fresh)
}
fn parse_rels(rels: &[RelClause], state: &mut ParseState) -> Result<Vec<JboRelClause>, String> {
let mut result = Vec::new();
for rel in rels {
if let Some(jrel) = parse_rel(rel, state)? {
result.push(jrel);
}
}
Ok(result)
}
fn parse_rel(rel: &RelClause, state: &mut ParseState) -> Result<Option<JboRelClause>, String> {
match rel {
RelClause::Restrictive(ss) => {
let pred = subsent_to_pred(ss, state)?;
Ok(Some(JboRelClause::JRRestrictive(pred)))
}
RelClause::Descriptive(ss) => {
let pred = subsent_to_pred(ss, state)?;
Ok(Some(JboRelClause::JRRestrictive(nonveridicial_pred(pred))))
}
RelClause::Incidental(ss) => {
let pred = subsent_to_pred(ss, state)?;
Ok(Some(JboRelClause::JRIncidental(pred)))
}
RelClause::RestrictiveGOI(goi, term) => {
parse_goi_rel(goi, term, state, |p| JboRelClause::JRRestrictive(p))
}
RelClause::IncidentalGOI(goi, term) => {
parse_goi_rel(goi, term, state, |p| JboRelClause::JRIncidental(p))
}
RelClause::Assignment(term) => {
parse_assignment_rel(term, state)
}
}
}
fn subsent_to_pred(ss: &Subsentence, state: &mut ParseState) -> Result<JboPred, String> {
let fresh = state.get_fresh_var(VariableDomain::UnrestrictedDomain);
let mut bridi_state = crate::parse_m::BridiParseState::new();
let outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let old_var_bindings = state.var_bindings.clone();
state.var_bindings = crate::parse_m::set_shunting(
&|n| SumtiAtom::RelVar(n as i32),
fresh.clone(),
&state.var_bindings,
);
let bridi_result = parse_subsentence(ss, &mut bridi_state, state);
state.var_bindings = old_var_bindings;
state.pending_prop_transforms.extend(outer_transforms);
let bridi = bridi_result?;
let reffed = match &fresh {
JboTerm::Var(n) => state.referenced(*n),
_ => return Err("bad fresh var".to_string()),
};
let bridi = crate::parse_m::partially_resolve_bridi(bridi, &bridi_state.arglist.args);
let fresh_clone = fresh.clone();
Ok(std::sync::Arc::new(move |o: &JboTerm| {
let args = if reffed {
crate::parse_m::Args::new()
} else {
[(crate::parse_m::ArgPos::UnfilledPos(0), fresh_clone.clone())].into_iter().collect()
};
let prop = bridi(&args);
crate::jbo_prop::sub_term(&fresh_clone, o, prop)
}))
}
fn parse_subsentence(ss: &Subsentence, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
do_frees_in_parse_m(&ss.frees, state)?;
parse_prenex_terms(&ss.prenex, bridi_state, state)?;
parse_sentence(&ss.sentence, bridi_state, state)
}
fn parse_sentence(s: &Sentence, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
parse_terms(&s.terms, bridi_state, state)?;
let bridi = parse_bridi_tail(&s.tail, bridi_state, state)?;
Ok(crate::parse_m::apply_transforms_to_bridi(bridi, state))
}
fn parse_bridi_tail(bt: &BridiTail, bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Bridi, String> {
match bt {
BridiTail::GekSentence(gs) => {
match gs.as_ref() {
GekSentence::ConnectedGS(conn, subsentence1, subsentence2, tail_terms) => {
let result = do_connective_with_bridi(
true, conn,
|bridi_state, state| parse_subsentence(subsentence1, bridi_state, state),
|bridi_state, state| parse_subsentence(subsentence2, bridi_state, state),
bridi_state,
state,
)?;
parse_terms(tail_terms, bridi_state, state)?;
Ok(result)
}
GekSentence::NegatedGS(inner_gs) => {
state.map_prop(crate::parse_m::PropTransform::Negate);
parse_bridi_tail(&BridiTail::GekSentence(inner_gs.clone()), bridi_state, state)
}
GekSentence::TaggedGS(tag, gek_sentence) => {
let tag_parsed = parse_tag_helper(tag, state)?;
do_bare_tag(&tag_parsed, state)?;
parse_bridi_tail(&BridiTail::GekSentence(gek_sentence.clone()), bridi_state, state)
}
}
}
BridiTail::ConnectedBT(conn, bridi_tail1, bridi_tail2, tail_terms) => {
let result = do_connective_with_bridi(
false,
conn,
|bridi_state, state| parse_bridi_tail(bridi_tail1, bridi_state, state),
|bridi_state, state| parse_bridi_tail(bridi_tail2, bridi_state, state),
bridi_state,
state,
)?;
parse_terms(tail_terms, bridi_state, state)?;
Ok(result)
}
BridiTail::BridiTail3(selbri, tail_terms) => {
match selbri {
Selbri::Negated(sb) => {
state.map_prop(crate::parse_m::PropTransform::Negate);
parse_bridi_tail(
&BridiTail::BridiTail3(*sb.clone(), tail_terms.clone()),
bridi_state,
state,
)
}
Selbri::TaggedSelbri(tag, inner_sb) => {
let tag_parsed = parse_tag_helper(tag, state)?;
do_bare_tag(&tag_parsed, state)?;
parse_bridi_tail(
&BridiTail::BridiTail3(*inner_sb.clone(), tail_terms.clone()),
bridi_state,
state,
)
}
Selbri::Selbri2(sb2) => {
match sb2 {
Selbri2::SBInverted(selbri3, selbri2) => {
parse_inverted_bridi_tail(selbri3, selbri2, tail_terms, bridi_state, state)
}
Selbri2::Selbri3(sb3) => {
if let (Some(alias), Some(primary)) = (bridi_binding_alias(sb3), bridi_binding_primary(sb3)) {
let bridi = parse_selbri3(primary, bridi_state, state)?;
parse_terms(tail_terms, bridi_state, state)?;
let captured_args = bridi_state.arglist.args.clone();
let shared: crate::parse_m::StoredBridi = std::sync::Arc::new(move |args| {
let combined_args = crate::parse_m::join_args(args, &captured_args);
bridi(&combined_args)
});
state.bribasti_bindings.insert(alias, shared.clone());
Ok(Box::new(move |args| shared(args)))
} else {
let bridi = parse_selbri(selbri, bridi_state, state)?;
parse_terms(tail_terms, bridi_state, state)?;
Ok(bridi)
}
}
}
}
}
}
}
}
fn parse_inverted_bridi_tail(
sb3: &Selbri3,
sb2: &Selbri2,
tail_terms: &[Term],
bridi_state: &mut crate::parse_m::BridiParseState,
state: &mut ParseState,
) -> Result<Bridi, String> {
let tertau = parse_selbri3(sb3, bridi_state, state)?;
let seltau = parse_seltau_bridi(bridi_state, state, |sub_state, state| {
parse_inverted_seltau_bridi(sb2, tail_terms, sub_state, state)
})?;
apply_seltau(seltau, tertau)
}
fn parse_inverted_seltau_bridi(
sb2: &Selbri2,
tail_terms: &[Term],
bridi_state: &mut crate::parse_m::BridiParseState,
state: &mut ParseState,
) -> Result<Bridi, String> {
match sb2 {
Selbri2::SBInverted(sb3_inner, sb2_inner) => {
let tertau = parse_selbri3(sb3_inner, bridi_state, state)?;
let seltau = parse_inverted_seltau_bridi(sb2_inner, tail_terms, bridi_state, state)?;
apply_seltau(seltau, tertau)
}
Selbri2::Selbri3(sb3_inner) => {
let wrapped = Selbri::Selbri2(Selbri2::Selbri3(Selbri3::TanruHead(
Vec::new(),
Box::new(TanruUnit::TUSelbri3(sb3_inner.clone())),
tail_terms.to_vec(),
)));
parse_selbri(&wrapped, bridi_state, state)
}
}
}
fn do_bare_tag(tag: &crate::jbo_prop::JboTag, state: &mut ParseState) -> Result<(), String> {
do_tag_helper(tag, None, state)
}
fn parse_goi_rel<F>(
goi: &str,
term: &Term,
state: &mut ParseState,
wrapper: F,
) -> Result<Option<JboRelClause>, String>
where
F: Fn(JboPred) -> JboRelClause,
{
let mut rel_bridi_state = crate::parse_m::BridiParseState::new();
let rets = crate::parse_m::ignoring_args(&mut rel_bridi_state, |bridi_state| {
parse_term(term, bridi_state, state)
})?;
match rets.into_iter().next() {
Some(Either::Right(o)) => {
let rel = match goi {
"pe" | "ne" => JboRel::Brivla("srana".to_string()),
"po'u" | "no'u" => JboRel::Equal,
"po" => JboRel::Tanru(
Box::new(JboRel::VPredRel(std::sync::Arc::new(|os: &[JboTerm]| {
Prop::Rel(JboRel::Brivla("steci".to_string()), os.to_vec())
}))),
Box::new(JboRel::Brivla("srana".to_string())),
),
"po'e" => JboRel::Tanru(
Box::new(JboRel::VPredRel(std::sync::Arc::new(|os: &[JboTerm]| {
Prop::Rel(JboRel::Brivla("jinzi".to_string()), os.to_vec())
}))),
Box::new(JboRel::Brivla("srana".to_string())),
),
_ => return Ok(None),
};
let pred = std::sync::Arc::new(move |x: &JboTerm| {
Prop::Rel(rel.clone(), vec![x.clone(), o.clone()])
});
Ok(Some(wrapper(pred)))
}
Some(Either::Left((jbotag, mo))) => {
let pred = std::sync::Arc::new(move |x: &JboTerm| {
Prop::Rel(
JboRel::TagRel(jbotag.clone()),
vec![mo.clone().unwrap_or(JboTerm::Unfilled), x.clone()],
)
});
Ok(Some(wrapper(pred)))
}
_ => Ok(None),
}
}
fn parse_assignment_rel(term: &Term, state: &mut ParseState) -> Result<Option<JboRelClause>, String> {
if let Term::Sumti(Tagged::Untagged, Sumti::QAtom { atom, .. }) = term {
if is_assignable_atom(atom) {
return Ok(Some(JboRelClause::JRAssign(Ok((**atom).clone()))));
}
}
let mut rel_bridi_state = crate::parse_m::BridiParseState::new();
let rets = crate::parse_m::ignoring_args(&mut rel_bridi_state, |bridi_state| {
parse_term(term, bridi_state, state)
})?;
for ret in rets {
if let Either::Right(o) = ret {
return Ok(Some(JboRelClause::JRAssign(Err(o))));
}
}
Ok(None)
}
fn is_assignable_atom(atom: &SumtiAtom) -> bool {
matches!(
atom,
SumtiAtom::Assignable(_) | SumtiAtom::LerfuString(_) | SumtiAtom::Name(_, _, _)
)
}
fn do_rel(o: JboTerm, jrel: JboRelClause, state: &mut ParseState) -> Result<JboTerm, String> {
match jrel {
JboRelClause::JRIncidental(p) => {
let stripped = crate::jbo_prop::strip_term_sides(&o);
let preds: Vec<JboPred> = vec![p];
let result = crate::parse_m::do_incidentals(stripped, &preds, state);
Ok(crate::jbo_prop::re_wrap_term_sides(&o, result))
}
JboRelClause::JRRestrictive(p) => {
let o_prime = state.get_fresh_constant();
let stripped = crate::jbo_prop::strip_term_sides(&o);
let is_among_pred = crate::jbo_prop::is_among(stripped);
let preds: Vec<JboPred> = vec![p, is_among_pred];
let result = crate::parse_m::do_incidentals(o_prime, &preds, state);
Ok(result)
}
JboRelClause::JRAssign(assign_result) => {
let either_assign = match assign_result {
Ok(atom) => crate::parse_m::Either::Left(atom),
Err(term) => crate::parse_m::Either::Right(term),
};
let stripped = crate::jbo_prop::strip_term_sides(&o);
let result = crate::parse_m::do_assign(stripped, &either_assign, state);
Ok(crate::jbo_prop::re_wrap_term_sides(&o, result))
}
}
}
enum FreeReturn {
FRSides(crate::jbo_prop::SideType, Vec<crate::jbo_prop::Texticule>),
FRTruthQ(Option<i32>),
FRIgnored,
}
fn eval_discursive_bridi_tail(bt: &BridiTail, state: &mut ParseState) -> Result<FreeReturn, String> {
let outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let mut bridi_state = crate::parse_m::BridiParseState::new();
let bridi = parse_bridi_tail(bt, &mut bridi_state, state)?;
let transforms = std::mem::take(&mut state.pending_prop_transforms);
state.pending_prop_transforms = outer_transforms;
let bridi = crate::parse_m::apply_transform_list_to_bridi(bridi, transforms);
let bridi = crate::parse_m::partially_resolve_bridi(bridi, &bridi_state.arglist.args);
let prop = bridi(&crate::parse_m::Args::new());
let texticule = crate::jbo_prop::Texticule::TexticuleProp(prop);
Ok(FreeReturn::FRSides(
crate::jbo_prop::SideType::SideDiscursive,
vec![texticule],
))
}
fn indicator_bridi_tail(indicator_cmavo: &str, indicator_nai: bool) -> Option<BridiTail> {
if indicator_nai {
return None;
}
let selbri = match indicator_cmavo {
"ui" => "gleki",
"ua" => "facki",
_ => return None,
};
let mi = Sumti::QAtom {
frees: vec![],
quant: None,
rels: vec![],
atom: Box::new(SumtiAtom::NonAnaphoricProsumti("mi".to_string())),
};
let selbri = sb3_to_sb(Selbri3::TanruHead(
vec![],
Box::new(TanruUnit::TUBrivla(selbri.to_string())),
vec![],
));
Some(BridiTail::BridiTail3(
selbri,
vec![Term::Sumti(Tagged::FATagged(1), mi)],
))
}
fn eval_free(free: &Free, state: &mut ParseState) -> Result<FreeReturn, String> {
match free {
Free::Discursive(bt) => eval_discursive_bridi_tail(bt, state),
Free::Bracketed(text) => {
Ok(FreeReturn::FRSides(
crate::jbo_prop::SideType::SideBracketed,
eval_texticules(text),
))
}
Free::TruthQ(kau) => {
Ok(FreeReturn::FRTruthQ(*kau))
}
Free::Indicator { indicator_nai, indicator_cmavo } if state.indicator_texticules => {
if let Some(bt) = indicator_bridi_tail(indicator_cmavo, *indicator_nai) {
eval_discursive_bridi_tail(&bt, state)
} else {
Ok(FreeReturn::FRIgnored)
}
}
_ => {
Ok(FreeReturn::FRIgnored)
}
}
}
fn do_free(free: &Free, state: &mut ParseState) -> Result<(), String> {
let fr = eval_free(free, state)?;
match fr {
FreeReturn::FRSides(side_type, jt) => {
for texticule in jt {
let texticule = match texticule {
crate::jbo_prop::Texticule::TexticuleProp(prop) => {
crate::parse_m::Texticule::TexticuleProp(prop)
}
crate::jbo_prop::Texticule::TexticuleSide(inner_side_type, inner) => {
crate::parse_m::Texticule::TexticuleSide(
inner_side_type,
Box::new(prop_texticule_to_parse(*inner)?),
)
}
crate::jbo_prop::Texticule::TexticuleFrag(_) => return Err("Unexpected fragment side texticule".to_string()),
};
state.add_side_texticule(crate::parse_m::Texticule::TexticuleSide(
side_type,
Box::new(texticule),
));
}
Ok(())
}
FreeReturn::FRTruthQ(kau) => {
state.add_question(crate::parse_m::Question {
kau_depth: kau,
info: crate::parse_m::QInfo::QTruth,
});
Ok(())
}
FreeReturn::FRIgnored => Ok(()),
}
}
fn do_frees(frees: &[Free], state: &mut ParseState) -> Result<(), String> {
for free in frees {
do_free(free, state)?;
}
Ok(())
}
fn do_frees_in_parse_m(frees: &[Free], state: &mut ParseState) -> Result<(), String> {
do_frees(frees, state)
}
fn process_discursive_frees(
discursives: &[Free],
state: &mut ParseState,
) -> Result<Vec<crate::jbo_prop::Texticule>, String> {
let mut result = Vec::new();
for free in discursives {
let fr = eval_free(free, state)?;
if let FreeReturn::FRSides(crate::jbo_prop::SideType::SideDiscursive, jt) = fr {
for t in jt {
result.push(crate::jbo_prop::Texticule::TexticuleSide(
crate::jbo_prop::SideType::SideDiscursive,
Box::new(t),
));
}
}
}
Ok(result)
}
fn parse_statements(stmts: &[Statement], state: &mut ParseState) -> Result<JboProp, String> {
let mut props = Vec::new();
for stmt in stmts {
props.push(parse_statement(stmt, state)?);
}
Ok(crate::logic::big_and(props))
}
fn parse_statement(stmt: &Statement, state: &mut ParseState) -> Result<JboProp, String> {
let old_var_bindings = std::mem::take(&mut state.var_bindings);
let old_rvar_bindings = std::mem::take(&mut state.rvar_bindings);
let result = (|| {
let non_discursive: Vec<Free> = stmt
.frees
.iter()
.filter(|f| !is_discursive_free(f))
.cloned()
.collect();
do_frees_in_parse_m(&non_discursive, state)?;
let mut bridi_state = crate::parse_m::BridiParseState::new();
parse_prenex_terms(&stmt.prenex, &mut bridi_state, state)?;
parse_statement1(&stmt.body, state)
})();
state.var_bindings = old_var_bindings;
state.rvar_bindings = old_rvar_bindings;
result
}
fn parse_statement1(stmt1: &Statement1, state: &mut ParseState) -> Result<JboProp, String> {
match stmt1 {
Statement1::ConnectedStatement(conn, s1, s2) => {
do_connective_prop(
false,
conn,
|state| parse_statement1(s1, state),
|state| parse_statement1(s2, state),
state,
)
}
Statement1::StatementParas { tag, paras } => {
let jbo_tag = match tag {
Some(tag) => Some(parse_tag_helper(tag, state)?),
None => None,
};
let mut props = Vec::new();
for para in paras {
for texticule in para {
match texticule {
crate::jbo_syntax::FragmentOrStatement::Fragment(_frag) => {}
crate::jbo_syntax::FragmentOrStatement::Statement(st) => {
props.push(parse_statement(st, state)?);
}
}
}
}
let prop = crate::logic::big_and(props);
if let Some(jbo_tag) = jbo_tag {
Ok(crate::logic::Prop::Modal(
crate::jbo_prop::JboModalOp::Tagged(jbo_tag, None),
Box::new(prop),
))
} else {
Ok(prop)
}
}
Statement1::StatementSentence { frees, sentence } => {
let non_discursive: Vec<Free> = frees
.iter()
.filter(|f| !is_discursive_free(f))
.cloned()
.collect();
do_frees_in_parse_m(&non_discursive, state)?;
let mut bridi_state = crate::parse_m::BridiParseState::new();
let bridi = parse_sentence(sentence, &mut bridi_state, state)?;
let captured_args = bridi_state.arglist.args.clone();
let prop = bridi(&captured_args);
let stored_bridi: crate::parse_m::StoredBridi = std::sync::Arc::new(move |args| {
let combined_args = crate::parse_m::join_args(args, &captured_args);
bridi(&combined_args)
});
state.bribasti_bindings = crate::parse_m::set_shunting(
&|n| TanruUnit::TUGOhA("go'i".to_string(), n as i32),
stored_bridi,
&state.bribasti_bindings,
);
Ok(prop)
}
}
}
fn parse_terms(terms: &[Term], bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Vec<JboTerm>, String> {
parse_terms_helper(terms, false, bridi_state, state)
}
fn parse_prenex_terms(terms: &[Term], bridi_state: &mut crate::parse_m::BridiParseState, state: &mut ParseState) -> Result<Vec<JboTerm>, String> {
let saved_arglist = bridi_state.arglist.clone();
let result = parse_terms_helper(terms, true, bridi_state, state);
bridi_state.arglist = saved_arglist;
result
}
fn parse_terms_helper(
terms: &[Term],
prenex: bool,
bridi_state: &mut crate::parse_m::BridiParseState,
state: &mut ParseState,
) -> Result<Vec<JboTerm>, String> {
let mut result = Vec::new();
for term in terms {
if prenex {
if let Term::Sumti(
Tagged::Untagged,
Sumti::QSelbri {
quant,
selbri: Selbri::Selbri2(Selbri2::Selbri3(Selbri3::TanruHead(_, tu, _))),
..
},
) = term
{
if tu_is_buha(tu) {
let m = parse_mex(quant, state)?;
do_buha(&m, tu, state)?;
continue; }
}
}
let rets = parse_term(term, bridi_state, state)?;
for ret in rets {
match ret {
Either::Left((jbo_tag, mo)) => {
do_tag_helper(&jbo_tag, mo, state)?;
}
Either::Right(o) => result.push(o),
}
}
}
Ok(result)
}
enum Either<L, R> {
Left(L),
Right(R),
}
type ParseTermResult = Result<Vec<Either<(crate::jbo_prop::JboTag, Option<JboTerm>), JboTerm>>, String>;
fn parse_term(
term: &Term,
bridi_state: &mut crate::parse_m::BridiParseState,
state: &mut ParseState,
) -> ParseTermResult {
match term {
Term::Termset(ts) => {
let mut result = Vec::new();
for t in ts {
result.extend(parse_term(t, bridi_state, state)?);
}
Ok(result)
}
Term::ConnectedTerms(forethought, conn, term1, term2) => {
let mut outer_transforms = std::mem::take(&mut state.pending_prop_transforms);
let mut left_bridi_state = bridi_state.clone();
let mut left_state = state.clone();
let mut right_bridi_state = bridi_state.clone();
let mut right_state = state.clone();
let mtag = match conn {
Connective::JboConnLog(mtag, _) => mtag.as_ref(),
Connective::JboConnJoik(mtag, _) => mtag.as_ref(),
};
let outer_transform_start = state.pending_prop_transforms.len();
if let Some(tag) = mtag {
let v = quantify_helper(
&crate::jbo_syntax::Mex::MexNumeralString(vec![
crate::jbo_syntax::Numeral::PA("su'o".to_string())
]),
None,
state,
)?;
outer_transforms.extend(state.pending_prop_transforms.split_off(outer_transform_start));
left_state.next_fresh_var = state.next_fresh_var;
left_state.variable_domains = state.variable_domains.clone();
right_state.next_fresh_var = state.next_fresh_var;
right_state.variable_domains = state.variable_domains.clone();
if *forethought {
let jtag = parse_tag_helper(tag, state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else if is_tense_tag(tag) {
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v.clone()), &mut left_state);
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v), &mut right_state)?;
} else {
let jtag = parse_tag_helper(tag, state)?;
do_tag_helper(&jtag, Some(v.clone()), &mut left_state)?;
do_modal_helper(&crate::jbo_prop::JboModalOp::WithEventAs(v), &mut right_state);
}
}
let result = parse_term(term1, &mut left_bridi_state, &mut left_state)?;
for ret in result {
if let Either::Left((jbo_tag, mo)) = ret {
do_tag_helper(&jbo_tag, mo, &mut left_state)?;
}
}
let left_arglist = left_bridi_state.arglist.clone();
right_state.sumbasti_bindings = left_state.sumbasti_bindings.clone();
right_state.backcount_stack = left_state.backcount_stack.clone();
right_state.bribasti_bindings = left_state.bribasti_bindings.clone();
right_state.next_fresh_var = left_state.next_fresh_var;
right_state.next_fresh_rvar = left_state.next_fresh_rvar;
right_state.variable_domains = left_state.variable_domains.clone();
right_state.next_fresh_constant = left_state.next_fresh_constant;
right_state.referenced_vars = left_state.referenced_vars.clone();
right_state.questions = left_state.questions.clone();
right_state.lambdas = left_state.lambdas.clone();
right_state.side_texticules = left_state.side_texticules.clone();
right_state.non_veridical_props = left_state.non_veridical_props.clone();
let right_result = parse_term(term2, &mut right_bridi_state, &mut right_state)?;
for ret in right_result {
if let Either::Left((jbo_tag, mo)) = ret {
do_tag_helper(&jbo_tag, mo, &mut right_state)?;
}
}
let right_arglist = right_bridi_state.arglist.clone();
let left_transforms = left_state.pending_prop_transforms.drain(..).collect::<Vec<_>>();
let right_transforms = right_state.pending_prop_transforms.drain(..).collect::<Vec<_>>();
let conn = conn.clone();
let transforms = outer_transforms;
*bridi_state = right_bridi_state;
*state = right_state;
state.map_prop(crate::parse_m::PropTransform::ConnectBranches {
conn,
left_args: left_arglist.args.clone(),
right_args: right_arglist.args.clone(),
continuation_position: right_arglist.position,
left_transforms,
right_transforms,
outer_transforms: transforms,
});
bridi_state.arglist = right_arglist;
for (pos, term) in left_arglist.args {
bridi_state.arglist.args.insert(pos, term);
}
Ok(vec![])
}
Term::Negation => {
state.map_prop(crate::parse_m::PropTransform::Negate);
Ok(vec![])
}
Term::Sumti(taggedness, sumti) => {
let o = parse_sumti(sumti, state)?;
match taggedness {
Tagged::Tagged(tag) => {
let jbo_tag = parse_tag_helper(tag, state)?;
Ok(vec![Either::Left((jbo_tag, Some(o)))])
}
Tagged::Untagged => {
crate::parse_m::add_arg(crate::parse_m::Arg::Untagged(o.clone()), bridi_state, state);
Ok(vec![Either::Right(o)])
}
Tagged::FATagged(n) => {
crate::parse_m::add_arg(crate::parse_m::Arg::FATagged(*n as usize, o.clone()), bridi_state, state);
Ok(vec![Either::Right(o)])
}
Tagged::FAITagged => {
crate::parse_m::add_arg(crate::parse_m::Arg::FAITagged(o.clone()), bridi_state, state);
Ok(vec![Either::Right(o)])
}
}
}
Term::BareFA(n) => {
if let Some(pos) = n {
crate::parse_m::set_arg_pos(*pos, bridi_state);
}
Ok(vec![])
}
Term::NullTerm => Ok(vec![]),
Term::BareTag(tag) => {
let jbo_tag = parse_tag_helper(tag, state)?;
Ok(vec![Either::Left((jbo_tag, None))])
}
}
}
fn parse_variable(
sa: &SumtiAtom,
rps: &[JboPred],
mm: Option<&JboMex>,
state: &mut ParseState,
) -> Result<JboTerm, String> {
let existing = state.var_bindings.get(sa).cloned();
match (existing, mm) {
(Some(o), None) => {
Ok(o)
}
_ => {
let m = mm.cloned().unwrap_or_else(|| {
JboMex::MexNumeralString(vec![crate::jbo_syntax::Numeral::PA("su'o".to_string())])
});
let restrict = crate::jbo_prop::and_m_pred(rps.to_vec());
let o = quantify(&m, restrict, state)?;
state.var_bindings.insert(sa.clone(), o.clone());
Ok(o)
}
}
}
fn do_buha(
m: &JboMex,
tu: &TanruUnit,
state: &mut ParseState,
) -> Result<JboRel, String> {
if !tu_is_buha(tu) {
return Err("Not a buha tanru unit".to_string());
}
let (base, n) = match tu {
TanruUnit::TUGOhA(goha, number) => {
let num = if *number > 1 {
*number
} else {
if goha == "bu'a" {
1
} else if goha == "bu'e" {
2
} else if goha == "bu'i" {
3
} else {
1
}
};
("bu'a", num)
}
_ => return Err("Invalid buha".to_string()),
};
let canonical_tu = TanruUnit::TUGOhA(base.to_string(), n);
let existing = state.rvar_bindings.get(&canonical_tu).cloned();
match existing {
Some(r) => Ok(r),
None => {
let r = rquantify(m, state)?;
state.rvar_bindings.insert(canonical_tu, r.clone());
Ok(r)
}
}
}
fn parsed_selbri_to_new_selbri<F>(
bridi_state: &crate::parse_m::BridiParseState,
state: &mut ParseState,
f: F,
) -> Result<Bridi, String>
where
F: FnOnce(&mut crate::parse_m::BridiParseState, &mut ParseState) -> Result<Bridi, String>,
{
let bridi = parse_seltau_bridi(bridi_state, state, f)?;
Ok(crate::parse_m::close_bridi(bridi))
}
fn swap_arg_positions_in_prop(n: i32, prop: crate::parse_m::JboProp) -> crate::parse_m::JboProp {
use crate::logic::Prop;
match prop {
Prop::Rel(rel, terms) => {
let mut new_terms = terms.clone();
if (1..=4).contains(&n) {
let idx = n as usize; if new_terms.len() > idx {
new_terms.swap(0, idx);
}
}
Prop::Rel(rel, new_terms)
}
Prop::Not(p) => Prop::Not(Box::new(swap_arg_positions_in_prop(n, *p))),
Prop::Connected(c, p1, p2) => Prop::Connected(
c,
Box::new(swap_arg_positions_in_prop(n, *p1)),
Box::new(swap_arg_positions_in_prop(n, *p2)),
),
Prop::NonLogConnected(c, p1, p2) => Prop::NonLogConnected(
c,
Box::new(swap_arg_positions_in_prop(n, *p1)),
Box::new(swap_arg_positions_in_prop(n, *p2)),
),
Prop::Modal(m, p) => Prop::Modal(m, Box::new(swap_arg_positions_in_prop(n, *p))),
Prop::Quantified(q, r, f) => {
Prop::Quantified(q, r, std::sync::Arc::new(move |v| swap_arg_positions_in_prop(n, f(v))))
}
other => other, }
}
fn push_canonical_lines(lines: &mut Vec<String>, lojban: &str) {
for line in lojban.lines().filter(|line| !line.is_empty()) {
if lines.is_empty() || line.starts_with(".i ") {
lines.push(line.to_string());
} else {
lines.push(format!(".i {}", line));
}
}
}
fn build_lojban_output_from_prop(
prop: &crate::parse_m::JboProp,
side_props: &[JboProp],
) -> String {
use crate::jbo_show::prop_to_lojban;
let mut lines = Vec::new();
for side_prop in side_props {
push_canonical_lines(&mut lines, &prop_to_lojban(side_prop));
}
push_canonical_lines(&mut lines, &prop_to_lojban(prop));
lines.join("\n")
}
fn build_lojban_output_from_texticules(
prop: &crate::parse_m::JboProp,
side_texticules: &[Texticule],
) -> String {
use crate::jbo_show::prop_to_lojban;
let mut lines = Vec::new();
for side_texticule in side_texticules {
if let Ok(parse_texticule) = prop_texticule_to_parse(side_texticule.clone()) {
push_canonical_lines(&mut lines, &prop_to_lojban(&prop_texticule_to_prop(parse_texticule)));
}
}
push_canonical_lines(&mut lines, &prop_to_lojban(prop));
lines.join("\n")
}