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 { lifetime: Option<String>, mutable: bool, inner: Box<IrType> },
298
299    /// Pointer *const T or *mut T
300    #[serde(rename = "pointer")]
301    Pointer { mutable: bool, inner: Box<IrType> },
302
303    /// Function type fn(A, B) -> C
304    #[serde(rename = "function")]
305    Function {
306        params: Vec<IrType>,
307        return_type: Box<IrType>,
308        is_async: bool,
309    },
310
311    /// Evidential wrapper E<T> with evidence level
312    #[serde(rename = "evidential")]
313    Evidential {
314        inner: Box<IrType>,
315        evidence: IrEvidence,
316    },
317
318    /// Cyclic arithmetic type Z/nZ
319    #[serde(rename = "cycle")]
320    Cycle { modulus: u64 },
321
322    /// SIMD vector type
323    #[serde(rename = "simd")]
324    Simd { element: Box<IrType>, lanes: usize },
325
326    /// Atomic type
327    #[serde(rename = "atomic")]
328    Atomic { inner: Box<IrType> },
329
330    /// Type variable (for inference)
331    #[serde(rename = "var")]
332    Var { id: String },
333
334    /// Infer placeholder _
335    #[serde(rename = "infer")]
336    Infer,
337
338    /// Lifetime bound 'static, 'a
339    #[serde(rename = "lifetime")]
340    Lifetime { name: String },
341
342    /// Trait object: dyn Trait
343    #[serde(rename = "trait_object")]
344    TraitObject { bounds: Vec<IrType> },
345
346    /// Higher-ranked trait bound: for<'a> Trait<'a>
347    #[serde(rename = "hrtb")]
348    Hrtb {
349        lifetimes: Vec<String>,
350        bound: Box<IrType>,
351    },
352
353    /// Inline struct type: struct { field: Type, ... }
354    #[serde(rename = "inline_struct")]
355    InlineStruct {
356        fields: Vec<(String, IrType)>,
357    },
358
359    /// Impl trait: impl Trait bounds
360    #[serde(rename = "impl_trait")]
361    ImplTrait { bounds: Vec<IrType> },
362
363    /// Inline enum type: enum { Variant1, Variant2, ... }
364    #[serde(rename = "inline_enum")]
365    InlineEnum { variants: Vec<String> },
366
367    /// Associated type binding: Output = Type
368    #[serde(rename = "assoc_type_binding")]
369    AssocTypeBinding { name: String, ty: Box<IrType> },
370
371    /// Error recovery type
372    #[serde(rename = "error")]
373    Error,
374}
375
376impl Default for IrType {
377    fn default() -> Self {
378        IrType::Unit
379    }
380}
381
382/// Type definition (struct, enum)
383#[derive(Debug, Clone, Serialize, Deserialize)]
384#[serde(tag = "kind")]
385pub enum IrTypeDef {
386    #[serde(rename = "struct_def")]
387    Struct {
388        name: String,
389        generics: Vec<IrGenericParam>,
390        fields: Vec<IrField>,
391        #[serde(skip_serializing_if = "Option::is_none")]
392        span: Option<IrSpan>,
393    },
394    #[serde(rename = "enum_def")]
395    Enum {
396        name: String,
397        generics: Vec<IrGenericParam>,
398        variants: Vec<IrVariant>,
399        #[serde(skip_serializing_if = "Option::is_none")]
400        span: Option<IrSpan>,
401    },
402    #[serde(rename = "type_alias")]
403    TypeAlias {
404        name: String,
405        generics: Vec<IrGenericParam>,
406        target: IrType,
407        #[serde(skip_serializing_if = "Option::is_none")]
408        span: Option<IrSpan>,
409    },
410}
411
412/// A struct field
413#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct IrField {
415    pub name: String,
416    #[serde(rename = "type")]
417    pub ty: IrType,
418    pub visibility: IrVisibility,
419}
420
421/// An enum variant
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct IrVariant {
424    pub name: String,
425    pub fields: Option<Vec<IrField>>,
426    pub discriminant: Option<i64>,
427}
428
429/// Trait definition
430#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct IrTraitDef {
432    pub name: String,
433    pub generics: Vec<IrGenericParam>,
434    pub super_traits: Vec<String>,
435    pub methods: Vec<IrFunction>,
436    #[serde(skip_serializing_if = "Option::is_none")]
437    pub span: Option<IrSpan>,
438}
439
440/// Impl block
441#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct IrImplBlock {
443    #[serde(skip_serializing_if = "Option::is_none")]
444    pub trait_name: Option<String>,
445    pub target_type: IrType,
446    pub generics: Vec<IrGenericParam>,
447    pub methods: Vec<IrFunction>,
448    #[serde(skip_serializing_if = "Option::is_none")]
449    pub span: Option<IrSpan>,
450}
451
452/// Constant definition
453#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct IrConstant {
455    pub name: String,
456    #[serde(rename = "type")]
457    pub ty: IrType,
458    pub value: IrOperation,
459    pub visibility: IrVisibility,
460    #[serde(skip_serializing_if = "Option::is_none")]
461    pub span: Option<IrSpan>,
462}
463
464/// Core operation node - the heart of the IR
465#[derive(Debug, Clone, Serialize, Deserialize)]
466#[serde(tag = "kind")]
467pub enum IrOperation {
468    // === Literals ===
469    #[serde(rename = "literal")]
470    Literal {
471        variant: LiteralVariant,
472        value: serde_json::Value,
473        #[serde(rename = "type")]
474        ty: IrType,
475        evidence: IrEvidence,
476    },
477
478    // === Variables ===
479    #[serde(rename = "var")]
480    Var {
481        name: String,
482        id: String,
483        #[serde(rename = "type")]
484        ty: IrType,
485        evidence: IrEvidence,
486    },
487
488    // === Bindings ===
489    #[serde(rename = "let")]
490    Let {
491        pattern: IrPattern,
492        #[serde(skip_serializing_if = "Option::is_none")]
493        type_annotation: Option<IrType>,
494        init: Box<IrOperation>,
495        evidence: IrEvidence,
496    },
497
498    // === Binary operations ===
499    #[serde(rename = "binary")]
500    Binary {
501        operator: BinaryOp,
502        left: Box<IrOperation>,
503        right: Box<IrOperation>,
504        #[serde(rename = "type")]
505        ty: IrType,
506        evidence: IrEvidence,
507    },
508
509    // === Unary operations ===
510    #[serde(rename = "unary")]
511    Unary {
512        operator: UnaryOp,
513        operand: Box<IrOperation>,
514        #[serde(rename = "type")]
515        ty: IrType,
516        evidence: IrEvidence,
517    },
518
519    // === Function calls ===
520    #[serde(rename = "call")]
521    Call {
522        function: String,
523        function_id: String,
524        args: Vec<IrOperation>,
525        #[serde(skip_serializing_if = "Vec::is_empty")]
526        type_args: Vec<IrType>,
527        #[serde(rename = "type")]
528        ty: IrType,
529        evidence: IrEvidence,
530    },
531
532    #[serde(rename = "method_call")]
533    MethodCall {
534        receiver: Box<IrOperation>,
535        method: String,
536        args: Vec<IrOperation>,
537        #[serde(skip_serializing_if = "Vec::is_empty")]
538        type_args: Vec<IrType>,
539        #[serde(rename = "type")]
540        ty: IrType,
541        evidence: IrEvidence,
542    },
543
544    // === Closures ===
545    #[serde(rename = "closure")]
546    Closure {
547        params: Vec<IrParam>,
548        body: Box<IrOperation>,
549        captures: Vec<String>,
550        #[serde(rename = "type")]
551        ty: IrType,
552        evidence: IrEvidence,
553    },
554
555    // === Control flow ===
556    #[serde(rename = "if")]
557    If {
558        condition: Box<IrOperation>,
559        then_branch: Box<IrOperation>,
560        #[serde(skip_serializing_if = "Option::is_none")]
561        else_branch: Option<Box<IrOperation>>,
562        #[serde(rename = "type")]
563        ty: IrType,
564        evidence: IrEvidence,
565    },
566
567    #[serde(rename = "match")]
568    Match {
569        scrutinee: Box<IrOperation>,
570        arms: Vec<IrMatchArm>,
571        #[serde(rename = "type")]
572        ty: IrType,
573        evidence: IrEvidence,
574    },
575
576    /// Pattern match used as a boolean condition in if-let/while-let expressions.
577    /// Returns true if the pattern matches, false otherwise.
578    /// Pattern bindings are extracted in the then-branch.
579    #[serde(rename = "let_match")]
580    LetMatch {
581        pattern: IrPattern,
582        value: Box<IrOperation>,
583        #[serde(rename = "type")]
584        ty: IrType,
585        evidence: IrEvidence,
586    },
587
588    #[serde(rename = "loop")]
589    Loop {
590        variant: LoopVariant,
591        #[serde(skip_serializing_if = "Option::is_none")]
592        condition: Option<Box<IrOperation>>,
593        #[serde(skip_serializing_if = "Option::is_none")]
594        iterator: Option<IrForIterator>,
595        body: Box<IrOperation>,
596        #[serde(rename = "type")]
597        ty: IrType,
598        evidence: IrEvidence,
599    },
600
601    #[serde(rename = "break")]
602    Break {
603        #[serde(skip_serializing_if = "Option::is_none")]
604        value: Option<Box<IrOperation>>,
605        evidence: IrEvidence,
606    },
607
608    #[serde(rename = "continue")]
609    Continue { evidence: IrEvidence },
610
611    #[serde(rename = "return")]
612    Return {
613        #[serde(skip_serializing_if = "Option::is_none")]
614        value: Option<Box<IrOperation>>,
615        evidence: IrEvidence,
616    },
617
618    // === Blocks ===
619    #[serde(rename = "block")]
620    Block {
621        statements: Vec<IrOperation>,
622        #[serde(rename = "type")]
623        ty: IrType,
624        evidence: IrEvidence,
625    },
626
627    // === Pipeline operations (core Sigil feature) ===
628    #[serde(rename = "pipeline")]
629    Pipeline {
630        input: Box<IrOperation>,
631        steps: Vec<IrPipelineStep>,
632        #[serde(rename = "type")]
633        ty: IrType,
634        evidence: IrEvidence,
635    },
636
637    // === Morpheme operations ===
638    #[serde(rename = "morpheme")]
639    Morpheme {
640        morpheme: MorphemeKind,
641        symbol: String,
642        input: Box<IrOperation>,
643        #[serde(skip_serializing_if = "Option::is_none")]
644        body: Option<Box<IrOperation>>,
645        #[serde(rename = "type")]
646        ty: IrType,
647        evidence: IrEvidence,
648    },
649
650    // === Fork/Join ===
651    #[serde(rename = "fork")]
652    Fork {
653        branches: Vec<IrOperation>,
654        join_strategy: JoinStrategy,
655        #[serde(rename = "type")]
656        ty: IrType,
657        evidence: IrEvidence,
658    },
659
660    #[serde(rename = "identity")]
661    Identity {
662        #[serde(rename = "type")]
663        ty: IrType,
664        evidence: IrEvidence,
665    },
666
667    // === Data structures ===
668    #[serde(rename = "array")]
669    Array {
670        elements: Vec<IrOperation>,
671        #[serde(rename = "type")]
672        ty: IrType,
673        evidence: IrEvidence,
674    },
675
676    #[serde(rename = "tuple")]
677    Tuple {
678        elements: Vec<IrOperation>,
679        #[serde(rename = "type")]
680        ty: IrType,
681        evidence: IrEvidence,
682    },
683
684    #[serde(rename = "struct_init")]
685    StructInit {
686        name: String,
687        fields: Vec<(String, IrOperation)>,
688        #[serde(skip_serializing_if = "Option::is_none")]
689        rest: Option<Box<IrOperation>>,
690        #[serde(rename = "type")]
691        ty: IrType,
692        evidence: IrEvidence,
693    },
694
695    // === Field/Index access ===
696    #[serde(rename = "field")]
697    Field {
698        expr: Box<IrOperation>,
699        field: String,
700        #[serde(rename = "type")]
701        ty: IrType,
702        evidence: IrEvidence,
703    },
704
705    #[serde(rename = "index")]
706    Index {
707        expr: Box<IrOperation>,
708        index: Box<IrOperation>,
709        #[serde(rename = "type")]
710        ty: IrType,
711        evidence: IrEvidence,
712    },
713
714    // === Assignment ===
715    #[serde(rename = "assign")]
716    Assign {
717        target: Box<IrOperation>,
718        value: Box<IrOperation>,
719        evidence: IrEvidence,
720    },
721
722    // === Evidentiality operations ===
723    #[serde(rename = "evidence_coerce")]
724    EvidenceCoerce {
725        operation: EvidenceOp,
726        expr: Box<IrOperation>,
727        from_evidence: IrEvidence,
728        to_evidence: IrEvidence,
729        #[serde(rename = "type")]
730        ty: IrType,
731    },
732
733    // === Incorporation (noun-verb fusion) ===
734    #[serde(rename = "incorporation")]
735    Incorporation {
736        segments: Vec<IncorporationSegment>,
737        args: Vec<IrOperation>,
738        #[serde(rename = "type")]
739        ty: IrType,
740        evidence: IrEvidence,
741    },
742
743    // === Affect (emotional markers) ===
744    #[serde(rename = "affect")]
745    Affect {
746        expr: Box<IrOperation>,
747        affect: IrAffect,
748        #[serde(rename = "type")]
749        ty: IrType,
750        evidence: IrEvidence,
751    },
752
753    // === Protocol operations ===
754    #[serde(rename = "http_request")]
755    HttpRequest {
756        method: HttpMethod,
757        url: Box<IrOperation>,
758        #[serde(skip_serializing_if = "Option::is_none")]
759        headers: Option<Box<IrOperation>>,
760        #[serde(skip_serializing_if = "Option::is_none")]
761        body: Option<Box<IrOperation>>,
762        #[serde(skip_serializing_if = "Option::is_none")]
763        timeout: Option<Box<IrOperation>>,
764        #[serde(rename = "type")]
765        ty: IrType,
766        evidence: IrEvidence,
767    },
768
769    #[serde(rename = "grpc_call")]
770    GrpcCall {
771        service: String,
772        method: String,
773        message: Box<IrOperation>,
774        #[serde(skip_serializing_if = "Option::is_none")]
775        metadata: Option<Box<IrOperation>>,
776        #[serde(skip_serializing_if = "Option::is_none")]
777        timeout: Option<Box<IrOperation>>,
778        #[serde(rename = "type")]
779        ty: IrType,
780        evidence: IrEvidence,
781    },
782
783    #[serde(rename = "websocket")]
784    WebSocket {
785        operation: WebSocketOp,
786        url: Box<IrOperation>,
787        #[serde(skip_serializing_if = "Option::is_none")]
788        message: Option<Box<IrOperation>>,
789        #[serde(rename = "type")]
790        ty: IrType,
791        evidence: IrEvidence,
792    },
793
794    #[serde(rename = "kafka_op")]
795    KafkaOp {
796        operation: KafkaOpKind,
797        topic: String,
798        #[serde(skip_serializing_if = "Option::is_none")]
799        payload: Option<Box<IrOperation>>,
800        #[serde(skip_serializing_if = "Option::is_none")]
801        key: Option<Box<IrOperation>>,
802        #[serde(rename = "type")]
803        ty: IrType,
804        evidence: IrEvidence,
805    },
806
807    // === Async ===
808    #[serde(rename = "await")]
809    Await {
810        expr: Box<IrOperation>,
811        #[serde(rename = "type")]
812        ty: IrType,
813        evidence: IrEvidence,
814    },
815
816    // === Unsafe ===
817    #[serde(rename = "unsafe")]
818    Unsafe {
819        body: Box<IrOperation>,
820        #[serde(rename = "type")]
821        ty: IrType,
822        evidence: IrEvidence,
823    },
824
825    // === Async ===
826    #[serde(rename = "async")]
827    Async {
828        body: Box<IrOperation>,
829        is_move: bool,
830        #[serde(rename = "type")]
831        ty: IrType,
832        evidence: IrEvidence,
833    },
834
835    // === Cast ===
836    #[serde(rename = "cast")]
837    Cast {
838        expr: Box<IrOperation>,
839        target_type: IrType,
840        #[serde(rename = "type")]
841        ty: IrType,
842        evidence: IrEvidence,
843    },
844
845    // === Try (? operator) ===
846    #[serde(rename = "try")]
847    Try {
848        expr: Box<IrOperation>,
849        #[serde(rename = "type")]
850        ty: IrType,
851        evidence: IrEvidence,
852    },
853}
854
855/// Literal variants
856#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
857#[serde(rename_all = "lowercase")]
858pub enum LiteralVariant {
859    Int,
860    Float,
861    Bool,
862    Char,
863    String,
864    Null,
865}
866
867/// Binary operators
868#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
869#[serde(rename_all = "snake_case")]
870pub enum BinaryOp {
871    Add,
872    Sub,
873    Mul,
874    Div,
875    Rem,
876    Pow,
877    And,
878    Or,
879    BitAnd,
880    BitOr,
881    BitXor,
882    Shl,
883    Shr,
884    Eq,
885    Ne,
886    Lt,
887    Le,
888    Gt,
889    Ge,
890    Concat,
891    MatMul,
892    Hadamard,
893    TensorProd,
894}
895
896/// Unary operators
897#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
898#[serde(rename_all = "snake_case")]
899pub enum UnaryOp {
900    Neg,
901    Not,
902    Deref,
903    Ref,
904    RefMut,
905}
906
907/// Loop variants
908#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
909#[serde(rename_all = "lowercase")]
910pub enum LoopVariant {
911    Infinite,
912    While,
913    For,
914}
915
916/// For loop iterator
917#[derive(Debug, Clone, Serialize, Deserialize)]
918pub struct IrForIterator {
919    pub pattern: IrPattern,
920    pub iterable: Box<IrOperation>,
921}
922
923/// Match arm
924#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct IrMatchArm {
926    pub pattern: IrPattern,
927    #[serde(skip_serializing_if = "Option::is_none")]
928    pub guard: Option<IrOperation>,
929    pub body: IrOperation,
930}
931
932/// Pattern in IR
933#[derive(Debug, Clone, Serialize, Deserialize)]
934#[serde(tag = "kind")]
935pub enum IrPattern {
936    #[serde(rename = "ident")]
937    Ident {
938        name: String,
939        mutable: bool,
940        #[serde(skip_serializing_if = "Option::is_none")]
941        evidence: Option<IrEvidence>,
942    },
943
944    #[serde(rename = "tuple")]
945    Tuple { elements: Vec<IrPattern> },
946
947    #[serde(rename = "struct")]
948    Struct {
949        path: String,
950        fields: Vec<(String, IrPattern)>,
951        rest: bool,
952    },
953
954    #[serde(rename = "tuple_struct")]
955    TupleStruct {
956        path: String,
957        fields: Vec<IrPattern>,
958    },
959
960    #[serde(rename = "slice")]
961    Slice { elements: Vec<IrPattern> },
962
963    #[serde(rename = "or")]
964    Or { patterns: Vec<IrPattern> },
965
966    #[serde(rename = "literal")]
967    Literal { value: serde_json::Value },
968
969    #[serde(rename = "range")]
970    Range {
971        #[serde(skip_serializing_if = "Option::is_none")]
972        start: Option<Box<IrPattern>>,
973        #[serde(skip_serializing_if = "Option::is_none")]
974        end: Option<Box<IrPattern>>,
975        inclusive: bool,
976    },
977
978    #[serde(rename = "wildcard")]
979    Wildcard,
980}
981
982/// Pipeline step
983#[derive(Debug, Clone, Serialize, Deserialize)]
984#[serde(tag = "op")]
985pub enum IrPipelineStep {
986    #[serde(rename = "call")]
987    Call {
988        #[serde(rename = "fn")]
989        function: String,
990        args: Vec<IrOperation>,
991    },
992
993    #[serde(rename = "morpheme")]
994    Morpheme {
995        morpheme: MorphemeKind,
996        symbol: String,
997        #[serde(skip_serializing_if = "Option::is_none")]
998        body: Option<Box<IrOperation>>,
999    },
1000
1001    #[serde(rename = "fork")]
1002    Fork { branches: Vec<IrPipelineStep> },
1003
1004    #[serde(rename = "identity")]
1005    Identity,
1006
1007    #[serde(rename = "method")]
1008    Method {
1009        name: String,
1010        args: Vec<IrOperation>,
1011    },
1012
1013    #[serde(rename = "await")]
1014    Await,
1015
1016    #[serde(rename = "protocol")]
1017    Protocol {
1018        operation: ProtocolOp,
1019        #[serde(skip_serializing_if = "Option::is_none")]
1020        config: Option<Box<IrOperation>>,
1021    },
1022}
1023
1024/// Morpheme kinds
1025#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1026#[serde(rename_all = "lowercase")]
1027pub enum MorphemeKind {
1028    Transform,
1029    Filter,
1030    Sort,
1031    Reduce,
1032    Lambda,
1033    Sum,
1034    Product,
1035    Min,
1036    Max,
1037    Concat,
1038    All,
1039    Any,
1040    First,
1041    Last,
1042    Middle,
1043    Choice,
1044    Nth,
1045    Next,
1046}
1047
1048impl MorphemeKind {
1049    pub fn symbol(&self) -> &'static str {
1050        match self {
1051            MorphemeKind::Transform => "τ",
1052            MorphemeKind::Filter => "φ",
1053            MorphemeKind::Sort => "σ",
1054            MorphemeKind::Reduce => "ρ",
1055            MorphemeKind::Lambda => "λ",
1056            MorphemeKind::Sum => "Σ",
1057            MorphemeKind::Product => "Π",
1058            MorphemeKind::Min => "ρ_min",
1059            MorphemeKind::Max => "ρ_max",
1060            MorphemeKind::Concat => "ρ++",
1061            MorphemeKind::All => "ρ&",
1062            MorphemeKind::Any => "ρ|",
1063            MorphemeKind::First => "α",
1064            MorphemeKind::Last => "ω",
1065            MorphemeKind::Middle => "μ",
1066            MorphemeKind::Choice => "χ",
1067            MorphemeKind::Nth => "ν",
1068            MorphemeKind::Next => "ξ",
1069        }
1070    }
1071}
1072
1073/// Join strategy for fork operations
1074#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1075#[serde(rename_all = "lowercase")]
1076pub enum JoinStrategy {
1077    Tuple,
1078    First,
1079    All,
1080    Race,
1081}
1082
1083/// Evidence operations
1084#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1085#[serde(rename_all = "lowercase")]
1086pub enum EvidenceOp {
1087    Trust,
1088    Verify,
1089    Mark,
1090}
1091
1092/// Incorporation segment (noun-verb)
1093#[derive(Debug, Clone, Serialize, Deserialize)]
1094#[serde(tag = "kind")]
1095pub enum IncorporationSegment {
1096    #[serde(rename = "noun")]
1097    Noun { name: String },
1098    #[serde(rename = "verb")]
1099    Verb { name: String },
1100}
1101
1102/// Affect markers
1103#[derive(Debug, Clone, Serialize, Deserialize)]
1104pub struct IrAffect {
1105    #[serde(skip_serializing_if = "Option::is_none")]
1106    pub sentiment: Option<Sentiment>,
1107    #[serde(skip_serializing_if = "Option::is_none")]
1108    pub intensity: Option<Intensity>,
1109    #[serde(skip_serializing_if = "Option::is_none")]
1110    pub formality: Option<Formality>,
1111    #[serde(skip_serializing_if = "Option::is_none")]
1112    pub emotion: Option<Emotion>,
1113    #[serde(skip_serializing_if = "Option::is_none")]
1114    pub confidence: Option<Confidence>,
1115    #[serde(default)]
1116    pub sarcasm: bool,
1117}
1118
1119#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1120#[serde(rename_all = "lowercase")]
1121pub enum Sentiment {
1122    Positive,
1123    Negative,
1124    Neutral,
1125}
1126
1127#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1128#[serde(rename_all = "lowercase")]
1129pub enum Intensity {
1130    Up,
1131    Down,
1132    Max,
1133}
1134
1135#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1136#[serde(rename_all = "lowercase")]
1137pub enum Formality {
1138    Formal,
1139    Informal,
1140}
1141
1142#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1143#[serde(rename_all = "lowercase")]
1144pub enum Emotion {
1145    Joy,
1146    Sadness,
1147    Anger,
1148    Fear,
1149    Surprise,
1150    Love,
1151}
1152
1153#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1154#[serde(rename_all = "lowercase")]
1155pub enum Confidence {
1156    High,
1157    Medium,
1158    Low,
1159}
1160
1161/// HTTP methods
1162#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1163#[serde(rename_all = "UPPERCASE")]
1164pub enum HttpMethod {
1165    Get,
1166    Post,
1167    Put,
1168    Delete,
1169    Patch,
1170    Head,
1171    Options,
1172    Connect,
1173    Trace,
1174}
1175
1176/// WebSocket operations
1177#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1178#[serde(rename_all = "lowercase")]
1179pub enum WebSocketOp {
1180    Connect,
1181    Send,
1182    Receive,
1183    Close,
1184}
1185
1186/// Kafka operations
1187#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1188#[serde(rename_all = "lowercase")]
1189pub enum KafkaOpKind {
1190    Produce,
1191    Consume,
1192    Subscribe,
1193    Unsubscribe,
1194    Commit,
1195    Seek,
1196}
1197
1198/// Protocol operations for pipeline
1199#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1200#[serde(rename_all = "lowercase")]
1201pub enum ProtocolOp {
1202    Send,
1203    Recv,
1204    Stream,
1205    Connect,
1206    Close,
1207    Timeout,
1208    Retry,
1209}
1210
1211/// Configuration options for IR dump
1212#[derive(Debug, Clone, Default)]
1213pub struct IrDumpOptions {
1214    /// Pretty-print JSON output
1215    pub pretty: bool,
1216    /// Include full type information on every node
1217    pub full_types: bool,
1218    /// Include source spans
1219    pub include_spans: bool,
1220    /// Optimization level to apply before dumping
1221    pub opt_level: Option<u8>,
1222}
1223
1224impl IrModule {
1225    /// Serialize to JSON string
1226    pub fn to_json(&self, pretty: bool) -> Result<String, serde_json::Error> {
1227        if pretty {
1228            serde_json::to_string_pretty(self)
1229        } else {
1230            serde_json::to_string(self)
1231        }
1232    }
1233
1234    /// Deserialize from JSON string
1235    pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
1236        serde_json::from_str(json)
1237    }
1238}
1239
1240#[cfg(test)]
1241mod tests {
1242    use super::*;
1243
1244    #[test]
1245    fn test_evidence_join() {
1246        assert_eq!(IrEvidence::Known.join(IrEvidence::Known), IrEvidence::Known);
1247        assert_eq!(
1248            IrEvidence::Known.join(IrEvidence::Uncertain),
1249            IrEvidence::Uncertain
1250        );
1251        assert_eq!(
1252            IrEvidence::Known.join(IrEvidence::Reported),
1253            IrEvidence::Reported
1254        );
1255        assert_eq!(
1256            IrEvidence::Known.join(IrEvidence::Paradox),
1257            IrEvidence::Paradox
1258        );
1259        assert_eq!(
1260            IrEvidence::Reported.join(IrEvidence::Paradox),
1261            IrEvidence::Paradox
1262        );
1263    }
1264
1265    #[test]
1266    fn test_evidence_meet() {
1267        assert_eq!(
1268            IrEvidence::Paradox.meet(IrEvidence::Paradox),
1269            IrEvidence::Paradox
1270        );
1271        assert_eq!(
1272            IrEvidence::Paradox.meet(IrEvidence::Reported),
1273            IrEvidence::Reported
1274        );
1275        assert_eq!(
1276            IrEvidence::Paradox.meet(IrEvidence::Uncertain),
1277            IrEvidence::Uncertain
1278        );
1279        assert_eq!(
1280            IrEvidence::Paradox.meet(IrEvidence::Known),
1281            IrEvidence::Known
1282        );
1283    }
1284
1285    #[test]
1286    fn test_ir_serialization() {
1287        let module = IrModule::new("test.sigil".to_string());
1288        let json = module.to_json(false).unwrap();
1289        let parsed: IrModule = IrModule::from_json(&json).unwrap();
1290        assert_eq!(parsed.version, IR_VERSION);
1291        assert_eq!(parsed.source, "test.sigil");
1292    }
1293
1294    #[test]
1295    fn test_morpheme_symbols() {
1296        assert_eq!(MorphemeKind::Transform.symbol(), "τ");
1297        assert_eq!(MorphemeKind::Filter.symbol(), "φ");
1298        assert_eq!(MorphemeKind::Reduce.symbol(), "ρ");
1299    }
1300}