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_simple(input: &str) -> Result<String, ParseError> {
51 compile_with_options(input, CompileOptions {
52 format: OutputFormat::SimpleFOL,
53 })
54}
55
56pub fn compile_kripke(input: &str) -> Result<String, ParseError> {
59 compile_with_options(input, CompileOptions {
60 format: OutputFormat::Kripke,
61 })
62}
63
64pub fn compile_kripke_with<F, R>(input: &str, f: F) -> Result<R, ParseError>
69where
70 F: FnOnce(&crate::ast::logic::LogicExpr<'_>, &Interner) -> R,
71{
72 if input.trim().is_empty() {
73 return Err(ParseError {
74 kind: crate::error::ParseErrorKind::Custom("Empty input".to_string()),
75 span: crate::token::Span { start: 0, end: 0 },
76 });
77 }
78 let mut interner = Interner::new();
79 let mut lexer = Lexer::new(input, &mut interner);
80 let tokens = lexer.tokenize();
81
82 let mwe_trie = mwe::build_mwe_trie();
83 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
84
85 let type_registry = {
86 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
87 discovery.run()
88 };
89
90 let expr_arena = Arena::new();
91 let term_arena = Arena::new();
92 let np_arena = Arena::new();
93 let sym_arena = Arena::new();
94 let role_arena = Arena::new();
95 let pp_arena = Arena::new();
96
97 let ctx = AstContext::new(
98 &expr_arena,
99 &term_arena,
100 &np_arena,
101 &sym_arena,
102 &role_arena,
103 &pp_arena,
104 );
105
106 let mut world_state = drs::WorldState::new();
107 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
108 let ast = parser.parse()?;
109 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, &mut interner);
110 let ast = semantics::apply_kripke_lowering(ast, ctx.exprs, ctx.terms, &mut interner);
111
112 Ok(f(ast, &interner))
113}
114
115pub fn compile_with_options(input: &str, options: CompileOptions) -> Result<String, ParseError> {
117 if input.trim().is_empty() {
118 return Err(ParseError {
119 kind: crate::error::ParseErrorKind::Custom("Empty input".to_string()),
120 span: crate::token::Span { start: 0, end: 0 },
121 });
122 }
123 let mut interner = Interner::new();
124 let mut lexer = Lexer::new(input, &mut interner);
125 let tokens = lexer.tokenize();
126
127 let mwe_trie = mwe::build_mwe_trie();
129 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
130
131 let type_registry = {
133 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
134 discovery.run()
135 };
136
137 let expr_arena = Arena::new();
138 let term_arena = Arena::new();
139 let np_arena = Arena::new();
140 let sym_arena = Arena::new();
141 let role_arena = Arena::new();
142 let pp_arena = Arena::new();
143
144 let ctx = AstContext::new(
145 &expr_arena,
146 &term_arena,
147 &np_arena,
148 &sym_arena,
149 &role_arena,
150 &pp_arena,
151 );
152
153 let mut world_state = drs::WorldState::new();
155 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
156 let ast = parser.parse()?;
157 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, &mut interner);
158
159 let ast = if options.format == OutputFormat::Kripke {
161 semantics::apply_kripke_lowering(ast, ctx.exprs, ctx.terms, &mut interner)
162 } else {
163 ast
164 };
165
166 let ast = pragmatics::apply_pragmatics(ast, ctx.exprs, &interner);
167 let mut registry = SymbolRegistry::new();
168 let main_output = ast.transpile_discourse(&mut registry, &interner, options.format);
170
171 let constraints = world_state.time_constraints();
173 if constraints.is_empty() {
174 Ok(main_output)
175 } else {
176 let constraint_strs: Vec<String> = constraints.iter().map(|c| {
177 match c.relation {
178 drs::TimeRelation::Precedes => format!("Precedes({}, {})", c.left, c.right),
179 drs::TimeRelation::Equals => format!("{}={}", c.left, c.right),
180 }
181 }).collect();
182 Ok(format!("{} ∧ {}", main_output, constraint_strs.join(" ∧ ")))
183 }
184}
185
186pub fn compile_with_world_state(input: &str, world_state: &mut drs::WorldState) -> Result<String, ParseError> {
188 compile_with_world_state_options(input, world_state, CompileOptions::default())
189}
190
191pub fn compile_with_world_state_options(
193 input: &str,
194 world_state: &mut drs::WorldState,
195 options: CompileOptions,
196) -> Result<String, ParseError> {
197 let mut interner = Interner::new();
198 compile_with_world_state_interner_options(input, world_state, &mut interner, options)
199}
200
201pub fn compile_with_discourse(
204 input: &str,
205 world_state: &mut drs::WorldState,
206 interner: &mut Interner,
207) -> Result<String, ParseError> {
208 compile_with_world_state_interner_options(input, world_state, interner, CompileOptions::default())
209}
210
211pub fn compile_with_world_state_interner_options(
213 input: &str,
214 world_state: &mut drs::WorldState,
215 interner: &mut Interner,
216 options: CompileOptions,
217) -> Result<String, ParseError> {
218 let mut lexer = Lexer::new(input, interner);
219 let tokens = lexer.tokenize();
220
221 let mwe_trie = mwe::build_mwe_trie();
223 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, interner);
224
225 let type_registry = {
227 let mut discovery = analysis::DiscoveryPass::new(&tokens, interner);
228 discovery.run()
229 };
230
231 let expr_arena = Arena::new();
232 let term_arena = Arena::new();
233 let np_arena = Arena::new();
234 let sym_arena = Arena::new();
235 let role_arena = Arena::new();
236 let pp_arena = Arena::new();
237
238 let ctx = AstContext::new(
239 &expr_arena,
240 &term_arena,
241 &np_arena,
242 &sym_arena,
243 &role_arena,
244 &pp_arena,
245 );
246
247 let mut parser = Parser::new(tokens, world_state, interner, ctx, type_registry);
248 parser.swap_drs_with_world_state();
250 let ast = parser.parse()?;
251 parser.swap_drs_with_world_state();
253 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, interner);
254
255 world_state.end_sentence();
257
258 let ast = if options.format == OutputFormat::Kripke {
259 semantics::apply_kripke_lowering(ast, ctx.exprs, ctx.terms, interner)
260 } else {
261 ast
262 };
263
264 let ast = pragmatics::apply_pragmatics(ast, ctx.exprs, interner);
265 let mut registry = SymbolRegistry::new();
266 let main_output = ast.transpile_discourse(&mut registry, interner, options.format);
267
268 let constraints = world_state.time_constraints();
269 if constraints.is_empty() {
270 Ok(main_output)
271 } else {
272 let constraint_strs: Vec<String> = constraints.iter().map(|c| {
273 match c.relation {
274 drs::TimeRelation::Precedes => format!("Precedes({}, {})", c.left, c.right),
275 drs::TimeRelation::Equals => format!("{}={}", c.left, c.right),
276 }
277 }).collect();
278 Ok(format!("{} ∧ {}", main_output, constraint_strs.join(" ∧ ")))
279 }
280}
281
282pub fn compile_all_scopes(input: &str) -> Result<Vec<String>, ParseError> {
288 compile_all_scopes_with_options(input, CompileOptions::default())
289}
290
291pub fn compile_all_scopes_with_options(input: &str, options: CompileOptions) -> Result<Vec<String>, ParseError> {
293 let mut interner = Interner::new();
294 let mut lexer = Lexer::new(input, &mut interner);
295 let tokens = lexer.tokenize();
296
297 let mwe_trie = mwe::build_mwe_trie();
299 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
300
301 let type_registry = {
303 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
304 discovery.run()
305 };
306
307 let expr_arena = Arena::new();
308 let term_arena = Arena::new();
309 let np_arena = Arena::new();
310 let sym_arena = Arena::new();
311 let role_arena = Arena::new();
312 let pp_arena = Arena::new();
313
314 let ctx = AstContext::new(
315 &expr_arena,
316 &term_arena,
317 &np_arena,
318 &sym_arena,
319 &role_arena,
320 &pp_arena,
321 );
322
323 let mut world_state = drs::WorldState::new();
325 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
326 let ast = parser.parse()?;
327
328 let scope_arena = Arena::new();
329 let scope_term_arena = Arena::new();
330 let scopings = lambda::enumerate_scopings(ast, &mut interner, &scope_arena, &scope_term_arena);
331
332 let intensional_arena = Arena::new();
333 let intensional_term_arena = Arena::new();
334 let intensional_role_arena: Arena<(crate::ast::ThematicRole, crate::ast::Term)> = Arena::new();
335
336 let mut results = Vec::new();
337 for scoped_expr in scopings {
338 let intensional_readings = lambda::enumerate_intensional_readings(
339 scoped_expr,
340 &mut interner,
341 &intensional_arena,
342 &intensional_term_arena,
343 &intensional_role_arena,
344 );
345 for reading in intensional_readings {
346 let reading = semantics::apply_axioms(reading, &intensional_arena, &intensional_term_arena, &mut interner);
347 let mut registry = SymbolRegistry::new();
348 results.push(reading.transpile(&mut registry, &interner, options.format));
349 }
350 }
351
352 Ok(results)
353}
354
355pub fn compile_forest(input: &str) -> Vec<String> {
362 compile_forest_with_options(input, CompileOptions::default())
363}
364
365pub fn compile_forest_with_options(input: &str, options: CompileOptions) -> Vec<String> {
367 let mut interner = Interner::new();
368 let mut lexer = Lexer::new(input, &mut interner);
369 let tokens = lexer.tokenize();
370
371 let mwe_trie = mwe::build_mwe_trie();
373 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
374
375 let type_registry = {
377 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
378 discovery.run()
379 };
380
381 let has_lexical_ambiguity = tokens.iter().any(|t| {
382 matches!(t.kind, token::TokenType::Ambiguous { .. })
383 });
384
385 let has_pp_ambiguity = tokens.iter().any(|t| {
386 if let token::TokenType::Preposition(sym) = &t.kind {
387 let prep = interner.resolve(*sym);
388 prep == "with" || prep == "by" || prep == "for"
389 } else {
390 false
391 }
392 });
393
394 let has_mixed_verb = tokens.iter().any(|t| {
396 if let token::TokenType::Verb { lemma, .. } = &t.kind {
397 Lexer::is_mixed_verb(interner.resolve(*lemma))
398 } else {
399 false
400 }
401 });
402
403 let has_collective_verb = tokens.iter().any(|t| {
405 if let token::TokenType::Verb { lemma, .. } = &t.kind {
406 Lexer::is_collective_verb(interner.resolve(*lemma))
407 } else {
408 false
409 }
410 });
411
412 let has_plural_subject = tokens.iter().any(|t| {
413 matches!(t.kind, token::TokenType::Cardinal(_))
414 || matches!(&t.kind, token::TokenType::Article(def) if matches!(def, lexicon::Definiteness::Definite))
415 });
416
417 let has_plurality_ambiguity = (has_mixed_verb || has_collective_verb) && has_plural_subject;
418
419 let has_event_adjective_ambiguity = {
421 let mut has_event_adj = false;
422 let mut has_agentive_noun = false;
423 for token in &tokens {
424 if let token::TokenType::Adjective(sym) = &token.kind {
425 if lexicon::is_event_modifier_adjective(interner.resolve(*sym)) {
426 has_event_adj = true;
427 }
428 }
429 if let token::TokenType::Noun(sym) = &token.kind {
430 if lexicon::lookup_agentive_noun(interner.resolve(*sym)).is_some() {
431 has_agentive_noun = true;
432 }
433 }
434 }
435 has_event_adj && has_agentive_noun
436 };
437
438 let has_negative_verb = tokens.iter().any(|t| {
440 if let token::TokenType::Verb { lemma, .. } = &t.kind {
441 lexicon::get_canonical_verb(&interner.resolve(*lemma).to_lowercase())
442 .map(|(_, is_neg)| is_neg)
443 .unwrap_or(false)
444 } else {
445 false
446 }
447 });
448
449 let has_may = tokens.iter().any(|t| matches!(t.kind, token::TokenType::May));
451 let has_can = tokens.iter().any(|t| matches!(t.kind, token::TokenType::Can));
452 let has_could = tokens.iter().any(|t| matches!(t.kind, token::TokenType::Could));
453
454 let mut results: Vec<String> = Vec::new();
455
456 {
458 let expr_arena = Arena::new();
459 let term_arena = Arena::new();
460 let np_arena = Arena::new();
461 let sym_arena = Arena::new();
462 let role_arena = Arena::new();
463 let pp_arena = Arena::new();
464
465 let ast_ctx = AstContext::new(
466 &expr_arena,
467 &term_arena,
468 &np_arena,
469 &sym_arena,
470 &role_arena,
471 &pp_arena,
472 );
473
474 let mut world_state = drs::WorldState::new();
475 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
476 parser.set_noun_priority_mode(false);
477
478 if let Ok(ast) = parser.parse() {
479 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
480 let ast = if options.format == OutputFormat::Kripke {
481 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
482 } else {
483 ast
484 };
485 let mut registry = SymbolRegistry::new();
486 results.push(ast.transpile_discourse(&mut registry, &interner, options.format));
487 }
488 }
489
490 if has_lexical_ambiguity {
492 let expr_arena = Arena::new();
493 let term_arena = Arena::new();
494 let np_arena = Arena::new();
495 let sym_arena = Arena::new();
496 let role_arena = Arena::new();
497 let pp_arena = Arena::new();
498
499 let ast_ctx = AstContext::new(
500 &expr_arena,
501 &term_arena,
502 &np_arena,
503 &sym_arena,
504 &role_arena,
505 &pp_arena,
506 );
507
508 let mut world_state = drs::WorldState::new();
509 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
510 parser.set_noun_priority_mode(true);
511
512 if let Ok(ast) = parser.parse() {
513 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
514 let ast = if options.format == OutputFormat::Kripke {
515 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
516 } else {
517 ast
518 };
519 let mut registry = SymbolRegistry::new();
520 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
521 if !results.contains(&reading) {
522 results.push(reading);
523 }
524 }
525 }
526
527 if has_pp_ambiguity {
529 let expr_arena = Arena::new();
530 let term_arena = Arena::new();
531 let np_arena = Arena::new();
532 let sym_arena = Arena::new();
533 let role_arena = Arena::new();
534 let pp_arena = Arena::new();
535
536 let ast_ctx = AstContext::new(
537 &expr_arena,
538 &term_arena,
539 &np_arena,
540 &sym_arena,
541 &role_arena,
542 &pp_arena,
543 );
544
545 let mut world_state = drs::WorldState::new();
546 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
547 parser.set_pp_attachment_mode(true);
548
549 if let Ok(ast) = parser.parse() {
550 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
551 let ast = if options.format == OutputFormat::Kripke {
552 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
553 } else {
554 ast
555 };
556 let mut registry = SymbolRegistry::new();
557 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
558 if !results.contains(&reading) {
559 results.push(reading);
560 }
561 }
562 }
563
564 if has_plurality_ambiguity {
566 let expr_arena = Arena::new();
567 let term_arena = Arena::new();
568 let np_arena = Arena::new();
569 let sym_arena = Arena::new();
570 let role_arena = Arena::new();
571 let pp_arena = Arena::new();
572
573 let ast_ctx = AstContext::new(
574 &expr_arena,
575 &term_arena,
576 &np_arena,
577 &sym_arena,
578 &role_arena,
579 &pp_arena,
580 );
581
582 let mut world_state = drs::WorldState::new();
583 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
584 parser.set_collective_mode(true);
585
586 if let Ok(ast) = parser.parse() {
587 if let Ok(transformed) = parser.transform_cardinal_to_group(ast) {
588 let transformed = semantics::apply_axioms(transformed, ast_ctx.exprs, ast_ctx.terms, &mut interner);
589 let mut registry = SymbolRegistry::new();
590 let reading = transformed.transpile(&mut registry, &interner, options.format);
591 if !results.contains(&reading) {
592 results.push(reading);
593 }
594 }
595 }
596 }
597
598 if has_event_adjective_ambiguity {
600 let expr_arena = Arena::new();
601 let term_arena = Arena::new();
602 let np_arena = Arena::new();
603 let sym_arena = Arena::new();
604 let role_arena = Arena::new();
605 let pp_arena = Arena::new();
606
607 let ast_ctx = AstContext::new(
608 &expr_arena,
609 &term_arena,
610 &np_arena,
611 &sym_arena,
612 &role_arena,
613 &pp_arena,
614 );
615
616 let mut world_state = drs::WorldState::new();
617 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
618 parser.set_event_reading_mode(true);
619
620 if let Ok(ast) = parser.parse() {
621 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
622 let ast = if options.format == OutputFormat::Kripke {
623 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
624 } else {
625 ast
626 };
627 let mut registry = SymbolRegistry::new();
628 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
629 if !results.contains(&reading) {
630 results.push(reading);
631 }
632 }
633 }
634
635 if has_negative_verb {
637 let expr_arena = Arena::new();
638 let term_arena = Arena::new();
639 let np_arena = Arena::new();
640 let sym_arena = Arena::new();
641 let role_arena = Arena::new();
642 let pp_arena = Arena::new();
643
644 let ast_ctx = AstContext::new(
645 &expr_arena,
646 &term_arena,
647 &np_arena,
648 &sym_arena,
649 &role_arena,
650 &pp_arena,
651 );
652
653 let mut world_state = drs::WorldState::new();
654 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
655 parser.set_negative_scope_mode(NegativeScopeMode::Wide);
656
657 if let Ok(ast) = parser.parse() {
658 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
659 let ast = if options.format == OutputFormat::Kripke {
660 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
661 } else {
662 ast
663 };
664 let mut registry = SymbolRegistry::new();
665 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
666 if !results.contains(&reading) {
667 results.push(reading);
668 }
669 }
670 }
671
672 if has_may || has_could {
674 let expr_arena = Arena::new();
675 let term_arena = Arena::new();
676 let np_arena = Arena::new();
677 let sym_arena = Arena::new();
678 let role_arena = Arena::new();
679 let pp_arena = Arena::new();
680
681 let ast_ctx = AstContext::new(
682 &expr_arena,
683 &term_arena,
684 &np_arena,
685 &sym_arena,
686 &role_arena,
687 &pp_arena,
688 );
689
690 let mut world_state = drs::WorldState::new();
691 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
692 parser.set_modal_preference(ModalPreference::Epistemic);
693
694 if let Ok(ast) = parser.parse() {
695 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
696 let ast = if options.format == OutputFormat::Kripke {
697 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
698 } else {
699 ast
700 };
701 let mut registry = SymbolRegistry::new();
702 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
703 if !results.contains(&reading) {
704 results.push(reading);
705 }
706 }
707 }
708
709 if has_can {
711 let expr_arena = Arena::new();
712 let term_arena = Arena::new();
713 let np_arena = Arena::new();
714 let sym_arena = Arena::new();
715 let role_arena = Arena::new();
716 let pp_arena = Arena::new();
717
718 let ast_ctx = AstContext::new(
719 &expr_arena,
720 &term_arena,
721 &np_arena,
722 &sym_arena,
723 &role_arena,
724 &pp_arena,
725 );
726
727 let mut world_state = drs::WorldState::new();
728 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry.clone());
729 parser.set_modal_preference(ModalPreference::Deontic);
730
731 if let Ok(ast) = parser.parse() {
732 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
733 let ast = if options.format == OutputFormat::Kripke {
734 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
735 } else {
736 ast
737 };
738 let mut registry = SymbolRegistry::new();
739 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
740 if !results.contains(&reading) {
741 results.push(reading);
742 }
743 }
744 }
745
746 if has_negative_verb && has_can {
748 let expr_arena = Arena::new();
749 let term_arena = Arena::new();
750 let np_arena = Arena::new();
751 let sym_arena = Arena::new();
752 let role_arena = Arena::new();
753 let pp_arena = Arena::new();
754
755 let ast_ctx = AstContext::new(
756 &expr_arena,
757 &term_arena,
758 &np_arena,
759 &sym_arena,
760 &role_arena,
761 &pp_arena,
762 );
763
764 let mut world_state = drs::WorldState::new();
765 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ast_ctx, type_registry);
766 parser.set_negative_scope_mode(NegativeScopeMode::Wide);
767 parser.set_modal_preference(ModalPreference::Deontic);
768
769 if let Ok(ast) = parser.parse() {
770 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
771 let ast = if options.format == OutputFormat::Kripke {
772 semantics::apply_kripke_lowering(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner)
773 } else {
774 ast
775 };
776 let mut registry = SymbolRegistry::new();
777 let reading = ast.transpile_discourse(&mut registry, &interner, options.format);
778 if !results.contains(&reading) {
779 results.push(reading);
780 }
781 }
782 }
783
784 results.truncate(MAX_FOREST_READINGS);
786
787 results
788}
789
790pub fn compile_discourse(sentences: &[&str]) -> Result<String, ParseError> {
796 compile_discourse_with_options(sentences, CompileOptions::default())
797}
798
799pub fn compile_discourse_with_options(sentences: &[&str], options: CompileOptions) -> Result<String, ParseError> {
801 let mut interner = Interner::new();
802 let mut world_state = drs::WorldState::new();
803 let mut results = Vec::new();
804 let mut registry = SymbolRegistry::new();
805 let mwe_trie = mwe::build_mwe_trie();
806
807 for sentence in sentences {
808 let event_var_name = world_state.next_event_var();
809 let event_var_symbol = interner.intern(&event_var_name);
810
811 let mut lexer = Lexer::new(sentence, &mut interner);
812 let tokens = lexer.tokenize();
813
814 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
816
817 let type_registry = {
819 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
820 discovery.run()
821 };
822
823 let expr_arena = Arena::new();
824 let term_arena = Arena::new();
825 let np_arena = Arena::new();
826 let sym_arena = Arena::new();
827 let role_arena = Arena::new();
828 let pp_arena = Arena::new();
829
830 let ast_ctx = AstContext::new(
831 &expr_arena,
832 &term_arena,
833 &np_arena,
834 &sym_arena,
835 &role_arena,
836 &pp_arena,
837 );
838
839 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ast_ctx, type_registry);
841 parser.set_discourse_event_var(event_var_symbol);
842 parser.swap_drs_with_world_state();
844 let ast = parser.parse()?;
845 parser.swap_drs_with_world_state();
847
848 world_state.end_sentence();
850
851 let ast = semantics::apply_axioms(ast, ast_ctx.exprs, ast_ctx.terms, &mut interner);
852 results.push(ast.transpile_discourse(&mut registry, &interner, options.format));
853 }
854
855 let event_history = world_state.event_history();
856 let mut precedes = Vec::new();
857 for i in 0..event_history.len().saturating_sub(1) {
858 precedes.push(format!("Precedes({}, {})", event_history[i], event_history[i + 1]));
859 }
860
861 if precedes.is_empty() {
862 Ok(results.join(" ∧ "))
863 } else {
864 Ok(format!("{} ∧ {}", results.join(" ∧ "), precedes.join(" ∧ ")))
865 }
866}
867
868pub fn compile_ambiguous(input: &str) -> Result<Vec<String>, ParseError> {
875 compile_ambiguous_with_options(input, CompileOptions::default())
876}
877
878pub fn compile_ambiguous_with_options(input: &str, options: CompileOptions) -> Result<Vec<String>, ParseError> {
880 let mut interner = Interner::new();
881 let mut lexer = Lexer::new(input, &mut interner);
882 let tokens = lexer.tokenize();
883
884 let mwe_trie = mwe::build_mwe_trie();
886 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
887
888 let type_registry = {
890 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
891 discovery.run()
892 };
893
894 let expr_arena = Arena::new();
895 let term_arena = Arena::new();
896 let np_arena = Arena::new();
897 let sym_arena = Arena::new();
898 let role_arena = Arena::new();
899 let pp_arena = Arena::new();
900
901 let ctx = AstContext::new(
902 &expr_arena,
903 &term_arena,
904 &np_arena,
905 &sym_arena,
906 &role_arena,
907 &pp_arena,
908 );
909
910 let mut world_state = drs::WorldState::new();
912 let mut parser = Parser::new(tokens.clone(), &mut world_state, &mut interner, ctx, type_registry.clone());
913 let ast = parser.parse()?;
914 let ast = semantics::apply_axioms(ast, ctx.exprs, ctx.terms, &mut interner);
915 let mut registry = SymbolRegistry::new();
916 let reading1 = ast.transpile(&mut registry, &interner, options.format);
917
918 let has_pp_ambiguity = tokens.iter().any(|t| {
919 if let token::TokenType::Preposition(sym) = &t.kind {
920 let prep = interner.resolve(*sym);
921 prep == "with" || prep == "by" || prep == "for"
922 } else {
923 false
924 }
925 });
926
927 if has_pp_ambiguity {
928 let expr_arena2 = Arena::new();
929 let term_arena2 = Arena::new();
930 let np_arena2 = Arena::new();
931 let sym_arena2 = Arena::new();
932 let role_arena2 = Arena::new();
933 let pp_arena2 = Arena::new();
934
935 let ctx2 = AstContext::new(
936 &expr_arena2,
937 &term_arena2,
938 &np_arena2,
939 &sym_arena2,
940 &role_arena2,
941 &pp_arena2,
942 );
943
944 let mut world_state2 = drs::WorldState::new();
945 let mut parser2 = Parser::new(tokens, &mut world_state2, &mut interner, ctx2, type_registry);
946 parser2.set_pp_attachment_mode(true);
947 let ast2 = parser2.parse()?;
948 let ast2 = semantics::apply_axioms(ast2, ctx2.exprs, ctx2.terms, &mut interner);
949 let mut registry2 = SymbolRegistry::new();
950 let reading2 = ast2.transpile(&mut registry2, &interner, options.format);
951
952 if reading1 != reading2 {
953 return Ok(vec![reading1, reading2]);
954 }
955 }
956
957 Ok(vec![reading1])
958}
959
960use crate::ast::{self, Stmt};
965use crate::token::Span;
966use crate::error::ParseErrorKind;
967use logicaffeine_proof::BackwardChainer;
968use crate::proof_convert::logic_expr_to_proof_expr;
969
970pub fn compile_theorem(input: &str) -> Result<String, ParseError> {
972 let mut interner = Interner::new();
973 let mut lexer = Lexer::new(input, &mut interner);
974 let tokens = lexer.tokenize();
975
976 let mwe_trie = mwe::build_mwe_trie();
978 let tokens = mwe::apply_mwe_pipeline(tokens, &mwe_trie, &mut interner);
979
980 let type_registry = {
982 let mut discovery = analysis::DiscoveryPass::new(&tokens, &mut interner);
983 discovery.run()
984 };
985
986 let expr_arena = Arena::new();
987 let term_arena = Arena::new();
988 let np_arena = Arena::new();
989 let sym_arena = Arena::new();
990 let role_arena = Arena::new();
991 let pp_arena = Arena::new();
992
993 let ctx = AstContext::new(
994 &expr_arena,
995 &term_arena,
996 &np_arena,
997 &sym_arena,
998 &role_arena,
999 &pp_arena,
1000 );
1001
1002 let mut world_state = drs::WorldState::new();
1004 let mut parser = Parser::new(tokens, &mut world_state, &mut interner, ctx, type_registry);
1005 let statements = parser.parse_program()?;
1006
1007 let theorem = statements
1009 .iter()
1010 .find_map(|stmt| {
1011 if let Stmt::Theorem(t) = stmt {
1012 Some(t)
1013 } else {
1014 None
1015 }
1016 })
1017 .ok_or_else(|| ParseError {
1018 kind: ParseErrorKind::Custom("No theorem block found in input".to_string()),
1019 span: Span::default(),
1020 })?;
1021
1022 let mut engine = BackwardChainer::new();
1024 for premise in &theorem.premises {
1025 let proof_expr = logic_expr_to_proof_expr(premise, &interner);
1026 engine.add_axiom(proof_expr);
1027 }
1028
1029 let goal = logic_expr_to_proof_expr(theorem.goal, &interner);
1031
1032 match engine.prove(goal.clone()) {
1034 Ok(derivation) => {
1035 Ok(format!(
1036 "Theorem '{}' Proved!\n{}",
1037 theorem.name,
1038 derivation.display_tree()
1039 ))
1040 }
1041 Err(e) => {
1042 Err(ParseError {
1044 kind: ParseErrorKind::Custom(format!(
1045 "Theorem '{}' failed.\n Goal: {}\n Premises: {}\n Error: {}",
1046 theorem.name,
1047 goal,
1048 theorem.premises.len(),
1049 e
1050 )),
1051 span: Span::default(),
1052 })
1053 }
1054 }
1055}
1056
1057#[cfg(test)]
1058mod tests {
1059 use super::*;
1060
1061 #[test]
1062 fn test_compile_simple_sentence() {
1063 let result = compile("John runs.");
1064 assert!(result.is_ok());
1065 let output = result.unwrap();
1066 assert!(output.contains("Run"));
1067 assert!(output.contains("John"));
1068 }
1069
1070 #[test]
1071 fn test_compile_with_unicode_format() {
1072 let options = CompileOptions { format: OutputFormat::Unicode };
1073 let result = compile_with_options("Every dog barks.", options);
1074 assert!(result.is_ok());
1075 let output = result.unwrap();
1076 assert!(output.contains("∀") || output.contains("Forall"));
1077 }
1078
1079 #[test]
1080 fn test_compile_all_scopes() {
1081 let result = compile_all_scopes("Every woman loves a man.");
1082 assert!(result.is_ok());
1083 let readings = result.unwrap();
1084 assert!(readings.len() >= 1);
1085 }
1086}