Skip to main content

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}