sigil_parser/
ir.rs

1//! AI-Facing Intermediate Representation (IR)
2//!
3//! This module provides a JSON-serializable IR designed for consumption by
4//! AI agents, language servers, and external tooling. The IR captures:
5//!
6//! - Function definitions with typed parameters and bodies
7//! - Pipeline operations (morphemes, transformations, forks)
8//! - Evidentiality annotations throughout
9//! - Type information including the evidentiality lattice
10//! - Control flow and data flow structures
11//! - Protocol operations with their trust boundaries
12
13use serde::{Deserialize, Serialize};
14
15/// The version of the IR schema
16pub const IR_VERSION: &str = "1.0.0";
17
18/// Top-level IR module representing a complete Sigil program
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct IrModule {
21    /// Schema version
22    pub version: String,
23    /// Source file path
24    pub source: String,
25    /// All function definitions
26    pub functions: Vec<IrFunction>,
27    /// Type definitions (structs, enums)
28    pub types: Vec<IrTypeDef>,
29    /// Trait definitions
30    pub traits: Vec<IrTraitDef>,
31    /// Impl blocks
32    pub impls: Vec<IrImplBlock>,
33    /// Constants
34    pub constants: Vec<IrConstant>,
35    /// The evidentiality lattice structure
36    pub evidentiality_lattice: EvidentialityLattice,
37}
38
39impl IrModule {
40    /// Create a new empty IR module
41    pub fn new(source: String) -> Self {
42        Self {
43            version: IR_VERSION.to_string(),
44            source,
45            functions: Vec::new(),
46            types: Vec::new(),
47            traits: Vec::new(),
48            impls: Vec::new(),
49            constants: Vec::new(),
50            evidentiality_lattice: EvidentialityLattice::default(),
51        }
52    }
53}
54
55/// The evidentiality lattice with explicit join/meet rules
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct EvidentialityLattice {
58    /// The four evidence levels in order
59    pub levels: Vec<EvidenceLevel>,
60    /// Join rules (pessimistic combination)
61    pub join_rules: Vec<LatticeRule>,
62    /// Meet rules (optimistic combination)
63    pub meet_rules: Vec<LatticeRule>,
64}
65
66impl Default for EvidentialityLattice {
67    fn default() -> Self {
68        Self {
69            levels: vec![
70                EvidenceLevel {
71                    name: "known".to_string(),
72                    symbol: "!".to_string(),
73                    order: 0,
74                    description: "Direct computation, verified".to_string(),
75                },
76                EvidenceLevel {
77                    name: "uncertain".to_string(),
78                    symbol: "?".to_string(),
79                    order: 1,
80                    description: "Inferred, possibly absent".to_string(),
81                },
82                EvidenceLevel {
83                    name: "reported".to_string(),
84                    symbol: "~".to_string(),
85                    order: 2,
86                    description: "External source, untrusted".to_string(),
87                },
88                EvidenceLevel {
89                    name: "paradox".to_string(),
90                    symbol: "‽".to_string(),
91                    order: 3,
92                    description: "Contradictory, trust boundary".to_string(),
93                },
94            ],
95            join_rules: vec![
96                LatticeRule::new("known", "uncertain", "uncertain"),
97                LatticeRule::new("known", "reported", "reported"),
98                LatticeRule::new("known", "paradox", "paradox"),
99                LatticeRule::new("uncertain", "reported", "reported"),
100                LatticeRule::new("uncertain", "paradox", "paradox"),
101                LatticeRule::new("reported", "paradox", "paradox"),
102            ],
103            meet_rules: vec![
104                LatticeRule::new("known", "uncertain", "known"),
105                LatticeRule::new("known", "reported", "known"),
106                LatticeRule::new("known", "paradox", "known"),
107                LatticeRule::new("uncertain", "reported", "uncertain"),
108                LatticeRule::new("uncertain", "paradox", "uncertain"),
109                LatticeRule::new("reported", "paradox", "reported"),
110            ],
111        }
112    }
113}
114
115/// An evidence level in the lattice
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct EvidenceLevel {
118    pub name: String,
119    pub symbol: String,
120    pub order: u8,
121    pub description: String,
122}
123
124/// A join/meet rule in the lattice
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct LatticeRule {
127    pub left: String,
128    pub right: String,
129    pub result: String,
130}
131
132impl LatticeRule {
133    pub fn new(left: &str, right: &str, result: &str) -> Self {
134        Self {
135            left: left.to_string(),
136            right: right.to_string(),
137            result: result.to_string(),
138        }
139    }
140}
141
142/// Evidence marker enum matching AST Evidentiality
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
144#[serde(rename_all = "lowercase")]
145pub enum IrEvidence {
146    Known,
147    Uncertain,
148    Reported,
149    Paradox,
150}
151
152impl IrEvidence {
153    /// Join two evidence levels (pessimistic - takes the higher/less certain)
154    pub fn join(self, other: IrEvidence) -> IrEvidence {
155        match (self, other) {
156            (IrEvidence::Paradox, _) | (_, IrEvidence::Paradox) => IrEvidence::Paradox,
157            (IrEvidence::Reported, _) | (_, IrEvidence::Reported) => IrEvidence::Reported,
158            (IrEvidence::Uncertain, _) | (_, IrEvidence::Uncertain) => IrEvidence::Uncertain,
159            (IrEvidence::Known, IrEvidence::Known) => IrEvidence::Known,
160        }
161    }
162
163    /// Meet two evidence levels (optimistic - takes the lower/more certain)
164    pub fn meet(self, other: IrEvidence) -> IrEvidence {
165        match (self, other) {
166            (IrEvidence::Known, _) | (_, IrEvidence::Known) => IrEvidence::Known,
167            (IrEvidence::Uncertain, _) | (_, IrEvidence::Uncertain) => IrEvidence::Uncertain,
168            (IrEvidence::Reported, _) | (_, IrEvidence::Reported) => IrEvidence::Reported,
169            (IrEvidence::Paradox, IrEvidence::Paradox) => IrEvidence::Paradox,
170        }
171    }
172
173    /// Get the symbol for this evidence level
174    pub fn symbol(&self) -> &'static str {
175        match self {
176            IrEvidence::Known => "!",
177            IrEvidence::Uncertain => "?",
178            IrEvidence::Reported => "~",
179            IrEvidence::Paradox => "‽",
180        }
181    }
182}
183
184impl Default for IrEvidence {
185    fn default() -> Self {
186        IrEvidence::Known
187    }
188}
189
190/// Source location span
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct IrSpan {
193    pub start: IrPosition,
194    pub end: IrPosition,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct IrPosition {
199    pub line: usize,
200    pub column: usize,
201}
202
203/// Function visibility
204#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
205#[serde(rename_all = "lowercase")]
206pub enum IrVisibility {
207    Public,
208    Private,
209    Crate,
210}
211
212impl Default for IrVisibility {
213    fn default() -> Self {
214        IrVisibility::Private
215    }
216}
217
218/// A function definition
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct IrFunction {
221    /// Function name
222    pub name: String,
223    /// Unique identifier
224    pub id: String,
225    /// Visibility
226    pub visibility: IrVisibility,
227    /// Generic type parameters
228    pub generics: Vec<IrGenericParam>,
229    /// Parameters
230    pub params: Vec<IrParam>,
231    /// Return type
232    pub return_type: IrType,
233    /// Function body
234    pub body: Option<IrOperation>,
235    /// Attributes (inline, pure, async, etc.)
236    pub attributes: Vec<String>,
237    /// Whether this is an async function
238    pub is_async: bool,
239    /// Source span
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub span: Option<IrSpan>,
242}
243
244/// A generic type parameter
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct IrGenericParam {
247    pub name: String,
248    pub bounds: Vec<String>,
249}
250
251/// A function parameter
252#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct IrParam {
254    pub name: String,
255    #[serde(rename = "type")]
256    pub ty: IrType,
257    pub evidence: IrEvidence,
258}
259
260/// Type representation in IR
261#[derive(Debug, Clone, Serialize, Deserialize)]
262#[serde(tag = "kind")]
263pub enum IrType {
264    /// Primitive types (i32, f64, bool, str, etc.)
265    #[serde(rename = "primitive")]
266    Primitive { name: String },
267
268    /// Unit type ()
269    #[serde(rename = "unit")]
270    Unit,
271
272    /// Never type !
273    #[serde(rename = "never")]
274    Never,
275
276    /// Array type [T; N]
277    #[serde(rename = "array")]
278    Array {
279        element: Box<IrType>,
280        size: Option<usize>,
281    },
282
283    /// Slice type [T]
284    #[serde(rename = "slice")]
285    Slice { element: Box<IrType> },
286
287    /// Tuple type (A, B, C)
288    #[serde(rename = "tuple")]
289    Tuple { elements: Vec<IrType> },
290
291    /// Named struct/enum type
292    #[serde(rename = "named")]
293    Named { name: String, generics: Vec<IrType> },
294
295    /// Reference &T, &mut T, &'a T, &'static mut T
296    #[serde(rename = "reference")]
297    Reference {
298        lifetime: Option<String>,
299        mutable: bool,
300        inner: Box<IrType>,
301    },
302
303    /// Pointer *const T or *mut T
304    #[serde(rename = "pointer")]
305    Pointer { mutable: bool, inner: Box<IrType> },
306
307    /// Function type fn(A, B) -> C
308    #[serde(rename = "function")]
309    Function {
310        params: Vec<IrType>,
311        return_type: Box<IrType>,
312        is_async: bool,
313    },
314
315    /// Evidential wrapper E<T> with evidence level
316    #[serde(rename = "evidential")]
317    Evidential {
318        inner: Box<IrType>,
319        evidence: IrEvidence,
320    },
321
322    /// Cyclic arithmetic type Z/nZ
323    #[serde(rename = "cycle")]
324    Cycle { modulus: u64 },
325
326    /// SIMD vector type
327    #[serde(rename = "simd")]
328    Simd { element: Box<IrType>, lanes: usize },
329
330    /// Atomic type
331    #[serde(rename = "atomic")]
332    Atomic { inner: Box<IrType> },
333
334    /// Type variable (for inference)
335    #[serde(rename = "var")]
336    Var { id: String },
337
338    /// Infer placeholder _
339    #[serde(rename = "infer")]
340    Infer,
341
342    /// Lifetime bound 'static, 'a
343    #[serde(rename = "lifetime")]
344    Lifetime { name: String },
345
346    /// Trait object: dyn Trait
347    #[serde(rename = "trait_object")]
348    TraitObject { bounds: Vec<IrType> },
349
350    /// Higher-ranked trait bound: for<'a> Trait<'a>
351    #[serde(rename = "hrtb")]
352    Hrtb {
353        lifetimes: Vec<String>,
354        bound: Box<IrType>,
355    },
356
357    /// Inline struct type: struct { field: Type, ... }
358    #[serde(rename = "inline_struct")]
359    InlineStruct { fields: Vec<(String, IrType)> },
360
361    /// Impl trait: impl Trait bounds
362    #[serde(rename = "impl_trait")]
363    ImplTrait { bounds: Vec<IrType> },
364
365    /// Inline enum type: enum { Variant1, Variant2, ... }
366    #[serde(rename = "inline_enum")]
367    InlineEnum { variants: Vec<String> },
368
369    /// Associated type binding: Output = Type
370    #[serde(rename = "assoc_type_binding")]
371    AssocTypeBinding { name: String, ty: Box<IrType> },
372
373    /// Error recovery type
374    #[serde(rename = "error")]
375    Error,
376}
377
378impl Default for IrType {
379    fn default() -> Self {
380        IrType::Unit
381    }
382}
383
384/// Type definition (struct, enum)
385#[derive(Debug, Clone, Serialize, Deserialize)]
386#[serde(tag = "kind")]
387pub enum IrTypeDef {
388    #[serde(rename = "struct_def")]
389    Struct {
390        name: String,
391        generics: Vec<IrGenericParam>,
392        fields: Vec<IrField>,
393        #[serde(skip_serializing_if = "Option::is_none")]
394        span: Option<IrSpan>,
395    },
396    #[serde(rename = "enum_def")]
397    Enum {
398        name: String,
399        generics: Vec<IrGenericParam>,
400        variants: Vec<IrVariant>,
401        #[serde(skip_serializing_if = "Option::is_none")]
402        span: Option<IrSpan>,
403    },
404    #[serde(rename = "type_alias")]
405    TypeAlias {
406        name: String,
407        generics: Vec<IrGenericParam>,
408        target: IrType,
409        #[serde(skip_serializing_if = "Option::is_none")]
410        span: Option<IrSpan>,
411    },
412}
413
414/// A struct field
415#[derive(Debug, Clone, Serialize, Deserialize)]
416pub struct IrField {
417    pub name: String,
418    #[serde(rename = "type")]
419    pub ty: IrType,
420    pub visibility: IrVisibility,
421}
422
423/// An enum variant
424#[derive(Debug, Clone, Serialize, Deserialize)]
425pub struct IrVariant {
426    pub name: String,
427    pub fields: Option<Vec<IrField>>,
428    pub discriminant: Option<i64>,
429}
430
431/// Trait definition
432#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct IrTraitDef {
434    pub name: String,
435    pub generics: Vec<IrGenericParam>,
436    pub super_traits: Vec<String>,
437    pub methods: Vec<IrFunction>,
438    #[serde(skip_serializing_if = "Option::is_none")]
439    pub span: Option<IrSpan>,
440}
441
442/// Impl block
443#[derive(Debug, Clone, Serialize, Deserialize)]
444pub struct IrImplBlock {
445    #[serde(skip_serializing_if = "Option::is_none")]
446    pub trait_name: Option<String>,
447    pub target_type: IrType,
448    pub generics: Vec<IrGenericParam>,
449    pub methods: Vec<IrFunction>,
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub span: Option<IrSpan>,
452}
453
454/// Constant definition
455#[derive(Debug, Clone, Serialize, Deserialize)]
456pub struct IrConstant {
457    pub name: String,
458    #[serde(rename = "type")]
459    pub ty: IrType,
460    pub value: IrOperation,
461    pub visibility: IrVisibility,
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub span: Option<IrSpan>,
464}
465
466/// Core operation node - the heart of the IR
467#[derive(Debug, Clone, Serialize, Deserialize)]
468#[serde(tag = "kind")]
469pub enum IrOperation {
470    // === Literals ===
471    #[serde(rename = "literal")]
472    Literal {
473        variant: LiteralVariant,
474        value: serde_json::Value,
475        #[serde(rename = "type")]
476        ty: IrType,
477        evidence: IrEvidence,
478    },
479
480    // === Variables ===
481    #[serde(rename = "var")]
482    Var {
483        name: String,
484        id: String,
485        #[serde(rename = "type")]
486        ty: IrType,
487        evidence: IrEvidence,
488    },
489
490    // === Bindings ===
491    #[serde(rename = "let")]
492    Let {
493        pattern: IrPattern,
494        #[serde(skip_serializing_if = "Option::is_none")]
495        type_annotation: Option<IrType>,
496        init: Box<IrOperation>,
497        evidence: IrEvidence,
498    },
499
500    // === Binary operations ===
501    #[serde(rename = "binary")]
502    Binary {
503        operator: BinaryOp,
504        left: Box<IrOperation>,
505        right: Box<IrOperation>,
506        #[serde(rename = "type")]
507        ty: IrType,
508        evidence: IrEvidence,
509    },
510
511    // === Unary operations ===
512    #[serde(rename = "unary")]
513    Unary {
514        operator: UnaryOp,
515        operand: Box<IrOperation>,
516        #[serde(rename = "type")]
517        ty: IrType,
518        evidence: IrEvidence,
519    },
520
521    // === Function calls ===
522    #[serde(rename = "call")]
523    Call {
524        function: String,
525        function_id: String,
526        args: Vec<IrOperation>,
527        #[serde(skip_serializing_if = "Vec::is_empty")]
528        type_args: Vec<IrType>,
529        #[serde(rename = "type")]
530        ty: IrType,
531        evidence: IrEvidence,
532    },
533
534    #[serde(rename = "method_call")]
535    MethodCall {
536        receiver: Box<IrOperation>,
537        method: String,
538        args: Vec<IrOperation>,
539        #[serde(skip_serializing_if = "Vec::is_empty")]
540        type_args: Vec<IrType>,
541        #[serde(rename = "type")]
542        ty: IrType,
543        evidence: IrEvidence,
544    },
545
546    // === Closures ===
547    #[serde(rename = "closure")]
548    Closure {
549        params: Vec<IrParam>,
550        body: Box<IrOperation>,
551        captures: Vec<String>,
552        #[serde(rename = "type")]
553        ty: IrType,
554        evidence: IrEvidence,
555    },
556
557    // === Control flow ===
558    #[serde(rename = "if")]
559    If {
560        condition: Box<IrOperation>,
561        then_branch: Box<IrOperation>,
562        #[serde(skip_serializing_if = "Option::is_none")]
563        else_branch: Option<Box<IrOperation>>,
564        #[serde(rename = "type")]
565        ty: IrType,
566        evidence: IrEvidence,
567    },
568
569    #[serde(rename = "match")]
570    Match {
571        scrutinee: Box<IrOperation>,
572        arms: Vec<IrMatchArm>,
573        #[serde(rename = "type")]
574        ty: IrType,
575        evidence: IrEvidence,
576    },
577
578    /// Pattern match used as a boolean condition in if-let/while-let expressions.
579    /// Returns true if the pattern matches, false otherwise.
580    /// Pattern bindings are extracted in the then-branch.
581    #[serde(rename = "let_match")]
582    LetMatch {
583        pattern: IrPattern,
584        value: Box<IrOperation>,
585        #[serde(rename = "type")]
586        ty: IrType,
587        evidence: IrEvidence,
588    },
589
590    #[serde(rename = "loop")]
591    Loop {
592        variant: LoopVariant,
593        #[serde(skip_serializing_if = "Option::is_none")]
594        condition: Option<Box<IrOperation>>,
595        #[serde(skip_serializing_if = "Option::is_none")]
596        iterator: Option<IrForIterator>,
597        body: Box<IrOperation>,
598        #[serde(rename = "type")]
599        ty: IrType,
600        evidence: IrEvidence,
601    },
602
603    #[serde(rename = "break")]
604    Break {
605        #[serde(skip_serializing_if = "Option::is_none")]
606        value: Option<Box<IrOperation>>,
607        evidence: IrEvidence,
608    },
609
610    #[serde(rename = "continue")]
611    Continue { evidence: IrEvidence },
612
613    #[serde(rename = "return")]
614    Return {
615        #[serde(skip_serializing_if = "Option::is_none")]
616        value: Option<Box<IrOperation>>,
617        evidence: IrEvidence,
618    },
619
620    // === Blocks ===
621    #[serde(rename = "block")]
622    Block {
623        statements: Vec<IrOperation>,
624        #[serde(rename = "type")]
625        ty: IrType,
626        evidence: IrEvidence,
627    },
628
629    // === Pipeline operations (core Sigil feature) ===
630    #[serde(rename = "pipeline")]
631    Pipeline {
632        input: Box<IrOperation>,
633        steps: Vec<IrPipelineStep>,
634        #[serde(rename = "type")]
635        ty: IrType,
636        evidence: IrEvidence,
637    },
638
639    // === Morpheme operations ===
640    #[serde(rename = "morpheme")]
641    Morpheme {
642        morpheme: MorphemeKind,
643        symbol: String,
644        input: Box<IrOperation>,
645        #[serde(skip_serializing_if = "Option::is_none")]
646        body: Option<Box<IrOperation>>,
647        #[serde(rename = "type")]
648        ty: IrType,
649        evidence: IrEvidence,
650    },
651
652    // === Fork/Join ===
653    #[serde(rename = "fork")]
654    Fork {
655        branches: Vec<IrOperation>,
656        join_strategy: JoinStrategy,
657        #[serde(rename = "type")]
658        ty: IrType,
659        evidence: IrEvidence,
660    },
661
662    #[serde(rename = "identity")]
663    Identity {
664        #[serde(rename = "type")]
665        ty: IrType,
666        evidence: IrEvidence,
667    },
668
669    // === Data structures ===
670    #[serde(rename = "array")]
671    Array {
672        elements: Vec<IrOperation>,
673        #[serde(rename = "type")]
674        ty: IrType,
675        evidence: IrEvidence,
676    },
677
678    #[serde(rename = "tuple")]
679    Tuple {
680        elements: Vec<IrOperation>,
681        #[serde(rename = "type")]
682        ty: IrType,
683        evidence: IrEvidence,
684    },
685
686    #[serde(rename = "struct_init")]
687    StructInit {
688        name: String,
689        fields: Vec<(String, IrOperation)>,
690        #[serde(skip_serializing_if = "Option::is_none")]
691        rest: Option<Box<IrOperation>>,
692        #[serde(rename = "type")]
693        ty: IrType,
694        evidence: IrEvidence,
695    },
696
697    // === Field/Index access ===
698    #[serde(rename = "field")]
699    Field {
700        expr: Box<IrOperation>,
701        field: String,
702        #[serde(rename = "type")]
703        ty: IrType,
704        evidence: IrEvidence,
705    },
706
707    #[serde(rename = "index")]
708    Index {
709        expr: Box<IrOperation>,
710        index: Box<IrOperation>,
711        #[serde(rename = "type")]
712        ty: IrType,
713        evidence: IrEvidence,
714    },
715
716    // === Assignment ===
717    #[serde(rename = "assign")]
718    Assign {
719        target: Box<IrOperation>,
720        value: Box<IrOperation>,
721        evidence: IrEvidence,
722    },
723
724    // === Evidentiality operations ===
725    #[serde(rename = "evidence_coerce")]
726    EvidenceCoerce {
727        operation: EvidenceOp,
728        expr: Box<IrOperation>,
729        from_evidence: IrEvidence,
730        to_evidence: IrEvidence,
731        #[serde(rename = "type")]
732        ty: IrType,
733    },
734
735    // === Incorporation (noun-verb fusion) ===
736    #[serde(rename = "incorporation")]
737    Incorporation {
738        segments: Vec<IncorporationSegment>,
739        args: Vec<IrOperation>,
740        #[serde(rename = "type")]
741        ty: IrType,
742        evidence: IrEvidence,
743    },
744
745    // === Affect (emotional markers) ===
746    #[serde(rename = "affect")]
747    Affect {
748        expr: Box<IrOperation>,
749        affect: IrAffect,
750        #[serde(rename = "type")]
751        ty: IrType,
752        evidence: IrEvidence,
753    },
754
755    // === Protocol operations ===
756    #[serde(rename = "http_request")]
757    HttpRequest {
758        method: HttpMethod,
759        url: Box<IrOperation>,
760        #[serde(skip_serializing_if = "Option::is_none")]
761        headers: Option<Box<IrOperation>>,
762        #[serde(skip_serializing_if = "Option::is_none")]
763        body: Option<Box<IrOperation>>,
764        #[serde(skip_serializing_if = "Option::is_none")]
765        timeout: Option<Box<IrOperation>>,
766        #[serde(rename = "type")]
767        ty: IrType,
768        evidence: IrEvidence,
769    },
770
771    #[serde(rename = "grpc_call")]
772    GrpcCall {
773        service: String,
774        method: String,
775        message: Box<IrOperation>,
776        #[serde(skip_serializing_if = "Option::is_none")]
777        metadata: Option<Box<IrOperation>>,
778        #[serde(skip_serializing_if = "Option::is_none")]
779        timeout: Option<Box<IrOperation>>,
780        #[serde(rename = "type")]
781        ty: IrType,
782        evidence: IrEvidence,
783    },
784
785    #[serde(rename = "websocket")]
786    WebSocket {
787        operation: WebSocketOp,
788        url: Box<IrOperation>,
789        #[serde(skip_serializing_if = "Option::is_none")]
790        message: Option<Box<IrOperation>>,
791        #[serde(rename = "type")]
792        ty: IrType,
793        evidence: IrEvidence,
794    },
795
796    #[serde(rename = "kafka_op")]
797    KafkaOp {
798        operation: KafkaOpKind,
799        topic: String,
800        #[serde(skip_serializing_if = "Option::is_none")]
801        payload: Option<Box<IrOperation>>,
802        #[serde(skip_serializing_if = "Option::is_none")]
803        key: Option<Box<IrOperation>>,
804        #[serde(rename = "type")]
805        ty: IrType,
806        evidence: IrEvidence,
807    },
808
809    // === Async ===
810    #[serde(rename = "await")]
811    Await {
812        expr: Box<IrOperation>,
813        #[serde(rename = "type")]
814        ty: IrType,
815        evidence: IrEvidence,
816    },
817
818    // === Unsafe ===
819    #[serde(rename = "unsafe")]
820    Unsafe {
821        body: Box<IrOperation>,
822        #[serde(rename = "type")]
823        ty: IrType,
824        evidence: IrEvidence,
825    },
826
827    // === Async ===
828    #[serde(rename = "async")]
829    Async {
830        body: Box<IrOperation>,
831        is_move: bool,
832        #[serde(rename = "type")]
833        ty: IrType,
834        evidence: IrEvidence,
835    },
836
837    // === Cast ===
838    #[serde(rename = "cast")]
839    Cast {
840        expr: Box<IrOperation>,
841        target_type: IrType,
842        #[serde(rename = "type")]
843        ty: IrType,
844        evidence: IrEvidence,
845    },
846
847    // === Try (? operator) ===
848    #[serde(rename = "try")]
849    Try {
850        expr: Box<IrOperation>,
851        #[serde(rename = "type")]
852        ty: IrType,
853        evidence: IrEvidence,
854    },
855}
856
857/// Literal variants
858#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
859#[serde(rename_all = "lowercase")]
860pub enum LiteralVariant {
861    Int,
862    Float,
863    Bool,
864    Char,
865    String,
866    Null,
867}
868
869/// Binary operators
870#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
871#[serde(rename_all = "snake_case")]
872pub enum BinaryOp {
873    Add,
874    Sub,
875    Mul,
876    Div,
877    Rem,
878    Pow,
879    And,
880    Or,
881    BitAnd,
882    BitOr,
883    BitXor,
884    Shl,
885    Shr,
886    Eq,
887    Ne,
888    Lt,
889    Le,
890    Gt,
891    Ge,
892    Concat,
893    MatMul,
894    Hadamard,
895    TensorProd,
896}
897
898/// Unary operators
899#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
900#[serde(rename_all = "snake_case")]
901pub enum UnaryOp {
902    Neg,
903    Not,
904    Deref,
905    Ref,
906    RefMut,
907}
908
909/// Loop variants
910#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
911#[serde(rename_all = "lowercase")]
912pub enum LoopVariant {
913    Infinite,
914    While,
915    For,
916}
917
918/// For loop iterator
919#[derive(Debug, Clone, Serialize, Deserialize)]
920pub struct IrForIterator {
921    pub pattern: IrPattern,
922    pub iterable: Box<IrOperation>,
923}
924
925/// Match arm
926#[derive(Debug, Clone, Serialize, Deserialize)]
927pub struct IrMatchArm {
928    pub pattern: IrPattern,
929    #[serde(skip_serializing_if = "Option::is_none")]
930    pub guard: Option<IrOperation>,
931    pub body: IrOperation,
932}
933
934/// Pattern in IR
935#[derive(Debug, Clone, Serialize, Deserialize)]
936#[serde(tag = "kind")]
937pub enum IrPattern {
938    #[serde(rename = "ident")]
939    Ident {
940        name: String,
941        mutable: bool,
942        #[serde(skip_serializing_if = "Option::is_none")]
943        evidence: Option<IrEvidence>,
944    },
945
946    #[serde(rename = "tuple")]
947    Tuple { elements: Vec<IrPattern> },
948
949    #[serde(rename = "struct")]
950    Struct {
951        path: String,
952        fields: Vec<(String, IrPattern)>,
953        rest: bool,
954    },
955
956    #[serde(rename = "tuple_struct")]
957    TupleStruct {
958        path: String,
959        fields: Vec<IrPattern>,
960    },
961
962    #[serde(rename = "slice")]
963    Slice { elements: Vec<IrPattern> },
964
965    #[serde(rename = "or")]
966    Or { patterns: Vec<IrPattern> },
967
968    #[serde(rename = "literal")]
969    Literal { value: serde_json::Value },
970
971    #[serde(rename = "range")]
972    Range {
973        #[serde(skip_serializing_if = "Option::is_none")]
974        start: Option<Box<IrPattern>>,
975        #[serde(skip_serializing_if = "Option::is_none")]
976        end: Option<Box<IrPattern>>,
977        inclusive: bool,
978    },
979
980    #[serde(rename = "wildcard")]
981    Wildcard,
982}
983
984/// Pipeline step
985#[derive(Debug, Clone, Serialize, Deserialize)]
986#[serde(tag = "op")]
987pub enum IrPipelineStep {
988    #[serde(rename = "call")]
989    Call {
990        #[serde(rename = "fn")]
991        function: String,
992        args: Vec<IrOperation>,
993    },
994
995    #[serde(rename = "morpheme")]
996    Morpheme {
997        morpheme: MorphemeKind,
998        symbol: String,
999        #[serde(skip_serializing_if = "Option::is_none")]
1000        body: Option<Box<IrOperation>>,
1001    },
1002
1003    #[serde(rename = "fork")]
1004    Fork { branches: Vec<IrPipelineStep> },
1005
1006    #[serde(rename = "identity")]
1007    Identity,
1008
1009    #[serde(rename = "method")]
1010    Method {
1011        name: String,
1012        args: Vec<IrOperation>,
1013    },
1014
1015    #[serde(rename = "await")]
1016    Await,
1017
1018    #[serde(rename = "protocol")]
1019    Protocol {
1020        operation: ProtocolOp,
1021        #[serde(skip_serializing_if = "Option::is_none")]
1022        config: Option<Box<IrOperation>>,
1023    },
1024}
1025
1026/// Morpheme kinds
1027#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1028#[serde(rename_all = "lowercase")]
1029pub enum MorphemeKind {
1030    Transform,
1031    Filter,
1032    Sort,
1033    Reduce,
1034    Lambda,
1035    Sum,
1036    Product,
1037    Min,
1038    Max,
1039    Concat,
1040    All,
1041    Any,
1042    First,
1043    Last,
1044    Middle,
1045    Choice,
1046    Nth,
1047    Next,
1048}
1049
1050impl MorphemeKind {
1051    pub fn symbol(&self) -> &'static str {
1052        match self {
1053            MorphemeKind::Transform => "τ",
1054            MorphemeKind::Filter => "φ",
1055            MorphemeKind::Sort => "σ",
1056            MorphemeKind::Reduce => "ρ",
1057            MorphemeKind::Lambda => "λ",
1058            MorphemeKind::Sum => "Σ",
1059            MorphemeKind::Product => "Π",
1060            MorphemeKind::Min => "ρ_min",
1061            MorphemeKind::Max => "ρ_max",
1062            MorphemeKind::Concat => "ρ++",
1063            MorphemeKind::All => "ρ&",
1064            MorphemeKind::Any => "ρ|",
1065            MorphemeKind::First => "α",
1066            MorphemeKind::Last => "ω",
1067            MorphemeKind::Middle => "μ",
1068            MorphemeKind::Choice => "χ",
1069            MorphemeKind::Nth => "ν",
1070            MorphemeKind::Next => "ξ",
1071        }
1072    }
1073}
1074
1075/// Join strategy for fork operations
1076#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1077#[serde(rename_all = "lowercase")]
1078pub enum JoinStrategy {
1079    Tuple,
1080    First,
1081    All,
1082    Race,
1083}
1084
1085/// Evidence operations
1086#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1087#[serde(rename_all = "lowercase")]
1088pub enum EvidenceOp {
1089    Trust,
1090    Verify,
1091    Mark,
1092}
1093
1094/// Incorporation segment (noun-verb)
1095#[derive(Debug, Clone, Serialize, Deserialize)]
1096#[serde(tag = "kind")]
1097pub enum IncorporationSegment {
1098    #[serde(rename = "noun")]
1099    Noun { name: String },
1100    #[serde(rename = "verb")]
1101    Verb { name: String },
1102}
1103
1104/// Affect markers
1105#[derive(Debug, Clone, Serialize, Deserialize)]
1106pub struct IrAffect {
1107    #[serde(skip_serializing_if = "Option::is_none")]
1108    pub sentiment: Option<Sentiment>,
1109    #[serde(skip_serializing_if = "Option::is_none")]
1110    pub intensity: Option<Intensity>,
1111    #[serde(skip_serializing_if = "Option::is_none")]
1112    pub formality: Option<Formality>,
1113    #[serde(skip_serializing_if = "Option::is_none")]
1114    pub emotion: Option<Emotion>,
1115    #[serde(skip_serializing_if = "Option::is_none")]
1116    pub confidence: Option<Confidence>,
1117    #[serde(default)]
1118    pub sarcasm: bool,
1119}
1120
1121#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1122#[serde(rename_all = "lowercase")]
1123pub enum Sentiment {
1124    Positive,
1125    Negative,
1126    Neutral,
1127}
1128
1129#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1130#[serde(rename_all = "lowercase")]
1131pub enum Intensity {
1132    Up,
1133    Down,
1134    Max,
1135}
1136
1137#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1138#[serde(rename_all = "lowercase")]
1139pub enum Formality {
1140    Formal,
1141    Informal,
1142}
1143
1144#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1145#[serde(rename_all = "lowercase")]
1146pub enum Emotion {
1147    Joy,
1148    Sadness,
1149    Anger,
1150    Fear,
1151    Surprise,
1152    Love,
1153}
1154
1155#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1156#[serde(rename_all = "lowercase")]
1157pub enum Confidence {
1158    High,
1159    Medium,
1160    Low,
1161}
1162
1163/// HTTP methods
1164#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1165#[serde(rename_all = "UPPERCASE")]
1166pub enum HttpMethod {
1167    Get,
1168    Post,
1169    Put,
1170    Delete,
1171    Patch,
1172    Head,
1173    Options,
1174    Connect,
1175    Trace,
1176}
1177
1178/// WebSocket operations
1179#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1180#[serde(rename_all = "lowercase")]
1181pub enum WebSocketOp {
1182    Connect,
1183    Send,
1184    Receive,
1185    Close,
1186}
1187
1188/// Kafka operations
1189#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1190#[serde(rename_all = "lowercase")]
1191pub enum KafkaOpKind {
1192    Produce,
1193    Consume,
1194    Subscribe,
1195    Unsubscribe,
1196    Commit,
1197    Seek,
1198}
1199
1200/// Protocol operations for pipeline
1201#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1202#[serde(rename_all = "lowercase")]
1203pub enum ProtocolOp {
1204    Send,
1205    Recv,
1206    Stream,
1207    Connect,
1208    Close,
1209    Timeout,
1210    Retry,
1211}
1212
1213/// Configuration options for IR dump
1214#[derive(Debug, Clone, Default)]
1215pub struct IrDumpOptions {
1216    /// Pretty-print JSON output
1217    pub pretty: bool,
1218    /// Include full type information on every node
1219    pub full_types: bool,
1220    /// Include source spans
1221    pub include_spans: bool,
1222    /// Optimization level to apply before dumping
1223    pub opt_level: Option<u8>,
1224}
1225
1226impl IrModule {
1227    /// Serialize to JSON string
1228    pub fn to_json(&self, pretty: bool) -> Result<String, serde_json::Error> {
1229        if pretty {
1230            serde_json::to_string_pretty(self)
1231        } else {
1232            serde_json::to_string(self)
1233        }
1234    }
1235
1236    /// Deserialize from JSON string
1237    pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
1238        serde_json::from_str(json)
1239    }
1240}
1241
1242#[cfg(test)]
1243mod tests {
1244    use super::*;
1245
1246    #[test]
1247    fn test_evidence_join() {
1248        assert_eq!(IrEvidence::Known.join(IrEvidence::Known), IrEvidence::Known);
1249        assert_eq!(
1250            IrEvidence::Known.join(IrEvidence::Uncertain),
1251            IrEvidence::Uncertain
1252        );
1253        assert_eq!(
1254            IrEvidence::Known.join(IrEvidence::Reported),
1255            IrEvidence::Reported
1256        );
1257        assert_eq!(
1258            IrEvidence::Known.join(IrEvidence::Paradox),
1259            IrEvidence::Paradox
1260        );
1261        assert_eq!(
1262            IrEvidence::Reported.join(IrEvidence::Paradox),
1263            IrEvidence::Paradox
1264        );
1265    }
1266
1267    #[test]
1268    fn test_evidence_meet() {
1269        assert_eq!(
1270            IrEvidence::Paradox.meet(IrEvidence::Paradox),
1271            IrEvidence::Paradox
1272        );
1273        assert_eq!(
1274            IrEvidence::Paradox.meet(IrEvidence::Reported),
1275            IrEvidence::Reported
1276        );
1277        assert_eq!(
1278            IrEvidence::Paradox.meet(IrEvidence::Uncertain),
1279            IrEvidence::Uncertain
1280        );
1281        assert_eq!(
1282            IrEvidence::Paradox.meet(IrEvidence::Known),
1283            IrEvidence::Known
1284        );
1285    }
1286
1287    #[test]
1288    fn test_ir_serialization() {
1289        let module = IrModule::new("test.sigil".to_string());
1290        let json = module.to_json(false).unwrap();
1291        let parsed: IrModule = IrModule::from_json(&json).unwrap();
1292        assert_eq!(parsed.version, IR_VERSION);
1293        assert_eq!(parsed.source, "test.sigil");
1294    }
1295
1296    #[test]
1297    fn test_morpheme_symbols() {
1298        assert_eq!(MorphemeKind::Transform.symbol(), "τ");
1299        assert_eq!(MorphemeKind::Filter.symbol(), "φ");
1300        assert_eq!(MorphemeKind::Reduce.symbol(), "ρ");
1301    }
1302}