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