1use logicaffeine_base::Arena;
8use crate::ast::{LogicExpr, ModalDomain, ModalVector, NeoEventData, QuantifierKind, Term};
9use logicaffeine_base::{Interner, Symbol};
10use crate::token::TokenType;
11
12pub struct KripkeContext {
18 world_counter: u32,
19 current_world: Symbol,
20 clock_counter: u32,
23 domain_hint: Option<ModalDomain>,
27}
28
29impl KripkeContext {
30 pub fn new(interner: &mut Interner) -> Self {
31 Self {
32 world_counter: 0,
33 current_world: interner.intern("w0"),
34 clock_counter: 0,
35 domain_hint: None,
36 }
37 }
38
39 pub fn fresh_world(&mut self, interner: &mut Interner) -> Symbol {
40 self.world_counter += 1;
41 interner.intern(&format!("w{}", self.world_counter))
42 }
43
44 pub fn clock_counter(&self) -> u32 {
46 self.clock_counter
47 }
48
49 pub fn domain_hint(&self) -> Option<ModalDomain> {
51 self.domain_hint
52 }
53
54 fn tick_clock(&mut self) {
56 self.clock_counter += 1;
57 }
58
59 fn set_domain_hint(&mut self, domain: ModalDomain) {
61 self.domain_hint = Some(domain);
62 }
63
64 fn clear_domain_hint(&mut self) {
66 self.domain_hint = None;
67 }
68}
69
70pub fn apply_kripke_lowering<'a>(
79 expr: &'a LogicExpr<'a>,
80 expr_arena: &'a Arena<LogicExpr<'a>>,
81 term_arena: &'a Arena<Term<'a>>,
82 interner: &mut Interner,
83) -> &'a LogicExpr<'a> {
84 let mut ctx = KripkeContext::new(interner);
85 lower_expr(expr, &mut ctx, expr_arena, term_arena, interner)
86}
87
88fn lower_expr<'a>(
89 expr: &'a LogicExpr<'a>,
90 ctx: &mut KripkeContext,
91 expr_arena: &'a Arena<LogicExpr<'a>>,
92 term_arena: &'a Arena<Term<'a>>,
93 interner: &mut Interner,
94) -> &'a LogicExpr<'a> {
95 match expr {
96 LogicExpr::Modal { vector, operand } => {
97 lower_modal(vector, operand, ctx, expr_arena, term_arena, interner)
98 }
99
100 LogicExpr::Predicate { name, args, world } => {
101 if world.is_none() {
102 expr_arena.alloc(LogicExpr::Predicate {
104 name: *name,
105 args: *args,
106 world: Some(ctx.current_world),
107 })
108 } else {
109 expr
110 }
111 }
112
113 LogicExpr::Quantifier { kind, variable, body, island_id } => {
114 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
115 expr_arena.alloc(LogicExpr::Quantifier {
116 kind: *kind,
117 variable: *variable,
118 body: new_body,
119 island_id: *island_id,
120 })
121 }
122
123 LogicExpr::BinaryOp { left, op, right } => {
124 let new_left = lower_expr(left, ctx, expr_arena, term_arena, interner);
125 let new_right = lower_expr(right, ctx, expr_arena, term_arena, interner);
126 expr_arena.alloc(LogicExpr::BinaryOp {
127 left: new_left,
128 op: op.clone(),
129 right: new_right,
130 })
131 }
132
133 LogicExpr::UnaryOp { op, operand } => {
134 let new_operand = lower_expr(operand, ctx, expr_arena, term_arena, interner);
135 expr_arena.alloc(LogicExpr::UnaryOp {
136 op: op.clone(),
137 operand: new_operand,
138 })
139 }
140
141 LogicExpr::NeoEvent(data) => {
142 if data.world.is_none() {
144 expr_arena.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
145 event_var: data.event_var,
146 verb: data.verb,
147 roles: data.roles,
148 modifiers: data.modifiers,
149 suppress_existential: data.suppress_existential,
150 world: Some(ctx.current_world),
151 })))
152 } else {
153 expr
154 }
155 }
156
157 LogicExpr::Temporal { operator, body } => {
158 use crate::ast::logic::TemporalOperator;
159 ctx.set_domain_hint(ModalDomain::Temporal);
161 let result = match operator {
162 TemporalOperator::Always => {
164 lower_temporal_unary(
166 body, ctx, expr_arena, term_arena, interner,
167 "Accessible_Temporal", true,
168 )
169 }
170 TemporalOperator::Eventually => {
171 lower_temporal_unary(
173 body, ctx, expr_arena, term_arena, interner,
174 "Reachable_Temporal", false,
175 )
176 }
177 TemporalOperator::BoundedEventually(n) => {
178 let lowered_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
180 expr_arena.alloc(LogicExpr::Temporal {
181 operator: TemporalOperator::BoundedEventually(*n),
182 body: lowered_body,
183 })
184 }
185 TemporalOperator::Next => {
186 ctx.tick_clock();
188 lower_temporal_unary(
189 body, ctx, expr_arena, term_arena, interner,
190 "Next_Temporal", true,
191 )
192 }
193 TemporalOperator::Past | TemporalOperator::Future => {
195 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
196 expr_arena.alloc(LogicExpr::Temporal {
197 operator: *operator,
198 body: new_body,
199 })
200 }
201 };
202 ctx.clear_domain_hint();
203 result
204 }
205
206 LogicExpr::TemporalBinary { operator, left, right } => {
207 let new_left = lower_expr(left, ctx, expr_arena, term_arena, interner);
210 let new_right = lower_expr(right, ctx, expr_arena, term_arena, interner);
211
212 let source_world = ctx.current_world;
214 let target_world = ctx.fresh_world(interner);
215 let next_name = interner.intern("Next_Temporal");
216 let accessibility = expr_arena.alloc(LogicExpr::Predicate {
217 name: next_name,
218 args: term_arena.alloc_slice([
219 Term::Variable(source_world),
220 Term::Variable(target_world),
221 ]),
222 world: None,
223 });
224
225 let recursive_body = expr_arena.alloc(LogicExpr::BinaryOp {
227 left: accessibility,
228 op: crate::token::TokenType::And,
229 right: expr_arena.alloc(LogicExpr::TemporalBinary {
230 operator: *operator,
231 left: new_left,
232 right: new_right,
233 }),
234 });
235 let existential = expr_arena.alloc(LogicExpr::Quantifier {
236 kind: QuantifierKind::Existential,
237 variable: target_world,
238 body: recursive_body,
239 island_id: 0,
240 });
241 let left_and_next = expr_arena.alloc(LogicExpr::BinaryOp {
242 left: new_left,
243 op: crate::token::TokenType::And,
244 right: existential,
245 });
246 expr_arena.alloc(LogicExpr::BinaryOp {
247 left: new_right,
248 op: crate::token::TokenType::Or,
249 right: left_and_next,
250 })
251 }
252
253 LogicExpr::Aspectual { operator, body } => {
254 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
255 expr_arena.alloc(LogicExpr::Aspectual {
256 operator: *operator,
257 body: new_body,
258 })
259 }
260
261 LogicExpr::Voice { operator, body } => {
262 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
263 expr_arena.alloc(LogicExpr::Voice {
264 operator: *operator,
265 body: new_body,
266 })
267 }
268
269 LogicExpr::Lambda { variable, body } => {
270 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
271 expr_arena.alloc(LogicExpr::Lambda {
272 variable: *variable,
273 body: new_body,
274 })
275 }
276
277 LogicExpr::App { function, argument } => {
278 let new_function = lower_expr(function, ctx, expr_arena, term_arena, interner);
279 let new_argument = lower_expr(argument, ctx, expr_arena, term_arena, interner);
280 expr_arena.alloc(LogicExpr::App {
281 function: new_function,
282 argument: new_argument,
283 })
284 }
285
286 LogicExpr::Intensional { operator, content } => {
287 let new_content = lower_expr(content, ctx, expr_arena, term_arena, interner);
288 expr_arena.alloc(LogicExpr::Intensional {
289 operator: *operator,
290 content: new_content,
291 })
292 }
293
294 LogicExpr::Control { verb, subject, object, infinitive } => {
295 let new_infinitive = lower_expr(infinitive, ctx, expr_arena, term_arena, interner);
296 expr_arena.alloc(LogicExpr::Control {
297 verb: *verb,
298 subject: *subject,
299 object: *object,
300 infinitive: new_infinitive,
301 })
302 }
303
304 LogicExpr::Scopal { operator, body } => {
305 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
306 expr_arena.alloc(LogicExpr::Scopal {
307 operator: *operator,
308 body: new_body,
309 })
310 }
311
312 LogicExpr::Question { wh_variable, body } => {
313 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
314 expr_arena.alloc(LogicExpr::Question {
315 wh_variable: *wh_variable,
316 body: new_body,
317 })
318 }
319
320 LogicExpr::YesNoQuestion { body } => {
321 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
322 expr_arena.alloc(LogicExpr::YesNoQuestion { body: new_body })
323 }
324
325 LogicExpr::Focus { kind, focused, scope } => {
326 let new_scope = lower_expr(scope, ctx, expr_arena, term_arena, interner);
327 expr_arena.alloc(LogicExpr::Focus {
328 kind: *kind,
329 focused: *focused,
330 scope: new_scope,
331 })
332 }
333
334 LogicExpr::Distributive { predicate } => {
335 let new_predicate = lower_expr(predicate, ctx, expr_arena, term_arena, interner);
336 expr_arena.alloc(LogicExpr::Distributive {
337 predicate: new_predicate,
338 })
339 }
340
341 LogicExpr::Counterfactual { antecedent, consequent } => {
342 let new_antecedent = lower_expr(antecedent, ctx, expr_arena, term_arena, interner);
343 let new_consequent = lower_expr(consequent, ctx, expr_arena, term_arena, interner);
344 expr_arena.alloc(LogicExpr::Counterfactual {
345 antecedent: new_antecedent,
346 consequent: new_consequent,
347 })
348 }
349
350 LogicExpr::Event { predicate, adverbs } => {
351 let new_predicate = lower_expr(predicate, ctx, expr_arena, term_arena, interner);
352 expr_arena.alloc(LogicExpr::Event {
353 predicate: new_predicate,
354 adverbs: *adverbs,
355 })
356 }
357
358 LogicExpr::Imperative { action } => {
359 let new_action = lower_expr(action, ctx, expr_arena, term_arena, interner);
360 expr_arena.alloc(LogicExpr::Imperative { action: new_action })
361 }
362
363 LogicExpr::Causal { effect, cause } => {
364 let new_effect = lower_expr(effect, ctx, expr_arena, term_arena, interner);
365 let new_cause = lower_expr(cause, ctx, expr_arena, term_arena, interner);
366 expr_arena.alloc(LogicExpr::Causal {
367 effect: new_effect,
368 cause: new_cause,
369 })
370 }
371
372 LogicExpr::Presupposition { assertion, presupposition } => {
373 let new_assertion = lower_expr(assertion, ctx, expr_arena, term_arena, interner);
374 let new_presupposition = lower_expr(presupposition, ctx, expr_arena, term_arena, interner);
375 expr_arena.alloc(LogicExpr::Presupposition {
376 assertion: new_assertion,
377 presupposition: new_presupposition,
378 })
379 }
380
381 LogicExpr::TemporalAnchor { anchor, body } => {
382 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
383 expr_arena.alloc(LogicExpr::TemporalAnchor {
384 anchor: *anchor,
385 body: new_body,
386 })
387 }
388
389 LogicExpr::GroupQuantifier { group_var, count, member_var, restriction, body } => {
390 let new_restriction = lower_expr(restriction, ctx, expr_arena, term_arena, interner);
391 let new_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
392 expr_arena.alloc(LogicExpr::GroupQuantifier {
393 group_var: *group_var,
394 count: *count,
395 member_var: *member_var,
396 restriction: new_restriction,
397 body: new_body,
398 })
399 }
400
401 LogicExpr::Identity { .. }
403 | LogicExpr::Metaphor { .. }
404 | LogicExpr::Categorical(_)
405 | LogicExpr::Relation(_)
406 | LogicExpr::Atom(_)
407 | LogicExpr::Superlative { .. }
408 | LogicExpr::Comparative { .. }
409 | LogicExpr::SpeechAct { .. } => expr,
410 }
411}
412
413fn lower_modal<'a>(
414 vector: &ModalVector,
415 operand: &'a LogicExpr<'a>,
416 ctx: &mut KripkeContext,
417 expr_arena: &'a Arena<LogicExpr<'a>>,
418 term_arena: &'a Arena<Term<'a>>,
419 interner: &mut Interner,
420) -> &'a LogicExpr<'a> {
421 let source_world = ctx.current_world;
422 let target_world = ctx.fresh_world(interner);
423
424 let old_world = ctx.current_world;
426 ctx.current_world = target_world;
427 let lowered_operand = lower_expr(operand, ctx, expr_arena, term_arena, interner);
428 ctx.current_world = old_world;
429
430 let access_name = match vector.domain {
432 ModalDomain::Alethic => interner.intern("Accessible_Alethic"),
433 ModalDomain::Deontic => interner.intern("Accessible_Deontic"),
434 ModalDomain::Temporal => interner.intern("Accessible_Temporal"),
435 };
436
437 let accessibility = expr_arena.alloc(LogicExpr::Predicate {
438 name: access_name,
439 args: term_arena.alloc_slice([
440 Term::Variable(source_world),
441 Term::Variable(target_world),
442 ]),
443 world: None, });
445
446 if vector.force > 0.5 {
447 let implication = expr_arena.alloc(LogicExpr::BinaryOp {
449 left: accessibility,
450 op: TokenType::Implies,
451 right: lowered_operand,
452 });
453 expr_arena.alloc(LogicExpr::Quantifier {
454 kind: QuantifierKind::Universal,
455 variable: target_world,
456 body: implication,
457 island_id: 0,
458 })
459 } else {
460 let conjunction = expr_arena.alloc(LogicExpr::BinaryOp {
462 left: accessibility,
463 op: TokenType::And,
464 right: lowered_operand,
465 });
466 expr_arena.alloc(LogicExpr::Quantifier {
467 kind: QuantifierKind::Existential,
468 variable: target_world,
469 body: conjunction,
470 island_id: 0,
471 })
472 }
473}
474
475fn lower_temporal_unary<'a>(
479 body: &'a LogicExpr<'a>,
480 ctx: &mut KripkeContext,
481 expr_arena: &'a Arena<LogicExpr<'a>>,
482 term_arena: &'a Arena<Term<'a>>,
483 interner: &mut Interner,
484 predicate_name: &str,
485 is_universal: bool,
486) -> &'a LogicExpr<'a> {
487 let source_world = ctx.current_world;
488 let target_world = ctx.fresh_world(interner);
489
490 let old_world = ctx.current_world;
492 ctx.current_world = target_world;
493 let lowered_body = lower_expr(body, ctx, expr_arena, term_arena, interner);
494 ctx.current_world = old_world;
495
496 let access_name = interner.intern(predicate_name);
498 let accessibility = expr_arena.alloc(LogicExpr::Predicate {
499 name: access_name,
500 args: term_arena.alloc_slice([
501 Term::Variable(source_world),
502 Term::Variable(target_world),
503 ]),
504 world: None,
505 });
506
507 if is_universal {
508 let implication = expr_arena.alloc(LogicExpr::BinaryOp {
510 left: accessibility,
511 op: TokenType::Implies,
512 right: lowered_body,
513 });
514 expr_arena.alloc(LogicExpr::Quantifier {
515 kind: QuantifierKind::Universal,
516 variable: target_world,
517 body: implication,
518 island_id: 0,
519 })
520 } else {
521 let conjunction = expr_arena.alloc(LogicExpr::BinaryOp {
523 left: accessibility,
524 op: TokenType::And,
525 right: lowered_body,
526 });
527 expr_arena.alloc(LogicExpr::Quantifier {
528 kind: QuantifierKind::Existential,
529 variable: target_world,
530 body: conjunction,
531 island_id: 0,
532 })
533 }
534}