1use super::modal::ModalParsing;
16use super::noun::NounParsing;
17use super::pragmatics::PragmaticsParsing;
18use super::quantifier::QuantifierParsing;
19use super::question::QuestionParsing;
20use super::verb::LogicVerbParsing;
21use super::{EventTemplate, ParseResult, Parser};
22use crate::ast::{AspectOperator, LogicExpr, NeoEventData, NounPhrase, QuantifierKind, TemporalOperator, Term, ThematicRole};
23use crate::lexer::Lexer;
24use crate::lexicon::Time;
25use crate::drs::{BoxType, Gender, Number};
26use super::ParserMode;
27use crate::error::{ParseError, ParseErrorKind};
28use logicaffeine_base::Symbol;
29use crate::lexicon::Definiteness;
30use crate::token::TokenType;
31
32pub trait ClauseParsing<'a, 'ctx, 'int> {
37 fn parse_sentence(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
39 fn parse_conditional(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
41 fn parse_either_or(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
43 fn parse_disjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
45 fn parse_conjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
47 fn parse_relative_clause(&mut self, gap_var: Symbol) -> ParseResult<&'a LogicExpr<'a>>;
49 fn parse_gapped_clause(&mut self, borrowed_verb: Symbol) -> ParseResult<&'a LogicExpr<'a>>;
51 fn parse_counterfactual_antecedent(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
53 fn parse_counterfactual_consequent(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
55 fn check_wh_word(&self) -> bool;
57 fn is_counterfactual_context(&self) -> bool;
59 fn is_complete_clause(&self, expr: &LogicExpr<'a>) -> bool;
61 fn extract_verb_from_expr(&self, expr: &LogicExpr<'a>) -> Option<Symbol>;
63 fn try_parse_ellipsis(&mut self) -> Option<ParseResult<&'a LogicExpr<'a>>>;
65 fn check_ellipsis_auxiliary(&self) -> bool;
67 fn check_ellipsis_terminator(&self) -> bool;
69}
70
71impl<'a, 'ctx, 'int> ClauseParsing<'a, 'ctx, 'int> for Parser<'a, 'ctx, 'int> {
72 fn parse_sentence(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
73 if self.mode == ParserMode::Imperative && self.check(&TokenType::Let) {
77 self.advance(); let _var = self.expect_identifier()?;
79 if self.check(&TokenType::Is) || self.check(&TokenType::Be) || self.check(&TokenType::Equals) || self.check(&TokenType::Identity) {
81 self.advance(); }
83 return self.parse_disjunction();
85 }
86
87 if let Some(result) = self.try_parse_ellipsis() {
89 return result;
90 }
91
92 if self.check_verb() {
93 let verb_pos = self.current;
94 let mut temp_pos = self.current + 1;
95 while temp_pos < self.tokens.len() {
96 if matches!(self.tokens[temp_pos].kind, TokenType::Exclamation) {
97 self.current = verb_pos;
98 let verb = self.consume_verb();
99 while !matches!(self.peek().kind, TokenType::Exclamation | TokenType::EOF) {
100 self.advance();
101 }
102 if self.check(&TokenType::Exclamation) {
103 self.advance();
104 }
105 let addressee = self.interner.intern("addressee");
106 let action = self.ctx.exprs.alloc(LogicExpr::Predicate {
107 name: verb,
108 args: self.ctx.terms.alloc_slice([Term::Variable(addressee)]),
109 world: None,
110 });
111 return Ok(self.ctx.exprs.alloc(LogicExpr::Imperative { action }));
112 }
113 if matches!(self.tokens[temp_pos].kind, TokenType::Period | TokenType::EOF) {
114 break;
115 }
116 temp_pos += 1;
117 }
118 }
119
120 if self.check_wh_word() {
121 return self.parse_wh_question();
122 }
123
124 if self.check(&TokenType::Does)
125 || self.check(&TokenType::Do)
126 || self.check(&TokenType::Is)
127 || self.check(&TokenType::Are)
128 || self.check(&TokenType::Was)
129 || self.check(&TokenType::Were)
130 || self.check(&TokenType::Would)
131 || self.check(&TokenType::Could)
132 || self.check(&TokenType::Can)
133 {
134 return self.parse_yes_no_question();
135 }
136
137 if self.match_token(&[TokenType::If]) {
138 return self.parse_conditional();
139 }
140
141 if self.match_token(&[TokenType::Either]) {
144 return self.parse_either_or();
145 }
146
147 if self.check_modal() {
148 self.advance();
149 return self.parse_modal();
150 }
151
152 if self.match_token(&[TokenType::Not]) {
153 self.negative_depth += 1;
154 let inner = self.parse_sentence()?;
155 self.negative_depth -= 1;
156 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
157 op: TokenType::Not,
158 operand: inner,
159 }));
160 }
161
162 self.parse_disjunction()
163 }
164
165 fn check_wh_word(&self) -> bool {
166 if matches!(
167 self.peek().kind,
168 TokenType::Who
169 | TokenType::What
170 | TokenType::Where
171 | TokenType::When
172 | TokenType::Why
173 ) {
174 return true;
175 }
176 if self.check_preposition() && self.current + 1 < self.tokens.len() {
177 matches!(
178 self.tokens[self.current + 1].kind,
179 TokenType::Who
180 | TokenType::What
181 | TokenType::Where
182 | TokenType::When
183 | TokenType::Why
184 )
185 } else {
186 false
187 }
188 }
189
190 fn parse_conditional(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
191 let is_counterfactual = self.is_counterfactual_context();
192
193 self.drs.enter_box(BoxType::ConditionalAntecedent);
195 let antecedent = self.parse_counterfactual_antecedent()?;
196 self.drs.exit_box();
197
198 if self.check(&TokenType::Comma) {
199 self.advance();
200 }
201
202 if self.check(&TokenType::Then) {
203 self.advance();
204 }
205
206 self.drs.enter_box(BoxType::ConditionalConsequent);
208 let consequent = self.parse_counterfactual_consequent()?;
209 self.drs.exit_box();
210
211 let universal_refs = self.drs.get_universal_referents();
213
214 let conditional = if is_counterfactual {
216 self.ctx.exprs.alloc(LogicExpr::Counterfactual {
217 antecedent,
218 consequent,
219 })
220 } else {
221 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
222 left: antecedent,
223 op: TokenType::If,
224 right: consequent,
225 })
226 };
227
228 let mut result = conditional;
230 for var in universal_refs.into_iter().rev() {
231 result = self.ctx.exprs.alloc(LogicExpr::Quantifier {
232 kind: QuantifierKind::Universal,
233 variable: var,
234 body: result,
235 island_id: self.current_island,
236 });
237 }
238
239 Ok(result)
240 }
241
242 fn parse_either_or(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
247 let start_pos = self.current;
249
250 if let TokenType::ProperName(name1) = self.peek().kind {
253 self.advance(); if self.check(&TokenType::Or) {
256 self.advance(); if let TokenType::ProperName(name2) = self.peek().kind {
259 self.advance(); let is_copula = matches!(
263 self.peek().kind,
264 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
265 );
266 if is_copula {
267 self.advance(); let is_negated = self.match_token(&[TokenType::Not]);
271
272 if let TokenType::Adjective(adj) = self.peek().kind {
274 self.advance(); let pred1 = self.ctx.exprs.alloc(LogicExpr::Predicate {
278 name: adj,
279 args: self.ctx.terms.alloc_slice(vec![
280 Term::Constant(name1)
281 ]),
282 world: None,
283 });
284 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
285 name: adj,
286 args: self.ctx.terms.alloc_slice(vec![
287 Term::Constant(name2)
288 ]),
289 world: None,
290 });
291
292 let left = if is_negated {
294 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
295 op: TokenType::Not,
296 operand: pred1,
297 })
298 } else {
299 pred1
300 };
301 let right = if is_negated {
302 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
303 op: TokenType::Not,
304 operand: pred2,
305 })
306 } else {
307 pred2
308 };
309
310 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
311 left,
312 op: TokenType::Or,
313 right,
314 }));
315 }
316 }
317 }
318 }
319
320 self.current = start_pos;
322 }
323
324 self.drs.enter_box(BoxType::Disjunct);
327 let left = self.parse_conjunction()?;
328 self.drs.exit_box();
329
330 if !self.check(&TokenType::Or) {
331 return Err(ParseError {
332 kind: ParseErrorKind::ExpectedKeyword { keyword: "or".to_string() },
333 span: self.current_span(),
334 });
335 }
336 self.advance(); self.drs.enter_box(BoxType::Disjunct);
340 let right = self.parse_conjunction()?;
341 self.drs.exit_box();
342
343 Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
344 left,
345 op: TokenType::Or,
346 right,
347 }))
348 }
349
350 fn is_counterfactual_context(&self) -> bool {
351 for i in 0..5 {
352 if self.current + i >= self.tokens.len() {
353 break;
354 }
355 let token = &self.tokens[self.current + i];
356 if matches!(token.kind, TokenType::Were | TokenType::Had) {
357 return true;
358 }
359 if matches!(token.kind, TokenType::Comma | TokenType::Period) {
360 break;
361 }
362 }
363 false
364 }
365
366 fn parse_counterfactual_antecedent(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
367 let unknown = self.interner.intern("?");
368 if self.check_content_word() || self.check_pronoun() || self.check_article() {
369 if self.check_pronoun() {
372 let token = self.peek();
373 let token_text = self.interner.resolve(token.lexeme);
374 if token_text.eq_ignore_ascii_case("it") {
375 if self.current + 1 < self.tokens.len() {
377 if let TokenType::Verb { lemma, time, .. } = &self.tokens[self.current + 1].kind {
379 let lemma_str = self.interner.resolve(*lemma);
380 if Lexer::is_weather_verb(lemma_str) {
381 let verb = *lemma;
382 let verb_time = *time;
383 self.advance(); self.advance(); let event_var = self.get_event_var();
387
388 let suppress_existential = self.drs.in_conditional_antecedent();
391
392 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
393 event_var,
394 verb,
395 roles: self.ctx.roles.alloc_slice(vec![]),
396 modifiers: self.ctx.syms.alloc_slice(vec![]),
397 suppress_existential,
398 world: None,
399 })));
400
401 while self.check(&TokenType::And) || self.check(&TokenType::Or) {
404 let is_disjunction = self.check(&TokenType::Or);
405 self.advance(); if let TokenType::Verb { lemma: lemma2, .. } = &self.peek().kind.clone() {
408 let lemma2_str = self.interner.resolve(*lemma2);
409 if Lexer::is_weather_verb(lemma2_str) {
410 let verb2 = *lemma2;
411 self.advance(); let neo_event2 = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
415 event_var, verb: verb2,
417 roles: self.ctx.roles.alloc_slice(vec![]),
418 modifiers: self.ctx.syms.alloc_slice(vec![]),
419 suppress_existential,
420 world: None,
421 })));
422
423 let op = if is_disjunction { TokenType::Or } else { TokenType::And };
424 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
425 left: result,
426 op,
427 right: neo_event2,
428 });
429 } else {
430 break; }
432 } else {
433 break;
434 }
435 }
436
437 return Ok(match verb_time {
438 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
439 operator: TemporalOperator::Past,
440 body: result,
441 }),
442 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
443 operator: TemporalOperator::Future,
444 body: result,
445 }),
446 _ => result,
447 });
448 }
449 }
450 else if self.current + 2 < self.tokens.len() {
452 let is_copula = matches!(
453 self.tokens[self.current + 1].kind,
454 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
455 );
456 if is_copula {
457 if let TokenType::Verb { lemma, .. } = &self.tokens[self.current + 2].kind {
458 let lemma_str = self.interner.resolve(*lemma);
459 if Lexer::is_weather_verb(lemma_str) {
460 let verb = *lemma;
461 let verb_time = if matches!(
462 self.tokens[self.current + 1].kind,
463 TokenType::Was | TokenType::Were
464 ) {
465 Time::Past
466 } else {
467 Time::Present
468 };
469 self.advance(); self.advance(); self.advance(); let event_var = self.get_event_var();
474 let suppress_existential = self.drs.in_conditional_antecedent();
477
478 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
479 event_var,
480 verb,
481 roles: self.ctx.roles.alloc_slice(vec![]),
482 modifiers: self.ctx.syms.alloc_slice(vec![]),
483 suppress_existential,
484 world: None,
485 })));
486
487 let with_aspect = self.ctx.exprs.alloc(LogicExpr::Aspectual {
489 operator: AspectOperator::Progressive,
490 body: neo_event,
491 });
492
493 return Ok(match verb_time {
494 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
495 operator: TemporalOperator::Past,
496 body: with_aspect,
497 }),
498 _ => with_aspect,
499 });
500 }
501 }
502 }
503 }
504 }
505 }
506 }
507
508 let (subject, subject_type_pred) = if self.check_pronoun() {
510 let token = self.advance().clone();
511 let token_text = self.interner.resolve(token.lexeme);
512 let resolved = if token_text.eq_ignore_ascii_case("i") {
514 self.interner.intern("Speaker")
515 } else if token_text.eq_ignore_ascii_case("you") {
516 self.interner.intern("Addressee")
517 } else if let TokenType::Pronoun { gender, number, .. } = token.kind {
518 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
519 match resolved_pronoun {
520 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
521 }
522 } else {
523 unknown
524 };
525 (resolved, None)
526 } else {
527 let np = self.parse_noun_phrase(true)?;
528
529 if np.definiteness == Some(Definiteness::Indefinite)
533 || np.definiteness == Some(Definiteness::Definite)
534 || np.definiteness == Some(Definiteness::Distal) {
535 let gender = Self::infer_noun_gender(self.interner.resolve(np.noun));
536 let number = if Self::is_plural_noun(self.interner.resolve(np.noun)) {
537 Number::Plural
538 } else {
539 Number::Singular
540 };
541
542 if np.definiteness == Some(Definiteness::Definite) || np.definiteness == Some(Definiteness::Distal) {
547 self.drs.introduce_referent_with_source(np.noun, np.noun, gender, number, crate::drs::ReferentSource::MainClause);
548 } else {
549 self.drs.introduce_referent(np.noun, np.noun, gender, number);
550 }
551
552 let type_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
554 name: np.noun,
555 args: self.ctx.terms.alloc_slice([Term::Variable(np.noun)]),
556 world: None,
557 });
558
559 (np.noun, Some(type_pred))
560 } else {
561 (np.noun, None)
563 }
564 };
565
566 let subject_term = if subject_type_pred.is_some() {
568 Term::Variable(subject)
569 } else {
570 Term::Constant(subject)
571 };
572
573 if self.check_presup_trigger() && self.is_followed_by_gerund() {
576 let presup_kind = match self.advance().kind {
577 TokenType::PresupTrigger(kind) => kind,
578 TokenType::Verb { lemma, .. } => {
579 let s = self.interner.resolve(lemma).to_lowercase();
580 crate::lexicon::lookup_presup_trigger(&s)
581 .expect("Lexicon mismatch: Verb flagged as trigger but lookup failed")
582 }
583 _ => panic!("Expected presupposition trigger"),
584 };
585 let np = NounPhrase {
586 noun: subject,
587 definiteness: None,
588 adjectives: &[],
589 possessor: None,
590 pps: &[],
591 superlative: None,
592 };
593 return self.parse_presupposition(&np, presup_kind);
594 }
595
596 if self.check(&TokenType::Were) {
597 self.advance();
598 let predicate = if self.check_pronoun() {
599 let token = self.advance().clone();
600 if let TokenType::Pronoun { gender, number, .. } = token.kind {
601 let token_text = self.interner.resolve(token.lexeme);
602 if token_text.eq_ignore_ascii_case("i") {
603 self.interner.intern("Speaker")
604 } else if token_text.eq_ignore_ascii_case("you") {
605 self.interner.intern("Addressee")
606 } else {
607 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
608 match resolved_pronoun {
609 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
610 }
611 }
612 } else {
613 unknown
614 }
615 } else {
616 self.consume_content_word()?
617 };
618 let be = self.interner.intern("Be");
619 let be_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
620 name: be,
621 args: self.ctx.terms.alloc_slice([
622 subject_term,
623 Term::Constant(predicate),
624 ]),
625 world: None,
626 });
627 return Ok(if let Some(type_pred) = subject_type_pred {
629 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
630 left: type_pred,
631 op: TokenType::And,
632 right: be_pred,
633 })
634 } else {
635 be_pred
636 });
637 }
638
639 if self.check(&TokenType::Had) {
640 self.advance();
641 let verb = self.consume_content_word()?;
642 let main_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
643 name: verb,
644 args: self.ctx.terms.alloc_slice([subject_term]),
645 world: None,
646 });
647
648 if self.check(&TokenType::Because) && !self.peek_next_is_string_literal() {
651 self.advance();
652 let cause = self.parse_atom()?;
653 let causal = self.ctx.exprs.alloc(LogicExpr::Causal {
654 effect: main_pred,
655 cause,
656 });
657 return Ok(if let Some(type_pred) = subject_type_pred {
659 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
660 left: type_pred,
661 op: TokenType::And,
662 right: causal,
663 })
664 } else {
665 causal
666 });
667 }
668
669 return Ok(if let Some(type_pred) = subject_type_pred {
671 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
672 left: type_pred,
673 op: TokenType::And,
674 right: main_pred,
675 })
676 } else {
677 main_pred
678 });
679 }
680
681 let verb_phrase = if subject_type_pred.is_some() {
684 self.parse_predicate_with_subject_as_var(subject)?
685 } else {
686 self.parse_predicate_with_subject(subject)?
687 };
688
689 return Ok(if let Some(type_pred) = subject_type_pred {
691 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
692 left: type_pred,
693 op: TokenType::And,
694 right: verb_phrase,
695 })
696 } else {
697 verb_phrase
698 });
699 }
700
701 self.parse_sentence()
702 }
703
704 fn parse_counterfactual_consequent(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
705 let unknown = self.interner.intern("?");
706 if self.check_content_word() || self.check_pronoun() {
707 if self.check_pronoun() {
710 let token = self.peek();
711 let token_text = self.interner.resolve(token.lexeme).to_lowercase();
712 if token_text == "its" {
713 if self.current + 1 < self.tokens.len() {
715 let next_token = &self.tokens[self.current + 1];
716 let next_str = self.interner.resolve(next_token.lexeme).to_lowercase();
717 if let Some(meta) = crate::lexicon::lookup_adjective_db(&next_str) {
718 if meta.features.contains(&crate::lexicon::Feature::Weather) {
719 return Err(ParseError {
720 kind: ParseErrorKind::GrammarError(
721 "Did you mean 'it's' (it is)? 'its' is a possessive pronoun.".to_string()
722 ),
723 span: self.current_span(),
724 });
725 }
726 }
727 }
728 }
729 }
730
731 if self.check_pronoun() {
733 let token_text = self.interner.resolve(self.peek().lexeme).to_lowercase();
734 if token_text == "it" {
735 if self.current + 2 < self.tokens.len() {
738 let next = &self.tokens[self.current + 1].kind;
739 if matches!(next, TokenType::Is | TokenType::Was | TokenType::Possessive) {
740 let adj_token = &self.tokens[self.current + 2];
742 let adj_sym = adj_token.lexeme;
743 let adj_str = self.interner.resolve(adj_sym).to_lowercase();
744 if let Some(meta) = crate::lexicon::lookup_adjective_db(&adj_str) {
745 if meta.features.contains(&crate::lexicon::Feature::Weather) {
746 self.advance(); self.advance(); self.advance(); let adj_lemma = self.interner.intern(meta.lemma);
752
753 let event_var = self.drs.get_last_event_referent(self.interner)
755 .unwrap_or_else(|| self.interner.intern("e"));
756
757 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::Predicate {
759 name: adj_lemma,
760 args: self.ctx.terms.alloc_slice([Term::Variable(event_var)]),
761 world: None,
762 });
763
764 while self.check(&TokenType::And) {
766 self.advance(); if self.check_content_word() {
768 let adj2_lexeme = self.peek().lexeme;
769 let adj2_str = self.interner.resolve(adj2_lexeme).to_lowercase();
770
771 if let Some(meta2) = crate::lexicon::lookup_adjective_db(&adj2_str) {
773 if meta2.features.contains(&crate::lexicon::Feature::Weather) {
774 self.advance(); let adj2_lemma = self.interner.intern(meta2.lemma);
777 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
778 name: adj2_lemma,
779 args: self.ctx.terms.alloc_slice([Term::Variable(event_var)]),
780 world: None,
781 });
782 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
783 left: result,
784 op: TokenType::And,
785 right: pred2,
786 });
787 continue;
788 }
789 }
790 }
791 break;
792 }
793
794 return Ok(result);
795 }
796 }
797 }
798 }
799 }
800 }
801
802 let subject = if self.check_pronoun() {
803 let token = self.advance().clone();
804 let token_text = self.interner.resolve(token.lexeme);
805 if token_text.eq_ignore_ascii_case("i") {
807 self.interner.intern("Speaker")
808 } else if token_text.eq_ignore_ascii_case("you") {
809 self.interner.intern("Addressee")
810 } else if let TokenType::Pronoun { gender, number, .. } = token.kind {
811 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
812 match resolved_pronoun {
813 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
814 }
815 } else {
816 unknown
817 }
818 } else {
819 self.parse_noun_phrase(true)?.noun
820 };
821
822 if self.check(&TokenType::Would) {
823 self.advance();
824 if self.check_content_word() {
825 let next_word = self.interner.resolve(self.peek().lexeme).to_lowercase();
826 if next_word == "have" {
827 self.advance();
828 }
829 }
830 let verb = self.consume_content_word()?;
831 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
832 name: verb,
833 args: self.ctx.terms.alloc_slice([Term::Constant(subject)]),
834 world: None,
835 }));
836 }
837
838 return self.parse_predicate_with_subject(subject);
839 }
840
841 self.parse_sentence()
842 }
843
844 fn extract_verb_from_expr(&self, expr: &LogicExpr<'a>) -> Option<Symbol> {
845 match expr {
846 LogicExpr::NeoEvent(data) => Some(data.verb),
848 LogicExpr::Control { verb, .. } => Some(*verb),
850 LogicExpr::BinaryOp { left, right, .. } => {
855 if let Some(verb) = self.extract_neo_event_verb(left) {
857 return Some(verb);
858 }
859 if let Some(verb) = self.extract_neo_event_verb(right) {
861 return Some(verb);
862 }
863 self.extract_verb_from_expr(left)
865 .or_else(|| self.extract_verb_from_expr(right))
866 }
867 LogicExpr::Predicate { name, .. } => Some(*name),
869 LogicExpr::Modal { operand, .. } => self.extract_verb_from_expr(operand),
870 LogicExpr::Presupposition { assertion, .. } => self.extract_verb_from_expr(assertion),
871 LogicExpr::Temporal { body, .. } => self.extract_verb_from_expr(body),
872 LogicExpr::TemporalAnchor { body, .. } => self.extract_verb_from_expr(body),
873 LogicExpr::Aspectual { body, .. } => self.extract_verb_from_expr(body),
874 LogicExpr::Quantifier { body, .. } => self.extract_verb_from_expr(body),
875 _ => None,
876 }
877 }
878
879 fn parse_gapped_clause(&mut self, borrowed_verb: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
882 let subject = self.parse_noun_phrase(true)?;
883
884 if self.check(&TokenType::Comma) {
885 self.advance();
886 }
887
888 let subject_term = self.noun_phrase_to_term(&subject);
889 let event_var = self.get_event_var();
890 let suppress_existential = self.drs.in_conditional_antecedent();
891
892 let template = self.last_event_template.clone();
894
895 let mut np_args: Vec<Term<'a>> = Vec::new();
897 let mut pp_args: Vec<(Symbol, Term<'a>)> = Vec::new();
898 let mut override_adverb: Option<Symbol> = None;
899
900 loop {
901 if self.check_temporal_adverb() {
902 if let TokenType::TemporalAdverb(sym) = self.advance().kind {
904 override_adverb = Some(sym);
905 }
906 } else if self.check_preposition() {
907 let prep = if let TokenType::Preposition(sym) = self.advance().kind {
909 sym
910 } else {
911 continue;
912 };
913 let np = self.parse_noun_phrase(false)?;
914 pp_args.push((prep, self.noun_phrase_to_term(&np)));
915 } else if self.check_content_word() || self.check_article() {
916 let np = self.parse_noun_phrase(false)?;
918 np_args.push(self.noun_phrase_to_term(&np));
919 if self.check(&TokenType::Comma) {
920 self.advance();
921 }
922 } else {
923 break;
924 }
925 }
926
927 let roles = self.build_gapped_roles(subject_term, &np_args, &pp_args, &template);
929
930 let modifiers = match (override_adverb, &template) {
932 (Some(adv), Some(tmpl)) => {
933 let mut mods: Vec<Symbol> = tmpl
935 .modifiers
936 .iter()
937 .filter(|m| !self.is_temporal_modifier(**m))
938 .cloned()
939 .collect();
940 mods.push(adv);
941 mods
942 }
943 (Some(adv), None) => vec![adv],
944 (None, Some(tmpl)) => tmpl.modifiers.clone(),
945 (None, None) => vec![],
946 };
947
948 Ok(self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
949 event_var,
950 verb: borrowed_verb,
951 roles: self.ctx.roles.alloc_slice(roles),
952 modifiers: self.ctx.syms.alloc_slice(modifiers),
953 suppress_existential,
954 world: None,
955 }))))
956 }
957
958 fn is_complete_clause(&self, expr: &LogicExpr<'a>) -> bool {
959 match expr {
960 LogicExpr::Atom(_) => false,
961 LogicExpr::Predicate { .. } => true,
962 LogicExpr::Quantifier { .. } => true,
963 LogicExpr::Modal { .. } => true,
964 LogicExpr::Temporal { .. } => true,
965 LogicExpr::Aspectual { .. } => true,
966 LogicExpr::BinaryOp { .. } => true,
967 LogicExpr::UnaryOp { .. } => true,
968 LogicExpr::Control { .. } => true,
969 LogicExpr::Presupposition { .. } => true,
970 LogicExpr::Categorical(_) => true,
971 LogicExpr::Relation(_) => true,
972 _ => true,
973 }
974 }
975
976 fn parse_disjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
979 let mut expr = self.parse_conjunction()?;
980
981 while self.check(&TokenType::Comma)
982 || self.check(&TokenType::Or)
983 || self.check(&TokenType::Iff)
984 {
985 if self.check(&TokenType::Comma) {
986 self.advance();
987 }
988 if !self.match_token(&[TokenType::Or, TokenType::Iff]) {
989 break;
990 }
991 let operator = self.previous().kind.clone();
992 self.current_island += 1;
993
994 let saved_pos = self.current;
995 let standard_attempt = self.try_parse(|p| p.parse_conjunction());
996
997 let use_gapping = match &standard_attempt {
1000 Some(right) => {
1001 !self.is_complete_clause(right)
1002 && (self.check(&TokenType::Comma) || self.check_content_word())
1003 && operator != TokenType::Iff }
1005 None => operator != TokenType::Iff, };
1007
1008 if !use_gapping {
1009 if let Some(right) = standard_attempt {
1010 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1011 left: expr,
1012 op: operator,
1013 right,
1014 });
1015 }
1016 } else {
1017 self.current = saved_pos;
1018
1019 let borrowed_verb = self.extract_verb_from_expr(expr).ok_or(ParseError {
1020 kind: ParseErrorKind::GappingResolutionFailed,
1021 span: self.current_span(),
1022 })?;
1023
1024 let right = self.parse_gapped_clause(borrowed_verb)?;
1025
1026 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1027 left: expr,
1028 op: operator,
1029 right,
1030 });
1031 }
1032 }
1033
1034 Ok(expr)
1035 }
1036
1037 fn parse_conjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1040 let mut expr = self.parse_atom()?;
1041
1042 if self.check(&TokenType::Because) && !self.peek_next_is_string_literal() {
1045 self.advance();
1046 let cause = self.parse_atom()?;
1047 return Ok(self.ctx.exprs.alloc(LogicExpr::Causal {
1048 effect: expr,
1049 cause,
1050 }));
1051 }
1052
1053 while self.check(&TokenType::Comma) || self.check(&TokenType::And) {
1054 if self.check(&TokenType::Comma) {
1055 self.advance();
1056 }
1057 if !self.match_token(&[TokenType::And]) {
1058 break;
1059 }
1060 let operator = self.previous().kind.clone();
1061 self.current_island += 1;
1062
1063 let saved_pos = self.current;
1064 let standard_attempt = self.try_parse(|p| p.parse_atom());
1065
1066 let use_gapping = match &standard_attempt {
1069 Some(right) => {
1070 !self.is_complete_clause(right)
1071 && (self.check(&TokenType::Comma)
1072 || self.check_content_word()
1073 || self.check_preposition()
1074 || self.check_temporal_adverb()
1075 || self.check(&TokenType::Period)
1076 || self.is_at_end())
1077 }
1078 None => true,
1079 };
1080
1081 if !use_gapping {
1082 if let Some(right) = standard_attempt {
1083 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1084 left: expr,
1085 op: operator,
1086 right,
1087 });
1088 }
1089 } else {
1090 self.current = saved_pos;
1091
1092 let borrowed_verb = self.extract_verb_from_expr(expr).ok_or(ParseError {
1093 kind: ParseErrorKind::GappingResolutionFailed,
1094 span: self.current_span(),
1095 })?;
1096
1097 let right = self.parse_gapped_clause(borrowed_verb)?;
1098
1099 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1100 left: expr,
1101 op: operator,
1102 right,
1103 });
1104 }
1105 }
1106
1107 Ok(expr)
1108 }
1109
1110 fn parse_relative_clause(&mut self, gap_var: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
1111 if self.check_verb() {
1112 return self.parse_verb_phrase_for_restriction(gap_var);
1113 }
1114
1115 if self.check(&TokenType::Do) || self.check(&TokenType::Does) {
1117 self.advance(); let is_negated = self.check(&TokenType::Not);
1120 if is_negated {
1121 self.advance(); }
1123
1124 if self.check_verb() {
1125 let verb = self.consume_verb();
1126
1127 let roles = if self.check(&TokenType::Reflexive) {
1129 self.advance(); vec![
1131 (ThematicRole::Agent, Term::Variable(gap_var)),
1132 (ThematicRole::Theme, Term::Variable(gap_var)),
1133 ]
1134 } else if self.check_content_word() || self.check_article() {
1135 let obj = self.parse_noun_phrase(false)?;
1137 vec![
1138 (ThematicRole::Agent, Term::Variable(gap_var)),
1139 (ThematicRole::Theme, Term::Constant(obj.noun)),
1140 ]
1141 } else {
1142 vec![(ThematicRole::Agent, Term::Variable(gap_var))]
1144 };
1145
1146 let event_var = self.get_event_var();
1147 let suppress_existential = self.drs.in_conditional_antecedent();
1148 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1149 event_var,
1150 verb,
1151 roles: self.ctx.roles.alloc_slice(roles),
1152 modifiers: self.ctx.syms.alloc_slice(vec![]),
1153 suppress_existential,
1154 world: None,
1155 })));
1156
1157 if is_negated {
1158 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1159 op: TokenType::Not,
1160 operand: event,
1161 }));
1162 }
1163 return Ok(event);
1164 }
1165 }
1166
1167 if self.check_content_word() || self.check_article() {
1168 let rel_subject = self.parse_noun_phrase_for_relative()?;
1169
1170 let nested_relative = if matches!(self.peek().kind, TokenType::Article(_)) {
1171 let nested_var = self.next_var_name();
1172 Some((nested_var, self.parse_relative_clause(nested_var)?))
1173 } else {
1174 None
1175 };
1176
1177 if self.check_verb() {
1178 let verb = self.consume_verb();
1179
1180 let mut roles: Vec<(ThematicRole, Term<'a>)> = vec![
1181 (ThematicRole::Agent, Term::Constant(rel_subject.noun)),
1182 (ThematicRole::Theme, Term::Variable(gap_var)),
1183 ];
1184
1185 while self.check_to_preposition() {
1186 self.advance();
1187 if self.check_content_word() || self.check_article() {
1188 let recipient = self.parse_noun_phrase(false)?;
1189 roles.push((ThematicRole::Recipient, Term::Constant(recipient.noun)));
1190 }
1191 }
1192
1193 let event_var = self.get_event_var();
1194 let suppress_existential = self.drs.in_conditional_antecedent();
1195 let this_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1196 event_var,
1197 verb,
1198 roles: self.ctx.roles.alloc_slice(roles),
1199 modifiers: self.ctx.syms.alloc_slice(vec![]),
1200 suppress_existential,
1201 world: None,
1202 })));
1203
1204 if let Some((nested_var, nested_clause)) = nested_relative {
1205 let type_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
1206 name: rel_subject.noun,
1207 args: self.ctx.terms.alloc_slice([Term::Variable(nested_var)]),
1208 world: None,
1209 });
1210
1211 let inner = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1212 left: type_pred,
1213 op: TokenType::And,
1214 right: nested_clause,
1215 });
1216
1217 let combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1218 left: inner,
1219 op: TokenType::And,
1220 right: this_event,
1221 });
1222
1223 return Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
1224 kind: crate::ast::QuantifierKind::Existential,
1225 variable: nested_var,
1226 body: combined,
1227 island_id: self.current_island,
1228 }));
1229 }
1230
1231 return Ok(this_event);
1232 }
1233 }
1234
1235 if self.check_verb() {
1236 return self.parse_verb_phrase_for_restriction(gap_var);
1237 }
1238
1239 let unknown = self.interner.intern("?");
1240 Ok(self.ctx.exprs.alloc(LogicExpr::Atom(unknown)))
1241 }
1242
1243 fn check_ellipsis_auxiliary(&self) -> bool {
1244 matches!(
1245 self.peek().kind,
1246 TokenType::Does | TokenType::Do |
1247 TokenType::Can | TokenType::Could | TokenType::Would |
1248 TokenType::May | TokenType::Must | TokenType::Should
1249 )
1250 }
1251
1252 fn check_ellipsis_terminator(&self) -> bool {
1253 if self.is_at_end() || self.check(&TokenType::Period) {
1254 return true;
1255 }
1256 if self.check_content_word() {
1257 let word = self.interner.resolve(self.peek().lexeme).to_lowercase();
1258 return word == "too" || word == "also";
1259 }
1260 false
1261 }
1262
1263 fn try_parse_ellipsis(&mut self) -> Option<ParseResult<&'a LogicExpr<'a>>> {
1264 if self.last_event_template.is_none() {
1266 return None;
1267 }
1268
1269 let saved_pos = self.current;
1270
1271 let subject_sym = if matches!(self.peek().kind, TokenType::ProperName(_)) {
1274 if let TokenType::ProperName(sym) = self.advance().kind {
1275 sym
1276 } else {
1277 self.current = saved_pos;
1278 return None;
1279 }
1280 } else if self.check_pronoun() {
1281 let token = self.advance().clone();
1282 if let TokenType::Pronoun { gender, number, .. } = token.kind {
1283 match self.resolve_pronoun(gender, number) {
1284 Ok(resolved) => match resolved {
1285 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
1286 },
1287 Err(e) => return Some(Err(e)),
1288 }
1289 } else {
1290 self.current = saved_pos;
1291 return None;
1292 }
1293 } else {
1294 return None;
1295 };
1296
1297 if !self.check_ellipsis_auxiliary() {
1299 self.current = saved_pos;
1300 return None;
1301 }
1302 let aux_token = self.advance().kind.clone();
1303
1304 let is_negated = self.match_token(&[TokenType::Not]);
1306
1307 if !self.check_ellipsis_terminator() {
1309 self.current = saved_pos;
1310 return None;
1311 }
1312
1313 if self.check_content_word() {
1315 let word = self.interner.resolve(self.peek().lexeme).to_lowercase();
1316 if word == "too" || word == "also" {
1317 self.advance();
1318 }
1319 }
1320
1321 let template = self.last_event_template.clone().unwrap();
1323 let event_var = self.get_event_var();
1324 let suppress_existential = self.drs.in_conditional_antecedent();
1325
1326 let mut roles: Vec<(ThematicRole, Term<'a>)> = vec![
1328 (ThematicRole::Agent, Term::Constant(subject_sym))
1329 ];
1330 roles.extend(template.non_agent_roles.iter().cloned());
1331
1332 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1333 event_var,
1334 verb: template.verb,
1335 roles: self.ctx.roles.alloc_slice(roles),
1336 modifiers: self.ctx.syms.alloc_slice(template.modifiers.clone()),
1337 suppress_existential,
1338 world: None,
1339 })));
1340
1341 let with_modal = match aux_token {
1343 TokenType::Can | TokenType::Could => {
1344 let vector = self.token_to_vector(&aux_token);
1345 self.ctx.modal(vector, neo_event)
1346 }
1347 TokenType::Would | TokenType::May | TokenType::Must | TokenType::Should => {
1348 let vector = self.token_to_vector(&aux_token);
1349 self.ctx.modal(vector, neo_event)
1350 }
1351 _ => neo_event,
1352 };
1353
1354 let result = if is_negated {
1356 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1357 op: TokenType::Not,
1358 operand: with_modal,
1359 })
1360 } else {
1361 with_modal
1362 };
1363
1364 Some(Ok(result))
1365 }
1366}
1367
1368impl<'a, 'ctx, 'int> Parser<'a, 'ctx, 'int> {
1370 fn extract_neo_event_verb(&self, expr: &LogicExpr<'a>) -> Option<Symbol> {
1372 match expr {
1373 LogicExpr::NeoEvent(data) => Some(data.verb),
1374 LogicExpr::Quantifier { body, .. } => self.extract_neo_event_verb(body),
1375 LogicExpr::BinaryOp { left, right, .. } => {
1376 self.extract_neo_event_verb(left)
1377 .or_else(|| self.extract_neo_event_verb(right))
1378 }
1379 LogicExpr::Temporal { body, .. } => self.extract_neo_event_verb(body),
1380 LogicExpr::Aspectual { body, .. } => self.extract_neo_event_verb(body),
1381 _ => None,
1382 }
1383 }
1384
1385 fn build_gapped_roles(
1388 &self,
1389 subject_term: Term<'a>,
1390 np_args: &[Term<'a>],
1391 pp_args: &[(Symbol, Term<'a>)],
1392 template: &Option<EventTemplate<'a>>,
1393 ) -> Vec<(ThematicRole, Term<'a>)> {
1394 let mut roles = vec![(ThematicRole::Agent, subject_term)];
1395
1396 match template {
1397 Some(tmpl) => {
1398 let template_roles = &tmpl.non_agent_roles;
1399
1400 let np_template_roles: Vec<_> = template_roles
1402 .iter()
1403 .filter(|(r, _)| {
1404 matches!(
1405 r,
1406 ThematicRole::Theme | ThematicRole::Recipient | ThematicRole::Patient
1407 )
1408 })
1409 .collect();
1410
1411 let pp_template_roles: Vec<_> = template_roles
1412 .iter()
1413 .filter(|(r, _)| {
1414 matches!(
1415 r,
1416 ThematicRole::Goal
1417 | ThematicRole::Source
1418 | ThematicRole::Location
1419 | ThematicRole::Instrument
1420 )
1421 })
1422 .collect();
1423
1424 match (np_template_roles.len(), np_args.len()) {
1426 (0, 0) => {} (_, 0) => {
1428 for (role, term) in &np_template_roles {
1430 roles.push((*role, term.clone()));
1431 }
1432 }
1433 (n, 1) if n > 0 => {
1434 for (role, term) in np_template_roles.iter().take(n - 1) {
1436 roles.push((*role, term.clone()));
1437 }
1438 if let Some((last_role, _)) = np_template_roles.last() {
1439 roles.push((*last_role, np_args[0].clone()));
1440 }
1441 }
1442 (n, m) if m == n => {
1443 for ((role, _), arg) in np_template_roles.iter().zip(np_args.iter()) {
1445 roles.push((*role, arg.clone()));
1446 }
1447 }
1448 (_, _) => {
1449 for (i, arg) in np_args.iter().enumerate() {
1451 let role = np_template_roles
1452 .get(i)
1453 .map(|(r, _)| *r)
1454 .unwrap_or(ThematicRole::Theme);
1455 roles.push((role, arg.clone()));
1456 }
1457 }
1458 }
1459
1460 if pp_args.is_empty() {
1462 for (role, term) in &pp_template_roles {
1464 roles.push((*role, term.clone()));
1465 }
1466 } else {
1467 for (prep, term) in pp_args {
1469 let role = self.preposition_to_role(*prep);
1470 roles.push((role, term.clone()));
1471 }
1472 }
1473 }
1474 None => {
1475 for arg in np_args {
1477 roles.push((ThematicRole::Theme, arg.clone()));
1478 }
1479 for (prep, term) in pp_args {
1480 let role = self.preposition_to_role(*prep);
1481 roles.push((role, term.clone()));
1482 }
1483 }
1484 }
1485 roles
1486 }
1487
1488 fn preposition_to_role(&self, prep: Symbol) -> ThematicRole {
1490 let prep_str = self.interner.resolve(prep).to_lowercase();
1491 match prep_str.as_str() {
1492 "to" | "toward" | "towards" => ThematicRole::Goal,
1493 "from" => ThematicRole::Source,
1494 "in" | "on" | "at" => ThematicRole::Location,
1495 "with" | "by" => ThematicRole::Instrument,
1496 _ => ThematicRole::Location, }
1498 }
1499
1500 fn is_temporal_modifier(&self, sym: Symbol) -> bool {
1502 let s = self.interner.resolve(sym).to_lowercase();
1503 matches!(
1504 s.as_str(),
1505 "yesterday" | "today" | "tomorrow" | "now" | "then" | "past" | "future"
1506 )
1507 }
1508}