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