logicaffeine_language/ast/logic.rs
1//! Logic expression AST types for first-order logic with modal and event extensions.
2//!
3//! This module defines the core logical expression types including:
4//!
5//! - **[`LogicExpr`]**: The main expression enum with all logical constructs
6//! - **[`Term`]**: Terms (constants, variables, function applications)
7//! - **[`NounPhrase`]**: Parsed noun phrase structure
8//! - **Semantic types**: Montague-style type markers
9//! - **Event roles**: Neo-Davidsonian thematic roles (Agent, Theme, Goal, etc.)
10//! - **Modal vectors**: Kripke semantics parameters (domain, flavor, force)
11//! - **Temporal operators**: Past, future, perfect, progressive
12//!
13//! All types use arena allocation with the `'a` lifetime parameter.
14
15use logicaffeine_base::Arena;
16use logicaffeine_base::Symbol;
17use crate::lexicon::Definiteness;
18use crate::token::TokenType;
19
20// ═══════════════════════════════════════════════════════════════════
21// Semantic Types (Montague Grammar)
22// ═══════════════════════════════════════════════════════════════════
23
24/// Montague semantic types for compositional interpretation.
25///
26/// These types classify expressions according to their denotation in
27/// a model-theoretic semantics, following Montague's "Universal Grammar".
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum LogicalType {
30 /// Type `e`: Individuals (entities) like "John" or "the ball".
31 Entity,
32 /// Type `t`: Truth values (propositions) like "John runs".
33 TruthValue,
34 /// Type `<e,t>`: Properties (one-place predicates) like "is a unicorn".
35 Property,
36 /// Type `<<e,t>,t>`: Generalized quantifiers like "every man" or "a woman".
37 Quantifier,
38}
39
40// ═══════════════════════════════════════════════════════════════════
41// Degree Semantics (Prover-Ready Number System)
42// ═══════════════════════════════════════════════════════════════════
43
44/// Physical dimension for degree semantics and unit tracking.
45///
46/// Used with [`NumberKind`] to enable dimensional analysis and prevent
47/// nonsensical comparisons (e.g., adding meters to seconds).
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum Dimension {
50 /// Spatial extent (meters, feet, inches).
51 Length,
52 /// Temporal duration (seconds, minutes, hours).
53 Time,
54 /// Mass (kilograms, pounds).
55 Weight,
56 /// Thermal measure (Celsius, Fahrenheit, Kelvin).
57 Temperature,
58 /// Count of discrete items.
59 Cardinality,
60}
61
62/// Numeric literal representation for degree semantics.
63///
64/// Supports exact integers, floating-point reals, and symbolic constants
65/// (e.g., π, e) for prover integration.
66#[derive(Debug, Clone, Copy, PartialEq)]
67pub enum NumberKind {
68 /// Floating-point real number (e.g., 3.14, 0.5).
69 Real(f64),
70 /// Exact integer (e.g., 42, -1, 0).
71 Integer(i64),
72 /// Symbolic constant (e.g., π, e, ∞).
73 Symbolic(Symbol),
74}
75
76// ═══════════════════════════════════════════════════════════════════
77// First-Order Logic Types (FOL Upgrade)
78// ═══════════════════════════════════════════════════════════════════
79
80/// First-order logic term representing entities or values.
81///
82/// Terms denote individuals, groups, or computed values in the domain
83/// of discourse. They serve as arguments to predicates.
84#[derive(Debug, Clone, Copy)]
85pub enum Term<'a> {
86 /// Named individual constant (e.g., `john`, `paris`).
87 Constant(Symbol),
88 /// Bound or free variable (e.g., `x`, `y`).
89 Variable(Symbol),
90 /// Function application: `f(t1, t2, ...)` (e.g., `mother(john)`).
91 Function(Symbol, &'a [Term<'a>]),
92 /// Plural group for collective readings (e.g., `john ⊕ mary`).
93 Group(&'a [Term<'a>]),
94 /// Possessive construction: `john's book` → `Poss(john, book)`.
95 Possessed { possessor: &'a Term<'a>, possessed: Symbol },
96 /// Definite description σ-term: `σx.P(x)` ("the unique x such that P").
97 Sigma(Symbol),
98 /// Intensional term (Montague up-arrow `^P`) for de dicto readings.
99 Intension(Symbol),
100 /// Kind term (`^Kind`) — a Carlson-style kind-denoting entity, distinct
101 /// from a Montague intension. Used for kind reference ("the dodo is extinct")
102 /// and as the base of a kind-level relational adjective ("dental procedure"
103 /// → `Pertains(x, ^Tooth)`; McNally & Boleda 2004, predicates of kinds).
104 Kind(Symbol),
105 /// Sentential complement (embedded clause as propositional argument).
106 Proposition(&'a LogicExpr<'a>),
107 /// Numeric value with optional unit and dimension.
108 Value {
109 kind: NumberKind,
110 unit: Option<Symbol>,
111 dimension: Option<Dimension>,
112 },
113}
114
115/// Degree-comparison relation for [`LogicExpr::Comparative`].
116///
117/// `Greater` is the strict comparative (`>`, "taller than"); `GreaterEqual` is the
118/// equative (`≥`, "as tall as" — at least as tall); `Equal` is the exact equative
119/// ("exactly as tall as").
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121pub enum ComparisonRelation {
122 Greater,
123 GreaterEqual,
124 Equal,
125}
126
127/// Quantifier types for first-order and generalized quantifiers.
128///
129/// Extends standard FOL with generalized quantifiers that cannot be
130/// expressed with ∀ and ∃ alone (e.g., "most", "few", "at least 3").
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub enum QuantifierKind {
133 /// Universal: ∀x ("every", "all", "each").
134 Universal,
135 /// Existential: ∃x ("some", "a", "an").
136 Existential,
137 /// Proportional: "most X are Y" (>50% of domain).
138 Most,
139 /// Proportional: "few X are Y" (<expected proportion).
140 Few,
141 /// Vague large quantity: "many X are Y".
142 Many,
143 /// Exact count: "exactly n X are Y".
144 Cardinal(u32),
145 /// Lower bound: "at least n X are Y".
146 AtLeast(u32),
147 /// Upper bound: "at most n X are Y".
148 AtMost(u32),
149 /// Generic: "cats meow" (characterizing generalization).
150 Generic,
151}
152
153/// Binary logical connectives.
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
155pub enum BinaryOpKind {
156 /// Conjunction: P ∧ Q.
157 And,
158 /// Disjunction: P ∨ Q.
159 Or,
160 /// Material implication: P → Q.
161 Implies,
162 /// Biconditional: P ↔ Q.
163 Iff,
164}
165
166/// Unary logical operators.
167#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub enum UnaryOpKind {
169 /// Negation: ¬P.
170 Not,
171}
172
173// ═══════════════════════════════════════════════════════════════════
174// Temporal & Aspect Operators (Arthur Prior's Tense Logic)
175// ═══════════════════════════════════════════════════════════════════
176
177/// Temporal logic operators.
178///
179/// Prior-style tense operators (Past, Future) for linguistic temporality.
180/// Pnueli-style LTL operators (Always, Eventually, Next) for hardware verification.
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum TemporalOperator {
183 /// Past tense: P(φ) — "it was the case that φ".
184 Past,
185 /// Future tense: F(φ) — "it will be the case that φ".
186 Future,
187 /// Always/Globally: G(φ) — φ holds at every future state.
188 Always,
189 /// Eventually/Finally: F(φ) — φ holds at some future state.
190 Eventually,
191 /// Next: X(φ) — φ holds at the immediate next state.
192 Next,
193 /// Bounded Eventually: F≤n(φ) — φ holds within n steps.
194 /// SVA target: `##[0:n] φ`
195 BoundedEventually(u32),
196}
197
198/// Binary temporal operators (LTL).
199///
200/// These require two operands and express relationships between
201/// properties over time in hardware state machines.
202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203pub enum BinaryTemporalOp {
204 /// φ U ψ — φ holds until ψ becomes true.
205 Until,
206 /// φ R ψ — dual of Until: ψ holds until φ releases it (or forever).
207 Release,
208 /// φ W ψ — weak until: φ holds until ψ, or φ holds forever.
209 WeakUntil,
210}
211
212// ═══════════════════════════════════════════════════════════════════
213// Event Semantics (Neo-Davidsonian)
214// ═══════════════════════════════════════════════════════════════════
215
216/// Neo-Davidsonian thematic roles for event semantics.
217///
218/// Following Parsons' neo-Davidsonian analysis, events are reified and
219/// participants are related to events via thematic role predicates:
220/// `∃e(Run(e) ∧ Agent(e, john) ∧ Location(e, park))`.
221#[derive(Debug, Clone, Copy, PartialEq, Eq)]
222pub enum ThematicRole {
223 /// Animate initiator of action (e.g., "John" in "John ran").
224 Agent,
225 /// Entity affected by action (e.g., "the window" in "broke the window").
226 Patient,
227 /// Entity involved without change (e.g., "the ball" in "saw the ball").
228 Theme,
229 /// Animate entity receiving something (e.g., "Mary" in "gave Mary a book").
230 Recipient,
231 /// Destination or endpoint (e.g., "Paris" in "went to Paris").
232 Goal,
233 /// Origin or starting point (e.g., "London" in "came from London").
234 Source,
235 /// Tool or means (e.g., "a knife" in "cut with a knife").
236 Instrument,
237 /// Spatial setting (e.g., "the park" in "ran in the park").
238 Location,
239 /// Temporal setting (e.g., "yesterday" in "arrived yesterday").
240 Time,
241 /// How action was performed (e.g., "quickly" in "ran quickly").
242 Manner,
243 /// Resulting state of an argument — resultative secondary predication
244 /// (e.g., "red" in "painted the door red"): `Result(e, Red(door))`.
245 Result,
246 /// State an argument holds during the event — depictive secondary predication
247 /// (e.g., "raw" in "ate the meat raw"): `Depictive(e, Raw(meat))`.
248 Depictive,
249}
250
251/// Grammatical aspect operators for event structure.
252///
253/// Aspect describes the internal temporal structure of events,
254/// distinct from tense which locates events in time.
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256pub enum AspectOperator {
257 /// Ongoing action: "is running" → PROG(Run(e)).
258 Progressive,
259 /// Completed with present relevance: "has eaten" → PERF(Eat(e)).
260 Perfect,
261 /// Characteristic pattern: "smokes" (habitually) → HAB(Smoke(e)).
262 Habitual,
263 /// Repeated action: "kept knocking" → ITER(Knock(e)).
264 Iterative,
265}
266
267/// Grammatical voice operators.
268#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269pub enum VoiceOperator {
270 /// Passive voice: "was eaten" promotes patient to subject position.
271 Passive,
272}
273
274// ═══════════════════════════════════════════════════════════════════
275// Legacy Types (kept during transition)
276// ═══════════════════════════════════════════════════════════════════
277
278/// Parsed noun phrase structure for compositional interpretation.
279///
280/// Captures the internal structure of noun phrases including determiners,
281/// modifiers, and possessives for correct semantic composition.
282#[derive(Debug, Clone, Copy)]
283pub struct NounPhrase<'a> {
284 /// Definiteness: the (definite), a/an (indefinite), or bare (none).
285 pub definiteness: Option<Definiteness>,
286 /// Pre-nominal adjectives (e.g., "big red" in "big red ball").
287 pub adjectives: &'a [Symbol],
288 /// Head noun (e.g., "ball" in "big red ball").
289 pub noun: Symbol,
290 /// Possessor phrase (e.g., "John's" in "John's book").
291 pub possessor: Option<&'a NounPhrase<'a>>,
292 /// Prepositional phrase modifiers attached to noun.
293 pub pps: &'a [&'a LogicExpr<'a>],
294 /// Superlative adjective if present (e.g., "tallest").
295 pub superlative: Option<Symbol>,
296}
297
298// ═══════════════════════════════════════════════════════════════════
299// Boxed Variant Data (keeps LogicExpr enum small)
300// ═══════════════════════════════════════════════════════════════════
301
302/// Aristotelian categorical proposition data.
303///
304/// Represents the four categorical forms (A, E, I, O):
305/// - A: All S are P
306/// - E: No S are P
307/// - I: Some S are P
308/// - O: Some S are not P
309#[derive(Debug)]
310pub struct CategoricalData<'a> {
311 /// The quantifier (All, No, Some).
312 pub quantifier: TokenType,
313 /// Subject term (S in "All S are P").
314 pub subject: NounPhrase<'a>,
315 /// Whether copula is negated (for O-form: "Some S are not P").
316 pub copula_negative: bool,
317 /// Predicate term (P in "All S are P").
318 pub predicate: NounPhrase<'a>,
319}
320
321/// Simple subject-verb-object relation data.
322#[derive(Debug)]
323pub struct RelationData<'a> {
324 /// Subject noun phrase.
325 pub subject: NounPhrase<'a>,
326 /// Verb predicate.
327 pub verb: Symbol,
328 /// Object noun phrase.
329 pub object: NounPhrase<'a>,
330}
331
332/// Neo-Davidsonian event structure with thematic roles.
333///
334/// Represents a verb event with its participants decomposed into
335/// separate thematic role predicates: `∃e(Run(e) ∧ Agent(e, john))`.
336#[derive(Debug)]
337pub struct NeoEventData<'a> {
338 /// The event variable (e, e1, e2, ...).
339 pub event_var: Symbol,
340 /// The verb predicate name.
341 pub verb: Symbol,
342 /// Thematic role assignments: (Role, Filler) pairs.
343 pub roles: &'a [(ThematicRole, Term<'a>)],
344 /// Adverbial modifiers (e.g., "quickly" → Quickly(e)).
345 pub modifiers: &'a [Symbol],
346 /// When true, suppress local ∃e quantification.
347 /// Used in DRT for generic conditionals where event var is bound by outer ∀.
348 pub suppress_existential: bool,
349 /// World argument for Kripke semantics. None = implicit actual world (w₀).
350 pub world: Option<Symbol>,
351}
352
353impl<'a> NounPhrase<'a> {
354 pub fn simple(noun: Symbol) -> Self {
355 NounPhrase {
356 definiteness: None,
357 adjectives: &[],
358 noun,
359 possessor: None,
360 pps: &[],
361 superlative: None,
362 }
363 }
364
365 pub fn with_definiteness(definiteness: Definiteness, noun: Symbol) -> Self {
366 NounPhrase {
367 definiteness: Some(definiteness),
368 adjectives: &[],
369 noun,
370 possessor: None,
371 pps: &[],
372 superlative: None,
373 }
374 }
375}
376
377/// Modal logic domain classification.
378///
379/// Determines the accessibility relation in Kripke semantics:
380/// what kinds of possible worlds are relevant.
381#[derive(Debug, Clone, Copy, PartialEq)]
382pub enum ModalDomain {
383 /// Alethic modality: logical/metaphysical possibility and necessity.
384 /// "It is possible that P" = P holds in some accessible world.
385 Alethic,
386 /// Deontic modality: obligation and permission.
387 /// "It is obligatory that P" = P holds in all deontically ideal worlds.
388 Deontic,
389 /// Temporal modality: hardware state transitions.
390 /// Accessibility = next-state relation (clock-cycle transitions).
391 Temporal,
392}
393
394/// Modal flavor affecting scope interpretation.
395///
396/// The distinction between root and epistemic modals affects
397/// quantifier scope: root modals scope under quantifiers (de re),
398/// while epistemic modals scope over quantifiers (de dicto).
399#[derive(Debug, Clone, Copy, PartialEq, Eq)]
400pub enum ModalFlavor {
401 /// Root modals express ability, obligation, or circumstantial possibility.
402 /// Verbs: can, must, should, shall, could, would.
403 /// Scope: NARROW (de re) — modal attaches inside quantifier scope.
404 /// Example: "Every student can solve this" = ∀x(Student(x) → ◇Solve(x, this))
405 Root,
406 /// Epistemic modals express possibility or deduction based on evidence.
407 /// Verbs: might, may (epistemic readings).
408 /// Scope: WIDE (de dicto) — modal wraps the entire quantified formula.
409 /// Example: "A student might win" = ◇∃x(Student(x) ∧ Win(x))
410 Epistemic,
411 /// Evidential modality marks an evidence source without asserting the
412 /// complement: raising verbs seem/appear/look (§4.3).
413 /// Frame: serial, non-reflexive — Seem(⟨P⟩) does not entail P.
414 /// Example: "John seems happy" = Seem(⟨Happy(john)⟩)
415 Evidential,
416 /// Bouletic modality quantifies over preference-ideal worlds: wishes
417 /// (§1.2 optatives) and directives (§1.4 imperatives).
418 /// Frame: serial — the wished/commanded content is never entailed.
419 Bouletic,
420}
421
422/// Modal operator parameters for Kripke semantics (Kratzer-style).
423///
424/// Combines domain (what kind of modality), force (necessity vs possibility),
425/// and flavor (scope/evidence behavior) with the conversational backgrounds:
426/// a modal base f (which worlds are in play) and an ordering source g (how
427/// they are ranked). For evidentials the modal base names the evidence-source
428/// lexeme (seem/appear); counterfactuals use g = similarity.
429#[derive(Debug, Clone, Copy, PartialEq)]
430pub struct ModalVector {
431 /// The modal domain: alethic or deontic.
432 pub domain: ModalDomain,
433 /// Modal force: 1.0 = necessity (□), 0.5 = possibility (◇), graded values between.
434 pub force: f32,
435 /// Scope flavor: root (narrow scope) or epistemic (wide scope).
436 pub flavor: ModalFlavor,
437 /// Kratzer modal base f — the conversational background supplying the
438 /// accessible worlds (for evidentials: the evidence-source lexeme).
439 pub modal_base: Option<Symbol>,
440 /// Kratzer ordering source g — ranks the modal-base worlds by ideality /
441 /// normality / similarity.
442 pub ordering_source: Option<Symbol>,
443}
444
445impl ModalVector {
446 /// A modal vector with empty conversational backgrounds (f = g = None).
447 pub fn new(domain: ModalDomain, force: f32, flavor: ModalFlavor) -> Self {
448 ModalVector {
449 domain,
450 force,
451 flavor,
452 modal_base: None,
453 ordering_source: None,
454 }
455 }
456
457 /// Attach a Kratzer modal base f.
458 pub fn with_base(mut self, base: Symbol) -> Self {
459 self.modal_base = Some(base);
460 self
461 }
462}
463
464// ═══════════════════════════════════════════════════════════════════
465// Expression Enum (hybrid: old + new variants)
466// ═══════════════════════════════════════════════════════════════════
467
468/// First-order logic expression with modal, temporal, and event extensions.
469///
470/// This is the core AST type representing logical formulas. All nodes are
471/// arena-allocated with the `'a` lifetime tracking the arena's scope.
472///
473/// # Categories
474///
475/// - **Core FOL**: [`Predicate`], [`Quantifier`], [`BinaryOp`], [`UnaryOp`], [`Identity`]
476/// - **Lambda calculus**: [`Lambda`], [`App`], [`Atom`]
477/// - **Modal logic**: [`Modal`], [`Intensional`]
478/// - **Temporal/Aspect**: [`Temporal`], [`Aspectual`], [`Voice`]
479/// - **Event semantics**: [`Event`], [`NeoEvent`]
480/// - **Questions**: [`Question`], [`YesNoQuestion`]
481/// - **Pragmatics**: [`SpeechAct`], [`Focus`], [`Presupposition`]
482/// - **Comparison**: [`Comparative`], [`Superlative`]
483/// - **Other**: [`Counterfactual`], [`Causal`], [`Control`], [`Imperative`]
484///
485/// [`Predicate`]: LogicExpr::Predicate
486/// [`Quantifier`]: LogicExpr::Quantifier
487/// [`BinaryOp`]: LogicExpr::BinaryOp
488/// [`UnaryOp`]: LogicExpr::UnaryOp
489/// [`Identity`]: LogicExpr::Identity
490/// [`Lambda`]: LogicExpr::Lambda
491/// [`App`]: LogicExpr::App
492/// [`Atom`]: LogicExpr::Atom
493/// [`Modal`]: LogicExpr::Modal
494/// [`Intensional`]: LogicExpr::Intensional
495/// [`Temporal`]: LogicExpr::Temporal
496/// [`Aspectual`]: LogicExpr::Aspectual
497/// [`Voice`]: LogicExpr::Voice
498/// [`Event`]: LogicExpr::Event
499/// [`NeoEvent`]: LogicExpr::NeoEvent
500/// [`Question`]: LogicExpr::Question
501/// [`YesNoQuestion`]: LogicExpr::YesNoQuestion
502/// [`SpeechAct`]: LogicExpr::SpeechAct
503/// [`Focus`]: LogicExpr::Focus
504/// [`Presupposition`]: LogicExpr::Presupposition
505/// [`Comparative`]: LogicExpr::Comparative
506/// [`Superlative`]: LogicExpr::Superlative
507/// [`Counterfactual`]: LogicExpr::Counterfactual
508/// [`Causal`]: LogicExpr::Causal
509/// [`Control`]: LogicExpr::Control
510/// [`Imperative`]: LogicExpr::Imperative
511#[derive(Debug)]
512pub enum LogicExpr<'a> {
513 /// Atomic predicate: `P(t1, t2, ...)` with optional world parameter.
514 Predicate {
515 name: Symbol,
516 args: &'a [Term<'a>],
517 /// World argument for Kripke semantics. None = implicit actual world (w₀).
518 world: Option<Symbol>,
519 },
520
521 /// Identity statement: `t1 = t2`.
522 Identity {
523 left: &'a Term<'a>,
524 right: &'a Term<'a>,
525 },
526
527 /// Metaphorical assertion: tenor "is" vehicle (non-literal identity).
528 Metaphor {
529 tenor: &'a Term<'a>,
530 vehicle: &'a Term<'a>,
531 },
532
533 /// Quantified formula: `∀x.φ` or `∃x.φ` with scope island tracking.
534 Quantifier {
535 kind: QuantifierKind,
536 variable: Symbol,
537 body: &'a LogicExpr<'a>,
538 /// Island ID prevents illicit scope interactions across syntactic boundaries.
539 island_id: u32,
540 },
541
542 /// Aristotelian categorical proposition (boxed to keep enum small).
543 Categorical(Box<CategoricalData<'a>>),
544
545 /// Simple S-V-O relation (boxed).
546 Relation(Box<RelationData<'a>>),
547
548 /// Modal operator: □φ (necessity) or ◇φ (possibility).
549 Modal {
550 vector: ModalVector,
551 operand: &'a LogicExpr<'a>,
552 },
553
554 /// Tense/temporal operator: PAST(φ), FUTURE(φ), ALWAYS(φ), EVENTUALLY(φ), NEXT(φ).
555 Temporal {
556 operator: TemporalOperator,
557 body: &'a LogicExpr<'a>,
558 },
559
560 /// Binary temporal operator: φ UNTIL ψ, φ RELEASE ψ, φ WEAKUNTIL ψ.
561 TemporalBinary {
562 operator: BinaryTemporalOp,
563 left: &'a LogicExpr<'a>,
564 right: &'a LogicExpr<'a>,
565 },
566
567 /// Aspect operator: PROG(φ), PERF(φ), HAB(φ), ITER(φ).
568 Aspectual {
569 operator: AspectOperator,
570 body: &'a LogicExpr<'a>,
571 },
572
573 /// Voice operator: PASSIVE(φ).
574 Voice {
575 operator: VoiceOperator,
576 body: &'a LogicExpr<'a>,
577 },
578
579 /// Binary connective: φ ∧ ψ, φ ∨ ψ, φ → ψ, φ ↔ ψ.
580 BinaryOp {
581 left: &'a LogicExpr<'a>,
582 op: TokenType,
583 right: &'a LogicExpr<'a>,
584 },
585
586 /// Unary operator: ¬φ.
587 UnaryOp {
588 op: TokenType,
589 operand: &'a LogicExpr<'a>,
590 },
591
592 /// Wh-question: λx.φ where x is the questioned variable.
593 Question {
594 wh_variable: Symbol,
595 body: &'a LogicExpr<'a>,
596 },
597
598 /// Yes/no question: ?φ (is φ true?).
599 YesNoQuestion {
600 body: &'a LogicExpr<'a>,
601 },
602
603 /// Atomic symbol (variable or constant in lambda context).
604 Atom(Symbol),
605
606 /// Lambda abstraction: λx.φ.
607 Lambda {
608 variable: Symbol,
609 body: &'a LogicExpr<'a>,
610 },
611
612 /// Function application: (φ)(ψ).
613 App {
614 function: &'a LogicExpr<'a>,
615 argument: &'a LogicExpr<'a>,
616 },
617
618 /// Intensional context: `operator[content]` for opaque verbs (believes, seeks).
619 Intensional {
620 operator: Symbol,
621 content: &'a LogicExpr<'a>,
622 },
623
624 /// Legacy event semantics (Davidson-style with adverb list).
625 Event {
626 predicate: &'a LogicExpr<'a>,
627 adverbs: &'a [Symbol],
628 },
629
630 /// Neo-Davidsonian event with thematic roles (boxed).
631 NeoEvent(Box<NeoEventData<'a>>),
632
633 /// Imperative command: !φ.
634 Imperative {
635 action: &'a LogicExpr<'a>,
636 },
637
638 /// Exclamative: affective stance toward a surprisingly-high degree, with no
639 /// subject-aux inversion ("How tall she is!", "What a fool he is!"). Asserts
640 /// `∃degree_var(body ∧ degree_var ≫ θ)` and presupposes `body`.
641 Exclamative {
642 degree_var: Symbol,
643 body: &'a LogicExpr<'a>,
644 },
645
646 /// Optative: a wish with no asserted truth ("May you prosper!", "Long live the
647 /// king!", "If only it were Friday!"). → `Wish(speaker, ⟨wish⟩)`; the complement
648 /// is NOT entailed.
649 Optative {
650 wish: &'a LogicExpr<'a>,
651 },
652
653 /// Scalar implicature (§8.7): a weak scalar item asserts `assertion` and
654 /// DEFEASIBLY implicates `implicature` (the negation of a stronger Horn
655 /// alternative). "Some students passed." → ∃… +> ¬∀…. Rendered `assertion +>
656 /// implicature`; the implicature is cancellable and not part of truth conditions.
657 Implicature {
658 assertion: &'a LogicExpr<'a>,
659 implicature: &'a LogicExpr<'a>,
660 },
661
662 /// Speech act: performative utterance with illocutionary force.
663 SpeechAct {
664 performer: Symbol,
665 act_type: Symbol,
666 content: &'a LogicExpr<'a>,
667 },
668
669 /// Counterfactual conditional: "If P had been, Q would have been".
670 Counterfactual {
671 antecedent: &'a LogicExpr<'a>,
672 consequent: &'a LogicExpr<'a>,
673 },
674
675 /// Causal relation: "effect because cause".
676 Causal {
677 effect: &'a LogicExpr<'a>,
678 cause: &'a LogicExpr<'a>,
679 },
680
681 /// Concessive relation: "main, although concession" — the main clause holds
682 /// DESPITE a defeated expectation from the concession ("Although she was tired,
683 /// she finished." → Finish(she) ∧ Concessive(Tired(she))).
684 Concessive {
685 main: &'a LogicExpr<'a>,
686 concession: &'a LogicExpr<'a>,
687 },
688
689 /// Comparative / equative: "X is taller than Y" (`>`), "X is as tall as Y"
690 /// (`≥`), "X is as tall as Y and no taller" (`=`). The `relation` selects the
691 /// degree comparison; `difference` is the optional measure ("by 2 inches").
692 Comparative {
693 adjective: Symbol,
694 subject: &'a Term<'a>,
695 object: &'a Term<'a>,
696 difference: Option<&'a Term<'a>>,
697 relation: ComparisonRelation,
698 },
699
700 /// Superlative: "X is the tallest among domain".
701 Superlative {
702 adjective: Symbol,
703 subject: &'a Term<'a>,
704 domain: Symbol,
705 },
706
707 /// Scopal adverb: "only", "always", etc. as operators.
708 Scopal {
709 operator: Symbol,
710 body: &'a LogicExpr<'a>,
711 },
712
713 /// Control verb: "wants to VP", "persuaded X to VP".
714 Control {
715 verb: Symbol,
716 subject: &'a Term<'a>,
717 object: Option<&'a Term<'a>>,
718 infinitive: &'a LogicExpr<'a>,
719 },
720
721 /// Presupposition-assertion structure.
722 Presupposition {
723 assertion: &'a LogicExpr<'a>,
724 presupposition: &'a LogicExpr<'a>,
725 },
726
727 /// Focus particle: "only X", "even X" with alternative set.
728 Focus {
729 kind: crate::token::FocusKind,
730 focused: &'a Term<'a>,
731 scope: &'a LogicExpr<'a>,
732 },
733
734 /// Temporal anchor: "yesterday(φ)", "now(φ)".
735 TemporalAnchor {
736 anchor: Symbol,
737 body: &'a LogicExpr<'a>,
738 },
739
740 /// Distributive operator: *P distributes P over group members.
741 Distributive {
742 predicate: &'a LogicExpr<'a>,
743 },
744
745 /// Group quantifier for collective cardinal readings.
746 /// `∃g(Group(g) ∧ Count(g,n) ∧ ∀x(Member(x,g) → Restriction(x)) ∧ Body(g))`
747 GroupQuantifier {
748 group_var: Symbol,
749 count: u32,
750 member_var: Symbol,
751 restriction: &'a LogicExpr<'a>,
752 body: &'a LogicExpr<'a>,
753 },
754}
755
756impl<'a> LogicExpr<'a> {
757 pub fn lambda(var: Symbol, body: &'a LogicExpr<'a>, arena: &'a Arena<LogicExpr<'a>>) -> &'a LogicExpr<'a> {
758 arena.alloc(LogicExpr::Lambda {
759 variable: var,
760 body,
761 })
762 }
763
764 pub fn app(func: &'a LogicExpr<'a>, arg: &'a LogicExpr<'a>, arena: &'a Arena<LogicExpr<'a>>) -> &'a LogicExpr<'a> {
765 arena.alloc(LogicExpr::App {
766 function: func,
767 argument: arg,
768 })
769 }
770}
771
772#[cfg(test)]
773mod size_tests {
774 use super::*;
775 use std::mem::size_of;
776
777 #[test]
778 fn test_ast_node_sizes() {
779 println!("LogicExpr size: {} bytes", size_of::<LogicExpr>());
780 println!("Term size: {} bytes", size_of::<Term>());
781 println!("NounPhrase size: {} bytes", size_of::<NounPhrase>());
782
783 assert!(
784 size_of::<LogicExpr>() <= 48,
785 "LogicExpr is {} bytes - consider boxing large variants",
786 size_of::<LogicExpr>()
787 );
788 assert!(
789 size_of::<Term>() <= 32,
790 "Term is {} bytes",
791 size_of::<Term>()
792 );
793 }
794}