rib/compiler/
ir.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::{AnalysedTypeWithUnit, ComponentDependencyKey, ParsedFunctionSite, VariableId};
16use bincode::{Decode, Encode};
17use golem_wasm_ast::analysis::AnalysedType;
18use golem_wasm_rpc::ValueAndType;
19use serde::{Deserialize, Serialize};
20
21// To create any type, example, CreateOption, you have to feed a fully formed AnalysedType
22#[derive(Debug, Clone, PartialEq, Encode, Decode)]
23pub enum RibIR {
24    PushLit(ValueAndType),
25    AssignVar(VariableId),
26    LoadVar(VariableId),
27    CreateAndPushRecord(AnalysedType),
28    UpdateRecord(String),
29    PushList(AnalysedType, usize),
30    PushTuple(AnalysedType, usize),
31    PushSome(AnalysedType),
32    PushNone(Option<AnalysedType>), // In certain cases, we don't need the type info
33    PushOkResult(AnalysedType),
34    PushErrResult(AnalysedType),
35    PushFlag(ValueAndType), // More or less like a literal, compiler can form the value directly
36    SelectField(String),
37    SelectIndex(usize), // Kept for backward compatibility. Cannot read old SelectIndex(usize) as a SelectIndexV1
38    SelectIndexV1,
39    EqualTo,
40    GreaterThan,
41    And,
42    Or,
43    LessThan,
44    GreaterThanOrEqualTo,
45    LessThanOrEqualTo,
46    IsEmpty,
47    JumpIfFalse(InstructionId),
48    Jump(InstructionId),
49    Label(InstructionId),
50    Deconstruct,
51    CreateFunctionName(ParsedFunctionSite, FunctionReferenceType),
52    InvokeFunction(
53        ComponentDependencyKey,
54        InstanceVariable,
55        usize,
56        AnalysedTypeWithUnit,
57    ),
58    PushVariant(String, AnalysedType), // There is no arg size since the type of each variant case is only 1 from beginning
59    PushEnum(String, AnalysedType),
60    Throw(String),
61    GetTag,
62    Concat(usize),
63    Plus(AnalysedType),
64    Minus(AnalysedType),
65    Divide(AnalysedType),
66    Multiply(AnalysedType),
67    Negate,
68    ToIterator,
69    CreateSink(AnalysedType),
70    AdvanceIterator,
71    PushToSink,
72    SinkToList,
73    Length,
74    GenerateWorkerName(Option<VariableId>),
75}
76
77#[derive(Debug, Clone, PartialEq, Encode, Decode)]
78pub enum InstanceVariable {
79    WitResource(VariableId),
80    WitWorker(VariableId),
81}
82
83impl RibIR {
84    pub fn get_instruction_id(&self) -> Option<InstructionId> {
85        match self {
86            RibIR::Label(id) => Some(id.clone()),
87            _ => None,
88        }
89    }
90}
91
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)]
93pub enum FunctionReferenceType {
94    Function {
95        function: String,
96    },
97    RawResourceConstructor {
98        resource: String,
99    },
100    RawResourceDrop {
101        resource: String,
102    },
103    RawResourceMethod {
104        resource: String,
105        method: String,
106    },
107    RawResourceStaticMethod {
108        resource: String,
109        method: String,
110    },
111    IndexedResourceConstructor {
112        resource: String,
113        arg_size: usize,
114    },
115    IndexedResourceMethod {
116        resource: String,
117        arg_size: usize,
118        method: String,
119    },
120    IndexedResourceStaticMethod {
121        resource: String,
122        arg_size: usize,
123        method: String,
124    },
125    IndexedResourceDrop {
126        resource: String,
127        arg_size: usize,
128    },
129}
130
131// Every instruction can have a unique ID, and the compiler
132// can assign this and label the start and end of byte code blocks.
133// This is more efficient than assigning index to every instruction and incrementing it
134// as we care about it only if we need to jump through instructions.
135// Jumping to an ID is simply draining the stack until we find a Label instruction with the same ID.
136#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize, Encode, Decode)]
137pub struct InstructionId {
138    pub index: usize,
139}
140
141impl InstructionId {
142    pub fn new(index: usize) -> Self {
143        InstructionId { index }
144    }
145
146    pub fn init() -> Self {
147        InstructionId { index: 0 }
148    }
149
150    pub fn increment(&self) -> InstructionId {
151        InstructionId {
152            index: self.index + 1,
153        }
154    }
155
156    pub fn increment_mut(&mut self) -> InstructionId {
157        self.index += 1;
158        self.clone()
159    }
160}
161
162#[cfg(feature = "protobuf")]
163mod protobuf {
164    use crate::{
165        AnalysedTypeWithUnit, ComponentDependencyKey, FunctionReferenceType, InstanceVariable,
166        InstructionId, ParsedFunctionSite, RibIR, VariableId,
167    };
168    use golem_api_grpc::proto::golem::rib::rib_ir::Instruction;
169    use golem_api_grpc::proto::golem::rib::{
170        And, ConcatInstruction, CreateFunctionNameInstruction, EqualTo, GetTag, GreaterThan,
171        GreaterThanOrEqualTo, InvokeFunctionInstruction, IsEmpty, JumpInstruction, LessThan,
172        LessThanOrEqualTo, Negate, Or, PushListInstruction, PushNoneInstruction,
173        PushTupleInstruction, RibIr as ProtoRibIR, WitResource,
174    };
175    use golem_wasm_ast::analysis::{AnalysedType, TypeStr};
176    use golem_wasm_rpc::ValueAndType;
177
178    impl TryFrom<golem_api_grpc::proto::golem::rib::FunctionReferenceType> for FunctionReferenceType {
179        type Error = String;
180        fn try_from(
181            value: golem_api_grpc::proto::golem::rib::FunctionReferenceType,
182        ) -> Result<Self, Self::Error> {
183            let value = value.r#type.ok_or("Missing type".to_string())?;
184            let function_reference_type = match value {
185                golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(name) => FunctionReferenceType::Function {
186                    function: name.name
187                },
188                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(name) =>
189                    FunctionReferenceType::RawResourceConstructor {
190                        resource: name.resource_name
191                    },
192                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(name) => FunctionReferenceType::RawResourceDrop {
193                    resource: name.resource_name
194                },
195                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(raw_resource_method) => {
196                    let resource = raw_resource_method.resource_name;
197                    let method = raw_resource_method.method_name;
198                    FunctionReferenceType::RawResourceMethod { resource, method }
199                }
200                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(raw_resource_static_method) => {
201                    let resource = raw_resource_static_method.resource_name;
202                    let method = raw_resource_static_method.method_name;
203                    FunctionReferenceType::RawResourceStaticMethod { resource, method }
204                }
205                golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(indexed_resource_constructor) => {
206                    let resource = indexed_resource_constructor.resource_name;
207                    let arg_size = indexed_resource_constructor.arg_size;
208                    FunctionReferenceType::IndexedResourceConstructor { resource, arg_size: arg_size as usize }
209                }
210                golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(indexed_resource_method) => {
211                    let resource = indexed_resource_method.resource_name;
212                    let arg_size = indexed_resource_method.arg_size;
213                    let method = indexed_resource_method.method_name;
214                    FunctionReferenceType::IndexedResourceMethod { resource, arg_size: arg_size as usize, method }
215                }
216                golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(indexed_resource_static_method) => {
217                    let resource = indexed_resource_static_method.resource_name;
218                    let arg_size = indexed_resource_static_method.arg_size;
219                    let method = indexed_resource_static_method.method_name;
220                    FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size: arg_size as usize, method }
221                }
222                golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(indexed_resource_drop) => {
223                    let resource = indexed_resource_drop.resource_name;
224                    let arg_size = indexed_resource_drop.arg_size;
225                    FunctionReferenceType::IndexedResourceDrop { resource, arg_size: arg_size as usize }
226                }
227            };
228            Ok(function_reference_type)
229        }
230    }
231
232    impl From<FunctionReferenceType> for golem_api_grpc::proto::golem::rib::FunctionReferenceType {
233        fn from(value: FunctionReferenceType) -> Self {
234            match value {
235                FunctionReferenceType::Function { function } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
236                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(golem_api_grpc::proto::golem::rib::Function {
237                        name: function
238                    }))
239                },
240                FunctionReferenceType::RawResourceConstructor { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
241                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructor {
242                        resource_name: resource
243                    }))
244                },
245                FunctionReferenceType::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
246                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDrop {
247                        resource_name: resource
248                    }))
249                },
250                FunctionReferenceType::RawResourceMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
251                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethod {
252                        resource_name: resource,
253                        method_name: method,
254                    }))
255                },
256                FunctionReferenceType::RawResourceStaticMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
257                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethod {
258                        resource_name: resource,
259                        method_name: method,
260                    }))
261                },
262                FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
263                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructor {
264                        resource_name: resource,
265                        arg_size: arg_size as u32,
266                    }))
267                },
268                FunctionReferenceType::IndexedResourceMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
269                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethod {
270                        resource_name: resource,
271                        arg_size: arg_size as u32,
272                        method_name: method,
273                    }))
274                },
275                FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
276                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethod {
277                        resource_name: resource,
278                        arg_size: arg_size as u32,
279                        method_name: method,
280                    }))
281                },
282                FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
283                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDrop {
284                        resource_name: resource,
285                        arg_size: arg_size as u32,
286                    }))
287                }
288            }
289        }
290    }
291
292    impl TryFrom<ProtoRibIR> for RibIR {
293        type Error = String;
294
295        fn try_from(value: ProtoRibIR) -> Result<Self, Self::Error> {
296            let instruction = value
297                .instruction
298                .ok_or_else(|| "Missing instruction".to_string())?;
299
300            match instruction {
301                Instruction::GenerateWorkerName(generate_worker_name) => {
302                    let variable_id = generate_worker_name
303                        .variable_id
304                        .map(VariableId::try_from)
305                        .transpose()?;
306
307                    Ok(RibIR::GenerateWorkerName(variable_id))
308                }
309                Instruction::PushLit(value) => {
310                    let value: ValueAndType = value.try_into()?;
311                    Ok(RibIR::PushLit(value))
312                }
313                Instruction::AssignVar(value) => Ok(RibIR::AssignVar(
314                    value
315                        .try_into()
316                        .map_err(|_| "Failed to convert AssignVar".to_string())?,
317                )),
318                Instruction::LoadVar(value) => Ok(RibIR::LoadVar(
319                    value
320                        .try_into()
321                        .map_err(|_| "Failed to convert LoadVar".to_string())?,
322                )),
323                Instruction::CreateAndPushRecord(value) => {
324                    Ok(RibIR::CreateAndPushRecord((&value).try_into().map_err(
325                        |_| "Failed to convert CreateAndPushRecord".to_string(),
326                    )?))
327                }
328                Instruction::Plus(value) => {
329                    Ok(RibIR::Plus((&value).try_into().map_err(|_| {
330                        "Failed to convert CreateAndPushRecord".to_string()
331                    })?))
332                }
333                Instruction::Multiply(value) => {
334                    Ok(RibIR::Multiply((&value).try_into().map_err(|_| {
335                        "Failed to convert CreateAndPushRecord".to_string()
336                    })?))
337                }
338                Instruction::Minus(value) => {
339                    Ok(RibIR::Minus((&value).try_into().map_err(|_| {
340                        "Failed to convert CreateAndPushRecord".to_string()
341                    })?))
342                }
343                Instruction::Divide(value) => {
344                    Ok(RibIR::Divide((&value).try_into().map_err(|_| {
345                        "Failed to convert CreateAndPushRecord".to_string()
346                    })?))
347                }
348
349                Instruction::UpdateRecord(value) => Ok(RibIR::UpdateRecord(value)),
350                Instruction::PushList(value) => Ok(RibIR::PushList(
351                    value
352                        .list_type
353                        .ok_or("List type not present".to_string())
354                        .and_then(|t| {
355                            (&t).try_into()
356                                .map_err(|_| "Failed to convert AnalysedType".to_string())
357                        })?,
358                    value.list_size as usize,
359                )),
360                Instruction::CreateSome(value) => Ok(RibIR::PushSome(
361                    (&value)
362                        .try_into()
363                        .map_err(|_| "Failed to convert CreateSome".to_string())?,
364                )),
365                Instruction::CreateNone(value) => match value.none_type {
366                    Some(v) => {
367                        let optional_type = (&v)
368                            .try_into()
369                            .map_err(|_| "Failed to convert AnalysedType".to_string());
370                        Ok(RibIR::PushNone(Some(optional_type?)))
371                    }
372                    None => Ok(RibIR::PushNone(None)),
373                },
374                Instruction::CreateOkResult(value) => {
375                    Ok(RibIR::PushOkResult((&value).try_into().map_err(|_| {
376                        "Failed to convert CreateOkResult".to_string()
377                    })?))
378                }
379                Instruction::CreateErrResult(value) => {
380                    Ok(RibIR::PushErrResult((&value).try_into().map_err(|_| {
381                        "Failed to convert CreateErrResult".to_string()
382                    })?))
383                }
384                Instruction::Length(_) => Ok(RibIR::Length),
385                Instruction::SelectField(value) => Ok(RibIR::SelectField(value)),
386                Instruction::SelectIndex(value) => Ok(RibIR::SelectIndex(value as usize)),
387                Instruction::SelectIndexV1(_) => Ok(RibIR::SelectIndexV1),
388                Instruction::EqualTo(_) => Ok(RibIR::EqualTo),
389                Instruction::GreaterThan(_) => Ok(RibIR::GreaterThan),
390                Instruction::LessThan(_) => Ok(RibIR::LessThan),
391                Instruction::GreaterThanOrEqualTo(_) => Ok(RibIR::GreaterThanOrEqualTo),
392                Instruction::LessThanOrEqualTo(_) => Ok(RibIR::LessThanOrEqualTo),
393                Instruction::And(_) => Ok(RibIR::And),
394                Instruction::IsEmpty(_) => Ok(RibIR::IsEmpty),
395                Instruction::Or(_) => Ok(RibIR::Or),
396                Instruction::JumpIfFalse(value) => Ok(RibIR::JumpIfFalse(InstructionId::new(
397                    value.instruction_id as usize,
398                ))),
399                Instruction::Jump(value) => Ok(RibIR::Jump(InstructionId::new(
400                    value.instruction_id as usize,
401                ))),
402                Instruction::Label(value) => Ok(RibIR::Label(InstructionId::new(
403                    value.instruction_id as usize,
404                ))),
405                Instruction::Deconstruct(_) => Ok(RibIR::Deconstruct),
406                Instruction::InvokeFunction(invoke_function_instruction) => {
407                    let return_type = match invoke_function_instruction.return_type {
408                        Some(return_type) => {
409                            let analysed_type = (&return_type)
410                                .try_into()
411                                .map_err(|_| "Failed to convert AnalysedType".to_string())?;
412
413                            AnalysedTypeWithUnit::Type(analysed_type)
414                        }
415                        None => AnalysedTypeWithUnit::Unit,
416                    };
417
418                    let instance_variable: InstanceVariable = invoke_function_instruction
419                        .instance_variable
420                        .ok_or("Missing instance_variable".to_string())
421                        .and_then(|iv| {
422                            match iv.kind.ok_or("Missing instance_variable kind".to_string())? {
423                                golem_api_grpc::proto::golem::rib::instance_variable::Kind::Resource(wit_resource) => {
424                                    let variable_id = wit_resource.variable_id.ok_or(
425                                        "Missing variable_id in WitResource".to_string(),
426                                    )?.try_into()
427                                        .map_err(|_| "Failed to convert VariableId".to_string())?;
428                                    Ok(InstanceVariable::WitResource(variable_id))
429                                }
430                                golem_api_grpc::proto::golem::rib::instance_variable::Kind::Worker(wit_worker) => {
431                                    let variable_id = wit_worker.variable_id.ok_or(
432                                        "Missing variable_id in WitWorker".to_string(),
433                                    )?.try_into()
434                                        .map_err(|_| "Failed to convert VariableId".to_string())?;
435
436                                    Ok(InstanceVariable::WitWorker(variable_id))
437                                }
438                            }
439                        })?;
440
441                    let component_dependency_key_proto = invoke_function_instruction
442                        .component
443                        .ok_or("Missing component_dependency_key".to_string())?;
444
445                    let component_dependency_key =
446                        ComponentDependencyKey::try_from(component_dependency_key_proto)
447                            .map_err(|_| "Failed to convert ComponentDependencyKey".to_string())?;
448
449                    Ok(RibIR::InvokeFunction(
450                        component_dependency_key,
451                        instance_variable,
452                        invoke_function_instruction.argument_count as usize,
453                        return_type,
454                    ))
455                }
456                Instruction::VariantConstruction(variant_construction) => {
457                    let variant_type = variant_construction
458                        .return_type
459                        .ok_or("Missing return_type for variant construction".to_string())?;
460
461                    let analysed_variant_type = (&variant_type)
462                        .try_into()
463                        .map_err(|_| "Failed to convert AnalysedType".to_string())?;
464
465                    Ok(RibIR::PushVariant(
466                        variant_construction.variant_name,
467                        analysed_variant_type,
468                    ))
469                }
470                Instruction::EnumConstruction(enum_construction) => {
471                    let enum_type = enum_construction
472                        .return_type
473                        .ok_or("Missing return_type for enum construction".to_string())?;
474
475                    let analysed_enum_type = (&enum_type)
476                        .try_into()
477                        .map_err(|_| "Failed to convert AnalysedType".to_string())?;
478
479                    Ok(RibIR::PushEnum(
480                        enum_construction.enum_name,
481                        analysed_enum_type,
482                    ))
483                }
484                Instruction::Throw(value) => Ok(RibIR::Throw(value)),
485                Instruction::PushFlag(flag) => {
486                    let flag: ValueAndType = flag.try_into()?;
487                    Ok(RibIR::PushFlag(flag))
488                }
489                Instruction::GetTag(_) => Ok(RibIR::GetTag),
490                Instruction::PushTuple(tuple_instruction) => {
491                    let tuple_type = tuple_instruction
492                        .tuple_type
493                        .ok_or("Missing tuple_type".to_string())
494                        .and_then(|t| {
495                            (&t).try_into()
496                                .map_err(|_| "Failed to convert AnalysedType".to_string())
497                        })?;
498
499                    Ok(RibIR::PushTuple(
500                        tuple_type,
501                        tuple_instruction.tuple_size as usize,
502                    ))
503                }
504                Instruction::Negate(_) => Ok(RibIR::Negate),
505                Instruction::Concat(concat_instruction) => {
506                    Ok(RibIR::Concat(concat_instruction.arg_size as usize))
507                }
508                Instruction::CreateFunctionName(instruction) => {
509                    let parsed_site = instruction.site.ok_or("Missing site".to_string())?;
510                    let parsed_function_site = ParsedFunctionSite::try_from(parsed_site)?;
511
512                    let reference_type = instruction
513                        .function_reference_details
514                        .ok_or("Missing reference_type".to_string())?;
515                    let function_reference_type = reference_type.try_into()?;
516
517                    Ok(RibIR::CreateFunctionName(
518                        parsed_function_site,
519                        function_reference_type,
520                    ))
521                }
522                Instruction::ListToIterator(_) => Ok(RibIR::ToIterator),
523                Instruction::CreateSink(create_sink) => {
524                    let result = create_sink
525                        .list_type
526                        .ok_or("Sink list type not present".to_string())
527                        .and_then(|t| {
528                            (&t).try_into()
529                                .map_err(|_| "Failed to convert AnalysedType".to_string())
530                        })?;
531
532                    Ok(RibIR::CreateSink(result))
533                }
534                Instruction::AdvanceIterator(_) => Ok(RibIR::AdvanceIterator),
535                Instruction::SinkToList(_) => Ok(RibIR::SinkToList),
536                Instruction::PushToSink(_) => Ok(RibIR::PushToSink),
537            }
538        }
539    }
540
541    impl TryFrom<RibIR> for ProtoRibIR {
542        type Error = String;
543
544        fn try_from(value: RibIR) -> Result<Self, Self::Error> {
545            let instruction = match value {
546                RibIR::GenerateWorkerName(variable_id) => {
547                    let variable_id_proto = variable_id.map(|v| v.into());
548
549                    Instruction::GenerateWorkerName(
550                        golem_api_grpc::proto::golem::rib::GenerateWorkerName {
551                            variable_id: variable_id_proto,
552                        },
553                    )
554                }
555                RibIR::PushLit(value) => {
556                    Instruction::PushLit(golem_wasm_rpc::protobuf::TypeAnnotatedValue {
557                        type_annotated_value: Some(
558                            value
559                                .try_into()
560                                .map_err(|errs: Vec<String>| errs.join(", "))?,
561                        ),
562                    })
563                }
564                RibIR::And => Instruction::And(And {}),
565                RibIR::IsEmpty => Instruction::IsEmpty(IsEmpty {}),
566                RibIR::Or => Instruction::Or(Or {}),
567                RibIR::AssignVar(value) => Instruction::AssignVar(value.into()),
568                RibIR::LoadVar(value) => Instruction::LoadVar(value.into()),
569                RibIR::CreateAndPushRecord(value) => {
570                    Instruction::CreateAndPushRecord((&value).into())
571                }
572                RibIR::Plus(value) => Instruction::Plus((&value).into()),
573                RibIR::Minus(value) => Instruction::Minus((&value).into()),
574                RibIR::Multiply(value) => Instruction::Multiply((&value).into()),
575                RibIR::Divide(value) => Instruction::Divide((&value).into()),
576                RibIR::UpdateRecord(value) => Instruction::UpdateRecord(value),
577                RibIR::PushList(value, arg_size) => Instruction::PushList(PushListInstruction {
578                    list_type: Some((&value).into()),
579                    list_size: arg_size as u64,
580                }),
581                RibIR::PushSome(value) => Instruction::CreateSome((&value).into()),
582                RibIR::PushNone(value) => {
583                    let push_none_instruction = PushNoneInstruction {
584                        none_type: value.map(|t| (&t).into()),
585                    };
586                    Instruction::CreateNone(push_none_instruction)
587                }
588                RibIR::PushOkResult(value) => Instruction::CreateOkResult((&value).into()),
589                RibIR::PushErrResult(value) => Instruction::CreateErrResult((&value).into()),
590                RibIR::SelectField(value) => Instruction::SelectField(value),
591                RibIR::SelectIndex(value) => Instruction::SelectIndex(value as u64),
592                RibIR::EqualTo => Instruction::EqualTo(EqualTo {}),
593                RibIR::GreaterThan => Instruction::GreaterThan(GreaterThan {}),
594                RibIR::LessThan => Instruction::LessThan(LessThan {}),
595                RibIR::Length => Instruction::Length(golem_api_grpc::proto::golem::rib::Length {}),
596                RibIR::SelectIndexV1 => {
597                    Instruction::SelectIndexV1(golem_api_grpc::proto::golem::rib::SelectIndexV1 {})
598                }
599                RibIR::GreaterThanOrEqualTo => {
600                    Instruction::GreaterThanOrEqualTo(GreaterThanOrEqualTo {})
601                }
602                RibIR::LessThanOrEqualTo => Instruction::LessThanOrEqualTo(LessThanOrEqualTo {}),
603                RibIR::JumpIfFalse(value) => Instruction::JumpIfFalse(JumpInstruction {
604                    instruction_id: value.index as u64,
605                }),
606                RibIR::Jump(value) => Instruction::Jump(JumpInstruction {
607                    instruction_id: value.index as u64,
608                }),
609                RibIR::Label(value) => Instruction::Label(JumpInstruction {
610                    instruction_id: value.index as u64,
611                }),
612                RibIR::Deconstruct => {
613                    Instruction::Deconstruct((&AnalysedType::Str(TypeStr)).into())
614                } //TODO; remove type in deconstruct from protobuf
615                RibIR::InvokeFunction(
616                    component_dependency_key,
617                    worker_name_presence,
618                    arg_count,
619                    return_type,
620                ) => {
621                    let typ = match return_type {
622                        AnalysedTypeWithUnit::Unit => None,
623                        AnalysedTypeWithUnit::Type(analysed_type) => {
624                            let typ =
625                                golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type);
626                            Some(typ)
627                        }
628                    };
629
630                    let instance_variable = match worker_name_presence {
631                        InstanceVariable::WitResource(variable_id) => {
632                            golem_api_grpc::proto::golem::rib::InstanceVariable {
633                                kind: Some(
634                                    golem_api_grpc::proto::golem::rib::instance_variable::Kind::Resource(
635                                        WitResource {
636                                            variable_id: Some(variable_id.into()),
637                                        },
638                                    ),
639                                ),
640                            }
641                        }
642                        InstanceVariable::WitWorker(variable_id) => {
643                            golem_api_grpc::proto::golem::rib::InstanceVariable {
644                                kind: Some(
645                                    golem_api_grpc::proto::golem::rib::instance_variable::Kind::Worker(
646                                        golem_api_grpc::proto::golem::rib::WitWorker {
647                                            variable_id: Some(variable_id.into()),
648                                        },
649                                    ),
650                                ),
651                            }
652                        }
653                    };
654
655                    let component_dependency_key =
656                        golem_api_grpc::proto::golem::rib::ComponentDependencyKey::from(
657                            component_dependency_key,
658                        );
659
660                    Instruction::InvokeFunction(InvokeFunctionInstruction {
661                        component: Some(component_dependency_key),
662                        argument_count: arg_count as u64,
663                        return_type: typ,
664                        instance_variable: Some(instance_variable),
665                    })
666                }
667                RibIR::PushVariant(name, return_type) => {
668                    let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type);
669
670                    Instruction::VariantConstruction(
671                        golem_api_grpc::proto::golem::rib::VariantConstructionInstruction {
672                            variant_name: name,
673                            return_type: Some(typ),
674                        },
675                    )
676                }
677                RibIR::PushEnum(name, return_type) => {
678                    let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type);
679
680                    Instruction::EnumConstruction(
681                        golem_api_grpc::proto::golem::rib::EnumConstructionInstruction {
682                            enum_name: name,
683                            return_type: Some(typ),
684                        },
685                    )
686                }
687                RibIR::Throw(msg) => Instruction::Throw(msg),
688                RibIR::PushFlag(flag) => {
689                    Instruction::PushFlag(golem_wasm_rpc::protobuf::TypeAnnotatedValue {
690                        type_annotated_value: Some(
691                            flag.try_into()
692                                .map_err(|errs: Vec<String>| errs.join(", "))?,
693                        ),
694                    })
695                }
696                RibIR::GetTag => Instruction::GetTag(GetTag {}),
697                RibIR::PushTuple(analysed_type, size) => {
698                    let typ = golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type);
699
700                    Instruction::PushTuple(PushTupleInstruction {
701                        tuple_type: Some(typ),
702                        tuple_size: size as u64,
703                    })
704                }
705                RibIR::Concat(concat) => Instruction::Concat(ConcatInstruction {
706                    arg_size: concat as u64,
707                }),
708                RibIR::Negate => Instruction::Negate(Negate {}),
709                RibIR::CreateFunctionName(site, reference_type) => {
710                    Instruction::CreateFunctionName(CreateFunctionNameInstruction {
711                        site: Some(site.into()),
712                        function_reference_details: Some(reference_type.into()),
713                    })
714                }
715
716                RibIR::ToIterator => Instruction::ListToIterator(
717                    golem_api_grpc::proto::golem::rib::ListToIterator {},
718                ),
719                RibIR::CreateSink(analysed_type) => {
720                    Instruction::CreateSink(golem_api_grpc::proto::golem::rib::CreateSink {
721                        list_type: Some((&analysed_type).into()),
722                    })
723                }
724                RibIR::AdvanceIterator => Instruction::AdvanceIterator(
725                    golem_api_grpc::proto::golem::rib::AdvanceIterator {},
726                ),
727                RibIR::PushToSink => {
728                    Instruction::PushToSink(golem_api_grpc::proto::golem::rib::PushToSink {})
729                }
730                RibIR::SinkToList => {
731                    Instruction::SinkToList(golem_api_grpc::proto::golem::rib::SinkToList {})
732                }
733            };
734
735            Ok(ProtoRibIR {
736                instruction: Some(instruction),
737            })
738        }
739    }
740}