rib/compiler/
ir.rs

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