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