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