logicaffeine_language/ast/stmt.rs
1//! Imperative statement AST types for the LOGOS language.
2//!
3//! This module defines statement types for the imperative fragment including:
4//!
5//! - **[`Stmt`]**: Statement variants (let, if, match, while, for, function defs)
6//! - **[`Expr`]**: Imperative expressions (field access, method calls, literals)
7//! - **[`TypeExpr`]**: Type annotations with refinements and generics
8//! - **[`Literal`]**: Literal values (numbers, strings, booleans)
9//! - **[`Block`]**: Statement blocks with optional return expressions
10//!
11//! The imperative AST is used in LOGOS mode for generating executable Rust code.
12
13use super::logic::LogicExpr;
14use super::theorem::TheoremBlock;
15use logicaffeine_base::Symbol;
16
17/// Type expression for explicit type annotations.
18///
19/// Represents type syntax like:
20/// - `Int` → Primitive(Int)
21/// - `User` → Named(User)
22/// - `List of Int` → Generic { base: List, params: [Primitive(Int)] }
23/// - `List of List of Int` → Generic { base: List, params: [Generic { base: List, params: [Primitive(Int)] }] }
24/// - `Result of Int and Text` → Generic { base: Result, params: [Primitive(Int), Primitive(Text)] }
25#[derive(Debug, Clone)]
26pub enum TypeExpr<'a> {
27 /// Primitive type: Int, Nat, Text, Bool
28 Primitive(Symbol),
29 /// Named type (user-defined): User, Point
30 Named(Symbol),
31 /// Generic type: List of Int, Option of Text, Result of Int and Text
32 Generic {
33 base: Symbol,
34 params: &'a [TypeExpr<'a>],
35 },
36 /// Function type: fn(A, B) -> C (for higher-order functions)
37 Function {
38 inputs: &'a [TypeExpr<'a>],
39 output: &'a TypeExpr<'a>,
40 },
41 /// Refinement type with predicate constraint.
42 /// Example: `Int where it > 0`
43 Refinement {
44 /// The base type being refined
45 base: &'a TypeExpr<'a>,
46 /// The bound variable (usually "it")
47 var: Symbol,
48 /// The predicate constraint (from Logic Kernel)
49 predicate: &'a LogicExpr<'a>,
50 },
51 /// Persistent storage wrapper type.
52 /// Example: `Persistent Counter`
53 /// Semantics: Wraps a Shared type with journal-backed storage
54 Persistent {
55 /// The inner type (must be a Shared/CRDT type)
56 inner: &'a TypeExpr<'a>,
57 },
58}
59
60/// Source for Read statements.
61#[derive(Debug, Clone, Copy)]
62pub enum ReadSource<'a> {
63 /// Read from console (stdin)
64 Console,
65 /// Read from file at given path
66 File(&'a Expr<'a>),
67}
68
69/// Pattern for loop variable binding.
70/// Supports single identifiers and tuple destructuring for Map iteration.
71#[derive(Debug, Clone)]
72pub enum Pattern {
73 /// Single identifier: `Repeat for x in list`
74 Identifier(Symbol),
75 /// Tuple destructuring: `Repeat for (k, v) in map`
76 Tuple(Vec<Symbol>),
77}
78
79/// Binary operation kinds for imperative expressions.
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum BinaryOpKind {
82 Add,
83 Subtract,
84 Multiply,
85 Divide,
86 Modulo,
87 Eq,
88 NotEq,
89 Lt,
90 Gt,
91 LtEq,
92 GtEq,
93 // Logical operators for compound conditions
94 And,
95 Or,
96 /// String concatenation ("X combined with Y")
97 Concat,
98}
99
100/// Block is a sequence of statements.
101pub type Block<'a> = &'a [Stmt<'a>];
102
103/// Match arm for pattern matching in Inspect statements.
104#[derive(Debug, Clone)]
105pub struct MatchArm<'a> {
106 pub enum_name: Option<Symbol>, // The enum type (e.g., Shape)
107 pub variant: Option<Symbol>, // None = Otherwise (wildcard)
108 pub bindings: Vec<(Symbol, Symbol)>, // (field_name, binding_name)
109 pub body: Block<'a>,
110}
111
112/// Imperative statement AST (LOGOS §15.0.0).
113///
114/// Stmt is the primary AST node for imperative code blocks like `## Main`
115/// and function bodies. The Assert variant bridges to the Logic Kernel.
116#[derive(Debug, Clone)]
117pub enum Stmt<'a> {
118 /// Variable binding: `Let x be 5.` or `Let x: Int be 5.`
119 Let {
120 var: Symbol,
121 ty: Option<&'a TypeExpr<'a>>,
122 value: &'a Expr<'a>,
123 mutable: bool,
124 },
125
126 /// Mutation: `Set x to 10.`
127 Set {
128 target: Symbol,
129 value: &'a Expr<'a>,
130 },
131
132 /// Function call as statement: `Call process with data.`
133 Call {
134 function: Symbol,
135 args: Vec<&'a Expr<'a>>,
136 },
137
138 /// Conditional: `If condition: ... Otherwise: ...`
139 If {
140 cond: &'a Expr<'a>,
141 then_block: Block<'a>,
142 else_block: Option<Block<'a>>,
143 },
144
145 /// Loop: `While condition: ...` or `While condition (decreasing expr): ...`
146 While {
147 cond: &'a Expr<'a>,
148 body: Block<'a>,
149 /// Optional decreasing variant for termination proof.
150 decreasing: Option<&'a Expr<'a>>,
151 },
152
153 /// Iteration: `Repeat for x in list: ...` or `Repeat for i from 1 to 10: ...`
154 Repeat {
155 pattern: Pattern, // Changed from `var: Symbol` to support tuple destructuring
156 iterable: &'a Expr<'a>,
157 body: Block<'a>,
158 },
159
160 /// Return: `Return x.` or `Return.`
161 Return {
162 value: Option<&'a Expr<'a>>,
163 },
164
165 /// Bridge to Logic Kernel: `Assert that P.`
166 Assert {
167 proposition: &'a LogicExpr<'a>,
168 },
169
170 /// Documented assertion with justification.
171 /// `Trust that P because "reason".`
172 /// Semantics: Documented runtime check that could be verified statically.
173 Trust {
174 proposition: &'a LogicExpr<'a>,
175 justification: Symbol,
176 },
177
178 /// Runtime assertion with imperative condition
179 /// `Assert that condition.` (for imperative mode)
180 RuntimeAssert {
181 condition: &'a Expr<'a>,
182 },
183
184 /// Ownership transfer (move): `Give x to processor.`
185 /// Semantics: Move ownership of `object` to `recipient`.
186 Give {
187 object: &'a Expr<'a>,
188 recipient: &'a Expr<'a>,
189 },
190
191 /// Immutable borrow: `Show x to console.`
192 /// Semantics: Immutable borrow of `object` passed to `recipient`.
193 Show {
194 object: &'a Expr<'a>,
195 recipient: &'a Expr<'a>,
196 },
197
198 /// Field mutation: `Set p's x to 10.`
199 SetField {
200 object: &'a Expr<'a>,
201 field: Symbol,
202 value: &'a Expr<'a>,
203 },
204
205 /// Struct definition for codegen.
206 StructDef {
207 name: Symbol,
208 fields: Vec<(Symbol, Symbol, bool)>, // (name, type_name, is_public)
209 is_portable: bool, // Derives Serialize/Deserialize
210 },
211
212 /// Function definition.
213 FunctionDef {
214 name: Symbol,
215 params: Vec<(Symbol, &'a TypeExpr<'a>)>,
216 body: Block<'a>,
217 return_type: Option<&'a TypeExpr<'a>>,
218 is_native: bool,
219 /// Rust path for user-defined native functions (e.g., "reqwest::blocking::get").
220 /// None for system native functions (read, write, etc.) which use map_native_function().
221 native_path: Option<Symbol>,
222 /// Whether this function is exported for FFI (C ABI or WASM).
223 is_exported: bool,
224 /// Export target: None = C ABI (#[no_mangle] extern "C"), Some("wasm") = #[wasm_bindgen].
225 export_target: Option<Symbol>,
226 },
227
228 /// Pattern matching on sum types.
229 Inspect {
230 target: &'a Expr<'a>,
231 arms: Vec<MatchArm<'a>>,
232 has_otherwise: bool, // For exhaustiveness tracking
233 },
234
235 /// Push to collection: `Push x to items.`
236 Push {
237 value: &'a Expr<'a>,
238 collection: &'a Expr<'a>,
239 },
240
241 /// Pop from collection: `Pop from items.` or `Pop from items into y.`
242 Pop {
243 collection: &'a Expr<'a>,
244 into: Option<Symbol>,
245 },
246
247 /// Add to set: `Add x to set.`
248 Add {
249 value: &'a Expr<'a>,
250 collection: &'a Expr<'a>,
251 },
252
253 /// Remove from set: `Remove x from set.`
254 Remove {
255 value: &'a Expr<'a>,
256 collection: &'a Expr<'a>,
257 },
258
259 /// Index assignment: `Set item N of X to Y.`
260 SetIndex {
261 collection: &'a Expr<'a>,
262 index: &'a Expr<'a>,
263 value: &'a Expr<'a>,
264 },
265
266 /// Memory arena block (Zone).
267 /// "Inside a new zone called 'Scratch':"
268 /// "Inside a zone called 'Buffer' of size 1 MB:"
269 /// "Inside a zone called 'Data' mapped from 'file.bin':"
270 Zone {
271 /// The variable name for the arena handle (e.g., "Scratch")
272 name: Symbol,
273 /// Optional pre-allocated capacity in bytes (Heap zones only)
274 capacity: Option<usize>,
275 /// Optional file path for memory-mapped zones (Mapped zones only)
276 source_file: Option<Symbol>,
277 /// The code block executed within this memory context
278 body: Block<'a>,
279 },
280
281 /// Concurrent execution block (async, I/O-bound).
282 /// "Attempt all of the following:"
283 /// Semantics: All tasks run concurrently via tokio::join!
284 /// Best for: network requests, file I/O, waiting operations
285 Concurrent {
286 /// The statements to execute concurrently
287 tasks: Block<'a>,
288 },
289
290 /// Parallel execution block (CPU-bound).
291 /// "Simultaneously:"
292 /// Semantics: True parallelism via rayon::join or thread::spawn
293 /// Best for: computation, data processing, number crunching
294 Parallel {
295 /// The statements to execute in parallel
296 tasks: Block<'a>,
297 },
298
299 /// Read from console or file.
300 /// `Read input from the console.` or `Read data from file "path.txt".`
301 ReadFrom {
302 var: Symbol,
303 source: ReadSource<'a>,
304 },
305
306 /// Write to file.
307 /// `Write "content" to file "output.txt".`
308 WriteFile {
309 content: &'a Expr<'a>,
310 path: &'a Expr<'a>,
311 },
312
313 /// Spawn an agent.
314 /// `Spawn a Worker called "w1".`
315 Spawn {
316 agent_type: Symbol,
317 name: Symbol,
318 },
319
320 /// Send message to agent.
321 /// `Send Ping to "agent".`
322 SendMessage {
323 message: &'a Expr<'a>,
324 destination: &'a Expr<'a>,
325 },
326
327 /// Await response from agent.
328 /// `Await response from "agent" into result.`
329 AwaitMessage {
330 source: &'a Expr<'a>,
331 into: Symbol,
332 },
333
334 /// Merge CRDT state.
335 /// `Merge remote into local.` or `Merge remote's field into local's field.`
336 MergeCrdt {
337 source: &'a Expr<'a>,
338 target: &'a Expr<'a>,
339 },
340
341 /// Increment GCounter.
342 /// `Increase local's points by 10.`
343 IncreaseCrdt {
344 object: &'a Expr<'a>,
345 field: Symbol,
346 amount: &'a Expr<'a>,
347 },
348
349 /// Decrement PNCounter (Tally).
350 /// `Decrease game's score by 5.`
351 DecreaseCrdt {
352 object: &'a Expr<'a>,
353 field: Symbol,
354 amount: &'a Expr<'a>,
355 },
356
357 /// Append to SharedSequence (RGA).
358 /// `Append "Hello" to doc's lines.`
359 AppendToSequence {
360 sequence: &'a Expr<'a>,
361 value: &'a Expr<'a>,
362 },
363
364 /// Resolve MVRegister conflicts.
365 /// `Resolve page's title to "Final".`
366 ResolveConflict {
367 object: &'a Expr<'a>,
368 field: Symbol,
369 value: &'a Expr<'a>,
370 },
371
372 /// Security check - mandatory runtime guard.
373 /// `Check that user is admin.`
374 /// `Check that user can publish the document.`
375 /// Semantics: NEVER optimized out. Panics if condition is false.
376 Check {
377 /// The subject being checked (e.g., "user")
378 subject: Symbol,
379 /// The predicate name (e.g., "admin") or action (e.g., "publish")
380 predicate: Symbol,
381 /// True if this is a capability check (`can [action]`)
382 is_capability: bool,
383 /// For capabilities: the object being acted on (e.g., "document")
384 object: Option<Symbol>,
385 /// Original English text for error message
386 source_text: String,
387 /// Source location for error reporting
388 span: crate::token::Span,
389 },
390
391 /// Listen on network address.
392 /// `Listen on "/ip4/127.0.0.1/tcp/8000".`
393 /// Semantics: Bind to address, start accepting connections via libp2p
394 Listen {
395 address: &'a Expr<'a>,
396 },
397
398 /// Connect to remote peer.
399 /// `Connect to "/ip4/127.0.0.1/tcp/8000".`
400 /// Semantics: Dial peer via libp2p
401 ConnectTo {
402 address: &'a Expr<'a>,
403 },
404
405 /// Create PeerAgent remote handle.
406 /// `Let remote be a PeerAgent at "/ip4/127.0.0.1/tcp/8000".`
407 /// Semantics: Create handle for remote agent communication
408 LetPeerAgent {
409 var: Symbol,
410 address: &'a Expr<'a>,
411 },
412
413 /// Sleep for milliseconds.
414 /// `Sleep 1000.` or `Sleep delay.`
415 /// Semantics: Pause execution for N milliseconds (async)
416 Sleep {
417 milliseconds: &'a Expr<'a>,
418 },
419
420 /// Sync CRDT variable on topic.
421 /// `Sync x on "topic".`
422 /// Semantics: Subscribe to GossipSub topic, auto-publish on mutation, auto-merge on receive
423 Sync {
424 var: Symbol,
425 topic: &'a Expr<'a>,
426 },
427
428 /// Mount persistent CRDT from journal file.
429 /// `Mount counter at "data/counter.journal".`
430 /// Semantics: Load or create journal, replay operations to reconstruct state
431 Mount {
432 /// The variable name for the mounted value
433 var: Symbol,
434 /// The path expression for the journal file
435 path: &'a Expr<'a>,
436 },
437
438 // =========================================================================
439 // Go-like Concurrency (Green Threads, Channels, Select)
440 // =========================================================================
441
442 /// Launch a fire-and-forget task (green thread).
443 /// `Launch a task to process(data).`
444 /// Semantics: tokio::spawn with no handle capture
445 LaunchTask {
446 /// The function to call
447 function: Symbol,
448 /// Arguments to pass
449 args: Vec<&'a Expr<'a>>,
450 },
451
452 /// Launch a task with handle for control.
453 /// `Let worker be Launch a task to process(data).`
454 /// Semantics: tokio::spawn returning JoinHandle
455 LaunchTaskWithHandle {
456 /// Variable to bind the handle
457 handle: Symbol,
458 /// The function to call
459 function: Symbol,
460 /// Arguments to pass
461 args: Vec<&'a Expr<'a>>,
462 },
463
464 /// Create a bounded channel (pipe).
465 /// `Let jobs be a new Pipe of Int.`
466 /// Semantics: tokio::sync::mpsc::channel(32)
467 CreatePipe {
468 /// Variable for the pipe
469 var: Symbol,
470 /// Type of values in the pipe
471 element_type: Symbol,
472 /// Optional capacity (defaults to 32)
473 capacity: Option<u32>,
474 },
475
476 /// Blocking send into pipe.
477 /// `Send value into pipe.`
478 /// Semantics: pipe_tx.send(value).await
479 SendPipe {
480 /// The value to send
481 value: &'a Expr<'a>,
482 /// The pipe to send into
483 pipe: &'a Expr<'a>,
484 },
485
486 /// Blocking receive from pipe.
487 /// `Receive x from pipe.`
488 /// Semantics: let x = pipe_rx.recv().await
489 ReceivePipe {
490 /// Variable to bind the received value
491 var: Symbol,
492 /// The pipe to receive from
493 pipe: &'a Expr<'a>,
494 },
495
496 /// Non-blocking send (try).
497 /// `Try to send value into pipe.`
498 /// Semantics: pipe_tx.try_send(value) - returns immediately
499 TrySendPipe {
500 /// The value to send
501 value: &'a Expr<'a>,
502 /// The pipe to send into
503 pipe: &'a Expr<'a>,
504 /// Variable to bind the result (true/false)
505 result: Option<Symbol>,
506 },
507
508 /// Non-blocking receive (try).
509 /// `Try to receive x from pipe.`
510 /// Semantics: pipe_rx.try_recv() - returns Option
511 TryReceivePipe {
512 /// Variable to bind the received value (if any)
513 var: Symbol,
514 /// The pipe to receive from
515 pipe: &'a Expr<'a>,
516 },
517
518 /// Cancel a spawned task.
519 /// `Stop worker.`
520 /// Semantics: handle.abort()
521 StopTask {
522 /// The handle to cancel
523 handle: &'a Expr<'a>,
524 },
525
526 /// Select on multiple channels/timeouts.
527 /// `Await the first of:`
528 /// `Receive x from ch:`
529 /// `...`
530 /// `After 5 seconds:`
531 /// `...`
532 /// Semantics: tokio::select! with auto-cancel
533 Select {
534 /// The branches to select from
535 branches: Vec<SelectBranch<'a>>,
536 },
537
538 /// Theorem block.
539 /// `## Theorem: Name`
540 /// `Given: Premise.`
541 /// `Prove: Goal.`
542 /// `Proof: Auto.`
543 Theorem(TheoremBlock<'a>),
544
545 /// Escape hatch: embed raw foreign code.
546 /// `Escape to Rust:` followed by an indented block of raw code.
547 ///
548 /// Variables from the enclosing LOGOS scope are available in the
549 /// escape block as their generated Rust types. The raw code is
550 /// emitted verbatim inside a `{ ... }` block in the generated Rust.
551 Escape {
552 /// Target language ("Rust" for now, forward-compatible with "Python", "WGSL", etc.)
553 language: Symbol,
554 /// Raw foreign code, captured verbatim with base indentation stripped.
555 code: Symbol,
556 /// Source span covering the entire escape block (header + body).
557 span: crate::token::Span,
558 },
559
560 /// Dependency declaration from `## Requires` block.
561 /// The "serde" crate version "1.0" with features "derive".
562 Require {
563 crate_name: Symbol,
564 version: Symbol,
565 features: Vec<Symbol>,
566 span: crate::token::Span,
567 },
568}
569
570/// A branch in a Select statement.
571#[derive(Debug, Clone)]
572pub enum SelectBranch<'a> {
573 /// Receive from a pipe: `Receive x from ch:`
574 Receive {
575 var: Symbol,
576 pipe: &'a Expr<'a>,
577 body: Block<'a>,
578 },
579 /// Timeout: `After N seconds:` or `After N milliseconds:`
580 Timeout {
581 milliseconds: &'a Expr<'a>,
582 body: Block<'a>,
583 },
584}
585
586/// Shared expression type for pure computations (LOGOS §15.0.0).
587///
588/// Expr is used by both LogicExpr (as terms) and Stmt (as values).
589/// These are pure computations without side effects.
590#[derive(Debug)]
591pub enum Expr<'a> {
592 /// Literal value: 42, "hello", true, nothing
593 Literal(Literal),
594
595 /// Variable reference: x
596 Identifier(Symbol),
597
598 /// Binary operation: x plus y
599 BinaryOp {
600 op: BinaryOpKind,
601 left: &'a Expr<'a>,
602 right: &'a Expr<'a>,
603 },
604
605 /// Function call as expression: f(x, y)
606 Call {
607 function: Symbol,
608 args: Vec<&'a Expr<'a>>,
609 },
610
611 /// Dynamic index access: `items at i` (1-indexed).
612 Index {
613 collection: &'a Expr<'a>,
614 index: &'a Expr<'a>,
615 },
616
617 /// Dynamic slice access: `items 1 through mid` (1-indexed, inclusive).
618 Slice {
619 collection: &'a Expr<'a>,
620 start: &'a Expr<'a>,
621 end: &'a Expr<'a>,
622 },
623
624 /// Copy expression: `copy of slice` → slice.to_vec().
625 Copy {
626 expr: &'a Expr<'a>,
627 },
628
629 /// Give expression: `Give x` → transfers ownership, no clone needed.
630 /// Used in function calls to explicitly move values.
631 Give {
632 value: &'a Expr<'a>,
633 },
634
635 /// Length expression: `length of items` → items.len().
636 Length {
637 collection: &'a Expr<'a>,
638 },
639
640 /// Set contains: `set contains x` or `x in set`
641 Contains {
642 collection: &'a Expr<'a>,
643 value: &'a Expr<'a>,
644 },
645
646 /// Set union: `a union b`
647 Union {
648 left: &'a Expr<'a>,
649 right: &'a Expr<'a>,
650 },
651
652 /// Set intersection: `a intersection b`
653 Intersection {
654 left: &'a Expr<'a>,
655 right: &'a Expr<'a>,
656 },
657
658 /// Get manifest of a zone.
659 /// `the manifest of Zone` → FileSipper::from_zone(&zone).manifest()
660 ManifestOf {
661 zone: &'a Expr<'a>,
662 },
663
664 /// Get chunk at index from a zone.
665 /// `the chunk at N in Zone` → FileSipper::from_zone(&zone).get_chunk(N)
666 ChunkAt {
667 index: &'a Expr<'a>,
668 zone: &'a Expr<'a>,
669 },
670
671 /// List literal: [1, 2, 3]
672 List(Vec<&'a Expr<'a>>),
673
674 /// Tuple literal: (1, "hello", true)
675 Tuple(Vec<&'a Expr<'a>>),
676
677 /// Range: 1 to 10 (inclusive)
678 Range {
679 start: &'a Expr<'a>,
680 end: &'a Expr<'a>,
681 },
682
683 /// Field access: `p's x` or `the x of p`.
684 FieldAccess {
685 object: &'a Expr<'a>,
686 field: Symbol,
687 },
688
689 /// Constructor: `a new Point` or `a new Point with x 10 and y 20`.
690 /// Supports generics: `a new Box of Int` and nested types: `a new Seq of (Seq of Int)`
691 New {
692 type_name: Symbol,
693 type_args: Vec<TypeExpr<'a>>, // Empty for non-generic types - now supports nested types
694 init_fields: Vec<(Symbol, &'a Expr<'a>)>, // Optional field initialization
695 },
696
697 /// Enum variant constructor: `a new Circle with radius 10`.
698 NewVariant {
699 enum_name: Symbol, // Shape (resolved from registry)
700 variant: Symbol, // Circle
701 fields: Vec<(Symbol, &'a Expr<'a>)>, // [(radius, 10)]
702 },
703
704 /// Escape hatch expression: raw foreign code that produces a value.
705 /// Used in expression position: `Let x: Int be Escape to Rust:`
706 Escape {
707 language: Symbol,
708 code: Symbol,
709 },
710
711 /// Option Some: `some 30` → Some(30)
712 OptionSome {
713 value: &'a Expr<'a>,
714 },
715
716 /// Option None: `none` → None
717 OptionNone,
718
719 /// Pre-allocation capacity hint wrapping an inner value expression.
720 /// `"" with capacity 100` or `a new Seq of Int with capacity n`
721 /// Codegen uses with_capacity(); interpreter ignores the hint.
722 WithCapacity {
723 value: &'a Expr<'a>,
724 capacity: &'a Expr<'a>,
725 },
726
727 /// Closure expression: `(params) -> body` or `(params) ->:` block body.
728 /// Captures variables from the enclosing scope by value (snapshot/clone).
729 Closure {
730 params: Vec<(Symbol, &'a TypeExpr<'a>)>,
731 body: ClosureBody<'a>,
732 return_type: Option<&'a TypeExpr<'a>>,
733 },
734
735 /// Call an expression that evaluates to a callable value.
736 /// `f(x)` where `f` is a variable holding a closure, not a named function.
737 CallExpr {
738 callee: &'a Expr<'a>,
739 args: Vec<&'a Expr<'a>>,
740 },
741}
742
743/// Body of a closure expression.
744#[derive(Debug, Clone)]
745pub enum ClosureBody<'a> {
746 /// Single expression: `(n: Int) -> n * 2`
747 Expression(&'a Expr<'a>),
748 /// Block of statements: `(n: Int) ->:` followed by indented body
749 Block(Block<'a>),
750}
751
752/// Literal values in LOGOS.
753#[derive(Debug, Clone, PartialEq)]
754pub enum Literal {
755 /// Integer literal
756 Number(i64),
757 /// Float literal
758 Float(f64),
759 /// Text literal
760 Text(Symbol),
761 /// Boolean literal
762 Boolean(bool),
763 /// The nothing literal (unit type)
764 Nothing,
765 /// Character literal
766 Char(char),
767 /// Duration literal (nanoseconds, signed for negative offsets like "5 minutes early")
768 Duration(i64),
769 /// Date literal (days since Unix epoch 1970-01-01)
770 Date(i32),
771 /// Moment literal (nanoseconds since Unix epoch)
772 Moment(i64),
773 /// Calendar span (months, days) - NOT flattened to seconds
774 /// Months and days are kept separate because they're incommensurable.
775 Span { months: i32, days: i32 },
776 /// Time-of-day literal (nanoseconds from midnight)
777 /// Range: 0 to 86_399_999_999_999 (just under 24 hours)
778 Time(i64),
779}