1use std::fmt::Write;
28
29use crate::ast::{LogicExpr, NounPhrase, Term, QuantifierKind};
30use crate::ast::logic::NumberKind;
31use crate::formatter::{KripkeFormatter, LatexFormatter, LogicFormatter, SimpleFOLFormatter, UnicodeFormatter};
32use logicaffeine_base::{Interner, Symbol};
33use crate::registry::SymbolRegistry;
34use crate::token::TokenType;
35use crate::{OutputFormat, TranspileContext};
36
37fn collect_suppress_existential_events<'a>(expr: &LogicExpr<'a>) -> Vec<Symbol> {
40 let mut events = Vec::new();
41 collect_suppress_existential_events_inner(expr, &mut events);
42 let mut unique = Vec::new();
45 for e in events {
46 if !unique.iter().any(|x| *x == e) {
47 unique.push(e);
48 }
49 }
50 unique
51}
52
53fn collect_suppress_existential_events_inner<'a>(expr: &LogicExpr<'a>, events: &mut Vec<Symbol>) {
54 match expr {
55 LogicExpr::NeoEvent(data) => {
56 if data.suppress_existential {
57 events.push(data.event_var);
58 }
59 }
60 LogicExpr::BinaryOp { left, right, .. } => {
61 collect_suppress_existential_events_inner(left, events);
62 collect_suppress_existential_events_inner(right, events);
63 }
64 LogicExpr::UnaryOp { operand, .. } => {
65 collect_suppress_existential_events_inner(operand, events);
66 }
67 LogicExpr::Temporal { body, .. } => {
68 collect_suppress_existential_events_inner(body, events);
69 }
70 LogicExpr::TemporalBinary { left, right, .. } => {
71 collect_suppress_existential_events_inner(left, events);
72 collect_suppress_existential_events_inner(right, events);
73 }
74 LogicExpr::Aspectual { body, .. } => {
75 collect_suppress_existential_events_inner(body, events);
76 }
77 LogicExpr::Modal { operand, .. } => {
78 collect_suppress_existential_events_inner(operand, events);
79 }
80 _ => {}
81 }
82}
83
84pub fn capitalize_first(s: &str) -> String {
88 let mut chars = s.chars();
89 match chars.next() {
90 None => String::new(),
91 Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),
92 }
93}
94
95fn write_capitalized<W: Write>(w: &mut W, s: &str) -> std::fmt::Result {
96 let mut chars = s.chars();
97 match chars.next() {
98 None => Ok(()),
99 Some(c) => {
100 for uc in c.to_uppercase() {
101 write!(w, "{}", uc)?;
102 }
103 write!(w, "{}", chars.as_str())
104 }
105 }
106}
107
108impl<'a> NounPhrase<'a> {
109 pub fn to_symbol(&self, registry: &mut SymbolRegistry, interner: &Interner) -> String {
111 registry.get_symbol(self.noun, interner)
112 }
113
114 pub fn to_symbol_full(&self, registry: &SymbolRegistry, interner: &Interner) -> String {
116 registry.get_symbol_full(self.noun, interner)
117 }
118}
119
120impl<'a> Term<'a> {
121 pub fn write_to<W: Write>(
123 &self,
124 w: &mut W,
125 registry: &mut SymbolRegistry,
126 interner: &Interner,
127 ) -> std::fmt::Result {
128 self.write_to_inner(w, registry, interner, false)
129 }
130
131 pub fn write_to_full<W: Write>(
133 &self,
134 w: &mut W,
135 registry: &mut SymbolRegistry,
136 interner: &Interner,
137 ) -> std::fmt::Result {
138 self.write_to_inner(w, registry, interner, true)
139 }
140
141 pub fn write_to_raw<W: Write>(
143 &self,
144 w: &mut W,
145 interner: &Interner,
146 ) -> std::fmt::Result {
147 match self {
148 Term::Constant(name) | Term::Variable(name) => {
149 write!(w, "{}", interner.resolve(*name))
150 }
151 Term::Function(name, args) => {
152 write!(w, "{}(", interner.resolve(*name))?;
153 for (i, arg) in args.iter().enumerate() {
154 if i > 0 {
155 write!(w, ", ")?;
156 }
157 arg.write_to_raw(w, interner)?;
158 }
159 write!(w, ")")
160 }
161 Term::Group(members) => {
162 write!(w, "(")?;
163 for (i, m) in members.iter().enumerate() {
164 if i > 0 {
165 write!(w, ", ")?;
166 }
167 m.write_to_raw(w, interner)?;
168 }
169 write!(w, ")")
170 }
171 Term::Possessed { possessor, possessed } => {
172 possessor.write_to_raw(w, interner)?;
173 write!(w, ".{}", interner.resolve(*possessed))
174 }
175 Term::Value { kind, .. } => match kind {
176 NumberKind::Integer(n) => write!(w, "{}", n),
177 NumberKind::Real(f) => write!(w, "{}", f),
178 NumberKind::Symbolic(s) => write!(w, "{}", interner.resolve(*s)),
179 }
180 Term::Sigma(predicate) => write!(w, "σ({})", interner.resolve(*predicate)),
181 Term::Intension(predicate) => write!(w, "^{}", interner.resolve(*predicate)),
182 Term::Proposition(expr) => write!(w, "[proposition]"),
183 }
184 }
185
186 fn write_to_inner<W: Write>(
187 &self,
188 w: &mut W,
189 registry: &mut SymbolRegistry,
190 interner: &Interner,
191 use_full_names: bool,
192 ) -> std::fmt::Result {
193 match self {
194 Term::Constant(name) => {
195 if use_full_names {
196 write!(w, "{}", registry.get_symbol_full(*name, interner))
197 } else {
198 write!(w, "{}", registry.get_symbol(*name, interner))
199 }
200 }
201 Term::Variable(name) => write!(w, "{}", interner.resolve(*name)),
202 Term::Function(name, args) => {
203 let fn_name = if use_full_names {
204 registry.get_symbol_full(*name, interner)
205 } else {
206 registry.get_symbol(*name, interner)
207 };
208 write!(w, "{}(", fn_name)?;
209 for (i, arg) in args.iter().enumerate() {
210 if i > 0 {
211 write!(w, ", ")?;
212 }
213 arg.write_to_inner(w, registry, interner, use_full_names)?;
214 }
215 write!(w, ")")
216 }
217 Term::Group(members) => {
218 for (i, m) in members.iter().enumerate() {
219 if i > 0 {
220 write!(w, " ⊕ ")?;
221 }
222 m.write_to_inner(w, registry, interner, use_full_names)?;
223 }
224 Ok(())
225 }
226 Term::Possessed { possessor, possessed } => {
227 let poss_name = if use_full_names {
228 registry.get_symbol_full(*possessed, interner)
229 } else {
230 registry.get_symbol(*possessed, interner)
231 };
232 write!(w, "Poss(")?;
233 possessor.write_to_inner(w, registry, interner, use_full_names)?;
234 write!(w, ", {})", poss_name)
235 }
236 Term::Sigma(predicate) => {
237 let pred_name = if use_full_names {
238 registry.get_symbol_full(*predicate, interner)
239 } else {
240 registry.get_symbol(*predicate, interner)
241 };
242 write!(w, "σ{}", pred_name)
243 }
244 Term::Intension(predicate) => {
245 let word = interner.resolve(*predicate);
247 let capitalized = word.chars().next()
248 .map(|c| c.to_uppercase().collect::<String>() + &word[1..])
249 .unwrap_or_default();
250 write!(w, "^{}", capitalized)
251 }
252 Term::Proposition(expr) => {
253 write!(w, "[")?;
254 expr.write_logic(w, registry, interner, &UnicodeFormatter)?;
255 write!(w, "]")
256 }
257 Term::Value { kind, unit, dimension: _ } => {
258 use crate::ast::NumberKind;
259 match kind {
260 NumberKind::Real(r) => write!(w, "{}", r)?,
261 NumberKind::Integer(i) => write!(w, "{}", i)?,
262 NumberKind::Symbolic(s) => write!(w, "{}", interner.resolve(*s))?,
263 }
264 if let Some(u) = unit {
265 write!(w, " {}", interner.resolve(*u))?;
266 }
267 Ok(())
268 }
269 }
270 }
271
272 pub fn transpile(&self, registry: &mut SymbolRegistry, interner: &Interner) -> String {
274 let mut buf = String::new();
275 let _ = self.write_to(&mut buf, registry, interner);
276 buf
277 }
278}
279
280fn collect_discourse_conjuncts<'a>(expr: &'a LogicExpr<'a>) -> Vec<&'a LogicExpr<'a>> {
283 let mut conjuncts = Vec::new();
284 collect_discourse_conjuncts_inner(expr, &mut conjuncts);
285 conjuncts
286}
287
288fn collect_discourse_conjuncts_inner<'a>(expr: &'a LogicExpr<'a>, conjuncts: &mut Vec<&'a LogicExpr<'a>>) {
289 match expr {
290 LogicExpr::BinaryOp { left, op: TokenType::And, right } => {
291 collect_discourse_conjuncts_inner(left, conjuncts);
293 collect_discourse_conjuncts_inner(right, conjuncts);
294 }
295 _ => {
296 conjuncts.push(expr);
298 }
299 }
300}
301
302impl<'a> LogicExpr<'a> {
303 pub fn transpile_discourse(
312 &self,
313 registry: &mut SymbolRegistry,
314 interner: &Interner,
315 format: OutputFormat,
316 ) -> String {
317 let conjuncts = collect_discourse_conjuncts(self);
318
319 if conjuncts.len() <= 1 {
320 return self.transpile(registry, interner, format);
322 }
323
324 let mut result = String::new();
326 for (i, conjunct) in conjuncts.iter().enumerate() {
327 if i > 0 {
328 result.push('\n');
329 }
330 let formula = conjunct.transpile(registry, interner, format);
331 result.push_str(&format!("{}) {}", i + 1, formula));
332 }
333 result
334 }
335
336 pub fn write_logic<W: Write, F: LogicFormatter>(
337 &self,
338 w: &mut W,
339 registry: &mut SymbolRegistry,
340 interner: &Interner,
341 fmt: &F,
342 ) -> std::fmt::Result {
343 match self {
344 LogicExpr::Predicate { name, args, world } => {
345 let pred_name = if fmt.use_full_names() {
346 registry.get_symbol_full(*name, interner)
347 } else {
348 registry.get_symbol(*name, interner)
349 };
350
351 if fmt.include_world_arguments() {
353 if let Some(w_sym) = world {
354 let mut extended: Vec<Term> = args.to_vec();
356 extended.push(Term::Variable(*w_sym));
357 return fmt.write_predicate(w, &pred_name, &extended, registry, interner);
358 }
359 }
360 fmt.write_predicate(w, &pred_name, args, registry, interner)
361 }
362
363 LogicExpr::Identity { left, right } => {
364 if fmt.wrap_identity() {
365 write!(w, "(")?;
366 }
367 if fmt.preserve_case() {
368 left.write_to_raw(w, interner)?;
369 } else if fmt.use_full_names() {
370 left.write_to_full(w, registry, interner)?;
371 } else {
372 left.write_to(w, registry, interner)?;
373 }
374 write!(w, "{}", fmt.identity())?;
375 if fmt.preserve_case() {
376 right.write_to_raw(w, interner)?;
377 } else if fmt.use_full_names() {
378 right.write_to_full(w, registry, interner)?;
379 } else {
380 right.write_to(w, registry, interner)?;
381 }
382 if fmt.wrap_identity() {
383 write!(w, ")")?;
384 }
385 Ok(())
386 }
387
388 LogicExpr::Metaphor { tenor, vehicle } => {
389 write!(w, "Metaphor(")?;
390 tenor.write_to(w, registry, interner)?;
391 write!(w, ", ")?;
392 vehicle.write_to(w, registry, interner)?;
393 write!(w, ")")
394 }
395
396 LogicExpr::Quantifier { kind, variable, body, .. } => {
397 let var_str = interner.resolve(*variable);
398
399 if fmt.use_simple_events() && (var_str == "e" || var_str.starts_with("e") && var_str[1..].chars().all(|c| c.is_ascii_digit())) {
401 return body.write_logic(w, registry, interner, fmt);
402 }
403
404 let mut body_buf = String::new();
405 body.write_logic(&mut body_buf, registry, interner, fmt)?;
406 write!(w, "{}", fmt.quantifier(kind, var_str, &body_buf))
407 }
408
409 LogicExpr::Categorical(data) => {
410 let s = if fmt.use_full_names() {
411 fmt.sanitize(&data.subject.to_symbol_full(registry, interner))
412 } else {
413 fmt.sanitize(&data.subject.to_symbol(registry, interner))
414 };
415 let p = if fmt.use_full_names() {
416 fmt.sanitize(&data.predicate.to_symbol_full(registry, interner))
417 } else {
418 fmt.sanitize(&data.predicate.to_symbol(registry, interner))
419 };
420 match (&data.quantifier, data.copula_negative) {
421 (TokenType::All, false) => write!(w, "{} {} is {}", fmt.categorical_all(), s, p),
422 (TokenType::No, false) => write!(w, "{} {} is {}", fmt.categorical_no(), s, p),
423 (TokenType::Some, false) => write!(w, "{} {} is {}", fmt.categorical_some(), s, p),
424 (TokenType::Some, true) => write!(w, "{} {} is {} {}", fmt.categorical_some(), s, fmt.categorical_not(), p),
425 (TokenType::All, true) => write!(w, "{} {} is {} {}", fmt.categorical_some(), s, fmt.categorical_not(), p),
426 _ => write!(w, "Invalid Syllogism"),
427 }
428 }
429
430 LogicExpr::Relation(data) => {
431 let s = if fmt.use_full_names() {
432 data.subject.to_symbol_full(registry, interner)
433 } else {
434 data.subject.to_symbol(registry, interner)
435 };
436 let v = if fmt.use_full_names() {
437 fmt.sanitize(®istry.get_symbol_full(data.verb, interner))
438 } else {
439 fmt.sanitize(®istry.get_symbol(data.verb, interner))
440 };
441 let o = if fmt.use_full_names() {
442 data.object.to_symbol_full(registry, interner)
443 } else {
444 data.object.to_symbol(registry, interner)
445 };
446 write!(w, "{}({}, {})", v, s, o)
447 }
448
449 LogicExpr::Modal { vector, operand } => {
450 let mut o = String::new();
451 operand.write_logic(&mut o, registry, interner, fmt)?;
452 write!(w, "{}", fmt.modal(vector.domain, vector.force, &o))
453 }
454
455 LogicExpr::BinaryOp { left, op, right } => {
456 let mut l = String::new();
457 let mut r = String::new();
458 left.write_logic(&mut l, registry, interner, fmt)?;
459 right.write_logic(&mut r, registry, interner, fmt)?;
460
461 if matches!(op, TokenType::If | TokenType::Implies) {
464 let events = collect_suppress_existential_events(self);
465 if !events.is_empty() {
466 let mut result = fmt.binary_op(op, &l, &r);
468 for event_var in events.into_iter().rev() {
469 let var_str = interner.resolve(event_var);
470 result = fmt.quantifier(&QuantifierKind::Universal, var_str, &result);
471 }
472 return write!(w, "{}", result);
473 }
474 }
475
476 write!(w, "{}", fmt.binary_op(op, &l, &r))
477 }
478
479 LogicExpr::UnaryOp { op, operand } => {
480 let mut o = String::new();
481 operand.write_logic(&mut o, registry, interner, fmt)?;
482 write!(w, "{}", fmt.unary_op(op, &o))
483 }
484
485 LogicExpr::Temporal { operator, body } => {
486 let mut inner = String::new();
487 body.write_logic(&mut inner, registry, interner, fmt)?;
488 write!(w, "{}", fmt.temporal(operator, &inner))
489 }
490
491 LogicExpr::TemporalBinary { operator, left, right } => {
492 let mut l = String::new();
493 let mut r = String::new();
494 left.write_logic(&mut l, registry, interner, fmt)?;
495 right.write_logic(&mut r, registry, interner, fmt)?;
496 write!(w, "{}", fmt.temporal_binary(operator, &l, &r))
497 }
498
499 LogicExpr::Aspectual { operator, body } => {
500 let mut inner = String::new();
501 body.write_logic(&mut inner, registry, interner, fmt)?;
502 write!(w, "{}", fmt.aspectual(operator, &inner))
503 }
504
505 LogicExpr::Voice { operator, body } => {
506 let mut inner = String::new();
507 body.write_logic(&mut inner, registry, interner, fmt)?;
508 write!(w, "{}", fmt.voice(operator, &inner))
509 }
510
511 LogicExpr::Question { wh_variable, body } => {
512 let mut body_str = String::new();
513 body.write_logic(&mut body_str, registry, interner, fmt)?;
514 write!(w, "{}", fmt.lambda(interner.resolve(*wh_variable), &body_str))
515 }
516
517 LogicExpr::YesNoQuestion { body } => {
518 write!(w, "?")?;
519 body.write_logic(w, registry, interner, fmt)
520 }
521
522 LogicExpr::Atom(s) => {
523 let name = if fmt.preserve_case() {
524 interner.resolve(*s).to_string()
525 } else if fmt.use_full_names() {
526 registry.get_symbol_full(*s, interner)
527 } else {
528 registry.get_symbol(*s, interner)
529 };
530 write!(w, "{}", fmt.sanitize(&name))
531 }
532
533 LogicExpr::Lambda { variable, body } => {
534 let mut b = String::new();
535 body.write_logic(&mut b, registry, interner, fmt)?;
536 write!(w, "{}", fmt.lambda(interner.resolve(*variable), &b))
537 }
538
539 LogicExpr::App { function, argument } => {
540 write!(w, "(")?;
541 function.write_logic(w, registry, interner, fmt)?;
542 write!(w, ")(")?;
543 argument.write_logic(w, registry, interner, fmt)?;
544 write!(w, ")")
545 }
546
547 LogicExpr::Intensional { operator, content } => {
548 write!(w, "{}[", fmt.sanitize(®istry.get_symbol(*operator, interner)))?;
549 content.write_logic(w, registry, interner, fmt)?;
550 write!(w, "]")
551 }
552
553 LogicExpr::Event { predicate, adverbs } => {
554 let mut pred_str = String::new();
555 predicate.write_logic(&mut pred_str, registry, interner, fmt)?;
556 let adverb_preds: Vec<String> = adverbs
557 .iter()
558 .map(|a| format!("{}(e)", fmt.sanitize(®istry.get_symbol(*a, interner))))
559 .collect();
560 write!(w, "{}", fmt.event_quantifier(&pred_str, &adverb_preds))
561 }
562
563 LogicExpr::NeoEvent(data) => {
564 use crate::ast::{QuantifierKind, ThematicRole};
565
566 if fmt.use_simple_events() {
567 write!(w, "{}", registry.get_symbol_full(data.verb, interner))?;
568 write!(w, "(")?;
569 let mut first = true;
570 for (role, term) in data.roles.iter() {
571 if matches!(role, ThematicRole::Agent | ThematicRole::Patient | ThematicRole::Theme | ThematicRole::Goal | ThematicRole::Location) {
573 if !first {
574 write!(w, ", ")?;
575 }
576 first = false;
577 term.write_to_full(w, registry, interner)?;
578 }
579 }
580 write!(w, ")")
581 } else {
582 let e = interner.resolve(data.event_var);
583 let mut body = String::new();
584
585 let world_suffix = if fmt.include_world_arguments() {
587 data.world.map(|w| format!(", {}", interner.resolve(w))).unwrap_or_default()
588 } else {
589 String::new()
590 };
591
592 write_capitalized(&mut body, interner.resolve(data.verb))?;
593 write!(body, "({}{})", e, world_suffix)?;
594 for (role, term) in data.roles.iter() {
595 let role_str = match role {
596 ThematicRole::Agent => "Agent",
597 ThematicRole::Patient => "Patient",
598 ThematicRole::Theme => "Theme",
599 ThematicRole::Recipient => "Recipient",
600 ThematicRole::Goal => "Goal",
601 ThematicRole::Source => "Source",
602 ThematicRole::Instrument => "Instrument",
603 ThematicRole::Location => "Location",
604 ThematicRole::Time => "Time",
605 ThematicRole::Manner => "Manner",
606 };
607 write!(body, " {} {}({}, ", fmt.and(), role_str, e)?;
608 if fmt.use_full_names() {
609 term.write_to_full(&mut body, registry, interner)?;
610 } else {
611 term.write_to(&mut body, registry, interner)?;
612 }
613 write!(body, "{})", world_suffix)?;
614 }
615 for mod_sym in data.modifiers.iter() {
616 write!(body, " {} ", fmt.and())?;
617 write_capitalized(&mut body, interner.resolve(*mod_sym))?;
618 write!(body, "({}{})", e, world_suffix)?;
619 }
620 if data.suppress_existential {
621 write!(w, "{}", body)
623 } else {
624 write!(w, "{}", fmt.quantifier(&QuantifierKind::Existential, e, &body))
626 }
627 }
628 }
629
630 LogicExpr::Imperative { action } => {
631 write!(w, "!")?;
632 action.write_logic(w, registry, interner, fmt)
633 }
634
635 LogicExpr::SpeechAct { performer, act_type, content } => {
636 write!(w, "SpeechAct({}, {}, ", interner.resolve(*act_type), fmt.sanitize(®istry.get_symbol(*performer, interner)))?;
637 content.write_logic(w, registry, interner, fmt)?;
638 write!(w, ")")
639 }
640
641 LogicExpr::Counterfactual { antecedent, consequent } => {
642 let mut a = String::new();
643 let mut c = String::new();
644 antecedent.write_logic(&mut a, registry, interner, fmt)?;
645 consequent.write_logic(&mut c, registry, interner, fmt)?;
646 write!(w, "{}", fmt.counterfactual(&a, &c))
647 }
648
649 LogicExpr::Causal { effect, cause } => {
650 write!(w, "Cause(")?;
651 cause.write_logic(w, registry, interner, fmt)?;
652 write!(w, ", ")?;
653 effect.write_logic(w, registry, interner, fmt)?;
654 write!(w, ")")
655 }
656
657 LogicExpr::Comparative { adjective, subject, object, difference } => {
658 let adj = interner.resolve(*adjective);
659 let mut subj_buf = String::new();
660 if fmt.preserve_case() {
661 subject.write_to_raw(&mut subj_buf, interner)?;
662 } else {
663 subject.write_to(&mut subj_buf, registry, interner)?;
664 }
665 let mut obj_buf = String::new();
666 if fmt.preserve_case() {
667 object.write_to_raw(&mut obj_buf, interner)?;
668 } else {
669 object.write_to(&mut obj_buf, registry, interner)?;
670 }
671 let diff_str = if let Some(diff) = difference {
672 let mut diff_buf = String::new();
673 if fmt.preserve_case() {
674 diff.write_to_raw(&mut diff_buf, interner)?;
675 } else {
676 diff.write_to(&mut diff_buf, registry, interner)?;
677 }
678 Some(diff_buf)
679 } else {
680 None
681 };
682 fmt.write_comparative(w, adj, &subj_buf, &obj_buf, diff_str.as_deref())
683 }
684
685 LogicExpr::Superlative { adjective, subject, domain } => {
686 let mut s = String::new();
687 subject.write_to(&mut s, registry, interner)?;
688 let mut d = String::new();
689 write_capitalized(&mut d, interner.resolve(*domain))?;
690 let comp = format!("{}er", interner.resolve(*adjective));
691 write!(w, "{}", fmt.superlative(&comp, &d, &s))
692 }
693
694 LogicExpr::Scopal { operator, body } => {
695 write!(w, "{}(", interner.resolve(*operator))?;
696 body.write_logic(w, registry, interner, fmt)?;
697 write!(w, ")")
698 }
699
700 LogicExpr::TemporalAnchor { anchor, body } => {
701 write!(w, "{}(", interner.resolve(*anchor))?;
702 body.write_logic(w, registry, interner, fmt)?;
703 write!(w, ")")
704 }
705
706 LogicExpr::Control { verb, subject, object, infinitive } => {
707 write!(w, "{}(", fmt.sanitize(®istry.get_symbol(*verb, interner)))?;
708 subject.write_to(w, registry, interner)?;
709 if let Some(obj) = object {
710 write!(w, ", ")?;
711 obj.write_to(w, registry, interner)?;
712 }
713 write!(w, ", ")?;
714 infinitive.write_logic(w, registry, interner, fmt)?;
715 write!(w, ")")
716 }
717
718 LogicExpr::Presupposition { assertion, presupposition } => {
719 assertion.write_logic(w, registry, interner, fmt)?;
720 write!(w, " [Presup: ")?;
721 presupposition.write_logic(w, registry, interner, fmt)?;
722 write!(w, "]")
723 }
724
725 LogicExpr::Focus { kind, focused, scope } => {
726 use crate::token::FocusKind;
727 let prefix = match kind {
728 FocusKind::Only => "Only",
729 FocusKind::Even => "Even",
730 FocusKind::Just => "Just",
731 };
732 write!(w, "{}(", prefix)?;
733 focused.write_to(w, registry, interner)?;
734 write!(w, ", ")?;
735 scope.write_logic(w, registry, interner, fmt)?;
736 write!(w, ")")
737 }
738
739 LogicExpr::Distributive { predicate } => {
740 write!(w, "*")?;
741 predicate.write_logic(w, registry, interner, fmt)
742 }
743
744 LogicExpr::GroupQuantifier { group_var, count, member_var, restriction, body } => {
745 let g = interner.resolve(*group_var);
746 let x = interner.resolve(*member_var);
747
748 write!(w, "{}{}(Group({}) {} Count({}, {}) {} {}{}(Member({}, {}) {} ",
750 fmt.existential(), g, g,
751 fmt.and(), g, count,
752 fmt.and(), fmt.universal(), x, x, g, fmt.implies())?;
753
754 restriction.write_logic(w, registry, interner, fmt)?;
755
756 write!(w, ") {} ", fmt.and())?;
757
758 body.write_logic(w, registry, interner, fmt)?;
759
760 write!(w, ")")
761 }
762 }
763 }
764
765 pub fn transpile_with<F: LogicFormatter>(
767 &self,
768 registry: &mut SymbolRegistry,
769 interner: &Interner,
770 fmt: &F,
771 ) -> String {
772 let mut buf = String::new();
773 let _ = self.write_logic(&mut buf, registry, interner, fmt);
774 buf
775 }
776
777 pub fn transpile(
786 &self,
787 registry: &mut SymbolRegistry,
788 interner: &Interner,
789 format: OutputFormat,
790 ) -> String {
791 match format {
792 OutputFormat::Unicode => self.transpile_with(registry, interner, &UnicodeFormatter),
793 OutputFormat::LaTeX => self.transpile_with(registry, interner, &LatexFormatter),
794 OutputFormat::SimpleFOL => self.transpile_with(registry, interner, &SimpleFOLFormatter),
795 OutputFormat::Kripke => self.transpile_with(registry, interner, &KripkeFormatter),
796 }
797 }
798
799 pub fn transpile_ctx<F: LogicFormatter>(
801 &self,
802 ctx: &mut TranspileContext<'_>,
803 fmt: &F,
804 ) -> String {
805 self.transpile_with(ctx.registry, ctx.interner, fmt)
806 }
807
808 pub fn transpile_ctx_unicode(&self, ctx: &mut TranspileContext<'_>) -> String {
810 self.transpile_ctx(ctx, &UnicodeFormatter)
811 }
812
813 pub fn transpile_ctx_latex(&self, ctx: &mut TranspileContext<'_>) -> String {
815 self.transpile_ctx(ctx, &LatexFormatter)
816 }
817}