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 { function: String },
95    RawResourceConstructor { resource: String },
96    RawResourceDrop { resource: String },
97    RawResourceMethod { resource: String, method: String },
98    RawResourceStaticMethod { resource: String, method: String },
99}
100
101// Every instruction can have a unique ID, and the compiler
102// can assign this and label the start and end of byte code blocks.
103// This is more efficient than assigning index to every instruction and incrementing it
104// as we care about it only if we need to jump through instructions.
105// Jumping to an ID is simply draining the stack until we find a Label instruction with the same ID.
106#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize, Encode, Decode)]
107pub struct InstructionId {
108    pub index: usize,
109}
110
111impl InstructionId {
112    pub fn new(index: usize) -> Self {
113        InstructionId { index }
114    }
115
116    pub fn init() -> Self {
117        InstructionId { index: 0 }
118    }
119
120    pub fn increment(&self) -> InstructionId {
121        InstructionId {
122            index: self.index + 1,
123        }
124    }
125
126    pub fn increment_mut(&mut self) -> InstructionId {
127        self.index += 1;
128        self.clone()
129    }
130}
131
132#[cfg(feature = "protobuf")]
133mod protobuf {
134    use crate::{
135        AnalysedTypeWithUnit, ComponentDependencyKey, FunctionReferenceType, InstanceVariable,
136        InstructionId, ParsedFunctionSite, RibIR, VariableId,
137    };
138    use golem_api_grpc::proto::golem::rib::rib_ir::Instruction;
139    use golem_api_grpc::proto::golem::rib::{
140        And, ConcatInstruction, CreateFunctionNameInstruction, EqualTo, GetTag, GreaterThan,
141        GreaterThanOrEqualTo, InvokeFunctionInstruction, IsEmpty, JumpInstruction, LessThan,
142        LessThanOrEqualTo, Negate, Or, PushListInstruction, PushNoneInstruction,
143        PushTupleInstruction, RibIr as ProtoRibIR, WitResource,
144    };
145    use golem_wasm_ast::analysis::{AnalysedType, TypeStr};
146
147    impl TryFrom<golem_api_grpc::proto::golem::rib::FunctionReferenceType> for FunctionReferenceType {
148        type Error = String;
149        fn try_from(
150            value: golem_api_grpc::proto::golem::rib::FunctionReferenceType,
151        ) -> Result<Self, Self::Error> {
152            let value = value.r#type.ok_or("Missing type".to_string())?;
153            let function_reference_type = match value {
154                golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(name) => FunctionReferenceType::Function {
155                    function: name.name
156                },
157                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(name) =>
158                    FunctionReferenceType::RawResourceConstructor {
159                        resource: name.resource_name
160                    },
161                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(name) => FunctionReferenceType::RawResourceDrop {
162                    resource: name.resource_name
163                },
164                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(raw_resource_method) => {
165                    let resource = raw_resource_method.resource_name;
166                    let method = raw_resource_method.method_name;
167                    FunctionReferenceType::RawResourceMethod { resource, method }
168                }
169                golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(raw_resource_static_method) => {
170                    let resource = raw_resource_static_method.resource_name;
171                    let method = raw_resource_static_method.method_name;
172                    FunctionReferenceType::RawResourceStaticMethod { resource, method }
173                }
174            };
175            Ok(function_reference_type)
176        }
177    }
178
179    impl From<FunctionReferenceType> for golem_api_grpc::proto::golem::rib::FunctionReferenceType {
180        fn from(value: FunctionReferenceType) -> Self {
181            match value {
182                FunctionReferenceType::Function { function } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
183                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(golem_api_grpc::proto::golem::rib::Function {
184                        name: function
185                    }))
186                },
187                FunctionReferenceType::RawResourceConstructor { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
188                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructor {
189                        resource_name: resource
190                    }))
191                },
192                FunctionReferenceType::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
193                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDrop {
194                        resource_name: resource
195                    }))
196                },
197                FunctionReferenceType::RawResourceMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
198                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethod {
199                        resource_name: resource,
200                        method_name: method,
201                    }))
202                },
203                FunctionReferenceType::RawResourceStaticMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType {
204                    r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethod {
205                        resource_name: resource,
206                        method_name: method,
207                    }))
208                },
209            }
210        }
211    }
212
213    impl TryFrom<ProtoRibIR> for RibIR {
214        type Error = String;
215
216        fn try_from(value: ProtoRibIR) -> Result<Self, Self::Error> {
217            let instruction = value
218                .instruction
219                .ok_or_else(|| "Missing instruction".to_string())?;
220
221            match instruction {
222                Instruction::GenerateWorkerName(generate_worker_name) => {
223                    let variable_id = generate_worker_name
224                        .variable_id
225                        .map(VariableId::try_from)
226                        .transpose()?;
227
228                    Ok(RibIR::GenerateWorkerName(variable_id))
229                }
230                Instruction::PushLit(value) => Ok(RibIR::PushLit(
231                    value
232                        .try_into()
233                        .map_err(|_| "Failed to convert PushLit".to_string())?,
234                )),
235                Instruction::AssignVar(value) => Ok(RibIR::AssignVar(
236                    value
237                        .try_into()
238                        .map_err(|_| "Failed to convert AssignVar".to_string())?,
239                )),
240                Instruction::LoadVar(value) => Ok(RibIR::LoadVar(
241                    value
242                        .try_into()
243                        .map_err(|_| "Failed to convert LoadVar".to_string())?,
244                )),
245                Instruction::CreateAndPushRecord(value) => {
246                    Ok(RibIR::CreateAndPushRecord((&value).try_into().map_err(
247                        |_| "Failed to convert CreateAndPushRecord".to_string(),
248                    )?))
249                }
250                Instruction::Plus(value) => {
251                    Ok(RibIR::Plus((&value).try_into().map_err(|_| {
252                        "Failed to convert CreateAndPushRecord".to_string()
253                    })?))
254                }
255                Instruction::Multiply(value) => {
256                    Ok(RibIR::Multiply((&value).try_into().map_err(|_| {
257                        "Failed to convert CreateAndPushRecord".to_string()
258                    })?))
259                }
260                Instruction::Minus(value) => {
261                    Ok(RibIR::Minus((&value).try_into().map_err(|_| {
262                        "Failed to convert CreateAndPushRecord".to_string()
263                    })?))
264                }
265                Instruction::Divide(value) => {
266                    Ok(RibIR::Divide((&value).try_into().map_err(|_| {
267                        "Failed to convert CreateAndPushRecord".to_string()
268                    })?))
269                }
270
271                Instruction::UpdateRecord(value) => Ok(RibIR::UpdateRecord(value)),
272                Instruction::PushList(value) => Ok(RibIR::PushList(
273                    value
274                        .list_type
275                        .ok_or("List type not present".to_string())
276                        .and_then(|t| {
277                            (&t).try_into()
278                                .map_err(|_| "Failed to convert AnalysedType".to_string())
279                        })?,
280                    value.list_size as usize,
281                )),
282                Instruction::CreateSome(value) => Ok(RibIR::PushSome(
283                    (&value)
284                        .try_into()
285                        .map_err(|_| "Failed to convert CreateSome".to_string())?,
286                )),
287                Instruction::CreateNone(value) => match value.none_type {
288                    Some(v) => {
289                        let optional_type = (&v)
290                            .try_into()
291                            .map_err(|_| "Failed to convert AnalysedType".to_string());
292                        Ok(RibIR::PushNone(Some(optional_type?)))
293                    }
294                    None => Ok(RibIR::PushNone(None)),
295                },
296                Instruction::CreateOkResult(value) => {
297                    Ok(RibIR::PushOkResult((&value).try_into().map_err(|_| {
298                        "Failed to convert CreateOkResult".to_string()
299                    })?))
300                }
301                Instruction::CreateErrResult(value) => {
302                    Ok(RibIR::PushErrResult((&value).try_into().map_err(|_| {
303                        "Failed to convert CreateErrResult".to_string()
304                    })?))
305                }
306                Instruction::Length(_) => Ok(RibIR::Length),
307                Instruction::SelectField(value) => Ok(RibIR::SelectField(value)),
308                Instruction::SelectIndex(value) => Ok(RibIR::SelectIndex(value as usize)),
309                Instruction::SelectIndexV1(_) => Ok(RibIR::SelectIndexV1),
310                Instruction::EqualTo(_) => Ok(RibIR::EqualTo),
311                Instruction::GreaterThan(_) => Ok(RibIR::GreaterThan),
312                Instruction::LessThan(_) => Ok(RibIR::LessThan),
313                Instruction::GreaterThanOrEqualTo(_) => Ok(RibIR::GreaterThanOrEqualTo),
314                Instruction::LessThanOrEqualTo(_) => Ok(RibIR::LessThanOrEqualTo),
315                Instruction::And(_) => Ok(RibIR::And),
316                Instruction::IsEmpty(_) => Ok(RibIR::IsEmpty),
317                Instruction::Or(_) => Ok(RibIR::Or),
318                Instruction::JumpIfFalse(value) => Ok(RibIR::JumpIfFalse(InstructionId::new(
319                    value.instruction_id as usize,
320                ))),
321                Instruction::Jump(value) => Ok(RibIR::Jump(InstructionId::new(
322                    value.instruction_id as usize,
323                ))),
324                Instruction::Label(value) => Ok(RibIR::Label(InstructionId::new(
325                    value.instruction_id as usize,
326                ))),
327                Instruction::Deconstruct(_) => Ok(RibIR::Deconstruct),
328                Instruction::InvokeFunction(invoke_function_instruction) => {
329                    let return_type = match invoke_function_instruction.return_type {
330                        Some(return_type) => {
331                            let analysed_type = (&return_type)
332                                .try_into()
333                                .map_err(|_| "Failed to convert AnalysedType".to_string())?;
334
335                            AnalysedTypeWithUnit::Type(analysed_type)
336                        }
337                        None => AnalysedTypeWithUnit::Unit,
338                    };
339
340                    let instance_variable: InstanceVariable = invoke_function_instruction
341                        .instance_variable
342                        .ok_or("Missing instance_variable".to_string())
343                        .and_then(|iv| {
344                            match iv.kind.ok_or("Missing instance_variable kind".to_string())? {
345                                golem_api_grpc::proto::golem::rib::instance_variable::Kind::Resource(wit_resource) => {
346                                    let variable_id = wit_resource.variable_id.ok_or(
347                                        "Missing variable_id in WitResource".to_string(),
348                                    )?.try_into()
349                                        .map_err(|_| "Failed to convert VariableId".to_string())?;
350                                    Ok(InstanceVariable::WitResource(variable_id))
351                                }
352                                golem_api_grpc::proto::golem::rib::instance_variable::Kind::Worker(wit_worker) => {
353                                    let variable_id = wit_worker.variable_id.ok_or(
354                                        "Missing variable_id in WitWorker".to_string(),
355                                    )?.try_into()
356                                        .map_err(|_| "Failed to convert VariableId".to_string())?;
357
358                                    Ok(InstanceVariable::WitWorker(variable_id))
359                                }
360                            }
361                        })?;
362
363                    let component_dependency_key_proto = invoke_function_instruction
364                        .component
365                        .ok_or("Missing component_dependency_key".to_string())?;
366
367                    let component_dependency_key =
368                        ComponentDependencyKey::try_from(component_dependency_key_proto)
369                            .map_err(|_| "Failed to convert ComponentDependencyKey".to_string())?;
370
371                    Ok(RibIR::InvokeFunction(
372                        component_dependency_key,
373                        instance_variable,
374                        invoke_function_instruction.argument_count as usize,
375                        return_type,
376                    ))
377                }
378                Instruction::VariantConstruction(variant_construction) => {
379                    let variant_type = variant_construction
380                        .return_type
381                        .ok_or("Missing return_type for variant construction".to_string())?;
382
383                    let analysed_variant_type = (&variant_type)
384                        .try_into()
385                        .map_err(|_| "Failed to convert AnalysedType".to_string())?;
386
387                    Ok(RibIR::PushVariant(
388                        variant_construction.variant_name,
389                        analysed_variant_type,
390                    ))
391                }
392                Instruction::EnumConstruction(enum_construction) => {
393                    let enum_type = enum_construction
394                        .return_type
395                        .ok_or("Missing return_type for enum construction".to_string())?;
396
397                    let analysed_enum_type = (&enum_type)
398                        .try_into()
399                        .map_err(|_| "Failed to convert AnalysedType".to_string())?;
400
401                    Ok(RibIR::PushEnum(
402                        enum_construction.enum_name,
403                        analysed_enum_type,
404                    ))
405                }
406                Instruction::Throw(value) => Ok(RibIR::Throw(value)),
407                Instruction::PushFlag(flag) => Ok(RibIR::PushFlag(
408                    flag.try_into()
409                        .map_err(|_| "Failed to convert PushFlag".to_string())?,
410                )),
411                Instruction::GetTag(_) => Ok(RibIR::GetTag),
412                Instruction::PushTuple(tuple_instruction) => {
413                    let tuple_type = tuple_instruction
414                        .tuple_type
415                        .ok_or("Missing tuple_type".to_string())
416                        .and_then(|t| {
417                            (&t).try_into()
418                                .map_err(|_| "Failed to convert AnalysedType".to_string())
419                        })?;
420
421                    Ok(RibIR::PushTuple(
422                        tuple_type,
423                        tuple_instruction.tuple_size as usize,
424                    ))
425                }
426                Instruction::Negate(_) => Ok(RibIR::Negate),
427                Instruction::Concat(concat_instruction) => {
428                    Ok(RibIR::Concat(concat_instruction.arg_size as usize))
429                }
430                Instruction::CreateFunctionName(instruction) => {
431                    let parsed_site = instruction.site.ok_or("Missing site".to_string())?;
432                    let parsed_function_site = ParsedFunctionSite::try_from(parsed_site)?;
433
434                    let reference_type = instruction
435                        .function_reference_details
436                        .ok_or("Missing reference_type".to_string())?;
437                    let function_reference_type = reference_type.try_into()?;
438
439                    Ok(RibIR::CreateFunctionName(
440                        parsed_function_site,
441                        function_reference_type,
442                    ))
443                }
444                Instruction::ListToIterator(_) => Ok(RibIR::ToIterator),
445                Instruction::CreateSink(create_sink) => {
446                    let result = create_sink
447                        .list_type
448                        .ok_or("Sink list type not present".to_string())
449                        .and_then(|t| {
450                            (&t).try_into()
451                                .map_err(|_| "Failed to convert AnalysedType".to_string())
452                        })?;
453
454                    Ok(RibIR::CreateSink(result))
455                }
456                Instruction::AdvanceIterator(_) => Ok(RibIR::AdvanceIterator),
457                Instruction::SinkToList(_) => Ok(RibIR::SinkToList),
458                Instruction::PushToSink(_) => Ok(RibIR::PushToSink),
459            }
460        }
461    }
462
463    impl TryFrom<RibIR> for ProtoRibIR {
464        type Error = String;
465
466        fn try_from(value: RibIR) -> Result<Self, Self::Error> {
467            let instruction = match value {
468                RibIR::GenerateWorkerName(variable_id) => {
469                    let variable_id_proto = variable_id.map(|v| v.into());
470
471                    Instruction::GenerateWorkerName(
472                        golem_api_grpc::proto::golem::rib::GenerateWorkerName {
473                            variable_id: variable_id_proto,
474                        },
475                    )
476                }
477                RibIR::PushLit(value) => Instruction::PushLit(value.into()),
478                RibIR::And => Instruction::And(And {}),
479                RibIR::IsEmpty => Instruction::IsEmpty(IsEmpty {}),
480                RibIR::Or => Instruction::Or(Or {}),
481                RibIR::AssignVar(value) => Instruction::AssignVar(value.into()),
482                RibIR::LoadVar(value) => Instruction::LoadVar(value.into()),
483                RibIR::CreateAndPushRecord(value) => {
484                    Instruction::CreateAndPushRecord((&value).into())
485                }
486                RibIR::Plus(value) => Instruction::Plus((&value).into()),
487                RibIR::Minus(value) => Instruction::Minus((&value).into()),
488                RibIR::Multiply(value) => Instruction::Multiply((&value).into()),
489                RibIR::Divide(value) => Instruction::Divide((&value).into()),
490                RibIR::UpdateRecord(value) => Instruction::UpdateRecord(value),
491                RibIR::PushList(value, arg_size) => Instruction::PushList(PushListInstruction {
492                    list_type: Some((&value).into()),
493                    list_size: arg_size as u64,
494                }),
495                RibIR::PushSome(value) => Instruction::CreateSome((&value).into()),
496                RibIR::PushNone(value) => {
497                    let push_none_instruction = PushNoneInstruction {
498                        none_type: value.map(|t| (&t).into()),
499                    };
500                    Instruction::CreateNone(push_none_instruction)
501                }
502                RibIR::PushOkResult(value) => Instruction::CreateOkResult((&value).into()),
503                RibIR::PushErrResult(value) => Instruction::CreateErrResult((&value).into()),
504                RibIR::SelectField(value) => Instruction::SelectField(value),
505                RibIR::SelectIndex(value) => Instruction::SelectIndex(value as u64),
506                RibIR::EqualTo => Instruction::EqualTo(EqualTo {}),
507                RibIR::GreaterThan => Instruction::GreaterThan(GreaterThan {}),
508                RibIR::LessThan => Instruction::LessThan(LessThan {}),
509                RibIR::Length => Instruction::Length(golem_api_grpc::proto::golem::rib::Length {}),
510                RibIR::SelectIndexV1 => {
511                    Instruction::SelectIndexV1(golem_api_grpc::proto::golem::rib::SelectIndexV1 {})
512                }
513                RibIR::GreaterThanOrEqualTo => {
514                    Instruction::GreaterThanOrEqualTo(GreaterThanOrEqualTo {})
515                }
516                RibIR::LessThanOrEqualTo => Instruction::LessThanOrEqualTo(LessThanOrEqualTo {}),
517                RibIR::JumpIfFalse(value) => Instruction::JumpIfFalse(JumpInstruction {
518                    instruction_id: value.index as u64,
519                }),
520                RibIR::Jump(value) => Instruction::Jump(JumpInstruction {
521                    instruction_id: value.index as u64,
522                }),
523                RibIR::Label(value) => Instruction::Label(JumpInstruction {
524                    instruction_id: value.index as u64,
525                }),
526                RibIR::Deconstruct => {
527                    Instruction::Deconstruct((&AnalysedType::Str(TypeStr)).into())
528                } //TODO; remove type in deconstruct from protobuf
529                RibIR::InvokeFunction(
530                    component_dependency_key,
531                    worker_name_presence,
532                    arg_count,
533                    return_type,
534                ) => {
535                    let typ = match return_type {
536                        AnalysedTypeWithUnit::Unit => None,
537                        AnalysedTypeWithUnit::Type(analysed_type) => {
538                            let typ =
539                                golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type);
540                            Some(typ)
541                        }
542                    };
543
544                    let instance_variable = match worker_name_presence {
545                        InstanceVariable::WitResource(variable_id) => {
546                            golem_api_grpc::proto::golem::rib::InstanceVariable {
547                                kind: Some(
548                                    golem_api_grpc::proto::golem::rib::instance_variable::Kind::Resource(
549                                        WitResource {
550                                            variable_id: Some(variable_id.into()),
551                                        },
552                                    ),
553                                ),
554                            }
555                        }
556                        InstanceVariable::WitWorker(variable_id) => {
557                            golem_api_grpc::proto::golem::rib::InstanceVariable {
558                                kind: Some(
559                                    golem_api_grpc::proto::golem::rib::instance_variable::Kind::Worker(
560                                        golem_api_grpc::proto::golem::rib::WitWorker {
561                                            variable_id: Some(variable_id.into()),
562                                        },
563                                    ),
564                                ),
565                            }
566                        }
567                    };
568
569                    let component_dependency_key =
570                        golem_api_grpc::proto::golem::rib::ComponentDependencyKey::from(
571                            component_dependency_key,
572                        );
573
574                    Instruction::InvokeFunction(InvokeFunctionInstruction {
575                        component: Some(component_dependency_key),
576                        argument_count: arg_count as u64,
577                        return_type: typ,
578                        instance_variable: Some(instance_variable),
579                    })
580                }
581                RibIR::PushVariant(name, return_type) => {
582                    let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type);
583
584                    Instruction::VariantConstruction(
585                        golem_api_grpc::proto::golem::rib::VariantConstructionInstruction {
586                            variant_name: name,
587                            return_type: Some(typ),
588                        },
589                    )
590                }
591                RibIR::PushEnum(name, return_type) => {
592                    let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type);
593
594                    Instruction::EnumConstruction(
595                        golem_api_grpc::proto::golem::rib::EnumConstructionInstruction {
596                            enum_name: name,
597                            return_type: Some(typ),
598                        },
599                    )
600                }
601                RibIR::Throw(msg) => Instruction::Throw(msg),
602                RibIR::PushFlag(flag) => Instruction::PushFlag(flag.into()),
603                RibIR::GetTag => Instruction::GetTag(GetTag {}),
604                RibIR::PushTuple(analysed_type, size) => {
605                    let typ = golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type);
606
607                    Instruction::PushTuple(PushTupleInstruction {
608                        tuple_type: Some(typ),
609                        tuple_size: size as u64,
610                    })
611                }
612                RibIR::Concat(concat) => Instruction::Concat(ConcatInstruction {
613                    arg_size: concat as u64,
614                }),
615                RibIR::Negate => Instruction::Negate(Negate {}),
616                RibIR::CreateFunctionName(site, reference_type) => {
617                    Instruction::CreateFunctionName(CreateFunctionNameInstruction {
618                        site: Some(site.into()),
619                        function_reference_details: Some(reference_type.into()),
620                    })
621                }
622
623                RibIR::ToIterator => Instruction::ListToIterator(
624                    golem_api_grpc::proto::golem::rib::ListToIterator {},
625                ),
626                RibIR::CreateSink(analysed_type) => {
627                    Instruction::CreateSink(golem_api_grpc::proto::golem::rib::CreateSink {
628                        list_type: Some((&analysed_type).into()),
629                    })
630                }
631                RibIR::AdvanceIterator => Instruction::AdvanceIterator(
632                    golem_api_grpc::proto::golem::rib::AdvanceIterator {},
633                ),
634                RibIR::PushToSink => {
635                    Instruction::PushToSink(golem_api_grpc::proto::golem::rib::PushToSink {})
636                }
637                RibIR::SinkToList => {
638                    Instruction::SinkToList(golem_api_grpc::proto::golem::rib::SinkToList {})
639                }
640            };
641
642            Ok(ProtoRibIR {
643                instruction: Some(instruction),
644            })
645        }
646    }
647}