1use super::clause::ClauseParsing;
16use super::noun::NounParsing;
17use super::quantifier::QuantifierParsing;
18use super::{ParseResult, Parser};
19use crate::ast::{LogicExpr, NounPhrase, NumberKind, QuantifierKind, TemporalOperator, Term};
20use crate::error::{ParseError, ParseErrorKind};
21use crate::lexicon::{self, Time};
22use crate::token::{MeasureKind, PresupKind, TokenType};
23
24pub trait PragmaticsParsing<'a, 'ctx, 'int> {
35 fn parse_focus(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
44
45 fn parse_measure(&mut self) -> ParseResult<&'a LogicExpr<'a>>;
51
52 fn parse_presupposition(
64 &mut self,
65 subject: &NounPhrase<'a>,
66 presup_kind: PresupKind,
67 negated: bool,
68 ) -> ParseResult<&'a LogicExpr<'a>>;
69
70 fn parse_presupposition_for_term(
75 &mut self,
76 subject_term: Term<'a>,
77 presup_kind: PresupKind,
78 negated: bool,
79 ) -> ParseResult<&'a LogicExpr<'a>>;
80
81 fn parse_predicate_for_subject(&mut self, subject: &NounPhrase<'a>)
87 -> ParseResult<&'a LogicExpr<'a>>;
88
89 fn parse_scopal_adverb(&mut self, subject: &NounPhrase<'a>) -> ParseResult<&'a LogicExpr<'a>>;
95
96 fn parse_superlative(&mut self, subject: &NounPhrase<'a>) -> ParseResult<&'a LogicExpr<'a>>;
102
103 fn parse_comparative(
112 &mut self,
113 subject: &NounPhrase<'a>,
114 copula_time: Time,
115 difference: Option<&'a Term<'a>>,
116 ) -> ParseResult<&'a LogicExpr<'a>>;
117
118 fn parse_equative(&mut self, subject: &NounPhrase<'a>) -> ParseResult<&'a LogicExpr<'a>>;
120
121 fn check_number(&self) -> bool;
126
127 fn parse_measure_phrase(&mut self) -> ParseResult<&'a Term<'a>>;
135
136 fn counting_np_lookahead(&self) -> Option<u32>;
149}
150
151impl<'a, 'ctx, 'int> PragmaticsParsing<'a, 'ctx, 'int> for Parser<'a, 'ctx, 'int> {
152 fn parse_focus(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
153 let kind = if let TokenType::Focus(k) = self.advance().kind {
154 k
155 } else {
156 return Err(ParseError {
157 kind: ParseErrorKind::ExpectedFocusParticle,
158 span: self.current_span(),
159 });
160 };
161
162 if self.check_quantifier() {
163 self.advance();
164 let quantified = self.parse_quantified()?;
165 let focus_var = self.interner.intern("focus");
166 let focused = self.ctx.terms.alloc(Term::Variable(focus_var));
167 return Ok(self.ctx.exprs.alloc(LogicExpr::Focus {
168 kind,
169 focused,
170 scope: quantified,
171 }));
172 }
173
174 let focused_np = self.parse_noun_phrase(true)?;
175 let focused = self.ctx.terms.alloc(Term::Constant(focused_np.noun));
176
177 let scope = self.parse_predicate_for_subject(&focused_np)?;
178
179 Ok(self.ctx.exprs.alloc(LogicExpr::Focus {
180 kind,
181 focused,
182 scope,
183 }))
184 }
185
186 fn parse_measure(&mut self) -> ParseResult<&'a LogicExpr<'a>> {
187 let kind = if let TokenType::Measure(k) = self.advance().kind {
188 k
189 } else {
190 return Err(ParseError {
191 kind: ParseErrorKind::UnexpectedToken {
192 expected: TokenType::Measure(MeasureKind::Much),
193 found: self.peek().kind.clone(),
194 },
195 span: self.current_span(),
196 });
197 };
198
199 let np = self.parse_noun_phrase(true)?;
200 let var = self.next_var_name();
201
202 let noun_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
203 name: np.noun,
204 args: self.ctx.terms.alloc_slice([Term::Variable(var)]),
205 world: None,
206 });
207
208 let measure_sym = self.interner.intern("Measure");
209 let kind_sym = self.interner.intern(match kind {
210 MeasureKind::Much => "Much",
211 MeasureKind::Little => "Little",
212 });
213 let measure_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
214 name: measure_sym,
215 args: self
216 .ctx
217 .terms
218 .alloc_slice([Term::Variable(var), Term::Constant(kind_sym)]),
219 world: None,
220 });
221
222 let (pred_expr, verb_time) = if self.check(&TokenType::Is) {
223 let copula_time = if let TokenType::Is = self.advance().kind {
224 Time::Present
225 } else {
226 Time::Present
227 };
228
229 if self.check_comparative() {
231 let subj_np = NounPhrase {
232 noun: np.noun,
233 definiteness: None,
234 adjectives: &[],
235 possessor: None,
236 pps: &[],
237 superlative: None,
238 };
239 let comp_expr = self.parse_comparative(&subj_np, copula_time, None)?;
240
241 let combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
242 left: noun_pred,
243 op: TokenType::And,
244 right: self.ctx.exprs.alloc(LogicExpr::BinaryOp {
245 left: measure_pred,
246 op: TokenType::And,
247 right: comp_expr,
248 }),
249 });
250
251 return Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
252 kind: QuantifierKind::Existential,
253 variable: var,
254 body: combined,
255 island_id: self.current_island,
256 }));
257 }
258
259 let adj = self.consume_content_word()?;
260 let adj_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
261 name: adj,
262 args: self.ctx.terms.alloc_slice([Term::Variable(var)]),
263 world: None,
264 });
265 (adj_pred, copula_time)
266 } else {
267 let (verb, verb_time, _, _) = self.consume_verb_with_metadata();
268 let verb_pred = self.ctx.exprs.alloc(LogicExpr::Predicate {
269 name: verb,
270 args: self.ctx.terms.alloc_slice([Term::Variable(var)]),
271 world: None,
272 });
273 (verb_pred, verb_time)
274 };
275
276 let combined = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
277 left: noun_pred,
278 op: TokenType::And,
279 right: self.ctx.exprs.alloc(LogicExpr::BinaryOp {
280 left: measure_pred,
281 op: TokenType::And,
282 right: pred_expr,
283 }),
284 });
285
286 let with_time = match verb_time {
287 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
288 operator: TemporalOperator::Past,
289 body: combined,
290 }),
291 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
292 operator: TemporalOperator::Future,
293 body: combined,
294 }),
295 _ => combined,
296 };
297
298 Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
299 kind: QuantifierKind::Existential,
300 variable: var,
301 body: with_time,
302 island_id: self.current_island,
303 }))
304 }
305
306 fn parse_presupposition(
307 &mut self,
308 subject: &NounPhrase<'a>,
309 presup_kind: PresupKind,
310 negated: bool,
311 ) -> ParseResult<&'a LogicExpr<'a>> {
312 self.parse_presupposition_for_term(Term::Constant(subject.noun), presup_kind, negated)
317 }
318
319 fn parse_presupposition_for_term(
320 &mut self,
321 subject_term: Term<'a>,
322 presup_kind: PresupKind,
323 negated: bool,
324 ) -> ParseResult<&'a LogicExpr<'a>> {
325
326 let unknown = self.interner.intern("?");
327 let complement_verb = if self.check_verb() {
328 Some(self.consume_verb())
329 } else {
330 None
331 };
332 let complement = match complement_verb {
333 Some(verb) => self.ctx.exprs.alloc(LogicExpr::Predicate {
334 name: verb,
335 args: self.ctx.terms.alloc_slice([subject_term]),
336 world: None,
337 }),
338 None => self.ctx.exprs.alloc(LogicExpr::Atom(unknown)),
339 };
340 let past_event = match complement_verb {
345 Some(verb) => {
346 use crate::ast::logic::NeoEventData;
347 use crate::ast::ThematicRole;
348 self.ctx.exprs.alloc(LogicExpr::NeoEvent(Box::new(NeoEventData {
349 event_var: self.interner.intern("e"),
350 verb,
351 roles: self
352 .ctx
353 .roles
354 .alloc_slice(vec![(ThematicRole::Agent, subject_term)]),
355 modifiers: self.ctx.syms.alloc_slice(vec![self.interner.intern("Past")]),
356 suppress_existential: false,
357 world: None,
358 })))
359 }
360 None => self.ctx.exprs.alloc(LogicExpr::Temporal {
361 operator: TemporalOperator::Past,
362 body: complement,
363 }),
364 };
365
366 let (mut assertion, presupposition) = match presup_kind {
367 PresupKind::Stop => {
368 let neg = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
369 op: TokenType::Not,
370 operand: complement,
371 });
372 (neg, past_event)
373 }
374 PresupKind::Start => {
375 let neg_past = self.ctx.exprs.alloc(LogicExpr::UnaryOp {
376 op: TokenType::Not,
377 operand: past_event,
378 });
379 (complement, neg_past)
380 }
381 PresupKind::Regret => {
382 let regret_sym = self.interner.intern("Regret");
383 let regret = self.ctx.exprs.alloc(LogicExpr::Predicate {
384 name: regret_sym,
385 args: self.ctx.terms.alloc_slice([subject_term]),
386 world: None,
387 });
388 (regret, past_event)
389 }
390 PresupKind::Continue | PresupKind::Realize | PresupKind::Know => {
391 let verb_name = match presup_kind {
392 PresupKind::Continue => self.interner.intern("Continue"),
393 PresupKind::Realize => self.interner.intern("Realize"),
394 PresupKind::Know => self.interner.intern("Know"),
395 _ => unknown,
396 };
397 let main = self.ctx.exprs.alloc(LogicExpr::Predicate {
398 name: verb_name,
399 args: self.ctx.terms.alloc_slice([subject_term]),
400 world: None,
401 });
402 (main, complement)
403 }
404 };
405
406 let subj_term = subject_term;
410 if let Some(off) = self.parse_temporal_offset_constraint(subj_term)? {
411 assertion = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
412 left: assertion,
413 op: TokenType::And,
414 right: off,
415 });
416 } else if let Some(off) = self.parse_bare_temporal_constraint(subj_term)? {
417 assertion = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
418 left: assertion,
419 op: TokenType::And,
420 right: off,
421 });
422 }
423
424 let assertion = if negated {
428 self.ctx.exprs.alloc(LogicExpr::UnaryOp {
429 op: TokenType::Not,
430 operand: assertion,
431 })
432 } else {
433 assertion
434 };
435
436 Ok(self.ctx.exprs.alloc(LogicExpr::Presupposition {
437 assertion,
438 presupposition,
439 }))
440 }
441
442 fn parse_predicate_for_subject(
443 &mut self,
444 subject: &NounPhrase<'a>,
445 ) -> ParseResult<&'a LogicExpr<'a>> {
446 if self.check_verb() {
447 let verb = self.consume_verb();
448
449 if self.check_focus() {
451 let focus_kind = if let TokenType::Focus(k) = self.advance().kind {
452 k
453 } else {
454 crate::token::FocusKind::Only
455 };
456
457 let object_np = self.parse_noun_phrase(false)?;
458 let object_term = Term::Constant(object_np.noun);
459
460 let predicate = self.ctx.exprs.alloc(LogicExpr::Predicate {
461 name: verb,
462 args: self.ctx.terms.alloc_slice([
463 Term::Constant(subject.noun),
464 object_term.clone(),
465 ]),
466 world: None,
467 });
468
469 return Ok(self.ctx.exprs.alloc(LogicExpr::Focus {
470 kind: focus_kind,
471 focused: self.ctx.terms.alloc(object_term),
472 scope: predicate,
473 }));
474 }
475
476 let mut args = vec![Term::Constant(subject.noun)];
477
478 if self.check_content_word() || self.check_article() {
479 let object = self.parse_noun_phrase(false)?;
480 args.push(Term::Constant(object.noun));
481 }
482
483 Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
484 name: verb,
485 args: self.ctx.terms.alloc_slice(args),
486 world: None,
487 }))
488 } else if matches!(self.peek().kind, TokenType::Is | TokenType::Are) {
489 self.advance();
492 if self.check_article() {
493 self.advance();
494 }
495 let predicate = match self.advance().kind.clone() {
496 TokenType::Adjective(sym)
497 | TokenType::Noun(sym)
498 | TokenType::ProperName(sym) => sym,
499 TokenType::Ambiguous { primary, alternatives } => {
500 let as_predicate = |t: &TokenType| match t {
501 TokenType::Adjective(sym)
502 | TokenType::Noun(sym)
503 | TokenType::ProperName(sym) => Some(*sym),
504 _ => None,
505 };
506 match as_predicate(&primary)
507 .or_else(|| alternatives.iter().find_map(as_predicate))
508 {
509 Some(sym) => sym,
510 None => {
511 return Err(ParseError {
512 kind: ParseErrorKind::ExpectedContentWord {
513 found: *primary,
514 },
515 span: self.current_span(),
516 });
517 }
518 }
519 }
520 found => {
521 return Err(ParseError {
522 kind: ParseErrorKind::ExpectedContentWord { found },
523 span: self.current_span(),
524 });
525 }
526 };
527 Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
528 name: predicate,
529 args: self.ctx.terms.alloc_slice([Term::Constant(subject.noun)]),
530 world: None,
531 }))
532 } else {
533 Ok(self.ctx.exprs.alloc(LogicExpr::Atom(subject.noun)))
534 }
535 }
536
537 fn parse_scopal_adverb(&mut self, subject: &NounPhrase<'a>) -> ParseResult<&'a LogicExpr<'a>> {
538 let operator = if let TokenType::ScopalAdverb(adv) = self.advance().kind.clone() {
539 adv
540 } else {
541 return Err(ParseError {
542 kind: ParseErrorKind::ExpectedScopalAdverb,
543 span: self.current_span(),
544 });
545 };
546
547 if !self.check_verb() {
548 return Err(ParseError {
549 kind: ParseErrorKind::ExpectedVerb {
550 found: self.peek().kind.clone(),
551 },
552 span: self.current_span(),
553 });
554 }
555
556 let clause_ends_after_verb = matches!(
559 self.tokens.get(self.current + 1).map(|t| t.kind.clone()),
560 Some(
561 TokenType::Period
562 | TokenType::Exclamation
563 | TokenType::EOF
564 | TokenType::Comma
565 | TokenType::And
566 ) | None
567 );
568 if !clause_ends_after_verb {
569 use super::verb::LogicVerbParsing;
570 let body = self.parse_predicate_with_subject(subject.noun)?;
571 return Ok(self.ctx.exprs.alloc(LogicExpr::Scopal { operator, body }));
572 }
573
574 let (verb, verb_time, _verb_aspect, _) = self.consume_verb_with_metadata();
575
576 let predicate = self.ctx.exprs.alloc(LogicExpr::Predicate {
577 name: verb,
578 args: self.ctx.terms.alloc_slice([Term::Constant(subject.noun)]),
579 world: None,
580 });
581
582 let with_time = match verb_time {
583 Time::Past => self.ctx.exprs.alloc(LogicExpr::Temporal {
584 operator: TemporalOperator::Past,
585 body: predicate,
586 }),
587 Time::Future => self.ctx.exprs.alloc(LogicExpr::Temporal {
588 operator: TemporalOperator::Future,
589 body: predicate,
590 }),
591 _ => predicate,
592 };
593
594 Ok(self.ctx.exprs.alloc(LogicExpr::Scopal {
595 operator,
596 body: with_time,
597 }))
598 }
599
600 fn parse_superlative(&mut self, subject: &NounPhrase<'a>) -> ParseResult<&'a LogicExpr<'a>> {
601 let adj = if let TokenType::Superlative(adj) = self.advance().kind.clone() {
602 adj
603 } else {
604 return Err(ParseError {
605 kind: ParseErrorKind::ExpectedSuperlativeAdjective,
606 span: self.current_span(),
607 });
608 };
609
610 let domain = self.consume_content_word()?;
611
612 Ok(self.ctx.exprs.alloc(LogicExpr::Superlative {
613 adjective: adj,
614 subject: self.ctx.terms.alloc(Term::Constant(subject.noun)),
615 domain,
616 }))
617 }
618
619 fn parse_comparative(
620 &mut self,
621 subject: &NounPhrase<'a>,
622 _copula_time: Time,
623 difference: Option<&'a Term<'a>>,
624 ) -> ParseResult<&'a LogicExpr<'a>> {
625 if crate::lexicon::is_degree_adverb(
631 &self.interner.resolve(self.peek().lexeme).to_lowercase(),
632 ) && matches!(
633 self.tokens.get(self.current + 1).map(|t| &t.kind),
634 Some(TokenType::Comparative(_))
635 ) {
636 self.advance(); }
638
639 let comp_tok = self.advance().clone();
640 let comp_surface = self.interner.resolve(comp_tok.lexeme).to_string();
641 let adj = if let TokenType::Comparative(adj) = comp_tok.kind {
642 adj
643 } else {
644 return Err(ParseError {
645 kind: ParseErrorKind::ExpectedComparativeAdjective,
646 span: self.current_span(),
647 });
648 };
649
650 if !self.check(&TokenType::Than) {
651 let comp_name = {
660 let mut c = comp_surface.chars();
661 match c.next() {
662 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
663 None => comp_surface.clone(),
664 }
665 };
666 return Ok(self.ctx.exprs.alloc(LogicExpr::Predicate {
667 name: self.interner.intern(&comp_name),
668 args: self.ctx.terms.alloc_slice([Term::Constant(subject.noun)]),
669 world: None,
670 }));
671 }
672 self.advance();
673
674 let object_term = if self.check_number() {
676 let num_sym = if let TokenType::Number(sym) = self.advance().kind {
678 sym
679 } else {
680 unreachable!()
681 };
682 let num_str = self.interner.resolve(num_sym);
683 let num_val = num_str.parse::<i64>().unwrap_or(0);
684 self.ctx.terms.alloc(Term::Value {
685 kind: crate::ast::logic::NumberKind::Integer(num_val),
686 unit: None,
687 dimension: None,
688 })
689 } else {
690 let saved_ctx = self.nominal_np_context;
696 self.nominal_np_context = true;
697 let object_result = self.parse_noun_phrase(true);
698 self.nominal_np_context = saved_ctx;
699 let object = object_result?;
700
701 if matches!(
706 self.peek().kind,
707 TokenType::Is | TokenType::Are | TokenType::Was | TokenType::Were
708 ) {
709 let save = self.current;
710 self.advance(); if let TokenType::Adjective(adj2) = self.peek().kind {
712 self.advance();
713 let d1 = self.next_var_name();
714 let d2 = self.next_var_name();
715 let matrix = self.ctx.exprs.alloc(LogicExpr::Predicate {
716 name: adj,
717 args: self
718 .ctx
719 .terms
720 .alloc_slice([Term::Constant(subject.noun), Term::Variable(d1)]),
721 world: None,
722 });
723 let than_clause = self.ctx.exprs.alloc(LogicExpr::Predicate {
724 name: adj2,
725 args: self
726 .ctx
727 .terms
728 .alloc_slice([Term::Constant(object.noun), Term::Variable(d2)]),
729 world: None,
730 });
731 let gt = self.ctx.exprs.alloc(LogicExpr::Predicate {
732 name: self.interner.intern(">"),
733 args: self
734 .ctx
735 .terms
736 .alloc_slice([Term::Variable(d1), Term::Variable(d2)]),
737 world: None,
738 });
739 let conj1 = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
740 left: matrix,
741 op: TokenType::And,
742 right: than_clause,
743 });
744 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
745 left: conj1,
746 op: TokenType::And,
747 right: gt,
748 });
749 let inner = self.ctx.exprs.alloc(LogicExpr::Quantifier {
750 kind: crate::ast::logic::QuantifierKind::Existential,
751 variable: d2,
752 body,
753 island_id: self.current_island,
754 });
755 let outer = self.ctx.exprs.alloc(LogicExpr::Quantifier {
756 kind: crate::ast::logic::QuantifierKind::Existential,
757 variable: d1,
758 body: inner,
759 island_id: self.current_island,
760 });
761 return Ok(outer);
762 }
763 if self.at_clause_boundary() {
767 } else {
769 self.current = save;
770 }
771 }
772
773 let subj_is_desc = !subject.adjectives.is_empty()
781 || subject.possessor.is_some()
782 || !subject.pps.is_empty();
783 let subj_var = if subj_is_desc { Some(self.next_var_name()) } else { None };
784 let subj_term = match subj_var {
785 Some(sv) => Term::Variable(sv),
786 None => Term::Constant(subject.noun),
787 };
788
789 let has_rel = self.check(&TokenType::Who) || self.check(&TokenType::That);
795 let obj_is_desc = has_rel
796 || !object.adjectives.is_empty()
797 || object.possessor.is_some()
798 || !object.pps.is_empty();
799 if obj_is_desc {
800 let obj_var = self.next_var_name();
801 let obj_var_term = Term::Variable(obj_var);
802 let mut restrictor = self.nominal_predication_with_pps(obj_var_term, &object);
803 if has_rel {
804 self.advance(); let rel = self.parse_relative_clause(obj_var)?;
806 restrictor = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
807 left: restrictor,
808 op: TokenType::And,
809 right: rel,
810 });
811 }
812 let cmp = self.ctx.exprs.alloc(LogicExpr::Comparative {
813 adjective: adj,
814 subject: self.ctx.terms.alloc(subj_term),
815 object: self.ctx.terms.alloc(obj_var_term),
816 difference,
817 relation: crate::ast::ComparisonRelation::Greater,
818 });
819 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
820 left: restrictor,
821 op: TokenType::And,
822 right: cmp,
823 });
824 let quant = self.ctx.exprs.alloc(LogicExpr::Quantifier {
825 kind: crate::ast::logic::QuantifierKind::Existential,
826 variable: obj_var,
827 body,
828 island_id: self.current_island,
829 });
830 return match subj_var {
831 Some(sv) => {
832 let subj_restrictor =
833 self.nominal_predication_with_pps(Term::Variable(sv), subject);
834 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
835 left: subj_restrictor,
836 op: TokenType::And,
837 right: quant,
838 });
839 Ok(self.ctx.exprs.alloc(LogicExpr::Quantifier {
840 kind: crate::ast::logic::QuantifierKind::Existential,
841 variable: sv,
842 body,
843 island_id: self.current_island,
844 }))
845 }
846 None => self.wrap_with_definiteness(subject.definiteness, subject.noun, quant),
847 };
848 }
849
850 let obj_term = self.ctx.terms.alloc(Term::Constant(object.noun));
851
852 let result = self.ctx.exprs.alloc(LogicExpr::Comparative {
853 adjective: adj,
854 subject: self.ctx.terms.alloc(subj_term),
855 object: obj_term,
856 difference,
857 relation: crate::ast::ComparisonRelation::Greater,
858 });
859
860 let result = match subj_var {
861 Some(sv) => {
862 let subj_restrictor =
863 self.nominal_predication_with_pps(Term::Variable(sv), subject);
864 let body = self.ctx.exprs.alloc(LogicExpr::BinaryOp {
865 left: subj_restrictor,
866 op: TokenType::And,
867 right: result,
868 });
869 self.ctx.exprs.alloc(LogicExpr::Quantifier {
870 kind: crate::ast::logic::QuantifierKind::Existential,
871 variable: sv,
872 body,
873 island_id: self.current_island,
874 })
875 }
876 None => self.wrap_with_definiteness(subject.definiteness, subject.noun, result)?,
877 };
878 return self.wrap_with_definiteness_for_object(object.definiteness, object.noun, result);
879 };
880
881 Ok(self.ctx.exprs.alloc(LogicExpr::Comparative {
883 adjective: adj,
884 subject: self.ctx.terms.alloc(Term::Constant(subject.noun)),
885 object: object_term,
886 difference,
887 relation: crate::ast::ComparisonRelation::Greater,
888 }))
889 }
890
891 fn parse_equative(
895 &mut self,
896 subject: &NounPhrase<'a>,
897 ) -> ParseResult<&'a LogicExpr<'a>> {
898 self.advance(); let adj = match self.advance().kind.clone() {
901 TokenType::Adjective(a) => a,
902 TokenType::Comparative(a) => a,
903 other => {
904 if let TokenType::Noun(a) = other {
906 a
907 } else {
908 self.interner.intern(&self.interner.resolve(self.previous().lexeme).to_string())
909 }
910 }
911 };
912 if self.interner.resolve(self.peek().lexeme).eq_ignore_ascii_case("as") {
914 self.advance();
915 }
916 let object = self.parse_noun_phrase(false)?;
917 let obj_term = self.ctx.terms.alloc(Term::Constant(object.noun));
918 let result = self.ctx.exprs.alloc(LogicExpr::Comparative {
919 adjective: adj,
920 subject: self.ctx.terms.alloc(Term::Constant(subject.noun)),
921 object: obj_term,
922 difference: None,
923 relation: crate::ast::ComparisonRelation::GreaterEqual,
924 });
925 let result = self.wrap_with_definiteness(subject.definiteness, subject.noun, result)?;
926 self.wrap_with_definiteness_for_object(object.definiteness, object.noun, result)
927 }
928
929 fn check_number(&self) -> bool {
930 matches!(
934 self.peek().kind,
935 TokenType::Number(_) | TokenType::TimeLiteral { .. }
936 )
937 }
938
939 fn parse_measure_phrase(&mut self) -> ParseResult<&'a Term<'a>> {
940 if let TokenType::TimeLiteral { nanos_from_midnight } = self.peek().kind {
946 self.advance();
947 let minutes = (nanos_from_midnight / 60_000_000_000) as i64;
948 return Ok(self.ctx.terms.alloc(Term::Value {
949 kind: crate::ast::logic::NumberKind::Integer(minutes),
950 unit: None,
951 dimension: Some(crate::ast::logic::Dimension::Time),
952 }));
953 }
954 let num_sym = if let TokenType::Number(sym) = self.advance().kind {
955 sym
956 } else {
957 return Err(ParseError {
958 kind: ParseErrorKind::ExpectedNumber,
959 span: self.current_span(),
960 });
961 };
962
963 let num_str = self.interner.resolve(num_sym);
964 let kind = parse_number_kind(num_str, num_sym);
965
966 let next_is_inflected_verb = match &self.peek().kind {
971 TokenType::Verb { time, .. } => matches!(time, Time::Past | Time::Future),
972 TokenType::Ambiguous { primary, .. } => {
973 matches!(**primary, TokenType::Verb { time, .. } if matches!(time, Time::Past | Time::Future))
974 }
975 _ => false,
976 };
977 let (unit, dimension) = if matches!(self.peek().kind, TokenType::CalendarUnit(_)) {
978 let unit_word = self.peek().lexeme;
983 self.advance();
984 (Some(unit_word), None)
985 } else if self.check_content_word() && !self.check_article() && !next_is_inflected_verb {
986 let unit_word = self.consume_content_word()?;
989 let unit_str = self.interner.resolve(unit_word).to_lowercase();
990 let dim = lexicon::lookup_unit_dimension(&unit_str);
991 (Some(unit_word), dim)
992 } else {
993 (None, None)
994 };
995
996 Ok(self.ctx.terms.alloc(Term::Value { kind, unit, dimension }))
997 }
998
999 fn counting_np_lookahead(&self) -> Option<u32> {
1000 let n = match self.peek().kind {
1001 TokenType::Number(sym) => self.interner.resolve(sym).parse::<u32>().ok()?,
1002 _ => return None,
1003 };
1004 let mut i = self.current + 1;
1009 let mut saw_modifier = false;
1010 while matches!(
1011 self.tokens.get(i).map(|t| &t.kind),
1012 Some(TokenType::Adjective(_))
1013 | Some(TokenType::NonIntersectiveAdjective(_))
1014 | Some(TokenType::ProperName(_))
1015 ) {
1016 saw_modifier = true;
1017 i += 1;
1018 }
1019 if !saw_modifier {
1020 return None;
1021 }
1022 let head_is_noun = match self.tokens.get(i).map(|t| &t.kind) {
1023 Some(TokenType::Noun(_)) | Some(TokenType::Item) | Some(TokenType::Items) => true,
1024 Some(TokenType::Verb { .. }) => true,
1029 Some(TokenType::Ambiguous { primary, alternatives }) => {
1030 matches!(**primary, TokenType::Noun(_) | TokenType::Verb { .. })
1031 || alternatives
1032 .iter()
1033 .any(|t| matches!(t, TokenType::Noun(_) | TokenType::Verb { .. }))
1034 }
1035 _ => false,
1036 };
1037 head_is_noun.then_some(n)
1038 }
1039}
1040
1041fn parse_number_kind(s: &str, sym: crate::intern::Symbol) -> NumberKind {
1042 if s.contains('.') {
1043 NumberKind::Real(s.parse().unwrap_or(0.0))
1044 } else if s.chars().all(|c| c.is_ascii_digit() || c == '-') {
1045 NumberKind::Integer(s.parse().unwrap_or(0))
1046 } else {
1047 NumberKind::Symbolic(sym)
1048 }
1049}