1use std::fmt;
23
24use crate::ast::{
25 AspectOperator, BinaryTemporalOp, LogicExpr, NounPhrase, QuantifierKind, TemporalOperator,
26 VoiceOperator, Term,
27};
28use logicaffeine_base::{Interner, Symbol};
29use crate::token::TokenType;
30
31pub trait DisplayWith {
33 fn fmt_with(&self, interner: &Interner, f: &mut fmt::Formatter<'_>) -> fmt::Result;
34
35 fn with<'a>(&'a self, interner: &'a Interner) -> WithInterner<'a, Self> {
36 WithInterner {
37 target: self,
38 interner,
39 }
40 }
41}
42
43pub struct WithInterner<'a, T: ?Sized> {
44 pub target: &'a T,
45 pub interner: &'a Interner,
46}
47
48impl<'a, T: DisplayWith> fmt::Display for WithInterner<'a, T> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 self.target.fmt_with(self.interner, f)
51 }
52}
53
54pub struct DebugWorld<'a, T: ?Sized> {
55 pub target: &'a T,
56 pub interner: &'a Interner,
57}
58
59impl<'a, T: DisplayWith> fmt::Debug for DebugWorld<'a, T> {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 self.target.fmt_with(self.interner, f)
62 }
63}
64
65impl DisplayWith for Symbol {
66 fn fmt_with(&self, interner: &Interner, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "{}", interner.resolve(*self))
68 }
69}
70
71impl<'a> DisplayWith for Term<'a> {
72 fn fmt_with(&self, interner: &Interner, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 match self {
74 Term::Constant(s) => write!(f, "{}", interner.resolve(*s)),
75 Term::Variable(s) => write!(f, "{}", interner.resolve(*s)),
76 Term::Function(name, args) => {
77 write!(f, "{}(", interner.resolve(*name))?;
78 for (i, arg) in args.iter().enumerate() {
79 if i > 0 {
80 write!(f, ", ")?;
81 }
82 arg.fmt_with(interner, f)?;
83 }
84 write!(f, ")")
85 }
86 Term::Group(members) => {
87 write!(f, "[")?;
88 for (i, m) in members.iter().enumerate() {
89 if i > 0 {
90 write!(f, " ⊕ ")?;
91 }
92 m.fmt_with(interner, f)?;
93 }
94 write!(f, "]")
95 }
96 Term::Possessed { possessor, possessed } => {
97 possessor.fmt_with(interner, f)?;
98 write!(f, ".{}", interner.resolve(*possessed))
99 }
100 Term::Sigma(predicate) => {
101 write!(f, "σx.{}(x)", interner.resolve(*predicate))
102 }
103 Term::Intension(predicate) => {
104 write!(f, "^{}", interner.resolve(*predicate))
105 }
106 Term::Kind(kind) => {
107 write!(f, "^{}", interner.resolve(*kind))
108 }
109 Term::Proposition(expr) => {
110 write!(f, "[{:?}]", expr)
111 }
112 Term::Value { kind, unit, dimension } => {
113 use crate::ast::NumberKind;
114 match kind {
115 NumberKind::Real(r) => write!(f, "{}", r)?,
116 NumberKind::Integer(i) => write!(f, "{}", i)?,
117 NumberKind::Symbolic(s) => write!(f, "{}", interner.resolve(*s))?,
118 }
119 if let Some(u) = unit {
120 write!(f, " {}", interner.resolve(*u))?;
121 }
122 if let Some(d) = dimension {
123 write!(f, " [{:?}]", d)?;
124 }
125 Ok(())
126 }
127 }
128 }
129}
130
131impl<'a> DisplayWith for NounPhrase<'a> {
132 fn fmt_with(&self, interner: &Interner, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 if let Some(def) = &self.definiteness {
134 write!(f, "{:?} ", def)?;
135 }
136 for adj in self.adjectives {
137 write!(f, "{} ", interner.resolve(*adj))?;
138 }
139 write!(f, "{}", interner.resolve(self.noun))
140 }
141}
142
143impl<'a> DisplayWith for LogicExpr<'a> {
144 fn fmt_with(&self, interner: &Interner, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 match self {
146 LogicExpr::Predicate { name, args, .. } => {
147 write!(f, "{}(", interner.resolve(*name))?;
148 for (i, arg) in args.iter().enumerate() {
149 if i > 0 {
150 write!(f, ", ")?;
151 }
152 arg.fmt_with(interner, f)?;
153 }
154 write!(f, ")")
155 }
156 LogicExpr::Identity { left, right } => {
157 left.fmt_with(interner, f)?;
158 write!(f, " = ")?;
159 right.fmt_with(interner, f)
160 }
161 LogicExpr::Metaphor { tenor, vehicle } => {
162 write!(f, "Metaphor(")?;
163 tenor.fmt_with(interner, f)?;
164 write!(f, ", ")?;
165 vehicle.fmt_with(interner, f)?;
166 write!(f, ")")
167 }
168 LogicExpr::Quantifier { kind, variable, body, .. } => {
169 let q = match kind {
170 QuantifierKind::Universal => "∀",
171 QuantifierKind::Existential => "∃",
172 QuantifierKind::Most => "MOST",
173 QuantifierKind::Few => "FEW",
174 QuantifierKind::Many => "MANY",
175 QuantifierKind::Generic => "Gen",
176 QuantifierKind::Cardinal(n) => return write!(f, "∃={}{}.{}", n, interner.resolve(*variable), body.with(interner)),
177 QuantifierKind::AtLeast(n) => return write!(f, "∃≥{}{}.{}", n, interner.resolve(*variable), body.with(interner)),
178 QuantifierKind::AtMost(n) => return write!(f, "∃≤{}{}.{}", n, interner.resolve(*variable), body.with(interner)),
179 };
180 write!(f, "{}{}.{}", q, interner.resolve(*variable), body.with(interner))
181 }
182 LogicExpr::Categorical(data) => {
183 let q = match &data.quantifier {
184 TokenType::All => "All",
185 TokenType::Some => "Some",
186 TokenType::No => "No",
187 _ => "?",
188 };
189 let cop = if data.copula_negative { "are not" } else { "are" };
190 write!(f, "{} {} {} {}", q, data.subject.with(interner), cop, data.predicate.with(interner))
191 }
192 LogicExpr::Relation(data) => {
193 write!(f, "{}({}, {})", interner.resolve(data.verb), data.subject.with(interner), data.object.with(interner))
194 }
195 LogicExpr::Modal { vector, operand } => {
196 let op = match (vector.domain, vector.force > 0.5) {
200 (crate::ast::ModalDomain::Alethic, true) => "□",
201 (crate::ast::ModalDomain::Alethic, false) => "◇",
202 (crate::ast::ModalDomain::Deontic, true) => "O",
203 (crate::ast::ModalDomain::Deontic, false) => "P",
204 (crate::ast::ModalDomain::Temporal, _) => "Temporal",
205 };
206 write!(f, "{}({})", op, operand.with(interner))
207 }
208 LogicExpr::Temporal { operator, body } => {
209 let op = match operator {
210 TemporalOperator::Past => "P",
211 TemporalOperator::Future => "F",
212 TemporalOperator::Always => "G",
213 TemporalOperator::Eventually
214 | TemporalOperator::BoundedEventually(_) => "F",
215 TemporalOperator::Next => "X",
216 };
217 write!(f, "{}({})", op, body.with(interner))
218 }
219 LogicExpr::Aspectual { operator, body } => {
220 let op = match operator {
221 AspectOperator::Progressive => "PROG",
222 AspectOperator::Perfect => "PERF",
223 AspectOperator::Habitual => "HAB",
224 AspectOperator::Iterative => "ITER",
225 };
226 write!(f, "{}({})", op, body.with(interner))
227 }
228 LogicExpr::Voice { operator, body } => {
229 let op = match operator {
230 VoiceOperator::Passive => "PASS",
231 };
232 write!(f, "{}({})", op, body.with(interner))
233 }
234 LogicExpr::BinaryOp { left, op, right } => {
235 let sym = match op {
236 TokenType::And => "∧",
237 TokenType::Or => "∨",
238 TokenType::If => "→",
239 TokenType::Iff => "↔",
240 _ => "?",
241 };
242 write!(f, "({} {} {})", left.with(interner), sym, right.with(interner))
243 }
244 LogicExpr::UnaryOp { op, operand } => {
245 let sym = match op {
246 TokenType::Not => "¬",
247 _ => "?",
248 };
249 write!(f, "{}({})", sym, operand.with(interner))
250 }
251 LogicExpr::Question { wh_variable, body } => {
252 write!(f, "?{}.{}", interner.resolve(*wh_variable), body.with(interner))
253 }
254 LogicExpr::YesNoQuestion { body } => {
255 write!(f, "?{}", body.with(interner))
256 }
257 LogicExpr::Atom(s) => write!(f, "{}", interner.resolve(*s)),
258 LogicExpr::Lambda { variable, body } => {
259 write!(f, "λ{}.{}", interner.resolve(*variable), body.with(interner))
260 }
261 LogicExpr::App { function, argument } => {
262 write!(f, "({})({})", function.with(interner), argument.with(interner))
263 }
264 LogicExpr::Intensional { operator, content } => {
265 write!(f, "{}({})", interner.resolve(*operator), content.with(interner))
266 }
267 LogicExpr::Event { predicate, adverbs } => {
268 predicate.fmt_with(interner, f)?;
269 for adv in *adverbs {
270 write!(f, "[{}]", interner.resolve(*adv))?;
271 }
272 Ok(())
273 }
274 LogicExpr::NeoEvent(data) => {
275 write!(f, "∃{}({}({})", interner.resolve(data.event_var), interner.resolve(data.verb), interner.resolve(data.event_var))?;
276 for (role, term) in data.roles.iter() {
277 write!(f, " ∧ {:?}({}, {})", role, interner.resolve(data.event_var), term.with(interner))?;
278 }
279 for mod_sym in data.modifiers.iter() {
280 write!(f, " ∧ {}({})", interner.resolve(*mod_sym), interner.resolve(data.event_var))?;
281 }
282 write!(f, ")")
283 }
284 LogicExpr::Imperative { action } => {
285 write!(f, "!({})", action.with(interner))
286 }
287 LogicExpr::Exclamative { degree_var, body } => {
288 write!(f, "Exclaim(∃{}({} ∧ {} ≫ θ))",
289 interner.resolve(*degree_var), body.with(interner), interner.resolve(*degree_var))
290 }
291 LogicExpr::Optative { wish } => {
292 write!(f, "Wish(Speaker, ⟨{}⟩)", wish.with(interner))
293 }
294 LogicExpr::Implicature { assertion, implicature } => {
295 write!(f, "{} +> Implicature({})", assertion.with(interner), implicature.with(interner))
296 }
297 LogicExpr::SpeechAct { performer, act_type, content } => {
298 write!(f, "{}:{}({})", interner.resolve(*performer), interner.resolve(*act_type), content.with(interner))
299 }
300 LogicExpr::Counterfactual { antecedent, consequent } => {
301 write!(f, "({} □→ {})", antecedent.with(interner), consequent.with(interner))
302 }
303 LogicExpr::Causal { effect, cause } => {
304 write!(f, "Cause({}, {})", cause.with(interner), effect.with(interner))
305 }
306 LogicExpr::Concessive { main, concession } => {
307 write!(f, "{} ∧ Concessive({})", main.with(interner), concession.with(interner))
308 }
309 LogicExpr::Comparative { adjective, subject, object, difference, .. } => {
310 if let Some(diff) = difference {
311 write!(f, "{}({}, {}, by: {})", interner.resolve(*adjective), subject.with(interner), object.with(interner), diff.with(interner))
312 } else {
313 write!(f, "{}({}, {})", interner.resolve(*adjective), subject.with(interner), object.with(interner))
314 }
315 }
316 LogicExpr::Superlative { adjective, subject, domain } => {
317 write!(f, "MOST-{}({}, {})", interner.resolve(*adjective), subject.with(interner), interner.resolve(*domain))
318 }
319 LogicExpr::Scopal { operator, body } => {
320 write!(f, "{}({})", interner.resolve(*operator), body.with(interner))
321 }
322 LogicExpr::Control { verb, subject, object, infinitive } => {
323 write!(f, "{}(", interner.resolve(*verb))?;
324 subject.fmt_with(interner, f)?;
325 if let Some(obj) = object {
326 write!(f, ", ")?;
327 obj.fmt_with(interner, f)?;
328 }
329 write!(f, ", {})", infinitive.with(interner))
330 }
331 LogicExpr::Presupposition { assertion, presupposition } => {
332 write!(f, "[{} | {}]", assertion.with(interner), presupposition.with(interner))
333 }
334 LogicExpr::Focus { kind, focused, scope } => {
335 let k = match kind {
336 crate::token::FocusKind::Only => "ONLY",
337 crate::token::FocusKind::Even => "EVEN",
338 crate::token::FocusKind::Just => "JUST",
339 crate::token::FocusKind::Cleft => "CLEFT",
340 };
341 write!(f, "{}[", k)?;
342 focused.fmt_with(interner, f)?;
343 write!(f, "]({})", scope.with(interner))
344 }
345 LogicExpr::TemporalAnchor { anchor, body } => {
346 write!(f, "@{}({})", interner.resolve(*anchor), body.with(interner))
347 }
348 LogicExpr::Distributive { predicate } => {
349 write!(f, "*")?;
350 predicate.fmt_with(interner, f)
351 }
352 LogicExpr::GroupQuantifier { group_var, count, member_var, restriction, body } => {
353 write!(
354 f,
355 "∃{}(Group({}) ∧ Count({}, {}) ∧ ∀{}(Member({}, {}) → ",
356 interner.resolve(*group_var),
357 interner.resolve(*group_var),
358 interner.resolve(*group_var),
359 count,
360 interner.resolve(*member_var),
361 interner.resolve(*member_var),
362 interner.resolve(*group_var)
363 )?;
364 restriction.fmt_with(interner, f)?;
365 write!(f, ") ∧ ")?;
366 body.fmt_with(interner, f)?;
367 write!(f, ")")
368 }
369 LogicExpr::TemporalBinary { operator, left, right } => {
370 let op = match operator {
371 BinaryTemporalOp::Until => "U",
372 BinaryTemporalOp::Release => "R",
373 BinaryTemporalOp::WeakUntil => "W",
374 };
375 write!(f, "({} {} {})", left.with(interner), op, right.with(interner))
376 }
377 }
378 }
379}
380
381#[cfg(test)]
382mod tests {
383 use super::*;
384 use logicaffeine_base::Arena;
385
386 #[test]
387 fn symbol_display_with_interner() {
388 let mut interner = Interner::new();
389 let sym = interner.intern("Socrates");
390 assert_eq!(sym.with(&interner).to_string(), "Socrates");
391 }
392
393 #[test]
394 fn symbol_empty_displays_empty() {
395 let interner = Interner::new();
396 assert_eq!(Symbol::EMPTY.with(&interner).to_string(), "");
397 }
398
399 #[test]
400 fn term_constant_display() {
401 let mut interner = Interner::new();
402 let sym = interner.intern("John");
403 let term = Term::Constant(sym);
404 assert_eq!(term.with(&interner).to_string(), "John");
405 }
406
407 #[test]
408 fn term_variable_display() {
409 let mut interner = Interner::new();
410 let x = interner.intern("x");
411 let term = Term::Variable(x);
412 assert_eq!(term.with(&interner).to_string(), "x");
413 }
414
415 #[test]
416 fn term_function_display() {
417 let mut interner = Interner::new();
418 let term_arena: Arena<Term> = Arena::new();
419 let f = interner.intern("father");
420 let j = interner.intern("John");
421 let term = Term::Function(f, term_arena.alloc_slice([Term::Constant(j)]));
422 assert_eq!(term.with(&interner).to_string(), "father(John)");
423 }
424
425 #[test]
426 fn term_group_display() {
427 let mut interner = Interner::new();
428 let term_arena: Arena<Term> = Arena::new();
429 let j = interner.intern("John");
430 let m = interner.intern("Mary");
431 let term = Term::Group(term_arena.alloc_slice([Term::Constant(j), Term::Constant(m)]));
432 assert_eq!(term.with(&interner).to_string(), "[John ⊕ Mary]");
433 }
434
435 #[test]
436 fn term_possessed_display() {
437 let mut interner = Interner::new();
438 let term_arena: Arena<Term> = Arena::new();
439 let j = interner.intern("John");
440 let dog = interner.intern("dog");
441 let term = Term::Possessed {
442 possessor: term_arena.alloc(Term::Constant(j)),
443 possessed: dog,
444 };
445 assert_eq!(term.with(&interner).to_string(), "John.dog");
446 }
447
448 #[test]
449 fn expr_predicate_display() {
450 let mut interner = Interner::new();
451 let term_arena: Arena<Term> = Arena::new();
452 let mortal = interner.intern("Mortal");
453 let x = interner.intern("x");
454 let expr = LogicExpr::Predicate {
455 name: mortal,
456 args: term_arena.alloc_slice([Term::Variable(x)]),
457 world: None,
458 };
459 assert_eq!(expr.with(&interner).to_string(), "Mortal(x)");
460 }
461
462 #[test]
463 fn expr_quantifier_display() {
464 let mut interner = Interner::new();
465 let expr_arena: Arena<LogicExpr> = Arena::new();
466 let term_arena: Arena<Term> = Arena::new();
467 let x = interner.intern("x");
468 let mortal = interner.intern("Mortal");
469 let body = expr_arena.alloc(LogicExpr::Predicate {
470 name: mortal,
471 args: term_arena.alloc_slice([Term::Variable(x)]),
472 world: None,
473 });
474 let expr = LogicExpr::Quantifier {
475 kind: QuantifierKind::Universal,
476 variable: x,
477 body,
478 island_id: 0,
479 };
480 assert_eq!(expr.with(&interner).to_string(), "∀x.Mortal(x)");
481 }
482
483 #[test]
484 fn expr_atom_display() {
485 let mut interner = Interner::new();
486 let p = interner.intern("P");
487 let expr = LogicExpr::Atom(p);
488 assert_eq!(expr.with(&interner).to_string(), "P");
489 }
490
491 #[test]
492 fn expr_binary_op_display() {
493 let mut interner = Interner::new();
494 let expr_arena: Arena<LogicExpr> = Arena::new();
495 let p = interner.intern("P");
496 let q = interner.intern("Q");
497 let expr = LogicExpr::BinaryOp {
498 left: expr_arena.alloc(LogicExpr::Atom(p)),
499 op: TokenType::And,
500 right: expr_arena.alloc(LogicExpr::Atom(q)),
501 };
502 assert_eq!(expr.with(&interner).to_string(), "(P ∧ Q)");
503 }
504
505 #[test]
506 fn expr_lambda_display() {
507 let mut interner = Interner::new();
508 let expr_arena: Arena<LogicExpr> = Arena::new();
509 let x = interner.intern("x");
510 let p = interner.intern("P");
511 let expr = LogicExpr::Lambda {
512 variable: x,
513 body: expr_arena.alloc(LogicExpr::Atom(p)),
514 };
515 assert_eq!(expr.with(&interner).to_string(), "λx.P");
516 }
517
518 #[test]
519 fn debug_world_works_with_dbg_pattern() {
520 let mut interner = Interner::new();
521 let sym = interner.intern("test");
522 let term = Term::Constant(sym);
523 let debug_str = format!("{:?}", DebugWorld { target: &term, interner: &interner });
524 assert!(debug_str.contains("test"));
525 }
526
527 #[test]
528 fn expr_temporal_display() {
529 let mut interner = Interner::new();
530 let expr_arena: Arena<LogicExpr> = Arena::new();
531 let p = interner.intern("Run");
532 let expr = LogicExpr::Temporal {
533 operator: TemporalOperator::Past,
534 body: expr_arena.alloc(LogicExpr::Atom(p)),
535 };
536 assert_eq!(expr.with(&interner).to_string(), "P(Run)");
537 }
538
539 #[test]
540 fn expr_modal_display() {
541 let mut interner = Interner::new();
542 let expr_arena: Arena<LogicExpr> = Arena::new();
543 let p = interner.intern("Rain");
544 let expr = LogicExpr::Modal {
545 vector: crate::ast::ModalVector {
546 domain: crate::ast::ModalDomain::Alethic,
547 force: 1.0,
548 flavor: crate::ast::ModalFlavor::Root, modal_base: None, ordering_source: None
549 },
550 operand: expr_arena.alloc(LogicExpr::Atom(p)),
551 };
552 assert_eq!(expr.with(&interner).to_string(), "□(Rain)");
553 }
554
555 #[test]
559 fn expr_modal_display_force_half_is_possibility_not_necessity() {
560 let mut interner = Interner::new();
561 let expr_arena: Arena<LogicExpr> = Arena::new();
562 let fly = interner.intern("Fly");
563 let expr = LogicExpr::Modal {
564 vector: crate::ast::ModalVector {
565 domain: crate::ast::ModalDomain::Alethic,
566 force: 0.5,
567 flavor: crate::ast::ModalFlavor::Root,
568 modal_base: None,
569 ordering_source: None,
570 },
571 operand: expr_arena.alloc(LogicExpr::Atom(fly)),
572 };
573 assert_eq!(expr.with(&interner).to_string(), "◇(Fly)");
574 }
575}