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) || self.check(&TokenType::Assign) {
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(&TokenType::While) {
124 self.advance(); let condition = self.parse_sentence()?;
126 if self.check(&TokenType::Comma) {
127 self.advance();
128 }
129 let consequent = self.parse_sentence()?;
130 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
131 left: condition,
132 op: TokenType::Implies,
133 right: consequent,
134 }));
135 }
136
137 if self.check(&TokenType::When) {
140 let saved = self.current;
141 let mut found_comma = false;
142 for i in (self.current + 1)..self.tokens.len() {
143 match &self.tokens[i].kind {
144 TokenType::Comma => { found_comma = true; break; }
145 TokenType::Period => break,
146 _ => {}
147 }
148 }
149 if found_comma {
150 self.advance(); let condition = self.parse_sentence()?;
152 if self.check(&TokenType::Comma) {
153 self.advance();
154 }
155 let consequent = self.parse_sentence()?;
156 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
157 left: condition,
158 op: TokenType::Implies,
159 right: consequent,
160 }));
161 }
162 self.current = saved;
163 }
164
165 if self.check_content_word() {
167 let word = self.interner.resolve(self.peek().lexeme).to_string();
168 if word == "Whenever" || word == "whenever" {
169 self.advance(); let condition = self.parse_sentence()?;
171 if self.check(&TokenType::Comma) {
172 self.advance();
173 }
174 let consequent = self.parse_sentence()?;
175 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
176 left: condition,
177 op: TokenType::Implies,
178 right: consequent,
179 }));
180 }
181 }
182
183 if self.check_wh_word() {
184 return self.parse_wh_question();
185 }
186
187 if self.check(&TokenType::Does)
188 || self.check(&TokenType::Do)
189 || self.check(&TokenType::Is)
190 || self.check(&TokenType::Are)
191 || self.check(&TokenType::Was)
192 || self.check(&TokenType::Were)
193 || self.check(&TokenType::Would)
194 || self.check(&TokenType::Could)
195 || self.check(&TokenType::Can)
196 {
197 return self.parse_yes_no_question();
198 }
199
200 if self.match_token(&[TokenType::If]) {
201 return self.parse_conditional();
202 }
203
204 if self.match_token(&[TokenType::Either]) {
207 return self.parse_either_or();
208 }
209
210 if self.check_modal() {
211 self.advance();
212 return self.parse_modal();
213 }
214
215 if self.match_token(&[TokenType::Not]) {
216 self.negative_depth += 1;
217 let inner = self.parse_sentence()?;
218 self.negative_depth -= 1;
219 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
220 op: TokenType::Not,
221 operand: inner,
222 }));
223 }
224
225 if self.check(&TokenType::Both) {
229 let next_is_clausal = if self.current + 1 < self.tokens.len() {
231 matches!(self.tokens[self.current + 1].kind,
232 TokenType::All | TokenType::No | TokenType::Some | TokenType::Any
233 | TokenType::Most | TokenType::Few | TokenType::Many
234 | TokenType::Cardinal(_) | TokenType::AtLeast(_) | TokenType::AtMost(_)
235 | TokenType::Article(_)
236 )
237 } else {
238 false
239 };
240 if next_is_clausal {
241 self.advance(); let first = self.parse_atom()?;
243 if self.check(&TokenType::And) {
244 self.advance(); }
246 let second = self.parse_atom()?;
247 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
248 left: first,
249 op: TokenType::And,
250 right: second,
251 }));
252 }
253 }
254
255 {
261 let temporal_op = match &self.peek().kind {
262 TokenType::Adverb(sym) | TokenType::ScopalAdverb(sym) | TokenType::TemporalAdverb(sym) => {
263 let resolved = self.interner.resolve(*sym).to_string();
264 match resolved.as_str() {
265 "Always" => Some(crate::ast::logic::TemporalOperator::Always),
266 "Eventually" => Some(crate::ast::logic::TemporalOperator::Eventually),
267 "Next" => Some(crate::ast::logic::TemporalOperator::Next),
268 _ => None,
269 }
270 }
271 TokenType::Adjective(sym) => {
273 let resolved = self.interner.resolve(*sym).to_string();
274 if resolved == "Next" {
275 Some(crate::ast::logic::TemporalOperator::Next)
276 } else {
277 None
278 }
279 }
280 _ => None,
281 };
282 if let Some(op) = temporal_op {
283 self.advance(); if self.check(&TokenType::Comma) {
286 self.advance();
287 }
288 let body = self.parse_sentence()?;
289 return Ok(self.ctx.exprs.alloc(LogicExpr::Temporal {
290 operator: op,
291 body,
292 }));
293 }
294 }
295 if self.check(&TokenType::Never) {
297 self.advance(); if self.check(&TokenType::Comma) {
300 self.advance();
301 }
302 let body = self.parse_sentence()?;
303 let negated = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
304 op: TokenType::Not,
305 operand: body,
306 });
307 return Ok(self.ctx.exprs.alloc(LogicExpr::Temporal {
308 operator: crate::ast::logic::TemporalOperator::Always,
309 body: negated,
310 }));
311 }
312
313 if self.check_preposition_is("after") || self.check_preposition_is("After") {
318 self.advance(); let is_bare_noun_comma = self.current + 1 < self.tokens.len()
323 && matches!(self.tokens[self.current + 1].kind, TokenType::Comma)
324 && (self.check_content_word()
325 || matches!(self.peek().kind, TokenType::Performative(_)));
326 let antecedent = if is_bare_noun_comma {
327 let noun = match self.advance().kind.clone() {
328 TokenType::Performative(s) => s,
329 TokenType::Noun(s) | TokenType::Adjective(s) | TokenType::ProperName(s) => s,
330 TokenType::Verb { lemma, .. } => lemma,
331 _ => return Err(crate::error::ParseError {
332 kind: crate::error::ParseErrorKind::ExpectedContentWord { found: self.peek().kind.clone() },
333 span: self.current_span(),
334 }),
335 };
336 self.ctx.exprs.alloc(LogicExpr::Atom(noun))
337 } else {
338 self.parse_sentence()?
339 };
340
341 if self.check(&TokenType::Comma) {
342 self.advance();
343 }
344 let consequent = self.parse_sentence()?;
345 let consequent = self.try_wrap_bounded_delay(consequent);
346 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
347 left: antecedent,
348 op: TokenType::Implies,
349 right: consequent,
350 }));
351 }
352 if self.check_preposition_is("before") || self.check_preposition_is("Before") {
353 self.advance(); let first_clause = self.parse_sentence()?;
355 if self.check(&TokenType::Comma) {
356 self.advance();
357 }
358 let second_clause = self.parse_sentence()?;
359 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
360 left: second_clause,
361 op: TokenType::Implies,
362 right: first_clause,
363 }));
364 }
365
366 self.parse_disjunction()
367 }
368
369 fn check_wh_word(&self) -> bool {
370 if matches!(
371 self.peek().kind,
372 TokenType::Who
373 | TokenType::What
374 | TokenType::Where
375 | TokenType::When
376 | TokenType::Why
377 ) {
378 return true;
379 }
380 if self.check_preposition() && self.current + 1 < self.tokens.len() {
381 matches!(
382 self.tokens[self.current + 1].kind,
383 TokenType::Who
384 | TokenType::What
385 | TokenType::Where
386 | TokenType::When
387 | TokenType::Why
388 )
389 } else {
390 false
391 }
392 }
393
394 fn parse_conditional(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
395 let is_counterfactual = self.is_counterfactual_context();
396
397 self.drs.enter_box(BoxType::ConditionalAntecedent);
399 let mut antecedent = self.parse_counterfactual_antecedent()?;
400
401 while self.check(&TokenType::And) {
403 self.advance(); let second = self.parse_counterfactual_antecedent()?;
405 antecedent = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
406 left: antecedent,
407 op: TokenType::And,
408 right: second,
409 });
410 }
411 self.drs.exit_box();
412
413 if self.check(&TokenType::Comma) {
414 self.advance();
415 }
416
417 if self.check(&TokenType::Then) {
418 self.advance();
419 }
420
421 self.drs.enter_box(BoxType::ConditionalConsequent);
423 let consequent = self.parse_counterfactual_consequent()?;
424 self.drs.exit_box();
425
426 let universal_refs = self.drs.get_universal_referents();
428
429 let conditional = if is_counterfactual {
431 self.ctx.exprs.alloc(LogicExpr::Counterfactual {
432 antecedent,
433 consequent,
434 })
435 } else {
436 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
437 left: antecedent,
438 op: TokenType::If,
439 right: consequent,
440 })
441 };
442
443 let mut result = conditional;
445 for var in universal_refs.into_iter().rev() {
446 result = self.ctx.exprs.alloc(LogicExpr::Quantifier {
447 kind: QuantifierKind::Universal,
448 variable: var,
449 body: result,
450 island_id: self.current_island,
451 });
452 }
453
454 Ok(result)
455 }
456
457 fn parse_either_or(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
462 let start_pos = self.current;
464
465 if let TokenType::ProperName(name1) = self.peek().kind {
468 self.advance(); if self.check(&TokenType::Or) {
471 self.advance(); if let TokenType::ProperName(name2) = self.peek().kind {
474 self.advance(); let is_copula = matches!(
478 self.peek().kind,
479 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
480 );
481 if is_copula {
482 self.advance(); let is_negated = self.match_token(&[TokenType::Not]);
486
487 if let TokenType::Adjective(adj) = self.peek().kind {
489 self.advance(); let pred1 = self.ctx.exprs.alloc(LogicExpr::Predicate {
493 name: adj,
494 args: self.ctx.terms.alloc_slice(vec![
495 Term::Constant(name1)
496 ]),
497 world: None,
498 });
499 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
500 name: adj,
501 args: self.ctx.terms.alloc_slice(vec![
502 Term::Constant(name2)
503 ]),
504 world: None,
505 });
506
507 let left = if is_negated {
509 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
510 op: TokenType::Not,
511 operand: pred1,
512 })
513 } else {
514 pred1
515 };
516 let right = if is_negated {
517 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
518 op: TokenType::Not,
519 operand: pred2,
520 })
521 } else {
522 pred2
523 };
524
525 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
526 left,
527 op: TokenType::Or,
528 right,
529 }));
530 }
531 }
532 }
533 }
534
535 self.current = start_pos;
537 }
538
539 self.drs.enter_box(BoxType::Disjunct);
542 let left = self.parse_conjunction()?;
543 self.drs.exit_box();
544
545 if !self.check(&TokenType::Or) {
546 return Err(ParseError {
547 kind: ParseErrorKind::ExpectedKeyword { keyword: "or".to_string() },
548 span: self.current_span(),
549 });
550 }
551 self.advance(); self.drs.enter_box(BoxType::Disjunct);
555 let right = self.parse_conjunction()?;
556 self.drs.exit_box();
557
558 Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
559 left,
560 op: TokenType::Or,
561 right,
562 }))
563 }
564
565 fn is_counterfactual_context(&self) -> bool {
566 for i in 0..5 {
567 if self.current + i >= self.tokens.len() {
568 break;
569 }
570 let token = &self.tokens[self.current + i];
571 if matches!(token.kind, TokenType::Were | TokenType::Had) {
572 return true;
573 }
574 if matches!(token.kind, TokenType::Comma | TokenType::Period) {
575 break;
576 }
577 }
578 false
579 }
580
581 fn parse_counterfactual_antecedent(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
582 let unknown = self.interner.intern("?");
583 if self.check_content_word() || self.check_pronoun() || self.check_article() {
584 if self.check_pronoun() {
587 let token = self.peek();
588 let token_text = self.interner.resolve(token.lexeme);
589 if token_text.eq_ignore_ascii_case("it") {
590 if self.current + 1 < self.tokens.len() {
592 if let TokenType::Verb { lemma, time, .. } = &self.tokens[self.current + 1].kind {
594 let lemma_str = self.interner.resolve(*lemma);
595 if Lexer::is_weather_verb(lemma_str) {
596 let verb = *lemma;
597 let verb_time = *time;
598 self.advance(); self.advance(); let event_var = self.get_event_var();
602
603 let suppress_existential = self.drs.in_conditional_antecedent();
606
607 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
608 event_var,
609 verb,
610 roles: self.ctx.roles.alloc_slice(vec![]),
611 modifiers: self.ctx.syms.alloc_slice(vec![]),
612 suppress_existential,
613 world: None,
614 })));
615
616 while self.check(&TokenType::And) || self.check(&TokenType::Or) {
619 let is_disjunction = self.check(&TokenType::Or);
620 self.advance(); if let TokenType::Verb { lemma: lemma2, .. } = &self.peek().kind.clone() {
623 let lemma2_str = self.interner.resolve(*lemma2);
624 if Lexer::is_weather_verb(lemma2_str) {
625 let verb2 = *lemma2;
626 self.advance(); let neo_event2 = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
630 event_var, verb: verb2,
632 roles: self.ctx.roles.alloc_slice(vec![]),
633 modifiers: self.ctx.syms.alloc_slice(vec![]),
634 suppress_existential,
635 world: None,
636 })));
637
638 let op = if is_disjunction { TokenType::Or } else { TokenType::And };
639 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
640 left: result,
641 op,
642 right: neo_event2,
643 });
644 } else {
645 break; }
647 } else {
648 break;
649 }
650 }
651
652 return Ok(match verb_time {
653 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
654 operator: TemporalOperator::Past,
655 body: result,
656 }),
657 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
658 operator: TemporalOperator::Future,
659 body: result,
660 }),
661 _ => result,
662 });
663 }
664 }
665 else if self.current + 2 < self.tokens.len() {
667 let is_copula = matches!(
668 self.tokens[self.current + 1].kind,
669 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
670 );
671 if is_copula {
672 if let TokenType::Verb { lemma, .. } = &self.tokens[self.current + 2].kind {
673 let lemma_str = self.interner.resolve(*lemma);
674 if Lexer::is_weather_verb(lemma_str) {
675 let verb = *lemma;
676 let verb_time = if matches!(
677 self.tokens[self.current + 1].kind,
678 TokenType::Was | TokenType::Were
679 ) {
680 Time::Past
681 } else {
682 Time::Present
683 };
684 self.advance(); self.advance(); self.advance(); let event_var = self.get_event_var();
689 let suppress_existential = self.drs.in_conditional_antecedent();
692
693 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
694 event_var,
695 verb,
696 roles: self.ctx.roles.alloc_slice(vec![]),
697 modifiers: self.ctx.syms.alloc_slice(vec![]),
698 suppress_existential,
699 world: None,
700 })));
701
702 let with_aspect = self.ctx.exprs.alloc(LogicExpr::Aspectual {
704 operator: AspectOperator::Progressive,
705 body: neo_event,
706 });
707
708 return Ok(match verb_time {
709 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
710 operator: TemporalOperator::Past,
711 body: with_aspect,
712 }),
713 _ => with_aspect,
714 });
715 }
716 }
717 }
718 }
719 }
720 }
721 }
722
723 let (subject, subject_type_pred) = if self.check_pronoun() {
725 let token = self.advance().clone();
726 let token_text = self.interner.resolve(token.lexeme);
727 let resolved = if token_text.eq_ignore_ascii_case("i") {
729 self.interner.intern("Speaker")
730 } else if token_text.eq_ignore_ascii_case("you") {
731 self.interner.intern("Addressee")
732 } else if let TokenType::Pronoun { gender, number, .. } = token.kind {
733 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
734 match resolved_pronoun {
735 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
736 }
737 } else {
738 unknown
739 };
740 (resolved, None)
741 } else {
742 let np = self.parse_noun_phrase(true)?;
743
744 if np.definiteness == Some(Definiteness::Indefinite)
748 || np.definiteness == Some(Definiteness::Definite)
749 || np.definiteness == Some(Definiteness::Distal) {
750 let gender = Self::infer_noun_gender(self.interner.resolve(np.noun));
751 let number = if Self::is_plural_noun(self.interner.resolve(np.noun)) {
752 Number::Plural
753 } else {
754 Number::Singular
755 };
756
757 if np.definiteness == Some(Definiteness::Definite) || np.definiteness == Some(Definiteness::Distal) {
762 self.drs.introduce_referent_with_source(np.noun, np.noun, gender, number, crate::drs::ReferentSource::MainClause);
763 } else {
764 self.drs.introduce_referent(np.noun, np.noun, gender, number);
765 }
766
767 let type_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
769 name: np.noun,
770 args: self.ctx.terms.alloc_slice([Term::Variable(np.noun)]),
771 world: None,
772 });
773
774 (np.noun, Some(type_pred))
775 } else {
776 (np.noun, None)
778 }
779 };
780
781 let subject_term = if subject_type_pred.is_some() {
783 Term::Variable(subject)
784 } else {
785 Term::Constant(subject)
786 };
787
788 if self.check_presup_trigger() && self.is_followed_by_gerund() {
791 let presup_kind = match self.advance().kind {
792 TokenType::PresupTrigger(kind) => kind,
793 TokenType::Verb { lemma, .. } => {
794 let s = self.interner.resolve(lemma).to_lowercase();
795 crate::lexicon::lookup_presup_trigger(&s)
796 .expect("Lexicon mismatch: Verb flagged as trigger but lookup failed")
797 }
798 _ => panic!("Expected presupposition trigger"),
799 };
800 let np = NounPhrase {
801 noun: subject,
802 definiteness: None,
803 adjectives: &[],
804 possessor: None,
805 pps: &[],
806 superlative: None,
807 };
808 return self.parse_presupposition(&np, presup_kind);
809 }
810
811 if self.check(&TokenType::Were) {
812 self.advance();
813 let predicate = if self.check_pronoun() {
814 let token = self.advance().clone();
815 if let TokenType::Pronoun { gender, number, .. } = token.kind {
816 let token_text = self.interner.resolve(token.lexeme);
817 if token_text.eq_ignore_ascii_case("i") {
818 self.interner.intern("Speaker")
819 } else if token_text.eq_ignore_ascii_case("you") {
820 self.interner.intern("Addressee")
821 } else {
822 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
823 match resolved_pronoun {
824 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
825 }
826 }
827 } else {
828 unknown
829 }
830 } else {
831 self.consume_content_word()?
832 };
833 let be = self.interner.intern("Be");
834 let be_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
835 name: be,
836 args: self.ctx.terms.alloc_slice([
837 subject_term,
838 Term::Constant(predicate),
839 ]),
840 world: None,
841 });
842 return Ok(if let Some(type_pred) = subject_type_pred {
844 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
845 left: type_pred,
846 op: TokenType::And,
847 right: be_pred,
848 })
849 } else {
850 be_pred
851 });
852 }
853
854 if self.check(&TokenType::Had) {
855 self.advance();
856 let verb = self.consume_content_word()?;
857 let main_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
858 name: verb,
859 args: self.ctx.terms.alloc_slice([subject_term]),
860 world: None,
861 });
862
863 if self.check(&TokenType::Because) && !self.peek_next_is_string_literal() {
866 self.advance();
867 let cause = self.parse_atom()?;
868 let causal = self.ctx.exprs.alloc(LogicExpr::Causal {
869 effect: main_pred,
870 cause,
871 });
872 return Ok(if let Some(type_pred) = subject_type_pred {
874 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
875 left: type_pred,
876 op: TokenType::And,
877 right: causal,
878 })
879 } else {
880 causal
881 });
882 }
883
884 return Ok(if let Some(type_pred) = subject_type_pred {
886 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
887 left: type_pred,
888 op: TokenType::And,
889 right: main_pred,
890 })
891 } else {
892 main_pred
893 });
894 }
895
896 let verb_phrase = if subject_type_pred.is_some() {
899 self.parse_predicate_with_subject_as_var(subject)?
900 } else {
901 self.parse_predicate_with_subject(subject)?
902 };
903
904 return Ok(if let Some(type_pred) = subject_type_pred {
906 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
907 left: type_pred,
908 op: TokenType::And,
909 right: verb_phrase,
910 })
911 } else {
912 verb_phrase
913 });
914 }
915
916 self.parse_sentence()
917 }
918
919 fn parse_counterfactual_consequent(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
920 let unknown = self.interner.intern("?");
921 if self.check_content_word() || self.check_pronoun() {
922 if self.check_pronoun() {
925 let token = self.peek();
926 let token_text = self.interner.resolve(token.lexeme).to_lowercase();
927 if token_text == "its" {
928 if self.current + 1 < self.tokens.len() {
930 let next_token = &self.tokens[self.current + 1];
931 let next_str = self.interner.resolve(next_token.lexeme).to_lowercase();
932 if let Some(meta) = crate::lexicon::lookup_adjective_db(&next_str) {
933 if meta.features.contains(&crate::lexicon::Feature::Weather) {
934 return Err(ParseError {
935 kind: ParseErrorKind::GrammarError(
936 "Did you mean 'it's' (it is)? 'its' is a possessive pronoun.".to_string()
937 ),
938 span: self.current_span(),
939 });
940 }
941 }
942 }
943 }
944 }
945
946 if self.check_pronoun() {
948 let token_text = self.interner.resolve(self.peek().lexeme).to_lowercase();
949 if token_text == "it" {
950 if self.current + 2 < self.tokens.len() {
953 let next = &self.tokens[self.current + 1].kind;
954 if matches!(next, TokenType::Is | TokenType::Was | TokenType::Possessive) {
955 let adj_token = &self.tokens[self.current + 2];
957 let adj_sym = adj_token.lexeme;
958 let adj_str = self.interner.resolve(adj_sym).to_lowercase();
959 if let Some(meta) = crate::lexicon::lookup_adjective_db(&adj_str) {
960 if meta.features.contains(&crate::lexicon::Feature::Weather) {
961 self.advance(); self.advance(); self.advance(); let adj_lemma = self.interner.intern(meta.lemma);
967
968 let event_var = self.drs.get_last_event_referent(self.interner)
970 .unwrap_or_else(|| self.interner.intern("e"));
971
972 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::Predicate {
974 name: adj_lemma,
975 args: self.ctx.terms.alloc_slice([Term::Variable(event_var)]),
976 world: None,
977 });
978
979 while self.check(&TokenType::And) {
981 self.advance(); if self.check_content_word() {
983 let adj2_lexeme = self.peek().lexeme;
984 let adj2_str = self.interner.resolve(adj2_lexeme).to_lowercase();
985
986 if let Some(meta2) = crate::lexicon::lookup_adjective_db(&adj2_str) {
988 if meta2.features.contains(&crate::lexicon::Feature::Weather) {
989 self.advance(); let adj2_lemma = self.interner.intern(meta2.lemma);
992 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
993 name: adj2_lemma,
994 args: self.ctx.terms.alloc_slice([Term::Variable(event_var)]),
995 world: None,
996 });
997 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
998 left: result,
999 op: TokenType::And,
1000 right: pred2,
1001 });
1002 continue;
1003 }
1004 }
1005 }
1006 break;
1007 }
1008
1009 return Ok(result);
1010 }
1011 }
1012 }
1013 }
1014 }
1015 }
1016
1017 let subject = if self.check_pronoun() {
1018 let token = self.advance().clone();
1019 let token_text = self.interner.resolve(token.lexeme);
1020 if token_text.eq_ignore_ascii_case("i") {
1022 self.interner.intern("Speaker")
1023 } else if token_text.eq_ignore_ascii_case("you") {
1024 self.interner.intern("Addressee")
1025 } else if let TokenType::Pronoun { gender, number, .. } = token.kind {
1026 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
1027 match resolved_pronoun {
1028 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
1029 }
1030 } else {
1031 unknown
1032 }
1033 } else {
1034 self.parse_noun_phrase(true)?.noun
1035 };
1036
1037 if self.check(&TokenType::Would) {
1038 self.advance();
1039 if self.check_content_word() {
1040 let next_word = self.interner.resolve(self.peek().lexeme).to_lowercase();
1041 if next_word == "have" {
1042 self.advance();
1043 }
1044 }
1045 let verb = self.consume_content_word()?;
1046 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
1047 name: verb,
1048 args: self.ctx.terms.alloc_slice([Term::Constant(subject)]),
1049 world: None,
1050 }));
1051 }
1052
1053 return self.parse_predicate_with_subject(subject);
1054 }
1055
1056 self.parse_sentence()
1057 }
1058
1059 fn extract_verb_from_expr(&self, expr: &LogicExpr<'a>) -> Option<Symbol> {
1060 match expr {
1061 LogicExpr::NeoEvent(data) => Some(data.verb),
1063 LogicExpr::Control { verb, .. } => Some(*verb),
1065 LogicExpr::BinaryOp { left, right, .. } => {
1070 if let Some(verb) = self.extract_neo_event_verb(left) {
1072 return Some(verb);
1073 }
1074 if let Some(verb) = self.extract_neo_event_verb(right) {
1076 return Some(verb);
1077 }
1078 self.extract_verb_from_expr(left)
1080 .or_else(|| self.extract_verb_from_expr(right))
1081 }
1082 LogicExpr::Predicate { name, .. } => Some(*name),
1084 LogicExpr::Modal { operand, .. } => self.extract_verb_from_expr(operand),
1085 LogicExpr::Presupposition { assertion, .. } => self.extract_verb_from_expr(assertion),
1086 LogicExpr::Temporal { body, .. } => self.extract_verb_from_expr(body),
1087 LogicExpr::TemporalAnchor { body, .. } => self.extract_verb_from_expr(body),
1088 LogicExpr::Aspectual { body, .. } => self.extract_verb_from_expr(body),
1089 LogicExpr::Quantifier { body, .. } => self.extract_verb_from_expr(body),
1090 _ => None,
1091 }
1092 }
1093
1094 fn parse_gapped_clause(&mut self, borrowed_verb: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
1097 let subject = self.parse_noun_phrase(true)?;
1098
1099 if self.check(&TokenType::Comma) {
1100 self.advance();
1101 }
1102
1103 let subject_term = self.noun_phrase_to_term(&subject);
1104 let event_var = self.get_event_var();
1105 let suppress_existential = self.drs.in_conditional_antecedent();
1106
1107 let template = self.last_event_template.clone();
1109
1110 let mut np_args: Vec<Term<'a>> = Vec::new();
1112 let mut pp_args: Vec<(Symbol, Term<'a>)> = Vec::new();
1113 let mut override_adverb: Option<Symbol> = None;
1114
1115 loop {
1116 if self.check_temporal_adverb() {
1117 if let TokenType::TemporalAdverb(sym) = self.advance().kind {
1119 override_adverb = Some(sym);
1120 }
1121 } else if self.check_preposition() {
1122 let prep = if let TokenType::Preposition(sym) = self.advance().kind {
1124 sym
1125 } else {
1126 continue;
1127 };
1128 let np = self.parse_noun_phrase(false)?;
1129 pp_args.push((prep, self.noun_phrase_to_term(&np)));
1130 } else if self.check_content_word() || self.check_article() {
1131 let np = self.parse_noun_phrase(false)?;
1133 np_args.push(self.noun_phrase_to_term(&np));
1134 if self.check(&TokenType::Comma) {
1135 self.advance();
1136 }
1137 } else {
1138 break;
1139 }
1140 }
1141
1142 let roles = self.build_gapped_roles(subject_term, &np_args, &pp_args, &template);
1144
1145 let modifiers = match (override_adverb, &template) {
1147 (Some(adv), Some(tmpl)) => {
1148 let mut mods: Vec<Symbol> = tmpl
1150 .modifiers
1151 .iter()
1152 .filter(|m| !self.is_temporal_modifier(**m))
1153 .cloned()
1154 .collect();
1155 mods.push(adv);
1156 mods
1157 }
1158 (Some(adv), None) => vec![adv],
1159 (None, Some(tmpl)) => tmpl.modifiers.clone(),
1160 (None, None) => vec![],
1161 };
1162
1163 Ok(self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1164 event_var,
1165 verb: borrowed_verb,
1166 roles: self.ctx.roles.alloc_slice(roles),
1167 modifiers: self.ctx.syms.alloc_slice(modifiers),
1168 suppress_existential,
1169 world: None,
1170 }))))
1171 }
1172
1173 fn is_complete_clause(&self, expr: &LogicExpr<'a>) -> bool {
1174 match expr {
1175 LogicExpr::Atom(_) => false,
1176 LogicExpr::Predicate { .. } => true,
1177 LogicExpr::Quantifier { .. } => true,
1178 LogicExpr::Modal { .. } => true,
1179 LogicExpr::Temporal { .. } => true,
1180 LogicExpr::Aspectual { .. } => true,
1181 LogicExpr::BinaryOp { .. } => true,
1182 LogicExpr::UnaryOp { .. } => true,
1183 LogicExpr::Control { .. } => true,
1184 LogicExpr::Presupposition { .. } => true,
1185 LogicExpr::Categorical(_) => true,
1186 LogicExpr::Relation(_) => true,
1187 _ => true,
1188 }
1189 }
1190
1191 fn parse_disjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1194 let mut expr = self.parse_conjunction()?;
1195
1196 while self.check(&TokenType::Comma)
1197 || self.check(&TokenType::Or)
1198 || self.check(&TokenType::Iff)
1199 {
1200 if self.check(&TokenType::Comma) {
1201 self.advance();
1202 }
1203 if !self.match_token(&[TokenType::Or, TokenType::Iff]) {
1204 break;
1205 }
1206 let operator = self.previous().kind.clone();
1207 self.current_island += 1;
1208
1209 let saved_pos = self.current;
1210 let standard_attempt = self.try_parse(|p| p.parse_conjunction());
1211
1212 let use_gapping = match &standard_attempt {
1215 Some(right) => {
1216 !self.is_complete_clause(right)
1217 && (self.check(&TokenType::Comma) || self.check_content_word())
1218 && operator != TokenType::Iff }
1220 None => operator != TokenType::Iff, };
1222
1223 if !use_gapping {
1224 if let Some(right) = standard_attempt {
1225 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1226 left: expr,
1227 op: operator,
1228 right,
1229 });
1230 }
1231 } else {
1232 self.current = saved_pos;
1233
1234 let borrowed_verb = self.extract_verb_from_expr(expr).ok_or(ParseError {
1235 kind: ParseErrorKind::GappingResolutionFailed,
1236 span: self.current_span(),
1237 })?;
1238
1239 let right = self.parse_gapped_clause(borrowed_verb)?;
1240
1241 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1242 left: expr,
1243 op: operator,
1244 right,
1245 });
1246 }
1247 }
1248
1249 if self.check(&TokenType::Until) || self.check(&TokenType::Release) || self.check(&TokenType::WeakUntil) {
1254 let op = match self.peek().kind {
1255 TokenType::Release => crate::ast::logic::BinaryTemporalOp::Release,
1256 TokenType::WeakUntil => crate::ast::logic::BinaryTemporalOp::WeakUntil,
1257 _ => crate::ast::logic::BinaryTemporalOp::Until,
1258 };
1259 self.advance();
1260 let right = self.parse_conjunction()?;
1261 expr = self.ctx.exprs.alloc(LogicExpr::TemporalBinary {
1262 operator: op,
1263 left: expr,
1264 right,
1265 });
1266 }
1267
1268 let expr = self.try_wrap_bounded_delay(expr);
1270
1271 Ok(expr)
1272 }
1273
1274 fn parse_conjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1277 let mut expr = self.parse_atom()?;
1278
1279 if self.check(&TokenType::Because) && !self.peek_next_is_string_literal() {
1282 self.advance();
1283 let cause = self.parse_atom()?;
1284 return Ok(self.ctx.exprs.alloc(LogicExpr::Causal {
1285 effect: expr,
1286 cause,
1287 }));
1288 }
1289
1290 while self.check(&TokenType::Comma) || self.check(&TokenType::And) {
1291 if self.check(&TokenType::Comma) {
1292 self.advance();
1293 }
1294 if !self.match_token(&[TokenType::And]) {
1295 break;
1296 }
1297 let operator = self.previous().kind.clone();
1298 self.current_island += 1;
1299
1300 let saved_pos = self.current;
1301 let standard_attempt = self.try_parse(|p| p.parse_atom());
1302
1303 let use_gapping = match &standard_attempt {
1306 Some(right) => {
1307 !self.is_complete_clause(right)
1308 && (self.check(&TokenType::Comma)
1309 || self.check_content_word()
1310 || self.check_preposition()
1311 || self.check_temporal_adverb()
1312 || self.check(&TokenType::Period)
1313 || self.is_at_end())
1314 }
1315 None => true,
1316 };
1317
1318 if !use_gapping {
1319 if let Some(right) = standard_attempt {
1320 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1321 left: expr,
1322 op: operator,
1323 right,
1324 });
1325 }
1326 } else {
1327 self.current = saved_pos;
1328
1329 let borrowed_verb = self.extract_verb_from_expr(expr).ok_or(ParseError {
1330 kind: ParseErrorKind::GappingResolutionFailed,
1331 span: self.current_span(),
1332 })?;
1333
1334 let right = self.parse_gapped_clause(borrowed_verb)?;
1335
1336 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1337 left: expr,
1338 op: operator,
1339 right,
1340 });
1341 }
1342 }
1343
1344 Ok(expr)
1345 }
1346
1347 fn parse_relative_clause(&mut self, gap_var: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
1348 if self.check_verb() {
1349 return self.parse_verb_phrase_for_restriction(gap_var);
1350 }
1351
1352 if self.check(&TokenType::Do) || self.check(&TokenType::Does) {
1354 self.advance(); let is_negated = self.check(&TokenType::Not);
1357 if is_negated {
1358 self.advance(); }
1360
1361 if self.check_verb() {
1362 let verb = self.consume_verb();
1363
1364 let roles = if self.check(&TokenType::Reflexive) {
1366 self.advance(); vec![
1368 (ThematicRole::Agent, Term::Variable(gap_var)),
1369 (ThematicRole::Theme, Term::Variable(gap_var)),
1370 ]
1371 } else if self.check_content_word() || self.check_article() {
1372 let obj = self.parse_noun_phrase(false)?;
1374 vec![
1375 (ThematicRole::Agent, Term::Variable(gap_var)),
1376 (ThematicRole::Theme, Term::Constant(obj.noun)),
1377 ]
1378 } else {
1379 vec![(ThematicRole::Agent, Term::Variable(gap_var))]
1381 };
1382
1383 let event_var = self.get_event_var();
1384 let suppress_existential = self.drs.in_conditional_antecedent();
1385 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1386 event_var,
1387 verb,
1388 roles: self.ctx.roles.alloc_slice(roles),
1389 modifiers: self.ctx.syms.alloc_slice(vec![]),
1390 suppress_existential,
1391 world: None,
1392 })));
1393
1394 if is_negated {
1395 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1396 op: TokenType::Not,
1397 operand: event,
1398 }));
1399 }
1400 return Ok(event);
1401 }
1402 }
1403
1404 if self.check_content_word() || self.check_article() {
1405 let rel_subject = self.parse_noun_phrase_for_relative()?;
1406
1407 let nested_relative = if matches!(self.peek().kind, TokenType::Article(_)) {
1408 let nested_var = self.next_var_name();
1409 Some((nested_var, self.parse_relative_clause(nested_var)?))
1410 } else {
1411 None
1412 };
1413
1414 if self.check_verb() {
1415 let verb = self.consume_verb();
1416
1417 let mut roles: Vec<(ThematicRole, Term<'a>)> = vec![
1418 (ThematicRole::Agent, Term::Constant(rel_subject.noun)),
1419 (ThematicRole::Theme, Term::Variable(gap_var)),
1420 ];
1421
1422 while self.check_to_preposition() {
1423 self.advance();
1424 if self.check_content_word() || self.check_article() {
1425 let recipient = self.parse_noun_phrase(false)?;
1426 roles.push((ThematicRole::Recipient, Term::Constant(recipient.noun)));
1427 }
1428 }
1429
1430 let event_var = self.get_event_var();
1431 let suppress_existential = self.drs.in_conditional_antecedent();
1432 let this_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1433 event_var,
1434 verb,
1435 roles: self.ctx.roles.alloc_slice(roles),
1436 modifiers: self.ctx.syms.alloc_slice(vec![]),
1437 suppress_existential,
1438 world: None,
1439 })));
1440
1441 if let Some((nested_var, nested_clause)) = nested_relative {
1442 let type_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
1443 name: rel_subject.noun,
1444 args: self.ctx.terms.alloc_slice([Term::Variable(nested_var)]),
1445 world: None,
1446 });
1447
1448 let inner = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1449 left: type_pred,
1450 op: TokenType::And,
1451 right: nested_clause,
1452 });
1453
1454 let combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1455 left: inner,
1456 op: TokenType::And,
1457 right: this_event,
1458 });
1459
1460 return Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
1461 kind: crate::ast::QuantifierKind::Existential,
1462 variable: nested_var,
1463 body: combined,
1464 island_id: self.current_island,
1465 }));
1466 }
1467
1468 return Ok(this_event);
1469 }
1470 }
1471
1472 if self.check_verb() {
1473 return self.parse_verb_phrase_for_restriction(gap_var);
1474 }
1475
1476 let unknown = self.interner.intern("?");
1477 Ok(self.ctx.exprs.alloc(LogicExpr::Atom(unknown)))
1478 }
1479
1480 fn check_ellipsis_auxiliary(&self) -> bool {
1481 matches!(
1482 self.peek().kind,
1483 TokenType::Does | TokenType::Do |
1484 TokenType::Can | TokenType::Could | TokenType::Would |
1485 TokenType::May | TokenType::Must | TokenType::Should
1486 )
1487 }
1488
1489 fn check_ellipsis_terminator(&self) -> bool {
1490 if self.is_at_end() || self.check(&TokenType::Period) {
1491 return true;
1492 }
1493 if self.check_content_word() {
1494 let word = self.interner.resolve(self.peek().lexeme).to_lowercase();
1495 return word == "too" || word == "also";
1496 }
1497 false
1498 }
1499
1500 fn try_parse_ellipsis(&mut self) -> Option<ParseResult<&'a LogicExpr<'a>>> {
1501 if self.last_event_template.is_none() {
1503 return None;
1504 }
1505
1506 let saved_pos = self.current;
1507
1508 let subject_sym = if matches!(self.peek().kind, TokenType::ProperName(_)) {
1511 if let TokenType::ProperName(sym) = self.advance().kind {
1512 sym
1513 } else {
1514 self.current = saved_pos;
1515 return None;
1516 }
1517 } else if self.check_pronoun() {
1518 let token = self.advance().clone();
1519 if let TokenType::Pronoun { gender, number, .. } = token.kind {
1520 match self.resolve_pronoun(gender, number) {
1521 Ok(resolved) => match resolved {
1522 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
1523 },
1524 Err(e) => return Some(Err(e)),
1525 }
1526 } else {
1527 self.current = saved_pos;
1528 return None;
1529 }
1530 } else {
1531 return None;
1532 };
1533
1534 if !self.check_ellipsis_auxiliary() {
1536 self.current = saved_pos;
1537 return None;
1538 }
1539 let aux_token = self.advance().kind.clone();
1540
1541 let is_negated = self.match_token(&[TokenType::Not]);
1543
1544 if !self.check_ellipsis_terminator() {
1546 self.current = saved_pos;
1547 return None;
1548 }
1549
1550 if self.check_content_word() {
1552 let word = self.interner.resolve(self.peek().lexeme).to_lowercase();
1553 if word == "too" || word == "also" {
1554 self.advance();
1555 }
1556 }
1557
1558 let template = self.last_event_template.clone().unwrap();
1560 let event_var = self.get_event_var();
1561 let suppress_existential = self.drs.in_conditional_antecedent();
1562
1563 let mut roles: Vec<(ThematicRole, Term<'a>)> = vec![
1565 (ThematicRole::Agent, Term::Constant(subject_sym))
1566 ];
1567 roles.extend(template.non_agent_roles.iter().cloned());
1568
1569 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1570 event_var,
1571 verb: template.verb,
1572 roles: self.ctx.roles.alloc_slice(roles),
1573 modifiers: self.ctx.syms.alloc_slice(template.modifiers.clone()),
1574 suppress_existential,
1575 world: None,
1576 })));
1577
1578 let with_modal = match aux_token {
1580 TokenType::Can | TokenType::Could => {
1581 let vector = self.token_to_vector(&aux_token);
1582 self.ctx.modal(vector, neo_event)
1583 }
1584 TokenType::Would | TokenType::May | TokenType::Must | TokenType::Should => {
1585 let vector = self.token_to_vector(&aux_token);
1586 self.ctx.modal(vector, neo_event)
1587 }
1588 _ => neo_event,
1589 };
1590
1591 let result = if is_negated {
1593 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1594 op: TokenType::Not,
1595 operand: with_modal,
1596 })
1597 } else {
1598 with_modal
1599 };
1600
1601 Some(Ok(result))
1602 }
1603}
1604
1605impl<'a, 'ctx, 'int> Parser<'a, 'ctx, 'int> {
1607 fn extract_neo_event_verb(&self, expr: &LogicExpr<'a>) -> Option<Symbol> {
1609 match expr {
1610 LogicExpr::NeoEvent(data) => Some(data.verb),
1611 LogicExpr::Quantifier { body, .. } => self.extract_neo_event_verb(body),
1612 LogicExpr::BinaryOp { left, right, .. } => {
1613 self.extract_neo_event_verb(left)
1614 .or_else(|| self.extract_neo_event_verb(right))
1615 }
1616 LogicExpr::Temporal { body, .. } => self.extract_neo_event_verb(body),
1617 LogicExpr::Aspectual { body, .. } => self.extract_neo_event_verb(body),
1618 _ => None,
1619 }
1620 }
1621
1622 fn build_gapped_roles(
1625 &self,
1626 subject_term: Term<'a>,
1627 np_args: &[Term<'a>],
1628 pp_args: &[(Symbol, Term<'a>)],
1629 template: &Option<EventTemplate<'a>>,
1630 ) -> Vec<(ThematicRole, Term<'a>)> {
1631 let mut roles = vec![(ThematicRole::Agent, subject_term)];
1632
1633 match template {
1634 Some(tmpl) => {
1635 let template_roles = &tmpl.non_agent_roles;
1636
1637 let np_template_roles: Vec<_> = template_roles
1639 .iter()
1640 .filter(|(r, _)| {
1641 matches!(
1642 r,
1643 ThematicRole::Theme | ThematicRole::Recipient | ThematicRole::Patient
1644 )
1645 })
1646 .collect();
1647
1648 let pp_template_roles: Vec<_> = template_roles
1649 .iter()
1650 .filter(|(r, _)| {
1651 matches!(
1652 r,
1653 ThematicRole::Goal
1654 | ThematicRole::Source
1655 | ThematicRole::Location
1656 | ThematicRole::Instrument
1657 )
1658 })
1659 .collect();
1660
1661 match (np_template_roles.len(), np_args.len()) {
1663 (0, 0) => {} (_, 0) => {
1665 for (role, term) in &np_template_roles {
1667 roles.push((*role, term.clone()));
1668 }
1669 }
1670 (n, 1) if n > 0 => {
1671 for (role, term) in np_template_roles.iter().take(n - 1) {
1673 roles.push((*role, term.clone()));
1674 }
1675 if let Some((last_role, _)) = np_template_roles.last() {
1676 roles.push((*last_role, np_args[0].clone()));
1677 }
1678 }
1679 (n, m) if m == n => {
1680 for ((role, _), arg) in np_template_roles.iter().zip(np_args.iter()) {
1682 roles.push((*role, arg.clone()));
1683 }
1684 }
1685 (_, _) => {
1686 for (i, arg) in np_args.iter().enumerate() {
1688 let role = np_template_roles
1689 .get(i)
1690 .map(|(r, _)| *r)
1691 .unwrap_or(ThematicRole::Theme);
1692 roles.push((role, arg.clone()));
1693 }
1694 }
1695 }
1696
1697 if pp_args.is_empty() {
1699 for (role, term) in &pp_template_roles {
1701 roles.push((*role, term.clone()));
1702 }
1703 } else {
1704 for (prep, term) in pp_args {
1706 let role = self.preposition_to_role(*prep);
1707 roles.push((role, term.clone()));
1708 }
1709 }
1710 }
1711 None => {
1712 for arg in np_args {
1714 roles.push((ThematicRole::Theme, arg.clone()));
1715 }
1716 for (prep, term) in pp_args {
1717 let role = self.preposition_to_role(*prep);
1718 roles.push((role, term.clone()));
1719 }
1720 }
1721 }
1722 roles
1723 }
1724
1725 fn preposition_to_role(&self, prep: Symbol) -> ThematicRole {
1727 let prep_str = self.interner.resolve(prep).to_lowercase();
1728 match prep_str.as_str() {
1729 "to" | "toward" | "towards" => ThematicRole::Goal,
1730 "from" => ThematicRole::Source,
1731 "in" | "on" | "at" => ThematicRole::Location,
1732 "with" | "by" => ThematicRole::Instrument,
1733 _ => ThematicRole::Location, }
1735 }
1736
1737 fn is_temporal_modifier(&self, sym: Symbol) -> bool {
1739 let s = self.interner.resolve(sym).to_lowercase();
1740 matches!(
1741 s.as_str(),
1742 "yesterday" | "today" | "tomorrow" | "now" | "then" | "past" | "future"
1743 )
1744 }
1745}