1use crate::{
34 analysis, Arena, CompileOptions, drs, Interner, lambda, lexicon, Lexer, mwe,
35 OutputFormat, Parser, pragmatics, semantics, SymbolRegistry, ParseError, token,
36 arena_ctx::AstContext,
37 parser::{NegativeScopeMode, ModalPreference, QuantifierParsing},
38};
39
40pub const MAX_FOREST_READINGS: usize = 12;
43
44pub fn compile(input: &str) -> Result<String, ParseError> {
46 compile_with_options(input, CompileOptions::default())
47}
48
49pub fn compile_pragmatic(input: &str) -> Result<String, ParseError> {
52 compile_with_options(input, CompileOptions {
53 format: OutputFormat::Unicode,
54 pragmatic: true,
55 })
56}
57
58pub fn compile_simple(input: &str) -> Result<String, ParseError> {
60 compile_with_options(input, CompileOptions { format: OutputFormat::SimpleFOL, pragmatic: false })
61}
62
63pub fn compile_kripke(input: &str) -> Result<String, ParseError> {
66 compile_with_options(input, CompileOptions { format: OutputFormat::Kripke, pragmatic: false })
67}
68
69pub fn compile_kripke_with<F, R>(input: &str, f: F) -> Result<R, ParseError>
74where
75 F: FnOnce(&crate::ast::logic::LogicExpr<'_>, &Interner) -> R,
76{
77 if input.trim().is_empty() {
78 return Err(ParseError {
79 kind: crate::error::ParseErrorKind::Custom("Empty input".to_string()),
80 span: crate::token::Span { start: 0, end: 0 },
81 });
82 }
83 let mut interner = Interner::new();
84 let mut lexer = Lexer::new(input, &mut interner);
85 let tokens = lexer.tokenize();
86
87 let mwe_trie = mwe::build_mwe_trie();
88 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
89
90 let type_registry = {
91 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
92 discovery.run()
93 };
94
95 let expr_arena = Arena::new();
96 let term_arena = Arena::new();
97 let np_arena = Arena::new();
98 let sym_arena = Arena::new();
99 let role_arena = Arena::new();
100 let pp_arena = Arena::new();
101
102 let ctx = AstContext::new(
103 &expr_arena,
104 &term_arena,
105 &np_arena,
106 &sym_arena,
107 &role_arena,
108 &pp_arena,
109 );
110
111 let mut world_state = drs::WorldState::new();
112 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
113 let ast = parser.parse()?;
114 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, &mut interner);
115 let ast = semantics::apply_kripke_lowering(ast, ctx.exprs, ctx.terms, &mut interner);
116
117 Ok(f(ast, &interner))
118}
119
120pub fn compile_with_options(input: &str, options: CompileOptions) -> Result<String, ParseError> {
122 if input.trim().is_empty() {
123 return Err(ParseError {
124 kind: crate::error::ParseErrorKind::Custom("Empty input".to_string()),
125 span: crate::token::Span { start: 0, end: 0 },
126 });
127 }
128 let mut interner = Interner::new();
129 let mut lexer = Lexer::new(input, &mut interner);
130 let tokens = lexer.tokenize();
131
132 let mwe_trie = mwe::build_mwe_trie();
134 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
135
136 let type_registry = {
138 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
139 discovery.run()
140 };
141
142 let expr_arena = Arena::new();
143 let term_arena = Arena::new();
144 let np_arena = Arena::new();
145 let sym_arena = Arena::new();
146 let role_arena = Arena::new();
147 let pp_arena = Arena::new();
148
149 let ctx = AstContext::new(
150 &expr_arena,
151 &term_arena,
152 &np_arena,
153 &sym_arena,
154 &role_arena,
155 &pp_arena,
156 );
157
158 let mut world_state = drs::WorldState::new();
160 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
161 let ast = if options.pragmatic {
162 parser.parse_pragmatic()?
163 } else {
164 parser.parse()?
165 };
166 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, &mut interner);
167
168 let ast = if options.format == OutputFormat::Kripke {
170 semantics::apply_kripke_lowering(ast, ctx.exprs, ctx.terms, &mut interner)
171 } else {
172 ast
173 };
174
175 let ast = pragmatics::apply_pragmatics(ast, ctx.exprs, &interner);
176 let mut registry = SymbolRegistry::new();
177 let main_output = ast.transpile_discourse(&mut registry, &interner, options.format);
179
180 let constraints = world_state.time_constraints();
182 if constraints.is_empty() {
183 Ok(main_output)
184 } else {
185 let constraint_strs: Vec<String> = constraints.iter().map(|c| {
186 match c.relation {
187 drs::TimeRelation::Precedes => format!("Precedes({}, {})", c.left, c.right),
188 drs::TimeRelation::Equals => format!("{}={}", c.left, c.right),
189 }
190 }).collect();
191 Ok(format!("{} ∧ {}", main_output, constraint_strs.join(" ∧ ")))
192 }
193}
194
195pub fn compile_with_world_state(input: &str, world_state: &mut drs::WorldState) -> Result<String, ParseError> {
197 compile_with_world_state_options(input, world_state, CompileOptions::default())
198}
199
200pub fn compile_with_world_state_options(
202 input: &str,
203 world_state: &mut drs::WorldState,
204 options: CompileOptions,
205) -> Result<String, ParseError> {
206 let mut interner = Interner::new();
207 compile_with_world_state_interner_options(input, world_state, &mut interner, options)
208}
209
210pub fn compile_with_discourse(
213 input: &str,
214 world_state: &mut drs::WorldState,
215 interner: &mut Interner,
216) -> Result<String, ParseError> {
217 compile_with_world_state_interner_options(input, world_state, interner, CompileOptions::default())
218}
219
220pub fn compile_with_world_state_interner_options(
222 input: &str,
223 world_state: &mut drs::WorldState,
224 interner: &mut Interner,
225 options: CompileOptions,
226) -> Result<String, ParseError> {
227 let mut lexer = Lexer::new(input, interner);
228 let tokens = lexer.tokenize();
229
230 let mwe_trie = mwe::build_mwe_trie();
232 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, interner);
233
234 let type_registry = {
236 let mut discovery = analysis::DiscoveryPass::new(&tokens, interner);
237 discovery.run()
238 };
239
240 let expr_arena = Arena::new();
241 let term_arena = Arena::new();
242 let np_arena = Arena::new();
243 let sym_arena = Arena::new();
244 let role_arena = Arena::new();
245 let pp_arena = Arena::new();
246
247 let ctx = AstContext::new(
248 &expr_arena,
249 &term_arena,
250 &np_arena,
251 &sym_arena,
252 &role_arena,
253 &pp_arena,
254 );
255
256 let mut parser = Parser::new(tokens, world_state, interner, ctx, type_registry);
257 parser.swap_drs_with_world_state();
259 let ast = parser.parse()?;
260 parser.swap_drs_with_world_state();
262 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, interner);
263
264 world_state.end_sentence();
266
267 let ast = if options.format == OutputFormat::Kripke {
268 semantics::apply_kripke_lowering(ast, ctx.exprs, ctx.terms, interner)
269 } else {
270 ast
271 };
272
273 let ast = pragmatics::apply_pragmatics(ast, ctx.exprs, interner);
274 let mut registry = SymbolRegistry::new();
275 let main_output = ast.transpile_discourse(&mut registry, interner, options.format);
276
277 let constraints = world_state.time_constraints();
278 if constraints.is_empty() {
279 Ok(main_output)
280 } else {
281 let constraint_strs: Vec<String> = constraints.iter().map(|c| {
282 match c.relation {
283 drs::TimeRelation::Precedes => format!("Precedes({}, {})", c.left, c.right),
284 drs::TimeRelation::Equals => format!("{}={}", c.left, c.right),
285 }
286 }).collect();
287 Ok(format!("{} ∧ {}", main_output, constraint_strs.join(" ∧ ")))
288 }
289}
290
291pub fn compile_all_scopes(input: &str) -> Result<Vec<String>, ParseError> {
297 compile_all_scopes_with_options(input, CompileOptions::default())
298}
299
300pub fn compile_all_scopes_with_options(input: &str, options: CompileOptions) -> Result<Vec<String>, ParseError> {
302 let mut interner = Interner::new();
303 let mut lexer = Lexer::new(input, &mut interner);
304 let tokens = lexer.tokenize();
305
306 let mwe_trie = mwe::build_mwe_trie();
308 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
309
310 let type_registry = {
312 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
313 discovery.run()
314 };
315
316 let expr_arena = Arena::new();
317 let term_arena = Arena::new();
318 let np_arena = Arena::new();
319 let sym_arena = Arena::new();
320 let role_arena = Arena::new();
321 let pp_arena = Arena::new();
322
323 let ctx = AstContext::new(
324 &expr_arena,
325 &term_arena,
326 &np_arena,
327 &sym_arena,
328 &role_arena,
329 &pp_arena,
330 );
331
332 let mut world_state = drs::WorldState::new();
334 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
335 let ast = parser.parse()?;
336
337 let scope_arena = Arena::new();
338 let scope_term_arena = Arena::new();
339 let scopings = lambda::enumerate_scopings(ast, &mut interner, &scope_arena, &scope_term_arena);
340
341 let intensional_arena = Arena::new();
342 let intensional_term_arena = Arena::new();
343 let intensional_role_arena: Arena<(crate::ast::ThematicRole, crate::ast::Term)> = Arena::new();
344
345 let mut results = Vec::new();
346 for scoped_expr in scopings {
347 let intensional_readings = lambda::enumerate_intensional_readings(
348 scoped_expr,
349 &mut interner,
350 &intensional_arena,
351 &intensional_term_arena,
352 &intensional_role_arena,
353 );
354 for reading in intensional_readings {
355 let reading = semantics::apply_axioms(reading, &intensional_arena, &intensional_term_arena, &mut interner);
356 let mut registry = SymbolRegistry::new();
357 results.push(reading.transpile(&mut registry, &interner, options.format));
358 }
359 }
360
361 if let Some(cumulative) = lambda::cumulative_reading(ast, &mut interner, &scope_arena) {
364 let cumulative =
365 semantics::apply_axioms(cumulative, &scope_arena, &scope_term_arena, &mut interner);
366 let mut registry = SymbolRegistry::new();
367 let rendered = cumulative.transpile(&mut registry, &interner, options.format);
368 if !results.contains(&rendered) {
369 results.push(rendered);
370 }
371 }
372
373 Ok(results)
374}
375
376pub fn compile_forest(input: &str) -> Vec<String> {
383 compile_forest_with_options(input, CompileOptions::default())
384}
385
386pub fn compile_forest_with_options(input: &str, options: CompileOptions) -> Vec<String> {
388 let mut interner = Interner::new();
389 let mut lexer = Lexer::new(input, &mut interner);
390 let tokens = lexer.tokenize();
391
392 let mwe_trie = mwe::build_mwe_trie();
394 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
395
396 let type_registry = {
398 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
399 discovery.run()
400 };
401
402 let has_lexical_ambiguity = tokens.iter().any(|t| {
403 matches!(t.kind, token::TokenType::Ambiguous { .. })
404 });
405
406 let has_pp_ambiguity = tokens.iter().any(|t| {
407 if let token::TokenType::Preposition(sym) = &t.kind {
408 let prep = interner.resolve(*sym);
409 prep == "with" || prep == "by" || prep == "for"
410 } else {
411 false
412 }
413 });
414
415 let has_mixed_verb = tokens.iter().any(|t| {
417 if let token::TokenType::Verb { lemma, .. } = &t.kind {
418 Lexer::is_mixed_verb(interner.resolve(*lemma))
419 } else {
420 false
421 }
422 });
423
424 let has_collective_verb = tokens.iter().any(|t| {
426 if let token::TokenType::Verb { lemma, .. } = &t.kind {
427 Lexer::is_collective_verb(interner.resolve(*lemma))
428 } else {
429 false
430 }
431 });
432
433 let has_plural_subject = tokens.iter().any(|t| {
434 matches!(t.kind, token::TokenType::Cardinal(_))
435 || matches!(&t.kind, token::TokenType::Article(def) if matches!(def, lexicon::Definiteness::Definite))
436 });
437
438 let has_plurality_ambiguity = (has_mixed_verb || has_collective_verb) && has_plural_subject;
439
440 let has_event_adjective_ambiguity = {
442 let mut has_event_adj = false;
443 let mut has_agentive_noun = false;
444 for token in &tokens {
445 if let token::TokenType::Adjective(sym) = &token.kind {
446 if lexicon::is_event_modifier_adjective(interner.resolve(*sym)) {
447 has_event_adj = true;
448 }
449 }
450 if let token::TokenType::Noun(sym) = &token.kind {
451 if lexicon::lookup_agentive_noun(interner.resolve(*sym)).is_some() {
452 has_agentive_noun = true;
453 }
454 }
455 }
456 has_event_adj && has_agentive_noun
457 };
458
459 let has_negative_verb = tokens.iter().any(|t| {
461 if let token::TokenType::Verb { lemma, .. } = &t.kind {
462 lexicon::get_canonical_verb(&interner.resolve(*lemma).to_lowercase())
463 .map(|(_, is_neg)| is_neg)
464 .unwrap_or(false)
465 } else {
466 false
467 }
468 });
469
470 let has_may = tokens.iter().any(|t| matches!(t.kind, token::TokenType::May));
472 let has_can = tokens.iter().any(|t| matches!(t.kind, token::TokenType::Can));
473 let has_could = tokens.iter().any(|t| matches!(t.kind, token::TokenType::Could));
474
475 let mut results: Vec<String> = Vec::new();
476
477 {
479 let expr_arena = Arena::new();
480 let term_arena = Arena::new();
481 let np_arena = Arena::new();
482 let sym_arena = Arena::new();
483 let role_arena = Arena::new();
484 let pp_arena = Arena::new();
485
486 let ast_ctx = AstContext::new(
487 &expr_arena,
488 &term_arena,
489 &np_arena,
490 &sym_arena,
491 &role_arena,
492 &pp_arena,
493 );
494
495 let mut world_state = drs::WorldState::new();
496 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
497 parser.set_noun_priority_mode(false);
498
499 if let Ok(ast) = parser.parse() {
500 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
501 let ast = if options.format == OutputFormat::Kripke {
502 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
503 } else {
504 ast
505 };
506 let mut registry = SymbolRegistry::new();
507 results.push(ast.transpile_discourse(&mut registry, &interner, options.format));
508 }
509 }
510
511 if has_lexical_ambiguity {
517 let amb_positions: Vec<usize> = tokens
518 .iter()
519 .enumerate()
520 .filter(|(_, t)| matches!(t.kind, token::TokenType::Ambiguous { .. }))
521 .map(|(i, _)| i)
522 .collect();
523 let option_counts: Vec<usize> = amb_positions
524 .iter()
525 .map(|&i| {
526 if let token::TokenType::Ambiguous { alternatives, .. } = &tokens[i].kind {
527 1 + alternatives.len()
528 } else {
529 1
530 }
531 })
532 .collect();
533 let total: usize = option_counts.iter().product();
534
535 if total <= MAX_FOREST_READINGS {
536 for combo in 0..total {
537 let mut variant = tokens.clone();
538 let mut rem = combo;
539 for (slot, &i) in amb_positions.iter().enumerate() {
540 let pick = rem % option_counts[slot];
541 rem /= option_counts[slot];
542 if let token::TokenType::Ambiguous { primary, alternatives } = &tokens[i].kind {
543 variant[i].kind = if pick == 0 {
544 (**primary).clone()
545 } else {
546 alternatives[pick - 1].clone()
547 };
548 }
549 }
550
551 let expr_arena = Arena::new();
552 let term_arena = Arena::new();
553 let np_arena = Arena::new();
554 let sym_arena = Arena::new();
555 let role_arena = Arena::new();
556 let pp_arena = Arena::new();
557
558 let ast_ctx = AstContext::new(
559 &expr_arena,
560 &term_arena,
561 &np_arena,
562 &sym_arena,
563 &role_arena,
564 &pp_arena,
565 );
566
567 let mut world_state = drs::WorldState::new();
568 let mut parser = Parser::new(
569 variant,
570 &mut world_state,
571 &mut interner,
572 ast_ctx,
573 type_registry.clone(),
574 );
575
576 if let Ok(ast) = parser.parse() {
577 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
578 let ast = if options.format == OutputFormat::Kripke {
579 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
580 } else {
581 ast
582 };
583 let mut registry = SymbolRegistry::new();
584 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
585 if !results.contains(&reading) {
586 results.push(reading);
587 }
588 }
589 }
590 }
591 }
592
593 if has_pp_ambiguity {
595 let expr_arena = Arena::new();
596 let term_arena = Arena::new();
597 let np_arena = Arena::new();
598 let sym_arena = Arena::new();
599 let role_arena = Arena::new();
600 let pp_arena = Arena::new();
601
602 let ast_ctx = AstContext::new(
603 &expr_arena,
604 &term_arena,
605 &np_arena,
606 &sym_arena,
607 &role_arena,
608 &pp_arena,
609 );
610
611 let mut world_state = drs::WorldState::new();
612 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
613 parser.set_pp_attachment_mode(true);
614
615 if let Ok(ast) = parser.parse() {
616 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
617 let ast = if options.format == OutputFormat::Kripke {
618 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
619 } else {
620 ast
621 };
622 let mut registry = SymbolRegistry::new();
623 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
624 if !results.contains(&reading) {
625 results.push(reading);
626 }
627 }
628 }
629
630 if has_plurality_ambiguity {
632 let expr_arena = Arena::new();
633 let term_arena = Arena::new();
634 let np_arena = Arena::new();
635 let sym_arena = Arena::new();
636 let role_arena = Arena::new();
637 let pp_arena = Arena::new();
638
639 let ast_ctx = AstContext::new(
640 &expr_arena,
641 &term_arena,
642 &np_arena,
643 &sym_arena,
644 &role_arena,
645 &pp_arena,
646 );
647
648 let mut world_state = drs::WorldState::new();
649 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
650 parser.set_collective_mode(true);
651
652 if let Ok(ast) = parser.parse() {
653 if let Ok(transformed) = parser.transform_cardinal_to_group(ast) {
654 let transformed = semantics::apply_axioms(transformed, ast_ctx.exprs, ast_ctx.terms, &mut interner);
655 let mut registry = SymbolRegistry::new();
656 let reading = transformed.transpile(&mut registry, &interner, options.format);
657 if !results.contains(&reading) {
658 results.push(reading);
659 }
660 }
661 }
662 }
663
664 if has_plurality_ambiguity {
668 let expr_arena = Arena::new();
669 let term_arena = Arena::new();
670 let np_arena = Arena::new();
671 let sym_arena = Arena::new();
672 let role_arena = Arena::new();
673 let pp_arena = Arena::new();
674
675 let ast_ctx = AstContext::new(
676 &expr_arena,
677 &term_arena,
678 &np_arena,
679 &sym_arena,
680 &role_arena,
681 &pp_arena,
682 );
683
684 let mut world_state = drs::WorldState::new();
685 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
686 parser.set_distributive_marker(true);
687
688 if let Ok(ast) = parser.parse() {
689 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
690 let mut registry = SymbolRegistry::new();
691 let reading = ast.transpile(&mut registry, &interner, options.format);
692 if !results.contains(&reading) {
693 results.push(reading);
694 }
695 }
696 }
697
698 if has_event_adjective_ambiguity {
700 let expr_arena = Arena::new();
701 let term_arena = Arena::new();
702 let np_arena = Arena::new();
703 let sym_arena = Arena::new();
704 let role_arena = Arena::new();
705 let pp_arena = Arena::new();
706
707 let ast_ctx = AstContext::new(
708 &expr_arena,
709 &term_arena,
710 &np_arena,
711 &sym_arena,
712 &role_arena,
713 &pp_arena,
714 );
715
716 let mut world_state = drs::WorldState::new();
717 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
718 parser.set_event_reading_mode(true);
719
720 if let Ok(ast) = parser.parse() {
721 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
722 let ast = if options.format == OutputFormat::Kripke {
723 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
724 } else {
725 ast
726 };
727 let mut registry = SymbolRegistry::new();
728 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
729 if !results.contains(&reading) {
730 results.push(reading);
731 }
732 }
733 }
734
735 if has_negative_verb {
737 let expr_arena = Arena::new();
738 let term_arena = Arena::new();
739 let np_arena = Arena::new();
740 let sym_arena = Arena::new();
741 let role_arena = Arena::new();
742 let pp_arena = Arena::new();
743
744 let ast_ctx = AstContext::new(
745 &expr_arena,
746 &term_arena,
747 &np_arena,
748 &sym_arena,
749 &role_arena,
750 &pp_arena,
751 );
752
753 let mut world_state = drs::WorldState::new();
754 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
755 parser.set_negative_scope_mode(NegativeScopeMode::Wide);
756
757 if let Ok(ast) = parser.parse() {
758 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
759 let ast = if options.format == OutputFormat::Kripke {
760 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
761 } else {
762 ast
763 };
764 let mut registry = SymbolRegistry::new();
765 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
766 if !results.contains(&reading) {
767 results.push(reading);
768 }
769 }
770 }
771
772 if has_may || has_could {
774 let expr_arena = Arena::new();
775 let term_arena = Arena::new();
776 let np_arena = Arena::new();
777 let sym_arena = Arena::new();
778 let role_arena = Arena::new();
779 let pp_arena = Arena::new();
780
781 let ast_ctx = AstContext::new(
782 &expr_arena,
783 &term_arena,
784 &np_arena,
785 &sym_arena,
786 &role_arena,
787 &pp_arena,
788 );
789
790 let mut world_state = drs::WorldState::new();
791 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
792 parser.set_modal_preference(ModalPreference::Epistemic);
793
794 if let Ok(ast) = parser.parse() {
795 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
796 let ast = if options.format == OutputFormat::Kripke {
797 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
798 } else {
799 ast
800 };
801 let mut registry = SymbolRegistry::new();
802 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
803 if !results.contains(&reading) {
804 results.push(reading);
805 }
806 }
807 }
808
809 if has_can {
811 let expr_arena = Arena::new();
812 let term_arena = Arena::new();
813 let np_arena = Arena::new();
814 let sym_arena = Arena::new();
815 let role_arena = Arena::new();
816 let pp_arena = Arena::new();
817
818 let ast_ctx = AstContext::new(
819 &expr_arena,
820 &term_arena,
821 &np_arena,
822 &sym_arena,
823 &role_arena,
824 &pp_arena,
825 );
826
827 let mut world_state = drs::WorldState::new();
828 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
829 parser.set_modal_preference(ModalPreference::Deontic);
830
831 if let Ok(ast) = parser.parse() {
832 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
833 let ast = if options.format == OutputFormat::Kripke {
834 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
835 } else {
836 ast
837 };
838 let mut registry = SymbolRegistry::new();
839 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
840 if !results.contains(&reading) {
841 results.push(reading);
842 }
843 }
844 }
845
846 if has_negative_verb && has_can {
848 let expr_arena = Arena::new();
849 let term_arena = Arena::new();
850 let np_arena = Arena::new();
851 let sym_arena = Arena::new();
852 let role_arena = Arena::new();
853 let pp_arena = Arena::new();
854
855 let ast_ctx = AstContext::new(
856 &expr_arena,
857 &term_arena,
858 &np_arena,
859 &sym_arena,
860 &role_arena,
861 &pp_arena,
862 );
863
864 let mut world_state = drs::WorldState::new();
865 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry);
866 parser.set_negative_scope_mode(NegativeScopeMode::Wide);
867 parser.set_modal_preference(ModalPreference::Deontic);
868
869 if let Ok(ast) = parser.parse() {
870 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
871 let ast = if options.format == OutputFormat::Kripke {
872 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
873 } else {
874 ast
875 };
876 let mut registry = SymbolRegistry::new();
877 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
878 if !results.contains(&reading) {
879 results.push(reading);
880 }
881 }
882 }
883
884 results.truncate(MAX_FOREST_READINGS);
886
887 results
888}
889
890pub fn compile_discourse(sentences: &[&str]) -> Result<String, ParseError> {
896 compile_discourse_with_options(sentences, CompileOptions::default())
897}
898
899pub fn compile_discourse_with_options(sentences: &[&str], options: CompileOptions) -> Result<String, ParseError> {
901 let mut interner = Interner::new();
902 let mut world_state = drs::WorldState::new();
903 let mut results = Vec::new();
904 let mut registry = SymbolRegistry::new();
905 let mwe_trie = mwe::build_mwe_trie();
906
907 for sentence in sentences {
908 let event_var_name = world_state.next_event_var();
909 let event_var_symbol = interner.intern(&event_var_name);
910
911 let mut lexer = Lexer::new(sentence, &mut interner);
912 let tokens = lexer.tokenize();
913
914 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
916
917 let type_registry = {
919 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
920 discovery.run()
921 };
922
923 let expr_arena = Arena::new();
924 let term_arena = Arena::new();
925 let np_arena = Arena::new();
926 let sym_arena = Arena::new();
927 let role_arena = Arena::new();
928 let pp_arena = Arena::new();
929
930 let ast_ctx = AstContext::new(
931 &expr_arena,
932 &term_arena,
933 &np_arena,
934 &sym_arena,
935 &role_arena,
936 &pp_arena,
937 );
938
939 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ast_ctx, type_registry);
941 parser.set_discourse_event_var(event_var_symbol);
942 parser.swap_drs_with_world_state();
944 let ast = parser.parse()?;
945 parser.swap_drs_with_world_state();
947
948 world_state.end_sentence();
950
951 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
952 results.push(ast.transpile_discourse(&mut registry, &interner, options.format));
953 }
954
955 let event_history = world_state.event_history();
956 let mut precedes = Vec::new();
957 for i in 0..event_history.len().saturating_sub(1) {
958 precedes.push(format!("Precedes({}, {})", event_history[i], event_history[i + 1]));
959 }
960
961 if precedes.is_empty() {
962 Ok(results.join(" ∧ "))
963 } else {
964 Ok(format!("{} ∧ {}", results.join(" ∧ "), precedes.join(" ∧ ")))
965 }
966}
967
968pub fn compile_ambiguous(input: &str) -> Result<Vec<String>, ParseError> {
975 compile_ambiguous_with_options(input, CompileOptions::default())
976}
977
978pub fn compile_ambiguous_with_options(input: &str, options: CompileOptions) -> Result<Vec<String>, ParseError> {
980 let mut interner = Interner::new();
981 let mut lexer = Lexer::new(input, &mut interner);
982 let tokens = lexer.tokenize();
983
984 let mwe_trie = mwe::build_mwe_trie();
986 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
987
988 let type_registry = {
990 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
991 discovery.run()
992 };
993
994 let expr_arena = Arena::new();
995 let term_arena = Arena::new();
996 let np_arena = Arena::new();
997 let sym_arena = Arena::new();
998 let role_arena = Arena::new();
999 let pp_arena = Arena::new();
1000
1001 let ctx = AstContext::new(
1002 &expr_arena,
1003 &term_arena,
1004 &np_arena,
1005 &sym_arena,
1006 &role_arena,
1007 &pp_arena,
1008 );
1009
1010 let mut world_state = drs::WorldState::new();
1012 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ctx, type_registry.clone());
1013 let ast = parser.parse()?;
1014 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, &mut interner);
1015 let mut registry = SymbolRegistry::new();
1016 let reading1 = ast.transpile(&mut registry, &interner, options.format);
1017
1018 let has_pp_ambiguity = tokens.iter().any(|t| {
1019 if let token::TokenType::Preposition(sym) = &t.kind {
1020 let prep = interner.resolve(*sym);
1021 prep == "with" || prep == "by" || prep == "for"
1022 } else {
1023 false
1024 }
1025 });
1026
1027 if has_pp_ambiguity {
1028 let expr_arena2 = Arena::new();
1029 let term_arena2 = Arena::new();
1030 let np_arena2 = Arena::new();
1031 let sym_arena2 = Arena::new();
1032 let role_arena2 = Arena::new();
1033 let pp_arena2 = Arena::new();
1034
1035 let ctx2 = AstContext::new(
1036 &expr_arena2,
1037 &term_arena2,
1038 &np_arena2,
1039 &sym_arena2,
1040 &role_arena2,
1041 &pp_arena2,
1042 );
1043
1044 let mut world_state2 = drs::WorldState::new();
1045 let mut parser2 = Parser::new(tokens, &mut world_state2, &mut interner, ctx2, type_registry);
1046 parser2.set_pp_attachment_mode(true);
1047 let ast2 = parser2.parse()?;
1048 let ast2 = semantics::apply_axioms(ast2, ctx2.exprs, ctx2.terms, &mut interner);
1049 let mut registry2 = SymbolRegistry::new();
1050 let reading2 = ast2.transpile(&mut registry2, &interner, options.format);
1051
1052 if reading1 != reading2 {
1053 return Ok(vec![reading1, reading2]);
1054 }
1055 }
1056
1057 Ok(vec![reading1])
1058}
1059
1060use crate::ast::{self, Stmt};
1065use crate::token::Span;
1066use crate::error::ParseErrorKind;
1067use crate::proof_convert::logic_expr_to_proof_expr;
1068
1069pub fn compile_theorem(input: &str) -> Result<String, ParseError> {
1071 let mut interner = Interner::new();
1072 let mut lexer = Lexer::new(input, &mut interner);
1073 let tokens = lexer.tokenize();
1074
1075 let mwe_trie = mwe::build_mwe_trie();
1077 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
1078
1079 let type_registry = {
1081 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
1082 discovery.run()
1083 };
1084
1085 let expr_arena = Arena::new();
1086 let term_arena = Arena::new();
1087 let np_arena = Arena::new();
1088 let sym_arena = Arena::new();
1089 let role_arena = Arena::new();
1090 let pp_arena = Arena::new();
1091
1092 let ctx = AstContext::new(
1093 &expr_arena,
1094 &term_arena,
1095 &np_arena,
1096 &sym_arena,
1097 &role_arena,
1098 &pp_arena,
1099 );
1100
1101 let mut world_state = drs::WorldState::new();
1103 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
1104 let statements = parser.parse_program()?;
1105
1106 let theorem = statements
1108 .iter()
1109 .find_map(|stmt| {
1110 if let Stmt::Theorem(t) = stmt {
1111 Some(t)
1112 } else {
1113 None
1114 }
1115 })
1116 .ok_or_else(|| ParseError {
1117 kind: ParseErrorKind::Custom("No theorem block found in input".to_string()),
1118 span: Span::default(),
1119 })?;
1120
1121 let premises: Vec<_> = theorem
1123 .premises
1124 .iter()
1125 .map(|premise| logic_expr_to_proof_expr(premise, &interner))
1126 .collect();
1127 let goal = logic_expr_to_proof_expr(theorem.goal, &interner);
1128
1129 let outcome = if let crate::ast::theorem::ProofStrategy::Script(src) = &theorem.strategy {
1137 use logicaffeine_proof::tactic::ProofState;
1138 let mut st =
1139 ProofState::start_with_names(premises.clone(), &theorem.premise_names, goal.clone());
1140 let fail = |err: String| logicaffeine_proof::verify::VerifiedProof {
1141 derivation: None,
1142 proof_term: None,
1143 kernel_ctx: Default::default(),
1144 verified: false,
1145 verification_error: Some(err),
1146 };
1147 match st.run_script(src) {
1148 Ok(_) => st.qed().unwrap_or_else(|e| fail(format!("{e:?}"))),
1149 Err(e) => fail(e.to_string()),
1150 }
1151 } else {
1152 logicaffeine_proof::verify::prove_certify_check(&premises, &goal)
1153 };
1154 match outcome.derivation {
1155 Some(derivation) if outcome.verified => Ok(format!(
1156 "Theorem '{}' Proved! [kernel-verified]\n{}",
1157 theorem.name,
1158 derivation.display_tree()
1159 )),
1160 Some(derivation) => Ok(format!(
1161 "Theorem '{}' — derivation found but NOT kernel-certified (this is not a proof)\n{}",
1162 theorem.name,
1163 derivation.display_tree()
1164 )),
1165 None => Err(ParseError {
1166 kind: ParseErrorKind::Custom(format!(
1167 "Theorem '{}' failed.\n Goal: {}\n Premises: {}\n Error: {}",
1168 theorem.name,
1169 goal,
1170 theorem.premises.len(),
1171 outcome
1172 .verification_error
1173 .unwrap_or_else(|| "no derivation found".to_string())
1174 )),
1175 span: Span::default(),
1176 }),
1177 }
1178}
1179
1180#[cfg(test)]
1181mod tests {
1182 use super::*;
1183
1184 #[test]
1185 fn test_compile_simple_sentence() {
1186 let result = compile("John runs.");
1187 assert!(result.is_ok());
1188 let output = result.unwrap();
1189 assert!(output.contains("Run"));
1190 assert!(output.contains("John"));
1191 }
1192
1193 #[test]
1194 fn test_compile_with_unicode_format() {
1195 let options = CompileOptions { format: OutputFormat::Unicode, pragmatic: false };
1196 let result = compile_with_options("Every dog barks.", options);
1197 assert!(result.is_ok());
1198 let output = result.unwrap();
1199 assert!(output.contains("∀") || output.contains("Forall"));
1200 }
1201
1202 #[test]
1203 fn test_compile_all_scopes() {
1204 let result = compile_all_scopes("Every woman loves a man.");
1205 assert!(result.is_ok());
1206 let readings = result.unwrap();
1207 assert!(readings.len() >= 1);
1208 }
1209}