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/// Binary operation kinds for imperative expressions.
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum BinaryOpKind {
72 Add,
73 Subtract,
74 Multiply,
75 Divide,
76 Modulo,
77 Eq,
78 NotEq,
79 Lt,
80 Gt,
81 LtEq,
82 GtEq,
83 // Logical operators for compound conditions
84 And,
85 Or,
86 /// String concatenation ("X combined with Y")
87 Concat,
88}
89
90/// Block is a sequence of statements.
91pub type Block<'a> = &'a [Stmt<'a>];
92
93/// Match arm for pattern matching in Inspect statements.
94#[derive(Debug)]
95pub struct MatchArm<'a> {
96 pub enum_name: Option<Symbol>, // The enum type (e.g., Shape)
97 pub variant: Option<Symbol>, // None = Otherwise (wildcard)
98 pub bindings: Vec<(Symbol, Symbol)>, // (field_name, binding_name)
99 pub body: Block<'a>,
100}
101
102/// Imperative statement AST (LOGOS §15.0.0).
103///
104/// Stmt is the primary AST node for imperative code blocks like `## Main`
105/// and function bodies. The Assert variant bridges to the Logic Kernel.
106#[derive(Debug)]
107pub enum Stmt<'a> {
108 /// Variable binding: `Let x be 5.` or `Let x: Int be 5.`
109 Let {
110 var: Symbol,
111 ty: Option<&'a TypeExpr<'a>>,
112 value: &'a Expr<'a>,
113 mutable: bool,
114 },
115
116 /// Mutation: `Set x to 10.`
117 Set {
118 target: Symbol,
119 value: &'a Expr<'a>,
120 },
121
122 /// Function call as statement: `Call process with data.`
123 Call {
124 function: Symbol,
125 args: Vec<&'a Expr<'a>>,
126 },
127
128 /// Conditional: `If condition: ... Otherwise: ...`
129 If {
130 cond: &'a Expr<'a>,
131 then_block: Block<'a>,
132 else_block: Option<Block<'a>>,
133 },
134
135 /// Loop: `While condition: ...` or `While condition (decreasing expr): ...`
136 While {
137 cond: &'a Expr<'a>,
138 body: Block<'a>,
139 /// Optional decreasing variant for termination proof.
140 decreasing: Option<&'a Expr<'a>>,
141 },
142
143 /// Iteration: `Repeat for x in list: ...` or `Repeat for i from 1 to 10: ...`
144 Repeat {
145 var: Symbol,
146 iterable: &'a Expr<'a>,
147 body: Block<'a>,
148 },
149
150 /// Return: `Return x.` or `Return.`
151 Return {
152 value: Option<&'a Expr<'a>>,
153 },
154
155 /// Bridge to Logic Kernel: `Assert that P.`
156 Assert {
157 proposition: &'a LogicExpr<'a>,
158 },
159
160 /// Documented assertion with justification.
161 /// `Trust that P because "reason".`
162 /// Semantics: Documented runtime check that could be verified statically.
163 Trust {
164 proposition: &'a LogicExpr<'a>,
165 justification: Symbol,
166 },
167
168 /// Runtime assertion with imperative condition
169 /// `Assert that condition.` (for imperative mode)
170 RuntimeAssert {
171 condition: &'a Expr<'a>,
172 },
173
174 /// Ownership transfer (move): `Give x to processor.`
175 /// Semantics: Move ownership of `object` to `recipient`.
176 Give {
177 object: &'a Expr<'a>,
178 recipient: &'a Expr<'a>,
179 },
180
181 /// Immutable borrow: `Show x to console.`
182 /// Semantics: Immutable borrow of `object` passed to `recipient`.
183 Show {
184 object: &'a Expr<'a>,
185 recipient: &'a Expr<'a>,
186 },
187
188 /// Field mutation: `Set p's x to 10.`
189 SetField {
190 object: &'a Expr<'a>,
191 field: Symbol,
192 value: &'a Expr<'a>,
193 },
194
195 /// Struct definition for codegen.
196 StructDef {
197 name: Symbol,
198 fields: Vec<(Symbol, Symbol, bool)>, // (name, type_name, is_public)
199 is_portable: bool, // Derives Serialize/Deserialize
200 },
201
202 /// Function definition.
203 FunctionDef {
204 name: Symbol,
205 params: Vec<(Symbol, &'a TypeExpr<'a>)>,
206 body: Block<'a>,
207 return_type: Option<&'a TypeExpr<'a>>,
208 is_native: bool,
209 },
210
211 /// Pattern matching on sum types.
212 Inspect {
213 target: &'a Expr<'a>,
214 arms: Vec<MatchArm<'a>>,
215 has_otherwise: bool, // For exhaustiveness tracking
216 },
217
218 /// Push to collection: `Push x to items.`
219 Push {
220 value: &'a Expr<'a>,
221 collection: &'a Expr<'a>,
222 },
223
224 /// Pop from collection: `Pop from items.` or `Pop from items into y.`
225 Pop {
226 collection: &'a Expr<'a>,
227 into: Option<Symbol>,
228 },
229
230 /// Add to set: `Add x to set.`
231 Add {
232 value: &'a Expr<'a>,
233 collection: &'a Expr<'a>,
234 },
235
236 /// Remove from set: `Remove x from set.`
237 Remove {
238 value: &'a Expr<'a>,
239 collection: &'a Expr<'a>,
240 },
241
242 /// Index assignment: `Set item N of X to Y.`
243 SetIndex {
244 collection: &'a Expr<'a>,
245 index: &'a Expr<'a>,
246 value: &'a Expr<'a>,
247 },
248
249 /// Memory arena block (Zone).
250 /// "Inside a new zone called 'Scratch':"
251 /// "Inside a zone called 'Buffer' of size 1 MB:"
252 /// "Inside a zone called 'Data' mapped from 'file.bin':"
253 Zone {
254 /// The variable name for the arena handle (e.g., "Scratch")
255 name: Symbol,
256 /// Optional pre-allocated capacity in bytes (Heap zones only)
257 capacity: Option<usize>,
258 /// Optional file path for memory-mapped zones (Mapped zones only)
259 source_file: Option<Symbol>,
260 /// The code block executed within this memory context
261 body: Block<'a>,
262 },
263
264 /// Concurrent execution block (async, I/O-bound).
265 /// "Attempt all of the following:"
266 /// Semantics: All tasks run concurrently via tokio::join!
267 /// Best for: network requests, file I/O, waiting operations
268 Concurrent {
269 /// The statements to execute concurrently
270 tasks: Block<'a>,
271 },
272
273 /// Parallel execution block (CPU-bound).
274 /// "Simultaneously:"
275 /// Semantics: True parallelism via rayon::join or thread::spawn
276 /// Best for: computation, data processing, number crunching
277 Parallel {
278 /// The statements to execute in parallel
279 tasks: Block<'a>,
280 },
281
282 /// Read from console or file.
283 /// `Read input from the console.` or `Read data from file "path.txt".`
284 ReadFrom {
285 var: Symbol,
286 source: ReadSource<'a>,
287 },
288
289 /// Write to file.
290 /// `Write "content" to file "output.txt".`
291 WriteFile {
292 content: &'a Expr<'a>,
293 path: &'a Expr<'a>,
294 },
295
296 /// Spawn an agent.
297 /// `Spawn a Worker called "w1".`
298 Spawn {
299 agent_type: Symbol,
300 name: Symbol,
301 },
302
303 /// Send message to agent.
304 /// `Send Ping to "agent".`
305 SendMessage {
306 message: &'a Expr<'a>,
307 destination: &'a Expr<'a>,
308 },
309
310 /// Await response from agent.
311 /// `Await response from "agent" into result.`
312 AwaitMessage {
313 source: &'a Expr<'a>,
314 into: Symbol,
315 },
316
317 /// Merge CRDT state.
318 /// `Merge remote into local.` or `Merge remote's field into local's field.`
319 MergeCrdt {
320 source: &'a Expr<'a>,
321 target: &'a Expr<'a>,
322 },
323
324 /// Increment GCounter.
325 /// `Increase local's points by 10.`
326 IncreaseCrdt {
327 object: &'a Expr<'a>,
328 field: Symbol,
329 amount: &'a Expr<'a>,
330 },
331
332 /// Decrement PNCounter (Tally).
333 /// `Decrease game's score by 5.`
334 DecreaseCrdt {
335 object: &'a Expr<'a>,
336 field: Symbol,
337 amount: &'a Expr<'a>,
338 },
339
340 /// Append to SharedSequence (RGA).
341 /// `Append "Hello" to doc's lines.`
342 AppendToSequence {
343 sequence: &'a Expr<'a>,
344 value: &'a Expr<'a>,
345 },
346
347 /// Resolve MVRegister conflicts.
348 /// `Resolve page's title to "Final".`
349 ResolveConflict {
350 object: &'a Expr<'a>,
351 field: Symbol,
352 value: &'a Expr<'a>,
353 },
354
355 /// Security check - mandatory runtime guard.
356 /// `Check that user is admin.`
357 /// `Check that user can publish the document.`
358 /// Semantics: NEVER optimized out. Panics if condition is false.
359 Check {
360 /// The subject being checked (e.g., "user")
361 subject: Symbol,
362 /// The predicate name (e.g., "admin") or action (e.g., "publish")
363 predicate: Symbol,
364 /// True if this is a capability check (`can [action]`)
365 is_capability: bool,
366 /// For capabilities: the object being acted on (e.g., "document")
367 object: Option<Symbol>,
368 /// Original English text for error message
369 source_text: String,
370 /// Source location for error reporting
371 span: crate::token::Span,
372 },
373
374 /// Listen on network address.
375 /// `Listen on "/ip4/127.0.0.1/tcp/8000".`
376 /// Semantics: Bind to address, start accepting connections via libp2p
377 Listen {
378 address: &'a Expr<'a>,
379 },
380
381 /// Connect to remote peer.
382 /// `Connect to "/ip4/127.0.0.1/tcp/8000".`
383 /// Semantics: Dial peer via libp2p
384 ConnectTo {
385 address: &'a Expr<'a>,
386 },
387
388 /// Create PeerAgent remote handle.
389 /// `Let remote be a PeerAgent at "/ip4/127.0.0.1/tcp/8000".`
390 /// Semantics: Create handle for remote agent communication
391 LetPeerAgent {
392 var: Symbol,
393 address: &'a Expr<'a>,
394 },
395
396 /// Sleep for milliseconds.
397 /// `Sleep 1000.` or `Sleep delay.`
398 /// Semantics: Pause execution for N milliseconds (async)
399 Sleep {
400 milliseconds: &'a Expr<'a>,
401 },
402
403 /// Sync CRDT variable on topic.
404 /// `Sync x on "topic".`
405 /// Semantics: Subscribe to GossipSub topic, auto-publish on mutation, auto-merge on receive
406 Sync {
407 var: Symbol,
408 topic: &'a Expr<'a>,
409 },
410
411 /// Mount persistent CRDT from journal file.
412 /// `Mount counter at "data/counter.journal".`
413 /// Semantics: Load or create journal, replay operations to reconstruct state
414 Mount {
415 /// The variable name for the mounted value
416 var: Symbol,
417 /// The path expression for the journal file
418 path: &'a Expr<'a>,
419 },
420
421 // =========================================================================
422 // Go-like Concurrency (Green Threads, Channels, Select)
423 // =========================================================================
424
425 /// Launch a fire-and-forget task (green thread).
426 /// `Launch a task to process(data).`
427 /// Semantics: tokio::spawn with no handle capture
428 LaunchTask {
429 /// The function to call
430 function: Symbol,
431 /// Arguments to pass
432 args: Vec<&'a Expr<'a>>,
433 },
434
435 /// Launch a task with handle for control.
436 /// `Let worker be Launch a task to process(data).`
437 /// Semantics: tokio::spawn returning JoinHandle
438 LaunchTaskWithHandle {
439 /// Variable to bind the handle
440 handle: Symbol,
441 /// The function to call
442 function: Symbol,
443 /// Arguments to pass
444 args: Vec<&'a Expr<'a>>,
445 },
446
447 /// Create a bounded channel (pipe).
448 /// `Let jobs be a new Pipe of Int.`
449 /// Semantics: tokio::sync::mpsc::channel(32)
450 CreatePipe {
451 /// Variable for the pipe
452 var: Symbol,
453 /// Type of values in the pipe
454 element_type: Symbol,
455 /// Optional capacity (defaults to 32)
456 capacity: Option<u32>,
457 },
458
459 /// Blocking send into pipe.
460 /// `Send value into pipe.`
461 /// Semantics: pipe_tx.send(value).await
462 SendPipe {
463 /// The value to send
464 value: &'a Expr<'a>,
465 /// The pipe to send into
466 pipe: &'a Expr<'a>,
467 },
468
469 /// Blocking receive from pipe.
470 /// `Receive x from pipe.`
471 /// Semantics: let x = pipe_rx.recv().await
472 ReceivePipe {
473 /// Variable to bind the received value
474 var: Symbol,
475 /// The pipe to receive from
476 pipe: &'a Expr<'a>,
477 },
478
479 /// Non-blocking send (try).
480 /// `Try to send value into pipe.`
481 /// Semantics: pipe_tx.try_send(value) - returns immediately
482 TrySendPipe {
483 /// The value to send
484 value: &'a Expr<'a>,
485 /// The pipe to send into
486 pipe: &'a Expr<'a>,
487 /// Variable to bind the result (true/false)
488 result: Option<Symbol>,
489 },
490
491 /// Non-blocking receive (try).
492 /// `Try to receive x from pipe.`
493 /// Semantics: pipe_rx.try_recv() - returns Option
494 TryReceivePipe {
495 /// Variable to bind the received value (if any)
496 var: Symbol,
497 /// The pipe to receive from
498 pipe: &'a Expr<'a>,
499 },
500
501 /// Cancel a spawned task.
502 /// `Stop worker.`
503 /// Semantics: handle.abort()
504 StopTask {
505 /// The handle to cancel
506 handle: &'a Expr<'a>,
507 },
508
509 /// Select on multiple channels/timeouts.
510 /// `Await the first of:`
511 /// `Receive x from ch:`
512 /// `...`
513 /// `After 5 seconds:`
514 /// `...`
515 /// Semantics: tokio::select! with auto-cancel
516 Select {
517 /// The branches to select from
518 branches: Vec<SelectBranch<'a>>,
519 },
520
521 /// Theorem block.
522 /// `## Theorem: Name`
523 /// `Given: Premise.`
524 /// `Prove: Goal.`
525 /// `Proof: Auto.`
526 Theorem(TheoremBlock<'a>),
527}
528
529/// A branch in a Select statement.
530#[derive(Debug)]
531pub enum SelectBranch<'a> {
532 /// Receive from a pipe: `Receive x from ch:`
533 Receive {
534 var: Symbol,
535 pipe: &'a Expr<'a>,
536 body: Block<'a>,
537 },
538 /// Timeout: `After N seconds:` or `After N milliseconds:`
539 Timeout {
540 milliseconds: &'a Expr<'a>,
541 body: Block<'a>,
542 },
543}
544
545/// Shared expression type for pure computations (LOGOS §15.0.0).
546///
547/// Expr is used by both LogicExpr (as terms) and Stmt (as values).
548/// These are pure computations without side effects.
549#[derive(Debug)]
550pub enum Expr<'a> {
551 /// Literal value: 42, "hello", true, nothing
552 Literal(Literal),
553
554 /// Variable reference: x
555 Identifier(Symbol),
556
557 /// Binary operation: x plus y
558 BinaryOp {
559 op: BinaryOpKind,
560 left: &'a Expr<'a>,
561 right: &'a Expr<'a>,
562 },
563
564 /// Function call as expression: f(x, y)
565 Call {
566 function: Symbol,
567 args: Vec<&'a Expr<'a>>,
568 },
569
570 /// Dynamic index access: `items at i` (1-indexed).
571 Index {
572 collection: &'a Expr<'a>,
573 index: &'a Expr<'a>,
574 },
575
576 /// Dynamic slice access: `items 1 through mid` (1-indexed, inclusive).
577 Slice {
578 collection: &'a Expr<'a>,
579 start: &'a Expr<'a>,
580 end: &'a Expr<'a>,
581 },
582
583 /// Copy expression: `copy of slice` → slice.to_vec().
584 Copy {
585 expr: &'a Expr<'a>,
586 },
587
588 /// Length expression: `length of items` → items.len().
589 Length {
590 collection: &'a Expr<'a>,
591 },
592
593 /// Set contains: `set contains x` or `x in set`
594 Contains {
595 collection: &'a Expr<'a>,
596 value: &'a Expr<'a>,
597 },
598
599 /// Set union: `a union b`
600 Union {
601 left: &'a Expr<'a>,
602 right: &'a Expr<'a>,
603 },
604
605 /// Set intersection: `a intersection b`
606 Intersection {
607 left: &'a Expr<'a>,
608 right: &'a Expr<'a>,
609 },
610
611 /// Get manifest of a zone.
612 /// `the manifest of Zone` → FileSipper::from_zone(&zone).manifest()
613 ManifestOf {
614 zone: &'a Expr<'a>,
615 },
616
617 /// Get chunk at index from a zone.
618 /// `the chunk at N in Zone` → FileSipper::from_zone(&zone).get_chunk(N)
619 ChunkAt {
620 index: &'a Expr<'a>,
621 zone: &'a Expr<'a>,
622 },
623
624 /// List literal: [1, 2, 3]
625 List(Vec<&'a Expr<'a>>),
626
627 /// Tuple literal: (1, "hello", true)
628 Tuple(Vec<&'a Expr<'a>>),
629
630 /// Range: 1 to 10 (inclusive)
631 Range {
632 start: &'a Expr<'a>,
633 end: &'a Expr<'a>,
634 },
635
636 /// Field access: `p's x` or `the x of p`.
637 FieldAccess {
638 object: &'a Expr<'a>,
639 field: Symbol,
640 },
641
642 /// Constructor: `a new Point` or `a new Point with x 10 and y 20`.
643 /// Supports generics: `a new Box of Int`
644 New {
645 type_name: Symbol,
646 type_args: Vec<Symbol>, // Empty for non-generic types
647 init_fields: Vec<(Symbol, &'a Expr<'a>)>, // Optional field initialization
648 },
649
650 /// Enum variant constructor: `a new Circle with radius 10`.
651 NewVariant {
652 enum_name: Symbol, // Shape (resolved from registry)
653 variant: Symbol, // Circle
654 fields: Vec<(Symbol, &'a Expr<'a>)>, // [(radius, 10)]
655 },
656}
657
658/// Literal values in LOGOS.
659#[derive(Debug, Clone, PartialEq)]
660pub enum Literal {
661 /// Integer literal
662 Number(i64),
663 /// Float literal
664 Float(f64),
665 /// Text literal
666 Text(Symbol),
667 /// Boolean literal
668 Boolean(bool),
669 /// The nothing literal (unit type)
670 Nothing,
671 /// Character literal
672 Char(char),
673}