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