rib/
expr.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::call_type::{CallType, InstanceCreationType};
16use crate::generic_type_parameter::GenericTypeParameter;
17use crate::parser::block::block;
18use crate::parser::type_name::TypeName;
19use crate::rib_compilation_error::RibCompilationError;
20use crate::rib_source_span::SourceSpan;
21use crate::type_registry::FunctionTypeRegistry;
22use crate::{
23    from_string, text, type_checker, type_inference, DynamicParsedFunctionName,
24    GlobalVariableTypeSpec, InferredType, ParsedFunctionName, VariableId,
25};
26use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive};
27use combine::parser::char::spaces;
28use combine::stream::position;
29use combine::Parser;
30use combine::{eof, EasyParser};
31use golem_api_grpc::proto::golem::rib::range_expr::RangeExpr;
32use golem_wasm_ast::analysis::AnalysedType;
33use golem_wasm_rpc::{IntoValueAndType, ValueAndType};
34use serde::{Deserialize, Serialize, Serializer};
35use serde_json::Value;
36use std::collections::VecDeque;
37use std::fmt::Display;
38use std::ops::Deref;
39use std::str::FromStr;
40
41#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
42pub enum Expr {
43    Let {
44        variable_id: VariableId,
45        type_annotation: Option<TypeName>,
46        expr: Box<Expr>,
47        inferred_type: InferredType,
48        source_span: SourceSpan,
49    },
50    SelectField {
51        expr: Box<Expr>,
52        field: String,
53        type_annotation: Option<TypeName>,
54        inferred_type: InferredType,
55        source_span: SourceSpan,
56    },
57    SelectIndex {
58        expr: Box<Expr>,
59        index: Box<Expr>,
60        type_annotation: Option<TypeName>,
61        inferred_type: InferredType,
62        source_span: SourceSpan,
63    },
64    Sequence {
65        exprs: Vec<Expr>,
66        type_annotation: Option<TypeName>,
67        inferred_type: InferredType,
68        source_span: SourceSpan,
69    },
70    Range {
71        range: Range,
72        type_annotation: Option<TypeName>,
73        inferred_type: InferredType,
74        source_span: SourceSpan,
75    },
76    Record {
77        exprs: Vec<(String, Box<Expr>)>,
78        type_annotation: Option<TypeName>,
79        inferred_type: InferredType,
80        source_span: SourceSpan,
81    },
82    Tuple {
83        exprs: Vec<Expr>,
84        type_annotation: Option<TypeName>,
85        inferred_type: InferredType,
86        source_span: SourceSpan,
87    },
88    Literal {
89        value: String,
90        type_annotation: Option<TypeName>,
91        inferred_type: InferredType,
92        source_span: SourceSpan,
93    },
94    Number {
95        number: Number,
96        type_annotation: Option<TypeName>,
97        inferred_type: InferredType,
98        source_span: SourceSpan,
99    },
100    Flags {
101        flags: Vec<String>,
102        type_annotation: Option<TypeName>,
103        inferred_type: InferredType,
104        source_span: SourceSpan,
105    },
106    Identifier {
107        variable_id: VariableId,
108        type_annotation: Option<TypeName>,
109        inferred_type: InferredType,
110        source_span: SourceSpan,
111    },
112    Boolean {
113        value: bool,
114        type_annotation: Option<TypeName>,
115        inferred_type: InferredType,
116        source_span: SourceSpan,
117    },
118    Concat {
119        exprs: Vec<Expr>,
120        type_annotation: Option<TypeName>,
121        inferred_type: InferredType,
122        source_span: SourceSpan,
123    },
124    ExprBlock {
125        exprs: Vec<Expr>,
126        type_annotation: Option<TypeName>,
127        inferred_type: InferredType,
128        source_span: SourceSpan,
129    },
130    Not {
131        expr: Box<Expr>,
132        inferred_type: InferredType,
133        type_annotation: Option<TypeName>,
134        source_span: SourceSpan,
135    },
136    GreaterThan {
137        lhs: Box<Expr>,
138        rhs: Box<Expr>,
139        type_annotation: Option<TypeName>,
140        inferred_type: InferredType,
141        source_span: SourceSpan,
142    },
143    And {
144        lhs: Box<Expr>,
145        rhs: Box<Expr>,
146        type_annotation: Option<TypeName>,
147        inferred_type: InferredType,
148        source_span: SourceSpan,
149    },
150    Or {
151        lhs: Box<Expr>,
152        rhs: Box<Expr>,
153        type_annotation: Option<TypeName>,
154        inferred_type: InferredType,
155        source_span: SourceSpan,
156    },
157    GreaterThanOrEqualTo {
158        lhs: Box<Expr>,
159        rhs: Box<Expr>,
160        type_annotation: Option<TypeName>,
161        inferred_type: InferredType,
162        source_span: SourceSpan,
163    },
164    LessThanOrEqualTo {
165        lhs: Box<Expr>,
166        rhs: Box<Expr>,
167        type_annotation: Option<TypeName>,
168        inferred_type: InferredType,
169        source_span: SourceSpan,
170    },
171    Plus {
172        lhs: Box<Expr>,
173        rhs: Box<Expr>,
174        type_annotation: Option<TypeName>,
175        inferred_type: InferredType,
176        source_span: SourceSpan,
177    },
178    Multiply {
179        lhs: Box<Expr>,
180        rhs: Box<Expr>,
181        type_annotation: Option<TypeName>,
182        inferred_type: InferredType,
183        source_span: SourceSpan,
184    },
185    Minus {
186        lhs: Box<Expr>,
187        rhs: Box<Expr>,
188        type_annotation: Option<TypeName>,
189        inferred_type: InferredType,
190        source_span: SourceSpan,
191    },
192    Divide {
193        lhs: Box<Expr>,
194        rhs: Box<Expr>,
195        type_annotation: Option<TypeName>,
196        inferred_type: InferredType,
197        source_span: SourceSpan,
198    },
199    EqualTo {
200        lhs: Box<Expr>,
201        rhs: Box<Expr>,
202        type_annotation: Option<TypeName>,
203        inferred_type: InferredType,
204        source_span: SourceSpan,
205    },
206    LessThan {
207        lhs: Box<Expr>,
208        rhs: Box<Expr>,
209        type_annotation: Option<TypeName>,
210        inferred_type: InferredType,
211        source_span: SourceSpan,
212    },
213    Cond {
214        cond: Box<Expr>,
215        lhs: Box<Expr>,
216        rhs: Box<Expr>,
217        type_annotation: Option<TypeName>,
218        inferred_type: InferredType,
219        source_span: SourceSpan,
220    },
221    PatternMatch {
222        predicate: Box<Expr>,
223        match_arms: Vec<MatchArm>,
224        type_annotation: Option<TypeName>,
225        inferred_type: InferredType,
226        source_span: SourceSpan,
227    },
228    Option {
229        expr: Option<Box<Expr>>,
230        type_annotation: Option<TypeName>,
231        inferred_type: InferredType,
232        source_span: SourceSpan,
233    },
234    Result {
235        expr: Result<Box<Expr>, Box<Expr>>,
236        type_annotation: Option<TypeName>,
237        inferred_type: InferredType,
238        source_span: SourceSpan,
239    },
240    // instance[t]("my-worker") will be parsed sd Expr::Call { "instance", Some(t }, vec!["my-worker"] }
241    // will be parsed as Expr::Call { "instance", vec!["my-worker"] }.
242    // During function call inference phase, the type of this `Expr::Call` will be `Expr::Call { InstanceCreation,.. }
243    // with inferred-type as `InstanceType`. This way any variables attached to the instance creation
244    // will be having the `InstanceType`.
245    Call {
246        call_type: CallType,
247        generic_type_parameter: Option<GenericTypeParameter>,
248        args: Vec<Expr>,
249        type_annotation: Option<TypeName>,
250        inferred_type: InferredType,
251        source_span: SourceSpan,
252    },
253    // Any calls such as `my-worker-variable-expr.function_name()` will be parsed as Expr::Invoke
254    // such that `my-worker-variable-expr` (lhs) will be of the type `InferredType::InstanceType`. `lhs` will
255    // be `Expr::Call { InstanceCreation }` with type `InferredType::InstanceType`.
256    // As part of a separate type inference phase this will be converted back to `Expr::Call` with fully
257    // qualified function names (the complex version) which further takes part in all other type inference phases.
258    InvokeMethodLazy {
259        lhs: Box<Expr>,
260        method: String,
261        generic_type_parameter: Option<GenericTypeParameter>,
262        args: Vec<Expr>,
263        type_annotation: Option<TypeName>,
264        inferred_type: InferredType,
265        source_span: SourceSpan,
266    },
267    Unwrap {
268        expr: Box<Expr>,
269        inferred_type: InferredType,
270        type_annotation: Option<TypeName>,
271        source_span: SourceSpan,
272    },
273    Throw {
274        message: String,
275        inferred_type: InferredType,
276        type_annotation: Option<TypeName>,
277        source_span: SourceSpan,
278    },
279    GetTag {
280        expr: Box<Expr>,
281        inferred_type: InferredType,
282        type_annotation: Option<TypeName>,
283        source_span: SourceSpan,
284    },
285    ListComprehension {
286        iterated_variable: VariableId,
287        iterable_expr: Box<Expr>,
288        yield_expr: Box<Expr>,
289        type_annotation: Option<TypeName>,
290        inferred_type: InferredType,
291        source_span: SourceSpan,
292    },
293    ListReduce {
294        reduce_variable: VariableId,
295        iterated_variable: VariableId,
296        iterable_expr: Box<Expr>,
297        type_annotation: Option<TypeName>,
298        yield_expr: Box<Expr>,
299        init_value_expr: Box<Expr>,
300        inferred_type: InferredType,
301        source_span: SourceSpan,
302    },
303    Length {
304        expr: Box<Expr>,
305        inferred_type: InferredType,
306        type_annotation: Option<TypeName>,
307        source_span: SourceSpan,
308    },
309}
310
311impl Expr {
312    pub fn as_record(&self) -> Option<Vec<(String, Expr)>> {
313        match self {
314            Expr::Record { exprs: fields, .. } => Some(
315                fields
316                    .iter()
317                    .map(|(k, v)| (k.clone(), v.deref().clone()))
318                    .collect::<Vec<_>>(),
319            ),
320            _ => None,
321        }
322    }
323    /// Parse a text directly as Rib expression
324    /// Example of a Rib expression:
325    ///
326    /// ```rib
327    ///   let shopping-cart-worker = instance("my-worker");
328    ///   let result = shopping-cart-worker.add-to-cart({product-name: "apple", quantity: 2});
329    ///
330    ///   match result {
331    ///     ok(id) => "product-id-${id}",
332    ///     err(error_msg) => "Error: ${error_msg}"
333    ///   }
334    /// ```
335    ///
336    /// Rib supports conditional calls, function calls, pattern-matching,
337    /// string interpolation (see error_message above) etc.
338    ///
339    pub fn from_text(input: &str) -> Result<Expr, String> {
340        if input.trim().ends_with(';') {
341            return Err("unexpected `;` at the end of rib expression. \nnote: `;` is used to separate expressions, but it should not appear after the last expression (which is the return value)".to_string());
342        }
343
344        spaces()
345            .with(block().skip(eof()))
346            .easy_parse(position::Stream::new(input))
347            .map(|t| t.0)
348            .map_err(|err| format!("{}", err))
349    }
350
351    pub fn is_literal(&self) -> bool {
352        matches!(self, Expr::Literal { .. })
353    }
354
355    pub fn is_block(&self) -> bool {
356        matches!(self, Expr::ExprBlock { .. })
357    }
358
359    pub fn is_number(&self) -> bool {
360        matches!(self, Expr::Number { .. })
361    }
362
363    pub fn is_record(&self) -> bool {
364        matches!(self, Expr::Record { .. })
365    }
366
367    pub fn is_result(&self) -> bool {
368        matches!(self, Expr::Result { .. })
369    }
370
371    pub fn is_option(&self) -> bool {
372        matches!(self, Expr::Option { .. })
373    }
374
375    pub fn is_tuple(&self) -> bool {
376        matches!(self, Expr::Tuple { .. })
377    }
378
379    pub fn is_list(&self) -> bool {
380        matches!(self, Expr::Sequence { .. })
381    }
382
383    pub fn is_flags(&self) -> bool {
384        matches!(self, Expr::Flags { .. })
385    }
386
387    pub fn is_identifier(&self) -> bool {
388        matches!(self, Expr::Identifier { .. })
389    }
390
391    pub fn is_select_field(&self) -> bool {
392        matches!(self, Expr::SelectField { .. })
393    }
394
395    pub fn is_if_else(&self) -> bool {
396        matches!(self, Expr::Cond { .. })
397    }
398
399    pub fn is_function_call(&self) -> bool {
400        matches!(self, Expr::Call { .. })
401    }
402
403    pub fn is_match_expr(&self) -> bool {
404        matches!(self, Expr::PatternMatch { .. })
405    }
406
407    pub fn is_boolean(&self) -> bool {
408        matches!(self, Expr::Boolean { .. })
409    }
410
411    pub fn is_comparison(&self) -> bool {
412        matches!(
413            self,
414            Expr::GreaterThan { .. }
415                | Expr::GreaterThanOrEqualTo { .. }
416                | Expr::LessThanOrEqualTo { .. }
417                | Expr::EqualTo { .. }
418                | Expr::LessThan { .. }
419        )
420    }
421
422    pub fn is_concat(&self) -> bool {
423        matches!(self, Expr::Concat { .. })
424    }
425
426    pub fn is_multiple(&self) -> bool {
427        matches!(self, Expr::ExprBlock { .. })
428    }
429
430    pub fn inbuilt_variant(&self) -> Option<(String, Option<Expr>)> {
431        match self {
432            Expr::Option {
433                expr: Some(expr), ..
434            } => Some(("some".to_string(), Some(expr.deref().clone()))),
435            Expr::Option { expr: None, .. } => Some(("some".to_string(), None)),
436            Expr::Result { expr: Ok(expr), .. } => {
437                Some(("ok".to_string(), Some(expr.deref().clone())))
438            }
439            Expr::Result {
440                expr: Err(expr), ..
441            } => Some(("err".to_string(), Some(expr.deref().clone()))),
442            _ => None,
443        }
444    }
445    pub fn unwrap(&self) -> Self {
446        Expr::Unwrap {
447            expr: Box::new(self.clone()),
448            inferred_type: InferredType::Unknown,
449            source_span: SourceSpan::default(),
450            type_annotation: None,
451        }
452    }
453
454    pub fn length(expr: Expr) -> Self {
455        Expr::Length {
456            expr: Box::new(expr),
457            inferred_type: InferredType::U64,
458            source_span: SourceSpan::default(),
459            type_annotation: None,
460        }
461    }
462
463    pub fn boolean(value: bool) -> Self {
464        Expr::Boolean {
465            value,
466            inferred_type: InferredType::Bool,
467            source_span: SourceSpan::default(),
468            type_annotation: None,
469        }
470    }
471
472    pub fn and(left: Expr, right: Expr) -> Self {
473        Expr::And {
474            lhs: Box::new(left),
475            rhs: Box::new(right),
476            inferred_type: InferredType::Bool,
477            source_span: SourceSpan::default(),
478            type_annotation: None,
479        }
480    }
481
482    pub fn throw(message: impl AsRef<str>) -> Self {
483        Expr::Throw {
484            message: message.as_ref().to_string(),
485            inferred_type: InferredType::Unknown,
486            source_span: SourceSpan::default(),
487            type_annotation: None,
488        }
489    }
490
491    pub fn plus(left: Expr, right: Expr) -> Self {
492        Expr::Plus {
493            lhs: Box::new(left),
494            rhs: Box::new(right),
495            inferred_type: InferredType::Unknown,
496            source_span: SourceSpan::default(),
497            type_annotation: None,
498        }
499    }
500
501    pub fn minus(left: Expr, right: Expr) -> Self {
502        Expr::Minus {
503            lhs: Box::new(left),
504            rhs: Box::new(right),
505            inferred_type: InferredType::number(),
506            source_span: SourceSpan::default(),
507            type_annotation: None,
508        }
509    }
510
511    pub fn divide(left: Expr, right: Expr) -> Self {
512        Expr::Divide {
513            lhs: Box::new(left),
514            rhs: Box::new(right),
515            inferred_type: InferredType::number(),
516            source_span: SourceSpan::default(),
517            type_annotation: None,
518        }
519    }
520
521    pub fn multiply(left: Expr, right: Expr) -> Self {
522        Expr::Multiply {
523            lhs: Box::new(left),
524            rhs: Box::new(right),
525            inferred_type: InferredType::number(),
526            source_span: SourceSpan::default(),
527            type_annotation: None,
528        }
529    }
530
531    pub fn and_combine(conditions: Vec<Expr>) -> Option<Expr> {
532        let mut cond: Option<Expr> = None;
533
534        for i in conditions {
535            let left = Box::new(cond.clone().unwrap_or(Expr::boolean(true)));
536            cond = Some(Expr::And {
537                lhs: left,
538                rhs: Box::new(i),
539                inferred_type: InferredType::Bool,
540                source_span: SourceSpan::default(),
541                type_annotation: None,
542            });
543        }
544
545        cond
546    }
547
548    pub fn call_worker_function(
549        dynamic_parsed_fn_name: DynamicParsedFunctionName,
550        generic_type_parameter: Option<GenericTypeParameter>,
551        worker_name: Option<Expr>,
552        args: Vec<Expr>,
553    ) -> Self {
554        Expr::Call {
555            call_type: CallType::Function {
556                function_name: dynamic_parsed_fn_name,
557                worker: worker_name.map(Box::new),
558            },
559            generic_type_parameter,
560            args,
561            inferred_type: InferredType::Unknown,
562            source_span: SourceSpan::default(),
563            type_annotation: None,
564        }
565    }
566
567    pub fn call(
568        call_type: CallType,
569        generic_type_parameter: Option<GenericTypeParameter>,
570        args: Vec<Expr>,
571    ) -> Self {
572        Expr::Call {
573            call_type,
574            generic_type_parameter,
575            args,
576            inferred_type: InferredType::Unknown,
577            source_span: SourceSpan::default(),
578            type_annotation: None,
579        }
580    }
581
582    pub fn invoke_worker_function(
583        lhs: Expr,
584        function_name: String,
585        generic_type_parameter: Option<GenericTypeParameter>,
586        args: Vec<Expr>,
587    ) -> Self {
588        Expr::InvokeMethodLazy {
589            lhs: Box::new(lhs),
590            method: function_name,
591            generic_type_parameter,
592            args,
593            inferred_type: InferredType::Unknown,
594            source_span: SourceSpan::default(),
595            type_annotation: None,
596        }
597    }
598
599    pub fn concat(expressions: Vec<Expr>) -> Self {
600        Expr::Concat {
601            exprs: expressions,
602            inferred_type: InferredType::Str,
603            source_span: SourceSpan::default(),
604            type_annotation: None,
605        }
606    }
607
608    pub fn cond(cond: Expr, lhs: Expr, rhs: Expr) -> Self {
609        Expr::Cond {
610            cond: Box::new(cond),
611            lhs: Box::new(lhs),
612            rhs: Box::new(rhs),
613            inferred_type: InferredType::Unknown,
614            source_span: SourceSpan::default(),
615            type_annotation: None,
616        }
617    }
618
619    pub fn equal_to(left: Expr, right: Expr) -> Self {
620        Expr::EqualTo {
621            lhs: Box::new(left),
622            rhs: Box::new(right),
623            inferred_type: InferredType::Bool,
624            source_span: SourceSpan::default(),
625            type_annotation: None,
626        }
627    }
628
629    pub fn err(expr: Expr, type_annotation: Option<TypeName>) -> Self {
630        let inferred_type = expr.inferred_type();
631        Expr::Result {
632            expr: Err(Box::new(expr)),
633            type_annotation,
634            inferred_type: InferredType::Result {
635                ok: Some(Box::new(InferredType::Unknown)),
636                error: Some(Box::new(inferred_type)),
637            },
638            source_span: SourceSpan::default(),
639        }
640    }
641
642    pub fn flags(flags: Vec<String>) -> Self {
643        Expr::Flags {
644            flags: flags.clone(),
645            inferred_type: InferredType::Flags(flags),
646            source_span: SourceSpan::default(),
647            type_annotation: None,
648        }
649    }
650
651    pub fn greater_than(left: Expr, right: Expr) -> Self {
652        Expr::GreaterThan {
653            lhs: Box::new(left),
654            rhs: Box::new(right),
655            inferred_type: InferredType::Bool,
656            source_span: SourceSpan::default(),
657            type_annotation: None,
658        }
659    }
660
661    pub fn greater_than_or_equal_to(left: Expr, right: Expr) -> Self {
662        Expr::GreaterThanOrEqualTo {
663            lhs: Box::new(left),
664            rhs: Box::new(right),
665            inferred_type: InferredType::Bool,
666            source_span: SourceSpan::default(),
667            type_annotation: None,
668        }
669    }
670
671    // An identifier by default is global until name-binding phase is run
672    pub fn identifier_global(name: impl AsRef<str>, type_annotation: Option<TypeName>) -> Self {
673        Expr::Identifier {
674            variable_id: VariableId::global(name.as_ref().to_string()),
675            type_annotation,
676            inferred_type: InferredType::Unknown,
677            source_span: SourceSpan::default(),
678        }
679    }
680
681    pub fn identifier_local(
682        name: impl AsRef<str>,
683        id: u32,
684        type_annotation: Option<TypeName>,
685    ) -> Self {
686        Expr::Identifier {
687            variable_id: VariableId::local(name.as_ref(), id),
688            type_annotation,
689            inferred_type: InferredType::Unknown,
690            source_span: SourceSpan::default(),
691        }
692    }
693
694    pub fn identifier_with_variable_id(
695        variable_id: VariableId,
696        type_annotation: Option<TypeName>,
697    ) -> Self {
698        Expr::Identifier {
699            variable_id,
700            type_annotation,
701            inferred_type: InferredType::Unknown,
702            source_span: SourceSpan::default(),
703        }
704    }
705
706    pub fn less_than(left: Expr, right: Expr) -> Self {
707        Expr::LessThan {
708            lhs: Box::new(left),
709            rhs: Box::new(right),
710            inferred_type: InferredType::Bool,
711            source_span: SourceSpan::default(),
712            type_annotation: None,
713        }
714    }
715
716    pub fn less_than_or_equal_to(left: Expr, right: Expr) -> Self {
717        Expr::LessThanOrEqualTo {
718            lhs: Box::new(left),
719            rhs: Box::new(right),
720            inferred_type: InferredType::Bool,
721            source_span: SourceSpan::default(),
722            type_annotation: None,
723        }
724    }
725
726    pub fn range(from: Expr, to: Expr) -> Self {
727        Expr::Range {
728            range: Range::Range {
729                from: Box::new(from.clone()),
730                to: Box::new(to.clone()),
731            },
732            inferred_type: InferredType::Range {
733                from: Box::new(from.inferred_type()),
734                to: Some(Box::new(to.inferred_type())),
735            },
736            source_span: SourceSpan::default(),
737            type_annotation: None,
738        }
739    }
740
741    pub fn range_from(from: Expr) -> Self {
742        Expr::Range {
743            range: Range::RangeFrom {
744                from: Box::new(from.clone()),
745            },
746            inferred_type: InferredType::Range {
747                from: Box::new(from.inferred_type()),
748                to: None,
749            },
750            source_span: SourceSpan::default(),
751            type_annotation: None,
752        }
753    }
754
755    pub fn range_inclusive(from: Expr, to: Expr) -> Self {
756        Expr::Range {
757            range: Range::RangeInclusive {
758                from: Box::new(from.clone()),
759                to: Box::new(to.clone()),
760            },
761            inferred_type: InferredType::Range {
762                from: Box::new(from.inferred_type()),
763                to: Some(Box::new(to.inferred_type())),
764            },
765            source_span: SourceSpan::default(),
766            type_annotation: None,
767        }
768    }
769
770    pub fn let_binding(
771        name: impl AsRef<str>,
772        expr: Expr,
773        type_annotation: Option<TypeName>,
774    ) -> Self {
775        Expr::Let {
776            variable_id: VariableId::global(name.as_ref().to_string()),
777            type_annotation,
778            expr: Box::new(expr),
779            source_span: SourceSpan::default(),
780            inferred_type: InferredType::Tuple(vec![]),
781        }
782    }
783
784    pub fn let_binding_with_variable_id(
785        variable_id: VariableId,
786        expr: Expr,
787        type_annotation: Option<TypeName>,
788    ) -> Self {
789        Expr::Let {
790            variable_id,
791            type_annotation,
792            expr: Box::new(expr),
793            source_span: SourceSpan::default(),
794            inferred_type: InferredType::Tuple(vec![]),
795        }
796    }
797
798    pub fn typed_list_reduce(
799        reduce_variable: VariableId,
800        iterated_variable: VariableId,
801        iterable_expr: Expr,
802        init_value_expr: Expr,
803        yield_expr: Expr,
804        inferred_type: InferredType,
805    ) -> Self {
806        Expr::ListReduce {
807            reduce_variable,
808            iterated_variable,
809            iterable_expr: Box::new(iterable_expr),
810            yield_expr: Box::new(yield_expr),
811            init_value_expr: Box::new(init_value_expr),
812            inferred_type,
813            source_span: SourceSpan::default(),
814            type_annotation: None,
815        }
816    }
817
818    pub fn list_reduce(
819        reduce_variable: VariableId,
820        iterated_variable: VariableId,
821        iterable_expr: Expr,
822        init_value_expr: Expr,
823        yield_expr: Expr,
824    ) -> Self {
825        Expr::typed_list_reduce(
826            reduce_variable,
827            iterated_variable,
828            iterable_expr,
829            init_value_expr,
830            yield_expr,
831            InferredType::Unknown,
832        )
833    }
834
835    pub fn list_comprehension_typed(
836        iterated_variable: VariableId,
837        iterable_expr: Expr,
838        yield_expr: Expr,
839        inferred_type: InferredType,
840    ) -> Self {
841        Expr::ListComprehension {
842            iterated_variable,
843            iterable_expr: Box::new(iterable_expr),
844            yield_expr: Box::new(yield_expr),
845            inferred_type,
846            source_span: SourceSpan::default(),
847            type_annotation: None,
848        }
849    }
850
851    pub fn list_comprehension(
852        variable_id: VariableId,
853        iterable_expr: Expr,
854        yield_expr: Expr,
855    ) -> Self {
856        Expr::list_comprehension_typed(
857            variable_id,
858            iterable_expr,
859            yield_expr,
860            InferredType::List(Box::new(InferredType::Unknown)),
861        )
862    }
863
864    pub fn bind_global_variable_types(
865        &self,
866        type_spec: &Vec<GlobalVariableTypeSpec>,
867    ) -> Result<Self, RibCompilationError> {
868        type_inference::bind_global_variable_types(self, type_spec)
869    }
870
871    pub fn bind_instance_types(&mut self) {
872        type_inference::bind_instance_types(self)
873    }
874
875    pub fn literal(value: impl AsRef<str>) -> Self {
876        Expr::Literal {
877            value: value.as_ref().to_string(),
878            inferred_type: InferredType::Str,
879            source_span: SourceSpan::default(),
880            type_annotation: None,
881        }
882    }
883
884    pub fn empty_expr() -> Self {
885        Expr::literal("")
886    }
887
888    pub fn expr_block(expressions: Vec<Expr>) -> Self {
889        let inferred_type = expressions
890            .last()
891            .map_or(InferredType::Unknown, |e| e.inferred_type());
892
893        Expr::ExprBlock {
894            exprs: expressions,
895            inferred_type,
896            source_span: SourceSpan::default(),
897            type_annotation: None,
898        }
899    }
900
901    #[allow(clippy::should_implement_trait)]
902    pub fn not(expr: Expr) -> Self {
903        Expr::Not {
904            expr: Box::new(expr),
905            inferred_type: InferredType::Bool,
906            source_span: SourceSpan::default(),
907            type_annotation: None,
908        }
909    }
910
911    pub fn ok(expr: Expr, type_annotation: Option<TypeName>) -> Self {
912        let inferred_type = expr.inferred_type();
913
914        Expr::Result {
915            expr: Ok(Box::new(expr)),
916            type_annotation,
917            inferred_type: InferredType::Result {
918                ok: Some(Box::new(inferred_type)),
919                error: Some(Box::new(InferredType::Unknown)),
920            },
921            source_span: SourceSpan::default(),
922        }
923    }
924
925    pub fn option(expr: Option<Expr>) -> Self {
926        let inferred_type = match &expr {
927            Some(expr) => expr.inferred_type(),
928            None => InferredType::Unknown,
929        };
930
931        Expr::Option {
932            expr: expr.map(Box::new),
933            type_annotation: None,
934            inferred_type: InferredType::Option(Box::new(inferred_type)),
935            source_span: SourceSpan::default(),
936        }
937    }
938
939    pub fn or(left: Expr, right: Expr) -> Self {
940        Expr::Or {
941            lhs: Box::new(left),
942            rhs: Box::new(right),
943            inferred_type: InferredType::Bool,
944            source_span: SourceSpan::default(),
945            type_annotation: None,
946        }
947    }
948
949    pub fn pattern_match(expr: Expr, match_arms: Vec<MatchArm>) -> Self {
950        Expr::PatternMatch {
951            predicate: Box::new(expr),
952            match_arms,
953            inferred_type: InferredType::Unknown,
954            source_span: SourceSpan::default(),
955            type_annotation: None,
956        }
957    }
958
959    pub fn record(expressions: Vec<(String, Expr)>) -> Self {
960        let inferred_type = InferredType::Record(
961            expressions
962                .iter()
963                .map(|(field_name, expr)| (field_name.to_string(), expr.inferred_type()))
964                .collect(),
965        );
966
967        Expr::Record {
968            exprs: expressions
969                .into_iter()
970                .map(|(field_name, expr)| (field_name, Box::new(expr)))
971                .collect(),
972            inferred_type,
973            source_span: SourceSpan::default(),
974            type_annotation: None,
975        }
976    }
977
978    pub fn select_field(
979        expr: Expr,
980        field: impl AsRef<str>,
981        type_annotation: Option<TypeName>,
982    ) -> Self {
983        Expr::SelectField {
984            expr: Box::new(expr),
985            field: field.as_ref().to_string(),
986            type_annotation,
987            inferred_type: InferredType::Unknown,
988            source_span: SourceSpan::default(),
989        }
990    }
991
992    pub fn select_index(expr: Expr, index: Expr) -> Self {
993        Expr::SelectIndex {
994            expr: Box::new(expr),
995            index: Box::new(index),
996            type_annotation: None,
997            inferred_type: InferredType::Unknown,
998            source_span: SourceSpan::default(),
999        }
1000    }
1001
1002    pub fn get_tag(expr: Expr) -> Self {
1003        Expr::GetTag {
1004            expr: Box::new(expr),
1005            inferred_type: InferredType::Unknown,
1006            source_span: SourceSpan::default(),
1007            type_annotation: None,
1008        }
1009    }
1010
1011    pub fn tuple(expressions: Vec<Expr>) -> Self {
1012        let inferred_type = InferredType::Tuple(
1013            expressions
1014                .iter()
1015                .map(|expr| expr.inferred_type())
1016                .collect(),
1017        );
1018
1019        Expr::Tuple {
1020            exprs: expressions,
1021            inferred_type,
1022            source_span: SourceSpan::default(),
1023            type_annotation: None,
1024        }
1025    }
1026
1027    pub fn sequence(expressions: Vec<Expr>, type_annotation: Option<TypeName>) -> Self {
1028        let inferred_type = InferredType::List(Box::new(
1029            expressions
1030                .first()
1031                .map_or(InferredType::Unknown, |x| x.inferred_type()),
1032        ));
1033
1034        Expr::Sequence {
1035            exprs: expressions,
1036            type_annotation,
1037            inferred_type,
1038            source_span: SourceSpan::default(),
1039        }
1040    }
1041
1042    pub fn inferred_type(&self) -> InferredType {
1043        match self {
1044            Expr::Let { inferred_type, .. }
1045            | Expr::SelectField { inferred_type, .. }
1046            | Expr::SelectIndex { inferred_type, .. }
1047            | Expr::Sequence { inferred_type, .. }
1048            | Expr::Record { inferred_type, .. }
1049            | Expr::Tuple { inferred_type, .. }
1050            | Expr::Literal { inferred_type, .. }
1051            | Expr::Number { inferred_type, .. }
1052            | Expr::Flags { inferred_type, .. }
1053            | Expr::Identifier { inferred_type, .. }
1054            | Expr::Boolean { inferred_type, .. }
1055            | Expr::Concat { inferred_type, .. }
1056            | Expr::ExprBlock { inferred_type, .. }
1057            | Expr::Not { inferred_type, .. }
1058            | Expr::GreaterThan { inferred_type, .. }
1059            | Expr::GreaterThanOrEqualTo { inferred_type, .. }
1060            | Expr::LessThanOrEqualTo { inferred_type, .. }
1061            | Expr::EqualTo { inferred_type, .. }
1062            | Expr::Plus { inferred_type, .. }
1063            | Expr::Minus { inferred_type, .. }
1064            | Expr::Divide { inferred_type, .. }
1065            | Expr::Multiply { inferred_type, .. }
1066            | Expr::LessThan { inferred_type, .. }
1067            | Expr::Cond { inferred_type, .. }
1068            | Expr::PatternMatch { inferred_type, .. }
1069            | Expr::Option { inferred_type, .. }
1070            | Expr::Result { inferred_type, .. }
1071            | Expr::Unwrap { inferred_type, .. }
1072            | Expr::Throw { inferred_type, .. }
1073            | Expr::GetTag { inferred_type, .. }
1074            | Expr::And { inferred_type, .. }
1075            | Expr::Or { inferred_type, .. }
1076            | Expr::ListComprehension { inferred_type, .. }
1077            | Expr::ListReduce { inferred_type, .. }
1078            | Expr::Call { inferred_type, .. }
1079            | Expr::Range { inferred_type, .. }
1080            | Expr::InvokeMethodLazy { inferred_type, .. } => inferred_type.clone(),
1081            Expr::Length { inferred_type, .. } => inferred_type.clone(),
1082        }
1083    }
1084
1085    pub fn infer_types(
1086        &mut self,
1087        function_type_registry: &FunctionTypeRegistry,
1088        type_spec: &Vec<GlobalVariableTypeSpec>,
1089    ) -> Result<(), RibCompilationError> {
1090        self.infer_types_initial_phase(function_type_registry, type_spec)?;
1091        self.bind_instance_types();
1092        // Identifying the first fix point with method calls to infer all
1093        // worker function invocations as this forms the foundation for the rest of the
1094        // compilation. This is compiler doing its best to infer all the calls such
1095        // as worker invokes or instance calls etc.
1096        type_inference::type_inference_fix_point(Self::resolve_method_calls, self)?;
1097        self.infer_function_call_types(function_type_registry)?;
1098        type_inference::type_inference_fix_point(Self::inference_scan, self)?;
1099        self.infer_orphan_literals()?;
1100        self.check_types(function_type_registry)?;
1101        self.unify_types()?;
1102        Ok(())
1103    }
1104
1105    pub fn infer_types_initial_phase(
1106        &mut self,
1107        function_type_registry: &FunctionTypeRegistry,
1108        type_spec: &Vec<GlobalVariableTypeSpec>,
1109    ) -> Result<(), RibCompilationError> {
1110        self.identify_instance_creation(function_type_registry)?;
1111        *self = self.bind_global_variable_types(type_spec)?;
1112        self.bind_type_annotations();
1113        self.bind_default_types_to_index_expressions();
1114        self.bind_variables_of_list_comprehension();
1115        self.bind_variables_of_list_reduce();
1116        self.bind_variables_of_pattern_match();
1117        self.bind_variables_of_let_assignment();
1118        self.infer_variants(function_type_registry);
1119        self.infer_enums(function_type_registry);
1120        Ok(())
1121    }
1122
1123    pub fn resolve_method_calls(&mut self) -> Result<(), RibCompilationError> {
1124        self.bind_instance_types();
1125        self.infer_worker_function_invokes()?;
1126        Ok(())
1127    }
1128
1129    // An inference is a single cycle of to-and-fro scanning of Rib expression, that it takes part in fix point of inference.
1130    // Not all phases of compilation will be part of this scan.
1131    // Example: function call argument inference based on the worker function hardly needs to be part of the scan.
1132    pub fn inference_scan(&mut self) -> Result<(), RibCompilationError> {
1133        self.infer_all_identifiers();
1134        self.push_types_down()?;
1135        self.infer_all_identifiers();
1136        let expr = self.pull_types_up()?;
1137        *self = expr;
1138        self.infer_global_inputs();
1139        Ok(())
1140    }
1141
1142    pub fn infer_orphan_literals(&mut self) -> Result<(), RibCompilationError> {
1143        type_inference::infer_orphan_literals(self)
1144    }
1145
1146    pub fn infer_worker_function_invokes(&mut self) -> Result<(), RibCompilationError> {
1147        type_inference::infer_worker_function_invokes(self)
1148    }
1149
1150    pub fn bind_default_types_to_index_expressions(&mut self) {
1151        type_inference::bind_default_types_to_index_expressions(self);
1152    }
1153
1154    // Make sure the bindings in the arm pattern of a pattern match are given variable-ids.
1155    // The same variable-ids will be tagged to the corresponding identifiers in the arm resolution
1156    // to avoid conflicts.
1157    pub fn bind_variables_of_pattern_match(&mut self) {
1158        type_inference::bind_variables_of_pattern_match(self);
1159    }
1160
1161    // Make sure the variable assignment (let binding) are given variable ids,
1162    // which will be tagged to the corresponding identifiers to avoid conflicts.
1163    // This is done only for local variables and not global variables
1164    pub fn bind_variables_of_let_assignment(&mut self) {
1165        type_inference::bind_variables_of_let_assignment(self);
1166    }
1167
1168    pub fn bind_variables_of_list_comprehension(&mut self) {
1169        type_inference::bind_variables_of_list_comprehension(self);
1170    }
1171
1172    pub fn bind_variables_of_list_reduce(&mut self) {
1173        type_inference::bind_variables_of_list_reduce(self);
1174    }
1175
1176    pub fn identify_instance_creation(
1177        &mut self,
1178        function_type_registry: &FunctionTypeRegistry,
1179    ) -> Result<(), RibCompilationError> {
1180        type_inference::identify_instance_creation(self, function_type_registry)
1181    }
1182
1183    pub fn infer_function_call_types(
1184        &mut self,
1185        function_type_registry: &FunctionTypeRegistry,
1186    ) -> Result<(), RibCompilationError> {
1187        type_inference::infer_function_call_types(self, function_type_registry)?;
1188        Ok(())
1189    }
1190
1191    pub fn push_types_down(&mut self) -> Result<(), RibCompilationError> {
1192        type_inference::push_types_down(self)
1193    }
1194
1195    pub fn infer_all_identifiers(&mut self) {
1196        type_inference::infer_all_identifiers(self)
1197    }
1198
1199    pub fn pull_types_up(&self) -> Result<Expr, RibCompilationError> {
1200        type_inference::type_pull_up(self)
1201    }
1202
1203    pub fn infer_global_inputs(&mut self) {
1204        type_inference::infer_global_inputs(self);
1205    }
1206
1207    pub fn bind_type_annotations(&mut self) {
1208        type_inference::bind_type_annotations(self);
1209    }
1210
1211    pub fn check_types(
1212        &mut self,
1213        function_type_registry: &FunctionTypeRegistry,
1214    ) -> Result<(), RibCompilationError> {
1215        type_checker::type_check(self, function_type_registry)
1216    }
1217
1218    pub fn unify_types(&mut self) -> Result<(), RibCompilationError> {
1219        type_inference::unify_types(self)?;
1220        Ok(())
1221    }
1222
1223    pub fn merge_inferred_type(&self, new_inferred_type: InferredType) -> Expr {
1224        let mut expr_copied = self.clone();
1225        expr_copied.add_infer_type_mut(new_inferred_type);
1226        expr_copied
1227    }
1228
1229    pub fn add_infer_type_mut(&mut self, new_inferred_type: InferredType) {
1230        match self {
1231            Expr::Identifier { inferred_type, .. }
1232            | Expr::Let { inferred_type, .. }
1233            | Expr::SelectField { inferred_type, .. }
1234            | Expr::SelectIndex { inferred_type, .. }
1235            | Expr::Sequence { inferred_type, .. }
1236            | Expr::Record { inferred_type, .. }
1237            | Expr::Tuple { inferred_type, .. }
1238            | Expr::Literal { inferred_type, .. }
1239            | Expr::Number { inferred_type, .. }
1240            | Expr::Flags { inferred_type, .. }
1241            | Expr::Boolean { inferred_type, .. }
1242            | Expr::Concat { inferred_type, .. }
1243            | Expr::ExprBlock { inferred_type, .. }
1244            | Expr::Not { inferred_type, .. }
1245            | Expr::GreaterThan { inferred_type, .. }
1246            | Expr::GreaterThanOrEqualTo { inferred_type, .. }
1247            | Expr::LessThanOrEqualTo { inferred_type, .. }
1248            | Expr::EqualTo { inferred_type, .. }
1249            | Expr::Plus { inferred_type, .. }
1250            | Expr::Minus { inferred_type, .. }
1251            | Expr::Divide { inferred_type, .. }
1252            | Expr::Multiply { inferred_type, .. }
1253            | Expr::LessThan { inferred_type, .. }
1254            | Expr::Cond { inferred_type, .. }
1255            | Expr::PatternMatch { inferred_type, .. }
1256            | Expr::Option { inferred_type, .. }
1257            | Expr::Result { inferred_type, .. }
1258            | Expr::Unwrap { inferred_type, .. }
1259            | Expr::Throw { inferred_type, .. }
1260            | Expr::GetTag { inferred_type, .. }
1261            | Expr::And { inferred_type, .. }
1262            | Expr::Or { inferred_type, .. }
1263            | Expr::ListComprehension { inferred_type, .. }
1264            | Expr::ListReduce { inferred_type, .. }
1265            | Expr::InvokeMethodLazy { inferred_type, .. }
1266            | Expr::Range { inferred_type, .. }
1267            | Expr::Length { inferred_type, .. }
1268            | Expr::Call { inferred_type, .. } => {
1269                if new_inferred_type != InferredType::Unknown {
1270                    *inferred_type = inferred_type.merge(new_inferred_type);
1271                }
1272            }
1273        }
1274    }
1275
1276    pub fn reset_type(&mut self) {
1277        type_inference::reset_type_info(self);
1278    }
1279
1280    pub fn source_span(&self) -> SourceSpan {
1281        match self {
1282            Expr::Identifier { source_span, .. }
1283            | Expr::Let { source_span, .. }
1284            | Expr::SelectField { source_span, .. }
1285            | Expr::SelectIndex { source_span, .. }
1286            | Expr::Sequence { source_span, .. }
1287            | Expr::Record { source_span, .. }
1288            | Expr::Tuple { source_span, .. }
1289            | Expr::Literal { source_span, .. }
1290            | Expr::Number { source_span, .. }
1291            | Expr::Flags { source_span, .. }
1292            | Expr::Boolean { source_span, .. }
1293            | Expr::Concat { source_span, .. }
1294            | Expr::ExprBlock { source_span, .. }
1295            | Expr::Not { source_span, .. }
1296            | Expr::GreaterThan { source_span, .. }
1297            | Expr::GreaterThanOrEqualTo { source_span, .. }
1298            | Expr::LessThanOrEqualTo { source_span, .. }
1299            | Expr::EqualTo { source_span, .. }
1300            | Expr::LessThan { source_span, .. }
1301            | Expr::Plus { source_span, .. }
1302            | Expr::Minus { source_span, .. }
1303            | Expr::Divide { source_span, .. }
1304            | Expr::Multiply { source_span, .. }
1305            | Expr::Cond { source_span, .. }
1306            | Expr::PatternMatch { source_span, .. }
1307            | Expr::Option { source_span, .. }
1308            | Expr::Result { source_span, .. }
1309            | Expr::Unwrap { source_span, .. }
1310            | Expr::Throw { source_span, .. }
1311            | Expr::And { source_span, .. }
1312            | Expr::Or { source_span, .. }
1313            | Expr::GetTag { source_span, .. }
1314            | Expr::ListComprehension { source_span, .. }
1315            | Expr::ListReduce { source_span, .. }
1316            | Expr::InvokeMethodLazy { source_span, .. }
1317            | Expr::Range { source_span, .. }
1318            | Expr::Length { source_span, .. }
1319            | Expr::Call { source_span, .. } => source_span.clone(),
1320        }
1321    }
1322
1323    pub fn with_type_annotation_opt(&self, type_annotation: Option<TypeName>) -> Expr {
1324        if let Some(type_annotation) = type_annotation {
1325            self.with_type_annotation(type_annotation)
1326        } else {
1327            self.clone()
1328        }
1329    }
1330
1331    pub fn with_type_annotation(&self, type_annotation: TypeName) -> Expr {
1332        let mut expr_copied = self.clone();
1333        expr_copied.with_type_annotation_mut(type_annotation);
1334        expr_copied
1335    }
1336
1337    pub fn with_type_annotation_mut(&mut self, type_annotation: TypeName) {
1338        let new_type_annotation = type_annotation;
1339
1340        match self {
1341            Expr::Identifier {
1342                type_annotation, ..
1343            }
1344            | Expr::Let {
1345                type_annotation, ..
1346            }
1347            | Expr::SelectField {
1348                type_annotation, ..
1349            }
1350            | Expr::SelectIndex {
1351                type_annotation, ..
1352            }
1353            | Expr::Sequence {
1354                type_annotation, ..
1355            }
1356            | Expr::Record {
1357                type_annotation, ..
1358            }
1359            | Expr::Tuple {
1360                type_annotation, ..
1361            }
1362            | Expr::Literal {
1363                type_annotation, ..
1364            }
1365            | Expr::Number {
1366                type_annotation, ..
1367            }
1368            | Expr::Flags {
1369                type_annotation, ..
1370            }
1371            | Expr::Boolean {
1372                type_annotation, ..
1373            }
1374            | Expr::Concat {
1375                type_annotation, ..
1376            }
1377            | Expr::ExprBlock {
1378                type_annotation, ..
1379            }
1380            | Expr::Not {
1381                type_annotation, ..
1382            }
1383            | Expr::GreaterThan {
1384                type_annotation, ..
1385            }
1386            | Expr::GreaterThanOrEqualTo {
1387                type_annotation, ..
1388            }
1389            | Expr::LessThanOrEqualTo {
1390                type_annotation, ..
1391            }
1392            | Expr::EqualTo {
1393                type_annotation, ..
1394            }
1395            | Expr::LessThan {
1396                type_annotation, ..
1397            }
1398            | Expr::Plus {
1399                type_annotation, ..
1400            }
1401            | Expr::Minus {
1402                type_annotation, ..
1403            }
1404            | Expr::Divide {
1405                type_annotation, ..
1406            }
1407            | Expr::Multiply {
1408                type_annotation, ..
1409            }
1410            | Expr::Cond {
1411                type_annotation, ..
1412            }
1413            | Expr::PatternMatch {
1414                type_annotation, ..
1415            }
1416            | Expr::Option {
1417                type_annotation, ..
1418            }
1419            | Expr::Result {
1420                type_annotation, ..
1421            }
1422            | Expr::Unwrap {
1423                type_annotation, ..
1424            }
1425            | Expr::Throw {
1426                type_annotation, ..
1427            }
1428            | Expr::And {
1429                type_annotation, ..
1430            }
1431            | Expr::Or {
1432                type_annotation, ..
1433            }
1434            | Expr::GetTag {
1435                type_annotation, ..
1436            }
1437            | Expr::Range {
1438                type_annotation, ..
1439            }
1440            | Expr::ListComprehension {
1441                type_annotation, ..
1442            }
1443            | Expr::ListReduce {
1444                type_annotation, ..
1445            }
1446            | Expr::InvokeMethodLazy {
1447                type_annotation, ..
1448            }
1449            | Expr::Length {
1450                type_annotation, ..
1451            }
1452            | Expr::Call {
1453                type_annotation, ..
1454            } => {
1455                *type_annotation = Some(new_type_annotation);
1456            }
1457        }
1458    }
1459
1460    pub fn with_source_span(&self, new_source_span: SourceSpan) -> Expr {
1461        let mut expr_copied = self.clone();
1462        expr_copied.with_source_span_mut(new_source_span);
1463        expr_copied
1464    }
1465
1466    pub fn with_source_span_mut(&mut self, new_source_span: SourceSpan) {
1467        match self {
1468            Expr::Identifier { source_span, .. }
1469            | Expr::Let { source_span, .. }
1470            | Expr::SelectField { source_span, .. }
1471            | Expr::SelectIndex { source_span, .. }
1472            | Expr::Sequence { source_span, .. }
1473            | Expr::Record { source_span, .. }
1474            | Expr::Tuple { source_span, .. }
1475            | Expr::Literal { source_span, .. }
1476            | Expr::Number { source_span, .. }
1477            | Expr::Flags { source_span, .. }
1478            | Expr::Boolean { source_span, .. }
1479            | Expr::Concat { source_span, .. }
1480            | Expr::ExprBlock { source_span, .. }
1481            | Expr::Not { source_span, .. }
1482            | Expr::GreaterThan { source_span, .. }
1483            | Expr::GreaterThanOrEqualTo { source_span, .. }
1484            | Expr::LessThanOrEqualTo { source_span, .. }
1485            | Expr::EqualTo { source_span, .. }
1486            | Expr::LessThan { source_span, .. }
1487            | Expr::Plus { source_span, .. }
1488            | Expr::Minus { source_span, .. }
1489            | Expr::Divide { source_span, .. }
1490            | Expr::Multiply { source_span, .. }
1491            | Expr::Cond { source_span, .. }
1492            | Expr::PatternMatch { source_span, .. }
1493            | Expr::Option { source_span, .. }
1494            | Expr::Result { source_span, .. }
1495            | Expr::Unwrap { source_span, .. }
1496            | Expr::Throw { source_span, .. }
1497            | Expr::And { source_span, .. }
1498            | Expr::Or { source_span, .. }
1499            | Expr::GetTag { source_span, .. }
1500            | Expr::Range { source_span, .. }
1501            | Expr::ListComprehension { source_span, .. }
1502            | Expr::ListReduce { source_span, .. }
1503            | Expr::InvokeMethodLazy { source_span, .. }
1504            | Expr::Length { source_span, .. }
1505            | Expr::Call { source_span, .. } => {
1506                *source_span = new_source_span;
1507            }
1508        }
1509    }
1510
1511    pub fn with_inferred_type(&self, new_inferred_type: InferredType) -> Expr {
1512        let mut expr_copied = self.clone();
1513        expr_copied.with_inferred_type_mut(new_inferred_type);
1514        expr_copied
1515    }
1516
1517    // `with_inferred_type` overrides the existing inferred_type and returns a new expr
1518    // This is different to `merge_inferred_type` where it tries to combine the new inferred type with the existing one.
1519    pub fn with_inferred_type_mut(&mut self, new_inferred_type: InferredType) {
1520        match self {
1521            Expr::Identifier { inferred_type, .. }
1522            | Expr::Let { inferred_type, .. }
1523            | Expr::SelectField { inferred_type, .. }
1524            | Expr::SelectIndex { inferred_type, .. }
1525            | Expr::Sequence { inferred_type, .. }
1526            | Expr::Record { inferred_type, .. }
1527            | Expr::Tuple { inferred_type, .. }
1528            | Expr::Literal { inferred_type, .. }
1529            | Expr::Number { inferred_type, .. }
1530            | Expr::Flags { inferred_type, .. }
1531            | Expr::Boolean { inferred_type, .. }
1532            | Expr::Concat { inferred_type, .. }
1533            | Expr::ExprBlock { inferred_type, .. }
1534            | Expr::Not { inferred_type, .. }
1535            | Expr::GreaterThan { inferred_type, .. }
1536            | Expr::GreaterThanOrEqualTo { inferred_type, .. }
1537            | Expr::LessThanOrEqualTo { inferred_type, .. }
1538            | Expr::EqualTo { inferred_type, .. }
1539            | Expr::LessThan { inferred_type, .. }
1540            | Expr::Plus { inferred_type, .. }
1541            | Expr::Minus { inferred_type, .. }
1542            | Expr::Divide { inferred_type, .. }
1543            | Expr::Multiply { inferred_type, .. }
1544            | Expr::Cond { inferred_type, .. }
1545            | Expr::PatternMatch { inferred_type, .. }
1546            | Expr::Option { inferred_type, .. }
1547            | Expr::Result { inferred_type, .. }
1548            | Expr::Unwrap { inferred_type, .. }
1549            | Expr::Throw { inferred_type, .. }
1550            | Expr::And { inferred_type, .. }
1551            | Expr::Or { inferred_type, .. }
1552            | Expr::GetTag { inferred_type, .. }
1553            | Expr::ListComprehension { inferred_type, .. }
1554            | Expr::ListReduce { inferred_type, .. }
1555            | Expr::InvokeMethodLazy { inferred_type, .. }
1556            | Expr::Range { inferred_type, .. }
1557            | Expr::Length { inferred_type, .. }
1558            | Expr::Call { inferred_type, .. } => {
1559                if new_inferred_type != InferredType::Unknown {
1560                    *inferred_type = new_inferred_type;
1561                }
1562            }
1563        }
1564    }
1565
1566    pub fn infer_enums(&mut self, function_type_registry: &FunctionTypeRegistry) {
1567        type_inference::infer_enums(self, function_type_registry);
1568    }
1569
1570    pub fn infer_variants(&mut self, function_type_registry: &FunctionTypeRegistry) {
1571        type_inference::infer_variants(self, function_type_registry);
1572    }
1573
1574    pub fn visit_children_bottom_up<'a>(&'a self, queue: &mut VecDeque<&'a Expr>) {
1575        type_inference::visit_children_bottom_up(self, queue);
1576    }
1577
1578    pub fn visit_children_mut_top_down<'a>(&'a mut self, queue: &mut VecDeque<&'a mut Expr>) {
1579        type_inference::visit_children_mut_top_down(self, queue);
1580    }
1581
1582    pub fn visit_children_mut_bottom_up<'a>(&'a mut self, queue: &mut VecDeque<&'a mut Expr>) {
1583        type_inference::visit_children_bottom_up_mut(self, queue);
1584    }
1585
1586    pub fn number_inferred(
1587        big_decimal: BigDecimal,
1588        type_annotation: Option<TypeName>,
1589        inferred_type: InferredType,
1590    ) -> Expr {
1591        Expr::Number {
1592            number: Number { value: big_decimal },
1593            type_annotation,
1594            inferred_type,
1595            source_span: SourceSpan::default(),
1596        }
1597    }
1598
1599    pub fn number(big_decimal: BigDecimal) -> Expr {
1600        Expr::number_inferred(big_decimal, None, InferredType::number())
1601    }
1602}
1603
1604#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord)]
1605pub enum Range {
1606    Range { from: Box<Expr>, to: Box<Expr> },
1607    RangeInclusive { from: Box<Expr>, to: Box<Expr> },
1608    RangeFrom { from: Box<Expr> },
1609}
1610
1611impl Range {
1612    pub fn from(&self) -> Option<&Expr> {
1613        match self {
1614            Range::Range { from, .. } => Some(from),
1615            Range::RangeInclusive { from, .. } => Some(from),
1616            Range::RangeFrom { from } => Some(from),
1617        }
1618    }
1619
1620    pub fn to(&self) -> Option<&Expr> {
1621        match self {
1622            Range::Range { to, .. } => Some(to),
1623            Range::RangeInclusive { to, .. } => Some(to),
1624            Range::RangeFrom { .. } => None,
1625        }
1626    }
1627
1628    pub fn inclusive(&self) -> bool {
1629        matches!(self, Range::RangeInclusive { .. })
1630    }
1631
1632    pub fn get_exprs_mut(&mut self) -> Vec<&mut Box<Expr>> {
1633        match self {
1634            Range::Range { from, to } => vec![from, to],
1635            Range::RangeInclusive { from, to } => vec![from, to],
1636            Range::RangeFrom { from } => vec![from],
1637        }
1638    }
1639
1640    pub fn get_exprs(&self) -> Vec<&Expr> {
1641        match self {
1642            Range::Range { from, to } => vec![from.as_ref(), to.as_ref()],
1643            Range::RangeInclusive { from, to } => vec![from.as_ref(), to.as_ref()],
1644            Range::RangeFrom { from } => vec![from.as_ref()],
1645        }
1646    }
1647}
1648
1649#[derive(Debug, Hash, Clone, PartialEq, Ord, PartialOrd)]
1650pub struct Number {
1651    pub value: BigDecimal,
1652}
1653
1654impl Eq for Number {}
1655
1656impl Number {
1657    pub fn to_val(&self, analysed_type: &AnalysedType) -> Option<ValueAndType> {
1658        match analysed_type {
1659            AnalysedType::F64(_) => self.value.to_f64().map(|v| v.into_value_and_type()),
1660            AnalysedType::U64(_) => self.value.to_u64().map(|v| v.into_value_and_type()),
1661            AnalysedType::F32(_) => self.value.to_f32().map(|v| v.into_value_and_type()),
1662            AnalysedType::U32(_) => self.value.to_u32().map(|v| v.into_value_and_type()),
1663            AnalysedType::S32(_) => self.value.to_i32().map(|v| v.into_value_and_type()),
1664            AnalysedType::S64(_) => self.value.to_i64().map(|v| v.into_value_and_type()),
1665            AnalysedType::U8(_) => self.value.to_u8().map(|v| v.into_value_and_type()),
1666            AnalysedType::S8(_) => self.value.to_i8().map(|v| v.into_value_and_type()),
1667            AnalysedType::U16(_) => self.value.to_u16().map(|v| v.into_value_and_type()),
1668            AnalysedType::S16(_) => self.value.to_i16().map(|v| v.into_value_and_type()),
1669            _ => None,
1670        }
1671    }
1672}
1673
1674impl Display for Number {
1675    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1676        write!(f, "{}", self.value)
1677    }
1678}
1679
1680#[derive(Debug, Hash, Clone, PartialEq, Eq, Ord, PartialOrd)]
1681pub struct MatchArm {
1682    pub arm_pattern: ArmPattern,
1683    pub arm_resolution_expr: Box<Expr>,
1684}
1685
1686impl MatchArm {
1687    pub fn new(arm_pattern: ArmPattern, arm_resolution: Expr) -> MatchArm {
1688        MatchArm {
1689            arm_pattern,
1690            arm_resolution_expr: Box::new(arm_resolution),
1691        }
1692    }
1693}
1694#[derive(Debug, Hash, Clone, PartialEq, Eq, Ord, PartialOrd)]
1695pub enum ArmPattern {
1696    WildCard,
1697    As(String, Box<ArmPattern>),
1698    Constructor(String, Vec<ArmPattern>),
1699    TupleConstructor(Vec<ArmPattern>),
1700    RecordConstructor(Vec<(String, ArmPattern)>),
1701    ListConstructor(Vec<ArmPattern>),
1702    Literal(Box<Expr>),
1703}
1704
1705impl ArmPattern {
1706    pub fn is_wildcard(&self) -> bool {
1707        matches!(self, ArmPattern::WildCard)
1708    }
1709
1710    pub fn is_literal_identifier(&self) -> bool {
1711        matches!(self, ArmPattern::Literal(expr) if expr.is_identifier())
1712    }
1713
1714    pub fn constructor(name: &str, patterns: Vec<ArmPattern>) -> ArmPattern {
1715        ArmPattern::Constructor(name.to_string(), patterns)
1716    }
1717
1718    pub fn literal(expr: Expr) -> ArmPattern {
1719        ArmPattern::Literal(Box::new(expr))
1720    }
1721
1722    pub fn get_expr_literals_mut(&mut self) -> Vec<&mut Box<Expr>> {
1723        match self {
1724            ArmPattern::Literal(expr) => vec![expr],
1725            ArmPattern::As(_, pattern) => pattern.get_expr_literals_mut(),
1726            ArmPattern::Constructor(_, patterns) => {
1727                let mut result = vec![];
1728                for pattern in patterns {
1729                    result.extend(pattern.get_expr_literals_mut());
1730                }
1731                result
1732            }
1733            ArmPattern::TupleConstructor(patterns) => {
1734                let mut result = vec![];
1735                for pattern in patterns {
1736                    result.extend(pattern.get_expr_literals_mut());
1737                }
1738                result
1739            }
1740            ArmPattern::RecordConstructor(patterns) => {
1741                let mut result = vec![];
1742                for (_, pattern) in patterns {
1743                    result.extend(pattern.get_expr_literals_mut());
1744                }
1745                result
1746            }
1747            ArmPattern::ListConstructor(patterns) => {
1748                let mut result = vec![];
1749                for pattern in patterns {
1750                    result.extend(pattern.get_expr_literals_mut());
1751                }
1752                result
1753            }
1754            ArmPattern::WildCard => vec![],
1755        }
1756    }
1757
1758    pub fn get_expr_literals(&self) -> Vec<&Expr> {
1759        match self {
1760            ArmPattern::Literal(expr) => vec![expr.as_ref()],
1761            ArmPattern::As(_, pattern) => pattern.get_expr_literals(),
1762            ArmPattern::Constructor(_, patterns) => {
1763                let mut result = vec![];
1764                for pattern in patterns {
1765                    result.extend(pattern.get_expr_literals());
1766                }
1767                result
1768            }
1769            ArmPattern::TupleConstructor(patterns) => {
1770                let mut result = vec![];
1771                for pattern in patterns {
1772                    result.extend(pattern.get_expr_literals());
1773                }
1774                result
1775            }
1776            ArmPattern::RecordConstructor(patterns) => {
1777                let mut result = vec![];
1778                for (_, pattern) in patterns {
1779                    result.extend(pattern.get_expr_literals());
1780                }
1781                result
1782            }
1783            ArmPattern::ListConstructor(patterns) => {
1784                let mut result = vec![];
1785                for pattern in patterns {
1786                    result.extend(pattern.get_expr_literals());
1787                }
1788                result
1789            }
1790            ArmPattern::WildCard => vec![],
1791        }
1792    }
1793    // Helper to construct ok(v). Cannot be used if there is nested constructors such as ok(some(v)))
1794    pub fn ok(binding_variable: &str) -> ArmPattern {
1795        ArmPattern::Literal(Box::new(Expr::Result {
1796            expr: Ok(Box::new(Expr::Identifier {
1797                variable_id: VariableId::global(binding_variable.to_string()),
1798                type_annotation: None,
1799                inferred_type: InferredType::Unknown,
1800                source_span: SourceSpan::default(),
1801            })),
1802            type_annotation: None,
1803            inferred_type: InferredType::Result {
1804                ok: Some(Box::new(InferredType::Unknown)),
1805                error: Some(Box::new(InferredType::Unknown)),
1806            },
1807            source_span: SourceSpan::default(),
1808        }))
1809    }
1810
1811    // Helper to construct err(v). Cannot be used if there is nested constructors such as err(some(v)))
1812    pub fn err(binding_variable: &str) -> ArmPattern {
1813        ArmPattern::Literal(Box::new(Expr::Result {
1814            expr: Err(Box::new(Expr::Identifier {
1815                variable_id: VariableId::global(binding_variable.to_string()),
1816                type_annotation: None,
1817                inferred_type: InferredType::Unknown,
1818                source_span: SourceSpan::default(),
1819            })),
1820            type_annotation: None,
1821            inferred_type: InferredType::Result {
1822                ok: Some(Box::new(InferredType::Unknown)),
1823                error: Some(Box::new(InferredType::Unknown)),
1824            },
1825            source_span: SourceSpan::default(),
1826        }))
1827    }
1828
1829    // Helper to construct some(v). Cannot be used if there is nested constructors such as some(ok(v)))
1830    pub fn some(binding_variable: &str) -> ArmPattern {
1831        ArmPattern::Literal(Box::new(Expr::Option {
1832            expr: Some(Box::new(Expr::Identifier {
1833                variable_id: VariableId::local_with_no_id(binding_variable),
1834                type_annotation: None,
1835                inferred_type: InferredType::Unknown,
1836                source_span: SourceSpan::default(),
1837            })),
1838            type_annotation: None,
1839            inferred_type: InferredType::Unknown,
1840            source_span: SourceSpan::default(),
1841        }))
1842    }
1843
1844    pub fn none() -> ArmPattern {
1845        ArmPattern::Literal(Box::new(Expr::Option {
1846            expr: None,
1847            type_annotation: None,
1848            inferred_type: InferredType::Unknown,
1849            source_span: SourceSpan::default(),
1850        }))
1851    }
1852
1853    pub fn identifier(binding_variable: &str) -> ArmPattern {
1854        ArmPattern::Literal(Box::new(Expr::Identifier {
1855            variable_id: VariableId::global(binding_variable.to_string()),
1856            type_annotation: None,
1857            inferred_type: InferredType::Unknown,
1858            source_span: SourceSpan::default(),
1859        }))
1860    }
1861    pub fn custom_constructor(name: &str, args: Vec<ArmPattern>) -> ArmPattern {
1862        ArmPattern::Constructor(name.to_string(), args)
1863    }
1864}
1865
1866#[cfg(feature = "protobuf")]
1867impl TryFrom<golem_api_grpc::proto::golem::rib::Expr> for Expr {
1868    type Error = String;
1869
1870    fn try_from(value: golem_api_grpc::proto::golem::rib::Expr) -> Result<Self, Self::Error> {
1871        let expr = value.expr.ok_or("Missing expr")?;
1872
1873        let expr = match expr {
1874            golem_api_grpc::proto::golem::rib::expr::Expr::Let(expr) => {
1875                let name = expr.name;
1876                let type_annotation = expr.type_name.map(TypeName::try_from).transpose()?;
1877                let expr_: golem_api_grpc::proto::golem::rib::Expr =
1878                    *expr.expr.ok_or("Missing expr")?;
1879                let expr: Expr = expr_.try_into()?;
1880                Expr::let_binding(name, expr, type_annotation)
1881            }
1882
1883            golem_api_grpc::proto::golem::rib::expr::Expr::SelectIndexV1(expr) => {
1884                let selection = *expr.expr.ok_or("Missing expr")?;
1885                let field = *expr.index.ok_or("Missing index")?;
1886                let type_annotation = expr.type_name.map(TypeName::try_from).transpose()?;
1887
1888                Expr::select_index(selection.try_into()?, field.try_into()?)
1889                    .with_type_annotation_opt(type_annotation)
1890            }
1891
1892            golem_api_grpc::proto::golem::rib::expr::Expr::Length(expr) => {
1893                let expr = expr.expr.ok_or("Missing expr")?;
1894                Expr::Length {
1895                    expr: Box::new((*expr).try_into()?),
1896                    type_annotation: None,
1897                    inferred_type: InferredType::Unknown,
1898                    source_span: SourceSpan::default(),
1899                }
1900            }
1901
1902            golem_api_grpc::proto::golem::rib::expr::Expr::Range(range) => {
1903                let range_expr = range.range_expr.ok_or("Missing range expr")?;
1904
1905                match range_expr {
1906                    RangeExpr::RangeFrom(range_from) => {
1907                        let from = range_from.from.ok_or("Missing from expr")?;
1908                        Expr::range_from((*from).try_into()?)
1909                    }
1910                    RangeExpr::Range(range) => {
1911                        let from = range.from.ok_or("Missing from expr")?;
1912                        let to = range.to.ok_or("Missing to expr")?;
1913                        Expr::range((*from).try_into()?, (*to).try_into()?)
1914                    }
1915                    RangeExpr::RangeInclusive(range_inclusive) => {
1916                        let from = range_inclusive.from.ok_or("Missing from expr")?;
1917                        let to = range_inclusive.to.ok_or("Missing to expr")?;
1918                        Expr::range_inclusive((*from).try_into()?, (*to).try_into()?)
1919                    }
1920                }
1921            }
1922
1923            golem_api_grpc::proto::golem::rib::expr::Expr::Not(expr) => {
1924                let expr = expr.expr.ok_or("Missing expr")?;
1925                Expr::not((*expr).try_into()?)
1926            }
1927
1928            golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThan(expr) => {
1929                let left = expr.left.ok_or("Missing left expr")?;
1930                let right = expr.right.ok_or("Missing right expr")?;
1931                Expr::greater_than((*left).try_into()?, (*right).try_into()?)
1932            }
1933
1934            golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThanOrEqual(expr) => {
1935                let left = expr.left.ok_or("Missing left expr")?;
1936                let right = expr.right.ok_or("Missing right expr")?;
1937                Expr::greater_than_or_equal_to((*left).try_into()?, (*right).try_into()?)
1938            }
1939
1940            golem_api_grpc::proto::golem::rib::expr::Expr::LessThan(expr) => {
1941                let left = expr.left.ok_or("Missing left expr")?;
1942                let right = expr.right.ok_or("Missing right expr")?;
1943                Expr::less_than((*left).try_into()?, (*right).try_into()?)
1944            }
1945
1946            golem_api_grpc::proto::golem::rib::expr::Expr::LessThanOrEqual(expr) => {
1947                let left = expr.left.ok_or("Missing left expr")?;
1948                let right = expr.right.ok_or("Missing right expr")?;
1949                Expr::less_than_or_equal_to((*left).try_into()?, (*right).try_into()?)
1950            }
1951
1952            golem_api_grpc::proto::golem::rib::expr::Expr::EqualTo(expr) => {
1953                let left = expr.left.ok_or("Missing left expr")?;
1954                let right = expr.right.ok_or("Missing right expr")?;
1955                Expr::equal_to((*left).try_into()?, (*right).try_into()?)
1956            }
1957
1958            golem_api_grpc::proto::golem::rib::expr::Expr::Add(expr) => {
1959                let left = expr.left.ok_or("Missing left expr")?;
1960                let right = expr.right.ok_or("Missing right expr")?;
1961                Expr::plus((*left).try_into()?, (*right).try_into()?)
1962            }
1963
1964            golem_api_grpc::proto::golem::rib::expr::Expr::Subtract(expr) => {
1965                let left = expr.left.ok_or("Missing left expr")?;
1966                let right = expr.right.ok_or("Missing right expr")?;
1967                Expr::plus((*left).try_into()?, (*right).try_into()?)
1968            }
1969
1970            golem_api_grpc::proto::golem::rib::expr::Expr::Divide(expr) => {
1971                let left = expr.left.ok_or("Missing left expr")?;
1972                let right = expr.right.ok_or("Missing right expr")?;
1973                Expr::plus((*left).try_into()?, (*right).try_into()?)
1974            }
1975
1976            golem_api_grpc::proto::golem::rib::expr::Expr::Multiply(expr) => {
1977                let left = expr.left.ok_or("Missing left expr")?;
1978                let right = expr.right.ok_or("Missing right expr")?;
1979                Expr::plus((*left).try_into()?, (*right).try_into()?)
1980            }
1981
1982            golem_api_grpc::proto::golem::rib::expr::Expr::Cond(expr) => {
1983                let left = expr.left.ok_or("Missing left expr")?;
1984                let cond = expr.cond.ok_or("Missing cond expr")?;
1985                let right = expr.right.ok_or("Missing right expr")?;
1986                Expr::cond(
1987                    (*left).try_into()?,
1988                    (*cond).try_into()?,
1989                    (*right).try_into()?,
1990                )
1991            }
1992
1993            golem_api_grpc::proto::golem::rib::expr::Expr::Concat(
1994                golem_api_grpc::proto::golem::rib::ConcatExpr { exprs },
1995            ) => {
1996                let exprs: Vec<Expr> = exprs
1997                    .into_iter()
1998                    .map(|expr| expr.try_into())
1999                    .collect::<Result<Vec<_>, _>>()?;
2000                Expr::concat(exprs)
2001            }
2002
2003            golem_api_grpc::proto::golem::rib::expr::Expr::Multiple(
2004                golem_api_grpc::proto::golem::rib::MultipleExpr { exprs },
2005            ) => {
2006                let exprs: Vec<Expr> = exprs
2007                    .into_iter()
2008                    .map(|expr| expr.try_into())
2009                    .collect::<Result<Vec<_>, _>>()?;
2010                Expr::expr_block(exprs)
2011            }
2012
2013            golem_api_grpc::proto::golem::rib::expr::Expr::Sequence(
2014                golem_api_grpc::proto::golem::rib::SequenceExpr { exprs, type_name },
2015            ) => {
2016                let type_annotation = type_name.map(TypeName::try_from).transpose()?;
2017
2018                let exprs: Vec<Expr> = exprs
2019                    .into_iter()
2020                    .map(|expr| expr.try_into())
2021                    .collect::<Result<Vec<_>, _>>()?;
2022                Expr::sequence(exprs, type_annotation)
2023            }
2024
2025            golem_api_grpc::proto::golem::rib::expr::Expr::Tuple(
2026                golem_api_grpc::proto::golem::rib::TupleExpr { exprs },
2027            ) => {
2028                let exprs: Vec<Expr> = exprs
2029                    .into_iter()
2030                    .map(|expr| expr.try_into())
2031                    .collect::<Result<Vec<_>, _>>()?;
2032                Expr::tuple(exprs)
2033            }
2034
2035            golem_api_grpc::proto::golem::rib::expr::Expr::Record(
2036                golem_api_grpc::proto::golem::rib::RecordExpr { fields },
2037            ) => {
2038                let mut values: Vec<(String, Expr)> = vec![];
2039                for record in fields.into_iter() {
2040                    let name = record.name;
2041                    let expr = record.expr.ok_or("Missing expr")?;
2042                    values.push((name, expr.try_into()?));
2043                }
2044                Expr::record(values)
2045            }
2046
2047            golem_api_grpc::proto::golem::rib::expr::Expr::Flags(
2048                golem_api_grpc::proto::golem::rib::FlagsExpr { values },
2049            ) => Expr::flags(values),
2050
2051            golem_api_grpc::proto::golem::rib::expr::Expr::Literal(
2052                golem_api_grpc::proto::golem::rib::LiteralExpr { value },
2053            ) => Expr::literal(value),
2054
2055            golem_api_grpc::proto::golem::rib::expr::Expr::Identifier(
2056                golem_api_grpc::proto::golem::rib::IdentifierExpr { name, type_name },
2057            ) => {
2058                let type_name = type_name.map(TypeName::try_from).transpose()?;
2059
2060                Expr::identifier_global(name.as_str(), type_name)
2061            }
2062
2063            golem_api_grpc::proto::golem::rib::expr::Expr::Boolean(
2064                golem_api_grpc::proto::golem::rib::BooleanExpr { value },
2065            ) => Expr::boolean(value),
2066
2067            golem_api_grpc::proto::golem::rib::expr::Expr::Throw(
2068                golem_api_grpc::proto::golem::rib::ThrowExpr { message },
2069            ) => Expr::throw(message),
2070
2071            golem_api_grpc::proto::golem::rib::expr::Expr::And(expr) => {
2072                let left = expr.left.ok_or("Missing left expr")?;
2073                let right = expr.right.ok_or("Missing right expr")?;
2074                Expr::and((*left).try_into()?, (*right).try_into()?)
2075            }
2076
2077            golem_api_grpc::proto::golem::rib::expr::Expr::Or(expr) => {
2078                let left = expr.left.ok_or("Missing left expr")?;
2079                let right = expr.right.ok_or("Missing right expr")?;
2080                Expr::or((*left).try_into()?, (*right).try_into()?)
2081            }
2082
2083            golem_api_grpc::proto::golem::rib::expr::Expr::Tag(expr) => {
2084                let expr = expr.expr.ok_or("Missing expr in tag")?;
2085                Expr::get_tag((*expr).try_into()?)
2086            }
2087
2088            golem_api_grpc::proto::golem::rib::expr::Expr::Unwrap(expr) => {
2089                let expr = expr.expr.ok_or("Missing expr")?;
2090                let expr: Expr = (*expr).try_into()?;
2091                expr.unwrap()
2092            }
2093
2094            golem_api_grpc::proto::golem::rib::expr::Expr::Number(number) => {
2095                // Backward compatibility
2096                let type_name = number.type_name.map(TypeName::try_from).transpose()?;
2097                let big_decimal = if let Some(number) = number.number {
2098                    BigDecimal::from_str(&number).map_err(|e| e.to_string())?
2099                } else if let Some(float) = number.float {
2100                    BigDecimal::from_f64(float).ok_or("Invalid float")?
2101                } else {
2102                    return Err("Missing number".to_string());
2103                };
2104
2105                Expr::number(big_decimal).with_type_annotation_opt(type_name)
2106            }
2107            golem_api_grpc::proto::golem::rib::expr::Expr::SelectField(expr) => {
2108                let expr = *expr;
2109                let field = expr.field;
2110                let type_name = expr.type_name.map(TypeName::try_from).transpose()?;
2111                let expr = *expr.expr.ok_or(
2112                    "Mi\
2113                ssing expr",
2114                )?;
2115
2116                Expr::select_field(expr.try_into()?, field.as_str(), type_name)
2117            }
2118            golem_api_grpc::proto::golem::rib::expr::Expr::SelectIndex(expr) => {
2119                let expr = *expr;
2120                let type_name = expr.type_name.map(TypeName::try_from).transpose()?;
2121                let index = expr.index as usize;
2122                let expr = *expr.expr.ok_or("Missing expr")?;
2123
2124                let index_expr =
2125                    Expr::number(BigDecimal::from_usize(index).ok_or("Invalid index")?);
2126
2127                Expr::select_index(expr.try_into()?, index_expr).with_type_annotation_opt(type_name)
2128            }
2129            golem_api_grpc::proto::golem::rib::expr::Expr::Option(expr) => {
2130                let type_name = expr.type_name;
2131                let type_name = type_name.map(TypeName::try_from).transpose()?;
2132
2133                match expr.expr {
2134                    Some(expr) => {
2135                        Expr::option(Some((*expr).try_into()?)).with_type_annotation_opt(type_name)
2136                    }
2137                    None => Expr::option(None).with_type_annotation_opt(type_name),
2138                }
2139            }
2140            golem_api_grpc::proto::golem::rib::expr::Expr::Result(expr) => {
2141                let type_name = expr.type_name;
2142                let type_name = type_name.map(TypeName::try_from).transpose()?;
2143                let result = expr.result.ok_or("Missing result")?;
2144                match result {
2145                    golem_api_grpc::proto::golem::rib::result_expr::Result::Ok(expr) => {
2146                        Expr::ok((*expr).try_into()?, type_name)
2147                    }
2148                    golem_api_grpc::proto::golem::rib::result_expr::Result::Err(expr) => {
2149                        Expr::err((*expr).try_into()?, type_name)
2150                    }
2151                }
2152            }
2153            golem_api_grpc::proto::golem::rib::expr::Expr::PatternMatch(expr) => {
2154                let patterns: Vec<MatchArm> = expr
2155                    .patterns
2156                    .into_iter()
2157                    .map(|expr| expr.try_into())
2158                    .collect::<Result<Vec<_>, _>>()?;
2159                let expr = expr.expr.ok_or("Missing expr")?;
2160                Expr::pattern_match((*expr).try_into()?, patterns)
2161            }
2162            golem_api_grpc::proto::golem::rib::expr::Expr::ListComprehension(
2163                list_comprehension,
2164            ) => {
2165                let iterable_expr = list_comprehension.iterable_expr.ok_or("Missing expr")?;
2166                let iterable_expr = (*iterable_expr).try_into()?;
2167                let yield_expr = list_comprehension.yield_expr.ok_or("Missing list")?;
2168                let yield_expr = (*yield_expr).try_into()?;
2169                let variable_id =
2170                    VariableId::list_comprehension_identifier(list_comprehension.iterated_variable);
2171                Expr::list_comprehension(variable_id, iterable_expr, yield_expr)
2172            }
2173            golem_api_grpc::proto::golem::rib::expr::Expr::ListReduce(list_reduce) => {
2174                let init_value_expr = list_reduce.init_value_expr.ok_or("Missing initial expr")?;
2175                let init_value_expr = (*init_value_expr).try_into()?;
2176                let iterable_expr = list_reduce.iterable_expr.ok_or("Missing expr")?;
2177                let iterable_expr = (*iterable_expr).try_into()?;
2178                let yield_expr = list_reduce.yield_expr.ok_or("Missing list")?;
2179                let yield_expr = (*yield_expr).try_into()?;
2180                let iterated_variable_id =
2181                    VariableId::list_comprehension_identifier(list_reduce.iterated_variable);
2182                let reduce_variable_id =
2183                    VariableId::list_reduce_identifier(list_reduce.reduce_variable);
2184                Expr::list_reduce(
2185                    reduce_variable_id,
2186                    iterated_variable_id,
2187                    iterable_expr,
2188                    init_value_expr,
2189                    yield_expr,
2190                )
2191            }
2192            golem_api_grpc::proto::golem::rib::expr::Expr::Call(expr) => {
2193                let params: Vec<Expr> = expr
2194                    .params
2195                    .into_iter()
2196                    .map(|expr| expr.try_into())
2197                    .collect::<Result<Vec<_>, _>>()?;
2198                // This is not required and kept for backward compatibility
2199                let legacy_invocation_name = expr.name;
2200                let call_type = expr.call_type;
2201                let generic_type_parameter = expr
2202                    .generic_type_parameter
2203                    .map(|tp| GenericTypeParameter { value: tp });
2204
2205                match (legacy_invocation_name, call_type) {
2206                    (Some(legacy), None) => {
2207                        let name = legacy.name.ok_or("Missing function call name")?;
2208                        match name {
2209                            golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => {
2210                                // Reading the previous parsed-function-name in persistent store as a dynamic-parsed-function-name
2211                                Expr::call_worker_function(DynamicParsedFunctionName::parse(
2212                                    ParsedFunctionName::try_from(name)?.to_string()
2213                                )?, generic_type_parameter, None, params)
2214                            }
2215                            golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor(
2216                                name,
2217                            ) => Expr::call_worker_function(DynamicParsedFunctionName::parse(name)?, generic_type_parameter, None, params),
2218                            golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(
2219                                name,
2220                            ) => Expr::call_worker_function(DynamicParsedFunctionName::parse(name)?, generic_type_parameter, None, params),
2221                        }
2222                    }
2223                    (_, Some(call_type)) => {
2224                        let name = call_type.name.ok_or("Missing function call name")?;
2225                        match name {
2226                            golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => {
2227                                Expr::call_worker_function(name.try_into()?, generic_type_parameter, None, params)
2228                            }
2229                            golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(
2230                                name,
2231                            ) => Expr::call_worker_function(DynamicParsedFunctionName::parse(name)?, generic_type_parameter, None, params),
2232                            golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(
2233                                name,
2234                            ) => Expr::call_worker_function(DynamicParsedFunctionName::parse(name)?, generic_type_parameter, None, params),
2235                            golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(instance_creation) => {
2236                                let instance_creation_type = InstanceCreationType::try_from(*instance_creation)?;
2237                                let call_type = CallType::InstanceCreation(instance_creation_type);
2238                                Expr::Call {
2239                                    call_type,
2240                                    generic_type_parameter,
2241                                    args: vec![],
2242                                    inferred_type: InferredType::Unknown,
2243                                    source_span: SourceSpan::default(),
2244                                    type_annotation: None, // TODO
2245                                }
2246                            }
2247                        }
2248                    }
2249                    (_, _) => Err("Missing both call type (and legacy invocation type)")?,
2250                }
2251            }
2252            golem_api_grpc::proto::golem::rib::expr::Expr::LazyInvokeMethod(lazy_invoke) => {
2253                let lhs_proto = lazy_invoke.lhs.ok_or("Missing lhs")?;
2254                let lhs = Box::new((*lhs_proto).try_into()?);
2255                let method = lazy_invoke.method;
2256                let generic_type_parameter = lazy_invoke.generic_type_parameter;
2257                let args: Vec<Expr> = lazy_invoke
2258                    .args
2259                    .into_iter()
2260                    .map(Expr::try_from)
2261                    .collect::<Result<Vec<_>, _>>()?;
2262
2263                Expr::InvokeMethodLazy {
2264                    lhs,
2265                    method,
2266                    generic_type_parameter: generic_type_parameter
2267                        .map(|value| GenericTypeParameter { value }),
2268                    args,
2269                    inferred_type: InferredType::Unknown,
2270                    source_span: SourceSpan::default(),
2271                    type_annotation: None, //TODO
2272                }
2273            }
2274        };
2275        Ok(expr)
2276    }
2277}
2278
2279impl Display for Expr {
2280    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2281        write!(f, "{}", text::to_string(self).unwrap())
2282    }
2283}
2284
2285impl Display for ArmPattern {
2286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2287        write!(f, "{}", text::to_string_arm_pattern(self).unwrap())
2288    }
2289}
2290
2291impl<'de> Deserialize<'de> for Expr {
2292    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2293    where
2294        D: serde::Deserializer<'de>,
2295    {
2296        let value = serde_json::Value::deserialize(deserializer)?;
2297        match value {
2298            Value::String(expr_string) => match from_string(expr_string.as_str()) {
2299                Ok(expr) => Ok(expr),
2300                Err(message) => Err(serde::de::Error::custom(message.to_string())),
2301            },
2302
2303            e => Err(serde::de::Error::custom(format!(
2304                "Failed to deserialize expression {}",
2305                e
2306            ))),
2307        }
2308    }
2309}
2310
2311impl Serialize for Expr {
2312    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2313    where
2314        S: Serializer,
2315    {
2316        match text::to_string(self) {
2317            Ok(value) => serde_json::Value::serialize(&Value::String(value), serializer),
2318            Err(error) => Err(serde::ser::Error::custom(error.to_string())),
2319        }
2320    }
2321}
2322
2323#[cfg(feature = "protobuf")]
2324mod protobuf {
2325    use crate::{ArmPattern, Expr, MatchArm, Range};
2326    use golem_api_grpc::proto::golem::rib::range_expr::RangeExpr;
2327
2328    impl From<Expr> for golem_api_grpc::proto::golem::rib::Expr {
2329        fn from(value: Expr) -> Self {
2330            let expr = match value {
2331                Expr::Let {
2332                    variable_id,
2333                    type_annotation,
2334                    expr,
2335                    ..
2336                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Let(
2337                    Box::new(golem_api_grpc::proto::golem::rib::LetExpr {
2338                        name: variable_id.name().to_string(),
2339                        expr: Some(Box::new((*expr).into())),
2340                        type_name: type_annotation.map(|t| t.into()),
2341                    }),
2342                )),
2343
2344                Expr::Length { expr, .. } => {
2345                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Length(
2346                        Box::new(golem_api_grpc::proto::golem::rib::LengthExpr {
2347                            expr: Some(Box::new((*expr).into())),
2348                        }),
2349                    ))
2350                }
2351
2352                Expr::SelectField {
2353                    expr,
2354                    field,
2355                    type_annotation,
2356                    ..
2357                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::SelectField(
2358                    Box::new(golem_api_grpc::proto::golem::rib::SelectFieldExpr {
2359                        expr: Some(Box::new((*expr).into())),
2360                        field,
2361                        type_name: type_annotation.map(|t| t.into()),
2362                    }),
2363                )),
2364
2365                Expr::Range { range, .. } => match range {
2366                    Range::RangeFrom { from } => {
2367                        Some(golem_api_grpc::proto::golem::rib::expr::Expr::Range(
2368                            Box::new(golem_api_grpc::proto::golem::rib::RangeExpr {
2369                                range_expr: Some(RangeExpr::RangeFrom(Box::new(
2370                                    golem_api_grpc::proto::golem::rib::RangeFrom {
2371                                        from: Some(Box::new((*from).into())),
2372                                    },
2373                                ))),
2374                            }),
2375                        ))
2376                    }
2377                    Range::Range { from, to } => {
2378                        Some(golem_api_grpc::proto::golem::rib::expr::Expr::Range(
2379                            Box::new(golem_api_grpc::proto::golem::rib::RangeExpr {
2380                                range_expr: Some(RangeExpr::Range(Box::new(
2381                                    golem_api_grpc::proto::golem::rib::Range {
2382                                        from: Some(Box::new((*from).into())),
2383                                        to: Some(Box::new((*to).into())),
2384                                    },
2385                                ))),
2386                            }),
2387                        ))
2388                    }
2389                    Range::RangeInclusive { from, to } => {
2390                        Some(golem_api_grpc::proto::golem::rib::expr::Expr::Range(
2391                            Box::new(golem_api_grpc::proto::golem::rib::RangeExpr {
2392                                range_expr: Some(RangeExpr::RangeInclusive(Box::new(
2393                                    golem_api_grpc::proto::golem::rib::RangeInclusive {
2394                                        from: Some(Box::new((*from).into())),
2395                                        to: Some(Box::new((*to).into())),
2396                                    },
2397                                ))),
2398                            }),
2399                        ))
2400                    }
2401                },
2402
2403                Expr::SelectIndex {
2404                    expr,
2405                    index,
2406                    type_annotation,
2407                    ..
2408                } => Some(
2409                    golem_api_grpc::proto::golem::rib::expr::Expr::SelectIndexV1(Box::new(
2410                        golem_api_grpc::proto::golem::rib::SelectIndexExprV1 {
2411                            expr: Some(Box::new((*expr).into())),
2412                            index: Some(Box::new((*index).into())),
2413                            type_name: type_annotation.map(|t| t.into()),
2414                        },
2415                    )),
2416                ),
2417
2418                Expr::Sequence {
2419                    exprs: expressions,
2420                    type_annotation,
2421                    ..
2422                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Sequence(
2423                    golem_api_grpc::proto::golem::rib::SequenceExpr {
2424                        exprs: expressions.into_iter().map(|expr| expr.into()).collect(),
2425                        type_name: type_annotation.map(|t| t.into()),
2426                    },
2427                )),
2428                Expr::Record { exprs: fields, .. } => {
2429                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Record(
2430                        golem_api_grpc::proto::golem::rib::RecordExpr {
2431                            fields: fields
2432                                .into_iter()
2433                                .map(|(name, expr)| {
2434                                    golem_api_grpc::proto::golem::rib::RecordFieldExpr {
2435                                        name,
2436                                        expr: Some((*expr).into()),
2437                                    }
2438                                })
2439                                .collect(),
2440                        },
2441                    ))
2442                }
2443                Expr::Tuple {
2444                    exprs: expressions, ..
2445                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Tuple(
2446                    golem_api_grpc::proto::golem::rib::TupleExpr {
2447                        exprs: expressions.into_iter().map(|expr| expr.into()).collect(),
2448                    },
2449                )),
2450                Expr::Literal { value, .. } => {
2451                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Literal(
2452                        golem_api_grpc::proto::golem::rib::LiteralExpr { value },
2453                    ))
2454                }
2455                Expr::Number {
2456                    number,
2457                    type_annotation,
2458                    ..
2459                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Number(
2460                    golem_api_grpc::proto::golem::rib::NumberExpr {
2461                        number: Some(number.value.to_string()),
2462                        float: None,
2463                        type_name: type_annotation.map(|t| t.into()),
2464                    },
2465                )),
2466                Expr::Flags { flags, .. } => {
2467                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Flags(
2468                        golem_api_grpc::proto::golem::rib::FlagsExpr { values: flags },
2469                    ))
2470                }
2471                Expr::Identifier {
2472                    variable_id,
2473                    type_annotation,
2474                    ..
2475                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Identifier(
2476                    golem_api_grpc::proto::golem::rib::IdentifierExpr {
2477                        name: variable_id.name(),
2478                        type_name: type_annotation.map(|t| t.into()),
2479                    },
2480                )),
2481                Expr::Boolean { value, .. } => {
2482                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Boolean(
2483                        golem_api_grpc::proto::golem::rib::BooleanExpr { value },
2484                    ))
2485                }
2486                Expr::Concat {
2487                    exprs: expressions, ..
2488                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Concat(
2489                    golem_api_grpc::proto::golem::rib::ConcatExpr {
2490                        exprs: expressions.into_iter().map(|expr| expr.into()).collect(),
2491                    },
2492                )),
2493                Expr::ExprBlock {
2494                    exprs: expressions, ..
2495                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Multiple(
2496                    golem_api_grpc::proto::golem::rib::MultipleExpr {
2497                        exprs: expressions.into_iter().map(|expr| expr.into()).collect(),
2498                    },
2499                )),
2500                Expr::Not { expr, .. } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Not(
2501                    Box::new(golem_api_grpc::proto::golem::rib::NotExpr {
2502                        expr: Some(Box::new((*expr).into())),
2503                    }),
2504                )),
2505                Expr::GreaterThan {
2506                    lhs: left,
2507                    rhs: right,
2508                    ..
2509                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThan(
2510                    Box::new(golem_api_grpc::proto::golem::rib::GreaterThanExpr {
2511                        left: Some(Box::new((*left).into())),
2512                        right: Some(Box::new((*right).into())),
2513                    }),
2514                )),
2515                Expr::GreaterThanOrEqualTo { lhs, rhs, .. } => Some(
2516                    golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThanOrEqual(Box::new(
2517                        golem_api_grpc::proto::golem::rib::GreaterThanOrEqualToExpr {
2518                            left: Some(Box::new((*lhs).into())),
2519                            right: Some(Box::new((*rhs).into())),
2520                        },
2521                    )),
2522                ),
2523                Expr::LessThan {
2524                    lhs: left,
2525                    rhs: right,
2526                    ..
2527                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::LessThan(
2528                    Box::new(golem_api_grpc::proto::golem::rib::LessThanExpr {
2529                        left: Some(Box::new((*left).into())),
2530                        right: Some(Box::new((*right).into())),
2531                    }),
2532                )),
2533                Expr::Plus {
2534                    lhs: left,
2535                    rhs: right,
2536                    ..
2537                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Add(
2538                    Box::new(golem_api_grpc::proto::golem::rib::AddExpr {
2539                        left: Some(Box::new((*left).into())),
2540                        right: Some(Box::new((*right).into())),
2541                    }),
2542                )),
2543                Expr::Minus {
2544                    lhs: left,
2545                    rhs: right,
2546                    ..
2547                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Subtract(
2548                    Box::new(golem_api_grpc::proto::golem::rib::SubtractExpr {
2549                        left: Some(Box::new((*left).into())),
2550                        right: Some(Box::new((*right).into())),
2551                    }),
2552                )),
2553                Expr::Divide { lhs, rhs, .. } => {
2554                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Divide(
2555                        Box::new(golem_api_grpc::proto::golem::rib::DivideExpr {
2556                            left: Some(Box::new((*lhs).into())),
2557                            right: Some(Box::new((*rhs).into())),
2558                        }),
2559                    ))
2560                }
2561                Expr::Multiply { lhs, rhs, .. } => {
2562                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Multiply(
2563                        Box::new(golem_api_grpc::proto::golem::rib::MultiplyExpr {
2564                            left: Some(Box::new((*lhs).into())),
2565                            right: Some(Box::new((*rhs).into())),
2566                        }),
2567                    ))
2568                }
2569                Expr::LessThanOrEqualTo { lhs, rhs, .. } => Some(
2570                    golem_api_grpc::proto::golem::rib::expr::Expr::LessThanOrEqual(Box::new(
2571                        golem_api_grpc::proto::golem::rib::LessThanOrEqualToExpr {
2572                            left: Some(Box::new((*lhs).into())),
2573                            right: Some(Box::new((*rhs).into())),
2574                        },
2575                    )),
2576                ),
2577                Expr::EqualTo { lhs, rhs, .. } => {
2578                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::EqualTo(
2579                        Box::new(golem_api_grpc::proto::golem::rib::EqualToExpr {
2580                            left: Some(Box::new((*lhs).into())),
2581                            right: Some(Box::new((*rhs).into())),
2582                        }),
2583                    ))
2584                }
2585                // Note: We were storing and retrieving (proto) condition expressions such that
2586                // `cond` was written `lhs` and vice versa.
2587                // This is probably difficult to fix to keep backward compatibility
2588                // The issue is only with the protobuf types and the roundtrip tests were/are working since
2589                // the read handles this (i.e, reading cond as lhs)
2590                Expr::Cond {
2591                    cond: lhs,
2592                    lhs: cond,
2593                    rhs,
2594                    ..
2595                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Cond(
2596                    Box::new(golem_api_grpc::proto::golem::rib::CondExpr {
2597                        left: Some(Box::new((*lhs).into())),
2598                        cond: Some(Box::new((*cond).into())),
2599                        right: Some(Box::new((*rhs).into())),
2600                    }),
2601                )),
2602                Expr::PatternMatch {
2603                    predicate,
2604                    match_arms,
2605                    ..
2606                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::PatternMatch(
2607                    Box::new(golem_api_grpc::proto::golem::rib::PatternMatchExpr {
2608                        expr: Some(Box::new((*predicate).into())),
2609                        patterns: match_arms.into_iter().map(|a| a.into()).collect(),
2610                    }),
2611                )),
2612                Expr::Option {
2613                    expr,
2614                    type_annotation,
2615                    ..
2616                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Option(
2617                    Box::new(golem_api_grpc::proto::golem::rib::OptionExpr {
2618                        expr: expr.map(|expr| Box::new((*expr).into())),
2619                        type_name: type_annotation.map(|t| t.into()),
2620                    }),
2621                )),
2622                Expr::Result {
2623                    expr,
2624                    type_annotation,
2625                    ..
2626                } => {
2627                    let type_name = type_annotation.map(|t| t.into());
2628
2629                    let result = match expr {
2630                        Ok(expr) => golem_api_grpc::proto::golem::rib::result_expr::Result::Ok(
2631                            Box::new((*expr).into()),
2632                        ),
2633                        Err(expr) => golem_api_grpc::proto::golem::rib::result_expr::Result::Err(
2634                            Box::new((*expr).into()),
2635                        ),
2636                    };
2637
2638                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Result(
2639                        Box::new(golem_api_grpc::proto::golem::rib::ResultExpr {
2640                            result: Some(result),
2641                            type_name,
2642                        }),
2643                    ))
2644                }
2645                Expr::Call {
2646                    call_type,
2647                    generic_type_parameter,
2648                    args,
2649                    ..
2650                } => {
2651                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Call(
2652                        Box::new(golem_api_grpc::proto::golem::rib::CallExpr {
2653                            name: None, // Kept for backward compatibility
2654                            params: args.into_iter().map(|expr| expr.into()).collect(),
2655                            generic_type_parameter: generic_type_parameter.map(|t| t.value),
2656                            call_type: Some(Box::new(
2657                                golem_api_grpc::proto::golem::rib::CallType::from(call_type),
2658                            )),
2659                        }),
2660                    ))
2661                }
2662                Expr::Unwrap { expr, .. } => {
2663                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Unwrap(
2664                        Box::new(golem_api_grpc::proto::golem::rib::UnwrapExpr {
2665                            expr: Some(Box::new((*expr).into())),
2666                        }),
2667                    ))
2668                }
2669                Expr::Throw { message, .. } => {
2670                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Throw(
2671                        golem_api_grpc::proto::golem::rib::ThrowExpr { message },
2672                    ))
2673                }
2674                Expr::GetTag { expr, .. } => {
2675                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Tag(
2676                        Box::new(golem_api_grpc::proto::golem::rib::GetTagExpr {
2677                            expr: Some(Box::new((*expr).into())),
2678                        }),
2679                    ))
2680                }
2681                Expr::And { lhs, rhs, .. } => {
2682                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::And(
2683                        Box::new(golem_api_grpc::proto::golem::rib::AndExpr {
2684                            left: Some(Box::new((*lhs).into())),
2685                            right: Some(Box::new((*rhs).into())),
2686                        }),
2687                    ))
2688                }
2689
2690                Expr::Or { lhs, rhs, .. } => {
2691                    Some(golem_api_grpc::proto::golem::rib::expr::Expr::Or(Box::new(
2692                        golem_api_grpc::proto::golem::rib::OrExpr {
2693                            left: Some(Box::new((*lhs).into())),
2694                            right: Some(Box::new((*rhs).into())),
2695                        },
2696                    )))
2697                }
2698                Expr::ListComprehension {
2699                    iterated_variable,
2700                    iterable_expr,
2701                    yield_expr,
2702                    ..
2703                } => Some(
2704                    golem_api_grpc::proto::golem::rib::expr::Expr::ListComprehension(Box::new(
2705                        golem_api_grpc::proto::golem::rib::ListComprehensionExpr {
2706                            iterated_variable: iterated_variable.name(),
2707                            iterable_expr: Some(Box::new((*iterable_expr).into())),
2708                            yield_expr: Some(Box::new((*yield_expr).into())),
2709                        },
2710                    )),
2711                ),
2712
2713                Expr::ListReduce {
2714                    reduce_variable,
2715                    iterated_variable,
2716                    iterable_expr,
2717                    yield_expr,
2718                    init_value_expr,
2719                    ..
2720                } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::ListReduce(
2721                    Box::new(golem_api_grpc::proto::golem::rib::ListReduceExpr {
2722                        reduce_variable: reduce_variable.name(),
2723                        iterated_variable: iterated_variable.name(),
2724                        iterable_expr: Some(Box::new((*iterable_expr).into())),
2725                        init_value_expr: Some(Box::new((*init_value_expr).into())),
2726                        yield_expr: Some(Box::new((*yield_expr).into())),
2727                    }),
2728                )),
2729                Expr::InvokeMethodLazy {
2730                    lhs,
2731                    method,
2732                    generic_type_parameter,
2733                    args,
2734                    ..
2735                } => Some(
2736                    golem_api_grpc::proto::golem::rib::expr::Expr::LazyInvokeMethod(Box::new(
2737                        golem_api_grpc::proto::golem::rib::LazyInvokeMethodExpr {
2738                            lhs: Some(Box::new((*lhs).into())),
2739                            method,
2740                            generic_type_parameter: generic_type_parameter.map(|t| t.value),
2741                            args: args.into_iter().map(|expr| expr.into()).collect(),
2742                        },
2743                    )),
2744                ),
2745            };
2746
2747            golem_api_grpc::proto::golem::rib::Expr { expr }
2748        }
2749    }
2750
2751    impl TryFrom<golem_api_grpc::proto::golem::rib::ArmPattern> for ArmPattern {
2752        type Error = String;
2753
2754        fn try_from(
2755            value: golem_api_grpc::proto::golem::rib::ArmPattern,
2756        ) -> Result<Self, Self::Error> {
2757            let pattern = value.pattern.ok_or("Missing pattern")?;
2758            match pattern {
2759                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::WildCard(_) => {
2760                    Ok(ArmPattern::WildCard)
2761                }
2762                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::As(asp) => {
2763                    let name = asp.name;
2764                    let pattern = asp.pattern.ok_or("Missing pattern")?;
2765                    Ok(ArmPattern::As(name, Box::new((*pattern).try_into()?)))
2766                }
2767                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Constructor(
2768                    golem_api_grpc::proto::golem::rib::ConstructorArmPattern { name, patterns },
2769                ) => {
2770                    let patterns = patterns
2771                        .into_iter()
2772                        .map(ArmPattern::try_from)
2773                        .collect::<Result<Vec<_>, _>>()?;
2774                    Ok(ArmPattern::Constructor(name, patterns))
2775                }
2776                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::TupleConstructor(
2777                    golem_api_grpc::proto::golem::rib::TupleConstructorArmPattern { patterns },
2778                ) => {
2779                    let patterns = patterns
2780                        .into_iter()
2781                        .map(ArmPattern::try_from)
2782                        .collect::<Result<Vec<_>, _>>()?;
2783                    Ok(ArmPattern::TupleConstructor(patterns))
2784                }
2785                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Literal(
2786                    golem_api_grpc::proto::golem::rib::LiteralArmPattern { expr },
2787                ) => {
2788                    let inner = expr.ok_or("Missing expr")?;
2789                    Ok(ArmPattern::Literal(Box::new(inner.try_into()?)))
2790                }
2791                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::RecordConstructor(
2792                    golem_api_grpc::proto::golem::rib::RecordConstructorArmPattern { fields },
2793                ) => {
2794                    let fields = fields
2795                        .into_iter()
2796                        .map(|field| {
2797                            let name = field.name;
2798                            let proto_pattern = field.pattern.ok_or("Missing pattern")?;
2799                            let arm_pattern = ArmPattern::try_from(proto_pattern)?;
2800                            Ok((name, arm_pattern))
2801                        })
2802                        .collect::<Result<Vec<_>, String>>()?;
2803                    Ok(ArmPattern::RecordConstructor(fields))
2804                }
2805                golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::ListConstructor(
2806                    golem_api_grpc::proto::golem::rib::ListConstructorArmPattern { patterns },
2807                ) => {
2808                    let patterns = patterns
2809                        .into_iter()
2810                        .map(ArmPattern::try_from)
2811                        .collect::<Result<Vec<_>, _>>()?;
2812                    Ok(ArmPattern::ListConstructor(patterns))
2813                }
2814            }
2815        }
2816    }
2817
2818    impl From<ArmPattern> for golem_api_grpc::proto::golem::rib::ArmPattern {
2819        fn from(value: ArmPattern) -> Self {
2820            match value {
2821                ArmPattern::WildCard => golem_api_grpc::proto::golem::rib::ArmPattern {
2822                    pattern: Some(
2823                        golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::WildCard(
2824                            golem_api_grpc::proto::golem::rib::WildCardArmPattern {},
2825                        ),
2826                    ),
2827                },
2828                ArmPattern::As(name, pattern) => golem_api_grpc::proto::golem::rib::ArmPattern {
2829                    pattern: Some(golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::As(
2830                        Box::new(golem_api_grpc::proto::golem::rib::AsArmPattern {
2831                            name,
2832                            pattern: Some(Box::new((*pattern).into())),
2833                        }),
2834                    )),
2835                },
2836                ArmPattern::Constructor(name, patterns) => {
2837                    golem_api_grpc::proto::golem::rib::ArmPattern {
2838                        pattern: Some(
2839                            golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Constructor(
2840                                golem_api_grpc::proto::golem::rib::ConstructorArmPattern {
2841                                    name,
2842                                    patterns: patterns
2843                                        .into_iter()
2844                                        .map(golem_api_grpc::proto::golem::rib::ArmPattern::from)
2845                                        .collect(),
2846                                },
2847                            ),
2848                        ),
2849                    }
2850                }
2851                ArmPattern::Literal(expr) => golem_api_grpc::proto::golem::rib::ArmPattern {
2852                    pattern: Some(
2853                        golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Literal(
2854                            golem_api_grpc::proto::golem::rib::LiteralArmPattern {
2855                                expr: Some((*expr).into()),
2856                            },
2857                        ),
2858                    ),
2859                },
2860
2861                ArmPattern::TupleConstructor(patterns) => {
2862                    golem_api_grpc::proto::golem::rib::ArmPattern {
2863                        pattern: Some(
2864                            golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::TupleConstructor(
2865                                golem_api_grpc::proto::golem::rib::TupleConstructorArmPattern {
2866                                    patterns: patterns
2867                                        .into_iter()
2868                                        .map(golem_api_grpc::proto::golem::rib::ArmPattern::from)
2869                                        .collect(),
2870                                },
2871                            ),
2872                        ),
2873                    }
2874                }
2875
2876                ArmPattern::RecordConstructor(fields) => {
2877                    golem_api_grpc::proto::golem::rib::ArmPattern {
2878                        pattern: Some(
2879                            golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::RecordConstructor(
2880                                golem_api_grpc::proto::golem::rib::RecordConstructorArmPattern {
2881                                    fields: fields
2882                                        .into_iter()
2883                                        .map(|(name, pattern)| {
2884                                            golem_api_grpc::proto::golem::rib::RecordFieldArmPattern {
2885                                                name,
2886                                                pattern: Some(pattern.into()),
2887                                            }
2888                                        })
2889                                        .collect(),
2890                                },
2891                            ),
2892                        ),
2893                    }
2894                }
2895
2896                ArmPattern::ListConstructor(patterns) => {
2897                    golem_api_grpc::proto::golem::rib::ArmPattern {
2898                        pattern: Some(
2899                            golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::ListConstructor(
2900                                golem_api_grpc::proto::golem::rib::ListConstructorArmPattern {
2901                                    patterns: patterns
2902                                        .into_iter()
2903                                        .map(golem_api_grpc::proto::golem::rib::ArmPattern::from)
2904                                        .collect(),
2905                                },
2906                            ),
2907                        ),
2908                    }
2909                }
2910            }
2911        }
2912    }
2913
2914    impl TryFrom<golem_api_grpc::proto::golem::rib::MatchArm> for MatchArm {
2915        type Error = String;
2916
2917        fn try_from(
2918            value: golem_api_grpc::proto::golem::rib::MatchArm,
2919        ) -> Result<Self, Self::Error> {
2920            let pattern = value.pattern.ok_or("Missing pattern")?;
2921            let expr = value.expr.ok_or("Missing expr")?;
2922            Ok(MatchArm::new(pattern.try_into()?, expr.try_into()?))
2923        }
2924    }
2925
2926    impl From<MatchArm> for golem_api_grpc::proto::golem::rib::MatchArm {
2927        fn from(value: MatchArm) -> Self {
2928            let MatchArm {
2929                arm_pattern,
2930                arm_resolution_expr,
2931            } = value;
2932            golem_api_grpc::proto::golem::rib::MatchArm {
2933                pattern: Some(arm_pattern.into()),
2934                expr: Some((*arm_resolution_expr).into()),
2935            }
2936        }
2937    }
2938}
2939
2940#[cfg(test)]
2941mod tests {
2942    use bigdecimal::BigDecimal;
2943    use test_r::test;
2944
2945    use crate::ParsedFunctionSite::PackagedInterface;
2946    use crate::{
2947        ArmPattern, DynamicParsedFunctionName, DynamicParsedFunctionReference, Expr, MatchArm,
2948    };
2949
2950    #[test]
2951    fn test_single_expr_in_interpolation_wrapped_in_quotes() {
2952        let input = r#""${foo}""#;
2953        let result = Expr::from_text(input);
2954        assert_eq!(
2955            result,
2956            Ok(Expr::concat(vec![Expr::identifier_global("foo", None)]))
2957        );
2958
2959        let input = r#""${{foo}}""#;
2960        let result = Expr::from_text(input);
2961        assert_eq!(
2962            result,
2963            Ok(Expr::concat(vec![Expr::flags(vec!["foo".to_string()])]))
2964        );
2965
2966        let input = r#""${{foo: "bar"}}""#;
2967        let result = Expr::from_text(input);
2968        assert_eq!(
2969            result,
2970            Ok(Expr::concat(vec![Expr::record(vec![(
2971                "foo".to_string(),
2972                Expr::literal("bar")
2973            )])]))
2974        );
2975    }
2976
2977    fn expected() -> Expr {
2978        Expr::expr_block(vec![
2979            Expr::let_binding("x", Expr::number(BigDecimal::from(1)), None),
2980            Expr::let_binding("y", Expr::number(BigDecimal::from(2)), None),
2981            Expr::let_binding(
2982                "result",
2983                Expr::greater_than(
2984                    Expr::identifier_global("x", None),
2985                    Expr::identifier_global("y", None),
2986                ),
2987                None,
2988            ),
2989            Expr::let_binding(
2990                "foo",
2991                Expr::option(Some(Expr::identifier_global("result", None))),
2992                None,
2993            ),
2994            Expr::let_binding(
2995                "bar",
2996                Expr::ok(Expr::identifier_global("result", None), None),
2997                None,
2998            ),
2999            Expr::let_binding(
3000                "baz",
3001                Expr::pattern_match(
3002                    Expr::identifier_global("foo", None),
3003                    vec![
3004                        MatchArm::new(
3005                            ArmPattern::constructor(
3006                                "some",
3007                                vec![ArmPattern::Literal(Box::new(Expr::identifier_global(
3008                                    "x", None,
3009                                )))],
3010                            ),
3011                            Expr::identifier_global("x", None),
3012                        ),
3013                        MatchArm::new(
3014                            ArmPattern::constructor("none", vec![]),
3015                            Expr::boolean(false),
3016                        ),
3017                    ],
3018                ),
3019                None,
3020            ),
3021            Expr::let_binding(
3022                "qux",
3023                Expr::pattern_match(
3024                    Expr::identifier_global("bar", None),
3025                    vec![
3026                        MatchArm::new(
3027                            ArmPattern::constructor(
3028                                "ok",
3029                                vec![ArmPattern::Literal(Box::new(Expr::identifier_global(
3030                                    "x", None,
3031                                )))],
3032                            ),
3033                            Expr::identifier_global("x", None),
3034                        ),
3035                        MatchArm::new(
3036                            ArmPattern::constructor(
3037                                "err",
3038                                vec![ArmPattern::Literal(Box::new(Expr::identifier_global(
3039                                    "msg", None,
3040                                )))],
3041                            ),
3042                            Expr::boolean(false),
3043                        ),
3044                    ],
3045                ),
3046                None,
3047            ),
3048            Expr::let_binding(
3049                "result",
3050                Expr::call_worker_function(
3051                    DynamicParsedFunctionName {
3052                        site: PackagedInterface {
3053                            namespace: "ns".to_string(),
3054                            package: "name".to_string(),
3055                            interface: "interface".to_string(),
3056                            version: None,
3057                        },
3058                        function: DynamicParsedFunctionReference::RawResourceStaticMethod {
3059                            resource: "resource1".to_string(),
3060                            method: "do-something-static".to_string(),
3061                        },
3062                    },
3063                    None,
3064                    None,
3065                    vec![
3066                        Expr::identifier_global("baz", None),
3067                        Expr::identifier_global("qux", None),
3068                    ],
3069                ),
3070                None,
3071            ),
3072            Expr::identifier_global("result", None),
3073        ])
3074    }
3075
3076    #[test]
3077    fn test_rib() {
3078        let sample_rib = r#"
3079         let x = 1;
3080         let y = 2;
3081         let result = x > y;
3082         let foo = some(result);
3083         let bar = ok(result);
3084
3085         let baz = match foo {
3086           some(x) => x,
3087           none => false
3088         };
3089
3090         let qux = match bar {
3091           ok(x) => x,
3092           err(msg) => false
3093         };
3094
3095         let result = ns:name/interface.{[static]resource1.do-something-static}(baz, qux);
3096
3097         result
3098       "#;
3099
3100        let result = Expr::from_text(sample_rib);
3101        assert_eq!(result, Ok(expected()));
3102    }
3103}