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
32fn starts_clause_subject(kind: &TokenType) -> bool {
36 matches!(
37 kind,
38 TokenType::ProperName(_)
39 | TokenType::Noun(_)
40 | TokenType::Article(_)
41 | TokenType::Pronoun { .. }
42 | TokenType::All
43 | TokenType::No
44 | TokenType::Some
45 | TokenType::Any
46 | TokenType::Most
47 | TokenType::Few
48 | TokenType::Many
49 | TokenType::Cardinal(_)
50 | TokenType::Number(_)
51 )
52}
53
54struct OfEntity<'a> {
61 sym: Symbol,
62 is_var: bool,
63 term: Term<'a>,
64 restrictor: Option<&'a LogicExpr<'a>>,
65}
66
67pub trait ClauseParsing<'a, 'ctx, 'int> {
72 fn parse_sentence(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
74 fn parse_conditional(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
76 fn parse_either_or(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
78 fn parse_disjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
80 fn parse_conjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
82 fn extract_copular_subject(&self, expr: &'a LogicExpr<'a>) -> Option<Symbol>;
84 fn try_parse_copular_predicate(&mut self, subject: Symbol) -> ParseResult<Option<&'a LogicExpr<'a>>>;
86 fn parse_relative_clause(&mut self, gap_var: Symbol) -> ParseResult<&'a LogicExpr<'a>>;
88 fn parse_gapped_clause(&mut self, borrowed_verb: Symbol) -> ParseResult<&'a LogicExpr<'a>>;
90 fn parse_counterfactual_antecedent(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
92 fn parse_counterfactual_consequent(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
94 fn check_wh_word(&self) -> bool;
96 fn is_counterfactual_context(&self) -> bool;
98 fn is_complete_clause(&self, expr: &LogicExpr<'a>) -> bool;
100 fn extract_verb_from_expr(&self, expr: &LogicExpr<'a>) -> Option<Symbol>;
102 fn try_parse_imperative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
106 fn clause_has_later_finite_verb(&self, from: usize) -> bool;
111 fn is_reduced_relative_verb(&self, vp: usize) -> bool;
115 fn try_parse_cleft(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
118 fn try_parse_exclamative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
121 fn try_parse_optative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
124 fn try_parse_correlative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
127 fn try_parse_of_pair_xor(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
130 fn try_parse_fronted_temporal_adjunct(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
133 fn try_parse_inverted_conditional(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>>;
137 fn try_parse_ellipsis(&mut self) -> Option<ParseResult<&'a LogicExpr<'a>>>;
139 fn check_ellipsis_auxiliary(&self) -> bool;
141 fn check_ellipsis_terminator(&self) -> bool;
143}
144
145impl<'a, 'ctx, 'int> ClauseParsing<'a, 'ctx, 'int> for Parser<'a, 'ctx, 'int> {
146 fn try_parse_imperative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
147 let start = self.current;
148 let mut negated = false;
149 let mut agent_name = "Addressee";
152
153 if self.check(&TokenType::Let) {
154 let n1 = self.current + 1;
156 if n1 >= self.tokens.len() {
157 return Ok(None);
158 }
159 let next = &self.tokens[n1];
160 let next_text = self.interner.resolve(next.lexeme);
161 let is_lets = matches!(next.kind, TokenType::Possessive)
162 || next_text.eq_ignore_ascii_case("us")
163 || next_text.eq_ignore_ascii_case("'s")
164 || next_text.eq_ignore_ascii_case("s");
165 if !is_lets {
166 return Ok(None);
167 }
168 self.advance(); self.advance(); agent_name = "Us";
171 } else if self.check(&TokenType::Do) {
172 let n1 = self.current + 1;
174 if n1 < self.tokens.len() && matches!(self.tokens[n1].kind, TokenType::Not) {
175 self.advance(); self.advance(); negated = true;
178 } else {
179 return Ok(None);
181 }
182 }
183
184 if let TokenType::ProperName(sym) = self.peek().kind {
191 let lemma = self.interner.resolve(sym).to_lowercase();
192 if crate::lexicon::is_base_verb(&lemma)
193 && !self.clause_has_later_finite_verb(self.current + 1)
194 {
195 let class = crate::lexicon::lookup_verb_class(&lemma);
196 self.tokens[self.current].kind = TokenType::Verb {
197 lemma: sym,
198 time: Time::Present,
199 aspect: crate::lexicon::Aspect::Simple,
200 class,
201 };
202 }
203 }
204
205 if !self.check_verb() {
209 self.current = start;
210 return Ok(None);
211 }
212
213 if self.clause_has_later_finite_verb(self.current + 1) {
216 self.current = start;
217 return Ok(None);
218 }
219
220 let agent = self.interner.intern(agent_name);
221 let core = self.parse_predicate_with_subject(agent)?;
222 let action = if negated {
223 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
224 op: TokenType::Not,
225 operand: core,
226 })
227 } else {
228 core
229 };
230 Ok(Some(self.ctx.exprs.alloc(LogicExpr::Imperative { action })))
231 }
232
233 fn clause_has_later_finite_verb(&self, from: usize) -> bool {
234 let mut j = from;
235 while j < self.tokens.len() {
236 if matches!(self.tokens[j].kind, TokenType::Verb { .. })
244 && self.is_reduced_relative_verb(j)
245 {
246 let after = j + 1;
247 if matches!(
248 self.tokens.get(after).map(|t| &t.kind),
249 Some(TokenType::Preposition(_))
250 ) {
251 j = after + 1;
252 } else {
253 j = after;
254 }
255 continue;
256 }
257 match self.tokens[j].kind {
258 TokenType::Period | TokenType::EOF | TokenType::Exclamation => return false,
259 TokenType::Verb { .. }
260 | TokenType::Auxiliary(_)
261 | TokenType::Is
262 | TokenType::Are
263 | TokenType::Was
264 | TokenType::Were
265 | TokenType::Do
266 | TokenType::Does => return true,
267 _ => {
268 let lex = self.interner.resolve(self.tokens[j].lexeme).to_lowercase();
271 if matches!(
272 lex.as_str(),
273 "has" | "have" | "had" | "is" | "are" | "was" | "were"
274 | "do" | "does" | "did" | "will" | "would" | "can"
275 | "could" | "should" | "shall" | "may" | "might" | "must"
276 ) {
277 return true;
278 }
279 }
280 }
281 j += 1;
282 }
283 false
284 }
285
286 fn is_reduced_relative_verb(&self, vp: usize) -> bool {
295 if vp == 0 {
296 return false;
297 }
298 let subj = vp - 1;
299 if !matches!(
300 self.tokens[subj].kind,
301 TokenType::ProperName(_) | TokenType::Pronoun { .. }
302 ) {
303 return false;
304 }
305 if subj == 0 {
306 return false;
307 }
308 let head = subj - 1;
310 if !matches!(
311 self.tokens[head].kind,
312 TokenType::Noun(_)
313 | TokenType::CalendarUnit(_)
314 | TokenType::Ambiguous { .. }
315 ) {
316 return false;
317 }
318 let mut k = head;
322 loop {
323 match self.tokens[k].kind {
324 TokenType::Article(_)
325 | TokenType::Possessive
326 | TokenType::All
327 | TokenType::Some
328 | TokenType::No
329 | TokenType::Any
330 | TokenType::Most
331 | TokenType::Few
332 | TokenType::Many => return true,
333 TokenType::Noun(_)
334 | TokenType::CalendarUnit(_)
335 | TokenType::Adjective(_)
336 | TokenType::Ambiguous { .. } => {
337 if k == 0 {
338 return false;
339 }
340 k -= 1;
341 }
342 _ => return false,
343 }
344 }
345 }
346
347 fn try_parse_cleft(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
348 let start = self.current;
349 if !self.interner.resolve(self.peek().lexeme).eq_ignore_ascii_case("it") {
351 return Ok(None);
352 }
353 if self.current + 1 >= self.tokens.len()
354 || !matches!(self.tokens[self.current + 1].kind, TokenType::Is | TokenType::Was)
355 {
356 return Ok(None);
357 }
358 self.advance(); self.advance(); let focus_np = match self.parse_noun_phrase(false) {
363 Ok(np) => np,
364 Err(_) => {
365 self.current = start;
366 return Ok(None);
367 }
368 };
369 if !self.check(&TokenType::Who) && !self.check(&TokenType::That) {
370 self.current = start;
371 return Ok(None);
372 }
373 self.advance(); let focus_sym = focus_np.noun;
376 let core = self.parse_predicate_with_subject(focus_sym)?;
379
380 let z = self.next_var_name();
382 let core_z = self.substitute_constant_with_var_sym(core, focus_sym, z)?;
383 let identity = self.ctx.exprs.alloc(LogicExpr::Identity {
384 left: self.ctx.terms.alloc(Term::Variable(z)),
385 right: self.ctx.terms.alloc(Term::Constant(focus_sym)),
386 });
387 let implies = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
388 left: core_z,
389 op: TokenType::Implies,
390 right: identity,
391 });
392 let exhaustivity = self.ctx.exprs.alloc(LogicExpr::Quantifier {
393 kind: QuantifierKind::Universal,
394 variable: z,
395 body: implies,
396 island_id: self.current_island,
397 });
398
399 let focused_term = self.ctx.terms.alloc(Term::Constant(focus_sym));
401 let focus_expr = self.ctx.exprs.alloc(LogicExpr::Focus {
402 kind: crate::token::FocusKind::Cleft,
403 focused: focused_term,
404 scope: core,
405 });
406 Ok(Some(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
407 left: focus_expr,
408 op: TokenType::And,
409 right: exhaustivity,
410 })))
411 }
412
413 fn try_parse_exclamative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
414 let start = self.current;
415 let lead = self.interner.resolve(self.peek().lexeme).to_lowercase();
416 if lead != "how" && lead != "what" {
417 return Ok(None);
418 }
419 let ends_with_exclamation = self.tokens[start..]
422 .iter()
423 .take_while(|t| !matches!(t.kind, TokenType::EOF))
424 .any(|t| matches!(t.kind, TokenType::Exclamation));
425 if !ends_with_exclamation {
426 return Ok(None);
427 }
428 let is_what = lead == "what";
429 self.advance(); if self.check_article() {
432 self.advance();
433 }
434 let pred_sym = match self.consume_content_word() {
436 Ok(s) => s,
437 Err(_) => {
438 self.current = start;
439 return Ok(None);
440 }
441 };
442 let subj_sym = if let TokenType::ProperName(s) = self.peek().kind {
444 self.advance();
445 s
446 } else if self.check_pronoun() {
447 let lx = self.interner.resolve(self.peek().lexeme).to_string();
448 self.advance();
449 let cap = lx
450 .chars()
451 .next()
452 .map(|c| c.to_uppercase().collect::<String>() + &lx[1..])
453 .unwrap_or(lx);
454 self.interner.intern(&cap)
455 } else {
456 match self.consume_content_word() {
457 Ok(s) => s,
458 Err(_) => {
459 self.current = start;
460 return Ok(None);
461 }
462 }
463 };
464 if matches!(
466 self.peek().kind,
467 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
468 ) {
469 self.advance();
470 }
471 if self.check(&TokenType::Exclamation) {
472 self.advance();
473 }
474
475 let degree_var = self.next_var_name();
476 let body = if is_what {
478 self.ctx.exprs.alloc(LogicExpr::Predicate {
479 name: pred_sym,
480 args: self.ctx.terms.alloc_slice([Term::Constant(subj_sym)]),
481 world: None,
482 })
483 } else {
484 self.ctx.exprs.alloc(LogicExpr::Predicate {
485 name: pred_sym,
486 args: self
487 .ctx
488 .terms
489 .alloc_slice([Term::Constant(subj_sym), Term::Variable(degree_var)]),
490 world: None,
491 })
492 };
493 Ok(Some(self.ctx.exprs.alloc(LogicExpr::Exclamative { degree_var, body })))
494 }
495
496 fn try_parse_optative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
497 let start = self.current;
498 let ends_with_exclamation = self.tokens[start..]
500 .iter()
501 .take_while(|t| !matches!(t.kind, TokenType::EOF))
502 .any(|t| matches!(t.kind, TokenType::Exclamation));
503 if !ends_with_exclamation {
504 return Ok(None);
505 }
506
507 let is_may_fronting = self.check(&TokenType::May)
513 || matches!(self.peek().kind, TokenType::ProperName(_))
514 && self.interner.resolve(self.peek().lexeme).eq_ignore_ascii_case("may");
515 if is_may_fronting {
516 self.advance(); let subj_sym = if let TokenType::ProperName(s) = self.peek().kind {
518 self.advance();
519 s
520 } else if self.check_pronoun() {
521 let lx = self.interner.resolve(self.peek().lexeme).to_lowercase();
522 self.advance();
523 match lx.as_str() {
524 "you" => self.interner.intern("Addressee"),
525 "i" | "me" => self.interner.intern("Speaker"),
526 other => self.interner.intern(
527 &(other.chars().next().map(|c| c.to_uppercase().collect::<String>() + &other[1..]).unwrap_or_default()),
528 ),
529 }
530 } else {
531 match self.parse_noun_phrase(false) {
532 Ok(np) => np.noun,
533 Err(_) => {
534 self.current = start;
535 return Ok(None);
536 }
537 }
538 };
539 if self.is_at_end() || self.check(&TokenType::Exclamation) {
542 self.current = start;
543 return Ok(None);
544 }
545 let vlex = self.interner.resolve(self.peek().lexeme).to_string();
546 let vname = vlex
547 .chars()
548 .next()
549 .map(|c| c.to_uppercase().collect::<String>() + &vlex[1..])
550 .unwrap_or(vlex);
551 let verb_sym = self.interner.intern(&vname);
552 self.advance(); let wish = if let TokenType::ProperName(o) = self.peek().kind {
555 self.advance();
556 self.ctx.exprs.alloc(LogicExpr::Predicate {
557 name: verb_sym,
558 args: self
559 .ctx
560 .terms
561 .alloc_slice([Term::Constant(subj_sym), Term::Constant(o)]),
562 world: None,
563 })
564 } else {
565 self.ctx.exprs.alloc(LogicExpr::Predicate {
566 name: verb_sym,
567 args: self.ctx.terms.alloc_slice([Term::Constant(subj_sym)]),
568 world: None,
569 })
570 };
571 return Ok(Some(self.ctx.exprs.alloc(LogicExpr::Optative { wish })));
572 }
573
574 let lead = self.interner.resolve(self.peek().lexeme).to_lowercase();
576 if lead == "long"
577 && self.current + 1 < self.tokens.len()
578 && self.interner.resolve(self.tokens[self.current + 1].lexeme).eq_ignore_ascii_case("live")
579 {
580 self.advance(); self.advance(); let np = self.parse_noun_phrase(false)?;
583 let live_sym = self.interner.intern("Live");
584 let wish = self.ctx.exprs.alloc(LogicExpr::Predicate {
585 name: live_sym,
586 args: self.ctx.terms.alloc_slice([Term::Constant(np.noun)]),
587 world: None,
588 });
589 return Ok(Some(self.ctx.exprs.alloc(LogicExpr::Optative { wish })));
590 }
591
592 if self.check(&TokenType::If)
594 && self.current + 1 < self.tokens.len()
595 && self.interner.resolve(self.tokens[self.current + 1].lexeme).eq_ignore_ascii_case("only")
596 {
597 self.advance(); self.advance(); let wish = self.parse_sentence()?;
600 return Ok(Some(self.ctx.exprs.alloc(LogicExpr::Optative { wish })));
601 }
602
603 Ok(None)
604 }
605
606 fn try_parse_correlative(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
607 let start = self.current;
608 let lead = self.interner.resolve(self.peek().lexeme).to_lowercase();
609 let is_neither = lead == "neither";
610 let is_either = lead == "either";
611 if !is_neither && !is_either {
612 return Ok(None);
613 }
614 self.advance(); fn build_disjunct<'a, 'ctx, 'int>(
625 p: &mut Parser<'a, 'ctx, 'int>,
626 ) -> ParseResult<OfEntity<'a>> {
627 let np = p.parse_noun_phrase(true)?;
628 let has_rel = p.check(&TokenType::Who)
629 || p.check(&TokenType::That)
630 || p.check(&TokenType::Where)
631 || p.check(&TokenType::Whose);
632 let is_desc = !np.adjectives.is_empty()
633 || np.possessor.is_some()
634 || !np.pps.is_empty()
635 || has_rel;
636 let (sym, is_var) = if is_desc {
637 (p.next_var_name(), true)
638 } else {
639 (np.noun, false)
640 };
641 let term = if is_var {
642 Term::Variable(sym)
643 } else {
644 Term::Constant(sym)
645 };
646 let rel = p.try_attach_relative(term)?;
647 let restrictor = if is_var {
648 let mut r = p.nominal_predication(term, &np);
649 for pp in np.pps {
650 let pp_sub = p.substitute_pp_placeholder(pp, sym);
651 r = p.ctx.exprs.alloc(LogicExpr::BinaryOp {
652 left: r,
653 op: TokenType::And,
654 right: pp_sub,
655 });
656 }
657 if let Some(rc) = rel {
658 r = p.ctx.exprs.alloc(LogicExpr::BinaryOp {
659 left: r,
660 op: TokenType::And,
661 right: rc,
662 });
663 }
664 Some(r)
665 } else {
666 None
667 };
668 Ok(OfEntity { sym, is_var, term, restrictor })
669 }
670
671 fn wrap_branch<'a, 'ctx, 'int>(
676 p: &mut Parser<'a, 'ctx, 'int>,
677 e: &OfEntity<'a>,
678 body: &'a LogicExpr<'a>,
679 ) -> &'a LogicExpr<'a> {
680 if !e.is_var {
681 return body;
682 }
683 let inner = match e.restrictor {
684 Some(r) => p.ctx.exprs.alloc(LogicExpr::BinaryOp {
685 left: r,
686 op: TokenType::And,
687 right: body,
688 }),
689 None => body,
690 };
691 p.ctx.exprs.alloc(LogicExpr::Quantifier {
692 kind: QuantifierKind::Existential,
693 variable: e.sym,
694 body: inner,
695 island_id: p.current_island,
696 })
697 }
698
699 let e1 = match self.try_parse(|p| build_disjunct(p)) {
700 Some(e) => e,
701 None => {
702 self.current = start;
703 return Ok(None);
704 }
705 };
706
707 let conj = self.interner.resolve(self.peek().lexeme).to_lowercase();
708 if conj != "nor" && conj != "or" {
709 self.current = start;
710 return Ok(None);
711 }
712 self.advance(); let e2 = match self.try_parse(|p| build_disjunct(p)) {
715 Some(e) => e,
716 None => {
717 self.current = start;
718 return Ok(None);
719 }
720 };
721
722 let vp_start = self.current;
725 let pred1 = if e1.is_var {
726 self.parse_predicate_with_subject_as_var(e1.sym)?
727 } else {
728 self.parse_predicate_with_subject(e1.sym)?
729 };
730 self.current = vp_start;
731 let pred2 = if e2.is_var {
732 self.parse_predicate_with_subject_as_var(e2.sym)?
733 } else {
734 self.parse_predicate_with_subject(e2.sym)?
735 };
736
737 let result = if is_neither {
738 let n1 = self.ctx.exprs.alloc(LogicExpr::UnaryOp { op: TokenType::Not, operand: pred1 });
741 let b1 = wrap_branch(self, &e1, n1);
742 let n2 = self.ctx.exprs.alloc(LogicExpr::UnaryOp { op: TokenType::Not, operand: pred2 });
743 let b2 = wrap_branch(self, &e2, n2);
744 self.ctx.exprs.alloc(LogicExpr::BinaryOp { left: b1, op: TokenType::And, right: b2 })
745 } else {
746 let b1 = wrap_branch(self, &e1, pred1);
750 let b2 = wrap_branch(self, &e2, pred2);
751 let disj = self.ctx.exprs.alloc(LogicExpr::BinaryOp { left: b1, op: TokenType::Or, right: b2 });
752 if self.pragmatic {
753 let both = self.ctx.exprs.alloc(LogicExpr::BinaryOp { left: b1, op: TokenType::And, right: b2 });
754 let not_both = self.ctx.exprs.alloc(LogicExpr::UnaryOp { op: TokenType::Not, operand: both });
755 self.ctx.exprs.alloc(LogicExpr::BinaryOp { left: disj, op: TokenType::And, right: not_both })
756 } else {
757 disj
758 }
759 };
760 Ok(Some(result))
761 }
762
763 fn try_parse_inverted_conditional(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
764 if !matches!(
766 self.peek().kind,
767 TokenType::Had | TokenType::Were | TokenType::Should
768 ) {
769 return Ok(None);
770 }
771
772 let has_comma = self.tokens[self.current..]
775 .iter()
776 .take_while(|t| !matches!(t.kind, TokenType::EOF | TokenType::Period))
777 .any(|t| matches!(t.kind, TokenType::Comma));
778 if !has_comma {
779 return Ok(None);
780 }
781
782 let start = self.current + 1;
787 let comma_at = self.tokens[start..]
788 .iter()
789 .position(|t| matches!(t.kind, TokenType::Comma))
790 .map(|p| start + p)
791 .unwrap_or(self.tokens.len());
792
793 let first_verb = (start..comma_at)
794 .find(|&j| matches!(self.tokens[j].kind, TokenType::Verb { .. }));
795
796 let mut i = start;
799 while i < comma_at
800 && matches!(
801 self.tokens[i].kind,
802 TokenType::Article(_)
803 | TokenType::Adjective(_)
804 | TokenType::Cardinal(_)
805 | TokenType::Possessive
806 )
807 {
808 i += 1;
809 }
810 let head_is_nominal = i < comma_at
811 && matches!(
812 self.tokens[i].kind,
813 TokenType::Noun(_) | TokenType::ProperName(_) | TokenType::Pronoun { .. }
814 );
815 let head_after_determiner =
816 i > start && i < comma_at && Self::is_content_word_type(&self.tokens[i].kind);
817
818 let insert_at = match first_verb {
819 Some(v) => v,
820 None if head_is_nominal || head_after_determiner => i + 1,
821 None => return Ok(None), };
823
824 let aux = self.tokens.remove(self.current);
829 self.tokens.insert(insert_at - 1, aux);
830 let mut if_tok = self.tokens[self.current].clone();
831 if_tok.kind = TokenType::If;
832 if_tok.lexeme = self.interner.intern("if");
833 self.tokens.insert(self.current, if_tok);
834 self.advance(); Ok(Some(self.parse_conditional()?))
836 }
837
838 fn try_parse_fronted_temporal_adjunct(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
844 let is_universal_det = matches!(self.peek().kind, TokenType::All);
845 let unit_next = matches!(
846 self.tokens.get(self.current + 1).map(|t| &t.kind),
847 Some(TokenType::CalendarUnit(_))
848 );
849 let subject_after = self
850 .tokens
851 .get(self.current + 2)
852 .map_or(false, |t| starts_clause_subject(&t.kind));
853 if !(is_universal_det && unit_next && subject_after) {
854 return Ok(None);
855 }
856 self.advance(); self.advance(); if self.check(&TokenType::Comma) {
859 self.advance();
860 }
861 let clause = self.parse_sentence()?;
862 if matches!(clause, LogicExpr::Aspectual { operator: AspectOperator::Habitual, .. }) {
865 return Ok(Some(clause));
866 }
867 Ok(Some(self.ctx.exprs.alloc(LogicExpr::Aspectual {
868 operator: AspectOperator::Habitual,
869 body: clause,
870 })))
871 }
872
873 fn parse_sentence(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
874 if self.mode == ParserMode::Imperative && self.check(&TokenType::Let) {
878 self.advance(); let _var = self.expect_identifier()?;
880 if self.check(&TokenType::Is) || self.check(&TokenType::Be) || self.check(&TokenType::Equals) || self.check(&TokenType::Identity) || self.check(&TokenType::Assign) {
882 self.advance(); }
884 return self.parse_disjunction();
886 }
887
888 if let Some(result) = self.try_parse_ellipsis() {
890 return result;
891 }
892
893 if self.mode != ParserMode::Imperative {
895 if let Some(opt) = self.try_parse_optative()? {
896 return Ok(opt);
897 }
898 }
899
900 if self.mode != ParserMode::Imperative {
902 if let Some(corr) = self.try_parse_correlative()? {
903 return Ok(corr);
904 }
905 }
906
907 if self.mode != ParserMode::Imperative {
909 if let Some(xor) = self.try_parse_of_pair_xor()? {
910 return Ok(xor);
911 }
912 }
913
914 if self.mode != ParserMode::Imperative {
917 if let Some(framed) = self.try_parse_fronted_temporal_adjunct()? {
918 return Ok(framed);
919 }
920 }
921
922 if self.mode != ParserMode::Imperative {
925 let lead_text = self.interner.resolve(self.peek().lexeme).to_lowercase();
926 if lead_text == "whoever" {
927 self.advance(); let var = self.next_var_name();
929 let restrictor = self.parse_predicate_with_subject(var)?;
930 let scope = self.parse_predicate_with_subject(var)?;
931 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
932 left: restrictor,
933 op: TokenType::Implies,
934 right: scope,
935 });
936 return Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
937 kind: QuantifierKind::Universal,
938 variable: var,
939 body,
940 island_id: self.current_island,
941 }));
942 }
943 }
944
945 if self.mode != ParserMode::Imperative {
948 if let Some(excl) = self.try_parse_exclamative()? {
949 return Ok(excl);
950 }
951 }
952
953 if self.mode != ParserMode::Imperative {
955 if let Some(cleft) = self.try_parse_cleft()? {
956 return Ok(cleft);
957 }
958 }
959
960 if self.mode != ParserMode::Imperative {
964 if let Some(imp) = self.try_parse_imperative()? {
965 return Ok(imp);
966 }
967 }
968
969 if self.check(&TokenType::Although) {
972 self.advance(); let concession = self.parse_sentence()?;
974 if self.check(&TokenType::Comma) {
975 self.advance();
976 }
977 let main = self.parse_sentence()?;
978 return Ok(self.ctx.exprs.alloc(LogicExpr::Concessive { main, concession }));
979 }
980
981 if self.check(&TokenType::While) {
985 self.advance(); let condition = self.parse_sentence()?;
987 if self.check(&TokenType::Comma) {
988 self.advance();
989 }
990 let consequent = self.parse_sentence()?;
991 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
992 left: condition,
993 op: TokenType::Implies,
994 right: consequent,
995 }));
996 }
997
998 if self.check(&TokenType::When) {
1001 let saved = self.current;
1002 let mut found_comma = false;
1003 for i in (self.current + 1)..self.tokens.len() {
1004 match &self.tokens[i].kind {
1005 TokenType::Comma => { found_comma = true; break; }
1006 TokenType::Period => break,
1007 _ => {}
1008 }
1009 }
1010 if found_comma {
1011 self.advance(); let condition = self.parse_sentence()?;
1013 if self.check(&TokenType::Comma) {
1014 self.advance();
1015 }
1016 let consequent = self.parse_sentence()?;
1017 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1018 left: condition,
1019 op: TokenType::Implies,
1020 right: consequent,
1021 }));
1022 }
1023 self.current = saved;
1024 }
1025
1026 if self.check_content_word() {
1028 let word = self.interner.resolve(self.peek().lexeme).to_string();
1029 if word == "Whenever" || word == "whenever" {
1030 self.advance(); let condition = self.parse_sentence()?;
1032 if self.check(&TokenType::Comma) {
1033 self.advance();
1034 }
1035 let consequent = self.parse_sentence()?;
1036 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1037 left: condition,
1038 op: TokenType::Implies,
1039 right: consequent,
1040 }));
1041 }
1042 }
1043
1044 if self.check_wh_word() {
1045 return self.parse_wh_question();
1046 }
1047
1048 if self.check(&TokenType::Does)
1049 || self.check(&TokenType::Do)
1050 || self.check(&TokenType::Is)
1051 || self.check(&TokenType::Are)
1052 || self.check(&TokenType::Was)
1053 || self.check(&TokenType::Were)
1054 || self.check(&TokenType::Would)
1055 || self.check(&TokenType::Could)
1056 || self.check(&TokenType::Can)
1057 {
1058 return self.parse_yes_no_question();
1059 }
1060
1061 if let Some(expr) = self.try_parse_inverted_conditional()? {
1064 return Ok(expr);
1065 }
1066
1067 if self.match_token(&[TokenType::If]) {
1068 return self.parse_conditional();
1069 }
1070
1071 if self.match_token(&[TokenType::Either]) {
1074 return self.parse_either_or();
1075 }
1076
1077 if self.check_modal() {
1078 self.advance();
1079 return self.parse_modal();
1080 }
1081
1082 if self.match_token(&[TokenType::Not]) {
1083 self.negative_depth += 1;
1084 let inner = self.parse_sentence()?;
1085 self.negative_depth -= 1;
1086 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1087 op: TokenType::Not,
1088 operand: inner,
1089 }));
1090 }
1091
1092 if self.check(&TokenType::Both) {
1096 let next_is_clausal = if self.current + 1 < self.tokens.len() {
1098 matches!(self.tokens[self.current + 1].kind,
1099 TokenType::All | TokenType::No | TokenType::Some | TokenType::Any
1100 | TokenType::Most | TokenType::Few | TokenType::Many
1101 | TokenType::Cardinal(_) | TokenType::AtLeast(_) | TokenType::AtMost(_)
1102 | TokenType::Article(_)
1103 )
1104 } else {
1105 false
1106 };
1107 if next_is_clausal {
1108 self.advance(); let first = self.parse_atom()?;
1110 if self.check(&TokenType::And) {
1111 self.advance(); }
1113 let second = self.parse_atom()?;
1114 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1115 left: first,
1116 op: TokenType::And,
1117 right: second,
1118 }));
1119 }
1120 }
1121
1122 {
1128 let temporal_op = match &self.peek().kind {
1129 TokenType::Adverb(sym) | TokenType::ScopalAdverb(sym) | TokenType::TemporalAdverb(sym) => {
1130 let resolved = self.interner.resolve(*sym).to_string();
1131 match resolved.as_str() {
1132 "Always" => Some(crate::ast::logic::TemporalOperator::Always),
1133 "Eventually" => Some(crate::ast::logic::TemporalOperator::Eventually),
1134 "Next" => Some(crate::ast::logic::TemporalOperator::Next),
1135 _ => None,
1136 }
1137 }
1138 TokenType::Adjective(sym) => {
1140 let resolved = self.interner.resolve(*sym).to_string();
1141 if resolved == "Next" {
1142 Some(crate::ast::logic::TemporalOperator::Next)
1143 } else {
1144 None
1145 }
1146 }
1147 _ => None,
1148 };
1149 if let Some(op) = temporal_op {
1150 self.advance(); if self.check(&TokenType::Comma) {
1153 self.advance();
1154 }
1155 let body = self.parse_sentence()?;
1156 return Ok(self.ctx.exprs.alloc(LogicExpr::Temporal {
1157 operator: op,
1158 body,
1159 }));
1160 }
1161 }
1162 if self.check(&TokenType::Never) {
1164 self.advance(); if self.check(&TokenType::Comma) {
1167 self.advance();
1168 }
1169 let body = self.parse_sentence()?;
1170 let negated = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1171 op: TokenType::Not,
1172 operand: body,
1173 });
1174 return Ok(self.ctx.exprs.alloc(LogicExpr::Temporal {
1175 operator: crate::ast::logic::TemporalOperator::Always,
1176 body: negated,
1177 }));
1178 }
1179
1180 if self.check_preposition_is("after") || self.check_preposition_is("After") {
1185 self.advance(); let is_bare_noun_comma = self.current + 1 < self.tokens.len()
1190 && matches!(self.tokens[self.current + 1].kind, TokenType::Comma)
1191 && (self.check_content_word()
1192 || matches!(self.peek().kind, TokenType::Performative(_)));
1193 let antecedent = if is_bare_noun_comma {
1194 let noun = match self.advance().kind.clone() {
1195 TokenType::Performative(s) => s,
1196 TokenType::Noun(s) | TokenType::Adjective(s) | TokenType::ProperName(s) => s,
1197 TokenType::Verb { lemma, .. } => lemma,
1198 _ => return Err(crate::error::ParseError {
1199 kind: crate::error::ParseErrorKind::ExpectedContentWord { found: self.peek().kind.clone() },
1200 span: self.current_span(),
1201 }),
1202 };
1203 self.ctx.exprs.alloc(LogicExpr::Atom(noun))
1204 } else {
1205 self.parse_sentence()?
1206 };
1207
1208 if self.check(&TokenType::Comma) {
1209 self.advance();
1210 }
1211 let consequent = self.parse_sentence()?;
1212 let consequent = self.try_wrap_bounded_delay(consequent);
1213 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1214 left: antecedent,
1215 op: TokenType::Implies,
1216 right: consequent,
1217 }));
1218 }
1219 if self.check_preposition_is("before") || self.check_preposition_is("Before") {
1220 self.advance(); let first_clause = self.parse_sentence()?;
1222 if self.check(&TokenType::Comma) {
1223 self.advance();
1224 }
1225 let second_clause = self.parse_sentence()?;
1226 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1227 left: second_clause,
1228 op: TokenType::Implies,
1229 right: first_clause,
1230 }));
1231 }
1232
1233 self.parse_disjunction()
1234 }
1235
1236 fn check_wh_word(&self) -> bool {
1237 if matches!(
1238 self.peek().kind,
1239 TokenType::Who
1240 | TokenType::What
1241 | TokenType::Where
1242 | TokenType::When
1243 | TokenType::Why
1244 ) {
1245 return true;
1246 }
1247 if self.check_preposition() && self.current + 1 < self.tokens.len() {
1248 matches!(
1249 self.tokens[self.current + 1].kind,
1250 TokenType::Who
1251 | TokenType::What
1252 | TokenType::Where
1253 | TokenType::When
1254 | TokenType::Why
1255 )
1256 } else {
1257 false
1258 }
1259 }
1260
1261 fn parse_conditional(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1262 let is_counterfactual = self.is_counterfactual_context();
1263
1264 let is_biscuit = self.check_pronoun()
1268 && self.interner.resolve(self.peek().lexeme).eq_ignore_ascii_case("you")
1269 && self
1270 .tokens
1271 .get(self.current + 1)
1272 .map(|t| {
1273 crate::lexicon::is_relevance_verb(
1274 &self.interner.resolve(t.lexeme).to_lowercase(),
1275 )
1276 })
1277 .unwrap_or(false);
1278
1279 self.drs.enter_box(BoxType::ConditionalAntecedent);
1281 let mut antecedent = self.parse_counterfactual_antecedent()?;
1282
1283 while self.check(&TokenType::And) {
1285 self.advance(); let second = self.parse_counterfactual_antecedent()?;
1287 antecedent = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1288 left: antecedent,
1289 op: TokenType::And,
1290 right: second,
1291 });
1292 }
1293 self.drs.exit_box();
1294
1295 if self.check(&TokenType::Comma) {
1296 self.advance();
1297 }
1298
1299 if self.check(&TokenType::Then) {
1300 self.advance();
1301 }
1302
1303 self.drs.enter_box(BoxType::ConditionalConsequent);
1305 let mut consequent = self.parse_counterfactual_consequent()?;
1306
1307 while self.check(&TokenType::And) {
1311 let cp = self.checkpoint();
1312 self.advance(); match self.parse_counterfactual_consequent() {
1314 Ok(second) => {
1315 consequent = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1316 left: consequent,
1317 op: TokenType::And,
1318 right: second,
1319 });
1320 }
1321 Err(_) => {
1322 self.restore(cp);
1323 break;
1324 }
1325 }
1326 }
1327
1328 if self.check(&TokenType::Until)
1333 || self.check(&TokenType::Release)
1334 || self.check(&TokenType::WeakUntil)
1335 {
1336 let op = match self.peek().kind {
1337 TokenType::Release => crate::ast::logic::BinaryTemporalOp::Release,
1338 TokenType::WeakUntil => crate::ast::logic::BinaryTemporalOp::WeakUntil,
1339 _ => crate::ast::logic::BinaryTemporalOp::Until,
1340 };
1341 self.advance();
1342 let right = self.parse_counterfactual_consequent()?;
1343 consequent = self.ctx.exprs.alloc(LogicExpr::TemporalBinary {
1344 operator: op,
1345 left: consequent,
1346 right,
1347 });
1348 }
1349 consequent = self.try_wrap_next_cycle(consequent);
1350 consequent = self.try_wrap_bounded_delay(consequent);
1351 self.drs.exit_box();
1352
1353 if is_biscuit {
1356 let relevance = self.ctx.exprs.alloc(LogicExpr::Predicate {
1357 name: self.interner.intern("Relevance"),
1358 args: self.ctx.terms.alloc_slice([Term::Proposition(antecedent)]),
1359 world: None,
1360 });
1361 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1362 left: consequent,
1363 op: TokenType::And,
1364 right: relevance,
1365 }));
1366 }
1367
1368 let universal_refs = self.drs.get_universal_referents();
1370
1371 let conditional = if is_counterfactual {
1373 self.ctx.exprs.alloc(LogicExpr::Counterfactual {
1374 antecedent,
1375 consequent,
1376 })
1377 } else {
1378 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1379 left: antecedent,
1380 op: TokenType::If,
1381 right: consequent,
1382 })
1383 };
1384
1385 let mut result = conditional;
1387 for var in universal_refs.into_iter().rev() {
1388 result = self.ctx.exprs.alloc(LogicExpr::Quantifier {
1389 kind: QuantifierKind::Universal,
1390 variable: var,
1391 body: result,
1392 island_id: self.current_island,
1393 });
1394 }
1395
1396 Ok(result)
1397 }
1398
1399 fn parse_either_or(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1404 let start_pos = self.current;
1406
1407 if let TokenType::ProperName(name1) = self.peek().kind {
1410 self.advance(); if self.check(&TokenType::Or) {
1413 self.advance(); if let TokenType::ProperName(name2) = self.peek().kind {
1416 self.advance(); let is_copula = matches!(
1420 self.peek().kind,
1421 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
1422 );
1423 if is_copula {
1424 self.advance(); let is_negated = self.match_token(&[TokenType::Not]);
1428
1429 if let TokenType::Adjective(adj) = self.peek().kind {
1431 self.advance(); let pred1 = self.ctx.exprs.alloc(LogicExpr::Predicate {
1435 name: adj,
1436 args: self.ctx.terms.alloc_slice(vec![
1437 Term::Constant(name1)
1438 ]),
1439 world: None,
1440 });
1441 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
1442 name: adj,
1443 args: self.ctx.terms.alloc_slice(vec![
1444 Term::Constant(name2)
1445 ]),
1446 world: None,
1447 });
1448
1449 let left = if is_negated {
1451 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1452 op: TokenType::Not,
1453 operand: pred1,
1454 })
1455 } else {
1456 pred1
1457 };
1458 let right = if is_negated {
1459 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1460 op: TokenType::Not,
1461 operand: pred2,
1462 })
1463 } else {
1464 pred2
1465 };
1466
1467 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1468 left,
1469 op: TokenType::Or,
1470 right,
1471 }));
1472 }
1473 }
1474 }
1475 }
1476
1477 self.current = start_pos;
1479 }
1480
1481 self.drs.enter_box(BoxType::Disjunct);
1484 let left = self.parse_conjunction()?;
1485 self.drs.exit_box();
1486
1487 if !self.check(&TokenType::Or) {
1488 return Err(ParseError {
1489 kind: ParseErrorKind::ExpectedKeyword { keyword: "or".to_string() },
1490 span: self.current_span(),
1491 });
1492 }
1493 self.advance(); self.drs.enter_box(BoxType::Disjunct);
1497 let right = self.parse_conjunction()?;
1498 self.drs.exit_box();
1499
1500 Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1501 left,
1502 op: TokenType::Or,
1503 right,
1504 }))
1505 }
1506
1507 fn is_counterfactual_context(&self) -> bool {
1508 for i in 0..5 {
1509 if self.current + i >= self.tokens.len() {
1510 break;
1511 }
1512 let token = &self.tokens[self.current + i];
1513 if matches!(token.kind, TokenType::Were | TokenType::Had) {
1514 return true;
1515 }
1516 if matches!(token.kind, TokenType::Comma | TokenType::Period) {
1517 break;
1518 }
1519 }
1520 false
1521 }
1522
1523 fn parse_counterfactual_antecedent(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1524 let unknown = self.interner.intern("?");
1525 if self.check_content_word() || self.check_pronoun() || self.check_article() {
1526 if self.check_pronoun() {
1529 let token = self.peek();
1530 let token_text = self.interner.resolve(token.lexeme);
1531 if token_text.eq_ignore_ascii_case("it") {
1532 if self.current + 1 < self.tokens.len() {
1534 if let TokenType::Verb { lemma, time, .. } = &self.tokens[self.current + 1].kind {
1536 let lemma_str = self.interner.resolve(*lemma);
1537 if Lexer::is_weather_verb(lemma_str) {
1538 let verb = *lemma;
1539 let verb_time = *time;
1540 self.advance(); self.advance(); let event_var = self.get_event_var();
1544
1545 let suppress_existential = self.drs.in_conditional_antecedent();
1548
1549 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1550 event_var,
1551 verb,
1552 roles: self.ctx.roles.alloc_slice(vec![]),
1553 modifiers: self.ctx.syms.alloc_slice(vec![]),
1554 suppress_existential,
1555 world: None,
1556 })));
1557
1558 while self.check(&TokenType::And) || self.check(&TokenType::Or) {
1561 let is_disjunction = self.check(&TokenType::Or);
1562 self.advance(); if let TokenType::Verb { lemma: lemma2, .. } = &self.peek().kind.clone() {
1565 let lemma2_str = self.interner.resolve(*lemma2);
1566 if Lexer::is_weather_verb(lemma2_str) {
1567 let verb2 = *lemma2;
1568 self.advance(); let neo_event2 = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1572 event_var, verb: verb2,
1574 roles: self.ctx.roles.alloc_slice(vec![]),
1575 modifiers: self.ctx.syms.alloc_slice(vec![]),
1576 suppress_existential,
1577 world: None,
1578 })));
1579
1580 let op = if is_disjunction { TokenType::Or } else { TokenType::And };
1581 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1582 left: result,
1583 op,
1584 right: neo_event2,
1585 });
1586 } else {
1587 break; }
1589 } else {
1590 break;
1591 }
1592 }
1593
1594 return Ok(match verb_time {
1595 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
1596 operator: TemporalOperator::Past,
1597 body: result,
1598 }),
1599 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
1600 operator: TemporalOperator::Future,
1601 body: result,
1602 }),
1603 _ => result,
1604 });
1605 }
1606 }
1607 else if self.current + 2 < self.tokens.len() {
1609 let is_copula = matches!(
1610 self.tokens[self.current + 1].kind,
1611 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
1612 );
1613 if is_copula {
1614 if let TokenType::Verb { lemma, .. } = &self.tokens[self.current + 2].kind {
1615 let lemma_str = self.interner.resolve(*lemma);
1616 if Lexer::is_weather_verb(lemma_str) {
1617 let verb = *lemma;
1618 let verb_time = if matches!(
1619 self.tokens[self.current + 1].kind,
1620 TokenType::Was | TokenType::Were
1621 ) {
1622 Time::Past
1623 } else {
1624 Time::Present
1625 };
1626 self.advance(); self.advance(); self.advance(); let event_var = self.get_event_var();
1631 let suppress_existential = self.drs.in_conditional_antecedent();
1634
1635 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1636 event_var,
1637 verb,
1638 roles: self.ctx.roles.alloc_slice(vec![]),
1639 modifiers: self.ctx.syms.alloc_slice(vec![]),
1640 suppress_existential,
1641 world: None,
1642 })));
1643
1644 let with_aspect = self.ctx.exprs.alloc(LogicExpr::Aspectual {
1646 operator: AspectOperator::Progressive,
1647 body: neo_event,
1648 });
1649
1650 return Ok(match verb_time {
1651 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
1652 operator: TemporalOperator::Past,
1653 body: with_aspect,
1654 }),
1655 _ => with_aspect,
1656 });
1657 }
1658 }
1659 }
1660 }
1661 }
1662 }
1663 }
1664
1665 let (subject, subject_type_pred) = if self.check_pronoun() {
1667 let token = self.advance().clone();
1668 let token_text = self.interner.resolve(token.lexeme);
1669 let resolved = if token_text.eq_ignore_ascii_case("i") {
1671 self.interner.intern("Speaker")
1672 } else if token_text.eq_ignore_ascii_case("you") {
1673 self.interner.intern("Addressee")
1674 } else if let TokenType::Pronoun { gender, number, .. } = token.kind {
1675 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
1676 match resolved_pronoun {
1677 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
1678 }
1679 } else {
1680 unknown
1681 };
1682 (resolved, None)
1683 } else {
1684 let np = self.parse_noun_phrase(true)?;
1685
1686 if np.definiteness == Some(Definiteness::Definite)
1690 || np.definiteness == Some(Definiteness::Distal) {
1691 let gender = Self::infer_noun_gender(self.interner.resolve(np.noun));
1701 let number = if Self::is_plural_noun(self.interner.resolve(np.noun)) {
1702 Number::Plural
1703 } else {
1704 Number::Singular
1705 };
1706 self.drs.introduce_referent_with_source(
1707 np.noun,
1708 np.noun,
1709 gender,
1710 number,
1711 crate::drs::ReferentSource::ProperName,
1712 );
1713 (np.noun, None)
1714 } else if np.definiteness == Some(Definiteness::Indefinite) {
1715 let gender = Self::infer_noun_gender(self.interner.resolve(np.noun));
1716 let number = if Self::is_plural_noun(self.interner.resolve(np.noun)) {
1717 Number::Plural
1718 } else {
1719 Number::Singular
1720 };
1721
1722 self.drs.introduce_referent(np.noun, np.noun, gender, number);
1725
1726 let type_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
1728 name: np.noun,
1729 args: self.ctx.terms.alloc_slice([Term::Variable(np.noun)]),
1730 world: None,
1731 });
1732
1733 (np.noun, Some(type_pred))
1734 } else {
1735 (np.noun, None)
1737 }
1738 };
1739
1740 let subject_term = if subject_type_pred.is_some() {
1742 Term::Variable(subject)
1743 } else {
1744 Term::Constant(subject)
1745 };
1746
1747 if self.check_presup_trigger() && self.is_followed_by_gerund() {
1750 let presup_kind = match self.advance().kind {
1751 TokenType::PresupTrigger(kind) => kind,
1752 TokenType::Verb { lemma, .. } => {
1753 let s = self.interner.resolve(lemma).to_lowercase();
1754 crate::lexicon::lookup_presup_trigger(&s)
1755 .expect("Lexicon mismatch: Verb flagged as trigger but lookup failed")
1756 }
1757 _ => panic!("Expected presupposition trigger"),
1758 };
1759 let np = NounPhrase {
1760 noun: subject,
1761 definiteness: None,
1762 adjectives: &[],
1763 possessor: None,
1764 pps: &[],
1765 superlative: None,
1766 };
1767 return self.parse_presupposition(&np, presup_kind, false);
1768 }
1769
1770 if self.check(&TokenType::Were) {
1771 self.advance();
1772 let predicate = if self.check_pronoun() {
1773 let token = self.advance().clone();
1774 if let TokenType::Pronoun { gender, number, .. } = token.kind {
1775 let token_text = self.interner.resolve(token.lexeme);
1776 if token_text.eq_ignore_ascii_case("i") {
1777 self.interner.intern("Speaker")
1778 } else if token_text.eq_ignore_ascii_case("you") {
1779 self.interner.intern("Addressee")
1780 } else {
1781 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
1782 match resolved_pronoun {
1783 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
1784 }
1785 }
1786 } else {
1787 unknown
1788 }
1789 } else {
1790 self.consume_content_word()?
1791 };
1792 let be = self.interner.intern("Be");
1793 let be_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
1794 name: be,
1795 args: self.ctx.terms.alloc_slice([
1796 subject_term,
1797 Term::Constant(predicate),
1798 ]),
1799 world: None,
1800 });
1801 return Ok(if let Some(type_pred) = subject_type_pred {
1803 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1804 left: type_pred,
1805 op: TokenType::And,
1806 right: be_pred,
1807 })
1808 } else {
1809 be_pred
1810 });
1811 }
1812
1813 if self.check(&TokenType::Had) {
1814 self.advance();
1815 let negated = self.check(&TokenType::Not);
1817 if negated {
1818 self.advance();
1819 }
1820 let verb = self.consume_content_word()?;
1821 let mut main_pred: &'a LogicExpr<'a> =
1822 self.ctx.exprs.alloc(LogicExpr::Predicate {
1823 name: verb,
1824 args: self.ctx.terms.alloc_slice([subject_term]),
1825 world: None,
1826 });
1827 if negated {
1828 main_pred = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1829 op: TokenType::Not,
1830 operand: main_pred,
1831 });
1832 }
1833
1834 if self.check(&TokenType::Because) && !self.peek_next_is_string_literal() {
1837 self.advance();
1838 let cause = self.parse_atom()?;
1839 let causal = self.ctx.exprs.alloc(LogicExpr::Causal {
1840 effect: main_pred,
1841 cause,
1842 });
1843 return Ok(if let Some(type_pred) = subject_type_pred {
1845 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1846 left: type_pred,
1847 op: TokenType::And,
1848 right: causal,
1849 })
1850 } else {
1851 causal
1852 });
1853 }
1854
1855 return Ok(if let Some(type_pred) = subject_type_pred {
1857 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1858 left: type_pred,
1859 op: TokenType::And,
1860 right: main_pred,
1861 })
1862 } else {
1863 main_pred
1864 });
1865 }
1866
1867 let verb_phrase = if subject_type_pred.is_some() {
1870 self.parse_predicate_with_subject_as_var(subject)?
1871 } else {
1872 self.parse_predicate_with_subject(subject)?
1873 };
1874
1875 return Ok(if let Some(type_pred) = subject_type_pred {
1877 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1878 left: type_pred,
1879 op: TokenType::And,
1880 right: verb_phrase,
1881 })
1882 } else {
1883 verb_phrase
1884 });
1885 }
1886
1887 self.parse_sentence()
1888 }
1889
1890 fn parse_counterfactual_consequent(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
1891 let unknown = self.interner.intern("?");
1892 if self.check_content_word() || self.check_pronoun() {
1893 if self.check_pronoun() {
1896 let token = self.peek();
1897 let token_text = self.interner.resolve(token.lexeme).to_lowercase();
1898 if token_text == "its" {
1899 if self.current + 1 < self.tokens.len() {
1901 let next_token = &self.tokens[self.current + 1];
1902 let next_str = self.interner.resolve(next_token.lexeme).to_lowercase();
1903 if let Some(meta) = crate::lexicon::lookup_adjective_db(&next_str) {
1904 if meta.features.contains(&crate::lexicon::Feature::Weather) {
1905 return Err(ParseError {
1906 kind: ParseErrorKind::GrammarError(
1907 "Did you mean 'it's' (it is)? 'its' is a possessive pronoun.".to_string()
1908 ),
1909 span: self.current_span(),
1910 });
1911 }
1912 }
1913 }
1914 }
1915 }
1916
1917 if self.check_pronoun() {
1919 let token_text = self.interner.resolve(self.peek().lexeme).to_lowercase();
1920 if token_text == "it" {
1921 if self.current + 2 < self.tokens.len() {
1924 let next = &self.tokens[self.current + 1].kind;
1925 if matches!(next, TokenType::Is | TokenType::Was | TokenType::Possessive) {
1926 let adj_token = &self.tokens[self.current + 2];
1928 let adj_sym = adj_token.lexeme;
1929 let adj_str = self.interner.resolve(adj_sym).to_lowercase();
1930 if let Some(meta) = crate::lexicon::lookup_adjective_db(&adj_str) {
1931 if meta.features.contains(&crate::lexicon::Feature::Weather) {
1932 self.advance(); self.advance(); self.advance(); let adj_lemma = self.interner.intern(meta.lemma);
1938
1939 let event_var = self.drs.get_last_event_referent(self.interner)
1941 .unwrap_or_else(|| self.interner.intern("e"));
1942
1943 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::Predicate {
1945 name: adj_lemma,
1946 args: self.ctx.terms.alloc_slice([Term::Variable(event_var)]),
1947 world: None,
1948 });
1949
1950 while self.check(&TokenType::And) {
1952 self.advance(); if self.check_content_word() {
1954 let adj2_lexeme = self.peek().lexeme;
1955 let adj2_str = self.interner.resolve(adj2_lexeme).to_lowercase();
1956
1957 if let Some(meta2) = crate::lexicon::lookup_adjective_db(&adj2_str) {
1959 if meta2.features.contains(&crate::lexicon::Feature::Weather) {
1960 self.advance(); let adj2_lemma = self.interner.intern(meta2.lemma);
1963 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
1964 name: adj2_lemma,
1965 args: self.ctx.terms.alloc_slice([Term::Variable(event_var)]),
1966 world: None,
1967 });
1968 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1969 left: result,
1970 op: TokenType::And,
1971 right: pred2,
1972 });
1973 continue;
1974 }
1975 }
1976 }
1977 break;
1978 }
1979
1980 return Ok(result);
1981 }
1982 }
1983 }
1984 }
1985 }
1986 }
1987
1988 let subject = if self.check_pronoun() {
1989 let token = self.advance().clone();
1990 let token_text = self.interner.resolve(token.lexeme);
1991 if token_text.eq_ignore_ascii_case("i") {
1993 self.interner.intern("Speaker")
1994 } else if token_text.eq_ignore_ascii_case("you") {
1995 self.interner.intern("Addressee")
1996 } else if let TokenType::Pronoun { gender, number, .. } = token.kind {
1997 let resolved_pronoun = self.resolve_pronoun(gender, number)?;
1998 match resolved_pronoun {
1999 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
2000 }
2001 } else {
2002 unknown
2003 }
2004 } else {
2005 let np = self.parse_noun_phrase(true)?;
2006 if np.definiteness == Some(crate::lexicon::Definiteness::Definite) {
2007 self.drs.introduce_referent_global(
2012 np.noun,
2013 np.noun,
2014 Gender::Unknown,
2015 Number::Singular,
2016 crate::drs::ReferentSource::MainClause,
2017 );
2018 }
2019 np.noun
2020 };
2021
2022 if self.check(&TokenType::Would) {
2023 self.advance();
2024 let negated = self.check(&TokenType::Not);
2026 if negated {
2027 self.advance();
2028 }
2029 if self.check_content_word() {
2030 let next_word = self.interner.resolve(self.peek().lexeme).to_lowercase();
2031 if next_word == "have" {
2032 self.advance();
2033 }
2034 }
2035 let clause_ends_after_verb = matches!(
2038 self.tokens.get(self.current + 1).map(|t| t.kind.clone()),
2039 Some(
2040 TokenType::Period
2041 | TokenType::Exclamation
2042 | TokenType::EOF
2043 | TokenType::And
2044 | TokenType::Comma
2045 ) | None
2046 );
2047 let mut pred: &'a LogicExpr<'a> = if clause_ends_after_verb {
2048 let verb = self.consume_content_word()?;
2049 self.ctx.exprs.alloc(LogicExpr::Predicate {
2050 name: verb,
2051 args: self.ctx.terms.alloc_slice([Term::Constant(subject)]),
2052 world: None,
2053 })
2054 } else {
2055 self.parse_predicate_with_subject(subject)?
2056 };
2057 if negated {
2058 pred = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2059 op: TokenType::Not,
2060 operand: pred,
2061 });
2062 }
2063 return Ok(pred);
2064 }
2065
2066 return self.parse_predicate_with_subject(subject);
2067 }
2068
2069 self.parse_sentence()
2070 }
2071
2072 fn extract_verb_from_expr(&self, expr: &LogicExpr<'a>) -> Option<Symbol> {
2073 match expr {
2074 LogicExpr::NeoEvent(data) => Some(data.verb),
2076 LogicExpr::Control { verb, .. } => Some(*verb),
2078 LogicExpr::BinaryOp { left, right, .. } => {
2083 if let Some(verb) = self.extract_neo_event_verb(left) {
2085 return Some(verb);
2086 }
2087 if let Some(verb) = self.extract_neo_event_verb(right) {
2089 return Some(verb);
2090 }
2091 self.extract_verb_from_expr(left)
2093 .or_else(|| self.extract_verb_from_expr(right))
2094 }
2095 LogicExpr::Predicate { name, .. } => Some(*name),
2097 LogicExpr::Modal { operand, .. } => self.extract_verb_from_expr(operand),
2098 LogicExpr::Presupposition { assertion, .. } => self.extract_verb_from_expr(assertion),
2099 LogicExpr::Temporal { body, .. } => self.extract_verb_from_expr(body),
2100 LogicExpr::TemporalAnchor { body, .. } => self.extract_verb_from_expr(body),
2101 LogicExpr::Aspectual { body, .. } => self.extract_verb_from_expr(body),
2102 LogicExpr::Quantifier { body, .. } => self.extract_verb_from_expr(body),
2103 _ => None,
2104 }
2105 }
2106
2107 fn parse_gapped_clause(&mut self, borrowed_verb: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
2110 let subject = self.parse_noun_phrase(true)?;
2111
2112 if self.check(&TokenType::Comma) {
2113 self.advance();
2114 }
2115
2116 let subject_term = self.noun_phrase_to_term(&subject);
2117 let event_var = self.get_event_var();
2118 let suppress_existential = self.drs.in_conditional_antecedent();
2119
2120 let template = self.last_event_template.clone();
2122
2123 let mut np_args: Vec<Term<'a>> = Vec::new();
2125 let mut pp_args: Vec<(Symbol, Term<'a>)> = Vec::new();
2126 let mut override_adverb: Option<Symbol> = None;
2127
2128 loop {
2129 if self.check_temporal_adverb() {
2130 if let TokenType::TemporalAdverb(sym) = self.advance().kind {
2132 override_adverb = Some(sym);
2133 }
2134 } else if self.check_preposition() {
2135 let prep = if let TokenType::Preposition(sym) = self.advance().kind {
2137 sym
2138 } else {
2139 continue;
2140 };
2141 let np = self.parse_noun_phrase(false)?;
2142 pp_args.push((prep, self.noun_phrase_to_term(&np)));
2143 } else if self.check_content_word() || self.check_article() {
2144 let np = self.parse_noun_phrase(false)?;
2146 np_args.push(self.noun_phrase_to_term(&np));
2147 if self.check(&TokenType::Comma) {
2148 self.advance();
2149 }
2150 } else {
2151 break;
2152 }
2153 }
2154
2155 let roles = self.build_gapped_roles(subject_term, &np_args, &pp_args, &template);
2157
2158 let modifiers = match (override_adverb, &template) {
2160 (Some(adv), Some(tmpl)) => {
2161 let mut mods: Vec<Symbol> = tmpl
2163 .modifiers
2164 .iter()
2165 .filter(|m| !self.is_temporal_modifier(**m))
2166 .cloned()
2167 .collect();
2168 mods.push(adv);
2169 mods
2170 }
2171 (Some(adv), None) => vec![adv],
2172 (None, Some(tmpl)) => tmpl.modifiers.clone(),
2173 (None, None) => vec![],
2174 };
2175
2176 Ok(self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
2177 event_var,
2178 verb: borrowed_verb,
2179 roles: self.ctx.roles.alloc_slice(roles),
2180 modifiers: self.ctx.syms.alloc_slice(modifiers),
2181 suppress_existential,
2182 world: None,
2183 }))))
2184 }
2185
2186 fn is_complete_clause(&self, expr: &LogicExpr<'a>) -> bool {
2187 match expr {
2188 LogicExpr::Atom(_) => false,
2189 LogicExpr::Predicate { .. } => true,
2190 LogicExpr::Quantifier { .. } => true,
2191 LogicExpr::Modal { .. } => true,
2192 LogicExpr::Temporal { .. } => true,
2193 LogicExpr::Aspectual { .. } => true,
2194 LogicExpr::BinaryOp { .. } => true,
2195 LogicExpr::UnaryOp { .. } => true,
2196 LogicExpr::Control { .. } => true,
2197 LogicExpr::Presupposition { .. } => true,
2198 LogicExpr::Categorical(_) => true,
2199 LogicExpr::Relation(_) => true,
2200 _ => true,
2201 }
2202 }
2203
2204 fn parse_disjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
2207 let mut expr = self.parse_conjunction()?;
2208
2209 while self.check(&TokenType::Comma)
2210 || self.check(&TokenType::Or)
2211 {
2212 if self.check(&TokenType::Comma) {
2213 self.advance();
2214 }
2215 if !self.match_token(&[TokenType::Or]) {
2218 break;
2219 }
2220 let operator = self.previous().kind.clone();
2221 self.current_island += 1;
2222
2223 let saved_pos = self.current;
2224 let standard_attempt = self.try_parse(|p| p.parse_conjunction());
2225
2226 let use_gapping = match &standard_attempt {
2229 Some(right) => {
2230 !self.is_complete_clause(right)
2231 && (self.check(&TokenType::Comma) || self.check_content_word())
2232 && operator != TokenType::Iff }
2234 None => operator != TokenType::Iff, };
2236
2237 if !use_gapping {
2238 if let Some(right) = standard_attempt {
2239 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2240 left: expr,
2241 op: operator,
2242 right,
2243 });
2244 }
2245 } else {
2246 self.current = saved_pos;
2247
2248 let borrowed_verb = self.extract_verb_from_expr(expr).ok_or(ParseError {
2249 kind: ParseErrorKind::GappingResolutionFailed,
2250 span: self.current_span(),
2251 })?;
2252
2253 let right = self.parse_gapped_clause(borrowed_verb)?;
2254
2255 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2256 left: expr,
2257 op: operator,
2258 right,
2259 });
2260 }
2261 }
2262
2263 if self.check(&TokenType::Until) || self.check(&TokenType::Release) || self.check(&TokenType::WeakUntil) {
2268 let op = match self.peek().kind {
2269 TokenType::Release => crate::ast::logic::BinaryTemporalOp::Release,
2270 TokenType::WeakUntil => crate::ast::logic::BinaryTemporalOp::WeakUntil,
2271 _ => crate::ast::logic::BinaryTemporalOp::Until,
2272 };
2273 self.advance();
2274 let right = self.parse_conjunction()?;
2275 expr = self.ctx.exprs.alloc(LogicExpr::TemporalBinary {
2276 operator: op,
2277 left: expr,
2278 right,
2279 });
2280 }
2281
2282 let expr = self.try_wrap_bounded_delay(expr);
2284
2285 let mut expr = self.try_wrap_next_cycle(expr);
2287
2288 if let TokenType::TemporalAdverb(anchor) = self.peek().kind {
2291 if matches!(
2292 self.tokens.get(self.current + 1).map(|t| &t.kind),
2293 Some(TokenType::Period) | Some(TokenType::Exclamation) | Some(TokenType::EOF) | None
2294 ) {
2295 self.advance();
2296 expr = self.ctx.exprs.alloc(LogicExpr::TemporalAnchor { anchor, body: expr });
2297 }
2298 }
2299
2300 if self.interner.resolve(self.peek().lexeme).eq_ignore_ascii_case("only")
2304 && matches!(
2305 self.tokens.get(self.current + 1).map(|t| &t.kind),
2306 Some(TokenType::When) | Some(TokenType::If)
2307 )
2308 {
2309 self.advance(); self.advance(); let condition = self.parse_conjunction()?;
2312 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2313 left: expr,
2314 op: TokenType::If,
2315 right: condition,
2316 });
2317 }
2318 else if self.check(&TokenType::When) {
2320 self.advance();
2321 let condition = self.parse_conjunction()?;
2322 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2323 left: condition,
2324 op: TokenType::Implies,
2325 right: expr,
2326 });
2327 }
2328
2329 while self.check(&TokenType::Iff) {
2333 self.advance();
2334 self.current_island += 1;
2335 let right = self.parse_disjunction()?;
2336 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2337 left: expr,
2338 op: TokenType::Iff,
2339 right,
2340 });
2341 }
2342
2343 Ok(expr)
2344 }
2345
2346 fn extract_copular_subject(&self, expr: &'a LogicExpr<'a>) -> Option<Symbol> {
2353 match expr {
2354 LogicExpr::Predicate { args, .. } => match args.first() {
2355 Some(Term::Constant(s)) => Some(*s),
2356 _ => None,
2357 },
2358 LogicExpr::Quantifier { body, .. } => self.extract_copular_subject(body),
2359 LogicExpr::Aspectual { body, .. } => self.extract_copular_subject(body),
2360 LogicExpr::UnaryOp { operand, .. } => self.extract_copular_subject(operand),
2361 LogicExpr::BinaryOp { left, .. } => self.extract_copular_subject(left),
2362 _ => None,
2363 }
2364 }
2365
2366 fn try_parse_copular_predicate(
2370 &mut self,
2371 subject: Symbol,
2372 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
2373 let pred_sym = if let TokenType::Adjective(adj) = self.peek().kind {
2374 if matches!(
2378 self.tokens.get(self.current + 1).map(|t| &t.kind),
2379 Some(TokenType::Is)
2380 | Some(TokenType::Are)
2381 | Some(TokenType::Was)
2382 | Some(TokenType::Were)
2383 ) {
2384 return Ok(None);
2385 }
2386 self.advance();
2387 adj
2388 } else if self.check_article() {
2389 let np = self.parse_noun_phrase(false)?;
2391 np.noun
2392 } else {
2393 return Ok(None);
2394 };
2395 Ok(Some(self.ctx.exprs.alloc(LogicExpr::Predicate {
2396 name: pred_sym,
2397 args: self.ctx.terms.alloc_slice([Term::Constant(subject)]),
2398 world: None,
2399 })))
2400 }
2401
2402 fn parse_conjunction(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
2403 let mut expr = self.parse_atom()?;
2404
2405 if self.check(&TokenType::Because) && !self.peek_next_is_string_literal() {
2408 self.advance();
2409 let cause = self.parse_atom()?;
2410 return Ok(self.ctx.exprs.alloc(LogicExpr::Causal {
2411 effect: expr,
2412 cause,
2413 }));
2414 }
2415
2416 while self.check(&TokenType::Comma) || self.check(&TokenType::And) {
2417 if self.check(&TokenType::Comma) {
2418 self.advance();
2419 }
2420 if !self.match_token(&[TokenType::And]) {
2421 break;
2422 }
2423 let operator = self.previous().kind.clone();
2424 self.current_island += 1;
2425
2426 if let Some(subj) = self.extract_copular_subject(expr) {
2431 let cop_pos = self.current;
2432 if let Some(p2) = self.try_parse_copular_predicate(subj)? {
2433 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2434 left: expr,
2435 op: operator,
2436 right: p2,
2437 });
2438 continue;
2439 }
2440 self.current = cop_pos;
2441 }
2442
2443 let saved_pos = self.current;
2444 let standard_attempt = self.try_parse(|p| p.parse_atom());
2445
2446 let use_gapping = match &standard_attempt {
2449 Some(right) => {
2450 !self.is_complete_clause(right)
2451 && (self.check(&TokenType::Comma)
2452 || self.check_content_word()
2453 || self.check_preposition()
2454 || self.check_temporal_adverb()
2455 || self.check(&TokenType::Period)
2456 || self.is_at_end())
2457 }
2458 None => true,
2459 };
2460
2461 if !use_gapping {
2462 if let Some(right) = standard_attempt {
2463 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2464 left: expr,
2465 op: operator,
2466 right,
2467 });
2468 }
2469 } else {
2470 self.current = saved_pos;
2471
2472 let borrowed_verb = self.extract_verb_from_expr(expr).ok_or(ParseError {
2473 kind: ParseErrorKind::GappingResolutionFailed,
2474 span: self.current_span(),
2475 })?;
2476
2477 let right = self.parse_gapped_clause(borrowed_verb)?;
2478
2479 expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2480 left: expr,
2481 op: operator,
2482 right,
2483 });
2484 }
2485 }
2486
2487 Ok(expr)
2488 }
2489
2490 fn parse_relative_clause(&mut self, gap_var: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
2491 if matches!(
2498 self.peek().kind,
2499 TokenType::Adverb(_) | TokenType::TemporalAdverb(_)
2500 ) {
2501 let next_opens_predicate = self.tokens.get(self.current + 1).map_or(false, |t| {
2502 self.kind_is_verb(&t.kind)
2503 || matches!(
2504 t.kind,
2505 TokenType::Had
2506 | TokenType::Auxiliary(_)
2507 | TokenType::Not
2508 | TokenType::Is
2509 | TokenType::Are
2510 | TokenType::Was
2511 | TokenType::Were
2512 | TokenType::Can
2513 | TokenType::Could
2514 | TokenType::Must
2515 | TokenType::Should
2516 | TokenType::May
2517 | TokenType::Might
2518 | TokenType::Would
2519 | TokenType::Shall
2520 | TokenType::Cannot
2521 )
2522 });
2523 if next_opens_predicate {
2524 let adv = match self.peek().kind {
2525 TokenType::Adverb(s) | TokenType::TemporalAdverb(s) => s,
2526 _ => unreachable!(),
2527 };
2528 self.advance();
2529 let rest = self.parse_relative_clause(gap_var)?;
2530 let adv_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2531 name: adv,
2532 args: self.ctx.terms.alloc_slice([Term::Variable(gap_var)]),
2533 world: None,
2534 });
2535 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2536 left: rest,
2537 op: TokenType::And,
2538 right: adv_pred,
2539 }));
2540 }
2541 }
2542
2543 if self.check(&TokenType::Had)
2546 && !matches!(
2547 self.tokens.get(self.current + 1).map(|t| &t.kind),
2548 Some(TokenType::Verb { .. })
2549 )
2550 {
2551 let have_lemma = self.interner.intern("Have");
2552 self.tokens[self.current].kind = TokenType::Verb {
2553 lemma: have_lemma,
2554 time: Time::Past,
2555 aspect: crate::lexicon::Aspect::Simple,
2556 class: crate::lexicon::VerbClass::State,
2557 };
2558 }
2559
2560 if matches!(self.peek().kind, TokenType::Auxiliary(_))
2563 && !matches!(
2564 self.tokens.get(self.current + 1).map(|t| &t.kind),
2565 Some(TokenType::Verb { .. })
2566 )
2567 {
2568 let lex = self.interner.resolve(self.peek().lexeme).to_lowercase();
2569 if matches!(lex.as_str(), "did" | "do" | "does") {
2570 let do_lemma = self.interner.intern("Do");
2571 let time = if lex == "did" { Time::Past } else { Time::Present };
2572 self.tokens[self.current].kind = TokenType::Verb {
2573 lemma: do_lemma,
2574 time,
2575 aspect: crate::lexicon::Aspect::Simple,
2576 class: crate::lexicon::VerbClass::Activity,
2577 };
2578 }
2579 }
2580
2581 let head_word = self.interner.resolve(self.peek().lexeme).to_lowercase();
2589 let is_perfect_head =
2590 matches!(head_word.as_str(), "has" | "have") || self.check(&TokenType::Had);
2591 let next_opens_participle = self.tokens.get(self.current + 1).map_or(false, |t| {
2592 self.kind_is_verb(&t.kind) || matches!(t.kind, TokenType::Not)
2593 });
2594 if is_perfect_head && next_opens_participle {
2595 return self.parse_aspect_chain_with_term(Term::Variable(gap_var));
2596 }
2597
2598 if self.check_verb() {
2599 return self.parse_verb_phrase_for_restriction(gap_var);
2600 }
2601
2602 if self.check_modal() {
2606 return self.parse_aspect_chain_with_term(Term::Variable(gap_var));
2607 }
2608
2609 if let TokenType::Auxiliary(time) = self.peek().kind {
2613 self.advance(); let is_be = self.check(&TokenType::Be)
2617 || matches!(self.peek().kind, TokenType::Verb { lemma, .. }
2618 if self.interner.resolve(lemma).eq_ignore_ascii_case("be"));
2619 if is_be {
2620 self.advance();
2621 }
2622 if self.check_verb() {
2623 let restriction = self.parse_verb_phrase_for_restriction(gap_var)?;
2624 return Ok(if time == Time::Future {
2625 self.ctx.exprs.alloc(LogicExpr::Temporal {
2626 operator: TemporalOperator::Future,
2627 body: restriction,
2628 })
2629 } else {
2630 restriction
2631 });
2632 }
2633 if self.check_content_word() || self.check_article() {
2635 let pred_np = self.parse_noun_phrase(false)?;
2636 let base = self.ctx.exprs.alloc(LogicExpr::Predicate {
2637 name: pred_np.noun,
2638 args: self.ctx.terms.alloc_slice([Term::Variable(gap_var)]),
2639 world: None,
2640 });
2641 return Ok(if time == Time::Future {
2642 self.ctx.exprs.alloc(LogicExpr::Temporal {
2643 operator: TemporalOperator::Future,
2644 body: base,
2645 })
2646 } else {
2647 base
2648 });
2649 }
2650 }
2651
2652 if matches!(
2654 self.peek().kind,
2655 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
2656 ) {
2657 let copula_past = matches!(self.peek().kind, TokenType::Was | TokenType::Were);
2658 self.advance(); let negated = self.check(&TokenType::Not);
2660 if negated {
2661 self.advance();
2662 }
2663 let rel_temporal_adv = if let TokenType::TemporalAdverb(s) = self.peek().kind {
2668 self.advance();
2669 Some(s)
2670 } else {
2671 None
2672 };
2673 if matches!(
2680 self.peek().kind,
2681 TokenType::Verb { aspect: crate::lexicon::Aspect::Progressive, .. }
2682 ) {
2683 let vp = self.parse_verb_phrase_for_restriction(gap_var)?;
2684 let vp = self.conjoin_relative_temporal_adverb(vp, gap_var, rel_temporal_adv);
2685 let vp = if negated {
2686 self.ctx.exprs.alloc(LogicExpr::UnaryOp { op: TokenType::Not, operand: vp })
2687 } else {
2688 vp
2689 };
2690 return Ok(if copula_past {
2691 self.ctx.exprs.alloc(LogicExpr::Temporal {
2692 operator: TemporalOperator::Past,
2693 body: vp,
2694 })
2695 } else {
2696 vp
2697 });
2698 }
2699 let pred: &'a LogicExpr<'a> = if self.check_preposition() {
2700 let prep = if let TokenType::Preposition(sym) = self.advance().kind {
2701 sym
2702 } else {
2703 self.interner.intern("At")
2704 };
2705 let obj = self.parse_noun_phrase(false)?;
2706 self.ctx.exprs.alloc(LogicExpr::Predicate {
2707 name: prep,
2708 args: self
2709 .ctx
2710 .terms
2711 .alloc_slice([Term::Variable(gap_var), Term::Constant(obj.noun)]),
2712 world: None,
2713 })
2714 } else if self.check_number() {
2715 let measure = self.parse_measure_phrase()?;
2718 let dim = if self.check_content_word() {
2719 self.consume_content_word()?
2720 } else {
2721 self.interner.intern("Measure")
2722 };
2723 self.ctx.exprs.alloc(LogicExpr::Predicate {
2724 name: dim,
2725 args: self
2726 .ctx
2727 .terms
2728 .alloc_slice([Term::Variable(gap_var), *measure]),
2729 world: None,
2730 })
2731 } else {
2732 let adj = self.consume_content_word()?;
2733 self.ctx.exprs.alloc(LogicExpr::Predicate {
2734 name: adj,
2735 args: self.ctx.terms.alloc_slice([Term::Variable(gap_var)]),
2736 world: None,
2737 })
2738 };
2739 let mut pred = pred;
2742 while self.check_preposition() {
2743 let prep = if let TokenType::Preposition(s) = self.advance().kind {
2744 s
2745 } else {
2746 break;
2747 };
2748 let obj_term = if self.check_number() {
2749 *self.parse_measure_phrase()?
2750 } else if self.check_content_word() || self.check_article() {
2751 Term::Constant(self.parse_noun_phrase(false)?.noun)
2752 } else {
2753 self.current -= 1;
2754 break;
2755 };
2756 let pp = self.ctx.exprs.alloc(LogicExpr::Predicate {
2757 name: prep,
2758 args: self.ctx.terms.alloc_slice([Term::Variable(gap_var), obj_term]),
2759 world: None,
2760 });
2761 pred = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2762 left: pred,
2763 op: TokenType::And,
2764 right: pp,
2765 });
2766 }
2767 let pred = self.conjoin_relative_temporal_adverb(pred, gap_var, rel_temporal_adv);
2768 let pred = if copula_past {
2769 &*self.ctx.exprs.alloc(LogicExpr::Temporal {
2770 operator: TemporalOperator::Past,
2771 body: pred,
2772 })
2773 } else {
2774 pred
2775 };
2776 return Ok(if negated {
2777 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2778 op: TokenType::Not,
2779 operand: pred,
2780 })
2781 } else {
2782 pred
2783 });
2784 }
2785
2786 if self.check(&TokenType::Do) || self.check(&TokenType::Does) {
2788 self.advance(); let is_negated = self.check(&TokenType::Not);
2791 if is_negated {
2792 self.advance(); }
2794
2795 if self.check_verb() {
2796 let verb = self.consume_verb();
2797
2798 let roles = if self.check(&TokenType::Reflexive) {
2800 self.advance(); vec![
2802 (ThematicRole::Agent, Term::Variable(gap_var)),
2803 (ThematicRole::Theme, Term::Variable(gap_var)),
2804 ]
2805 } else if self.check_content_word() || self.check_article() {
2806 let obj = self.parse_noun_phrase(false)?;
2808 vec![
2809 (ThematicRole::Agent, Term::Variable(gap_var)),
2810 (ThematicRole::Theme, Term::Constant(obj.noun)),
2811 ]
2812 } else {
2813 vec![(ThematicRole::Agent, Term::Variable(gap_var))]
2815 };
2816
2817 let event_var = self.get_event_var();
2818 let suppress_existential = self.drs.in_conditional_antecedent();
2819 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
2820 event_var,
2821 verb,
2822 roles: self.ctx.roles.alloc_slice(roles),
2823 modifiers: self.ctx.syms.alloc_slice(vec![]),
2824 suppress_existential,
2825 world: None,
2826 })));
2827
2828 if is_negated {
2829 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2830 op: TokenType::Not,
2831 operand: event,
2832 }));
2833 }
2834 return Ok(event);
2835 }
2836 }
2837
2838 if self.check_content_word() || self.check_article() {
2839 let rel_subject = self.parse_noun_phrase_for_relative()?;
2840
2841 let nested_relative = if matches!(self.peek().kind, TokenType::Article(_)) {
2842 let nested_var = self.next_var_name();
2843 Some((nested_var, self.parse_relative_clause(nested_var)?))
2844 } else {
2845 None
2846 };
2847
2848 if self.check_verb() {
2849 let verb = self.consume_verb();
2850
2851 let stranded_prep: Option<Symbol> = if self.check_preposition()
2856 && !self.check_to_preposition()
2857 {
2858 let has_overt_object = matches!(
2859 self.tokens.get(self.current + 1).map(|t| &t.kind),
2860 Some(TokenType::Article(_))
2861 | Some(TokenType::Noun(_))
2862 | Some(TokenType::ProperName(_))
2863 | Some(TokenType::Number(_))
2864 | Some(TokenType::Cardinal(_))
2865 | Some(TokenType::Pronoun { .. })
2866 | Some(TokenType::Possessive)
2867 );
2868 let prep_sym = match &self.peek().kind {
2869 TokenType::Preposition(s) => Some(*s),
2870 _ => None,
2871 };
2872 if !has_overt_object && prep_sym.is_some() {
2873 self.advance();
2874 prep_sym
2875 } else {
2876 None
2877 }
2878 } else {
2879 None
2880 };
2881
2882 let mut roles: Vec<(ThematicRole, Term<'a>)> =
2883 vec![(ThematicRole::Agent, Term::Constant(rel_subject.noun))];
2884 if stranded_prep.is_none() {
2885 roles.push((ThematicRole::Theme, Term::Variable(gap_var)));
2886 }
2887
2888 while self.check_to_preposition() {
2889 self.advance();
2890 if self.check_content_word() || self.check_article() {
2891 let recipient = self.parse_noun_phrase(false)?;
2892 roles.push((ThematicRole::Recipient, Term::Constant(recipient.noun)));
2893 }
2894 }
2895
2896 let event_var = self.get_event_var();
2897
2898 let mut pp_preds: Vec<&'a LogicExpr<'a>> = Vec::new();
2903 if let Some(prep) = stranded_prep {
2906 pp_preds.push(self.ctx.exprs.alloc(LogicExpr::Predicate {
2907 name: prep,
2908 args: self
2909 .ctx
2910 .terms
2911 .alloc_slice([Term::Variable(event_var), Term::Variable(gap_var)]),
2912 world: None,
2913 }));
2914 }
2915 while self.check_preposition() {
2916 let prep = if let TokenType::Preposition(s) = self.advance().kind {
2917 s
2918 } else {
2919 break;
2920 };
2921 let obj_term = if self.check_number() {
2922 *self.parse_measure_phrase()?
2923 } else if self.check_content_word() || self.check_article() {
2924 Term::Constant(self.parse_noun_phrase(false)?.noun)
2925 } else {
2926 self.current -= 1;
2927 break;
2928 };
2929 pp_preds.push(self.ctx.exprs.alloc(LogicExpr::Predicate {
2930 name: prep,
2931 args: self.ctx.terms.alloc_slice([Term::Variable(event_var), obj_term]),
2932 world: None,
2933 }));
2934 }
2935 let has_pps = !pp_preds.is_empty();
2936
2937 let suppress_existential = self.drs.in_conditional_antecedent() || has_pps;
2941 let neo = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
2942 event_var,
2943 verb,
2944 roles: self.ctx.roles.alloc_slice(roles),
2945 modifiers: self.ctx.syms.alloc_slice(vec![]),
2946 suppress_existential,
2947 world: None,
2948 })));
2949 let mut event_body = neo;
2950 for pp in pp_preds {
2951 event_body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2952 left: event_body,
2953 op: TokenType::And,
2954 right: pp,
2955 });
2956 }
2957 let this_event: &'a LogicExpr<'a> = if has_pps {
2958 self.ctx.exprs.alloc(LogicExpr::Quantifier {
2959 kind: crate::ast::QuantifierKind::Existential,
2960 variable: event_var,
2961 body: event_body,
2962 island_id: self.current_island,
2963 })
2964 } else {
2965 event_body
2966 };
2967
2968 if let Some((nested_var, nested_clause)) = nested_relative {
2969 let type_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2970 name: rel_subject.noun,
2971 args: self.ctx.terms.alloc_slice([Term::Variable(nested_var)]),
2972 world: None,
2973 });
2974
2975 let inner = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2976 left: type_pred,
2977 op: TokenType::And,
2978 right: nested_clause,
2979 });
2980
2981 let combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2982 left: inner,
2983 op: TokenType::And,
2984 right: this_event,
2985 });
2986
2987 return Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
2988 kind: crate::ast::QuantifierKind::Existential,
2989 variable: nested_var,
2990 body: combined,
2991 island_id: self.current_island,
2992 }));
2993 }
2994
2995 return Ok(this_event);
2996 }
2997 }
2998
2999 if self.check_verb() {
3000 return self.parse_verb_phrase_for_restriction(gap_var);
3001 }
3002
3003 let unknown = self.interner.intern("?");
3004 Ok(self.ctx.exprs.alloc(LogicExpr::Atom(unknown)))
3005 }
3006
3007 fn check_ellipsis_auxiliary(&self) -> bool {
3008 matches!(
3009 self.peek().kind,
3010 TokenType::Does | TokenType::Do |
3011 TokenType::Can | TokenType::Could | TokenType::Would |
3012 TokenType::May | TokenType::Must | TokenType::Should
3013 )
3014 }
3015
3016 fn check_ellipsis_terminator(&self) -> bool {
3017 if self.is_at_end() || self.check(&TokenType::Period) {
3018 return true;
3019 }
3020 if self.check_content_word() {
3021 let word = self.interner.resolve(self.peek().lexeme).to_lowercase();
3022 return word == "too" || word == "also";
3023 }
3024 false
3025 }
3026
3027 fn try_parse_ellipsis(&mut self) -> Option<ParseResult<&'a LogicExpr<'a>>> {
3028 if self.last_event_template.is_none() {
3030 return None;
3031 }
3032
3033 let saved_pos = self.current;
3034
3035 let subject_sym = if matches!(self.peek().kind, TokenType::ProperName(_)) {
3038 if let TokenType::ProperName(sym) = self.advance().kind {
3039 sym
3040 } else {
3041 self.current = saved_pos;
3042 return None;
3043 }
3044 } else if self.check_pronoun() {
3045 let token = self.advance().clone();
3046 if let TokenType::Pronoun { gender, number, .. } = token.kind {
3047 match self.resolve_pronoun(gender, number) {
3048 Ok(resolved) => match resolved {
3049 super::ResolvedPronoun::Variable(s) | super::ResolvedPronoun::Constant(s) => s,
3050 },
3051 Err(e) => return Some(Err(e)),
3052 }
3053 } else {
3054 self.current = saved_pos;
3055 return None;
3056 }
3057 } else {
3058 return None;
3059 };
3060
3061 if !self.check_ellipsis_auxiliary() {
3063 self.current = saved_pos;
3064 return None;
3065 }
3066 let aux_token = self.advance().kind.clone();
3067
3068 let is_negated = self.match_token(&[TokenType::Not]);
3070
3071 if !self.check_ellipsis_terminator() {
3073 self.current = saved_pos;
3074 return None;
3075 }
3076
3077 if self.check_content_word() {
3079 let word = self.interner.resolve(self.peek().lexeme).to_lowercase();
3080 if word == "too" || word == "also" {
3081 self.advance();
3082 }
3083 }
3084
3085 let template = self.last_event_template.clone().unwrap();
3087 let event_var = self.get_event_var();
3088 let suppress_existential = self.drs.in_conditional_antecedent();
3089
3090 let mut roles: Vec<(ThematicRole, Term<'a>)> = vec![
3092 (ThematicRole::Agent, Term::Constant(subject_sym))
3093 ];
3094 roles.extend(template.non_agent_roles.iter().cloned());
3095
3096 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
3097 event_var,
3098 verb: template.verb,
3099 roles: self.ctx.roles.alloc_slice(roles),
3100 modifiers: self.ctx.syms.alloc_slice(template.modifiers.clone()),
3101 suppress_existential,
3102 world: None,
3103 })));
3104
3105 let with_modal = match aux_token {
3107 TokenType::Can | TokenType::Could => {
3108 let vector = self.token_to_vector(&aux_token);
3109 self.ctx.modal(vector, neo_event)
3110 }
3111 TokenType::Would | TokenType::May | TokenType::Must | TokenType::Should => {
3112 let vector = self.token_to_vector(&aux_token);
3113 self.ctx.modal(vector, neo_event)
3114 }
3115 _ => neo_event,
3116 };
3117
3118 let result = if is_negated {
3120 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
3121 op: TokenType::Not,
3122 operand: with_modal,
3123 })
3124 } else {
3125 with_modal
3126 };
3127
3128 Some(Ok(result))
3129 }
3130
3131 fn try_parse_of_pair_xor(&mut self) -> ParseResult<Option<&'a LogicExpr<'a>>> {
3132 let start = self.current;
3133
3134 let is_of = {
3136 let text = self.interner.resolve(self.peek().lexeme).to_lowercase();
3137 text == "of" && matches!(self.peek().kind, TokenType::Preposition(_))
3138 };
3139 if !is_of {
3140 return Ok(None);
3141 }
3142
3143 let scan_start = self.current + 1; let comma_pos = {
3148 let mut found = None;
3149 for i in scan_start..self.tokens.len() {
3150 match &self.tokens[i].kind {
3151 TokenType::Period | TokenType::EOF => break,
3152 TokenType::Comma => {
3153 found = Some(i);
3154 break;
3155 }
3156 _ => {}
3157 }
3158 }
3159 match found {
3160 Some(p) => p,
3161 None => return Ok(None),
3162 }
3163 };
3164 let and_pos = {
3165 let mut found = None;
3166 for i in scan_start..comma_pos {
3167 if self.interner.resolve(self.tokens[i].lexeme).to_lowercase() == "and" {
3168 found = Some(i);
3169 }
3170 }
3171 match found {
3172 Some(p) => p,
3173 None => return Ok(None),
3174 }
3175 };
3176 let one_ok = self
3177 .tokens
3178 .get(comma_pos + 1)
3179 .map(|t| self.interner.resolve(t.lexeme).to_lowercase() == "one")
3180 .unwrap_or(false);
3181 if !one_ok {
3182 return Ok(None);
3183 }
3184
3185 fn scan_head<'a, 'ctx, 'int>(p: &mut Parser<'a, 'ctx, 'int>, lo: usize, hi: usize) -> Option<Symbol> {
3191 let mut i = hi;
3192 while i > lo {
3193 i -= 1;
3194 let head = match p.tokens[i].kind {
3195 TokenType::ProperName(s) | TokenType::Noun(s) => Some(s),
3196 TokenType::Verb { lemma, .. } => Some(lemma),
3197 TokenType::Ambiguous { ref primary, ref alternatives } => {
3198 match **primary {
3199 TokenType::Noun(s) | TokenType::ProperName(s) => Some(s),
3200 TokenType::Verb { lemma, .. } => Some(lemma),
3201 _ => alternatives.iter().find_map(|t| match t {
3202 TokenType::Noun(s) | TokenType::ProperName(s) => Some(*s),
3203 TokenType::Verb { lemma, .. } => Some(*lemma),
3204 _ => None,
3205 }),
3206 }
3207 }
3208 _ => None,
3209 };
3210 if let Some(s) = head {
3211 if i > lo {
3212 if let TokenType::Cardinal(n) = p.tokens[i - 1].kind {
3213 return Some(
3214 p.interner
3215 .intern(&format!("{}_{}", n, p.interner.resolve(s))),
3216 );
3217 }
3218 }
3219 return Some(s);
3220 }
3221 }
3222 None
3223 }
3224
3225 fn build_entity<'a, 'ctx, 'int>(
3234 p: &mut Parser<'a, 'ctx, 'int>,
3235 boundary: usize,
3236 ) -> ParseResult<OfEntity<'a>> {
3237 let saved_ctx = p.nominal_np_context;
3243 p.nominal_np_context = true;
3244 let np_result = p.parse_noun_phrase(true);
3245 p.nominal_np_context = saved_ctx;
3246 let np = np_result?;
3247 let has_rel = (p.check(&TokenType::Who)
3251 || p.check(&TokenType::That)
3252 || p.check(&TokenType::Where)
3253 || p.check(&TokenType::Whose))
3254 && p.current < boundary;
3255 let has_reduced = p.peek_heads_reduced_relative_participle() && p.current < boundary;
3256 let is_desc = np.definiteness.is_some()
3257 || !np.adjectives.is_empty()
3258 || np.possessor.is_some()
3259 || !np.pps.is_empty()
3260 || has_rel
3261 || has_reduced;
3262 let (sym, is_var) = if is_desc {
3263 (p.next_var_name(), true)
3264 } else {
3265 (np.noun, false)
3266 };
3267 let term = if is_var {
3268 Term::Variable(sym)
3269 } else {
3270 Term::Constant(sym)
3271 };
3272 let rel = if has_rel {
3273 p.try_attach_relative(term)?
3274 } else {
3275 None
3276 };
3277 let reduced = if has_reduced {
3278 p.try_consume_reduced_relative(term)?
3279 } else {
3280 None
3281 };
3282 if p.current != boundary {
3283 return Err(ParseError {
3284 kind: ParseErrorKind::Custom("of-pair NP misaligned".into()),
3285 span: p.current_span(),
3286 });
3287 }
3288 let restrictor = if is_var {
3289 let mut r = p.nominal_predication(term, &np);
3291 for pp in np.pps {
3292 let pp_sub = p.substitute_pp_placeholder(pp, sym);
3293 r = p.ctx.exprs.alloc(LogicExpr::BinaryOp {
3294 left: r,
3295 op: TokenType::And,
3296 right: pp_sub,
3297 });
3298 }
3299 for rc in rel.into_iter().chain(reduced) {
3300 r = p.ctx.exprs.alloc(LogicExpr::BinaryOp {
3301 left: r,
3302 op: TokenType::And,
3303 right: rc,
3304 });
3305 }
3306 Some(r)
3307 } else {
3308 None
3309 };
3310 Ok(OfEntity { sym, is_var, term, restrictor })
3311 }
3312
3313 self.advance(); let e1 = match self.try_parse(|p| build_entity(p, and_pos)) {
3317 Some(e) => e,
3318 None => {
3319 self.current = and_pos;
3320 match scan_head(self, scan_start, and_pos) {
3321 Some(h) => OfEntity { sym: h, is_var: false, term: Term::Constant(h), restrictor: None },
3322 None => {
3323 self.current = start;
3324 return Ok(None);
3325 }
3326 }
3327 }
3328 };
3329 self.advance(); let e2 = match self.try_parse(|p| build_entity(p, comma_pos)) {
3333 Some(e) => e,
3334 None => {
3335 self.current = comma_pos;
3336 match scan_head(self, and_pos + 1, comma_pos) {
3337 Some(h) => OfEntity { sym: h, is_var: false, term: Term::Constant(h), restrictor: None },
3338 None => {
3339 self.current = start;
3340 return Ok(None);
3341 }
3342 }
3343 }
3344 };
3345 self.advance(); self.advance(); {
3352 let cur_is_classifier = matches!(
3357 self.tokens.get(self.current).map(|t| &t.kind),
3358 Some(TokenType::Noun(_))
3359 ) || self
3360 .tokens
3361 .get(self.current)
3362 .map(|t| {
3363 matches!(
3364 self.interner.resolve(t.lexeme).to_lowercase().as_str(),
3365 "type" | "kind" | "sort" | "variety" | "category" | "version"
3366 )
3367 })
3368 .unwrap_or(false);
3369 if cur_is_classifier
3370 && matches!(
3371 self.tokens.get(self.current + 1).map(|t| &t.kind),
3372 Some(TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
3373 | TokenType::Verb { .. } | TokenType::Auxiliary(_))
3374 )
3375 {
3376 self.advance(); }
3378 }
3379
3380 let other_and_pos = {
3386 let mut found = None;
3387 let mut i = self.current;
3388 while i + 2 < self.tokens.len() {
3389 if matches!(self.tokens[i].kind, TokenType::Period | TokenType::EOF) {
3390 break;
3391 }
3392 if matches!(self.tokens[i].kind, TokenType::And)
3393 && matches!(self.tokens[i + 1].kind, TokenType::Article(_))
3394 && self
3395 .interner
3396 .resolve(self.tokens[i + 2].lexeme)
3397 .eq_ignore_ascii_case("other")
3398 {
3399 found = Some(i);
3400 break;
3401 }
3402 i += 1;
3403 }
3404 found
3405 };
3406 let saved_and_tok = other_and_pos.map(|p| self.tokens[p].clone());
3407 if let Some(p) = other_and_pos {
3408 let mut t = self.tokens[p].clone();
3409 t.kind = TokenType::Period;
3410 self.tokens[p] = t;
3411 }
3412
3413 macro_rules! restore_and {
3414 () => {
3415 if let (Some(p), Some(tok)) = (other_and_pos, saved_and_tok.as_ref()) {
3416 self.tokens[p] = tok.clone();
3417 }
3418 };
3419 }
3420
3421 macro_rules! vp_with {
3424 ($start:expr, $e:expr) => {{
3425 self.current = $start;
3426 let __r = if $e.is_var {
3427 self.parse_predicate_with_subject_as_var($e.sym)
3428 } else {
3429 self.parse_predicate_with_subject($e.sym)
3430 };
3431 match __r {
3432 Ok(v) => v,
3433 Err(err) => {
3434 restore_and!();
3435 return Err(err);
3436 }
3437 }
3438 }};
3439 }
3440
3441 let vp1_start = self.current;
3443 let vp1_e1 = vp_with!(vp1_start, e1);
3444
3445 if self.check(&TokenType::Comma) { self.advance(); }
3448 if let Some(marker) = other_and_pos {
3449 if self.current != marker || !self.check(&TokenType::Period) {
3450 restore_and!();
3451 self.current = start;
3452 return Ok(None);
3453 }
3454 self.advance(); } else {
3456 if self.interner.resolve(self.peek().lexeme).to_lowercase() != "and" {
3457 self.current = start;
3458 return Ok(None);
3459 }
3460 self.advance(); }
3462
3463 if !self.check_article() {
3465 restore_and!();
3466 self.current = start;
3467 return Ok(None);
3468 }
3469 self.advance(); if self.interner.resolve(self.peek().lexeme).to_lowercase() != "other" {
3473 restore_and!();
3474 self.current = start;
3475 return Ok(None);
3476 }
3477 self.advance(); {
3481 let cur_is_classifier = matches!(
3486 self.tokens.get(self.current).map(|t| &t.kind),
3487 Some(TokenType::Noun(_))
3488 ) || self
3489 .tokens
3490 .get(self.current)
3491 .map(|t| {
3492 matches!(
3493 self.interner.resolve(t.lexeme).to_lowercase().as_str(),
3494 "type" | "kind" | "sort" | "variety" | "category" | "version"
3495 )
3496 })
3497 .unwrap_or(false);
3498 if cur_is_classifier
3499 && matches!(
3500 self.tokens.get(self.current + 1).map(|t| &t.kind),
3501 Some(TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
3502 | TokenType::Verb { .. } | TokenType::Auxiliary(_))
3503 )
3504 {
3505 self.advance(); }
3507 }
3508
3509 let vp2_start = self.current;
3511 let vp2_e2 = vp_with!(vp2_start, e2);
3512 let end_pos = self.current;
3513 let vp1_e2 = vp_with!(vp1_start, e2);
3514 let vp2_e1 = vp_with!(vp2_start, e1);
3515 self.current = end_pos;
3516
3517 restore_and!();
3520
3521 let branch1 = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3523 left: vp1_e1,
3524 op: TokenType::And,
3525 right: vp2_e2,
3526 });
3527 let branch2 = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3528 left: vp1_e2,
3529 op: TokenType::And,
3530 right: vp2_e1,
3531 });
3532 let mut result: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3533 left: branch1,
3534 op: TokenType::Or,
3535 right: branch2,
3536 });
3537
3538 if e1.is_var || e2.is_var {
3543 let identity = self.ctx.exprs.alloc(LogicExpr::Identity {
3544 left: self.ctx.terms.alloc(e1.term),
3545 right: self.ctx.terms.alloc(e2.term),
3546 });
3547 let ineq = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
3548 op: TokenType::Not,
3549 operand: identity,
3550 });
3551 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3552 left: ineq,
3553 op: TokenType::And,
3554 right: result,
3555 });
3556 }
3557
3558 if let Some(r2) = e2.restrictor {
3562 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3563 left: r2,
3564 op: TokenType::And,
3565 right: result,
3566 });
3567 }
3568 if let Some(r1) = e1.restrictor {
3569 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3570 left: r1,
3571 op: TokenType::And,
3572 right: result,
3573 });
3574 }
3575 if e2.is_var {
3576 result = self.ctx.exprs.alloc(LogicExpr::Quantifier {
3577 kind: QuantifierKind::Existential,
3578 variable: e2.sym,
3579 body: result,
3580 island_id: self.current_island,
3581 });
3582 }
3583 if e1.is_var {
3584 result = self.ctx.exprs.alloc(LogicExpr::Quantifier {
3585 kind: QuantifierKind::Existential,
3586 variable: e1.sym,
3587 body: result,
3588 island_id: self.current_island,
3589 });
3590 }
3591 Ok(Some(result))
3592 }
3593}
3594
3595impl<'a, 'ctx, 'int> Parser<'a, 'ctx, 'int> {
3597 fn extract_neo_event_verb(&self, expr: &LogicExpr<'a>) -> Option<Symbol> {
3599 match expr {
3600 LogicExpr::NeoEvent(data) => Some(data.verb),
3601 LogicExpr::Quantifier { body, .. } => self.extract_neo_event_verb(body),
3602 LogicExpr::BinaryOp { left, right, .. } => {
3603 self.extract_neo_event_verb(left)
3604 .or_else(|| self.extract_neo_event_verb(right))
3605 }
3606 LogicExpr::Temporal { body, .. } => self.extract_neo_event_verb(body),
3607 LogicExpr::Aspectual { body, .. } => self.extract_neo_event_verb(body),
3608 _ => None,
3609 }
3610 }
3611
3612 fn build_gapped_roles(
3615 &self,
3616 subject_term: Term<'a>,
3617 np_args: &[Term<'a>],
3618 pp_args: &[(Symbol, Term<'a>)],
3619 template: &Option<EventTemplate<'a>>,
3620 ) -> Vec<(ThematicRole, Term<'a>)> {
3621 if let Some(tmpl) = template {
3627 if let Some(shared_agent) = &tmpl.agent {
3628 let np_template_roles: Vec<_> = tmpl
3629 .non_agent_roles
3630 .iter()
3631 .filter(|(r, _)| {
3632 matches!(
3633 r,
3634 ThematicRole::Theme | ThematicRole::Recipient | ThematicRole::Patient
3635 )
3636 })
3637 .collect();
3638 if np_template_roles.len() == 1 && np_args.is_empty() && pp_args.is_empty() {
3643 let (role, _) = np_template_roles[0];
3644 return vec![
3645 (ThematicRole::Agent, shared_agent.clone()),
3646 (*role, subject_term),
3647 ];
3648 }
3649 if np_template_roles.len() >= 2 && 1 + np_args.len() == np_template_roles.len() {
3650 let mut roles = vec![(ThematicRole::Agent, shared_agent.clone())];
3651 let remnants: Vec<Term<'a>> = std::iter::once(subject_term)
3652 .chain(np_args.iter().cloned())
3653 .collect();
3654 for ((role, _), arg) in np_template_roles.iter().zip(remnants.iter()) {
3655 roles.push((*role, arg.clone()));
3656 }
3657 if pp_args.is_empty() {
3659 for (role, term) in tmpl.non_agent_roles.iter().filter(|(r, _)| {
3660 matches!(
3661 r,
3662 ThematicRole::Goal
3663 | ThematicRole::Source
3664 | ThematicRole::Location
3665 | ThematicRole::Instrument
3666 )
3667 }) {
3668 roles.push((*role, term.clone()));
3669 }
3670 } else {
3671 for (prep, term) in pp_args {
3672 roles.push((self.preposition_to_role(*prep), term.clone()));
3673 }
3674 }
3675 return roles;
3676 }
3677 }
3678 }
3679
3680 let mut roles = vec![(ThematicRole::Agent, subject_term)];
3681
3682 match template {
3683 Some(tmpl) => {
3684 let template_roles = &tmpl.non_agent_roles;
3685
3686 let np_template_roles: Vec<_> = template_roles
3688 .iter()
3689 .filter(|(r, _)| {
3690 matches!(
3691 r,
3692 ThematicRole::Theme | ThematicRole::Recipient | ThematicRole::Patient
3693 )
3694 })
3695 .collect();
3696
3697 let pp_template_roles: Vec<_> = template_roles
3698 .iter()
3699 .filter(|(r, _)| {
3700 matches!(
3701 r,
3702 ThematicRole::Goal
3703 | ThematicRole::Source
3704 | ThematicRole::Location
3705 | ThematicRole::Instrument
3706 )
3707 })
3708 .collect();
3709
3710 match (np_template_roles.len(), np_args.len()) {
3712 (0, 0) => {} (_, 0) => {
3714 for (role, term) in &np_template_roles {
3716 roles.push((*role, term.clone()));
3717 }
3718 }
3719 (n, 1) if n > 0 => {
3720 for (role, term) in np_template_roles.iter().take(n - 1) {
3722 roles.push((*role, term.clone()));
3723 }
3724 if let Some((last_role, _)) = np_template_roles.last() {
3725 roles.push((*last_role, np_args[0].clone()));
3726 }
3727 }
3728 (n, m) if m == n => {
3729 for ((role, _), arg) in np_template_roles.iter().zip(np_args.iter()) {
3731 roles.push((*role, arg.clone()));
3732 }
3733 }
3734 (_, _) => {
3735 for (i, arg) in np_args.iter().enumerate() {
3737 let role = np_template_roles
3738 .get(i)
3739 .map(|(r, _)| *r)
3740 .unwrap_or(ThematicRole::Theme);
3741 roles.push((role, arg.clone()));
3742 }
3743 }
3744 }
3745
3746 if pp_args.is_empty() {
3748 for (role, term) in &pp_template_roles {
3750 roles.push((*role, term.clone()));
3751 }
3752 } else {
3753 for (prep, term) in pp_args {
3755 let role = self.preposition_to_role(*prep);
3756 roles.push((role, term.clone()));
3757 }
3758 }
3759 }
3760 None => {
3761 for arg in np_args {
3763 roles.push((ThematicRole::Theme, arg.clone()));
3764 }
3765 for (prep, term) in pp_args {
3766 let role = self.preposition_to_role(*prep);
3767 roles.push((role, term.clone()));
3768 }
3769 }
3770 }
3771 roles
3772 }
3773
3774 fn preposition_to_role(&self, prep: Symbol) -> ThematicRole {
3776 let prep_str = self.interner.resolve(prep).to_lowercase();
3777 match prep_str.as_str() {
3778 "to" | "toward" | "towards" => ThematicRole::Goal,
3779 "from" => ThematicRole::Source,
3780 "in" | "on" | "at" => ThematicRole::Location,
3781 "with" | "by" => ThematicRole::Instrument,
3782 _ => ThematicRole::Location, }
3784 }
3785
3786 fn is_temporal_modifier(&self, sym: Symbol) -> bool {
3788 let s = self.interner.resolve(sym).to_lowercase();
3789 matches!(
3790 s.as_str(),
3791 "yesterday" | "today" | "tomorrow" | "now" | "then" | "past" | "future"
3792 )
3793 }
3794}