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