1use super::clause::ClauseParsing;
25use super::modal::ModalParsing;
26use super::noun::NounParsing;
27use super::pragmatics::PragmaticsParsing;
28use super::quantifier::QuantifierParsing;
29use super::{ParseResult, Parser};
30use crate::ast::{
31 AspectOperator, LogicExpr, NeoEventData, NounPhrase, QuantifierKind, TemporalOperator, Term,
32 ThematicRole,
33};
34use crate::drs::{Gender, Number, ReferentSource};
35use crate::error::{ParseError, ParseErrorKind};
36use logicaffeine_base::Symbol;
37use crate::lexer::Lexer;
38use crate::lexicon::{Aspect, Definiteness, Time};
39use crate::token::{FocusKind, Span, Token, TokenType};
40
41use crate::ast::Stmt;
42
43pub trait LogicVerbParsing<'a, 'ctx, 'int> {
48 fn parse_predicate_with_subject(&mut self, subject_symbol: Symbol)
50 -> ParseResult<&'a LogicExpr<'a>>;
51 fn parse_predicate_with_subject_as_var(&mut self, subject_symbol: Symbol)
53 -> ParseResult<&'a LogicExpr<'a>>;
54 fn try_parse_plural_subject(&mut self, first_subject: &NounPhrase<'a>)
57 -> Result<Option<&'a LogicExpr<'a>>, ParseError>;
58 fn parse_control_structure(
60 &mut self,
61 subject: &NounPhrase<'a>,
62 verb: Symbol,
63 verb_time: Time,
64 ) -> ParseResult<&'a LogicExpr<'a>>;
65 fn is_control_verb(&self, verb: Symbol) -> bool;
67 fn build_group_predicate(
69 &mut self,
70 subjects: &[Symbol],
71 verb: Symbol,
72 verb_time: Time,
73 ) -> &'a LogicExpr<'a>;
74 fn build_group_transitive(
76 &mut self,
77 subjects: &[Symbol],
78 objects: &[Symbol],
79 verb: Symbol,
80 verb_time: Time,
81 ) -> &'a LogicExpr<'a>;
82}
83
84pub trait ImperativeVerbParsing<'a, 'ctx, 'int> {
88 fn parse_statement_with_subject(&mut self, subject_symbol: Symbol)
90 -> ParseResult<Stmt<'a>>;
91}
92
93impl<'a, 'ctx, 'int> Parser<'a, 'ctx, 'int> {
94 pub(super) fn nominal_predication(
103 &mut self,
104 subject_term: Term<'a>,
105 pred_np: &NounPhrase<'a>,
106 ) -> &'a LogicExpr<'a> {
107 let mut result = self.ctx.exprs.alloc(LogicExpr::Predicate {
108 name: pred_np.noun,
109 args: self.ctx.terms.alloc_slice([subject_term]),
110 world: None,
111 });
112
113 for &adj in pred_np.adjectives {
114 let adj_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
115 name: adj,
116 args: self.ctx.terms.alloc_slice([subject_term]),
117 world: None,
118 });
119 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
120 left: result,
121 op: TokenType::And,
122 right: adj_pred,
123 });
124 }
125
126 if let Some(possessor) = pred_np.possessor {
127 let poss_logic = self.possessor_predication(possessor, subject_term);
128 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
129 left: result,
130 op: TokenType::And,
131 right: poss_logic,
132 });
133 }
134
135 result
136 }
137
138 pub(super) fn possessor_entity(
156 &mut self,
157 np: &NounPhrase<'a>,
158 ) -> (Term<'a>, Option<(Symbol, &'a LogicExpr<'a>)>) {
159 let is_descriptive = !np.adjectives.is_empty()
160 || np.possessor.is_some()
161 || !np.pps.is_empty();
162 if !is_descriptive {
163 return (Term::Constant(np.noun), None);
164 }
165 let pvar = self.next_var_name();
166 let mut restr = self.nominal_predication(Term::Variable(pvar), np);
167 for pp in np.pps {
168 let pp_sub = self.substitute_pp_placeholder(pp, pvar);
169 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
170 left: restr,
171 op: TokenType::And,
172 right: pp_sub,
173 });
174 }
175 (Term::Variable(pvar), Some((pvar, restr)))
176 }
177
178 pub(super) fn wrap_in_possessor_entity(
183 &mut self,
184 restr: Option<(Symbol, &'a LogicExpr<'a>)>,
185 relation: &'a LogicExpr<'a>,
186 ) -> &'a LogicExpr<'a> {
187 match restr {
188 None => relation,
189 Some((pvar, restrictor)) => {
190 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
191 left: restrictor,
192 op: TokenType::And,
193 right: relation,
194 });
195 self.ctx.exprs.alloc(LogicExpr::Quantifier {
196 kind: QuantifierKind::Existential,
197 variable: pvar,
198 body,
199 island_id: self.current_island,
200 })
201 }
202 }
203 }
204
205 pub(super) fn possessor_predication(
215 &mut self,
216 possessor: &NounPhrase<'a>,
217 possessed_term: Term<'a>,
218 ) -> &'a LogicExpr<'a> {
219 let (poss_term, restr) = self.possessor_entity(possessor);
220 let possesses = self.ctx.exprs.alloc(LogicExpr::Predicate {
221 name: self.interner.intern("Possesses"),
222 args: self.ctx.terms.alloc_slice([poss_term, possessed_term]),
223 world: None,
224 });
225 self.wrap_in_possessor_entity(restr, possesses)
226 }
227
228 pub(super) fn nominal_predication_with_pps(
234 &mut self,
235 subject_term: Term<'a>,
236 pred_np: &NounPhrase<'a>,
237 ) -> &'a LogicExpr<'a> {
238 let mut result = self.nominal_predication(subject_term, pred_np);
239 for pp in pred_np.pps {
240 let pp_sub = self.substitute_pp_self_term(pp, subject_term);
244 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
245 left: result,
246 op: TokenType::And,
247 right: pp_sub,
248 });
249 }
250 result
251 }
252
253 pub(super) fn pp_object_modifier_preds(
259 &mut self,
260 pp_object: &NounPhrase<'a>,
261 ) -> Vec<&'a LogicExpr<'a>> {
262 let mut out: Vec<&'a LogicExpr<'a>> = Vec::new();
263 for &adj in pp_object.adjectives {
264 out.push(self.ctx.exprs.alloc(LogicExpr::Predicate {
265 name: adj,
266 args: self.ctx.terms.alloc_slice([Term::Constant(pp_object.noun)]),
267 world: None,
268 }));
269 }
270 let placeholder = self.interner.intern("_PP_SELF_");
271 for nested in pp_object.pps {
272 if let LogicExpr::Predicate { name, args, world } = nested {
273 let new_args: Vec<Term<'a>> = args
274 .iter()
275 .map(|a| match a {
276 Term::Variable(v) if *v == placeholder => Term::Constant(pp_object.noun),
277 other => *other,
278 })
279 .collect();
280 out.push(self.ctx.exprs.alloc(LogicExpr::Predicate {
281 name: *name,
282 args: self.ctx.terms.alloc_slice(new_args),
283 world: *world,
284 }));
285 }
286 }
287 out
288 }
289
290 pub(super) fn attach_pp_object_modifiers(
294 &mut self,
295 mut pred: &'a LogicExpr<'a>,
296 pp_object: &NounPhrase<'a>,
297 ) -> &'a LogicExpr<'a> {
298 for m in self.pp_object_modifier_preds(pp_object) {
299 pred = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
300 left: pred,
301 op: TokenType::And,
302 right: m,
303 });
304 }
305 pred
306 }
307
308 pub(super) fn attach_trailing_event_pps(
315 &mut self,
316 mut event: &'a LogicExpr<'a>,
317 event_var: Symbol,
318 ) -> ParseResult<&'a LogicExpr<'a>> {
319 while self.check_preposition() || self.check_to() {
320 if self.check_preposition_is("within")
322 && matches!(
323 self.tokens.get(self.current + 1).map(|t| &t.kind),
324 Some(TokenType::Cardinal(_)) | Some(TokenType::Number(_))
325 )
326 {
327 break;
328 }
329 let object_follows = matches!(
331 self.tokens.get(self.current + 1).map(|t| &t.kind),
332 Some(TokenType::Article(_))
333 | Some(TokenType::Noun(_))
334 | Some(TokenType::ProperName(_))
335 | Some(TokenType::All)
336 | Some(TokenType::Some)
337 | Some(TokenType::Any)
338 | Some(TokenType::Cardinal(_))
339 | Some(TokenType::Number(_))
340 | Some(TokenType::Pronoun { .. })
341 );
342 if !object_follows {
343 break;
344 }
345 let prep_token = self.advance().clone();
346 let prep_name = match prep_token.kind {
347 TokenType::Preposition(sym) => sym,
348 TokenType::To => self.interner.intern("To"),
349 _ => break,
350 };
351 if matches!(
357 self.peek().kind,
358 TokenType::Some | TokenType::Any | TokenType::All | TokenType::No
359 ) {
360 self.advance();
361 }
362 let pp_np = self.parse_noun_phrase(false)?;
363 let pp_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
364 name: prep_name,
365 args: self
366 .ctx
367 .terms
368 .alloc_slice([Term::Variable(event_var), Term::Constant(pp_np.noun)]),
369 world: None,
370 });
371 event = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
372 left: event,
373 op: TokenType::And,
374 right: pp_pred,
375 });
376 }
377 Ok(event)
378 }
379
380 pub(super) fn substitute_pp_self_term(
385 &mut self,
386 pp: &'a LogicExpr<'a>,
387 term: Term<'a>,
388 ) -> &'a LogicExpr<'a> {
389 let placeholder = self.interner.intern("_PP_SELF_");
390 match pp {
391 LogicExpr::Predicate { name, args, .. } => {
392 let new_args: Vec<Term<'a>> = args
393 .iter()
394 .map(|a| match a {
395 Term::Variable(v) if *v == placeholder => term,
396 other => *other,
397 })
398 .collect();
399 self.ctx.exprs.alloc(LogicExpr::Predicate {
400 name: *name,
401 args: self.ctx.terms.alloc_slice(new_args),
402 world: None,
403 })
404 }
405 LogicExpr::BinaryOp { left, op, right } => {
406 let l = self.substitute_pp_self_term(left, term);
407 let r = self.substitute_pp_self_term(right, term);
408 self.ctx.exprs.alloc(LogicExpr::BinaryOp { left: l, op: op.clone(), right: r })
409 }
410 LogicExpr::UnaryOp { op, operand } => {
411 let o = self.substitute_pp_self_term(operand, term);
412 self.ctx.exprs.alloc(LogicExpr::UnaryOp { op: op.clone(), operand: o })
413 }
414 LogicExpr::Quantifier { kind, variable, body, island_id } => {
415 let b = self.substitute_pp_self_term(body, term);
416 self.ctx.exprs.alloc(LogicExpr::Quantifier {
417 kind: *kind,
418 variable: *variable,
419 body: b,
420 island_id: *island_id,
421 })
422 }
423 LogicExpr::Temporal { operator, body } => {
424 let b = self.substitute_pp_self_term(body, term);
425 self.ctx.exprs.alloc(LogicExpr::Temporal { operator: *operator, body: b })
426 }
427 LogicExpr::NeoEvent(data) => {
428 let new_roles: Vec<(ThematicRole, Term<'a>)> = data
429 .roles
430 .iter()
431 .map(|(role, t)| {
432 let nt = match t {
433 Term::Variable(v) if *v == placeholder => term,
434 other => *other,
435 };
436 (*role, nt)
437 })
438 .collect();
439 self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
440 event_var: data.event_var,
441 verb: data.verb,
442 roles: self.ctx.roles.alloc_slice(new_roles),
443 modifiers: data.modifiers,
444 suppress_existential: data.suppress_existential,
445 world: data.world,
446 })))
447 }
448 _ => pp,
449 }
450 }
451
452 pub(super) fn try_attach_relative(
466 &mut self,
467 term: Term<'a>,
468 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
469 if let Term::Constant(s) | Term::Variable(s) = term {
470 if self.check(&TokenType::Who) || self.check(&TokenType::That) {
471 self.advance();
472 return Ok(Some(self.parse_relative_clause(s)?));
473 } else if self.check(&TokenType::Where) {
474 return Ok(Some(self.parse_where_relative(s)?));
475 } else if self.check(&TokenType::Whose) {
476 return Ok(Some(self.parse_whose_relative(s)?));
477 }
478 }
479 Ok(None)
480 }
481
482 pub(super) fn conjoin_trailing_relative(
483 &mut self,
484 pred: &'a LogicExpr<'a>,
485 subject_term: Term<'a>,
486 ) -> ParseResult<&'a LogicExpr<'a>> {
487 let mut pred = pred;
488 if let Some(rc) = self.try_attach_relative(subject_term.clone())? {
490 pred = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
491 left: pred,
492 op: TokenType::And,
493 right: rc,
494 });
495 }
496 if let Some(rr) = self.try_consume_reduced_relative(subject_term)? {
501 pred = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
502 left: pred,
503 op: TokenType::And,
504 right: rr,
505 });
506 }
507 Ok(pred)
508 }
509
510 pub(super) fn conjoin_relative_temporal_adverb(
515 &mut self,
516 pred: &'a LogicExpr<'a>,
517 gap_var: Symbol,
518 adv: Option<Symbol>,
519 ) -> &'a LogicExpr<'a> {
520 match adv {
521 Some(a) => {
522 let adv_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
523 name: a,
524 args: self.ctx.terms.alloc_slice([Term::Variable(gap_var)]),
525 world: None,
526 });
527 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
528 left: pred,
529 op: TokenType::And,
530 right: adv_pred,
531 })
532 }
533 None => pred,
534 }
535 }
536
537 pub(super) fn copula_temporal_adverb_complement(
548 &mut self,
549 subject_term: Term<'a>,
550 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
551 let adv = match self.peek().kind {
552 TokenType::TemporalAdverb(s) => s,
553 _ => return Ok(None),
554 };
555 self.advance();
556 let adv_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
557 name: adv,
558 args: self.ctx.terms.alloc_slice([subject_term.clone()]),
559 world: None,
560 });
561 if self.check_article() || self.check_content_word() {
562 let saved_ctx = self.nominal_np_context;
563 self.nominal_np_context = true;
564 let comp_np_result = self.parse_noun_phrase(true);
565 self.nominal_np_context = saved_ctx;
566 let comp_np = comp_np_result?;
567 let comp_pred = self.nominal_predication_with_pps(subject_term.clone(), &comp_np);
568 let comp_pred = self.conjoin_trailing_relative(comp_pred, subject_term.clone())?;
569 return Ok(Some(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
570 left: comp_pred,
571 op: TokenType::And,
572 right: adv_pred,
573 })));
574 }
575 Ok(Some(adv_pred))
576 }
577
578 pub(super) fn augment_with_np_restrictions(
584 &mut self,
585 expr: &'a LogicExpr<'a>,
586 np: &NounPhrase<'a>,
587 ) -> &'a LogicExpr<'a> {
588 let entity = Term::Constant(np.noun);
589 let mut result = expr;
590 if let Some(possessor) = np.possessor {
591 let possesses = self.interner.intern("Possesses");
592 let poss = self.ctx.exprs.alloc(LogicExpr::Predicate {
593 name: possesses,
594 args: self
595 .ctx
596 .terms
597 .alloc_slice([Term::Constant(possessor.noun), entity]),
598 world: None,
599 });
600 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
601 left: result,
602 op: TokenType::And,
603 right: poss,
604 });
605 }
606 if !np.pps.is_empty() {
607 let placeholder = self.interner.intern("_PP_SELF_");
608 for pp in np.pps {
609 let pp_sub = match pp {
610 LogicExpr::Predicate { name, args, world } => {
611 let new_args: Vec<Term<'a>> = args
612 .iter()
613 .map(|a| match a {
614 Term::Variable(v) if *v == placeholder => entity,
615 other => *other,
616 })
617 .collect();
618 self.ctx.exprs.alloc(LogicExpr::Predicate {
619 name: *name,
620 args: self.ctx.terms.alloc_slice(new_args),
621 world: *world,
622 })
623 }
624 other => *other,
625 };
626 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
627 left: result,
628 op: TokenType::And,
629 right: pp_sub,
630 });
631 }
632 }
633 result
634 }
635
636 pub(super) fn finish_copula(
639 &self,
640 base: &'a LogicExpr<'a>,
641 copula_time: Time,
642 is_negated: bool,
643 copula_temporal: Option<super::CopulaTemporal>,
644 ) -> &'a LogicExpr<'a> {
645 let with_time = if copula_time == Time::Past {
646 self.ctx.exprs.alloc(LogicExpr::Temporal {
647 operator: TemporalOperator::Past,
648 body: base,
649 })
650 } else {
651 base
652 };
653 let with_neg = if is_negated {
654 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
655 op: TokenType::Not,
656 operand: with_time,
657 })
658 } else {
659 with_time
660 };
661 match copula_temporal {
662 Some(super::CopulaTemporal::Always) => self.ctx.exprs.alloc(LogicExpr::Temporal {
663 operator: TemporalOperator::Always,
664 body: with_neg,
665 }),
666 Some(super::CopulaTemporal::Never) => {
667 let negated = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
668 op: TokenType::Not,
669 operand: with_time,
670 });
671 self.ctx.exprs.alloc(LogicExpr::Temporal {
672 operator: TemporalOperator::Always,
673 body: negated,
674 })
675 }
676 Some(super::CopulaTemporal::Eventually) => self.ctx.exprs.alloc(LogicExpr::Temporal {
677 operator: TemporalOperator::Eventually,
678 body: with_neg,
679 }),
680 None => with_neg,
681 }
682 }
683
684 pub(super) fn try_arithmetic_comparative(
693 &mut self,
694 verb: Symbol,
695 subject_term: Term<'a>,
696 verb_time: Time,
697 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
698 let is_unit = |k: &TokenType| {
699 matches!(
700 k,
701 TokenType::Noun(_)
702 | TokenType::Adjective(_)
703 | TokenType::NonIntersectiveAdjective(_)
704 | TokenType::Verb { .. }
705 | TokenType::ProperName(_)
706 | TokenType::Performative(_)
707 | TokenType::Ambiguous { .. }
708 | TokenType::CalendarUnit(_)
712 | TokenType::DurationLiteral { .. }
713 )
714 };
715 let cp = self.checkpoint();
716
717 if matches!(self.peek().kind, TokenType::Preposition(s)
723 if matches!(self.interner.resolve(s).to_lowercase().as_str(), "for" | "at" | "with"))
724 {
725 self.advance();
726 }
727
728 if matches!(self.peek().kind, TokenType::Article(crate::lexicon::Definiteness::Indefinite)) {
733 self.advance();
734 }
735
736 let count_kind: Option<crate::ast::NumberKind> = match self.peek().kind {
738 TokenType::Number(s) => {
739 self.advance();
740 let raw = self.interner.resolve(s);
741 Some(if let Ok(n) = raw.parse::<i64>() {
742 crate::ast::NumberKind::Integer(n)
743 } else if raw.contains('.') {
744 crate::ast::NumberKind::Real(raw.parse().unwrap_or(0.0))
745 } else {
746 crate::ast::NumberKind::Symbolic(s)
747 })
748 }
749 TokenType::Cardinal(n) => {
750 self.advance();
751 Some(crate::ast::NumberKind::Integer(n as i64))
752 }
753 _ => None,
754 };
755
756 let mut unit_sym: Option<Symbol> = None;
758 if count_kind.is_some()
759 && is_unit(&self.peek().kind)
760 && matches!(
761 self.tokens.get(self.current + 1).map(|t| &t.kind),
762 Some(TokenType::Comparative(_))
763 )
764 {
765 unit_sym = Some(self.consume_content_word()?);
766 }
767
768 let mut has_vague = false;
776 if unit_sym.is_none() && count_kind.is_none() {
777 let mut k = self.current;
782 while self.tokens.get(k).map_or(false, |t| {
783 matches!(t.kind, TokenType::Noun(_) | TokenType::Ambiguous { .. })
784 && !crate::lexicon::is_degree_adverb(
785 &self.interner.resolve(t.lexeme).to_lowercase(),
786 )
787 }) {
788 k += 1;
789 }
790 let dim_end = k;
791 let has_dim = dim_end > self.current;
792 let degree = !matches!(
793 self.tokens.get(k).map(|t| &t.kind),
794 Some(TokenType::Comparative(_))
795 ) && matches!(
796 self.tokens.get(k + 1).map(|t| &t.kind),
797 Some(TokenType::Comparative(_))
798 );
799 let comp_at = if degree { k + 1 } else { k };
800 let comp_here = matches!(
801 self.tokens.get(comp_at).map(|t| &t.kind),
802 Some(TokenType::Comparative(_))
803 );
804 if has_dim && comp_here {
805 let mut dim: Option<Symbol> = None;
806 while self.current < dim_end {
807 let n = self.consume_content_word()?;
808 dim = Some(match dim {
809 Some(d) => self.interner.intern(&format!(
810 "{}_{}",
811 self.interner.resolve(d),
812 self.interner.resolve(n)
813 )),
814 None => n,
815 });
816 }
817 if degree {
818 self.advance(); has_vague = true;
820 }
821 unit_sym = dim;
822 }
823 }
824 if unit_sym.is_none()
826 && !matches!(self.peek().kind, TokenType::Comparative(_))
827 && matches!(
828 self.tokens.get(self.current + 1).map(|t| &t.kind),
829 Some(TokenType::Comparative(_))
830 )
831 {
832 self.advance(); has_vague = true;
834 }
835
836 let comp_adj = match self.peek().kind {
838 TokenType::Comparative(a) => {
839 self.advance();
840 a
841 }
842 _ => {
843 self.restore(cp);
844 return Ok(None);
845 }
846 };
847
848 {
855 let mut k = self.current;
856 while self.tokens.get(k).map_or(false, |t| is_unit(&t.kind)) {
857 k += 1;
858 }
859 let unit_end = k;
860 let infinitive: Option<Symbol> = if unit_end > self.current
865 && matches!(self.tokens.get(unit_end).map(|t| &t.kind), Some(TokenType::To))
866 {
867 match self.tokens.get(unit_end + 1).map(|t| t.kind.clone()) {
868 Some(TokenType::Verb { lemma, .. }) => Some(lemma),
869 _ => None,
870 }
871 } else {
872 None
873 };
874 let after = if infinitive.is_some() { unit_end + 2 } else { unit_end };
875 if unit_end > self.current
876 && matches!(self.tokens.get(after).map(|t| &t.kind), Some(TokenType::Than))
877 {
878 let mut dim = self.consume_content_word()?;
879 while self.current < unit_end {
880 let next = self.consume_content_word()?;
881 dim = self.interner.intern(&format!(
882 "{}_{}",
883 self.interner.resolve(dim),
884 self.interner.resolve(next)
885 ));
886 }
887 if let Some(vlemma) = infinitive {
888 self.advance(); self.advance(); dim = self.interner.intern(&format!(
891 "{}_{}",
892 self.interner.resolve(dim),
893 self.interner.resolve(vlemma)
894 ));
895 }
896 if unit_sym.is_none() {
897 unit_sym = Some(dim);
898 }
899 }
900 }
901
902 let mut rate_unit: Option<Symbol> = None;
908 if matches!(self.peek().kind, TokenType::Preposition(s)
909 if self.interner.resolve(s).eq_ignore_ascii_case("per"))
910 {
911 let cp_rate = self.checkpoint();
912 self.advance(); if is_unit(&self.peek().kind) {
914 rate_unit = Some(self.consume_content_word()?);
915 } else {
916 self.restore(cp_rate);
917 }
918 }
919
920 if !matches!(self.peek().kind, TokenType::Than) {
927 self.restore(cp);
928 return Ok(None);
929 }
930 if count_kind.is_none() && !has_vague {
931 let standard_quantified = matches!(
936 self.tokens.get(self.current + 1).map(|t| &t.kind),
937 Some(TokenType::Number(_))
938 | Some(TokenType::Cardinal(_))
939 | Some(TokenType::All)
940 | Some(TokenType::No)
941 | Some(TokenType::Some)
942 | Some(TokenType::Any)
943 | Some(TokenType::Most)
944 | Some(TokenType::Few)
945 | Some(TokenType::Many)
946 | Some(TokenType::AtLeast(_))
947 | Some(TokenType::AtMost(_))
948 );
949 if standard_quantified {
950 self.restore(cp);
951 return Ok(None);
952 }
953 }
954 self.advance(); let event_var = self.get_event_var();
957 let mut modifiers = Vec::new();
958 let effective_time = self.pending_time.take().unwrap_or(verb_time);
959 match effective_time {
960 Time::Past => modifiers.push(self.interner.intern("Past")),
961 Time::Future => modifiers.push(self.interner.intern("Future")),
962 _ => {}
963 }
964 let suppress_existential = self.drs.in_conditional_antecedent();
965 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
966 event_var,
967 verb,
968 roles: self
969 .ctx
970 .roles
971 .alloc_slice(vec![(ThematicRole::Agent, subject_term)]),
972 modifiers: self.ctx.syms.alloc_slice(modifiers),
973 suppress_existential,
974 world: None,
975 })));
976
977 let cap = |s: &str| -> String {
983 let mut c = s.chars();
984 match c.next() {
985 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
986 None => String::new(),
987 }
988 };
989 let measure_name = match (rate_unit, unit_sym) {
990 (Some(r), _) => format!(
993 "{}_per_{}",
994 cap(&self.interner.resolve(verb).to_string()),
995 cap(&self.interner.resolve(r).to_string())
996 ),
997 (None, Some(u)) => cap(&self.interner.resolve(u).to_string()),
998 (None, None) => cap(&self.interner.resolve(verb).to_string()),
999 };
1000 let measure_sym = self.interner.intern(&measure_name);
1001 let comp_str = self.interner.resolve(comp_adj).to_lowercase();
1004 let subtract = crate::lexicon::is_decreasing_adjective(&comp_str);
1005 let op_sym = self.interner.intern(if subtract { "sub" } else { "add" });
1006 let dir_sym = self.interner.intern(if subtract { "Less" } else { "Greater" });
1007 let offset_unit = if rate_unit.is_some() { unit_sym } else { None };
1010 let offset_term: Option<Term<'a>> = count_kind.map(|kind| Term::Value {
1011 kind,
1012 unit: offset_unit,
1013 dimension: None,
1014 });
1015 let measure_x = Term::Function(measure_sym, self.ctx.terms.alloc_slice([subject_term]));
1016 let build_constraint = move |p: &mut Self, y_term: Term<'a>| -> &'a LogicExpr<'a> {
1017 let measure_y = Term::Function(measure_sym, p.ctx.terms.alloc_slice([y_term]));
1018 match offset_term {
1019 Some(off) => {
1020 let rhs =
1021 Term::Function(op_sym, p.ctx.terms.alloc_slice([measure_y, off]));
1022 p.ctx.exprs.alloc(LogicExpr::Identity {
1023 left: p.ctx.terms.alloc(measure_x),
1024 right: p.ctx.terms.alloc(rhs),
1025 })
1026 }
1027 None => p.ctx.exprs.alloc(LogicExpr::Predicate {
1028 name: dir_sym,
1029 args: p.ctx.terms.alloc_slice([measure_x, measure_y]),
1030 world: None,
1031 }),
1032 }
1033 };
1034
1035 let saved_ctx = self.nominal_np_context;
1047 self.nominal_np_context = true;
1048 let std_np_result = self.parse_noun_phrase(true);
1049 self.nominal_np_context = saved_ctx;
1050 let std_np = std_np_result?;
1051 let has_rel = self.check(&TokenType::Who) || self.check(&TokenType::That);
1052 let is_desc = has_rel
1053 || std_np.definiteness.is_some()
1054 || !std_np.adjectives.is_empty()
1055 || std_np.possessor.is_some()
1056 || !std_np.pps.is_empty();
1057 let result = if is_desc {
1058 let std_var = self.next_var_name();
1059 let mut restr = self.nominal_predication(Term::Variable(std_var), &std_np);
1061 for pp in std_np.pps {
1062 let pp_sub = self.substitute_pp_placeholder(pp, std_var);
1063 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1064 left: restr,
1065 op: TokenType::And,
1066 right: pp_sub,
1067 });
1068 }
1069 if has_rel {
1070 self.advance(); let rel = self.parse_relative_clause(std_var)?;
1072 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1073 left: restr,
1074 op: TokenType::And,
1075 right: rel,
1076 });
1077 }
1078 let comparison = build_constraint(self, Term::Variable(std_var));
1079 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1080 left: restr,
1081 op: TokenType::And,
1082 right: comparison,
1083 });
1084 let quantified = self.ctx.exprs.alloc(LogicExpr::Quantifier {
1085 kind: QuantifierKind::Existential,
1086 variable: std_var,
1087 body,
1088 island_id: self.current_island,
1089 });
1090 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1091 left: event,
1092 op: TokenType::And,
1093 right: quantified,
1094 })
1095 } else {
1096 let comparison = build_constraint(self, Term::Constant(std_np.noun));
1097 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1098 left: event,
1099 op: TokenType::And,
1100 right: comparison,
1101 })
1102 };
1103 Ok(Some(result))
1104 }
1105
1106 pub(super) fn parse_bare_temporal_constraint(
1119 &mut self,
1120 subject_term: Term<'a>,
1121 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
1122 let j = self.current;
1123 let std_at = |k: Option<&TokenType>| {
1124 matches!(
1125 k,
1126 Some(TokenType::Article(_))
1127 | Some(TokenType::Noun(_))
1128 | Some(TokenType::ProperName(_))
1129 )
1130 };
1131 let lead_adverb = match self.tokens.get(j).map(|t| &t.kind) {
1132 Some(TokenType::Adverb(_)) => true,
1133 Some(_) => matches!(
1134 self.interner.resolve(self.tokens[j].lexeme).to_lowercase().as_str(),
1135 "sometime" | "shortly" | "soon" | "immediately" | "long" | "right" | "just"
1136 ),
1137 None => false,
1138 };
1139 let dj = if lead_adverb { j + 1 } else { j };
1140 let next_kind = self.tokens.get(dj + 1).map(|t| &t.kind);
1141 let temporal_at = |k: Option<&TokenType>| {
1145 std_at(k)
1146 || matches!(
1147 k,
1148 Some(TokenType::Number(_)) | Some(TokenType::TimeLiteral { .. })
1149 )
1150 };
1151 let bare_dir = match self.tokens.get(dj).map(|t| &t.kind) {
1152 Some(TokenType::Before) if temporal_at(next_kind) => Some("Before"),
1153 Some(TokenType::Preposition(s))
1154 if self.interner.resolve(*s).eq_ignore_ascii_case("before")
1155 && temporal_at(next_kind) =>
1156 {
1157 Some("Before")
1158 }
1159 Some(TokenType::Preposition(s))
1160 if self.interner.resolve(*s).eq_ignore_ascii_case("after")
1161 && temporal_at(next_kind) =>
1162 {
1163 Some("After")
1164 }
1165 _ => None,
1166 };
1167 let dir = match bare_dir {
1168 Some(d) => d,
1169 None => return Ok(None),
1170 };
1171 if lead_adverb {
1172 self.advance();
1173 }
1174 self.advance(); let rel_sym = self.interner.intern(dir);
1176 if matches!(
1179 self.peek().kind,
1180 TokenType::Number(_) | TokenType::TimeLiteral { .. }
1181 ) {
1182 let year = self.parse_measure_phrase()?;
1183 return Ok(Some(self.ctx.exprs.alloc(LogicExpr::Predicate {
1184 name: rel_sym,
1185 args: self.ctx.terms.alloc_slice([subject_term, *year]),
1186 world: None,
1187 })));
1188 }
1189 let std_np = self.parse_noun_phrase(true)?;
1190 let has_rel = self.check(&TokenType::Who) || self.check(&TokenType::That);
1191 let is_desc = has_rel
1192 || std_np.definiteness.is_some()
1193 || !std_np.adjectives.is_empty()
1194 || std_np.possessor.is_some()
1195 || !std_np.pps.is_empty();
1196 let result = if is_desc {
1197 let v = self.next_var_name();
1198 let mut restr = self.nominal_predication(Term::Variable(v), &std_np);
1199 for pp in std_np.pps {
1200 let pp_sub = self.substitute_pp_placeholder(pp, v);
1201 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1202 left: restr,
1203 op: TokenType::And,
1204 right: pp_sub,
1205 });
1206 }
1207 if has_rel {
1208 self.advance();
1209 let rel = self.parse_relative_clause(v)?;
1210 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1211 left: restr,
1212 op: TokenType::And,
1213 right: rel,
1214 });
1215 }
1216 let rel = self.ctx.exprs.alloc(LogicExpr::Predicate {
1217 name: rel_sym,
1218 args: self.ctx.terms.alloc_slice([subject_term, Term::Variable(v)]),
1219 world: None,
1220 });
1221 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1222 left: restr,
1223 op: TokenType::And,
1224 right: rel,
1225 });
1226 self.ctx.exprs.alloc(LogicExpr::Quantifier {
1227 kind: QuantifierKind::Existential,
1228 variable: v,
1229 body,
1230 island_id: self.current_island,
1231 })
1232 } else {
1233 self.ctx.exprs.alloc(LogicExpr::Predicate {
1234 name: rel_sym,
1235 args: self.ctx.terms.alloc_slice([subject_term, Term::Constant(std_np.noun)]),
1236 world: None,
1237 })
1238 };
1239 Ok(Some(result))
1240 }
1241
1242 pub(super) fn try_temporal_offset(
1243 &mut self,
1244 verb: Symbol,
1245 subject_term: Term<'a>,
1246 verb_time: Time,
1247 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
1248 let j = self.current;
1249
1250 let std_at = |k: Option<&TokenType>| {
1256 matches!(
1257 k,
1258 Some(TokenType::Article(_))
1259 | Some(TokenType::Noun(_))
1260 | Some(TokenType::ProperName(_))
1261 )
1262 };
1263 let lead_adverb = match self.tokens.get(j).map(|t| &t.kind) {
1268 Some(TokenType::Adverb(_)) => true,
1269 Some(_) => matches!(
1270 self.interner.resolve(self.tokens[j].lexeme).to_lowercase().as_str(),
1271 "sometime" | "shortly" | "soon" | "immediately" | "long" | "right" | "just"
1272 ),
1273 None => false,
1274 };
1275 let dj = if lead_adverb { j + 1 } else { j };
1276 let next_kind = self.tokens.get(dj + 1).map(|t| &t.kind);
1277 let num_at = |k: Option<&TokenType>| {
1281 matches!(
1282 k,
1283 Some(TokenType::Number(_)) | Some(TokenType::TimeLiteral { .. })
1284 )
1285 };
1286 let bare_dir = match self.tokens.get(dj).map(|t| &t.kind) {
1287 Some(TokenType::Before) if std_at(next_kind) || num_at(next_kind) => Some("Before"),
1288 Some(TokenType::Preposition(s))
1289 if self.interner.resolve(*s).eq_ignore_ascii_case("before")
1290 && (std_at(next_kind) || num_at(next_kind)) =>
1291 {
1292 Some("Before")
1293 }
1294 Some(TokenType::Preposition(s))
1295 if self.interner.resolve(*s).eq_ignore_ascii_case("after")
1296 && (matches!(next_kind, Some(TokenType::Article(_))) || num_at(next_kind)) =>
1297 {
1298 Some("After")
1299 }
1300 _ => None,
1301 };
1302 if let Some(dir) = bare_dir {
1303 if lead_adverb {
1304 self.advance(); }
1306 self.advance(); let event_var = self.get_event_var();
1308 let mut modifiers = Vec::new();
1309 let effective_time = self.pending_time.take().unwrap_or(verb_time);
1310 match effective_time {
1311 Time::Past => modifiers.push(self.interner.intern("Past")),
1312 Time::Future => modifiers.push(self.interner.intern("Future")),
1313 _ => {}
1314 }
1315 let suppress_existential = self.drs.in_conditional_antecedent();
1316 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1317 event_var,
1318 verb,
1319 roles: self
1320 .ctx
1321 .roles
1322 .alloc_slice(vec![(ThematicRole::Agent, subject_term)]),
1323 modifiers: self.ctx.syms.alloc_slice(modifiers),
1324 suppress_existential,
1325 world: None,
1326 })));
1327 let rel_sym = self.interner.intern(dir);
1328 if matches!(
1331 self.peek().kind,
1332 TokenType::Number(_) | TokenType::TimeLiteral { .. }
1333 ) {
1334 let year = self.parse_measure_phrase()?;
1335 let rel = self.ctx.exprs.alloc(LogicExpr::Predicate {
1336 name: rel_sym,
1337 args: self
1338 .ctx
1339 .terms
1340 .alloc_slice([Term::Variable(event_var), *year]),
1341 world: None,
1342 });
1343 return Ok(Some(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1344 left: event,
1345 op: TokenType::And,
1346 right: rel,
1347 })));
1348 }
1349 let saved_ctx = self.nominal_np_context;
1352 self.nominal_np_context = true;
1353 let std_np_result = self.parse_noun_phrase(true);
1354 self.nominal_np_context = saved_ctx;
1355 let std_np = std_np_result?;
1356 let is_desc = std_np.definiteness.is_some()
1357 || !std_np.adjectives.is_empty()
1358 || std_np.possessor.is_some()
1359 || !std_np.pps.is_empty();
1360 let result = if is_desc {
1361 let v = self.next_var_name();
1362 let mut restr = self.nominal_predication(Term::Variable(v), &std_np);
1363 for pp in std_np.pps {
1364 let pp_sub = self.substitute_pp_placeholder(pp, v);
1365 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1366 left: restr,
1367 op: TokenType::And,
1368 right: pp_sub,
1369 });
1370 }
1371 if self.check(&TokenType::Who) || self.check(&TokenType::That) {
1376 self.advance();
1377 let rc = self.parse_relative_clause(v)?;
1378 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1379 left: restr,
1380 op: TokenType::And,
1381 right: rc,
1382 });
1383 }
1384 let rel = self.ctx.exprs.alloc(LogicExpr::Predicate {
1385 name: rel_sym,
1386 args: self
1387 .ctx
1388 .terms
1389 .alloc_slice([Term::Variable(event_var), Term::Variable(v)]),
1390 world: None,
1391 });
1392 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1393 left: restr,
1394 op: TokenType::And,
1395 right: rel,
1396 });
1397 let quant = self.ctx.exprs.alloc(LogicExpr::Quantifier {
1398 kind: QuantifierKind::Existential,
1399 variable: v,
1400 body,
1401 island_id: self.current_island,
1402 });
1403 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1404 left: event,
1405 op: TokenType::And,
1406 right: quant,
1407 })
1408 } else {
1409 let rel = self.ctx.exprs.alloc(LogicExpr::Predicate {
1410 name: rel_sym,
1411 args: self
1412 .ctx
1413 .terms
1414 .alloc_slice([Term::Variable(event_var), Term::Constant(std_np.noun)]),
1415 world: None,
1416 });
1417 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1418 left: event,
1419 op: TokenType::And,
1420 right: rel,
1421 })
1422 };
1423 return Ok(Some(result));
1424 }
1425
1426 let has_count = matches!(
1432 self.tokens.get(j).map(|t| &t.kind),
1433 Some(TokenType::Number(_)) | Some(TokenType::Cardinal(_))
1434 );
1435 let has_unit = matches!(
1436 self.tokens.get(j + 1).map(|t| &t.kind),
1437 Some(TokenType::CalendarUnit(_))
1438 );
1439 let has_dir = matches!(self.tokens.get(j + 2).map(|t| &t.kind), Some(TokenType::Before))
1440 || matches!(self.tokens.get(j + 2).map(|t| &t.kind),
1441 Some(TokenType::Preposition(s))
1442 if matches!(self.interner.resolve(*s).to_lowercase().as_str(), "after" | "before"));
1443 if !(has_count && has_unit && has_dir) {
1444 return Ok(None);
1445 }
1446
1447 let effective_time = self.pending_time.take().unwrap_or(verb_time);
1450 let constraint = match self.parse_temporal_offset_constraint(subject_term)? {
1451 Some(c) => c,
1452 None => return Ok(None),
1453 };
1454 let event_var = self.get_event_var();
1455 let mut modifiers = Vec::new();
1456 match effective_time {
1457 Time::Past => modifiers.push(self.interner.intern("Past")),
1458 Time::Future => modifiers.push(self.interner.intern("Future")),
1459 _ => {}
1460 }
1461 let suppress_existential = self.drs.in_conditional_antecedent();
1462 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1463 event_var,
1464 verb,
1465 roles: self
1466 .ctx
1467 .roles
1468 .alloc_slice(vec![(ThematicRole::Agent, subject_term)]),
1469 modifiers: self.ctx.syms.alloc_slice(modifiers),
1470 suppress_existential,
1471 world: None,
1472 })));
1473 Ok(Some(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1474 left: event,
1475 op: TokenType::And,
1476 right: constraint,
1477 })))
1478 }
1479
1480 pub(super) fn parse_temporal_offset_constraint(
1489 &mut self,
1490 subject_term: Term<'a>,
1491 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
1492 let j = self.current;
1493 let has_count = matches!(
1494 self.tokens.get(j).map(|t| &t.kind),
1495 Some(TokenType::Number(_)) | Some(TokenType::Cardinal(_))
1496 );
1497 let has_unit = matches!(
1498 self.tokens.get(j + 1).map(|t| &t.kind),
1499 Some(TokenType::CalendarUnit(_))
1500 );
1501 let direction = match self.tokens.get(j + 2).map(|t| &t.kind) {
1502 Some(TokenType::Before) => Some("Before"),
1503 Some(TokenType::Preposition(s)) => {
1504 match self.interner.resolve(*s).to_lowercase().as_str() {
1505 "after" => Some("After"),
1506 "before" => Some("Before"),
1507 _ => None,
1508 }
1509 }
1510 _ => None,
1511 };
1512 if !(has_count && has_unit && direction.is_some()) {
1513 return Ok(None);
1514 }
1515 let direction = direction.unwrap();
1516
1517 let count_kind = match self.advance().kind {
1519 TokenType::Number(s) => {
1520 let raw = self.interner.resolve(s);
1521 if let Ok(n) = raw.parse::<i64>() {
1522 crate::ast::NumberKind::Integer(n)
1523 } else {
1524 crate::ast::NumberKind::Symbolic(s)
1525 }
1526 }
1527 TokenType::Cardinal(n) => crate::ast::NumberKind::Integer(n as i64),
1528 _ => unreachable!("guarded by has_count"),
1529 };
1530 let unit_lexeme = self.peek().lexeme;
1531 self.advance(); self.advance(); let cap = |s: &str| -> String {
1535 let mut c = s.chars();
1536 match c.next() {
1537 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
1538 None => String::new(),
1539 }
1540 };
1541 let measure_sym = self.interner.intern(&cap(&self.interner.resolve(unit_lexeme).to_string()));
1542 let op_sym = self.interner.intern(if direction == "After" { "add" } else { "sub" });
1543 let offset_term = Term::Value {
1544 kind: count_kind,
1545 unit: None,
1546 dimension: None,
1547 };
1548
1549 let measure_x = Term::Function(measure_sym, self.ctx.terms.alloc_slice([subject_term]));
1550 let build_constraint = move |p: &mut Self, y_term: Term<'a>| -> &'a LogicExpr<'a> {
1551 let measure_y = Term::Function(measure_sym, p.ctx.terms.alloc_slice([y_term]));
1552 let rhs = Term::Function(op_sym, p.ctx.terms.alloc_slice([measure_y, offset_term]));
1553 p.ctx.exprs.alloc(LogicExpr::Identity {
1554 left: p.ctx.terms.alloc(measure_x),
1555 right: p.ctx.terms.alloc(rhs),
1556 })
1557 };
1558
1559 let saved_ctx = self.nominal_np_context;
1566 self.nominal_np_context = true;
1567 let std_np_result = self.parse_noun_phrase(true);
1568 self.nominal_np_context = saved_ctx;
1569 let std_np = std_np_result?;
1570 let has_rel = self.check(&TokenType::Who) || self.check(&TokenType::That);
1571 let is_desc = has_rel
1572 || std_np.definiteness.is_some()
1573 || !std_np.adjectives.is_empty()
1574 || std_np.possessor.is_some()
1575 || !std_np.pps.is_empty();
1576 let result = if is_desc {
1577 let std_var = self.next_var_name();
1578 let mut restr = self.nominal_predication(Term::Variable(std_var), &std_np);
1579 for pp in std_np.pps {
1580 let pp_sub = self.substitute_pp_placeholder(pp, std_var);
1581 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1582 left: restr,
1583 op: TokenType::And,
1584 right: pp_sub,
1585 });
1586 }
1587 if has_rel {
1588 self.advance(); let rel = self.parse_relative_clause(std_var)?;
1590 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1591 left: restr,
1592 op: TokenType::And,
1593 right: rel,
1594 });
1595 }
1596 let relation = build_constraint(self, Term::Variable(std_var));
1597 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1598 left: restr,
1599 op: TokenType::And,
1600 right: relation,
1601 });
1602 self.ctx.exprs.alloc(LogicExpr::Quantifier {
1603 kind: QuantifierKind::Existential,
1604 variable: std_var,
1605 body,
1606 island_id: self.current_island,
1607 })
1608 } else {
1609 build_constraint(self, Term::Constant(std_np.noun))
1610 };
1611 Ok(Some(result))
1612 }
1613
1614 pub(super) fn try_positional_offset(
1621 &mut self,
1622 verb: Symbol,
1623 subject_term: Term<'a>,
1624 verb_time: Time,
1625 ) -> ParseResult<Option<&'a LogicExpr<'a>>> {
1626 let j = self.current;
1627 let has_count = matches!(
1628 self.tokens.get(j).map(|t| &t.kind),
1629 Some(TokenType::Number(_)) | Some(TokenType::Cardinal(_))
1630 );
1631 let is_pos_unit = self
1632 .tokens
1633 .get(j + 1)
1634 .map(|t| {
1635 matches!(
1636 self.interner.resolve(t.lexeme).to_lowercase().as_str(),
1637 "place" | "places" | "spot" | "spots"
1638 )
1639 })
1640 .unwrap_or(false);
1641 if !(has_count && is_pos_unit) {
1642 return Ok(None);
1643 }
1644 let (subtract, ahead_of) = match self.tokens.get(j + 2).map(|t| &t.kind) {
1646 Some(TokenType::Before) => (true, false),
1647 Some(_) => match self
1648 .interner
1649 .resolve(self.tokens[j + 2].lexeme)
1650 .to_lowercase()
1651 .as_str()
1652 {
1653 "ahead" => (true, true),
1654 "before" => (true, false),
1655 "behind" => (false, false),
1656 "after" => (false, false),
1657 _ => return Ok(None),
1658 },
1659 None => return Ok(None),
1660 };
1661
1662 let count_kind = match self.advance().kind {
1663 TokenType::Number(s) => {
1664 let raw = self.interner.resolve(s);
1665 if let Ok(n) = raw.parse::<i64>() {
1666 crate::ast::NumberKind::Integer(n)
1667 } else {
1668 crate::ast::NumberKind::Symbolic(s)
1669 }
1670 }
1671 TokenType::Cardinal(n) => crate::ast::NumberKind::Integer(n as i64),
1672 _ => unreachable!("guarded by has_count"),
1673 };
1674 self.advance(); self.advance(); if ahead_of
1677 && matches!(self.peek().kind, TokenType::Preposition(s)
1678 if self.interner.resolve(s).eq_ignore_ascii_case("of"))
1679 {
1680 self.advance(); }
1682
1683 let measure_sym = self.interner.intern("Place");
1684 let op_sym = self.interner.intern(if subtract { "sub" } else { "add" });
1685 let offset_term = Term::Value { kind: count_kind, unit: None, dimension: None };
1686
1687 let event_var = self.get_event_var();
1688 let mut modifiers = Vec::new();
1689 let effective_time = self.pending_time.take().unwrap_or(verb_time);
1690 match effective_time {
1691 Time::Past => modifiers.push(self.interner.intern("Past")),
1692 Time::Future => modifiers.push(self.interner.intern("Future")),
1693 _ => {}
1694 }
1695 let suppress_existential = self.drs.in_conditional_antecedent();
1696 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1697 event_var,
1698 verb,
1699 roles: self.ctx.roles.alloc_slice(vec![(ThematicRole::Agent, subject_term)]),
1700 modifiers: self.ctx.syms.alloc_slice(modifiers),
1701 suppress_existential,
1702 world: None,
1703 })));
1704
1705 let measure_x = Term::Function(measure_sym, self.ctx.terms.alloc_slice([subject_term]));
1706 let build_constraint = move |p: &mut Self, y_term: Term<'a>| -> &'a LogicExpr<'a> {
1707 let measure_y = Term::Function(measure_sym, p.ctx.terms.alloc_slice([y_term]));
1708 let rhs = Term::Function(op_sym, p.ctx.terms.alloc_slice([measure_y, offset_term]));
1709 p.ctx.exprs.alloc(LogicExpr::Identity {
1710 left: p.ctx.terms.alloc(measure_x),
1711 right: p.ctx.terms.alloc(rhs),
1712 })
1713 };
1714
1715 let std_np = self.parse_noun_phrase(true)?;
1716 let has_rel = self.check(&TokenType::Who) || self.check(&TokenType::That);
1717 let is_desc = has_rel
1718 || std_np.definiteness.is_some()
1719 || !std_np.adjectives.is_empty()
1720 || std_np.possessor.is_some()
1721 || !std_np.pps.is_empty();
1722 let result = if is_desc {
1723 let std_var = self.next_var_name();
1724 let mut restr = self.nominal_predication(Term::Variable(std_var), &std_np);
1725 for pp in std_np.pps {
1726 let pp_sub = self.substitute_pp_placeholder(pp, std_var);
1727 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1728 left: restr,
1729 op: TokenType::And,
1730 right: pp_sub,
1731 });
1732 }
1733 if has_rel {
1734 self.advance();
1735 let rel = self.parse_relative_clause(std_var)?;
1736 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1737 left: restr,
1738 op: TokenType::And,
1739 right: rel,
1740 });
1741 }
1742 let relation = build_constraint(self, Term::Variable(std_var));
1743 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1744 left: restr,
1745 op: TokenType::And,
1746 right: relation,
1747 });
1748 let quantified = self.ctx.exprs.alloc(LogicExpr::Quantifier {
1749 kind: QuantifierKind::Existential,
1750 variable: std_var,
1751 body,
1752 island_id: self.current_island,
1753 });
1754 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1755 left: event,
1756 op: TokenType::And,
1757 right: quantified,
1758 })
1759 } else {
1760 let relation = build_constraint(self, Term::Constant(std_np.noun));
1761 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
1762 left: event,
1763 op: TokenType::And,
1764 right: relation,
1765 })
1766 };
1767 Ok(Some(result))
1768 }
1769
1770 fn parse_predicate_impl(
1771 &mut self,
1772 subject_symbol: Symbol,
1773 as_variable: bool,
1774 ) -> ParseResult<&'a LogicExpr<'a>> {
1775 let subject_term = if as_variable {
1776 Term::Variable(subject_symbol)
1777 } else {
1778 Term::Constant(subject_symbol)
1779 };
1780
1781 let subject_str = self.interner.resolve(subject_symbol).to_lowercase();
1783 if subject_str == "it" && self.check_verb() {
1784 if let TokenType::Verb { lemma, time, .. } = &self.peek().kind {
1785 let lemma_str = self.interner.resolve(*lemma);
1786 if Lexer::is_weather_verb(lemma_str) {
1787 let verb = *lemma;
1788 let verb_time = *time;
1789 self.advance(); let event_var = self.get_event_var();
1792 let suppress_existential = self.drs.in_conditional_antecedent();
1793 if suppress_existential {
1794 let event_class = self.interner.intern("Event");
1795 self.drs.introduce_referent(event_var, event_class, Gender::Neuter, Number::Singular);
1796 }
1797 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1798 event_var,
1799 verb,
1800 roles: self.ctx.roles.alloc_slice(vec![]), modifiers: self.ctx.syms.alloc_slice(vec![]),
1802 suppress_existential,
1803 world: None,
1804 })));
1805
1806 return Ok(match verb_time {
1807 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
1808 operator: TemporalOperator::Past,
1809 body: neo_event,
1810 }),
1811 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
1812 operator: TemporalOperator::Future,
1813 body: neo_event,
1814 }),
1815 _ => neo_event,
1816 });
1817 }
1818 }
1819 }
1820
1821 if subject_str == "it" && (self.check(&TokenType::Is) || self.check(&TokenType::Was) || self.check(&TokenType::Possessive)) {
1824 let saved_pos = self.current;
1825 self.advance(); if self.check_content_word() {
1828 let adj_lexeme = self.peek().lexeme;
1829 let adj_str = self.interner.resolve(adj_lexeme).to_lowercase();
1830
1831 if let Some(meta) = crate::lexicon::lookup_adjective_db(&adj_str) {
1832 if meta.features.contains(&crate::lexicon::Feature::Weather) {
1833 let adj_sym = self.consume_content_word().unwrap_or(adj_lexeme);
1834 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
1836 name: adj_sym,
1837 args: self.ctx.terms.alloc_slice([]),
1838 world: None,
1839 }));
1840 }
1841 }
1842 }
1843 self.current = saved_pos;
1845 }
1846
1847 if self.check(&TokenType::Never) {
1848 self.advance();
1849 let verb = self.consume_verb();
1850 let verb_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
1851 name: verb,
1852 args: self.ctx.terms.alloc_slice([subject_term]),
1853 world: None,
1854 });
1855 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1856 op: TokenType::Not,
1857 operand: verb_pred,
1858 }));
1859 }
1860
1861 if self.check_modal() {
1862 return self.parse_aspect_chain_with_term(subject_term.clone());
1863 }
1864
1865 if self.check_content_word() {
1866 let next_word = self.interner.resolve(self.peek().lexeme).to_lowercase();
1867 if next_word == "has" || next_word == "have" || next_word == "had" {
1868 let is_perfect_aspect = if self.current + 1 < self.tokens.len() {
1872 let next_token = &self.tokens[self.current + 1].kind;
1873 matches!(
1874 next_token,
1875 TokenType::Verb { .. } | TokenType::Not
1876 ) && !matches!(next_token, TokenType::Number(_))
1877 } else {
1878 false
1879 };
1880 if is_perfect_aspect {
1881 return self.parse_aspect_chain(subject_symbol);
1882 }
1883 }
1885 }
1886
1887 if self.check(&TokenType::Had) {
1888 return self.parse_aspect_chain(subject_symbol);
1889 }
1890
1891 if self.check(&TokenType::Does) || self.check(&TokenType::Do) {
1893 self.advance();
1894 let is_negated = self.match_token(&[TokenType::Not]);
1895
1896 if self.check(&TokenType::Ever) {
1897 self.advance();
1898 }
1899
1900 if self.check_verb() {
1901 let (verb, verb_time, verb_aspect, verb_class) =
1902 self.consume_verb_with_metadata();
1903
1904 if self.check_wh_word() {
1906 let wh_token = self.advance().kind.clone();
1907 let is_who = matches!(wh_token, TokenType::Who);
1908 let is_what = matches!(wh_token, TokenType::What);
1909
1910 let is_sluicing = self.is_at_end() ||
1911 self.check(&TokenType::Period) ||
1912 self.check(&TokenType::Comma);
1913
1914 if is_sluicing {
1915 if let Some(template) = self.last_event_template.clone() {
1916 let wh_var = self.next_var_name();
1917
1918 let roles: Vec<_> = if is_who {
1919 std::iter::once((ThematicRole::Agent, Term::Variable(wh_var)))
1920 .chain(template.non_agent_roles.iter().cloned())
1921 .collect()
1922 } else if is_what {
1923 vec![
1924 (ThematicRole::Agent, subject_term.clone()),
1925 (ThematicRole::Theme, Term::Variable(wh_var)),
1926 ]
1927 } else {
1928 std::iter::once((ThematicRole::Agent, Term::Variable(wh_var)))
1929 .chain(template.non_agent_roles.iter().cloned())
1930 .collect()
1931 };
1932
1933 let event_var = self.get_event_var();
1934 let suppress_existential = self.drs.in_conditional_antecedent();
1935 let reconstructed = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1936 event_var,
1937 verb: template.verb,
1938 roles: self.ctx.roles.alloc_slice(roles),
1939 modifiers: self.ctx.syms.alloc_slice(template.modifiers.clone()),
1940 suppress_existential,
1941 world: None,
1942 })));
1943
1944 let question = self.ctx.exprs.alloc(LogicExpr::Question {
1945 wh_variable: wh_var,
1946 body: reconstructed,
1947 });
1948
1949 let know_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
1950 event_var: self.get_event_var(),
1951 verb,
1952 roles: self.ctx.roles.alloc_slice(vec![
1953 (ThematicRole::Agent, subject_term.clone()),
1954 (ThematicRole::Theme, Term::Proposition(question)),
1955 ]),
1956 modifiers: self.ctx.syms.alloc_slice(vec![]),
1957 suppress_existential,
1958 world: None,
1959 })));
1960
1961 let result = if is_negated {
1962 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1963 op: TokenType::Not,
1964 operand: know_event,
1965 })
1966 } else {
1967 know_event
1968 };
1969
1970 return Ok(result);
1971 }
1972 }
1973 }
1974
1975 if is_negated {
1981 self.negative_depth += 1;
1982 }
1983 let vp = self.build_verb_vp(
1984 subject_symbol,
1985 subject_term,
1986 as_variable,
1987 verb,
1988 verb_time,
1989 verb_aspect,
1990 verb_class,
1991 )?;
1992 if is_negated {
1993 self.negative_depth -= 1;
1994 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
1995 op: TokenType::Not,
1996 operand: vp,
1997 }));
1998 }
1999 return Ok(vp);
2000 }
2001 }
2002
2003 if self.check_auxiliary() && self.is_true_auxiliary_usage() {
2007 let aux_time = if let TokenType::Auxiliary(time) = self.advance().kind {
2008 time
2009 } else {
2010 Time::None
2011 };
2012 self.pending_time = Some(aux_time);
2013
2014 if self.match_token(&[TokenType::Not]) {
2015 self.negative_depth += 1;
2016
2017 if let TokenType::Performative(_) = self.peek().kind {
2022 let lemma = self
2023 .interner
2024 .intern(&self.interner.resolve(self.peek().lexeme).to_lowercase());
2025 self.tokens[self.current].kind = TokenType::Verb {
2026 lemma,
2027 time: Time::None,
2028 aspect: Aspect::Simple,
2029 class: crate::lexicon::VerbClass::Activity,
2030 };
2031 }
2032 if self.check_verb() || self.check(&TokenType::Do) {
2034 let (verb, verb_time, verb_aspect, verb_class) =
2035 if self.check(&TokenType::Do) {
2036 self.advance(); (
2038 self.interner.intern("Do"),
2039 Time::None,
2040 Aspect::Simple,
2041 crate::lexicon::VerbClass::Activity,
2042 )
2043 } else {
2044 self.consume_verb_with_metadata()
2045 };
2046
2047 if self.check_quantifier() {
2048 let quantifier_token = self.advance().kind.clone();
2049 let object_np = self.parse_noun_phrase(false)?;
2050 let obj_var = self.next_var_name();
2051
2052 let obj_restriction = self.ctx.exprs.alloc(LogicExpr::Predicate {
2053 name: object_np.noun,
2054 args: self.ctx.terms.alloc_slice([Term::Variable(obj_var)]),
2055 world: None,
2056 });
2057
2058 let verb_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2059 name: verb,
2060 args: self
2061 .ctx
2062 .terms
2063 .alloc_slice([subject_term, Term::Variable(obj_var)]),
2064 world: None,
2065 });
2066
2067 let (kind, body) = match quantifier_token {
2068 TokenType::Any => {
2069 if self.is_negative_context() {
2070 (
2071 QuantifierKind::Existential,
2072 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2073 left: obj_restriction,
2074 op: TokenType::And,
2075 right: verb_pred,
2076 }),
2077 )
2078 } else {
2079 (
2080 QuantifierKind::Universal,
2081 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2082 left: obj_restriction,
2083 op: TokenType::Implies,
2084 right: verb_pred,
2085 }),
2086 )
2087 }
2088 }
2089 TokenType::Some => (
2090 QuantifierKind::Existential,
2091 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2092 left: obj_restriction,
2093 op: TokenType::And,
2094 right: verb_pred,
2095 }),
2096 ),
2097 TokenType::All => (
2098 QuantifierKind::Universal,
2099 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2100 left: obj_restriction,
2101 op: TokenType::Implies,
2102 right: verb_pred,
2103 }),
2104 ),
2105 _ => (
2106 QuantifierKind::Existential,
2107 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2108 left: obj_restriction,
2109 op: TokenType::And,
2110 right: verb_pred,
2111 }),
2112 ),
2113 };
2114
2115 let quantified = self.ctx.exprs.alloc(LogicExpr::Quantifier {
2116 kind,
2117 variable: obj_var,
2118 body,
2119 island_id: self.current_island,
2120 });
2121
2122 let effective_time = self.pending_time.take().unwrap_or(Time::None);
2123 let with_time = match effective_time {
2124 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
2125 operator: TemporalOperator::Past,
2126 body: quantified,
2127 }),
2128 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
2129 operator: TemporalOperator::Future,
2130 body: quantified,
2131 }),
2132 _ => quantified,
2133 };
2134
2135 self.negative_depth -= 1;
2136 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2137 op: TokenType::Not,
2138 operand: with_time,
2139 }));
2140 }
2141
2142 if self.check_npi_object() {
2143 let npi_token = self.advance().kind.clone();
2144 let obj_var = self.next_var_name();
2145
2146 let restriction_name = match npi_token {
2147 TokenType::Anything => "Thing",
2148 TokenType::Anyone => "Person",
2149 _ => "Thing",
2150 };
2151
2152 let restriction_sym = self.interner.intern(restriction_name);
2153 let obj_restriction = self.ctx.exprs.alloc(LogicExpr::Predicate {
2154 name: restriction_sym,
2155 args: self.ctx.terms.alloc_slice([Term::Variable(obj_var)]),
2156 world: None,
2157 });
2158
2159 let verb_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2160 name: verb,
2161 args: self.ctx.terms.alloc_slice([subject_term, Term::Variable(obj_var)]),
2162 world: None,
2163 });
2164
2165 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2166 left: obj_restriction,
2167 op: TokenType::And,
2168 right: verb_pred,
2169 });
2170
2171 let quantified = self.ctx.exprs.alloc(LogicExpr::Quantifier {
2172 kind: QuantifierKind::Existential,
2173 variable: obj_var,
2174 body,
2175 island_id: self.current_island,
2176 });
2177
2178 let effective_time = self.pending_time.take().unwrap_or(Time::None);
2179 let with_time = match effective_time {
2180 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
2181 operator: TemporalOperator::Past,
2182 body: quantified,
2183 }),
2184 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
2185 operator: TemporalOperator::Future,
2186 body: quantified,
2187 }),
2188 _ => quantified,
2189 };
2190
2191 self.negative_depth -= 1;
2192 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2193 op: TokenType::Not,
2194 operand: with_time,
2195 }));
2196 }
2197
2198 let vp = self.build_verb_vp(
2203 subject_symbol,
2204 subject_term,
2205 as_variable,
2206 verb,
2207 verb_time,
2208 verb_aspect,
2209 verb_class,
2210 )?;
2211
2212 self.negative_depth -= 1;
2213 return Ok(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2214 op: TokenType::Not,
2215 operand: vp,
2216 }));
2217 }
2218
2219 self.negative_depth -= 1;
2220 }
2221 }
2222
2223 if self.check(&TokenType::Is)
2224 || self.check(&TokenType::Are)
2225 || self.check(&TokenType::Was)
2226 || self.check(&TokenType::Were)
2227 {
2228 let copula_time = if self.check(&TokenType::Was) || self.check(&TokenType::Were) {
2229 Time::Past
2230 } else {
2231 Time::Present
2232 };
2233 self.advance();
2234
2235 let is_negated = self.check(&TokenType::Not);
2237 if is_negated {
2238 self.advance(); }
2240
2241 let mut copula_temporal: Option<super::CopulaTemporal> = None;
2243 if !is_negated {
2244 if self.check(&TokenType::Never) {
2245 self.advance();
2246 copula_temporal = Some(super::CopulaTemporal::Never);
2247 } else if let TokenType::Adverb(sym) | TokenType::ScopalAdverb(sym) | TokenType::TemporalAdverb(sym) = &self.peek().kind {
2248 let resolved = self.interner.resolve(*sym).to_string();
2249 if resolved == "Always" || resolved == "always" {
2250 self.advance();
2251 copula_temporal = Some(super::CopulaTemporal::Always);
2252 } else if resolved == "Eventually" || resolved == "eventually" {
2253 self.advance();
2254 copula_temporal = Some(super::CopulaTemporal::Eventually);
2255 }
2256 }
2257 }
2258
2259 if self.check_verb() {
2260 let (verb, _verb_time, verb_aspect, verb_class) = self.consume_verb_with_metadata();
2261
2262 if verb_class.is_stative() && verb_aspect == Aspect::Progressive {
2264 return Err(crate::error::ParseError {
2265 kind: crate::error::ParseErrorKind::StativeProgressiveConflict,
2266 span: self.current_span(),
2267 });
2268 }
2269
2270 let mut predicate: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::Predicate {
2271 name: verb,
2272 args: self.ctx.terms.alloc_slice([subject_term]),
2273 world: None,
2274 });
2275
2276 if self.check_by_preposition() {
2282 self.advance(); if self.check_content_word()
2284 || matches!(self.peek().kind, TokenType::Article(_))
2285 {
2286 let agent = self.parse_noun_phrase(true)?;
2287 let (agent_term, agent_restr) = self.possessor_entity(&agent);
2290 let core = self.ctx.exprs.alloc(LogicExpr::Predicate {
2291 name: verb,
2292 args: self.ctx.terms.alloc_slice([agent_term, subject_term]),
2293 world: None,
2294 });
2295 predicate = self.wrap_in_possessor_entity(agent_restr, core);
2296 }
2297 }
2298
2299 while self.check_preposition() && !self.check_of_preposition()
2305 && !self.pp_is_cycle_temporal()
2306 {
2307 let prep = match self.advance().kind {
2308 TokenType::Preposition(s) => s,
2309 _ => break,
2310 };
2311 let adjunct = if self.check_number() {
2312 let m = self.parse_measure_phrase()?;
2313 self.ctx.exprs.alloc(LogicExpr::Predicate {
2314 name: prep,
2315 args: self.ctx.terms.alloc_slice([subject_term, *m]),
2316 world: None,
2317 })
2318 } else if self.check_content_word()
2319 || matches!(self.peek().kind, TokenType::Article(_))
2320 {
2321 let obj = self.parse_noun_phrase(true)?;
2322 self.ctx.exprs.alloc(LogicExpr::Predicate {
2323 name: prep,
2324 args: self.ctx.terms.alloc_slice([subject_term, Term::Constant(obj.noun)]),
2325 world: None,
2326 })
2327 } else {
2328 break;
2329 };
2330 predicate = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2331 left: predicate,
2332 op: TokenType::And,
2333 right: adjunct,
2334 });
2335 }
2336 if let Some(constraint) = self.parse_temporal_offset_constraint(subject_term)? {
2337 predicate = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2338 left: predicate,
2339 op: TokenType::And,
2340 right: constraint,
2341 });
2342 }
2343
2344 let with_aspect = if verb_aspect == Aspect::Progressive {
2345 let operator = if verb_class == crate::lexicon::VerbClass::Semelfactive {
2347 AspectOperator::Iterative
2348 } else {
2349 AspectOperator::Progressive
2350 };
2351 self.ctx.exprs.alloc(LogicExpr::Aspectual {
2352 operator,
2353 body: predicate,
2354 })
2355 } else {
2356 predicate
2357 };
2358
2359 let with_time = if copula_time == Time::Past {
2360 self.ctx.exprs.alloc(LogicExpr::Temporal {
2361 operator: TemporalOperator::Past,
2362 body: with_aspect,
2363 })
2364 } else {
2365 with_aspect
2366 };
2367
2368 let with_neg = if is_negated {
2369 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2370 op: TokenType::Not,
2371 operand: with_time,
2372 })
2373 } else {
2374 with_time
2375 };
2376
2377 let result = match copula_temporal {
2378 Some(super::CopulaTemporal::Always) => {
2379 self.ctx.exprs.alloc(LogicExpr::Temporal {
2380 operator: TemporalOperator::Always,
2381 body: with_neg,
2382 })
2383 }
2384 Some(super::CopulaTemporal::Never) => {
2385 let negated = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2386 op: TokenType::Not,
2387 operand: with_time,
2388 });
2389 self.ctx.exprs.alloc(LogicExpr::Temporal {
2390 operator: TemporalOperator::Always,
2391 body: negated,
2392 })
2393 }
2394 Some(super::CopulaTemporal::Eventually) => {
2395 self.ctx.exprs.alloc(LogicExpr::Temporal {
2396 operator: TemporalOperator::Eventually,
2397 body: with_neg,
2398 })
2399 }
2400 None => with_neg,
2401 };
2402
2403 return Ok(result);
2404 }
2405
2406 if self.check_number() {
2413 let after_measure_is_comparative = {
2414 let mut i = self.current + 1; if matches!(
2416 self.tokens.get(i).map(|t| &t.kind),
2417 Some(TokenType::Noun(_)) | Some(TokenType::CalendarUnit(_))
2418 ) {
2419 i += 1; }
2421 matches!(
2422 self.tokens.get(i).map(|t| &t.kind),
2423 Some(TokenType::Comparative(_))
2424 )
2425 };
2426 if !after_measure_is_comparative {
2427 let measure = self.parse_measure_phrase()?;
2428 let pred = if self.check_content_word() {
2429 let adj = self.consume_content_word()?;
2430 self.ctx.exprs.alloc(LogicExpr::Predicate {
2431 name: adj,
2432 args: self.ctx.terms.alloc_slice([subject_term, *measure]),
2433 world: None,
2434 })
2435 } else {
2436 self.ctx.exprs.alloc(LogicExpr::Identity {
2437 left: self.ctx.terms.alloc(subject_term),
2438 right: measure,
2439 })
2440 };
2441 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2442 }
2443 }
2444
2445 if self.check_preposition() && !self.check_by_preposition() {
2448 let prep_token = self.advance().clone();
2449 let prep_sym = match prep_token.kind {
2450 TokenType::Preposition(s) => s,
2451 _ => unreachable!("guarded by check_preposition()"),
2452 };
2453 let base = if self.check_number() {
2457 let m = self.parse_measure_phrase()?;
2458 self.ctx.exprs.alloc(LogicExpr::Predicate {
2459 name: prep_sym,
2460 args: self.ctx.terms.alloc_slice([subject_term, *m]),
2461 world: None,
2462 })
2463 } else {
2464 let pp_obj = self.parse_noun_phrase(true)?;
2465 self.ctx.exprs.alloc(LogicExpr::Predicate {
2466 name: prep_sym,
2467 args: self.ctx.terms.alloc_slice([subject_term, Term::Constant(pp_obj.noun)]),
2468 world: None,
2469 })
2470 };
2471 let with_time = if copula_time == Time::Past {
2472 self.ctx.exprs.alloc(LogicExpr::Temporal {
2473 operator: TemporalOperator::Past,
2474 body: base,
2475 })
2476 } else {
2477 base
2478 };
2479 return Ok(if is_negated {
2480 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2481 op: TokenType::Not,
2482 operand: with_time,
2483 })
2484 } else {
2485 with_time
2486 });
2487 }
2488
2489 if let TokenType::ProperName(pname) = self.peek().kind {
2494 if matches!(
2495 self.tokens.get(self.current + 1).map(|t| &t.kind),
2496 Some(TokenType::Possessive)
2497 ) {
2498 let elided = matches!(
2505 self.tokens.get(self.current + 2).map(|t| &t.kind),
2506 Some(TokenType::Period) | Some(TokenType::EOF)
2507 | Some(TokenType::Comma) | Some(TokenType::And)
2508 | Some(TokenType::Or) | None
2509 );
2510 if elided {
2511 self.advance(); self.advance(); let pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2514 name: self.interner.intern("Possesses"),
2515 args: self.ctx.terms.alloc_slice([
2516 Term::Constant(pname),
2517 subject_term,
2518 ]),
2519 world: None,
2520 });
2521 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2522 }
2523 let saved_ctx = self.nominal_np_context;
2524 self.nominal_np_context = true;
2525 let np_result = self.parse_noun_phrase(true);
2526 self.nominal_np_context = saved_ctx;
2527 let np = np_result?;
2528 let pred = self.nominal_predication_with_pps(subject_term, &np);
2529 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2530 }
2531
2532 let multiword_poss = {
2537 let mut k = self.current + 1;
2538 while matches!(self.tokens.get(k).map(|t| &t.kind), Some(TokenType::ProperName(_))) {
2539 k += 1;
2540 }
2541 if k > self.current + 1
2542 && matches!(self.tokens.get(k).map(|t| &t.kind), Some(TokenType::Possessive))
2543 {
2544 Some(k)
2545 } else {
2546 None
2547 }
2548 };
2549 if let Some(poss_pos) = multiword_poss {
2550 let elided = matches!(
2551 self.tokens.get(poss_pos + 1).map(|t| &t.kind),
2552 Some(TokenType::Period) | Some(TokenType::EOF)
2553 | Some(TokenType::Comma) | Some(TokenType::And)
2554 | Some(TokenType::Or) | None
2555 );
2556 self.advance(); let possessor = self.absorb_multiword_proper_name(pname);
2558 self.advance(); let poss_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2560 name: self.interner.intern("Possesses"),
2561 args: self.ctx.terms.alloc_slice([Term::Constant(possessor), subject_term]),
2562 world: None,
2563 });
2564 let pred = if elided {
2565 poss_pred
2566 } else {
2567 let saved_ctx = self.nominal_np_context;
2568 self.nominal_np_context = true;
2569 let np_result = self.parse_noun_phrase(true);
2570 self.nominal_np_context = saved_ctx;
2571 let np = np_result?;
2572 let np_pred = self.nominal_predication_with_pps(subject_term, &np);
2573 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2574 left: np_pred,
2575 op: TokenType::And,
2576 right: poss_pred,
2577 })
2578 };
2579 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2580 }
2581
2582 self.advance();
2583 let pname = self.absorb_multiword_proper_name(pname);
2587 let identity = self.ctx.exprs.alloc(LogicExpr::Identity {
2588 left: self.ctx.terms.alloc(subject_term),
2589 right: self.ctx.terms.alloc(Term::Constant(pname)),
2590 });
2591 return Ok(self.finish_copula(identity, copula_time, is_negated, copula_temporal));
2592 }
2593
2594 if self.check(&TokenType::Either) {
2596 self.advance(); let saved_ctx = self.nominal_np_context;
2598 self.nominal_np_context = true;
2599 let np1_result = self.parse_noun_phrase(true);
2600 self.nominal_np_context = saved_ctx;
2601 let np1 = np1_result?;
2602 let pred1 = self.nominal_predication_with_pps(subject_term, &np1);
2606 let pred1 = self.conjoin_trailing_relative(pred1, subject_term)?;
2609 if self.check(&TokenType::Or) {
2610 self.advance(); let saved_ctx2 = self.nominal_np_context;
2612 self.nominal_np_context = true;
2613 let np2_result = self.parse_noun_phrase(true);
2614 self.nominal_np_context = saved_ctx2;
2615 let np2 = np2_result?;
2616 let pred2 = self.nominal_predication_with_pps(subject_term, &np2);
2617 let pred2 = self.conjoin_trailing_relative(pred2, subject_term)?;
2618 let disj = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2619 left: pred1,
2620 op: TokenType::Or,
2621 right: pred2,
2622 });
2623 return Ok(self.finish_copula(disj, copula_time, is_negated, copula_temporal));
2624 }
2625 return Ok(self.finish_copula(pred1, copula_time, is_negated, copula_temporal));
2626 }
2627
2628 if self.check_article() {
2633 let saved_ctx = self.nominal_np_context;
2634 self.nominal_np_context = true;
2635 let pred_np_result = self.parse_noun_phrase(true);
2636 self.nominal_np_context = saved_ctx;
2637 let pred_np = pred_np_result?;
2638 let pred = self.nominal_predication_with_pps(subject_term, &pred_np);
2639 let pred = self.conjoin_trailing_relative(pred, subject_term)?;
2644 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2645 }
2646
2647 if let TokenType::Comparative(_) = self.peek().kind {
2655 let comp_tok = self.advance().clone();
2656 let comp_surface = self.interner.resolve(comp_tok.lexeme).to_string();
2657 let comp_name = {
2658 let mut c = comp_surface.chars();
2659 match c.next() {
2660 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
2661 None => comp_surface.clone(),
2662 }
2663 };
2664 let name = self.interner.intern(&comp_name);
2665 let pred = if self.check(&TokenType::Than) {
2666 self.advance(); let std_np = self.parse_noun_phrase(true)?;
2668 let std = self.nominal_predication(Term::Constant(std_np.noun), &std_np);
2669 let cmp = self.ctx.exprs.alloc(LogicExpr::Predicate {
2670 name,
2671 args: self.ctx.terms.alloc_slice([
2672 subject_term,
2673 Term::Constant(std_np.noun),
2674 ]),
2675 world: None,
2676 });
2677 if matches!(std, LogicExpr::Predicate { args, .. } if args.len() == 1) {
2680 cmp
2681 } else {
2682 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2683 left: cmp,
2684 op: TokenType::And,
2685 right: std,
2686 })
2687 }
2688 } else {
2689 self.ctx.exprs.alloc(LogicExpr::Predicate {
2690 name,
2691 args: self.ctx.terms.alloc_slice([subject_term]),
2692 world: None,
2693 })
2694 };
2695 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2696 }
2697
2698 if let Some(base) = self.copula_temporal_adverb_complement(subject_term.clone())? {
2701 return Ok(self.finish_copula(base, copula_time, is_negated, copula_temporal));
2702 }
2703
2704 let predicate = self.consume_content_word()?;
2705
2706 {
2711 let mut coord_adjs: Vec<Symbol> = vec![predicate];
2712 while self.check(&TokenType::And) {
2713 let saved = self.current;
2714 self.advance();
2715 if let TokenType::Adjective(a) = self.peek().kind {
2716 if matches!(
2719 self.tokens.get(self.current + 1).map(|t| &t.kind),
2720 Some(TokenType::Is) | Some(TokenType::Are)
2721 | Some(TokenType::Was) | Some(TokenType::Were)
2722 | Some(TokenType::Verb { .. })
2723 ) {
2724 self.current = saved;
2725 break;
2726 }
2727 self.advance();
2728 coord_adjs.push(a);
2729 } else {
2730 self.current = saved;
2731 break;
2732 }
2733 }
2734 if coord_adjs.len() > 1 {
2735 let mut conj: &'a LogicExpr<'a> = self.ctx.exprs.alloc(LogicExpr::Predicate {
2736 name: coord_adjs[0],
2737 args: self.ctx.terms.alloc_slice([subject_term.clone()]),
2738 world: None,
2739 });
2740 for &a in &coord_adjs[1..] {
2741 let p = self.ctx.exprs.alloc(LogicExpr::Predicate {
2742 name: a,
2743 args: self.ctx.terms.alloc_slice([subject_term.clone()]),
2744 world: None,
2745 });
2746 conj = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
2747 left: conj,
2748 op: TokenType::And,
2749 right: p,
2750 });
2751 }
2752 return Ok(self.finish_copula(conj, copula_time, is_negated, copula_temporal));
2753 }
2754 }
2755
2756 if self.check_number() {
2762 let measure = self.parse_measure_phrase()?;
2763 let pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2764 name: predicate,
2765 args: self.ctx.terms.alloc_slice([subject_term.clone(), *measure]),
2766 world: None,
2767 });
2768 return Ok(self.finish_copula(pred, copula_time, is_negated, copula_temporal));
2769 }
2770
2771 let base_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
2772 name: predicate,
2773 args: self.ctx.terms.alloc_slice([subject_term]),
2774 world: None,
2775 });
2776
2777 let with_time = if copula_time == Time::Past {
2778 self.ctx.exprs.alloc(LogicExpr::Temporal {
2779 operator: TemporalOperator::Past,
2780 body: base_pred,
2781 })
2782 } else {
2783 base_pred
2784 };
2785
2786 let with_neg = if is_negated {
2787 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2788 op: TokenType::Not,
2789 operand: with_time,
2790 })
2791 } else {
2792 with_time
2793 };
2794
2795 let result = match copula_temporal {
2796 Some(super::CopulaTemporal::Always) => {
2797 self.ctx.exprs.alloc(LogicExpr::Temporal {
2798 operator: TemporalOperator::Always,
2799 body: with_neg,
2800 })
2801 }
2802 Some(super::CopulaTemporal::Never) => {
2803 let negated = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
2804 op: TokenType::Not,
2805 operand: with_time,
2806 });
2807 self.ctx.exprs.alloc(LogicExpr::Temporal {
2808 operator: TemporalOperator::Always,
2809 body: negated,
2810 })
2811 }
2812 Some(super::CopulaTemporal::Eventually) => {
2813 self.ctx.exprs.alloc(LogicExpr::Temporal {
2814 operator: TemporalOperator::Eventually,
2815 body: with_neg,
2816 })
2817 }
2818 None => with_neg,
2819 };
2820
2821 return Ok(result);
2822 }
2823
2824 if self.check_auxiliary_as_main_verb() {
2827 return self.parse_do_as_main_verb(subject_term);
2828 }
2829
2830 self.parse_finite_verb_vp(subject_symbol, subject_term, as_variable)
2831 }
2832
2833 pub(super) fn parse_finite_verb_vp(
2839 &mut self,
2840 subject_symbol: Symbol,
2841 subject_term: Term<'a>,
2842 as_variable: bool,
2843 ) -> ParseResult<&'a LogicExpr<'a>> {
2844 if self.check_verb() {
2845 let (verb, verb_time, verb_aspect, verb_class) = self.consume_verb_with_metadata();
2846 self.build_verb_vp(
2847 subject_symbol,
2848 subject_term,
2849 as_variable,
2850 verb,
2851 verb_time,
2852 verb_aspect,
2853 verb_class,
2854 )
2855 } else {
2856 Ok(self.ctx.exprs.alloc(LogicExpr::Atom(subject_symbol)))
2857 }
2858 }
2859
2860 pub(super) fn build_verb_vp(
2874 &mut self,
2875 subject_symbol: Symbol,
2876 subject_term: Term<'a>,
2877 as_variable: bool,
2878 verb: Symbol,
2879 verb_time: Time,
2880 verb_aspect: Aspect,
2881 verb_class: crate::lexicon::VerbClass,
2882 ) -> ParseResult<&'a LogicExpr<'a>> {
2883 let shared_prefix = self.capture_distributive_prefix();
2889
2890 let first = self.build_verb_vp_single(
2891 subject_symbol,
2892 subject_term.clone(),
2893 as_variable,
2894 verb,
2895 verb_time,
2896 verb_aspect,
2897 verb_class,
2898 )?;
2899
2900 let mut combined = first;
2901 loop {
2902 let mut k = self.current;
2906 let mut saw_coordinator = false;
2907 if matches!(self.tokens.get(k).map(|t| &t.kind), Some(TokenType::Comma)) {
2908 k += 1;
2909 saw_coordinator = true;
2910 }
2911 if matches!(self.tokens.get(k).map(|t| &t.kind), Some(TokenType::And)) {
2912 k += 1;
2913 saw_coordinator = true;
2914 }
2915 if !saw_coordinator {
2916 break;
2917 }
2918 let opens_object = matches!(
2922 self.tokens.get(k).map(|t| &t.kind),
2923 Some(TokenType::Article(_))
2924 | Some(TokenType::All)
2925 | Some(TokenType::Some)
2926 | Some(TokenType::No)
2927 | Some(TokenType::Any)
2928 | Some(TokenType::Most)
2929 | Some(TokenType::Few)
2930 | Some(TokenType::Many)
2931 | Some(TokenType::Noun(_))
2932 | Some(TokenType::ProperName(_))
2933 | Some(TokenType::CalendarUnit(_))
2934 | Some(TokenType::Ambiguous { .. })
2935 | Some(TokenType::Number(_))
2936 | Some(TokenType::Cardinal(_))
2937 );
2938 if !opens_object {
2939 break;
2940 }
2941 {
2949 let mut p = k;
2950 if matches!(
2951 self.tokens.get(p).map(|t| &t.kind),
2952 Some(TokenType::Article(_)) | Some(TokenType::All) | Some(TokenType::Some)
2953 | Some(TokenType::No) | Some(TokenType::Any) | Some(TokenType::Most)
2954 | Some(TokenType::Few) | Some(TokenType::Many)
2955 ) {
2956 p += 1;
2957 }
2958 while matches!(
2959 self.tokens.get(p).map(|t| &t.kind),
2960 Some(TokenType::Adjective(_)) | Some(TokenType::NonIntersectiveAdjective(_))
2961 ) {
2962 p += 1;
2963 }
2964 let head_start = p;
2965 while matches!(self.tokens.get(p).map(|t| &t.kind), Some(TokenType::Noun(_))) {
2966 p += 1;
2967 }
2968 let saw_noun_head = p > head_start;
2969 let verb_follows = self.tokens.get(p).map_or(false, |t| {
2970 self.kind_is_verb(&t.kind)
2971 || matches!(
2972 t.kind,
2973 TokenType::Auxiliary(_)
2974 | TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
2975 | TokenType::Must | TokenType::Can | TokenType::Should
2976 | TokenType::Could | TokenType::Would | TokenType::May
2977 | TokenType::Might | TokenType::Shall | TokenType::Cannot
2978 )
2979 });
2980 if saw_noun_head && verb_follows {
2981 break;
2982 }
2983 }
2984 self.current = k;
2986 let has_own_determiner = matches!(
2989 self.tokens.get(self.current).map(|t| &t.kind),
2990 Some(TokenType::Article(_))
2991 | Some(TokenType::All)
2992 | Some(TokenType::Some)
2993 | Some(TokenType::No)
2994 | Some(TokenType::Any)
2995 | Some(TokenType::Most)
2996 | Some(TokenType::Few)
2997 | Some(TokenType::Many)
2998 );
2999 if !has_own_determiner && !shared_prefix.is_empty() {
3000 self.splice_tokens(self.current, &shared_prefix);
3001 }
3002 let next = self.build_verb_vp_single(
3003 subject_symbol,
3004 subject_term.clone(),
3005 as_variable,
3006 verb,
3007 verb_time,
3008 verb_aspect,
3009 verb_class,
3010 )?;
3011 combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3012 left: combined,
3013 op: TokenType::And,
3014 right: next,
3015 });
3016 }
3017 Ok(combined)
3018 }
3019
3020 fn capture_distributive_prefix(&self) -> Vec<Token> {
3026 let mut p = self.current;
3027 let mut prefix: Vec<Token> = Vec::new();
3028 let is_quantifier = matches!(
3029 self.tokens.get(p).map(|t| &t.kind),
3030 Some(TokenType::All)
3031 | Some(TokenType::Some)
3032 | Some(TokenType::No)
3033 | Some(TokenType::Any)
3034 | Some(TokenType::Most)
3035 | Some(TokenType::Few)
3036 | Some(TokenType::Many)
3037 );
3038 if !is_quantifier {
3039 return prefix;
3040 }
3041 prefix.push(self.tokens[p].clone());
3042 p += 1;
3043 let mut q = p;
3045 let mut saw_noun = false;
3046 while matches!(
3047 self.tokens.get(q).map(|t| &t.kind),
3048 Some(TokenType::Noun(_)) | Some(TokenType::Ambiguous { .. })
3049 ) {
3050 saw_noun = true;
3051 q += 1;
3052 }
3053 if saw_noun
3054 && matches!(
3055 self.tokens.get(q).map(|t| &t.kind),
3056 Some(TokenType::Possessive)
3057 )
3058 {
3059 for t in &self.tokens[p..=q] {
3060 prefix.push(t.clone());
3061 }
3062 }
3063 prefix
3064 }
3065
3066 fn splice_tokens(&mut self, at: usize, toks: &[Token]) {
3068 for (i, t) in toks.iter().enumerate() {
3069 self.tokens.insert(at + i, t.clone());
3070 }
3071 }
3072
3073 pub(super) fn build_verb_vp_single(
3076 &mut self,
3077 subject_symbol: Symbol,
3078 subject_term: Term<'a>,
3079 as_variable: bool,
3080 mut verb: Symbol,
3081 verb_time: Time,
3082 verb_aspect: Aspect,
3083 verb_class: crate::lexicon::VerbClass,
3084 ) -> ParseResult<&'a LogicExpr<'a>> {
3085 let mut args = vec![subject_term.clone()];
3086
3087 if self.is_control_verb(verb) && self.check_to() {
3092 let subject_np = NounPhrase {
3093 noun: subject_symbol,
3094 definiteness: None,
3095 adjectives: &[],
3096 possessor: None,
3097 pps: &[],
3098 superlative: None,
3099 };
3100 let control = self.parse_control_structure(&subject_np, verb, verb_time)?;
3101 return if as_variable {
3102 self.substitute_constant_with_var(control, subject_symbol, subject_symbol)
3103 } else {
3104 Ok(control)
3105 };
3106 }
3107
3108 if let Some(cmp) = self.try_arithmetic_comparative(verb, subject_term.clone(), verb_time)? {
3112 return Ok(cmp);
3113 }
3114
3115 if let Some(off) = self.try_temporal_offset(verb, subject_term.clone(), verb_time)? {
3117 return Ok(off);
3118 }
3119
3120 if let Some(off) = self.try_positional_offset(verb, subject_term.clone(), verb_time)? {
3122 return Ok(off);
3123 }
3124
3125 if let TokenType::Comparative(comp_adj) = self.peek().kind.clone() {
3129 if matches!(
3130 self.tokens.get(self.current + 1).map(|t| t.kind.clone()),
3131 Some(TokenType::Than)
3132 ) {
3133 self.advance(); self.advance(); let event_var = self.get_event_var();
3137 let mut modifiers = Vec::new();
3138 let effective_time = self.pending_time.take().unwrap_or(verb_time);
3139 match effective_time {
3140 Time::Past => modifiers.push(self.interner.intern("Past")),
3141 Time::Future => modifiers.push(self.interner.intern("Future")),
3142 _ => {}
3143 }
3144 let suppress_existential = self.drs.in_conditional_antecedent();
3145 let event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
3146 event_var,
3147 verb,
3148 roles: self
3149 .ctx
3150 .roles
3151 .alloc_slice(vec![(ThematicRole::Agent, subject_term.clone())]),
3152 modifiers: self.ctx.syms.alloc_slice(modifiers),
3153 suppress_existential,
3154 world: None,
3155 })));
3156
3157 let result = if self.check_quantifier() {
3158 let q = self.advance().kind.clone();
3159 let std_np = self.parse_noun_phrase(false)?;
3160 let std_var = self.next_var_name();
3161 let restriction = self.ctx.exprs.alloc(LogicExpr::Predicate {
3162 name: std_np.noun,
3163 args: self.ctx.terms.alloc_slice([Term::Variable(std_var)]),
3164 world: None,
3165 });
3166 let comparison = self.ctx.exprs.alloc(LogicExpr::Comparative {
3167 adjective: comp_adj,
3168 subject: self.ctx.terms.alloc(subject_term.clone()),
3169 object: self.ctx.terms.alloc(Term::Variable(std_var)),
3170 difference: None,
3171 relation: crate::ast::logic::ComparisonRelation::Greater,
3172 });
3173 let (std_kind, std_op) = match q {
3174 TokenType::All => (QuantifierKind::Universal, TokenType::Implies),
3175 TokenType::Most => (QuantifierKind::Most, TokenType::And),
3176 TokenType::Few => (QuantifierKind::Few, TokenType::And),
3177 TokenType::Many => (QuantifierKind::Many, TokenType::And),
3178 _ => (QuantifierKind::Existential, TokenType::And),
3179 };
3180 let std_body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3181 left: restriction,
3182 op: std_op,
3183 right: comparison,
3184 });
3185 let quantified = self.ctx.exprs.alloc(LogicExpr::Quantifier {
3186 kind: std_kind,
3187 variable: std_var,
3188 body: std_body,
3189 island_id: self.current_island,
3190 });
3191 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3192 left: event,
3193 op: TokenType::And,
3194 right: quantified,
3195 })
3196 } else {
3197 let std_np = self.parse_noun_phrase(true)?;
3203 let has_rel = self.check(&TokenType::Who) || self.check(&TokenType::That);
3204 let is_desc = has_rel
3205 || std_np.definiteness.is_some()
3206 || !std_np.adjectives.is_empty()
3207 || std_np.possessor.is_some()
3208 || !std_np.pps.is_empty();
3209 if is_desc {
3210 let std_var = self.next_var_name();
3211 let mut restr =
3212 self.nominal_predication(Term::Variable(std_var), &std_np);
3213 for pp in std_np.pps {
3214 let pp_sub = self.substitute_pp_placeholder(pp, std_var);
3215 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3216 left: restr,
3217 op: TokenType::And,
3218 right: pp_sub,
3219 });
3220 }
3221 if has_rel {
3222 self.advance(); let rel = self.parse_relative_clause(std_var)?;
3224 restr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3225 left: restr,
3226 op: TokenType::And,
3227 right: rel,
3228 });
3229 }
3230 let comparison = self.ctx.exprs.alloc(LogicExpr::Comparative {
3231 adjective: comp_adj,
3232 subject: self.ctx.terms.alloc(subject_term.clone()),
3233 object: self.ctx.terms.alloc(Term::Variable(std_var)),
3234 difference: None,
3235 relation: crate::ast::logic::ComparisonRelation::Greater,
3236 });
3237 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3238 left: restr,
3239 op: TokenType::And,
3240 right: comparison,
3241 });
3242 let quantified = self.ctx.exprs.alloc(LogicExpr::Quantifier {
3243 kind: QuantifierKind::Existential,
3244 variable: std_var,
3245 body,
3246 island_id: self.current_island,
3247 });
3248 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3249 left: event,
3250 op: TokenType::And,
3251 right: quantified,
3252 })
3253 } else {
3254 let comparison = self.ctx.exprs.alloc(LogicExpr::Comparative {
3255 adjective: comp_adj,
3256 subject: self.ctx.terms.alloc(subject_term.clone()),
3257 object: self.ctx.terms.alloc(Term::Constant(std_np.noun)),
3258 difference: None,
3259 relation: crate::ast::logic::ComparisonRelation::Greater,
3260 });
3261 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3262 left: event,
3263 op: TokenType::And,
3264 right: comparison,
3265 })
3266 }
3267 };
3268 return Ok(result);
3269 }
3270 }
3271
3272 if crate::lexicon::is_perception_verb(&self.interner.resolve(verb).to_lowercase()) {
3277 let mut vp_idx = None;
3278 let mut i = self.current;
3279 while i < self.tokens.len()
3280 && !matches!(
3281 self.tokens[i].kind,
3282 TokenType::Period | TokenType::EOF | TokenType::Comma
3283 )
3284 {
3285 let is_verb_reading = match &self.tokens[i].kind {
3289 TokenType::Verb { .. } => true,
3290 TokenType::Ambiguous { primary, .. } if !self.noun_priority_mode => {
3291 matches!(**primary, TokenType::Verb { .. })
3292 }
3293 _ => false,
3294 };
3295 if is_verb_reading {
3296 vp_idx = Some(i);
3297 }
3298 i += 1;
3299 }
3300 if let Some(vp_i) = vp_idx {
3301 if vp_i > self.current {
3302 let psubj = match self.tokens[vp_i - 1].kind.clone() {
3303 TokenType::Noun(n) | TokenType::ProperName(n) => Some(n),
3304 TokenType::Pronoun { .. } | TokenType::Ambiguous { .. } => {
3305 let lx = self
3306 .interner
3307 .resolve(self.tokens[vp_i - 1].lexeme)
3308 .to_lowercase();
3309 let cap = lx
3310 .chars()
3311 .next()
3312 .map(|c| c.to_uppercase().collect::<String>() + &lx[1..])
3313 .unwrap_or(lx);
3314 Some(self.interner.intern(&cap))
3315 }
3316 _ => None,
3317 };
3318 if let Some(psubj) = psubj {
3319 let inner_verb = match &self.tokens[vp_i].kind {
3320 TokenType::Verb { lemma, .. } => *lemma,
3321 TokenType::Ambiguous { primary, .. } => {
3322 if let TokenType::Verb { lemma, .. } = **primary {
3323 lemma
3324 } else {
3325 unreachable!("gated on verb reading")
3326 }
3327 }
3328 _ => unreachable!("gated on verb reading"),
3329 };
3330 self.current = vp_i + 1; let perceived = self.ctx.exprs.alloc(LogicExpr::Predicate {
3332 name: inner_verb,
3333 args: self.ctx.terms.alloc_slice([Term::Constant(psubj)]),
3334 world: None,
3335 });
3336 let perceived_advs = self.collect_adverbs();
3337 let perceived = if perceived_advs.is_empty() {
3338 perceived
3339 } else {
3340 self.ctx.exprs.alloc(LogicExpr::Event {
3341 predicate: perceived,
3342 adverbs: self.ctx.syms.alloc_slice(perceived_advs),
3343 })
3344 };
3345 let mut modifiers: Vec<Symbol> = Vec::new();
3346 match verb_time {
3347 Time::Past => modifiers.push(self.interner.intern("Past")),
3348 Time::Future => modifiers.push(self.interner.intern("Future")),
3349 _ => {}
3350 }
3351 let event_var = self.get_event_var();
3352 let suppress_existential = self.drs.in_conditional_antecedent();
3353 return Ok(self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(
3354 NeoEventData {
3355 event_var,
3356 verb,
3357 roles: self.ctx.roles.alloc_slice(vec![
3358 (ThematicRole::Agent, subject_term.clone()),
3359 (ThematicRole::Theme, Term::Proposition(perceived)),
3360 ]),
3361 modifiers: self.ctx.syms.alloc_slice(modifiers),
3362 suppress_existential,
3363 world: None,
3364 },
3365 ))));
3366 }
3367 }
3368 }
3369 }
3370
3371 if self.check_wh_word() {
3373 let wh_token = self.advance().kind.clone();
3374
3375 let is_who = matches!(wh_token, TokenType::Who);
3376 let is_what = matches!(wh_token, TokenType::What);
3377
3378 let is_sluicing = self.is_at_end() ||
3380 self.check(&TokenType::Period) ||
3381 self.check(&TokenType::Comma);
3382
3383 if is_sluicing {
3384 if let Some(template) = self.last_event_template.clone() {
3385 let wh_var = self.next_var_name();
3386
3387 let roles: Vec<_> = if is_who {
3388 std::iter::once((ThematicRole::Agent, Term::Variable(wh_var)))
3389 .chain(template.non_agent_roles.iter().cloned())
3390 .collect()
3391 } else if is_what {
3392 vec![
3393 (ThematicRole::Agent, subject_term.clone()),
3394 (ThematicRole::Theme, Term::Variable(wh_var)),
3395 ]
3396 } else {
3397 std::iter::once((ThematicRole::Agent, Term::Variable(wh_var)))
3398 .chain(template.non_agent_roles.iter().cloned())
3399 .collect()
3400 };
3401
3402 let event_var = self.get_event_var();
3403 let suppress_existential = self.drs.in_conditional_antecedent();
3404 let reconstructed = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
3405 event_var,
3406 verb: template.verb,
3407 roles: self.ctx.roles.alloc_slice(roles),
3408 modifiers: self.ctx.syms.alloc_slice(template.modifiers.clone()),
3409 suppress_existential,
3410 world: None,
3411 })));
3412
3413 let question = self.ctx.exprs.alloc(LogicExpr::Question {
3414 wh_variable: wh_var,
3415 body: reconstructed,
3416 });
3417
3418 let know_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
3419 event_var: self.get_event_var(),
3420 verb,
3421 roles: self.ctx.roles.alloc_slice(vec![
3422 (ThematicRole::Agent, subject_term),
3423 (ThematicRole::Theme, Term::Proposition(question)),
3424 ]),
3425 modifiers: self.ctx.syms.alloc_slice(vec![]),
3426 suppress_existential,
3427 world: None,
3428 })));
3429
3430 return Ok(know_event);
3431 }
3432 }
3433
3434 let embedded = self.parse_embedded_wh_clause()?;
3436 let question = self.ctx.exprs.alloc(LogicExpr::Question {
3437 wh_variable: self.interner.intern("x"),
3438 body: embedded,
3439 });
3440
3441 let suppress_existential = self.drs.in_conditional_antecedent();
3442 let know_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
3443 event_var: self.get_event_var(),
3444 verb,
3445 roles: self.ctx.roles.alloc_slice(vec![
3446 (ThematicRole::Agent, subject_term),
3447 (ThematicRole::Theme, Term::Proposition(question)),
3448 ]),
3449 modifiers: self.ctx.syms.alloc_slice(vec![]),
3450 suppress_existential,
3451 world: None,
3452 })));
3453
3454 return Ok(know_event);
3455 }
3456
3457 if crate::lexicon::is_opaque_verb(&self.interner.resolve(verb).to_lowercase()) {
3464 let mut i = self.current;
3465 if i < self.tokens.len() && matches!(self.tokens[i].kind, TokenType::That) {
3466 i += 1;
3467 }
3468 let subj_is_name_or_pronoun = i < self.tokens.len()
3469 && matches!(
3470 self.tokens[i].kind,
3471 TokenType::ProperName(_) | TokenType::Pronoun { .. }
3472 );
3473 let verb_follows = subj_is_name_or_pronoun
3474 && i + 1 < self.tokens.len()
3475 && matches!(
3476 self.tokens[i + 1].kind,
3477 TokenType::Verb { .. } | TokenType::Auxiliary(_)
3478 );
3479 let definite_np_clause = i + 2 < self.tokens.len()
3483 && matches!(self.tokens[i].kind, TokenType::Article(_))
3484 && matches!(self.tokens[i + 1].kind, TokenType::Noun(_))
3485 && matches!(
3486 self.tokens[i + 2].kind,
3487 TokenType::Verb { .. } | TokenType::Auxiliary(_)
3488 );
3489 if verb_follows || definite_np_clause {
3490 if self.check(&TokenType::That) {
3491 self.advance();
3492 }
3493 let embedded_subject = match self.peek().kind {
3494 TokenType::ProperName(s) => {
3495 self.advance();
3496 s
3497 }
3498 TokenType::Pronoun { gender, number, .. } => {
3499 self.advance();
3500 match self.resolve_pronoun(gender, number)? {
3501 super::ResolvedPronoun::Variable(s)
3502 | super::ResolvedPronoun::Constant(s) => s,
3503 }
3504 }
3505 TokenType::Article(_) => {
3506 let np = self.parse_noun_phrase(false)?;
3507 np.noun
3508 }
3509 _ => unreachable!("guarded by subj_is_name_or_pronoun"),
3510 };
3511 let embedded_pred = self.parse_predicate_with_subject(embedded_subject)?;
3512 let embedded_term = Term::Proposition(embedded_pred);
3513 let main_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
3514 name: verb,
3515 args: self
3516 .ctx
3517 .terms
3518 .alloc_slice([subject_term.clone(), embedded_term]),
3519 world: None,
3520 });
3521 let effective_time = self.pending_time.take().unwrap_or(verb_time);
3522 return Ok(if effective_time == Time::Past {
3523 self.ctx.exprs.alloc(LogicExpr::Temporal {
3524 operator: TemporalOperator::Past,
3525 body: main_pred,
3526 })
3527 } else {
3528 main_pred
3529 });
3530 }
3531 }
3532
3533 let mut object_term: Option<Term<'a>> = None;
3534 let mut second_object_term: Option<Term<'a>> = None;
3535 let mut as_role: Option<Symbol> = None;
3538 let mut gap_object = false;
3540 let mut object_pps: &[&LogicExpr<'a>] = &[]; let mut object_adjectives: &[Symbol] = &[]; if self.check(&TokenType::Reflexive) {
3543 self.advance();
3544 let term = subject_term.clone();
3548 object_term = Some(term.clone());
3549 args.push(term);
3550 } else if self.check_pronoun()
3551 && !(self.check_possessive_pronoun()
3552 && match self.tokens.get(self.current + 1).map(|t| t.kind.clone()) {
3553 Some(TokenType::Noun(_)) => true,
3554 Some(TokenType::Ambiguous { .. }) => self.noun_priority_mode,
3557 _ => false,
3558 })
3559 {
3560 let token = self.advance().clone();
3561 let (gender, number) = match &token.kind {
3562 TokenType::Pronoun { gender, number, .. } => (*gender, *number),
3563 TokenType::Ambiguous { primary, alternatives } => {
3564 if let TokenType::Pronoun { gender, number, .. } = **primary {
3565 (gender, number)
3566 } else {
3567 alternatives.iter().find_map(|t| {
3568 if let TokenType::Pronoun { gender, number, .. } = t {
3569 Some((*gender, *number))
3570 } else {
3571 None
3572 }
3573 }).unwrap_or((Gender::Unknown, Number::Singular))
3574 }
3575 }
3576 _ => (Gender::Unknown, Number::Singular),
3577 };
3578
3579 let plex = self.interner.resolve(token.lexeme).to_lowercase();
3582 let term = match plex.as_str() {
3583 "you" | "yourself" => Term::Constant(self.interner.intern("Addressee")),
3584 "me" | "myself" | "i" => Term::Constant(self.interner.intern("Speaker")),
3585 _ => match self.resolve_donkey_pronoun(gender) {
3589 Some(donkey_var) => Term::Variable(donkey_var),
3590 None => match self.resolve_pronoun(gender, number)? {
3591 super::ResolvedPronoun::Variable(s) => Term::Variable(s),
3592 super::ResolvedPronoun::Constant(s) => Term::Constant(s),
3593 },
3594 },
3595 };
3596 object_term = Some(term);
3597 args.push(term);
3598
3599 let verb_str = self.interner.resolve(verb);
3600 if Lexer::is_ditransitive_verb(verb_str)
3601 && (self.check_content_word() || self.check_article())
3602 {
3603 let second_np = self.parse_noun_phrase(false)?;
3604 let second_term = Term::Constant(second_np.noun);
3605 second_object_term = Some(second_term);
3606 args.push(second_term);
3607 }
3608 } else if self.peek_definite_reduced_relative_object() {
3609 self.nominal_np_context = true;
3621 let object_np_result = self.parse_noun_phrase(true);
3622 self.nominal_np_context = false;
3623 let object_np = object_np_result?;
3624
3625 let obj_gender = Self::infer_noun_gender(self.interner.resolve(object_np.noun));
3626 let obj_number = if Self::is_plural_noun(self.interner.resolve(object_np.noun)) {
3627 Number::Plural
3628 } else {
3629 Number::Singular
3630 };
3631 self.drs.introduce_referent_with_source(
3632 object_np.noun,
3633 object_np.noun,
3634 obj_gender,
3635 obj_number,
3636 ReferentSource::MainClause,
3637 );
3638
3639 let term = Term::Constant(object_np.noun);
3640 object_term = Some(term);
3641 object_pps = object_np.pps;
3642 object_adjectives = object_np.adjectives;
3643 args.push(term);
3644 } else if self.counting_np_lookahead().is_some()
3645 || self.check_quantifier()
3646 || self.check_article()
3647 || self.check_possessive_pronoun()
3648 {
3649 let obj_quantifier = if let Some(n) = self.counting_np_lookahead() {
3650 self.advance();
3657 Some(TokenType::Cardinal(n))
3658 } else if self.check_possessive_pronoun() {
3659 None
3662 } else if self.check_quantifier() {
3663 Some(self.advance().kind.clone())
3664 } else {
3665 let art = self.advance().kind.clone();
3666 if let TokenType::Article(def) = art {
3667 if def == Definiteness::Indefinite {
3668 Some(TokenType::Some)
3669 } else {
3670 None
3671 }
3672 } else {
3673 None
3674 }
3675 };
3676
3677 self.nominal_np_context = true;
3680 let object_np_result = self.parse_noun_phrase(false);
3681 self.nominal_np_context = false;
3682 let object_np = object_np_result?;
3683
3684 if let Some(obj_q) = obj_quantifier {
3685 let obj_var = self.next_var_name();
3686
3687 let obj_gender = Self::infer_noun_gender(self.interner.resolve(object_np.noun));
3689 let obj_number = if Self::is_plural_noun(self.interner.resolve(object_np.noun)) {
3690 Number::Plural
3691 } else {
3692 Number::Singular
3693 };
3694 if object_np.definiteness == Some(Definiteness::Definite) {
3696 self.drs.introduce_referent_with_source(obj_var, object_np.noun, obj_gender, obj_number, ReferentSource::MainClause);
3697 } else {
3698 self.drs.introduce_referent(obj_var, object_np.noun, obj_gender, obj_number);
3699 }
3700
3701 let mut obj_restriction: &'a LogicExpr<'a> =
3702 self.ctx.exprs.alloc(LogicExpr::Predicate {
3703 name: object_np.noun,
3704 args: self.ctx.terms.alloc_slice([Term::Variable(obj_var)]),
3705 world: None,
3706 });
3707 for &adj in object_np.adjectives {
3711 let adj_pred = self.adjective_restriction(adj, obj_var, object_np.noun);
3712 obj_restriction = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3713 left: obj_restriction,
3714 op: TokenType::And,
3715 right: adj_pred,
3716 });
3717 }
3718 for pp in object_np.pps {
3719 let pp_sub = self.substitute_pp_placeholder(pp, obj_var);
3720 obj_restriction = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3721 left: obj_restriction,
3722 op: TokenType::And,
3723 right: pp_sub,
3724 });
3725 }
3726
3727 let verb_str = self.interner.resolve(verb).to_string();
3732 let mut second_object: Option<Term<'a>> = None;
3733 let mut recipient: Option<Term<'a>> = None;
3734 let mut recipient_quant: Option<(TokenType, Symbol, Symbol)> = None;
3735 let mut control_infinitive: Option<Symbol> = None;
3736
3737 if Lexer::is_ditransitive_verb(&verb_str)
3738 && (self.check_content_word() || self.check_article())
3739 {
3740 let second_np = self.parse_noun_phrase(false)?;
3741 second_object = Some(Term::Constant(second_np.noun));
3742 } else if self.check_to_marker() {
3743 let after_to = self.tokens.get(self.current + 1).map(|t| t.kind.clone());
3744 match after_to {
3745 Some(TokenType::Verb { lemma, .. }) => {
3746 self.advance(); self.advance(); control_infinitive = Some(lemma);
3749 }
3750 Some(TokenType::Noun(word))
3754 if crate::lexicon::lookup_verb_db(
3755 &self.interner.resolve(word).to_lowercase(),
3756 )
3757 .is_some() =>
3758 {
3759 let lemma_str = crate::lexicon::lookup_verb_db(
3760 &self.interner.resolve(word).to_lowercase(),
3761 )
3762 .map(|m| m.lemma)
3763 .unwrap();
3764 self.advance(); self.advance(); control_infinitive = Some(self.interner.intern(lemma_str));
3767 }
3768 Some(kind)
3769 if Lexer::is_ditransitive_verb(&verb_str)
3770 && matches!(
3771 kind,
3772 TokenType::All
3773 | TokenType::Some
3774 | TokenType::No
3775 | TokenType::Most
3776 | TokenType::Few
3777 | TokenType::Many
3778 | TokenType::Cardinal(_)
3779 | TokenType::AtLeast(_)
3780 | TokenType::AtMost(_)
3781 ) =>
3782 {
3783 self.advance(); let r_quant = self.advance().kind.clone();
3785 let r_np = self.parse_noun_phrase(false)?;
3786 let r_var = self.next_var_name();
3787 recipient_quant = Some((r_quant, r_var, r_np.noun));
3788 }
3789 Some(kind)
3790 if Lexer::is_ditransitive_verb(&verb_str)
3791 && matches!(
3792 kind,
3793 TokenType::ProperName(_)
3794 | TokenType::Noun(_)
3795 | TokenType::Article(_)
3796 ) =>
3797 {
3798 self.advance(); let r_np = self.parse_noun_phrase(false)?;
3800 recipient = Some(Term::Constant(r_np.noun));
3801 }
3802 _ => {}
3803 }
3804 }
3805
3806 let event_var = self.get_event_var();
3807 let mut modifiers = self.collect_adverbs();
3808 let effective_time = self.pending_time.take().unwrap_or(verb_time);
3809 match effective_time {
3810 Time::Past => modifiers.push(self.interner.intern("Past")),
3811 Time::Future => modifiers.push(self.interner.intern("Future")),
3812 _ => {}
3813 }
3814
3815 let mut roles = vec![(ThematicRole::Agent, subject_term.clone())];
3816 if let Some(second) = second_object {
3817 roles.push((ThematicRole::Recipient, Term::Variable(obj_var)));
3818 roles.push((ThematicRole::Theme, second));
3819 } else {
3820 roles.push((ThematicRole::Theme, Term::Variable(obj_var)));
3821 if let Some(r) = recipient {
3822 roles.push((ThematicRole::Recipient, r));
3823 } else if let Some((_, r_var, _)) = recipient_quant {
3824 roles.push((ThematicRole::Recipient, Term::Variable(r_var)));
3825 }
3826 }
3827
3828 let suppress_existential = self.drs.in_conditional_antecedent();
3829 let neo_event = if let Some(inf) = control_infinitive {
3830 let inf_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
3831 name: inf,
3832 args: self.ctx.terms.alloc_slice([Term::Variable(obj_var)]),
3833 world: None,
3834 });
3835 let control = self.ctx.exprs.alloc(LogicExpr::Control {
3836 verb,
3837 subject: self.ctx.terms.alloc(subject_term.clone()),
3838 object: Some(&*self.ctx.terms.alloc(Term::Variable(obj_var))),
3839 infinitive: inf_pred,
3840 });
3841 match effective_time {
3842 Time::Past => &*self.ctx.exprs.alloc(LogicExpr::Temporal {
3843 operator: TemporalOperator::Past,
3844 body: control,
3845 }),
3846 Time::Future => &*self.ctx.exprs.alloc(LogicExpr::Temporal {
3847 operator: TemporalOperator::Future,
3848 body: control,
3849 }),
3850 _ => control,
3851 }
3852 } else {
3853 let plain = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
3854 event_var,
3855 verb,
3856 roles: self.ctx.roles.alloc_slice(roles),
3857 modifiers: self.ctx.syms.alloc_slice(modifiers),
3858 suppress_existential,
3859 world: None,
3860 })));
3861 if let Some((r_quant, r_var, r_noun)) = recipient_quant {
3862 let r_restriction = self.ctx.exprs.alloc(LogicExpr::Predicate {
3863 name: r_noun,
3864 args: self.ctx.terms.alloc_slice([Term::Variable(r_var)]),
3865 world: None,
3866 });
3867 let r_kind = match r_quant {
3868 TokenType::All => QuantifierKind::Universal,
3869 TokenType::Most => QuantifierKind::Most,
3870 TokenType::Few => QuantifierKind::Few,
3871 TokenType::Many => QuantifierKind::Many,
3872 TokenType::Cardinal(n) => QuantifierKind::Cardinal(n),
3873 TokenType::AtLeast(n) => QuantifierKind::AtLeast(n),
3874 TokenType::AtMost(n) => QuantifierKind::AtMost(n),
3875 _ => QuantifierKind::Existential,
3876 };
3877 let r_body = if matches!(r_kind, QuantifierKind::Universal) {
3878 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3879 left: r_restriction,
3880 op: TokenType::Implies,
3881 right: plain,
3882 })
3883 } else {
3884 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3885 left: r_restriction,
3886 op: TokenType::And,
3887 right: plain,
3888 })
3889 };
3890 &*self.ctx.exprs.alloc(LogicExpr::Quantifier {
3891 kind: r_kind,
3892 variable: r_var,
3893 body: r_body,
3894 island_id: self.current_island,
3895 })
3896 } else {
3897 plain
3898 }
3899 };
3900
3901 let neo_event = self.attach_trailing_event_pps(neo_event, event_var)?;
3905
3906 let obj_kind = match obj_q {
3907 TokenType::All => QuantifierKind::Universal,
3908 TokenType::Some => QuantifierKind::Existential,
3909 TokenType::No => QuantifierKind::Universal,
3910 TokenType::Most => QuantifierKind::Most,
3911 TokenType::Few => QuantifierKind::Few,
3912 TokenType::Many => QuantifierKind::Many,
3913 TokenType::Cardinal(n) => QuantifierKind::Cardinal(n),
3914 TokenType::AtLeast(n) => QuantifierKind::AtLeast(n),
3915 TokenType::AtMost(n) => QuantifierKind::AtMost(n),
3916 _ => QuantifierKind::Existential,
3917 };
3918
3919 let obj_body = match obj_q {
3920 TokenType::All => self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3921 left: obj_restriction,
3922 op: TokenType::Implies,
3923 right: neo_event,
3924 }),
3925 TokenType::No => {
3926 let neg = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
3927 op: TokenType::Not,
3928 operand: neo_event,
3929 });
3930 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3931 left: obj_restriction,
3932 op: TokenType::Implies,
3933 right: neg,
3934 })
3935 }
3936 _ => self.ctx.exprs.alloc(LogicExpr::BinaryOp {
3937 left: obj_restriction,
3938 op: TokenType::And,
3939 right: neo_event,
3940 }),
3941 };
3942
3943 return Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
3944 kind: obj_kind,
3945 variable: obj_var,
3946 body: obj_body,
3947 island_id: self.current_island,
3948 }));
3949 } else {
3950 if object_np.definiteness == Some(Definiteness::Definite) {
3954 let obj_gender = Self::infer_noun_gender(self.interner.resolve(object_np.noun));
3955 let obj_number = if Self::is_plural_noun(self.interner.resolve(object_np.noun)) {
3956 Number::Plural
3957 } else {
3958 Number::Singular
3959 };
3960 self.drs.introduce_referent_with_source(object_np.noun, object_np.noun, obj_gender, obj_number, ReferentSource::MainClause);
3962 }
3963
3964 let term = Term::Constant(object_np.noun);
3965 object_term = Some(term);
3966 object_pps = object_np.pps;
3970 object_adjectives = object_np.adjectives;
3971 args.push(term);
3972
3973 let verb_str = self.interner.resolve(verb);
3981 if Lexer::is_ditransitive_verb(verb_str)
3982 && (self.check_content_word() || self.check_article())
3983 {
3984 let second_np = self.parse_noun_phrase(false)?;
3985 let second_term = Term::Constant(second_np.noun);
3986 second_object_term = Some(second_term);
3987 args.push(second_term);
3988 }
3989 }
3990 } else if self.check_focus() {
3991 let focus_kind = if let TokenType::Focus(k) = self.advance().kind {
3992 k
3993 } else {
3994 FocusKind::Only
3995 };
3996
3997 let event_var = self.get_event_var();
3998 let mut modifiers = self.collect_adverbs();
3999 let effective_time = self.pending_time.take().unwrap_or(verb_time);
4000 match effective_time {
4001 Time::Past => modifiers.push(self.interner.intern("Past")),
4002 Time::Future => modifiers.push(self.interner.intern("Future")),
4003 _ => {}
4004 }
4005
4006 if self.check_preposition() {
4007 let prep_token = self.advance().clone();
4008 let prep_name = if let TokenType::Preposition(sym) = prep_token.kind {
4009 sym
4010 } else {
4011 self.interner.intern("to")
4012 };
4013 let pp_obj = self.parse_noun_phrase(false)?;
4014 let pp_obj_term = Term::Constant(pp_obj.noun);
4015
4016 let roles = vec![(ThematicRole::Agent, subject_term)];
4017 let suppress_existential = self.drs.in_conditional_antecedent();
4018 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
4019 event_var,
4020 verb,
4021 roles: self.ctx.roles.alloc_slice(roles),
4022 modifiers: self.ctx.syms.alloc_slice(modifiers),
4023 suppress_existential,
4024 world: None,
4025 })));
4026
4027 let pp_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
4028 name: prep_name,
4029 args: self.ctx.terms.alloc_slice([Term::Variable(event_var), pp_obj_term]),
4030 world: None,
4031 });
4032
4033 let with_pp = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4034 left: neo_event,
4035 op: TokenType::And,
4036 right: pp_pred,
4037 });
4038
4039 let focused_ref = self.ctx.terms.alloc(pp_obj_term);
4040 return Ok(self.ctx.exprs.alloc(LogicExpr::Focus {
4041 kind: focus_kind,
4042 focused: focused_ref,
4043 scope: with_pp,
4044 }));
4045 }
4046
4047 let focused_np = self.parse_noun_phrase(false)?;
4048 let focused_term = Term::Constant(focused_np.noun);
4049 args.push(focused_term);
4050
4051 let roles = vec![
4052 (ThematicRole::Agent, subject_term),
4053 (ThematicRole::Theme, focused_term),
4054 ];
4055
4056 let suppress_existential = self.drs.in_conditional_antecedent();
4057 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
4058 event_var,
4059 verb,
4060 roles: self.ctx.roles.alloc_slice(roles),
4061 modifiers: self.ctx.syms.alloc_slice(modifiers),
4062 suppress_existential,
4063 world: None,
4064 })));
4065
4066 let focused_ref = self.ctx.terms.alloc(focused_term);
4067 return Ok(self.ctx.exprs.alloc(LogicExpr::Focus {
4068 kind: focus_kind,
4069 focused: focused_ref,
4070 scope: neo_event,
4071 }));
4072 } else if self.check(&TokenType::Either) {
4073 self.advance(); let np1 = self.parse_noun_phrase(true)?;
4076 if self.check(&TokenType::Or) {
4077 self.advance(); let np2 = self.parse_noun_phrase(true)?;
4079 let effective_time = self.pending_time.take().unwrap_or(verb_time);
4080 let placeholder = self.interner.intern("_PP_SELF_");
4081 let possesses = self.interner.intern("Possesses");
4082 let mut build = |p: &mut Self, np: &NounPhrase<'a>| -> &'a LogicExpr<'a> {
4087 let obj = Term::Constant(np.noun);
4088 let mut pred: &'a LogicExpr<'a> = p.ctx.exprs.alloc(LogicExpr::Predicate {
4089 name: verb,
4090 args: p.ctx.terms.alloc_slice([subject_term, obj]),
4091 world: None,
4092 });
4093 if let Some(possessor) = np.possessor {
4094 let poss = p.ctx.exprs.alloc(LogicExpr::Predicate {
4095 name: possesses,
4096 args: p
4097 .ctx
4098 .terms
4099 .alloc_slice([Term::Constant(possessor.noun), obj]),
4100 world: None,
4101 });
4102 pred = p.ctx.exprs.alloc(LogicExpr::BinaryOp {
4103 left: pred,
4104 op: TokenType::And,
4105 right: poss,
4106 });
4107 }
4108 for pp in np.pps {
4109 let pp_sub = match pp {
4110 LogicExpr::Predicate { name, args, world } => {
4111 let new_args: Vec<Term<'a>> = args
4112 .iter()
4113 .map(|a| match a {
4114 Term::Variable(v) if *v == placeholder => obj,
4115 other => *other,
4116 })
4117 .collect();
4118 p.ctx.exprs.alloc(LogicExpr::Predicate {
4119 name: *name,
4120 args: p.ctx.terms.alloc_slice(new_args),
4121 world: *world,
4122 })
4123 }
4124 other => *other,
4125 };
4126 pred = p.ctx.exprs.alloc(LogicExpr::BinaryOp {
4127 left: pred,
4128 op: TokenType::And,
4129 right: pp_sub,
4130 });
4131 }
4132 pred
4133 };
4134 let pred1 = build(self, &np1);
4135 let pred2 = build(self, &np2);
4136 let mut wrap_time = |p: &mut Self, e: &'a LogicExpr<'a>| -> &'a LogicExpr<'a> {
4137 if effective_time == Time::Past {
4138 p.ctx.exprs.alloc(LogicExpr::Temporal {
4139 operator: TemporalOperator::Past,
4140 body: e,
4141 })
4142 } else {
4143 e
4144 }
4145 };
4146 let pred1 = wrap_time(self, pred1);
4147 let pred2 = wrap_time(self, pred2);
4148 return Ok(self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4149 left: pred1,
4150 op: TokenType::Or,
4151 right: pred2,
4152 }));
4153 }
4154 let term = Term::Constant(np1.noun);
4156 object_term = Some(term);
4157 args.push(term);
4158 } else if self.check_number() {
4159 let measure = self.parse_measure_phrase()?;
4160 object_term = Some(*measure);
4164 if self.check_content_word() {
4165 let noun_sym = self.consume_content_word()?;
4166 args.push(*measure);
4167 args.push(Term::Constant(noun_sym));
4168 } else {
4169 args.push(*measure);
4170 }
4171 } else if self.check_content_word() {
4172 let potential_object = self.parse_noun_phrase(false)?;
4173 object_pps = potential_object.pps;
4175 object_adjectives = potential_object.adjectives;
4176
4177 let verb_is_opaque =
4184 crate::lexicon::is_opaque_verb(&self.interner.resolve(verb).to_lowercase());
4185 if self.check_verb() && (self.filler_gap.is_some() || verb_is_opaque) {
4186 let embedded_subject = potential_object.noun;
4187 let embedded_pred = self.parse_predicate_with_subject(embedded_subject)?;
4188
4189 let embedded_term = Term::Proposition(embedded_pred);
4190 let main_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
4191 name: verb,
4192 args: self.ctx.terms.alloc_slice([subject_term, embedded_term]),
4193 world: None,
4194 });
4195
4196 let effective_time = self.pending_time.take().unwrap_or(verb_time);
4197 return Ok(if effective_time == Time::Past {
4198 self.ctx.exprs.alloc(LogicExpr::Temporal {
4199 operator: TemporalOperator::Past,
4200 body: main_pred,
4201 })
4202 } else {
4203 main_pred
4204 });
4205 }
4206
4207 let mut all_objects: Vec<Symbol> = vec![potential_object.noun];
4209
4210 while self.check(&TokenType::And) {
4212 let saved = self.current;
4213 self.advance(); if self.check_content_word() || self.check_article() {
4215 let next_obj = match self.parse_noun_phrase(false) {
4216 Ok(np) => np,
4217 Err(_) => {
4218 self.current = saved;
4219 break;
4220 }
4221 };
4222 all_objects.push(next_obj.noun);
4223 } else {
4224 self.current = saved;
4225 break;
4226 }
4227 }
4228
4229 if self.check(&TokenType::Respectively) {
4231 let respectively_span = self.peek().span;
4232 if all_objects.len() > 1 {
4234 return Err(ParseError {
4235 kind: ParseErrorKind::RespectivelyLengthMismatch {
4236 subject_count: 1,
4237 object_count: all_objects.len(),
4238 },
4239 span: respectively_span,
4240 });
4241 }
4242 self.advance(); }
4245
4246 let term = Term::Constant(all_objects[0]);
4248 object_term = Some(term);
4249 args.push(term);
4250
4251 if all_objects.len() > 1 {
4253 let obj_members: Vec<Term<'a>> = all_objects.iter()
4254 .map(|o| Term::Constant(*o))
4255 .collect();
4256 let obj_group = Term::Group(self.ctx.terms.alloc_slice(obj_members));
4257 args.pop();
4263 args.push(obj_group);
4264 object_term = Some(obj_group);
4265 }
4266
4267 let verb_str = self.interner.resolve(verb);
4268 if Lexer::is_ditransitive_verb(verb_str)
4269 && (self.check_content_word() || self.check_article())
4270 {
4271 let second_np = self.parse_noun_phrase(false)?;
4272 let second_term = Term::Constant(second_np.noun);
4273 second_object_term = Some(second_term);
4274 args.push(second_term);
4275 }
4276 } else if self.filler_gap.is_some() && !self.check_content_word() && !self.check_pronoun()
4277 {
4278 let gap_var = self.filler_gap.take().unwrap();
4279 let term = Term::Variable(gap_var);
4280 object_term = Some(term);
4281 args.push(term);
4282 gap_object = true;
4283 }
4284
4285 let unknown = self.interner.intern("?");
4286 let mut pp_predicates: Vec<&'a LogicExpr<'a>> = Vec::new();
4287
4288 if let TokenType::Particle(particle_sym) = self.peek().kind {
4290 let verb_str = self.interner.resolve(verb).to_lowercase();
4291 let particle_str = self.interner.resolve(particle_sym).to_lowercase();
4292 if let Some((phrasal_lemma, _class)) = crate::lexicon::lookup_phrasal_verb(&verb_str, &particle_str) {
4293 self.advance(); verb = self.interner.intern(phrasal_lemma);
4295 } else {
4296 self.advance(); let event_sym = self.get_event_var();
4303 let cap = {
4304 let p = self.interner.resolve(particle_sym);
4305 let mut chs = p.chars();
4306 match chs.next() {
4307 Some(f) => f.to_uppercase().collect::<String>() + chs.as_str(),
4308 None => String::new(),
4309 }
4310 };
4311 pp_predicates.push(self.ctx.exprs.alloc(LogicExpr::Predicate {
4312 name: self.interner.intern(&cap),
4313 args: self.ctx.terms.alloc_slice([Term::Variable(event_sym)]),
4314 world: None,
4315 }));
4316 }
4317 }
4318 while self.check_preposition() || self.check_to() {
4319 if self.check_preposition_is("within") && self.current + 1 < self.tokens.len()
4321 && matches!(self.tokens[self.current + 1].kind, TokenType::Cardinal(_) | TokenType::Number(_))
4322 {
4323 break;
4324 }
4325 let prep_token = self.advance().clone();
4326 let prep_name = if let TokenType::Preposition(sym) = prep_token.kind {
4327 sym
4328 } else if matches!(prep_token.kind, TokenType::To) {
4329 self.interner.intern("To")
4330 } else {
4331 continue;
4332 };
4333
4334 let pp_obj_term = if self.check(&TokenType::Reflexive) {
4335 self.advance();
4336 Term::Constant(subject_symbol)
4337 } else if self.check_pronoun() {
4338 let token = self.advance().clone();
4339 let (gender, number) = match &token.kind {
4340 TokenType::Pronoun { gender, number, .. } => (*gender, *number),
4341 TokenType::Ambiguous { primary, alternatives } => {
4342 if let TokenType::Pronoun { gender, number, .. } = **primary {
4343 (gender, number)
4344 } else {
4345 alternatives.iter().find_map(|t| {
4346 if let TokenType::Pronoun { gender, number, .. } = t {
4347 Some((*gender, *number))
4348 } else {
4349 None
4350 }
4351 }).unwrap_or((Gender::Unknown, Number::Singular))
4352 }
4353 }
4354 _ => (Gender::Unknown, Number::Singular),
4355 };
4356 let resolved = self.resolve_pronoun(gender, number)?;
4357 match resolved {
4358 super::ResolvedPronoun::Variable(s) => Term::Variable(s),
4359 super::ResolvedPronoun::Constant(s) => Term::Constant(s),
4360 }
4361 } else if self.check_content_word() || self.check_article() {
4362 let prep_obj = self.parse_noun_phrase(false)?;
4363 Term::Constant(prep_obj.noun)
4364 } else if self.check_number() {
4365 let premodified = matches!(
4370 self.tokens.get(self.current + 2).map(|t| &t.kind),
4371 Some(TokenType::Noun(_)) | Some(TokenType::Ambiguous { .. })
4372 );
4373 if premodified {
4374 let saved_ctx = self.nominal_np_context;
4375 self.nominal_np_context = true;
4376 let r = self.parse_noun_phrase(false);
4377 self.nominal_np_context = saved_ctx;
4378 Term::Constant(r?.noun)
4379 } else {
4380 *self.parse_measure_phrase()?
4381 }
4382 } else if gap_object {
4383 continue;
4386 } else if self.at_clause_boundary()
4387 && crate::lexicon::is_particle(
4388 &self.interner.resolve(prep_name).to_lowercase(),
4389 )
4390 {
4391 let event_sym = self.get_event_var();
4395 pp_predicates.push(self.ctx.exprs.alloc(LogicExpr::Predicate {
4396 name: prep_name,
4397 args: self.ctx.terms.alloc_slice([Term::Variable(event_sym)]),
4398 world: None,
4399 }));
4400 continue;
4401 } else {
4402 self.current -= 1;
4406 break;
4407 };
4408
4409 if self.pp_attach_to_noun {
4410 if let Some(obj) = object_term {
4411 let pp_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
4412 name: prep_name,
4413 args: self.ctx.terms.alloc_slice([obj, pp_obj_term]),
4414 world: None,
4415 });
4416 pp_predicates.push(pp_pred);
4417 } else {
4418 args.push(pp_obj_term);
4419 }
4420 } else {
4421 let event_sym = self.get_event_var();
4422 let pp_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
4423 name: prep_name,
4424 args: self
4425 .ctx
4426 .terms
4427 .alloc_slice([Term::Variable(event_sym), pp_obj_term]),
4428 world: None,
4429 });
4430 pp_predicates.push(pp_pred);
4431 }
4432 }
4433
4434 if self.check(&TokenType::That) || self.check(&TokenType::Who) {
4435 self.advance();
4436 let rel_var = self.next_var_name();
4437 let rel_pred = self.parse_relative_clause(rel_var)?;
4438 pp_predicates.push(rel_pred);
4439 }
4440
4441 if object_term.is_some()
4448 && matches!(self.peek().kind, TokenType::Noun(_))
4449 && self.interner.resolve(self.peek().lexeme).eq_ignore_ascii_case("as")
4450 {
4451 self.advance(); if self.check_possessive_pronoun() {
4453 self.advance(); }
4455 if self.check_content_word() {
4456 as_role = Some(self.consume_content_word()?);
4457 }
4458 }
4459
4460 let mut modifiers = self.collect_adverbs();
4461
4462 let effective_time = self.pending_time.take().unwrap_or(verb_time);
4463 match effective_time {
4464 Time::Past => modifiers.push(self.interner.intern("Past")),
4465 Time::Future => modifiers.push(self.interner.intern("Future")),
4466 _ => {}
4467 }
4468
4469 if verb_aspect == Aspect::Progressive {
4470 modifiers.push(self.interner.intern("Progressive"));
4471 } else if verb_aspect == Aspect::Perfect {
4472 modifiers.push(self.interner.intern("Perfect"));
4473 }
4474
4475 let mut roles: Vec<(ThematicRole, Term<'a>)> = Vec::new();
4476
4477 let verb_str = self.interner.resolve(verb).to_lowercase();
4479 let is_unaccusative = crate::lexicon::lookup_verb_db(&verb_str)
4480 .map(|meta| meta.features.contains(&crate::lexicon::Feature::Unaccusative))
4481 .unwrap_or(false);
4482
4483 let has_object = object_term.is_some() || second_object_term.is_some();
4486 let subject_role = if is_unaccusative && !has_object {
4487 ThematicRole::Theme
4488 } else {
4489 ThematicRole::Agent
4490 };
4491
4492 roles.push((subject_role, subject_term));
4493 if let Some(second_obj) = second_object_term {
4494 if let Some(first_obj) = object_term {
4495 roles.push((ThematicRole::Recipient, first_obj));
4496 }
4497 roles.push((ThematicRole::Theme, second_obj));
4498 } else if let Some(obj) = object_term {
4499 roles.push((ThematicRole::Theme, obj));
4500 }
4501
4502 let event_var = self.get_event_var();
4503 let suppress_existential = self.drs.in_conditional_antecedent();
4504 if suppress_existential {
4505 let event_class = self.interner.intern("Event");
4506 self.drs.introduce_referent(event_var, event_class, Gender::Neuter, Number::Singular);
4507 }
4508 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
4509 event_var,
4510 verb,
4511 roles: self.ctx.roles.alloc_slice(roles.clone()),
4512 modifiers: self.ctx.syms.alloc_slice(modifiers.clone()),
4513 suppress_existential,
4514 world: None,
4515 })));
4516
4517 self.capture_event_template(verb, &roles, &modifiers);
4519
4520 let with_pps = if pp_predicates.is_empty() {
4521 neo_event
4522 } else {
4523 let mut combined = neo_event;
4524 for pp in pp_predicates {
4525 combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4526 left: combined,
4527 op: TokenType::And,
4528 right: pp,
4529 });
4530 }
4531 combined
4532 };
4533
4534 let with_object_pps = if object_pps.is_empty() {
4537 with_pps
4538 } else if let Some(obj_term) = object_term {
4539 let mut combined = with_pps;
4540 for pp in object_pps {
4541 let substituted = self.substitute_pp_self_term(pp, obj_term);
4547 combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4548 left: combined,
4549 op: TokenType::And,
4550 right: substituted,
4551 });
4552 }
4553 combined
4554 } else {
4555 with_pps
4556 };
4557
4558 let with_object_pps = if object_adjectives.is_empty() {
4562 with_object_pps
4563 } else if let Some(obj_term) = object_term {
4564 let mut combined = with_object_pps;
4565 for &adj in object_adjectives {
4566 let adj_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
4567 name: adj,
4568 args: self.ctx.terms.alloc_slice([obj_term]),
4569 world: None,
4570 });
4571 combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4572 left: combined,
4573 op: TokenType::And,
4574 right: adj_pred,
4575 });
4576 }
4577 combined
4578 } else {
4579 with_object_pps
4580 };
4581
4582 let with_aspect = if verb_aspect == Aspect::Simple && effective_time == Time::Present {
4584 if !verb_class.is_stative() {
4586 self.ctx.exprs.alloc(LogicExpr::Aspectual {
4587 operator: AspectOperator::Habitual,
4588 body: with_object_pps,
4589 })
4590 } else {
4591 with_object_pps
4592 }
4593 } else if verb_aspect == Aspect::Progressive {
4594 if verb_class == crate::lexicon::VerbClass::Semelfactive {
4596 self.ctx.exprs.alloc(LogicExpr::Aspectual {
4597 operator: AspectOperator::Iterative,
4598 body: with_object_pps,
4599 })
4600 } else {
4601 with_object_pps
4602 }
4603 } else {
4604 with_object_pps
4605 };
4606
4607 let with_aspect = if let (Some(role), Some(obj)) = (as_role, object_term) {
4609 let role_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
4610 name: role,
4611 args: self.ctx.terms.alloc_slice([obj]),
4612 world: None,
4613 });
4614 self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4615 left: with_aspect,
4616 op: TokenType::And,
4617 right: role_pred,
4618 })
4619 } else {
4620 with_aspect
4621 };
4622
4623 Ok(with_aspect)
4624 }
4625}
4626
4627impl<'a, 'ctx, 'int> LogicVerbParsing<'a, 'ctx, 'int> for Parser<'a, 'ctx, 'int> {
4628 fn parse_predicate_with_subject(&mut self, subject_symbol: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
4629 let result = self.parse_predicate_impl(subject_symbol, false)?;
4630 Ok(self.try_wrap_bounded_delay(result))
4631 }
4632
4633 fn parse_predicate_with_subject_as_var(&mut self, subject_symbol: Symbol) -> ParseResult<&'a LogicExpr<'a>> {
4634 let result = self.parse_predicate_impl(subject_symbol, true)?;
4635 Ok(self.try_wrap_bounded_delay(result))
4636 }
4637
4638 fn try_parse_plural_subject(
4639 &mut self,
4640 first_subject: &NounPhrase<'a>,
4641 ) -> Result<Option<&'a LogicExpr<'a>>, ParseError> {
4642 let saved_pos = self.current;
4643
4644 self.advance();
4646
4647 if !self.check_content_word() {
4648 self.current = saved_pos;
4649 return Ok(None);
4650 }
4651
4652 let mut subjects: Vec<Symbol> = vec![first_subject.noun];
4654
4655 loop {
4656 if !self.check_content_word() {
4657 break;
4658 }
4659 let next_subject = match self.parse_noun_phrase(true) {
4660 Ok(np) => np,
4661 Err(_) => {
4662 self.current = saved_pos;
4663 return Ok(None);
4664 }
4665 };
4666 subjects.push(next_subject.noun);
4667
4668 if self.check(&TokenType::And) {
4669 self.advance();
4670 } else {
4671 break;
4672 }
4673 }
4674
4675 if self.check(&TokenType::Is) || self.check(&TokenType::Are)
4678 || self.check(&TokenType::Was) || self.check(&TokenType::Were)
4679 {
4680 let copula_time = if self.check(&TokenType::Was) || self.check(&TokenType::Were) {
4681 Time::Past
4682 } else {
4683 Time::Present
4684 };
4685 self.advance(); let is_negated = self.check(&TokenType::Not);
4689 if is_negated {
4690 self.advance(); }
4692
4693 let has_both = self.check(&TokenType::Both);
4697 if has_both {
4698 self.advance(); }
4700
4701 if !self.check_content_word() && !self.check_article() {
4703 self.current = saved_pos;
4704 return Ok(None);
4705 }
4706
4707 let predicate_np = match self.parse_noun_phrase(false) {
4708 Ok(np) => np,
4709 Err(_) => {
4710 self.current = saved_pos;
4711 return Ok(None);
4712 }
4713 };
4714 let predicate = predicate_np.noun;
4715
4716 let is_different = predicate_np.adjectives.iter().any(|a| {
4721 self.interner.resolve(*a).eq_ignore_ascii_case("different")
4722 });
4723
4724 for subj in &subjects {
4732 self.drs.register_item_category(*subj, predicate);
4733 }
4734
4735 let mut conjuncts: Vec<&'a LogicExpr<'a>> = Vec::new();
4737 for subj in &subjects {
4738 let pred_expr = self.ctx.exprs.alloc(LogicExpr::Predicate {
4739 name: predicate,
4740 args: self.ctx.terms.alloc_slice([Term::Constant(*subj)]),
4741 world: None,
4742 });
4743 conjuncts.push(pred_expr);
4744 }
4745 if is_different {
4746 for i in 0..subjects.len() {
4747 for j in (i + 1)..subjects.len() {
4748 let eq = self.ctx.exprs.alloc(LogicExpr::Identity {
4749 left: self.ctx.terms.alloc(Term::Constant(subjects[i])),
4750 right: self.ctx.terms.alloc(Term::Constant(subjects[j])),
4751 });
4752 conjuncts.push(self.ctx.exprs.alloc(LogicExpr::UnaryOp {
4753 op: TokenType::Not,
4754 operand: eq,
4755 }));
4756 }
4757 }
4758 }
4759
4760 if is_negated && !has_both {
4761 for conjunct in &mut conjuncts {
4763 *conjunct = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
4764 op: TokenType::Not,
4765 operand: *conjunct,
4766 });
4767 }
4768 }
4769
4770 let mut result = conjuncts[0];
4772 for conjunct in &conjuncts[1..] {
4773 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4774 left: result,
4775 op: TokenType::And,
4776 right: *conjunct,
4777 });
4778 }
4779
4780 if is_negated && has_both {
4782 result = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
4783 op: TokenType::Not,
4784 operand: result,
4785 });
4786 }
4787
4788 let with_time = match copula_time {
4790 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
4791 operator: TemporalOperator::Past,
4792 body: result,
4793 }),
4794 _ => result,
4795 };
4796
4797 return Ok(Some(with_time));
4798 }
4799
4800 if !self.check_verb() {
4801 self.current = saved_pos;
4802 return Ok(None);
4803 }
4804
4805 let (verb, verb_time, _verb_aspect, _) = self.consume_verb_with_metadata();
4808
4809 if self.check(&TokenType::Reciprocal) {
4811 self.advance();
4812 if subjects.len() != 2 {
4813 self.current = saved_pos;
4814 return Ok(None);
4815 }
4816 let pred1 = self.ctx.exprs.alloc(LogicExpr::Predicate {
4817 name: verb,
4818 args: self.ctx.terms.alloc_slice([
4819 Term::Constant(subjects[0]),
4820 Term::Constant(subjects[1]),
4821 ]),
4822 world: None,
4823 });
4824 let pred2 = self.ctx.exprs.alloc(LogicExpr::Predicate {
4825 name: verb,
4826 args: self.ctx.terms.alloc_slice([
4827 Term::Constant(subjects[1]),
4828 Term::Constant(subjects[0]),
4829 ]),
4830 world: None,
4831 });
4832 let expr = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4833 left: pred1,
4834 op: TokenType::And,
4835 right: pred2,
4836 });
4837
4838 let with_time = match verb_time {
4839 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
4840 operator: TemporalOperator::Past,
4841 body: expr,
4842 }),
4843 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
4844 operator: TemporalOperator::Future,
4845 body: expr,
4846 }),
4847 _ => expr,
4848 };
4849 return Ok(Some(with_time));
4850 }
4851
4852 let mut objects: Vec<Symbol> = Vec::new();
4854 if self.check_content_word() || self.check_article() {
4855 let first_obj = match self.parse_noun_phrase(false) {
4857 Ok(np) => np,
4858 Err(_) => {
4859 return Ok(Some(self.build_group_predicate(&subjects, verb, verb_time)));
4861 }
4862 };
4863 objects.push(first_obj.noun);
4864
4865 while self.check(&TokenType::And) {
4867 self.advance();
4868 if self.check_content_word() || self.check_article() {
4869 let next_obj = match self.parse_noun_phrase(false) {
4870 Ok(np) => np,
4871 Err(_) => break,
4872 };
4873 objects.push(next_obj.noun);
4874 } else {
4875 break;
4876 }
4877 }
4878 }
4879
4880 let mut recipients: Vec<Symbol> = Vec::new();
4884 let respectively_ahead = {
4885 let mut i = self.current;
4886 let mut found = false;
4887 while i < self.tokens.len()
4888 && !matches!(self.tokens[i].kind, TokenType::Period | TokenType::EOF)
4889 {
4890 if matches!(self.tokens[i].kind, TokenType::Respectively) {
4891 found = true;
4892 break;
4893 }
4894 i += 1;
4895 }
4896 found
4897 };
4898 if respectively_ahead && self.check_to_marker() {
4899 self.advance(); loop {
4901 let r_np = self.parse_noun_phrase(false)?;
4902 recipients.push(r_np.noun);
4903 if self.check(&TokenType::And) {
4904 self.advance();
4905 } else {
4906 break;
4907 }
4908 }
4909 }
4910
4911 if self.check(&TokenType::Respectively) {
4912 let respectively_span = self.peek().span;
4913 self.advance(); let pair_targets: &[Symbol] = if recipients.is_empty() {
4916 &objects
4917 } else {
4918 &recipients
4919 };
4920 if subjects.len() != pair_targets.len() {
4921 return Err(ParseError {
4922 kind: ParseErrorKind::RespectivelyLengthMismatch {
4923 subject_count: subjects.len(),
4924 object_count: pair_targets.len(),
4925 },
4926 span: respectively_span,
4927 });
4928 }
4929
4930 let mut conjuncts: Vec<&'a LogicExpr<'a>> = Vec::new();
4933 let suppress_existential = self.drs.in_conditional_antecedent();
4934 for (subj, target) in subjects.iter().zip(pair_targets.iter()) {
4935 let event_var = self.get_event_var();
4936 let roles = if recipients.is_empty() {
4937 vec![
4938 (ThematicRole::Agent, Term::Constant(*subj)),
4939 (ThematicRole::Theme, Term::Constant(*target)),
4940 ]
4941 } else {
4942 let mut r = vec![(ThematicRole::Agent, Term::Constant(*subj))];
4943 if let Some(theme) = objects.first() {
4944 r.push((ThematicRole::Theme, Term::Constant(*theme)));
4945 }
4946 r.push((ThematicRole::Recipient, Term::Constant(*target)));
4947 r
4948 };
4949 let neo_event = self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
4950 event_var,
4951 verb,
4952 roles: self.ctx.roles.alloc_slice(roles),
4953 modifiers: self.ctx.syms.alloc_slice(vec![]),
4954 suppress_existential,
4955 world: None,
4956 })));
4957 conjuncts.push(neo_event);
4958 }
4959
4960 let mut result = conjuncts[0];
4962 for conjunct in &conjuncts[1..] {
4963 result = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
4964 left: result,
4965 op: TokenType::And,
4966 right: *conjunct,
4967 });
4968 }
4969
4970 let with_time = match verb_time {
4972 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
4973 operator: TemporalOperator::Past,
4974 body: result,
4975 }),
4976 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
4977 operator: TemporalOperator::Future,
4978 body: result,
4979 }),
4980 _ => result,
4981 };
4982
4983 return Ok(Some(with_time));
4984 }
4985
4986 if objects.is_empty() {
4988 Ok(Some(self.build_group_predicate(&subjects, verb, verb_time)))
4990 } else {
4991 Ok(Some(self.build_group_transitive(&subjects, &objects, verb, verb_time)))
4993 }
4994 }
4995
4996 fn build_group_predicate(
4998 &mut self,
4999 subjects: &[Symbol],
5000 verb: Symbol,
5001 verb_time: Time,
5002 ) -> &'a LogicExpr<'a> {
5003 let group_members: Vec<Term<'a>> = subjects.iter()
5004 .map(|s| Term::Constant(*s))
5005 .collect();
5006 let group_members_slice = self.ctx.terms.alloc_slice(group_members);
5007
5008 let expr = self.ctx.exprs.alloc(LogicExpr::Predicate {
5009 name: verb,
5010 args: self.ctx.terms.alloc_slice([Term::Group(group_members_slice)]),
5011 world: None,
5012 });
5013
5014 match verb_time {
5015 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
5016 operator: TemporalOperator::Past,
5017 body: expr,
5018 }),
5019 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
5020 operator: TemporalOperator::Future,
5021 body: expr,
5022 }),
5023 _ => expr,
5024 }
5025 }
5026
5027 fn build_group_transitive(
5029 &mut self,
5030 subjects: &[Symbol],
5031 objects: &[Symbol],
5032 verb: Symbol,
5033 verb_time: Time,
5034 ) -> &'a LogicExpr<'a> {
5035 let subj_members: Vec<Term<'a>> = subjects.iter()
5036 .map(|s| Term::Constant(*s))
5037 .collect();
5038 let obj_members: Vec<Term<'a>> = objects.iter()
5039 .map(|o| Term::Constant(*o))
5040 .collect();
5041
5042 let subj_group = Term::Group(self.ctx.terms.alloc_slice(subj_members));
5043 let obj_group = Term::Group(self.ctx.terms.alloc_slice(obj_members));
5044
5045 let expr = self.ctx.exprs.alloc(LogicExpr::Predicate {
5046 name: verb,
5047 args: self.ctx.terms.alloc_slice([subj_group, obj_group]),
5048 world: None,
5049 });
5050
5051 match verb_time {
5052 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
5053 operator: TemporalOperator::Past,
5054 body: expr,
5055 }),
5056 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
5057 operator: TemporalOperator::Future,
5058 body: expr,
5059 }),
5060 _ => expr,
5061 }
5062 }
5063
5064 fn parse_control_structure(
5065 &mut self,
5066 subject: &NounPhrase<'a>,
5067 verb: Symbol,
5068 verb_time: Time,
5069 ) -> ParseResult<&'a LogicExpr<'a>> {
5070 let subject_sym = subject.noun;
5071 let verb_str = self.interner.resolve(verb);
5072
5073 if Lexer::is_raising_verb(verb_str) {
5074 if !self.check_to() {
5075 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
5076 name: verb,
5077 args: self.ctx.terms.alloc_slice([Term::Constant(subject_sym)]),
5078 world: None,
5079 }));
5080 }
5081 self.advance();
5082
5083 if !self.check_verb() {
5084 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
5085 name: verb,
5086 args: self.ctx.terms.alloc_slice([Term::Constant(subject_sym)]),
5087 world: None,
5088 }));
5089 }
5090
5091 let inf_verb = self.consume_verb();
5092
5093 let embedded = if self.is_control_verb(inf_verb) {
5094 let raised_np = NounPhrase {
5095 noun: subject_sym,
5096 definiteness: None,
5097 adjectives: &[],
5098 possessor: None,
5099 pps: &[],
5100 superlative: None,
5101 };
5102 self.parse_control_structure(&raised_np, inf_verb, Time::None)?
5103 } else {
5104 self.ctx.exprs.alloc(LogicExpr::Predicate {
5105 name: inf_verb,
5106 args: self.ctx.terms.alloc_slice([Term::Constant(subject_sym)]),
5107 world: None,
5108 })
5109 };
5110
5111 let result = self.ctx.exprs.alloc(LogicExpr::Scopal {
5112 operator: verb,
5113 body: embedded,
5114 });
5115
5116 return Ok(match verb_time {
5117 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
5118 operator: TemporalOperator::Past,
5119 body: result,
5120 }),
5121 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
5122 operator: TemporalOperator::Future,
5123 body: result,
5124 }),
5125 _ => result,
5126 });
5127 }
5128
5129 let is_object_control = Lexer::is_object_control_verb(self.interner.resolve(verb));
5130 let (object_term, pro_controller_sym) = if self.check_to() {
5131 (None, subject_sym)
5132 } else if self.check_content_word() {
5133 let object_np = self.parse_noun_phrase(false)?;
5134 let obj_sym = object_np.noun;
5135
5136 let controller = if is_object_control {
5137 obj_sym
5138 } else {
5139 subject_sym
5140 };
5141 (
5142 Some(self.ctx.terms.alloc(Term::Constant(obj_sym))),
5143 controller,
5144 )
5145 } else {
5146 (None, subject_sym)
5147 };
5148
5149 if !self.check_to() {
5150 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
5151 name: verb,
5152 args: match object_term {
5153 Some(obj) => self.ctx.terms.alloc_slice([
5154 Term::Constant(subject_sym),
5155 Term::Constant(match obj {
5156 Term::Constant(s) => *s,
5157 _ => subject_sym,
5158 }),
5159 ]),
5160 None => self.ctx.terms.alloc_slice([Term::Constant(subject_sym)]),
5161 },
5162 world: None,
5163 }));
5164 }
5165 self.advance();
5166
5167 if !self.check_verb() {
5168 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
5169 name: verb,
5170 args: self.ctx.terms.alloc_slice([Term::Constant(subject_sym)]),
5171 world: None,
5172 }));
5173 }
5174
5175 let inf_verb = self.consume_verb();
5176 let inf_verb_str = self.interner.resolve(inf_verb).to_lowercase();
5177
5178 let infinitive = if inf_verb_str == "be" && self.check_verb() {
5179 let passive_verb = self.consume_verb();
5180 let mut passive_args = vec![Term::Constant(pro_controller_sym)];
5183 let mut agent_restr: Option<(Symbol, &'a LogicExpr<'a>)> = None;
5187 if self.check_preposition_is("by")
5188 && self
5189 .tokens
5190 .get(self.current + 1)
5191 .map_or(false, |t| matches!(
5192 t.kind,
5193 TokenType::ProperName(_) | TokenType::Noun(_) | TokenType::Article(_)
5194 ))
5195 {
5196 self.advance(); let agent_np = self.parse_noun_phrase(false)?;
5198 let (agent_term, restr) = self.possessor_entity(&agent_np);
5199 agent_restr = restr;
5200 passive_args.insert(0, agent_term);
5201 }
5202 let passive_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
5203 name: passive_verb,
5204 args: self.ctx.terms.alloc_slice(passive_args),
5205 world: None,
5206 });
5207 let passive_pred = self.wrap_in_possessor_entity(agent_restr, passive_pred);
5208 self.ctx.voice(crate::ast::VoiceOperator::Passive, passive_pred)
5209 } else if self.is_control_verb(inf_verb) {
5210 let controller_np = NounPhrase {
5211 noun: pro_controller_sym,
5212 definiteness: None,
5213 adjectives: &[],
5214 possessor: None,
5215 pps: &[],
5216 superlative: None,
5217 };
5218 self.parse_control_structure(&controller_np, inf_verb, Time::None)?
5219 } else {
5220 self.ctx.exprs.alloc(LogicExpr::Predicate {
5221 name: inf_verb,
5222 args: self
5223 .ctx
5224 .terms
5225 .alloc_slice([Term::Constant(pro_controller_sym)]),
5226 world: None,
5227 })
5228 };
5229
5230 let control = self.ctx.exprs.alloc(LogicExpr::Control {
5231 verb,
5232 subject: self.ctx.terms.alloc(Term::Constant(subject_sym)),
5233 object: object_term,
5234 infinitive,
5235 });
5236
5237 Ok(match verb_time {
5238 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
5239 operator: TemporalOperator::Past,
5240 body: control,
5241 }),
5242 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
5243 operator: TemporalOperator::Future,
5244 body: control,
5245 }),
5246 _ => control,
5247 })
5248 }
5249
5250 fn is_control_verb(&self, verb: Symbol) -> bool {
5251 let lemma = self.interner.resolve(verb);
5252 Lexer::is_subject_control_verb(lemma)
5253 || Lexer::is_object_control_verb(lemma)
5254 || Lexer::is_raising_verb(lemma)
5255 }
5256}