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