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::Kind(kind) => write!(w, "^{}", interner.resolve(*kind)),
183 Term::Proposition(expr) => write!(w, "[proposition]"),
184 }
185 }
186
187 fn write_to_inner<W: Write>(
188 &self,
189 w: &mut W,
190 registry: &mut SymbolRegistry,
191 interner: &Interner,
192 use_full_names: bool,
193 ) -> std::fmt::Result {
194 match self {
195 Term::Constant(name) => {
196 if use_full_names {
197 write!(w, "{}", registry.get_symbol_full(*name, interner))
198 } else {
199 write!(w, "{}", registry.get_symbol(*name, interner))
200 }
201 }
202 Term::Variable(name) => write!(w, "{}", interner.resolve(*name)),
203 Term::Function(name, args) => {
204 let fn_name = if use_full_names {
205 registry.get_symbol_full(*name, interner)
206 } else {
207 registry.get_symbol(*name, interner)
208 };
209 write!(w, "{}(", fn_name)?;
210 for (i, arg) in args.iter().enumerate() {
211 if i > 0 {
212 write!(w, ", ")?;
213 }
214 arg.write_to_inner(w, registry, interner, use_full_names)?;
215 }
216 write!(w, ")")
217 }
218 Term::Group(members) => {
219 for (i, m) in members.iter().enumerate() {
220 if i > 0 {
221 write!(w, " ⊕ ")?;
222 }
223 m.write_to_inner(w, registry, interner, use_full_names)?;
224 }
225 Ok(())
226 }
227 Term::Possessed { possessor, possessed } => {
228 let poss_name = if use_full_names {
229 registry.get_symbol_full(*possessed, interner)
230 } else {
231 registry.get_symbol(*possessed, interner)
232 };
233 write!(w, "Poss(")?;
234 possessor.write_to_inner(w, registry, interner, use_full_names)?;
235 write!(w, ", {})", poss_name)
236 }
237 Term::Sigma(predicate) => {
238 let pred_name = if use_full_names {
239 registry.get_symbol_full(*predicate, interner)
240 } else {
241 registry.get_symbol(*predicate, interner)
242 };
243 write!(w, "σ{}", pred_name)
244 }
245 Term::Intension(predicate) => {
246 let word = interner.resolve(*predicate);
248 let capitalized = word.chars().next()
249 .map(|c| c.to_uppercase().collect::<String>() + &word[1..])
250 .unwrap_or_default();
251 write!(w, "^{}", capitalized)
252 }
253 Term::Kind(kind) => {
254 let word = interner.resolve(*kind);
256 let capitalized = word.chars().next()
257 .map(|c| c.to_uppercase().collect::<String>() + &word[1..])
258 .unwrap_or_default();
259 write!(w, "^{}", capitalized)
260 }
261 Term::Proposition(expr) => {
262 write!(w, "[")?;
263 expr.write_logic(w, registry, interner, &UnicodeFormatter)?;
264 write!(w, "]")
265 }
266 Term::Value { kind, unit, dimension: _ } => {
267 use crate::ast::NumberKind;
268 match kind {
269 NumberKind::Real(r) => write!(w, "{}", r)?,
270 NumberKind::Integer(i) => write!(w, "{}", i)?,
271 NumberKind::Symbolic(s) => write!(w, "{}", interner.resolve(*s))?,
272 }
273 if let Some(u) = unit {
274 write!(w, " {}", interner.resolve(*u))?;
275 }
276 Ok(())
277 }
278 }
279 }
280
281 pub fn transpile(&self, registry: &mut SymbolRegistry, interner: &Interner) -> String {
283 let mut buf = String::new();
284 let _ = self.write_to(&mut buf, registry, interner);
285 buf
286 }
287}
288
289fn collect_discourse_conjuncts<'a>(expr: &'a LogicExpr<'a>) -> Vec<&'a LogicExpr<'a>> {
292 let mut conjuncts = Vec::new();
293 collect_discourse_conjuncts_inner(expr, &mut conjuncts);
294 conjuncts
295}
296
297fn collect_discourse_conjuncts_inner<'a>(expr: &'a LogicExpr<'a>, conjuncts: &mut Vec<&'a LogicExpr<'a>>) {
298 match expr {
299 LogicExpr::BinaryOp { left, op: TokenType::And, right } => {
300 collect_discourse_conjuncts_inner(left, conjuncts);
302 collect_discourse_conjuncts_inner(right, conjuncts);
303 }
304 _ => {
305 conjuncts.push(expr);
307 }
308 }
309}
310
311impl<'a> LogicExpr<'a> {
312 pub fn transpile_discourse(
321 &self,
322 registry: &mut SymbolRegistry,
323 interner: &Interner,
324 format: OutputFormat,
325 ) -> String {
326 let conjuncts = collect_discourse_conjuncts(self);
327
328 if conjuncts.len() <= 1 {
329 return self.transpile(registry, interner, format);
331 }
332
333 let mut result = String::new();
335 for (i, conjunct) in conjuncts.iter().enumerate() {
336 if i > 0 {
337 result.push('\n');
338 }
339 let formula = conjunct.transpile(registry, interner, format);
340 result.push_str(&format!("{}) {}", i + 1, formula));
341 }
342 result
343 }
344
345 pub fn write_logic<W: Write, F: LogicFormatter>(
346 &self,
347 w: &mut W,
348 registry: &mut SymbolRegistry,
349 interner: &Interner,
350 fmt: &F,
351 ) -> std::fmt::Result {
352 match self {
353 LogicExpr::Predicate { name, args, world } => {
354 let pred_name = if fmt.use_full_names() {
355 registry.get_symbol_full(*name, interner)
356 } else {
357 registry.get_symbol(*name, interner)
358 };
359
360 if fmt.include_world_arguments() {
362 if let Some(w_sym) = world {
363 let mut extended: Vec<Term> = args.to_vec();
365 extended.push(Term::Variable(*w_sym));
366 return fmt.write_predicate(w, &pred_name, &extended, registry, interner);
367 }
368 }
369 fmt.write_predicate(w, &pred_name, args, registry, interner)
370 }
371
372 LogicExpr::Identity { left, right } => {
373 if fmt.wrap_identity() {
374 write!(w, "(")?;
375 }
376 if fmt.preserve_case() {
377 left.write_to_raw(w, interner)?;
378 } else if fmt.use_full_names() {
379 left.write_to_full(w, registry, interner)?;
380 } else {
381 left.write_to(w, registry, interner)?;
382 }
383 write!(w, "{}", fmt.identity())?;
384 if fmt.preserve_case() {
385 right.write_to_raw(w, interner)?;
386 } else if fmt.use_full_names() {
387 right.write_to_full(w, registry, interner)?;
388 } else {
389 right.write_to(w, registry, interner)?;
390 }
391 if fmt.wrap_identity() {
392 write!(w, ")")?;
393 }
394 Ok(())
395 }
396
397 LogicExpr::Metaphor { tenor, vehicle } => {
398 write!(w, "Metaphor(")?;
399 tenor.write_to(w, registry, interner)?;
400 write!(w, ", ")?;
401 vehicle.write_to(w, registry, interner)?;
402 write!(w, ")")
403 }
404
405 LogicExpr::Quantifier { kind, variable, body, .. } => {
406 let var_str = interner.resolve(*variable);
407
408 if fmt.use_simple_events() && (var_str == "e" || var_str.starts_with("e") && var_str[1..].chars().all(|c| c.is_ascii_digit())) {
410 return body.write_logic(w, registry, interner, fmt);
411 }
412
413 let mut body_buf = String::new();
414 body.write_logic(&mut body_buf, registry, interner, fmt)?;
415 write!(w, "{}", fmt.quantifier(kind, var_str, &body_buf))
416 }
417
418 LogicExpr::Categorical(data) => {
419 let s = if fmt.use_full_names() {
420 fmt.sanitize(&data.subject.to_symbol_full(registry, interner))
421 } else {
422 fmt.sanitize(&data.subject.to_symbol(registry, interner))
423 };
424 let p = if fmt.use_full_names() {
425 fmt.sanitize(&data.predicate.to_symbol_full(registry, interner))
426 } else {
427 fmt.sanitize(&data.predicate.to_symbol(registry, interner))
428 };
429 match (&data.quantifier, data.copula_negative) {
430 (TokenType::All, false) => write!(w, "{} {} is {}", fmt.categorical_all(), s, p),
431 (TokenType::No, false) => write!(w, "{} {} is {}", fmt.categorical_no(), s, p),
432 (TokenType::Some, false) => write!(w, "{} {} is {}", fmt.categorical_some(), s, p),
433 (TokenType::Some, true) => write!(w, "{} {} is {} {}", fmt.categorical_some(), s, fmt.categorical_not(), p),
434 (TokenType::All, true) => write!(w, "{} {} is {} {}", fmt.categorical_some(), s, fmt.categorical_not(), p),
435 _ => write!(w, "Invalid Syllogism"),
436 }
437 }
438
439 LogicExpr::Relation(data) => {
440 let s = if fmt.use_full_names() {
441 data.subject.to_symbol_full(registry, interner)
442 } else {
443 data.subject.to_symbol(registry, interner)
444 };
445 let v = if fmt.use_full_names() {
446 fmt.sanitize(®istry.get_symbol_full(data.verb, interner))
447 } else {
448 fmt.sanitize(®istry.get_symbol(data.verb, interner))
449 };
450 let o = if fmt.use_full_names() {
451 data.object.to_symbol_full(registry, interner)
452 } else {
453 data.object.to_symbol(registry, interner)
454 };
455 write!(w, "{}({}, {})", v, s, o)
456 }
457
458 LogicExpr::Modal { vector, operand } => {
459 let mut o = String::new();
460 operand.write_logic(&mut o, registry, interner, fmt)?;
461 if vector.flavor == crate::ast::ModalFlavor::Evidential {
465 let source = match vector.modal_base {
466 Some(base) if fmt.use_full_names() => {
467 registry.get_symbol_full(base, interner)
468 }
469 Some(base) => registry.get_symbol(base, interner),
470 None => "Seem".to_string(),
471 };
472 return write!(w, "{}([{}])", source, o);
473 }
474 write!(w, "{}", fmt.modal(vector.domain, vector.force, &o))
475 }
476
477 LogicExpr::BinaryOp { left, op, right } => {
478 let mut l = String::new();
479 let mut r = String::new();
480 left.write_logic(&mut l, registry, interner, fmt)?;
481 right.write_logic(&mut r, registry, interner, fmt)?;
482
483 if matches!(op, TokenType::If | TokenType::Implies) {
486 let events = collect_suppress_existential_events(self);
487 if !events.is_empty() {
488 let mut result = fmt.binary_op(op, &l, &r);
490 for event_var in events.into_iter().rev() {
491 let var_str = interner.resolve(event_var);
492 result = fmt.quantifier(&QuantifierKind::Universal, var_str, &result);
493 }
494 return write!(w, "{}", result);
495 }
496 }
497
498 write!(w, "{}", fmt.binary_op(op, &l, &r))
499 }
500
501 LogicExpr::UnaryOp { op, operand } => {
502 let mut o = String::new();
503 operand.write_logic(&mut o, registry, interner, fmt)?;
504 write!(w, "{}", fmt.unary_op(op, &o))
505 }
506
507 LogicExpr::Temporal { operator, body } => {
508 let mut inner = String::new();
509 body.write_logic(&mut inner, registry, interner, fmt)?;
510 write!(w, "{}", fmt.temporal(operator, &inner))
511 }
512
513 LogicExpr::TemporalBinary { operator, left, right } => {
514 let mut l = String::new();
515 let mut r = String::new();
516 left.write_logic(&mut l, registry, interner, fmt)?;
517 right.write_logic(&mut r, registry, interner, fmt)?;
518 write!(w, "{}", fmt.temporal_binary(operator, &l, &r))
519 }
520
521 LogicExpr::Aspectual { operator, body } => {
522 let mut inner = String::new();
523 body.write_logic(&mut inner, registry, interner, fmt)?;
524 write!(w, "{}", fmt.aspectual(operator, &inner))
525 }
526
527 LogicExpr::Voice { operator, body } => {
528 let mut inner = String::new();
529 body.write_logic(&mut inner, registry, interner, fmt)?;
530 write!(w, "{}", fmt.voice(operator, &inner))
531 }
532
533 LogicExpr::Question { wh_variable, body } => {
534 let mut body_str = String::new();
535 body.write_logic(&mut body_str, registry, interner, fmt)?;
536 write!(w, "{}", fmt.lambda(interner.resolve(*wh_variable), &body_str))
537 }
538
539 LogicExpr::YesNoQuestion { body } => {
540 write!(w, "?")?;
541 body.write_logic(w, registry, interner, fmt)
542 }
543
544 LogicExpr::Atom(s) => {
545 let name = if fmt.preserve_case() {
546 interner.resolve(*s).to_string()
547 } else if fmt.use_full_names() {
548 registry.get_symbol_full(*s, interner)
549 } else {
550 registry.get_symbol(*s, interner)
551 };
552 write!(w, "{}", fmt.sanitize(&name))
553 }
554
555 LogicExpr::Lambda { variable, body } => {
556 let mut b = String::new();
557 body.write_logic(&mut b, registry, interner, fmt)?;
558 write!(w, "{}", fmt.lambda(interner.resolve(*variable), &b))
559 }
560
561 LogicExpr::App { function, argument } => {
562 write!(w, "(")?;
563 function.write_logic(w, registry, interner, fmt)?;
564 write!(w, ")(")?;
565 argument.write_logic(w, registry, interner, fmt)?;
566 write!(w, ")")
567 }
568
569 LogicExpr::Intensional { operator, content } => {
570 write!(w, "{}[", fmt.sanitize(®istry.get_symbol(*operator, interner)))?;
571 content.write_logic(w, registry, interner, fmt)?;
572 write!(w, "]")
573 }
574
575 LogicExpr::Event { predicate, adverbs } => {
576 let mut pred_str = String::new();
577 predicate.write_logic(&mut pred_str, registry, interner, fmt)?;
578 let adverb_preds: Vec<String> = adverbs
579 .iter()
580 .map(|a| format!("{}(e)", fmt.sanitize(®istry.get_symbol(*a, interner))))
581 .collect();
582 write!(w, "{}", fmt.event_quantifier(&pred_str, &adverb_preds))
583 }
584
585 LogicExpr::NeoEvent(data) => {
586 use crate::ast::{QuantifierKind, ThematicRole};
587
588 if fmt.use_simple_events() {
589 write!(w, "{}", registry.get_symbol_full(data.verb, interner))?;
590 write!(w, "(")?;
591 let mut first = true;
592 let mut subject_term = None;
593 for (role, term) in data.roles.iter() {
594 if matches!(role, ThematicRole::Agent | ThematicRole::Patient | ThematicRole::Theme | ThematicRole::Goal | ThematicRole::Location) {
596 if !first {
597 write!(w, ", ")?;
598 }
599 first = false;
600 term.write_to_full(w, registry, interner)?;
601 if subject_term.is_none() || matches!(role, ThematicRole::Agent) {
604 subject_term = Some(term);
605 }
606 }
607 }
608 write!(w, ")")?;
609 for mod_sym in data.modifiers.iter() {
613 write!(w, " {} ", fmt.and())?;
614 write_capitalized(w, interner.resolve(*mod_sym))?;
615 write!(w, "(")?;
616 if let Some(term) = subject_term {
617 term.write_to_full(w, registry, interner)?;
618 }
619 write!(w, ")")?;
620 }
621 Ok(())
622 } else {
623 let e = interner.resolve(data.event_var);
624 let mut body = String::new();
625
626 let world_suffix = if fmt.include_world_arguments() {
628 data.world.map(|w| format!(", {}", interner.resolve(w))).unwrap_or_default()
629 } else {
630 String::new()
631 };
632
633 write_capitalized(&mut body, interner.resolve(data.verb))?;
634 write!(body, "({}{})", e, world_suffix)?;
635 for (role, term) in data.roles.iter() {
636 let role_str = match role {
637 ThematicRole::Agent => "Agent",
638 ThematicRole::Patient => "Patient",
639 ThematicRole::Theme => "Theme",
640 ThematicRole::Recipient => "Recipient",
641 ThematicRole::Goal => "Goal",
642 ThematicRole::Source => "Source",
643 ThematicRole::Instrument => "Instrument",
644 ThematicRole::Location => "Location",
645 ThematicRole::Time => "Time",
646 ThematicRole::Manner => "Manner",
647 ThematicRole::Result => "Result",
648 ThematicRole::Depictive => "Depictive",
649 };
650 write!(body, " {} {}({}, ", fmt.and(), role_str, e)?;
651 if fmt.use_full_names() {
652 term.write_to_full(&mut body, registry, interner)?;
653 } else {
654 term.write_to(&mut body, registry, interner)?;
655 }
656 write!(body, "{})", world_suffix)?;
657 }
658 for mod_sym in data.modifiers.iter() {
659 write!(body, " {} ", fmt.and())?;
660 write_capitalized(&mut body, interner.resolve(*mod_sym))?;
661 write!(body, "({}{})", e, world_suffix)?;
662 }
663 if data.suppress_existential {
664 write!(w, "{}", body)
666 } else {
667 write!(w, "{}", fmt.quantifier(&QuantifierKind::Existential, e, &body))
669 }
670 }
671 }
672
673 LogicExpr::Imperative { action } => {
674 use crate::ast::ThematicRole;
679 fn directive_agent<'b>(e: &'b LogicExpr<'b>) -> Option<&'b Term<'b>> {
680 match e {
681 LogicExpr::NeoEvent(data) => data
682 .roles
683 .iter()
684 .find(|(role, _)| matches!(role, ThematicRole::Agent))
685 .map(|(_, term)| term),
686 LogicExpr::UnaryOp { operand, .. } => directive_agent(operand),
687 LogicExpr::Quantifier { body, .. } => directive_agent(body),
688 LogicExpr::BinaryOp { left, .. } => directive_agent(left),
689 _ => None,
690 }
691 }
692 let mut addressee = String::new();
693 match directive_agent(action) {
694 Some(t) if fmt.use_full_names() => {
695 t.write_to_full(&mut addressee, registry, interner)?
696 }
697 Some(t) => t.write_to(&mut addressee, registry, interner)?,
698 None => addressee.push_str("Addressee"),
699 }
700 let mut a = String::new();
701 action.write_logic(&mut a, registry, interner, fmt)?;
702 write!(w, "Directive({}, [{}])", addressee, a)
703 }
704
705 LogicExpr::Exclamative { degree_var, body } => {
706 let d = interner.resolve(*degree_var);
708 write!(w, "Exclaim(∃{}(", d)?;
709 body.write_logic(w, registry, interner, fmt)?;
710 write!(w, " {} {} ≫ θ))", fmt.and(), d)
711 }
712
713 LogicExpr::Optative { wish } => {
714 write!(w, "Wish(Speaker, ⟨")?;
716 wish.write_logic(w, registry, interner, fmt)?;
717 write!(w, "⟩)")
718 }
719
720 LogicExpr::Implicature { assertion, implicature } => {
721 assertion.write_logic(w, registry, interner, fmt)?;
724 write!(w, " +> Implicature(")?;
725 implicature.write_logic(w, registry, interner, fmt)?;
726 write!(w, ")")
727 }
728
729 LogicExpr::SpeechAct { performer, act_type, content } => {
730 write!(w, "SpeechAct({}, {}, ", interner.resolve(*act_type), fmt.sanitize(®istry.get_symbol_full(*performer, interner)))?;
733 content.write_logic(w, registry, interner, fmt)?;
734 write!(w, ")")
735 }
736
737 LogicExpr::Counterfactual { antecedent, consequent } => {
738 let mut a = String::new();
739 let mut c = String::new();
740 antecedent.write_logic(&mut a, registry, interner, fmt)?;
741 consequent.write_logic(&mut c, registry, interner, fmt)?;
742 write!(w, "{}", fmt.counterfactual(&a, &c))
743 }
744
745 LogicExpr::Causal { effect, cause } => {
746 write!(w, "Cause(")?;
747 cause.write_logic(w, registry, interner, fmt)?;
748 write!(w, ", ")?;
749 effect.write_logic(w, registry, interner, fmt)?;
750 write!(w, ")")
751 }
752
753 LogicExpr::Concessive { main, concession } => {
754 main.write_logic(w, registry, interner, fmt)?;
756 write!(w, " {} Concessive(", fmt.and())?;
757 concession.write_logic(w, registry, interner, fmt)?;
758 write!(w, ")")
759 }
760
761 LogicExpr::Comparative { adjective, subject, object, difference, relation } => {
762 use crate::ast::ComparisonRelation;
763 if !matches!(relation, ComparisonRelation::Greater) {
766 let rel = if matches!(relation, ComparisonRelation::Equal) { "=" } else { "≥" };
767 let adj = interner.resolve(*adjective);
768 let mut s = String::new();
769 subject.write_to(&mut s, registry, interner)?;
770 let mut o = String::new();
771 object.write_to(&mut o, registry, interner)?;
772 let cap = adj.chars().next()
773 .map(|c| c.to_uppercase().collect::<String>() + &adj[1..])
774 .unwrap_or_default();
775 return write!(w, "max{{d:{}({},d)}} {} max{{d:{}({},d)}}", cap, s, rel, cap, o);
776 }
777 let adj = interner.resolve(*adjective);
778 let mut subj_buf = String::new();
779 if fmt.preserve_case() {
780 subject.write_to_raw(&mut subj_buf, interner)?;
781 } else if fmt.use_full_names() {
782 subject.write_to_full(&mut subj_buf, registry, interner)?;
783 } else {
784 subject.write_to(&mut subj_buf, registry, interner)?;
785 }
786 let mut obj_buf = String::new();
787 if fmt.preserve_case() {
788 object.write_to_raw(&mut obj_buf, interner)?;
789 } else if fmt.use_full_names() {
790 object.write_to_full(&mut obj_buf, registry, interner)?;
791 } else {
792 object.write_to(&mut obj_buf, registry, interner)?;
793 }
794 let diff_str = if let Some(diff) = difference {
795 let mut diff_buf = String::new();
796 if fmt.preserve_case() {
797 diff.write_to_raw(&mut diff_buf, interner)?;
798 } else if fmt.use_full_names() {
799 diff.write_to_full(&mut diff_buf, registry, interner)?;
800 } else {
801 diff.write_to(&mut diff_buf, registry, interner)?;
802 }
803 Some(diff_buf)
804 } else {
805 None
806 };
807 fmt.write_comparative(w, adj, &subj_buf, &obj_buf, diff_str.as_deref())
808 }
809
810 LogicExpr::Superlative { adjective, subject, domain } => {
811 let mut s = String::new();
812 subject.write_to(&mut s, registry, interner)?;
813 let mut d = String::new();
814 write_capitalized(&mut d, interner.resolve(*domain))?;
815 let comp = format!("{}er", interner.resolve(*adjective));
816 write!(w, "{}", fmt.superlative(&comp, &d, &s))
817 }
818
819 LogicExpr::Scopal { operator, body } => {
820 write!(w, "{}(", interner.resolve(*operator))?;
821 body.write_logic(w, registry, interner, fmt)?;
822 write!(w, ")")
823 }
824
825 LogicExpr::TemporalAnchor { anchor, body } => {
826 write!(w, "{}(", interner.resolve(*anchor))?;
827 body.write_logic(w, registry, interner, fmt)?;
828 write!(w, ")")
829 }
830
831 LogicExpr::Control { verb, subject, object, infinitive } => {
832 write!(w, "{}(", fmt.sanitize(®istry.get_symbol(*verb, interner)))?;
833 subject.write_to(w, registry, interner)?;
834 if let Some(obj) = object {
835 write!(w, ", ")?;
836 obj.write_to(w, registry, interner)?;
837 }
838 write!(w, ", ")?;
839 infinitive.write_logic(w, registry, interner, fmt)?;
840 write!(w, ")")
841 }
842
843 LogicExpr::Presupposition { assertion, presupposition } => {
844 assertion.write_logic(w, registry, interner, fmt)?;
845 write!(w, " [Presup: ")?;
846 presupposition.write_logic(w, registry, interner, fmt)?;
847 write!(w, "]")
848 }
849
850 LogicExpr::Focus { kind, focused, scope } => {
851 use crate::token::FocusKind;
852 let prefix = match kind {
853 FocusKind::Only => "Only",
854 FocusKind::Even => "Even",
855 FocusKind::Just => "Just",
856 FocusKind::Cleft => "Cleft",
857 };
858 write!(w, "{}(", prefix)?;
859 focused.write_to(w, registry, interner)?;
860 write!(w, ", ")?;
861 scope.write_logic(w, registry, interner, fmt)?;
862 write!(w, ")")
863 }
864
865 LogicExpr::Distributive { predicate } => {
866 write!(w, "*")?;
867 predicate.write_logic(w, registry, interner, fmt)
868 }
869
870 LogicExpr::GroupQuantifier { group_var, count, member_var, restriction, body } => {
871 let g = interner.resolve(*group_var);
872 let x = interner.resolve(*member_var);
873
874 write!(w, "{}{}(Group({}) {} Count({}, {}) {} {}{}(Member({}, {}) {} ",
876 fmt.existential(), g, g,
877 fmt.and(), g, count,
878 fmt.and(), fmt.universal(), x, x, g, fmt.implies())?;
879
880 restriction.write_logic(w, registry, interner, fmt)?;
881
882 write!(w, ") {} ", fmt.and())?;
883
884 body.write_logic(w, registry, interner, fmt)?;
885
886 write!(w, ")")
887 }
888 }
889 }
890
891 pub fn transpile_with<F: LogicFormatter>(
893 &self,
894 registry: &mut SymbolRegistry,
895 interner: &Interner,
896 fmt: &F,
897 ) -> String {
898 let mut buf = String::new();
899 let _ = self.write_logic(&mut buf, registry, interner, fmt);
900 buf
901 }
902
903 pub fn transpile(
912 &self,
913 registry: &mut SymbolRegistry,
914 interner: &Interner,
915 format: OutputFormat,
916 ) -> String {
917 match format {
918 OutputFormat::Unicode => self.transpile_with(registry, interner, &UnicodeFormatter),
919 OutputFormat::LaTeX => self.transpile_with(registry, interner, &LatexFormatter),
920 OutputFormat::SimpleFOL => self.transpile_with(registry, interner, &SimpleFOLFormatter),
921 OutputFormat::Kripke => self.transpile_with(registry, interner, &KripkeFormatter),
922 }
923 }
924
925 pub fn transpile_ctx<F: LogicFormatter>(
927 &self,
928 ctx: &mut TranspileContext<'_>,
929 fmt: &F,
930 ) -> String {
931 self.transpile_with(ctx.registry, ctx.interner, fmt)
932 }
933
934 pub fn transpile_ctx_unicode(&self, ctx: &mut TranspileContext<'_>) -> String {
936 self.transpile_ctx(ctx, &UnicodeFormatter)
937 }
938
939 pub fn transpile_ctx_latex(&self, ctx: &mut TranspileContext<'_>) -> String {
941 self.transpile_ctx(ctx, &LatexFormatter)
942 }
943}