Skip to main content

sage_parser/
ast.rs

1//! Abstract Syntax Tree definitions for the Sage language.
2//!
3//! This module defines all AST node types that the parser produces.
4//! Every node carries a `Span` for error reporting.
5
6use crate::{Ident, Span, TypeExpr};
7use std::fmt;
8
9// =============================================================================
10// Program (top-level)
11// =============================================================================
12
13/// A complete Sage program (or module).
14#[derive(Debug, Clone, PartialEq)]
15pub struct Program {
16    /// Module declarations (`mod foo`).
17    pub mod_decls: Vec<ModDecl>,
18    /// Use declarations (`use foo::Bar`).
19    pub use_decls: Vec<UseDecl>,
20    /// Record type declarations.
21    pub records: Vec<RecordDecl>,
22    /// Enum type declarations.
23    pub enums: Vec<EnumDecl>,
24    /// Constant declarations.
25    pub consts: Vec<ConstDecl>,
26    /// Tool declarations (RFC-0011).
27    pub tools: Vec<ToolDecl>,
28    /// Protocol declarations (Phase 3 session types).
29    pub protocols: Vec<ProtocolDecl>,
30    /// Effect handler declarations (Phase 3 algebraic effects).
31    pub effect_handlers: Vec<EffectHandlerDecl>,
32    /// Agent declarations.
33    pub agents: Vec<AgentDecl>,
34    /// Supervisor declarations (v2 supervision trees).
35    pub supervisors: Vec<SupervisorDecl>,
36    /// Function declarations.
37    pub functions: Vec<FnDecl>,
38    /// Extern function declarations (Rust FFI).
39    pub extern_fns: Vec<ExternFnDecl>,
40    /// Test declarations (RFC-0012). Only valid in `_test.sg` files.
41    pub tests: Vec<TestDecl>,
42    /// The entry-point agent or supervisor (from `run Name`).
43    /// None for library modules that don't have an entry point.
44    pub run_agent: Option<Ident>,
45    /// Span covering the entire program.
46    pub span: Span,
47}
48
49// =============================================================================
50// Module declarations
51// =============================================================================
52
53/// A module declaration: `mod name` or `pub mod name`
54#[derive(Debug, Clone, PartialEq)]
55pub struct ModDecl {
56    /// Whether this module is public.
57    pub is_pub: bool,
58    /// The module name.
59    pub name: Ident,
60    /// Span covering the declaration.
61    pub span: Span,
62}
63
64/// A use declaration: `use path::to::Item`
65#[derive(Debug, Clone, PartialEq)]
66pub struct UseDecl {
67    /// Whether this is a public re-export (`pub use`).
68    pub is_pub: bool,
69    /// The path segments (e.g., `["agents", "Researcher"]`).
70    pub path: Vec<Ident>,
71    /// The kind of import.
72    pub kind: UseKind,
73    /// Span covering the declaration.
74    pub span: Span,
75}
76
77/// The kind of use declaration.
78#[derive(Debug, Clone, PartialEq)]
79pub enum UseKind {
80    /// Simple import: `use a::B` or `use a::B as C`
81    /// The Option is the alias (e.g., `C` in `use a::B as C`).
82    Simple(Option<Ident>),
83    /// Glob import: `use a::*`
84    Glob,
85    /// Group import: `use a::{B, C as D}`
86    /// Each tuple is (name, optional alias).
87    Group(Vec<(Ident, Option<Ident>)>),
88}
89
90// =============================================================================
91// Type declarations (records, enums)
92// =============================================================================
93
94/// A record declaration: `record Point { x: Int, y: Int }` or `record Pair<A, B> { first: A, second: B }`
95#[derive(Debug, Clone, PartialEq)]
96pub struct RecordDecl {
97    /// Whether this record is public.
98    pub is_pub: bool,
99    /// The record's name.
100    pub name: Ident,
101    /// Type parameters for generic records (e.g., `<A, B>` in `Pair<A, B>`).
102    pub type_params: Vec<Ident>,
103    /// The record's fields.
104    pub fields: Vec<RecordField>,
105    /// Span covering the declaration.
106    pub span: Span,
107}
108
109/// A field in a record declaration: `name: Type`
110#[derive(Debug, Clone, PartialEq)]
111pub struct RecordField {
112    /// The field's name.
113    pub name: Ident,
114    /// The field's type.
115    pub ty: TypeExpr,
116    /// Span covering the field.
117    pub span: Span,
118}
119
120/// An enum variant with optional payload: `Ok(T)` or `None`
121#[derive(Debug, Clone, PartialEq)]
122pub struct EnumVariant {
123    /// The variant's name.
124    pub name: Ident,
125    /// Optional payload type (e.g., `T` in `Ok(T)`).
126    pub payload: Option<TypeExpr>,
127    /// Span covering the variant.
128    pub span: Span,
129}
130
131/// An enum declaration: `enum Status { Active, Pending, Done }` or `enum Tree<T> { Leaf(T), Node(Tree<T>, Tree<T>) }`
132#[derive(Debug, Clone, PartialEq)]
133pub struct EnumDecl {
134    /// Whether this enum is public.
135    pub is_pub: bool,
136    /// The enum's name.
137    pub name: Ident,
138    /// Type parameters for generic enums (e.g., `<T>` in `Tree<T>`).
139    pub type_params: Vec<Ident>,
140    /// The enum's variants.
141    pub variants: Vec<EnumVariant>,
142    /// Span covering the declaration.
143    pub span: Span,
144}
145
146/// A const declaration: `const MAX_RETRIES: Int = 3`
147#[derive(Debug, Clone, PartialEq)]
148pub struct ConstDecl {
149    /// Whether this const is public.
150    pub is_pub: bool,
151    /// The constant's name.
152    pub name: Ident,
153    /// The constant's type.
154    pub ty: TypeExpr,
155    /// The constant's value.
156    pub value: Expr,
157    /// Span covering the declaration.
158    pub span: Span,
159}
160
161// =============================================================================
162// Tool declarations (RFC-0011)
163// =============================================================================
164
165/// A tool declaration: `tool Http { fn get(url: String) -> Result<String, String> }`
166#[derive(Debug, Clone, PartialEq)]
167pub struct ToolDecl {
168    /// Whether this tool is public.
169    pub is_pub: bool,
170    /// The tool's name.
171    pub name: Ident,
172    /// The tool's function signatures.
173    pub functions: Vec<ToolFnDecl>,
174    /// Span covering the declaration.
175    pub span: Span,
176}
177
178/// A function signature in a tool declaration (no body).
179#[derive(Debug, Clone, PartialEq)]
180pub struct ToolFnDecl {
181    /// The function's name.
182    pub name: Ident,
183    /// The function's parameters.
184    pub params: Vec<Param>,
185    /// The return type.
186    pub return_ty: TypeExpr,
187    /// Span covering the declaration.
188    pub span: Span,
189}
190
191// =============================================================================
192// Agent declarations
193// =============================================================================
194
195/// An agent declaration: `agent Name { ... }` or `pub agent Name receives MsgType { ... }`
196#[derive(Debug, Clone, PartialEq)]
197pub struct AgentDecl {
198    /// Whether this agent is public (can be imported by other modules).
199    pub is_pub: bool,
200    /// The agent's name.
201    pub name: Ident,
202    /// The message type this agent receives (for message passing).
203    pub receives: Option<TypeExpr>,
204    /// Protocol roles this agent follows (Phase 3): `follows Protocol as Role`
205    pub follows: Vec<ProtocolRole>,
206    /// Tools this agent uses (RFC-0011): `use Http, Fs`
207    pub tool_uses: Vec<Ident>,
208    /// Belief declarations (agent state).
209    pub beliefs: Vec<BeliefDecl>,
210    /// Event handlers.
211    pub handlers: Vec<HandlerDecl>,
212    /// Span covering the entire declaration.
213    pub span: Span,
214}
215
216/// A belief declaration: `name: Type` or `@persistent name: Type`
217#[derive(Debug, Clone, PartialEq)]
218pub struct BeliefDecl {
219    /// Whether this field is persistent (checkpointed across restarts).
220    pub is_persistent: bool,
221    /// The belief's name.
222    pub name: Ident,
223    /// The belief's type.
224    pub ty: TypeExpr,
225    /// Span covering the declaration.
226    pub span: Span,
227}
228
229/// An event handler: `on start { ... }`, `on message(x: T) { ... }`, `on stop { ... }`
230#[derive(Debug, Clone, PartialEq)]
231pub struct HandlerDecl {
232    /// The event kind this handler responds to.
233    pub event: EventKind,
234    /// The handler body.
235    pub body: Block,
236    /// Span covering the entire handler.
237    pub span: Span,
238}
239
240/// The kind of event a handler responds to.
241#[derive(Debug, Clone, PartialEq)]
242pub enum EventKind {
243    /// `on waking` — runs before start, after persistent state loaded (v2 lifecycle).
244    Waking,
245    /// `on start` — runs when the agent is spawned.
246    Start,
247    /// `on message(param: Type)` — runs when a message is received.
248    Message {
249        /// The parameter name for the incoming message.
250        param_name: Ident,
251        /// The type of the message.
252        param_ty: TypeExpr,
253    },
254    /// `on pause` — runs when supervisor signals graceful pause (v2 lifecycle).
255    Pause,
256    /// `on resume` — runs when agent is unpaused (v2 lifecycle).
257    Resume,
258    /// `on stop` — runs during graceful shutdown.
259    Stop,
260    /// `on resting` — alias for stop (v2 terminology).
261    Resting,
262    /// `on error(e)` — runs when an unhandled error occurs in the agent.
263    Error {
264        /// The parameter name for the error.
265        param_name: Ident,
266    },
267}
268
269impl fmt::Display for EventKind {
270    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271        match self {
272            EventKind::Waking => write!(f, "waking"),
273            EventKind::Start => write!(f, "start"),
274            EventKind::Message {
275                param_name,
276                param_ty,
277            } => {
278                write!(f, "message({param_name}: {param_ty})")
279            }
280            EventKind::Pause => write!(f, "pause"),
281            EventKind::Resume => write!(f, "resume"),
282            EventKind::Stop => write!(f, "stop"),
283            EventKind::Resting => write!(f, "resting"),
284            EventKind::Error { param_name } => {
285                write!(f, "error({param_name})")
286            }
287        }
288    }
289}
290
291// =============================================================================
292// Function declarations
293// =============================================================================
294
295/// A function declaration: `fn name(params) -> ReturnType { ... }` or `fn map<T, U>(list: List<T>, f: Fn(T) -> U) -> List<U> { ... }`
296#[derive(Debug, Clone, PartialEq)]
297pub struct FnDecl {
298    /// Whether this function is public (can be imported by other modules).
299    pub is_pub: bool,
300    /// The function's name.
301    pub name: Ident,
302    /// Type parameters for generic functions (e.g., `<T, U>` in `map<T, U>`).
303    pub type_params: Vec<Ident>,
304    /// The function's parameters.
305    pub params: Vec<Param>,
306    /// The return type.
307    pub return_ty: TypeExpr,
308    /// Whether this function can fail (marked with `fails`).
309    pub is_fallible: bool,
310    /// The function body.
311    pub body: Block,
312    /// Span covering the entire declaration.
313    pub span: Span,
314}
315
316/// An extern function declaration: `extern fn name(params) -> Type`
317/// The implementation is provided by external Rust code.
318#[derive(Debug, Clone, PartialEq)]
319pub struct ExternFnDecl {
320    /// The function's name.
321    pub name: Ident,
322    /// The function's parameters.
323    pub params: Vec<Param>,
324    /// The return type.
325    pub return_ty: TypeExpr,
326    /// Whether this function can fail (marked with `fails`).
327    pub is_fallible: bool,
328    /// Span covering the entire declaration.
329    pub span: Span,
330}
331
332/// A function parameter: `name: Type`
333#[derive(Debug, Clone, PartialEq)]
334pub struct Param {
335    /// The parameter name.
336    pub name: Ident,
337    /// The parameter type.
338    pub ty: TypeExpr,
339    /// Span covering the parameter.
340    pub span: Span,
341}
342
343/// A closure parameter: `name` or `name: Type`
344#[derive(Debug, Clone, PartialEq)]
345pub struct ClosureParam {
346    /// The parameter name.
347    pub name: Ident,
348    /// Optional type annotation (can be inferred).
349    pub ty: Option<TypeExpr>,
350    /// Span covering the parameter.
351    pub span: Span,
352}
353
354// =============================================================================
355// Test declarations (RFC-0012)
356// =============================================================================
357
358/// A test declaration: `test "description" { ... }` or `@serial test "description" { ... }`
359#[derive(Debug, Clone, PartialEq)]
360pub struct TestDecl {
361    /// The test description (the string after `test`).
362    pub name: String,
363    /// Whether this test must run serially (marked with `@serial`).
364    pub is_serial: bool,
365    /// The test body.
366    pub body: Block,
367    /// Span covering the entire declaration.
368    pub span: Span,
369}
370
371// =============================================================================
372// Supervision tree declarations (v2)
373// =============================================================================
374
375/// A supervisor declaration for OTP-style supervision trees.
376///
377/// Example:
378/// ```sage
379/// supervisor AppSupervisor {
380///     strategy: OneForOne
381///     children {
382///         DatabaseSteward { restart: Permanent, schema_version: 0 }
383///         APISteward { restart: Transient, routes_generated: false }
384///     }
385/// }
386/// ```
387#[derive(Debug, Clone, PartialEq)]
388pub struct SupervisorDecl {
389    /// Whether this supervisor is public.
390    pub is_pub: bool,
391    /// The supervisor's name.
392    pub name: Ident,
393    /// The supervision strategy.
394    pub strategy: SupervisionStrategy,
395    /// Child specifications.
396    pub children: Vec<ChildSpec>,
397    /// Span covering the declaration.
398    pub span: Span,
399}
400
401/// Supervision strategy (inspired by Erlang/OTP).
402#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
403pub enum SupervisionStrategy {
404    /// Restart only the failed child.
405    OneForOne,
406    /// Restart all children if one fails.
407    OneForAll,
408    /// Restart the failed child and all children started after it.
409    RestForOne,
410}
411
412impl fmt::Display for SupervisionStrategy {
413    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414        match self {
415            SupervisionStrategy::OneForOne => write!(f, "OneForOne"),
416            SupervisionStrategy::OneForAll => write!(f, "OneForAll"),
417            SupervisionStrategy::RestForOne => write!(f, "RestForOne"),
418        }
419    }
420}
421
422/// Restart policy for supervised children.
423#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
424pub enum RestartPolicy {
425    /// Always restart, regardless of exit reason.
426    #[default]
427    Permanent,
428    /// Restart only on abnormal termination (error).
429    Transient,
430    /// Never restart.
431    Temporary,
432}
433
434impl fmt::Display for RestartPolicy {
435    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436        match self {
437            RestartPolicy::Permanent => write!(f, "Permanent"),
438            RestartPolicy::Transient => write!(f, "Transient"),
439            RestartPolicy::Temporary => write!(f, "Temporary"),
440        }
441    }
442}
443
444/// A child specification within a supervisor.
445///
446/// Example:
447/// ```sage
448/// DatabaseSteward { restart: Permanent, schema_version: 0 }
449/// ```
450#[derive(Debug, Clone, PartialEq)]
451pub struct ChildSpec {
452    /// The agent type to spawn.
453    pub agent_name: Ident,
454    /// Restart policy for this child.
455    pub restart: RestartPolicy,
456    /// Initial belief values.
457    pub beliefs: Vec<FieldInit>,
458    /// Effect handler assignments (Phase 3): `handler Infer: FastLLM`
459    pub handler_assignments: Vec<HandlerAssignment>,
460    /// Span covering the child spec.
461    pub span: Span,
462}
463
464// =============================================================================
465// Protocol declarations (Phase 3 session types)
466// =============================================================================
467
468/// A protocol declaration for session types.
469///
470/// Example:
471/// ```sage
472/// protocol SchemaSync {
473///     DatabaseSteward -> APISteward: SchemaChanged
474///     APISteward -> DatabaseSteward: Acknowledged
475/// }
476/// ```
477#[derive(Debug, Clone, PartialEq)]
478pub struct ProtocolDecl {
479    /// Whether this protocol is public.
480    pub is_pub: bool,
481    /// The protocol's name.
482    pub name: Ident,
483    /// The protocol steps.
484    pub steps: Vec<ProtocolStep>,
485    /// Span covering the declaration.
486    pub span: Span,
487}
488
489/// A single step in a protocol: `Sender -> Receiver: MessageType`
490#[derive(Debug, Clone, PartialEq)]
491pub struct ProtocolStep {
492    /// The sender role.
493    pub sender: Ident,
494    /// The receiver role.
495    pub receiver: Ident,
496    /// The message type for this step.
497    pub message_type: TypeExpr,
498    /// Span covering the step.
499    pub span: Span,
500}
501
502/// A protocol role assignment: `follows ProtocolName as RoleName`
503#[derive(Debug, Clone, PartialEq)]
504pub struct ProtocolRole {
505    /// The protocol being followed.
506    pub protocol: Ident,
507    /// The role this agent plays in the protocol.
508    pub role: Ident,
509    /// Span covering the role assignment.
510    pub span: Span,
511}
512
513// =============================================================================
514// Effect handler declarations (Phase 3 algebraic effects)
515// =============================================================================
516
517/// An effect handler declaration for per-agent configuration.
518///
519/// Example:
520/// ```sage
521/// handler DefaultLLM handles Infer {
522///     model: "gpt-4o"
523///     temperature: 0.7
524///     max_tokens: 1024
525/// }
526/// ```
527#[derive(Debug, Clone, PartialEq)]
528pub struct EffectHandlerDecl {
529    /// Whether this handler is public.
530    pub is_pub: bool,
531    /// The handler's name.
532    pub name: Ident,
533    /// The effect being handled (e.g., "Infer").
534    pub effect: Ident,
535    /// Configuration key-value pairs.
536    pub config: Vec<HandlerConfig>,
537    /// Span covering the declaration.
538    pub span: Span,
539}
540
541/// A configuration entry in an effect handler.
542#[derive(Debug, Clone, PartialEq)]
543pub struct HandlerConfig {
544    /// The configuration key.
545    pub key: Ident,
546    /// The configuration value.
547    pub value: Literal,
548    /// Span covering the entry.
549    pub span: Span,
550}
551
552/// An effect handler assignment in a child spec: `handler Effect: HandlerName`
553#[derive(Debug, Clone, PartialEq)]
554pub struct HandlerAssignment {
555    /// The effect being assigned (e.g., "Infer").
556    pub effect: Ident,
557    /// The handler to use for this effect.
558    pub handler: Ident,
559    /// Span covering the assignment.
560    pub span: Span,
561}
562
563// =============================================================================
564// Blocks and statements
565// =============================================================================
566
567/// A block of statements: `{ stmt* }`
568#[derive(Debug, Clone, PartialEq)]
569pub struct Block {
570    /// The statements in this block.
571    pub stmts: Vec<Stmt>,
572    /// Span covering the entire block (including braces).
573    pub span: Span,
574}
575
576/// A statement.
577#[derive(Debug, Clone, PartialEq)]
578pub enum Stmt {
579    /// Variable binding: `let name: Type = expr` or `let name = expr`
580    Let {
581        /// The variable name.
582        name: Ident,
583        /// Optional type annotation.
584        ty: Option<TypeExpr>,
585        /// The initial value.
586        value: Expr,
587        /// Span covering the statement.
588        span: Span,
589    },
590
591    /// Assignment: `name = expr`
592    Assign {
593        /// The variable being assigned to.
594        name: Ident,
595        /// The new value.
596        value: Expr,
597        /// Span covering the statement.
598        span: Span,
599    },
600
601    /// Return statement: `return expr?`
602    Return {
603        /// The optional return value.
604        value: Option<Expr>,
605        /// Span covering the statement.
606        span: Span,
607    },
608
609    /// If statement: `if cond { ... } else { ... }`
610    If {
611        /// The condition (must be Bool).
612        condition: Expr,
613        /// The then branch.
614        then_block: Block,
615        /// The optional else branch (can be another If for else-if chains).
616        else_block: Option<ElseBranch>,
617        /// Span covering the statement.
618        span: Span,
619    },
620
621    /// For loop: `for x in iter { ... }` or `for (k, v) in map { ... }`
622    For {
623        /// The loop pattern (can be a simple binding or tuple destructuring).
624        pattern: Pattern,
625        /// The iterable expression (List<T> or Map<K, V>).
626        iter: Expr,
627        /// The loop body.
628        body: Block,
629        /// Span covering the statement.
630        span: Span,
631    },
632
633    /// While loop: `while cond { ... }`
634    While {
635        /// The condition (must be Bool).
636        condition: Expr,
637        /// The loop body.
638        body: Block,
639        /// Span covering the statement.
640        span: Span,
641    },
642
643    /// Infinite loop: `loop { ... }`
644    Loop {
645        /// The loop body.
646        body: Block,
647        /// Span covering the statement.
648        span: Span,
649    },
650
651    /// Break statement: `break`
652    Break {
653        /// Span covering the statement.
654        span: Span,
655    },
656
657    /// Span block: `span "name" { body }` for timed observability blocks.
658    /// Records start/end times and emits trace events.
659    SpanBlock {
660        /// The span name (should be a string literal or expression).
661        name: Expr,
662        /// The block body.
663        body: Block,
664        /// Span covering the statement.
665        span: Span,
666    },
667
668    /// Explicit checkpoint statement: `checkpoint();`
669    /// Forces an immediate checkpoint of all @persistent beliefs.
670    /// Only valid inside agent handler bodies.
671    Checkpoint {
672        /// Span covering the statement.
673        span: Span,
674    },
675
676    /// Expression statement: `expr`
677    Expr {
678        /// The expression.
679        expr: Expr,
680        /// Span covering the statement.
681        span: Span,
682    },
683
684    /// Tuple destructuring: `let (a, b) = expr;`
685    LetTuple {
686        /// The variable names.
687        names: Vec<Ident>,
688        /// Optional type annotation.
689        ty: Option<TypeExpr>,
690        /// The value expression.
691        value: Expr,
692        /// Span covering the statement.
693        span: Span,
694    },
695
696    /// RFC-0012: Mock divine statement: `mock divine -> expr;`
697    MockDivine {
698        /// The mock value expression.
699        value: MockValue,
700        /// Span covering the statement.
701        span: Span,
702    },
703
704    /// Mock tool statement: `mock tool Http.get -> value;`
705    MockTool {
706        /// The tool name.
707        tool_name: Ident,
708        /// The function name.
709        fn_name: Ident,
710        /// The mock value expression.
711        value: MockValue,
712        /// Span covering the statement.
713        span: Span,
714    },
715}
716
717/// RFC-0012: A mock value for `mock divine -> value`.
718#[derive(Debug, Clone, PartialEq)]
719pub enum MockValue {
720    /// A literal value: `mock divine -> "string"` or `mock divine -> SomeRecord { ... }`
721    Value(Expr),
722    /// A failure: `mock divine -> fail("error message")`
723    Fail(Expr),
724}
725
726impl Stmt {
727    /// Get the span of this statement.
728    #[must_use]
729    pub fn span(&self) -> &Span {
730        match self {
731            Stmt::Let { span, .. }
732            | Stmt::Assign { span, .. }
733            | Stmt::Return { span, .. }
734            | Stmt::If { span, .. }
735            | Stmt::For { span, .. }
736            | Stmt::While { span, .. }
737            | Stmt::Loop { span, .. }
738            | Stmt::Break { span, .. }
739            | Stmt::SpanBlock { span, .. }
740            | Stmt::Checkpoint { span, .. }
741            | Stmt::Expr { span, .. }
742            | Stmt::LetTuple { span, .. }
743            | Stmt::MockDivine { span, .. }
744            | Stmt::MockTool { span, .. } => span,
745        }
746    }
747}
748
749/// The else branch of an if statement.
750#[derive(Debug, Clone, PartialEq)]
751pub enum ElseBranch {
752    /// `else { ... }`
753    Block(Block),
754    /// `else if ...` (chained if)
755    ElseIf(Box<Stmt>),
756}
757
758// =============================================================================
759// Expressions
760// =============================================================================
761
762/// An expression.
763#[derive(Debug, Clone, PartialEq)]
764pub enum Expr {
765    /// LLM divination: `divine("template")` or `divine("template" -> Type)`
766    Divine {
767        /// The prompt template (may contain `{ident}` interpolations).
768        template: StringTemplate,
769        /// Optional result type annotation.
770        result_ty: Option<TypeExpr>,
771        /// Span covering the expression.
772        span: Span,
773    },
774
775    /// Agent summoning: `summon AgentName { field: value, ... }`
776    Summon {
777        /// The agent type to spawn.
778        agent: Ident,
779        /// Initial belief values.
780        fields: Vec<FieldInit>,
781        /// Span covering the expression.
782        span: Span,
783    },
784
785    /// Await: `await expr` or `await expr timeout(ms)`
786    Await {
787        /// The agent handle to await.
788        handle: Box<Expr>,
789        /// Optional timeout in milliseconds.
790        timeout: Option<Box<Expr>>,
791        /// Span covering the expression.
792        span: Span,
793    },
794
795    /// Send message: `send(handle, message)`
796    Send {
797        /// The agent handle to send to.
798        handle: Box<Expr>,
799        /// The message to send.
800        message: Box<Expr>,
801        /// Span covering the expression.
802        span: Span,
803    },
804
805    /// Yield value: `yield(value)`
806    Yield {
807        /// The value to emit to the awaiter.
808        value: Box<Expr>,
809        /// Span covering the expression.
810        span: Span,
811    },
812
813    /// Function call: `name(args)` or `name::<T, U>(args)` (turbofish)
814    Call {
815        /// The function name.
816        name: Ident,
817        /// Explicit type arguments (turbofish syntax): `foo::<Int, String>(...)`
818        type_args: Vec<TypeExpr>,
819        /// The arguments.
820        args: Vec<Expr>,
821        /// Span covering the expression.
822        span: Span,
823    },
824
825    /// Apply expression: call an arbitrary expression as a function.
826    /// Used for method calls on values: `expr.method(args)` becomes
827    /// `Apply { callee: FieldAccess { object: expr, field: method }, args }`
828    Apply {
829        /// The expression being called (typically a FieldAccess for method calls).
830        callee: Box<Expr>,
831        /// The arguments.
832        args: Vec<Expr>,
833        /// Span covering the expression.
834        span: Span,
835    },
836
837    /// Method call on self: `self.method(args)`
838    SelfMethodCall {
839        /// The method name.
840        method: Ident,
841        /// The arguments.
842        args: Vec<Expr>,
843        /// Span covering the expression.
844        span: Span,
845    },
846
847    /// Self field access: `self.field`
848    SelfField {
849        /// The field (belief) name.
850        field: Ident,
851        /// Span covering the expression.
852        span: Span,
853    },
854
855    /// Binary operation: `left op right`
856    Binary {
857        /// The operator.
858        op: BinOp,
859        /// The left operand.
860        left: Box<Expr>,
861        /// The right operand.
862        right: Box<Expr>,
863        /// Span covering the expression.
864        span: Span,
865    },
866
867    /// Unary operation: `op operand`
868    Unary {
869        /// The operator.
870        op: UnaryOp,
871        /// The operand.
872        operand: Box<Expr>,
873        /// Span covering the expression.
874        span: Span,
875    },
876
877    /// List literal: `[a, b, c]`
878    List {
879        /// The list elements.
880        elements: Vec<Expr>,
881        /// Span covering the expression.
882        span: Span,
883    },
884
885    /// Literal value.
886    Literal {
887        /// The literal value.
888        value: Literal,
889        /// Span covering the expression.
890        span: Span,
891    },
892
893    /// Variable reference.
894    Var {
895        /// The variable name.
896        name: Ident,
897        /// Span covering the expression.
898        span: Span,
899    },
900
901    /// Parenthesized expression: `(expr)`
902    Paren {
903        /// The inner expression.
904        inner: Box<Expr>,
905        /// Span covering the expression (including parens).
906        span: Span,
907    },
908
909    /// Interpolated string: `"Hello, {name}!"`
910    StringInterp {
911        /// The string template with interpolations.
912        template: StringTemplate,
913        /// Span covering the expression.
914        span: Span,
915    },
916
917    /// Match expression: `match expr { Pattern => expr, ... }`
918    Match {
919        /// The scrutinee expression.
920        scrutinee: Box<Expr>,
921        /// The match arms.
922        arms: Vec<MatchArm>,
923        /// Span covering the expression.
924        span: Span,
925    },
926
927    /// Record construction: `Point { x: 1, y: 2 }` or `Pair::<Int, String> { first: 1, second: "hi" }`
928    RecordConstruct {
929        /// The record type name.
930        name: Ident,
931        /// Explicit type arguments (turbofish syntax): `Pair::<Int, String> { ... }`
932        type_args: Vec<TypeExpr>,
933        /// Field initializations.
934        fields: Vec<FieldInit>,
935        /// Span covering the expression.
936        span: Span,
937    },
938
939    /// Field access: `record.field`
940    FieldAccess {
941        /// The record expression.
942        object: Box<Expr>,
943        /// The field name.
944        field: Ident,
945        /// Span covering the expression.
946        span: Span,
947    },
948
949    /// Receive message from mailbox: `receive()`
950    Receive {
951        /// Span covering the expression.
952        span: Span,
953    },
954
955    /// Try expression: `try expr` — propagates failure upward.
956    Try {
957        /// The expression that may fail.
958        expr: Box<Expr>,
959        /// Span covering the expression.
960        span: Span,
961    },
962
963    /// Catch expression: `expr catch { recovery }` or `expr catch(e) { recovery }`.
964    Catch {
965        /// The expression that may fail.
966        expr: Box<Expr>,
967        /// The optional error binding (e.g., `e` in `catch(e)`).
968        error_bind: Option<Ident>,
969        /// The recovery expression.
970        recovery: Box<Expr>,
971        /// Span covering the expression.
972        span: Span,
973    },
974
975    /// Fail expression: `fail "message"` or `fail Error { ... }`.
976    /// Type is `Never` - this expression never returns.
977    Fail {
978        /// The error value (either a string message or an Error record).
979        error: Box<Expr>,
980        /// Span covering the expression.
981        span: Span,
982    },
983
984    /// Retry expression: `retry(3) { ... }` or `retry(3, delay: 1000) { ... }`
985    Retry {
986        /// Number of retry attempts (1-10).
987        count: Box<Expr>,
988        /// Optional delay between attempts in milliseconds.
989        delay: Option<Box<Expr>>,
990        /// Optional list of error kinds to retry on.
991        on_errors: Option<Vec<Expr>>,
992        /// The body to retry.
993        body: Box<Expr>,
994        /// Span covering the expression.
995        span: Span,
996    },
997
998    /// Trace expression: `trace("message")` for emitting trace events.
999    Trace {
1000        /// The message to trace (must be a string).
1001        message: Box<Expr>,
1002        /// Span covering the expression.
1003        span: Span,
1004    },
1005
1006    /// Closure expression: `|params| body`
1007    Closure {
1008        /// The closure parameters.
1009        params: Vec<ClosureParam>,
1010        /// The closure body (single expression).
1011        body: Box<Expr>,
1012        /// Span covering the expression.
1013        span: Span,
1014    },
1015
1016    /// Tuple literal: `(a, b, c)`
1017    Tuple {
1018        /// The tuple elements (at least 2).
1019        elements: Vec<Expr>,
1020        /// Span covering the expression.
1021        span: Span,
1022    },
1023
1024    /// Tuple index access: `tuple.0`
1025    TupleIndex {
1026        /// The tuple expression.
1027        tuple: Box<Expr>,
1028        /// The index (0-based).
1029        index: usize,
1030        /// Span covering the expression.
1031        span: Span,
1032    },
1033
1034    /// Map literal: `{ key: value, ... }` or `{}`
1035    Map {
1036        /// The map entries.
1037        entries: Vec<MapEntry>,
1038        /// Span covering the expression.
1039        span: Span,
1040    },
1041
1042    /// Enum variant construction: `MyEnum.Variant` or `Either::<L, R>.Left(payload)`
1043    VariantConstruct {
1044        /// The enum type name.
1045        enum_name: Ident,
1046        /// Explicit type arguments (turbofish syntax): `Either::<L, R>.Left(...)`
1047        type_args: Vec<TypeExpr>,
1048        /// The variant name.
1049        variant: Ident,
1050        /// The optional payload expression.
1051        payload: Option<Box<Expr>>,
1052        /// Span covering the expression.
1053        span: Span,
1054    },
1055
1056    /// Tool function call (RFC-0011): `Http.get(url)`
1057    ToolCall {
1058        /// The tool name.
1059        tool: Ident,
1060        /// The function name.
1061        function: Ident,
1062        /// The arguments.
1063        args: Vec<Expr>,
1064        /// Span covering the expression.
1065        span: Span,
1066    },
1067
1068    /// Reply to current message (Phase 3 session types): `reply(message)`
1069    ///
1070    /// Only valid inside `on message` handlers when the agent follows a protocol.
1071    Reply {
1072        /// The message to send back.
1073        message: Box<Expr>,
1074        /// Span covering the expression.
1075        span: Span,
1076    },
1077}
1078
1079/// A map entry: `key: value`
1080#[derive(Debug, Clone, PartialEq)]
1081pub struct MapEntry {
1082    /// The key expression.
1083    pub key: Expr,
1084    /// The value expression.
1085    pub value: Expr,
1086    /// Span covering the entry.
1087    pub span: Span,
1088}
1089
1090impl Expr {
1091    /// Get the span of this expression.
1092    #[must_use]
1093    pub fn span(&self) -> &Span {
1094        match self {
1095            Expr::Divine { span, .. }
1096            | Expr::Summon { span, .. }
1097            | Expr::Await { span, .. }
1098            | Expr::Send { span, .. }
1099            | Expr::Yield { span, .. }
1100            | Expr::Call { span, .. }
1101            | Expr::Apply { span, .. }
1102            | Expr::SelfMethodCall { span, .. }
1103            | Expr::SelfField { span, .. }
1104            | Expr::Binary { span, .. }
1105            | Expr::Unary { span, .. }
1106            | Expr::List { span, .. }
1107            | Expr::Literal { span, .. }
1108            | Expr::Var { span, .. }
1109            | Expr::Paren { span, .. }
1110            | Expr::StringInterp { span, .. }
1111            | Expr::Match { span, .. }
1112            | Expr::RecordConstruct { span, .. }
1113            | Expr::FieldAccess { span, .. }
1114            | Expr::Receive { span, .. }
1115            | Expr::Try { span, .. }
1116            | Expr::Catch { span, .. }
1117            | Expr::Fail { span, .. }
1118            | Expr::Retry { span, .. }
1119            | Expr::Trace { span, .. }
1120            | Expr::Closure { span, .. }
1121            | Expr::Tuple { span, .. }
1122            | Expr::TupleIndex { span, .. }
1123            | Expr::Map { span, .. }
1124            | Expr::VariantConstruct { span, .. }
1125            | Expr::ToolCall { span, .. }
1126            | Expr::Reply { span, .. } => span,
1127        }
1128    }
1129}
1130
1131/// A field initialization in a spawn or record construction expression: `field: value`
1132#[derive(Debug, Clone, PartialEq)]
1133pub struct FieldInit {
1134    /// The field name.
1135    pub name: Ident,
1136    /// The initial value.
1137    pub value: Expr,
1138    /// Span covering the field initialization.
1139    pub span: Span,
1140}
1141
1142/// A match arm: `Pattern => expr`
1143#[derive(Debug, Clone, PartialEq)]
1144pub struct MatchArm {
1145    /// The pattern to match.
1146    pub pattern: Pattern,
1147    /// The expression to evaluate if the pattern matches.
1148    pub body: Expr,
1149    /// Span covering the arm.
1150    pub span: Span,
1151}
1152
1153/// A pattern in a match expression.
1154#[derive(Debug, Clone, PartialEq)]
1155pub enum Pattern {
1156    /// Wildcard pattern: `_`
1157    Wildcard {
1158        /// Span covering the pattern.
1159        span: Span,
1160    },
1161    /// Enum variant pattern: `Status::Active`, `Ok(x)`, or just `Active`
1162    Variant {
1163        /// Optional enum type name (for qualified patterns).
1164        enum_name: Option<Ident>,
1165        /// The variant name.
1166        variant: Ident,
1167        /// Optional payload binding pattern (e.g., `x` in `Ok(x)`).
1168        payload: Option<Box<Pattern>>,
1169        /// Span covering the pattern.
1170        span: Span,
1171    },
1172    /// Literal pattern: `42`, `"hello"`, `true`
1173    Literal {
1174        /// The literal value.
1175        value: Literal,
1176        /// Span covering the pattern.
1177        span: Span,
1178    },
1179    /// Binding pattern: `x` (binds the matched value to a variable)
1180    Binding {
1181        /// The variable name.
1182        name: Ident,
1183        /// Span covering the pattern.
1184        span: Span,
1185    },
1186    /// Tuple pattern: `(a, b, c)`
1187    Tuple {
1188        /// The element patterns.
1189        elements: Vec<Pattern>,
1190        /// Span covering the pattern.
1191        span: Span,
1192    },
1193}
1194
1195impl Pattern {
1196    /// Get the span of this pattern.
1197    #[must_use]
1198    pub fn span(&self) -> &Span {
1199        match self {
1200            Pattern::Wildcard { span }
1201            | Pattern::Variant { span, .. }
1202            | Pattern::Literal { span, .. }
1203            | Pattern::Binding { span, .. }
1204            | Pattern::Tuple { span, .. } => span,
1205        }
1206    }
1207}
1208
1209// =============================================================================
1210// Operators
1211// =============================================================================
1212
1213/// Binary operators.
1214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1215pub enum BinOp {
1216    // Arithmetic
1217    /// `+`
1218    Add,
1219    /// `-`
1220    Sub,
1221    /// `*`
1222    Mul,
1223    /// `/`
1224    Div,
1225    /// `%` (remainder/modulo)
1226    Rem,
1227
1228    // Comparison
1229    /// `==`
1230    Eq,
1231    /// `!=`
1232    Ne,
1233    /// `<`
1234    Lt,
1235    /// `>`
1236    Gt,
1237    /// `<=`
1238    Le,
1239    /// `>=`
1240    Ge,
1241
1242    // Logical
1243    /// `&&`
1244    And,
1245    /// `||`
1246    Or,
1247
1248    // String
1249    /// `++` (string concatenation)
1250    Concat,
1251}
1252
1253impl BinOp {
1254    /// Get the precedence of this operator (higher = binds tighter).
1255    #[must_use]
1256    pub fn precedence(self) -> u8 {
1257        match self {
1258            BinOp::Or => 1,
1259            BinOp::And => 2,
1260            BinOp::Eq | BinOp::Ne => 3,
1261            BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge => 4,
1262            BinOp::Concat => 5,
1263            BinOp::Add | BinOp::Sub => 6,
1264            BinOp::Mul | BinOp::Div | BinOp::Rem => 7,
1265        }
1266    }
1267
1268    /// Check if this operator is left-associative.
1269    #[must_use]
1270    pub fn is_left_assoc(self) -> bool {
1271        // All our operators are left-associative
1272        true
1273    }
1274}
1275
1276impl fmt::Display for BinOp {
1277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1278        match self {
1279            BinOp::Add => write!(f, "+"),
1280            BinOp::Sub => write!(f, "-"),
1281            BinOp::Mul => write!(f, "*"),
1282            BinOp::Div => write!(f, "/"),
1283            BinOp::Rem => write!(f, "%"),
1284            BinOp::Eq => write!(f, "=="),
1285            BinOp::Ne => write!(f, "!="),
1286            BinOp::Lt => write!(f, "<"),
1287            BinOp::Gt => write!(f, ">"),
1288            BinOp::Le => write!(f, "<="),
1289            BinOp::Ge => write!(f, ">="),
1290            BinOp::And => write!(f, "&&"),
1291            BinOp::Or => write!(f, "||"),
1292            BinOp::Concat => write!(f, "++"),
1293        }
1294    }
1295}
1296
1297/// Unary operators.
1298#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1299pub enum UnaryOp {
1300    /// `-` (negation)
1301    Neg,
1302    /// `!` (logical not)
1303    Not,
1304}
1305
1306impl fmt::Display for UnaryOp {
1307    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1308        match self {
1309            UnaryOp::Neg => write!(f, "-"),
1310            UnaryOp::Not => write!(f, "!"),
1311        }
1312    }
1313}
1314
1315// =============================================================================
1316// Literals
1317// =============================================================================
1318
1319/// A literal value.
1320#[derive(Debug, Clone, PartialEq)]
1321pub enum Literal {
1322    /// Integer literal: `42`, `-7`
1323    Int(i64),
1324    /// Float literal: `3.14`, `-0.5`
1325    Float(f64),
1326    /// Boolean literal: `true`, `false`
1327    Bool(bool),
1328    /// String literal: `"hello"`
1329    String(String),
1330}
1331
1332impl fmt::Display for Literal {
1333    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1334        match self {
1335            Literal::Int(n) => write!(f, "{n}"),
1336            Literal::Float(n) => write!(f, "{n}"),
1337            Literal::Bool(b) => write!(f, "{b}"),
1338            Literal::String(s) => write!(f, "\"{s}\""),
1339        }
1340    }
1341}
1342
1343// =============================================================================
1344// String templates (for interpolation)
1345// =============================================================================
1346
1347/// A string template that may contain interpolations.
1348///
1349/// For example, `"Hello, {name}!"` becomes:
1350/// ```text
1351/// StringTemplate {
1352///     parts: [
1353///         StringPart::Literal("Hello, "),
1354///         StringPart::Interpolation(Ident("name")),
1355///         StringPart::Literal("!"),
1356///     ]
1357/// }
1358/// ```
1359#[derive(Debug, Clone, PartialEq)]
1360pub struct StringTemplate {
1361    /// The parts of the template.
1362    pub parts: Vec<StringPart>,
1363    /// Span covering the entire template string.
1364    pub span: Span,
1365}
1366
1367impl StringTemplate {
1368    /// Create a simple template with no interpolations.
1369    #[must_use]
1370    pub fn literal(s: String, span: Span) -> Self {
1371        Self {
1372            parts: vec![StringPart::Literal(s)],
1373            span,
1374        }
1375    }
1376
1377    /// Check if this template has any interpolations.
1378    #[must_use]
1379    pub fn has_interpolations(&self) -> bool {
1380        self.parts
1381            .iter()
1382            .any(|p| matches!(p, StringPart::Interpolation(_)))
1383    }
1384
1385    /// Get all interpolation expressions.
1386    pub fn interpolations(&self) -> impl Iterator<Item = &Expr> {
1387        self.parts.iter().filter_map(|p| match p {
1388            StringPart::Interpolation(expr) => Some(expr.as_ref()),
1389            StringPart::Literal(_) => None,
1390        })
1391    }
1392}
1393
1394impl fmt::Display for StringTemplate {
1395    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1396        write!(f, "\"")?;
1397        for part in &self.parts {
1398            match part {
1399                StringPart::Literal(s) => write!(f, "{s}")?,
1400                StringPart::Interpolation(_) => write!(f, "{{...}}")?,
1401            }
1402        }
1403        write!(f, "\"")
1404    }
1405}
1406
1407/// A part of a string template.
1408#[derive(Debug, Clone, PartialEq)]
1409pub enum StringPart {
1410    /// A literal string segment.
1411    Literal(String),
1412    /// An interpolated expression: `{ident}`, `{a + b}`, `{foo()}`
1413    Interpolation(Box<Expr>),
1414}
1415
1416// =============================================================================
1417// Tests
1418// =============================================================================
1419
1420#[cfg(test)]
1421mod tests {
1422    use super::*;
1423
1424    #[test]
1425    fn binop_precedence() {
1426        // Mul/Div > Add/Sub > Comparison > And > Or
1427        assert!(BinOp::Mul.precedence() > BinOp::Add.precedence());
1428        assert!(BinOp::Add.precedence() > BinOp::Lt.precedence());
1429        assert!(BinOp::Lt.precedence() > BinOp::And.precedence());
1430        assert!(BinOp::And.precedence() > BinOp::Or.precedence());
1431    }
1432
1433    #[test]
1434    fn binop_display() {
1435        assert_eq!(format!("{}", BinOp::Add), "+");
1436        assert_eq!(format!("{}", BinOp::Eq), "==");
1437        assert_eq!(format!("{}", BinOp::Concat), "++");
1438        assert_eq!(format!("{}", BinOp::And), "&&");
1439    }
1440
1441    #[test]
1442    fn unaryop_display() {
1443        assert_eq!(format!("{}", UnaryOp::Neg), "-");
1444        assert_eq!(format!("{}", UnaryOp::Not), "!");
1445    }
1446
1447    #[test]
1448    fn literal_display() {
1449        assert_eq!(format!("{}", Literal::Int(42)), "42");
1450        assert_eq!(format!("{}", Literal::Float(3.14)), "3.14");
1451        assert_eq!(format!("{}", Literal::Bool(true)), "true");
1452        assert_eq!(format!("{}", Literal::String("hello".into())), "\"hello\"");
1453    }
1454
1455    #[test]
1456    fn event_kind_display() {
1457        assert_eq!(format!("{}", EventKind::Start), "start");
1458        assert_eq!(format!("{}", EventKind::Stop), "stop");
1459
1460        let msg = EventKind::Message {
1461            param_name: Ident::dummy("msg"),
1462            param_ty: TypeExpr::String,
1463        };
1464        assert_eq!(format!("{msg}"), "message(msg: String)");
1465    }
1466
1467    #[test]
1468    fn string_template_literal() {
1469        let template = StringTemplate::literal("hello".into(), Span::dummy());
1470        assert!(!template.has_interpolations());
1471        assert_eq!(format!("{template}"), "\"hello\"");
1472    }
1473
1474    #[test]
1475    fn string_template_with_interpolation() {
1476        let template = StringTemplate {
1477            parts: vec![
1478                StringPart::Literal("Hello, ".into()),
1479                StringPart::Interpolation(Box::new(Expr::Var {
1480                    name: Ident::dummy("name"),
1481                    span: Span::dummy(),
1482                })),
1483                StringPart::Literal("!".into()),
1484            ],
1485            span: Span::dummy(),
1486        };
1487        assert!(template.has_interpolations());
1488        assert_eq!(format!("{template}"), "\"Hello, {...}!\"");
1489
1490        let interps: Vec<_> = template.interpolations().collect();
1491        assert_eq!(interps.len(), 1);
1492        // Verify it's a Var expression with name "name"
1493        if let Expr::Var { name, .. } = interps[0] {
1494            assert_eq!(name.name, "name");
1495        } else {
1496            panic!("Expected Var expression");
1497        }
1498    }
1499
1500    #[test]
1501    fn expr_span() {
1502        let span = Span::dummy();
1503        let expr = Expr::Literal {
1504            value: Literal::Int(42),
1505            span: span.clone(),
1506        };
1507        assert_eq!(expr.span(), &span);
1508    }
1509
1510    #[test]
1511    fn stmt_span() {
1512        let span = Span::dummy();
1513        let stmt = Stmt::Return {
1514            value: None,
1515            span: span.clone(),
1516        };
1517        assert_eq!(stmt.span(), &span);
1518    }
1519}