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