Skip to main content

rib/compiler/
ir.rs

1use crate::wit_type::WitType;
2use crate::ValueAndType;
3use crate::{ComponentDependencyKey, ParsedFunctionSite, VariableId, WitTypeWithUnit};
4use serde::{Deserialize, Serialize};
5
6// To create any type, example, CreateOption, you have to feed a fully formed WitType
7#[derive(Debug, Clone, PartialEq)]
8pub enum RibIR {
9    PushLit(ValueAndType),
10    AssignVar(VariableId),
11    LoadVar(VariableId),
12    CreateAndPushRecord(WitType),
13    UpdateRecord(String),
14    PushList(WitType, usize),
15    PushTuple(WitType, usize),
16    PushSome(WitType),
17    PushNone(Option<WitType>), // In certain cases, we don't need the type info
18    PushOkResult(WitType),
19    PushErrResult(WitType),
20    PushFlag(ValueAndType), // More or less like a literal, compiler can form the value directly
21    SelectField(String),
22    SelectIndex(usize), // Kept for backward compatibility. Cannot read old SelectIndex(usize) as a SelectIndexV1
23    SelectIndexV1,
24    EqualTo,
25    GreaterThan,
26    And,
27    Or,
28    LessThan,
29    GreaterThanOrEqualTo,
30    LessThanOrEqualTo,
31    IsEmpty,
32    JumpIfFalse(InstructionId),
33    Jump(InstructionId),
34    Label(InstructionId),
35    Deconstruct,
36    CreateFunctionName(ParsedFunctionSite, FunctionReferenceType),
37    InvokeFunction(
38        ComponentDependencyKey,
39        InstanceVariable,
40        usize,
41        WitTypeWithUnit,
42    ),
43    PushVariant(String, WitType), // There is no arg size since the type of each variant case is only 1 from beginning
44    PushEnum(String, WitType),
45    Throw(String),
46    GetTag,
47    Concat(usize),
48    Plus(WitType),
49    Minus(WitType),
50    Divide(WitType),
51    Multiply(WitType),
52    Negate,
53    ToIterator,
54    CreateSink(WitType),
55    AdvanceIterator,
56    PushToSink,
57    SinkToList,
58    Length,
59    GenerateWorkerName(Option<VariableId>),
60}
61
62#[derive(Debug, Clone, PartialEq)]
63pub enum InstanceVariable {
64    WitResource(VariableId),
65    WitWorker(VariableId),
66}
67
68impl RibIR {
69    pub fn get_instruction_id(&self) -> Option<InstructionId> {
70        match self {
71            RibIR::Label(id) => Some(id.clone()),
72            _ => None,
73        }
74    }
75}
76
77#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
78pub enum FunctionReferenceType {
79    Function { function: String },
80    RawResourceConstructor { resource: String },
81    RawResourceDrop { resource: String },
82    RawResourceMethod { resource: String, method: String },
83    RawResourceStaticMethod { resource: String, method: String },
84}
85
86// Every instruction can have a unique ID, and the compiler
87// can assign this and label the start and end of byte code blocks.
88// This is more efficient than assigning index to every instruction and incrementing it
89// as we care about it only if we need to jump through instructions.
90// Jumping to an ID is simply draining the stack until we find a Label instruction with the same ID.
91#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)]
92pub struct InstructionId {
93    pub index: usize,
94}
95
96impl InstructionId {
97    pub fn new(index: usize) -> Self {
98        InstructionId { index }
99    }
100
101    pub fn init() -> Self {
102        InstructionId { index: 0 }
103    }
104
105    pub fn increment(&self) -> InstructionId {
106        InstructionId {
107            index: self.index + 1,
108        }
109    }
110
111    pub fn increment_mut(&mut self) -> InstructionId {
112        self.index += 1;
113        self.clone()
114    }
115}