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