logicaffeine_language/token.rs
1//! Token types for the LOGOS lexer and parser.
2//!
3//! This module defines the vocabulary of the LOGOS language at the token level.
4//! Tokens represent the atomic syntactic units produced by the lexer and consumed
5//! by the parser.
6//!
7//! ## Token Categories
8//!
9//! | Category | Examples | Description |
10//! |----------|----------|-------------|
11//! | **Quantifiers** | every, some, no | Bind variables over domains |
12//! | **Determiners** | the, a, this | Select referents |
13//! | **Nouns** | cat, philosopher | Predicates over individuals |
14//! | **Verbs** | runs, loves | Relations between arguments |
15//! | **Adjectives** | red, happy | Modify noun denotations |
16//! | **Connectives** | and, or, implies | Combine propositions |
17//! | **Pronouns** | he, she, it | Resolve to antecedents |
18//!
19//! ## Block Types
20//!
21//! LOGOS uses markdown-style block headers for structured documents:
22//!
23//! - `## Theorem`: Declares a proposition to be proved
24//! - `## Proof`: Contains the proof steps
25//! - `## Definition`: Introduces new terminology
26//! - `## Main`: Program entry point
27
28use logicaffeine_base::Symbol;
29use logicaffeine_lexicon::{Aspect, Case, Definiteness, Gender, Number, Time, VerbClass};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
32pub struct Span {
33 pub start: usize,
34 pub end: usize,
35}
36
37impl Span {
38 pub fn new(start: usize, end: usize) -> Self {
39 Self { start, end }
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum PresupKind {
45 Stop,
46 Start,
47 Regret,
48 Continue,
49 Realize,
50 Know,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum FocusKind {
55 Only,
56 Even,
57 Just,
58 /// it-cleft / pseudo-cleft: "It was John who left." — focus + exhaustivity.
59 Cleft,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum MeasureKind {
64 Much,
65 Little,
66}
67
68/// Calendar time units for Span expressions.
69///
70/// These represent variable-length calendar durations, as opposed to
71/// fixed SI time units (ns, ms, s, etc.) used in Duration.
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum CalendarUnit {
74 Second,
75 Minute,
76 Hour,
77 Day,
78 Week,
79 Month,
80 Year,
81}
82
83/// Document structure block type markers.
84///
85/// LOGOS uses markdown-style `## Header` syntax to delimit different
86/// sections of a program or proof document.
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum BlockType {
89 /// An unknown `## Header` a small edit distance from a CONSEQUENTIAL
90 /// code header (`## Mian` → `Main`) — the parser fails loudly with the
91 /// suggestion instead of silently treating the whole block as prose.
92 SuspectedTypo { found: Symbol, suggestion: Symbol },
93 /// `## Theorem` - Declares a proposition to be proved.
94 Theorem,
95 /// `## Main` - Program entry point for imperative code.
96 Main,
97 /// `## Definition` - Introduces new terminology or type definitions.
98 Definition,
99 /// `## Define` - Mints a vernacular-logic predicate definition that the
100 /// prover unfolds (Rung 0a). Distinct from `## Definition` (type defs).
101 Define,
102 /// `## Axiom` - Declares a named first-order axiom in formal notation
103 /// (`## Axiom name: for all a b, Cong(a,b,b,a).`). Its body is parsed by the
104 /// formal-formula parser and registered as a shared premise for later theorems —
105 /// the seam for an axiomatic base like Tarski geometry.
106 Axiom,
107 /// `## Theory` - Names a development that groups the `## Axiom`s and `## Theorem`s
108 /// that follow it (`## Theory Tarski`).
109 Theory,
110 /// `## Proof` - Contains proof steps for a theorem.
111 Proof,
112 /// `## Example` - Illustrative examples.
113 Example,
114 /// `## Logic` - Direct logical notation input.
115 Logic,
116 /// `## Note` - Explanatory documentation.
117 Note,
118 /// `## To` - Function definition block.
119 Function,
120 /// Inline type definition: `## A Point has:` or `## A Color is one of:`.
121 TypeDef,
122 /// `## Policy` - Security policy rule definitions.
123 Policy,
124 /// `## Requires` - External crate dependency declarations.
125 Requires,
126 /// `## Hardware` - Signal declarations for hardware verification.
127 Hardware,
128 /// `## Property` - Temporal assertions for hardware verification.
129 Property,
130 /// `## No` - Optimization annotation (followed by Memo, TCO, Peephole, Borrow, or Optimize).
131 No,
132 /// `## Tier` - Tiered-optimizer pin: `## Tier <opt> <eager|t1|t2|t3|never>` overrides
133 /// the hotness tier at which that optimization runs (HOTSWAP §8).
134 Tier,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
138pub enum TokenType {
139 // Document Structure
140 BlockHeader { block_type: BlockType },
141
142 // Quantifiers
143 All,
144 No,
145 Some,
146 Any,
147 Both, // Correlative conjunction marker: "both X and Y"
148 Most,
149 Few,
150 Many,
151 Cardinal(u32),
152 AtLeast(u32),
153 AtMost(u32),
154
155 // Negative Polarity Items (NPIs)
156 Anything,
157 Anyone,
158 Nothing,
159 Nobody,
160 NoOne,
161 Nowhere,
162 Ever,
163 Never,
164
165 // Logical Connectives
166 And,
167 Or,
168 If,
169 Then,
170 Not,
171 Iff,
172 Because,
173 /// Concessive subordinator: "although"/"though"/"even though".
174 Although,
175 /// Temporal binary connective: "P until Q"
176 Until,
177 /// Temporal binary connective: "P release Q" (dual of Until)
178 Release,
179 /// Temporal binary connective: "P weak-until Q" (Until or Always)
180 WeakUntil,
181 /// Compiler-generated implication (e.g., quantifier restrictions from Kripke lowering).
182 /// Distinguished from `If` which represents user-written conditionals.
183 /// This separation gives downstream passes (KG extraction, SVA synthesis)
184 /// irrefutable provenance: `If` = user intent, `Implies` = compiler glue.
185 Implies,
186
187 // Modal Operators
188 Must,
189 Shall,
190 Should,
191 Can,
192 May,
193 Cannot,
194 Would,
195 Could,
196 Might,
197 Had,
198
199 // Imperative Statement Keywords
200 Let,
201 Set,
202 Return,
203 /// Exits the innermost while loop: `Break.`
204 Break,
205 Be,
206 While,
207 Repeat,
208 For,
209 In,
210 From,
211 Assert,
212 /// Documented assertion with justification string.
213 Trust,
214 /// Enforced runtime invariant: `Require that <cond>.` → a hard `assert!`
215 /// (survives release, unlike `Assert` → `debug_assert!`).
216 Require,
217 /// Function precondition clause: `Requires <check>.` (checked at entry).
218 Requires,
219 /// Function postcondition clause: `Ensures <check>.` (checked before return).
220 Ensures,
221 Otherwise,
222 /// Alias for `Otherwise` - Pythonic else clause
223 Else,
224 /// Python-style else-if shorthand
225 Elif,
226 Call,
227 /// Constructor keyword for struct instantiation.
228 New,
229 /// Sum type definition keyword.
230 Either,
231 /// Pattern matching statement keyword.
232 Inspect,
233 /// Native function modifier for FFI bindings.
234 Native,
235 /// Escape hatch header keyword: "Escape to Rust:"
236 Escape,
237 /// Raw code block captured verbatim from an escape hatch body.
238 /// The Symbol holds the interned raw foreign code (indentation-stripped).
239 EscapeBlock(Symbol),
240
241 // Theorem Keywords
242 /// Premise marker in theorem blocks.
243 Given,
244 /// Goal marker in theorem blocks.
245 Prove,
246 /// Automatic proof strategy directive.
247 Auto,
248
249 // IO Keywords
250 /// "Read input from..."
251 Read,
252 /// "Write x to file..."
253 Write,
254 /// "...from the console"
255 Console,
256 /// "...from file..." or "...to file..."
257 File,
258
259 // Ownership Keywords (Move/Borrow Semantics)
260 /// Move ownership: "Give x to processor"
261 Give,
262 /// Immutable borrow: "Show x to console"
263 Show,
264
265 // Collection Operations
266 /// "Push x to items"
267 Push,
268 /// "Pop from items"
269 Pop,
270 /// "copy of slice" → slice.to_vec()
271 Copy,
272 /// "items 1 through 3" → inclusive slice
273 Through,
274 /// "length of items" → items.len()
275 Length,
276 /// "items at i" → `items[i]`
277 At,
278
279 // Set Operations
280 /// "Add x to set" (insert)
281 Add,
282 /// "Remove x from set"
283 Remove,
284 /// "set contains x"
285 Contains,
286 /// "a union b"
287 Union,
288 /// "a intersection b"
289 Intersection,
290
291 // Memory Management (Zones)
292 /// "Inside a new zone..."
293 Inside,
294 /// "...zone called..."
295 Zone,
296 /// "...called 'Scratch'"
297 Called,
298 /// "...of size 1 MB"
299 Size,
300 /// "...mapped from 'file.bin'"
301 Mapped,
302
303 // Structured Concurrency
304 /// "Attempt all of the following:" → concurrent (async, I/O-bound)
305 Attempt,
306 /// "the following"
307 Following,
308 /// "Simultaneously:" → parallel (CPU-bound)
309 Simultaneously,
310
311 // Agent System (Actor Model)
312 /// "Spawn a Worker called 'w1'" → create agent
313 Spawn,
314 /// "Send Ping to 'agent'" → send message to agent
315 Send,
316 /// "Await response from 'agent' into result" → receive message
317 Await,
318
319 // Serialization
320 /// "A Message is Portable and has:" → serde derives
321 Portable,
322
323 // Sipping Protocol
324 /// "the manifest of Zone" → FileSipper manifest
325 Manifest,
326 /// "the chunk at N in Zone" → FileSipper chunk
327 Chunk,
328
329 // CRDT Keywords
330 /// "A Counter is Shared and has:" → CRDT struct
331 Shared,
332 /// "Merge remote into local" → CRDT merge
333 Merge,
334 /// "Increase x's count by 10" → GCounter increment
335 Increase,
336
337 // Extended CRDT Keywords
338 /// "Decrease x's count by 5" → PNCounter decrement
339 Decrease,
340 /// "which is a Tally" → PNCounter type
341 Tally,
342 /// "which is a SharedSet of T" → ORSet type
343 SharedSet,
344 /// "which is a SharedSequence of T" → RGA type
345 SharedSequence,
346 /// "which is a CollaborativeSequence of T" → YATA type
347 CollaborativeSequence,
348 /// "which is a SharedMap from K to V" → ORMap type
349 SharedMap,
350 /// "which is a Divergent T" → MVRegister type
351 Divergent,
352 /// "Append x to seq" → RGA append
353 Append,
354 /// "Resolve x to value" → MVRegister resolve
355 Resolve,
356 /// "(RemoveWins)" → ORSet bias
357 RemoveWins,
358 /// "(AddWins)" → ORSet bias (default)
359 AddWins,
360 /// "(YATA)" → Sequence algorithm
361 YATA,
362 /// "x's values" → MVRegister values accessor
363 Values,
364
365 // Security Keywords
366 /// "Check that user is admin" → mandatory runtime guard
367 Check,
368
369 // P2P Networking Keywords
370 /// "Listen on \[addr\]" → bind to network address
371 Listen,
372 /// "Connect to \[addr\]" → dial a peer (NetConnect to avoid conflict)
373 NetConnect,
374 /// "Sleep N." → pause execution for N milliseconds
375 Sleep,
376
377 // GossipSub Keywords
378 /// "Sync x on 'topic'" → automatic CRDT replication
379 Sync,
380
381 // Persistence Keywords
382 /// "Mount x at \[path\]" → load/create persistent CRDT from journal
383 Mount,
384 /// "Persistent Counter" → type wrapped with journaling
385 Persistent,
386 /// "x combined with y" → string concatenation
387 Combined,
388 /// "a followed by b" → sequence concatenation (merge two sequences into one)
389 Followed,
390
391 // Go-like Concurrency Keywords
392 /// "Launch a task to..." → spawn green thread
393 Launch,
394 /// "a task" → identifier for task context
395 Task,
396 /// "Pipe of Type" → channel creation
397 Pipe,
398 /// "Receive from pipe" → recv from channel
399 Receive,
400 /// "Stop handle" → abort task
401 Stop,
402 /// "Try to send/receive" → non-blocking variant
403 Try,
404 /// "Send value into pipe" → channel send
405 Into,
406 /// "Await the first of:" → select statement
407 First,
408 /// "After N seconds:" → timeout branch
409 After,
410
411 // Block Scoping
412 Colon,
413 Indent,
414 Dedent,
415 Newline,
416
417 // Content Words
418 Noun(Symbol),
419 Adjective(Symbol),
420 NonIntersectiveAdjective(Symbol),
421 Adverb(Symbol),
422 ScopalAdverb(Symbol),
423 TemporalAdverb(Symbol),
424 Verb {
425 lemma: Symbol,
426 time: Time,
427 aspect: Aspect,
428 class: VerbClass,
429 },
430 ProperName(Symbol),
431
432 /// Lexically ambiguous token (e.g., "fish" as noun or verb).
433 ///
434 /// The parser tries the primary interpretation first, then alternatives
435 /// if parsing fails. Used for parse forest generation.
436 Ambiguous {
437 primary: Box<TokenType>,
438 alternatives: Vec<TokenType>,
439 },
440
441 // Speech Acts (Performatives)
442 Performative(Symbol),
443 Exclamation,
444
445 // Articles (Definiteness)
446 Article(Definiteness),
447
448 // Temporal Auxiliaries
449 Auxiliary(Time),
450
451 // Copula & Functional
452 Is,
453 Are,
454 Was,
455 Were,
456 That,
457 Who,
458 What,
459 Where,
460 Whose,
461 When,
462 Why,
463 Does,
464 Do,
465
466 // Identity & Reflexive (FOL)
467 Identity,
468 Equals,
469 Reflexive,
470 Reciprocal,
471 /// Pairwise list coordination: "A and B respectively love C and D"
472 Respectively,
473
474 // Pronouns (Discourse)
475 Pronoun {
476 gender: Gender,
477 number: Number,
478 case: Case,
479 },
480
481 // Prepositions (for N-ary relations)
482 Preposition(Symbol),
483
484 // Phrasal Verb Particles (up, down, out, in, off, on, away)
485 Particle(Symbol),
486
487 // Comparatives & Superlatives (Pillar 3 - Degree Semantics)
488 Comparative(Symbol),
489 Superlative(Symbol),
490 Than,
491
492 // Control Verbs (Chomsky's Control Theory)
493 To,
494
495 // Presupposition Triggers (Austin/Strawson)
496 PresupTrigger(PresupKind),
497
498 // Focus Particles (Rooth)
499 Focus(FocusKind),
500
501 // Mass Noun Measure
502 Measure(MeasureKind),
503
504 // Numeric Literals (prover-ready: stores raw string for symbolic math)
505 Number(Symbol),
506
507 /// Currency-symbol money literal: `$19.99`, `€5`, `£10`, `¥100`. Carries the magnitude (digits +
508 /// optional decimal point, thousands separators stripped) and the resolved ISO-4217 code, so a
509 /// money-aware parser builds `money(..)` while a magnitude-only consumer can still read `amount`.
510 MoneyLiteral {
511 amount: Symbol,
512 currency: Symbol,
513 },
514
515 /// Duration literal with SI suffix: 500ms, 2s, 50ns
516 /// Stores the value normalized to nanoseconds and preserves the original unit.
517 DurationLiteral {
518 nanos: i64,
519 original_unit: Symbol,
520 },
521
522 /// Date literal in ISO-8601 format: 2026-05-20
523 /// Stores days since Unix epoch (1970-01-01).
524 DateLiteral {
525 days: i32,
526 },
527
528 /// Time-of-day literal: 4pm, 9:30am, noon, midnight
529 /// Stores nanoseconds from midnight (00:00:00).
530 TimeLiteral {
531 nanos_from_midnight: i64,
532 },
533
534 /// Calendar time unit word: day, week, month, year (or plurals)
535 /// Used in Span expressions like "3 days" or "2 months and 5 days"
536 CalendarUnit(CalendarUnit),
537
538 /// Postfix operator for relative past time: "3 days ago"
539 Ago,
540
541 /// Postfix operator for relative future time: "3 days hence"
542 Hence,
543
544 /// Binary operator for span subtraction from a date: "3 days before 2026-05-20"
545 Before,
546
547 /// String literal: `"hello world"`
548 StringLiteral(Symbol),
549
550 /// Interpolated string literal: `"Hello, {name}!"`
551 /// Contains raw content with {} holes preserved
552 InterpolatedString(Symbol),
553
554 // Character literal: `x` (backtick syntax)
555 CharLiteral(Symbol),
556
557 // Index Access (1-indexed)
558 Item,
559 Items,
560
561 // Possession (Genitive Case)
562 Possessive,
563
564 // Punctuation
565 LParen,
566 RParen,
567 LBracket,
568 RBracket,
569 /// `{` — map/set literal opener (`{k: v}`, `{a, b}`). Interpolation braces
570 /// never reach here (they are consumed inside the string-literal path).
571 LBrace,
572 /// `&` in IMPERATIVE code — bitwise AND on Int, intersection on Sets.
573 /// In prose the same character stays the coordination/firm-name joiner.
574 Amp,
575 /// `|` in imperative code — bitwise OR on Int, union on Sets. (`Pipe`
576 /// is taken by the channel keyword `Pipe of T`.)
577 VBar,
578 /// `~` in imperative code — bitwise complement (lowers to `x ^ -1`).
579 Tilde,
580 /// `^` in imperative code — bitwise XOR on Int, symmetric difference on
581 /// Sets (the word `xor` remains the English spelling).
582 Caret,
583 /// `}` — map/set literal closer.
584 RBrace,
585 Comma,
586 Period,
587 /// `.` as the FIELD-ACCESS / UFCS-method operator (imperative only): `p.x`
588 /// (≡ `p's x`) and `xs.f(a)` (≡ `f(xs, a)`). Distinguished from a sentence
589 /// `Period` in the lexer by the no-whitespace + identifier-on-both-sides rule.
590 Dot,
591
592 // Bitwise Operators
593 /// "x xor y" → bitwise XOR (`^`)
594 Xor,
595 /// "x shifted left/right by y" → bit shift (`<<`/`>>`)
596 Shifted,
597
598 // Arithmetic Operators
599 Plus,
600 Minus,
601 Star,
602 Slash,
603 Percent, // Modulo operator
604 /// Compound assignment operators — `x += e` desugars to `Set x to x <op> e`.
605 PlusEq,
606 MinusEq,
607 StarEq,
608 SlashEq,
609 PercentEq,
610 /// `**` — the exponentiation operator.
611 StarStar,
612 /// `//` — floor division (rounds toward negative infinity).
613 SlashSlash,
614
615 // Comparison Operators
616 /// `<`
617 Lt,
618 /// `>`
619 Gt,
620 /// `<=`
621 LtEq,
622 /// `>=`
623 GtEq,
624 /// `==`
625 EqEq,
626 /// `!=`
627 NotEq,
628
629 /// Arrow for return type syntax: `->`
630 Arrow,
631
632 /// Assignment operator `=` for `identifier = value` syntax
633 Assign,
634
635 /// Mutability keyword `mut` for explicit mutable declarations
636 Mut,
637
638 /// Generic identifier (for equals-style assignment)
639 Identifier,
640
641 EOF,
642}
643
644#[derive(Debug, Clone)]
645pub struct Token {
646 pub kind: TokenType,
647 pub lexeme: Symbol,
648 pub span: Span,
649}
650
651impl Token {
652 pub fn new(kind: TokenType, lexeme: Symbol, span: Span) -> Self {
653 Token { kind, lexeme, span }
654 }
655}
656
657impl TokenType {
658 pub const WH_WORDS: &'static [TokenType] = &[
659 TokenType::Who,
660 TokenType::What,
661 TokenType::Where,
662 TokenType::When,
663 TokenType::Why,
664 ];
665
666 pub const MODALS: &'static [TokenType] = &[
667 TokenType::Must,
668 TokenType::Shall,
669 TokenType::Should,
670 TokenType::Can,
671 TokenType::May,
672 TokenType::Cannot,
673 TokenType::Would,
674 TokenType::Could,
675 TokenType::Might,
676 ];
677}
678
679#[cfg(test)]
680mod tests {
681 use super::*;
682
683 #[test]
684 fn span_new_stores_positions() {
685 let span = Span::new(5, 10);
686 assert_eq!(span.start, 5);
687 assert_eq!(span.end, 10);
688 }
689
690 #[test]
691 fn span_default_is_zero() {
692 let span = Span::default();
693 assert_eq!(span.start, 0);
694 assert_eq!(span.end, 0);
695 }
696
697 #[test]
698 fn token_has_span_field() {
699 use logicaffeine_base::Interner;
700 let mut interner = Interner::new();
701 let lexeme = interner.intern("test");
702 let token = Token::new(TokenType::Noun(lexeme), lexeme, Span::new(0, 4));
703 assert_eq!(token.span.start, 0);
704 assert_eq!(token.span.end, 4);
705 }
706
707 #[test]
708 fn wh_words_contains_all_wh_tokens() {
709 assert_eq!(TokenType::WH_WORDS.len(), 5);
710 assert!(TokenType::WH_WORDS.contains(&TokenType::Who));
711 assert!(TokenType::WH_WORDS.contains(&TokenType::What));
712 assert!(TokenType::WH_WORDS.contains(&TokenType::Where));
713 assert!(TokenType::WH_WORDS.contains(&TokenType::When));
714 assert!(TokenType::WH_WORDS.contains(&TokenType::Why));
715 }
716
717 #[test]
718 fn modals_contains_all_modal_tokens() {
719 assert_eq!(TokenType::MODALS.len(), 9);
720 assert!(TokenType::MODALS.contains(&TokenType::Must));
721 assert!(TokenType::MODALS.contains(&TokenType::Shall));
722 assert!(TokenType::MODALS.contains(&TokenType::Should));
723 assert!(TokenType::MODALS.contains(&TokenType::Can));
724 assert!(TokenType::MODALS.contains(&TokenType::May));
725 assert!(TokenType::MODALS.contains(&TokenType::Cannot));
726 assert!(TokenType::MODALS.contains(&TokenType::Would));
727 assert!(TokenType::MODALS.contains(&TokenType::Could));
728 assert!(TokenType::MODALS.contains(&TokenType::Might));
729 }
730}