Skip to main content

geam_core/plan/module/
step.rs

1use super::expression::{
2    BitArrayExpr, BitArrayFunctionExpr, BoolExpr, BoolFunctionExpr, CustomExpr, CustomFunctionExpr,
3    CustomLocalExpr, Expr, ExternalExpr, ExternalFunctionExpr, FloatExpr, FloatFunctionExpr,
4    FunctionFunctionExpr, GenericExpr, GenericFunctionExpr, IntExpr, IntFunctionExpr,
5    ListFunctionExpr, ListLocalExpr, NilExpr, NilFunctionExpr, StringExpr, StringFunctionExpr,
6    TupleExpr, TupleFunctionExpr, TypedFunctionExpr, UtfCodepointExpr, UtfCodepointFunctionExpr,
7};
8use super::function::{ParamLocal, ParamSlot};
9use super::id::{
10    BitArrayFunctionLocalId, BitArrayLocalId, BoolFunctionLocalId, BoolLocalId,
11    CustomFunctionLocal, CustomFunctionLocalId, CustomLocal, CustomLocalId, ExternalFunctionLocal,
12    ExternalFunctionLocalId, ExternalLocal, FloatFunctionLocalId, FloatLocalId,
13    FunctionFunctionLocal, FunctionFunctionLocalId, GenericFunctionLocal, GenericLocal,
14    IntFunctionLocalId, IntLocalId, ListFunctionLocal, ListLocal, NilFunctionLocalId, NilLocalId,
15    StringFunctionLocalId, StringLocalId, TupleFunctionLocalId, TupleLocalId,
16    UtfCodepointFunctionLocalId, UtfCodepointLocalId,
17};
18use crate::plan::{BitArrayPattern, CustomBindingPattern};
19use crate::plan::{EchoSite, PanicSite, SourceSpan, ValueType};
20use ecow::EcoString;
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct Step {
24    kind: StepKind,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub(crate) struct AssertBinding {
29    slot: ParamSlot,
30    name: EcoString,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub(crate) struct StringAssertBinding {
35    local: StringLocalId,
36    name: EcoString,
37}
38
39#[derive(Debug, Clone, PartialEq)]
40pub(crate) enum AssertPattern {
41    Bind(AssertBinding),
42    Discard,
43    Int(num_bigint::BigInt),
44    Float(f64),
45    String(EcoString),
46    Bool(bool),
47    Nil,
48    Tuple(Vec<AssertPattern>),
49    List(ListAssertPattern),
50    BitArray(BitArrayPattern),
51    Custom(crate::plan::CustomPattern),
52    StringPrefix {
53        prefix: EcoString,
54        left: Option<StringAssertBinding>,
55        right: Option<StringAssertBinding>,
56    },
57    Alias {
58        pattern: Box<AssertPattern>,
59        binding: AssertBinding,
60    },
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub(crate) enum AssertSubject {
65    Int(IntLocalId),
66    Float(FloatLocalId),
67    String(StringLocalId),
68    BitArray(BitArrayLocalId),
69    Custom(CustomLocal),
70    Bool(BoolLocalId),
71    Nil(NilLocalId),
72    Tuple(TupleLocalId),
73    List(ListLocal),
74}
75
76#[derive(Debug, Clone, PartialEq)]
77pub(crate) struct ListAssertPattern {
78    element_type: ValueType,
79    elements: Vec<AssertPattern>,
80    tail: Option<ListAssertTail>,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub(crate) struct ListAssertTailBinding {
85    local: ListLocal,
86    name: EcoString,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq)]
90pub(crate) enum ListAssertTail {
91    Ignore,
92    Bind(ListAssertTailBinding),
93}
94
95#[derive(Debug, Clone, PartialEq)]
96pub(crate) enum StepKind {
97    LetGeneric {
98        local: GenericLocal,
99        name: EcoString,
100        value: GenericExpr,
101    },
102    LetInt {
103        local: IntLocalId,
104        name: EcoString,
105        value: IntExpr,
106    },
107    LetFloat {
108        local: FloatLocalId,
109        name: EcoString,
110        value: FloatExpr,
111    },
112    LetString {
113        local: StringLocalId,
114        name: EcoString,
115        value: StringExpr,
116    },
117    LetBitArray {
118        local: BitArrayLocalId,
119        name: EcoString,
120        value: BitArrayExpr,
121    },
122    LetUtfCodepoint {
123        local: UtfCodepointLocalId,
124        name: EcoString,
125        value: UtfCodepointExpr,
126    },
127    LetCustom {
128        binding: CustomLocalExpr,
129        name: EcoString,
130    },
131    LetExternal {
132        local: ExternalLocal,
133        name: EcoString,
134        value: ExternalExpr,
135    },
136    LetBool {
137        local: BoolLocalId,
138        name: EcoString,
139        value: BoolExpr,
140    },
141    LetNil {
142        local: NilLocalId,
143        name: EcoString,
144        value: NilExpr,
145    },
146    LetTuple {
147        local: TupleLocalId,
148        name: EcoString,
149        value: TupleExpr,
150    },
151    LetList {
152        name: EcoString,
153        value: ListLocalExpr,
154    },
155    LetIntFunction {
156        local: IntFunctionLocalId,
157        name: EcoString,
158        value: TypedFunctionExpr<IntFunctionExpr>,
159    },
160    LetFloatFunction {
161        local: FloatFunctionLocalId,
162        name: EcoString,
163        value: TypedFunctionExpr<FloatFunctionExpr>,
164    },
165    LetStringFunction {
166        local: StringFunctionLocalId,
167        name: EcoString,
168        value: TypedFunctionExpr<StringFunctionExpr>,
169    },
170    LetBitArrayFunction {
171        local: BitArrayFunctionLocalId,
172        name: EcoString,
173        value: TypedFunctionExpr<BitArrayFunctionExpr>,
174    },
175    LetUtfCodepointFunction {
176        local: UtfCodepointFunctionLocalId,
177        name: EcoString,
178        value: TypedFunctionExpr<UtfCodepointFunctionExpr>,
179    },
180    LetCustomFunction {
181        local: CustomFunctionLocal,
182        name: EcoString,
183        value: TypedFunctionExpr<CustomFunctionExpr>,
184    },
185    LetExternalFunction {
186        local: ExternalFunctionLocal,
187        name: EcoString,
188        value: TypedFunctionExpr<ExternalFunctionExpr>,
189    },
190    LetBoolFunction {
191        local: BoolFunctionLocalId,
192        name: EcoString,
193        value: TypedFunctionExpr<BoolFunctionExpr>,
194    },
195    LetNilFunction {
196        local: NilFunctionLocalId,
197        name: EcoString,
198        value: TypedFunctionExpr<NilFunctionExpr>,
199    },
200    LetTupleFunction {
201        local: TupleFunctionLocalId,
202        name: EcoString,
203        value: TypedFunctionExpr<TupleFunctionExpr>,
204    },
205    LetListFunction {
206        local: ListFunctionLocal,
207        name: EcoString,
208        value: TypedFunctionExpr<ListFunctionExpr>,
209    },
210    LetFunctionFunction {
211        local: FunctionFunctionLocal,
212        name: EcoString,
213        value: TypedFunctionExpr<FunctionFunctionExpr>,
214    },
215    LetGenericFunction {
216        local: GenericFunctionLocal,
217        name: EcoString,
218        value: TypedFunctionExpr<GenericFunctionExpr>,
219    },
220    Echo(Echo),
221    AssertPattern {
222        subject: AssertSubject,
223        pattern: AssertPattern,
224        message: Option<StringExpr>,
225        site: PanicSite,
226        pattern_span: SourceSpan,
227    },
228    BindCustomFields {
229        local: CustomLocal,
230        pattern: CustomBindingPattern,
231    },
232    AssertBool {
233        condition: BoolExpr,
234        message: Option<StringExpr>,
235        site: PanicSite,
236    },
237    Evaluate(Expr),
238}
239
240#[derive(Debug, Clone, PartialEq)]
241pub(crate) struct Echo {
242    subject: EchoSubject,
243    message: Option<StringExpr>,
244    site: EchoSite,
245}
246
247#[derive(Debug, Clone, PartialEq)]
248pub(crate) enum EchoSubject {
249    Generic {
250        local: GenericLocal,
251        value: GenericExpr,
252    },
253    Int {
254        local: IntLocalId,
255        value: IntExpr,
256    },
257    Float {
258        local: FloatLocalId,
259        value: FloatExpr,
260    },
261    String {
262        local: StringLocalId,
263        value: StringExpr,
264    },
265    BitArray {
266        local: BitArrayLocalId,
267        value: BitArrayExpr,
268    },
269    UtfCodepoint {
270        local: UtfCodepointLocalId,
271        value: UtfCodepointExpr,
272    },
273    Custom(CustomLocalExpr),
274    External {
275        local: ExternalLocal,
276        value: ExternalExpr,
277    },
278    Bool {
279        local: BoolLocalId,
280        value: BoolExpr,
281    },
282    Nil {
283        local: NilLocalId,
284        value: NilExpr,
285    },
286    Tuple {
287        local: TupleLocalId,
288        value: TupleExpr,
289    },
290    List(ListLocalExpr),
291    IntFunction {
292        local: IntFunctionLocalId,
293        value: TypedFunctionExpr<IntFunctionExpr>,
294    },
295    FloatFunction {
296        local: FloatFunctionLocalId,
297        value: TypedFunctionExpr<FloatFunctionExpr>,
298    },
299    StringFunction {
300        local: StringFunctionLocalId,
301        value: TypedFunctionExpr<StringFunctionExpr>,
302    },
303    BitArrayFunction {
304        local: BitArrayFunctionLocalId,
305        value: TypedFunctionExpr<BitArrayFunctionExpr>,
306    },
307    UtfCodepointFunction {
308        local: UtfCodepointFunctionLocalId,
309        value: TypedFunctionExpr<UtfCodepointFunctionExpr>,
310    },
311    CustomFunction {
312        local: CustomFunctionLocal,
313        value: TypedFunctionExpr<CustomFunctionExpr>,
314    },
315    ExternalFunction {
316        local: ExternalFunctionLocal,
317        value: TypedFunctionExpr<ExternalFunctionExpr>,
318    },
319    BoolFunction {
320        local: BoolFunctionLocalId,
321        value: TypedFunctionExpr<BoolFunctionExpr>,
322    },
323    NilFunction {
324        local: NilFunctionLocalId,
325        value: TypedFunctionExpr<NilFunctionExpr>,
326    },
327    TupleFunction {
328        local: TupleFunctionLocalId,
329        value: TypedFunctionExpr<TupleFunctionExpr>,
330    },
331    ListFunction {
332        local: ListFunctionLocal,
333        value: TypedFunctionExpr<ListFunctionExpr>,
334    },
335    FunctionFunction {
336        local: FunctionFunctionLocal,
337        value: TypedFunctionExpr<FunctionFunctionExpr>,
338    },
339    GenericFunction {
340        local: GenericFunctionLocal,
341        value: TypedFunctionExpr<GenericFunctionExpr>,
342    },
343}
344
345impl AssertBinding {
346    pub(crate) fn new(local: ParamLocal, name: EcoString, shape: crate::plan::ValueShape) -> Self {
347        Self {
348            slot: ParamSlot::new(local, shape),
349            name,
350        }
351    }
352
353    pub(crate) fn local(&self) -> &ParamLocal {
354        self.slot.local()
355    }
356
357    pub(crate) fn slot(&self) -> &ParamSlot {
358        &self.slot
359    }
360}
361
362impl StringAssertBinding {
363    pub(crate) fn new(local: StringLocalId, name: EcoString) -> Self {
364        Self { local, name }
365    }
366
367    pub(crate) fn local(&self) -> StringLocalId {
368        self.local
369    }
370}
371
372impl AssertPattern {
373    pub(crate) fn list(pattern: ListAssertPattern) -> Self {
374        Self::List(pattern)
375    }
376
377    pub(crate) fn bit_array(pattern: BitArrayPattern) -> Self {
378        Self::BitArray(pattern)
379    }
380
381    pub(crate) fn custom(pattern: crate::plan::CustomPattern) -> Self {
382        Self::Custom(pattern)
383    }
384
385    pub(crate) fn alias(pattern: AssertPattern, binding: AssertBinding) -> Self {
386        Self::Alias {
387            pattern: Box::new(pattern),
388            binding,
389        }
390    }
391}
392
393impl ListAssertPattern {
394    pub(crate) fn new(
395        element_type: ValueType,
396        elements: Vec<AssertPattern>,
397        tail: Option<ListAssertTail>,
398    ) -> Self {
399        Self {
400            element_type,
401            elements,
402            tail,
403        }
404    }
405
406    pub(crate) fn element_type(&self) -> &ValueType {
407        &self.element_type
408    }
409
410    pub(crate) fn elements(&self) -> &[AssertPattern] {
411        &self.elements
412    }
413
414    pub(crate) fn tail(&self) -> Option<&ListAssertTail> {
415        self.tail.as_ref()
416    }
417}
418
419impl ListAssertTail {
420    pub(crate) fn bind(local: ListLocal, name: EcoString) -> Self {
421        Self::Bind(ListAssertTailBinding { local, name })
422    }
423}
424
425impl ListAssertTailBinding {
426    pub(crate) fn local(&self) -> &ListLocal {
427        &self.local
428    }
429}
430
431impl Step {
432    pub(crate) fn let_generic(local: GenericLocal, name: EcoString, value: GenericExpr) -> Self {
433        Self {
434            kind: StepKind::LetGeneric { local, name, value },
435        }
436    }
437
438    pub(crate) fn let_int(local: IntLocalId, name: EcoString, value: IntExpr) -> Self {
439        Self {
440            kind: StepKind::LetInt { local, name, value },
441        }
442    }
443
444    pub(crate) fn let_float(local: FloatLocalId, name: EcoString, value: FloatExpr) -> Self {
445        Self {
446            kind: StepKind::LetFloat { local, name, value },
447        }
448    }
449
450    pub(crate) fn let_string(local: StringLocalId, name: EcoString, value: StringExpr) -> Self {
451        Self {
452            kind: StepKind::LetString { local, name, value },
453        }
454    }
455
456    pub(crate) fn let_bit_array(
457        local: BitArrayLocalId,
458        name: EcoString,
459        value: BitArrayExpr,
460    ) -> Self {
461        Self {
462            kind: StepKind::LetBitArray { local, name, value },
463        }
464    }
465
466    pub(crate) fn let_utf_codepoint(
467        local: UtfCodepointLocalId,
468        name: EcoString,
469        value: UtfCodepointExpr,
470    ) -> Self {
471        Self {
472            kind: StepKind::LetUtfCodepoint { local, name, value },
473        }
474    }
475
476    pub(crate) fn let_custom(local: CustomLocalId, name: EcoString, value: CustomExpr) -> Self {
477        Self {
478            kind: StepKind::LetCustom {
479                binding: CustomLocalExpr::from_value(local, value),
480                name,
481            },
482        }
483    }
484
485    pub(crate) fn let_external(local: ExternalLocal, name: EcoString, value: ExternalExpr) -> Self {
486        Self {
487            kind: StepKind::LetExternal { local, name, value },
488        }
489    }
490
491    pub(crate) fn let_bool(local: BoolLocalId, name: EcoString, value: BoolExpr) -> Self {
492        Self {
493            kind: StepKind::LetBool { local, name, value },
494        }
495    }
496
497    pub(crate) fn let_nil(local: NilLocalId, name: EcoString, value: NilExpr) -> Self {
498        Self {
499            kind: StepKind::LetNil { local, name, value },
500        }
501    }
502
503    pub(crate) fn let_tuple(local: TupleLocalId, name: EcoString, value: TupleExpr) -> Self {
504        Self {
505            kind: StepKind::LetTuple { local, name, value },
506        }
507    }
508
509    pub(crate) fn let_list_expr(name: EcoString, value: ListLocalExpr) -> Self {
510        Self {
511            kind: StepKind::LetList { name, value },
512        }
513    }
514
515    pub(crate) fn let_int_function_expr(
516        local: IntFunctionLocalId,
517        name: EcoString,
518        value: TypedFunctionExpr<IntFunctionExpr>,
519    ) -> Self {
520        Self {
521            kind: StepKind::LetIntFunction { local, name, value },
522        }
523    }
524
525    pub(crate) fn let_float_function_expr(
526        local: FloatFunctionLocalId,
527        name: EcoString,
528        value: TypedFunctionExpr<FloatFunctionExpr>,
529    ) -> Self {
530        Self {
531            kind: StepKind::LetFloatFunction { local, name, value },
532        }
533    }
534
535    pub(crate) fn let_string_function_expr(
536        local: StringFunctionLocalId,
537        name: EcoString,
538        value: TypedFunctionExpr<StringFunctionExpr>,
539    ) -> Self {
540        Self {
541            kind: StepKind::LetStringFunction { local, name, value },
542        }
543    }
544
545    pub(crate) fn let_bit_array_function_expr(
546        local: BitArrayFunctionLocalId,
547        name: EcoString,
548        value: TypedFunctionExpr<BitArrayFunctionExpr>,
549    ) -> Self {
550        Self {
551            kind: StepKind::LetBitArrayFunction { local, name, value },
552        }
553    }
554
555    pub(crate) fn let_utf_codepoint_function_expr(
556        local: UtfCodepointFunctionLocalId,
557        name: EcoString,
558        value: TypedFunctionExpr<UtfCodepointFunctionExpr>,
559    ) -> Self {
560        Self {
561            kind: StepKind::LetUtfCodepointFunction { local, name, value },
562        }
563    }
564
565    pub(crate) fn let_custom_function_expr(
566        local: CustomFunctionLocalId,
567        name: EcoString,
568        value: TypedFunctionExpr<CustomFunctionExpr>,
569    ) -> Self {
570        let local =
571            CustomFunctionLocal::new(local, value.expression().custom_function_type().clone());
572        Self {
573            kind: StepKind::LetCustomFunction { local, name, value },
574        }
575    }
576
577    pub(crate) fn let_external_function_expr(
578        local: ExternalFunctionLocalId,
579        name: EcoString,
580        value: TypedFunctionExpr<ExternalFunctionExpr>,
581    ) -> Self {
582        let local =
583            ExternalFunctionLocal::new(local, value.expression().external_function_type().clone());
584        Self {
585            kind: StepKind::LetExternalFunction { local, name, value },
586        }
587    }
588
589    pub(crate) fn let_bool_function_expr(
590        local: BoolFunctionLocalId,
591        name: EcoString,
592        value: TypedFunctionExpr<BoolFunctionExpr>,
593    ) -> Self {
594        Self {
595            kind: StepKind::LetBoolFunction { local, name, value },
596        }
597    }
598
599    pub(crate) fn let_nil_function_expr(
600        local: NilFunctionLocalId,
601        name: EcoString,
602        value: TypedFunctionExpr<NilFunctionExpr>,
603    ) -> Self {
604        Self {
605            kind: StepKind::LetNilFunction { local, name, value },
606        }
607    }
608
609    pub(crate) fn let_tuple_function_expr(
610        local: TupleFunctionLocalId,
611        name: EcoString,
612        value: TypedFunctionExpr<TupleFunctionExpr>,
613    ) -> Self {
614        Self {
615            kind: StepKind::LetTupleFunction { local, name, value },
616        }
617    }
618
619    pub(crate) fn let_list_function_expr(
620        local: ListFunctionLocal,
621        name: EcoString,
622        value: TypedFunctionExpr<ListFunctionExpr>,
623    ) -> Self {
624        Self {
625            kind: StepKind::LetListFunction { local, name, value },
626        }
627    }
628
629    pub(crate) fn let_function_function_expr(
630        local: FunctionFunctionLocalId,
631        name: EcoString,
632        value: TypedFunctionExpr<FunctionFunctionExpr>,
633    ) -> Self {
634        let local =
635            FunctionFunctionLocal::new(local, value.expression().function_function_type().clone());
636        Self {
637            kind: StepKind::LetFunctionFunction { local, name, value },
638        }
639    }
640
641    pub(crate) fn let_generic_function_expr(
642        local: GenericFunctionLocal,
643        name: EcoString,
644        value: TypedFunctionExpr<GenericFunctionExpr>,
645    ) -> Self {
646        Self {
647            kind: StepKind::LetGenericFunction { local, name, value },
648        }
649    }
650
651    pub(crate) fn echo(subject: EchoSubject, message: Option<StringExpr>, site: EchoSite) -> Self {
652        Self {
653            kind: StepKind::Echo(Echo {
654                subject,
655                message,
656                site,
657            }),
658        }
659    }
660
661    #[cfg(test)]
662    pub(crate) fn let_int_function(
663        local: IntFunctionLocalId,
664        name: EcoString,
665        value: IntFunctionExpr,
666    ) -> Self {
667        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
668        Self::let_int_function_expr(local, name, TypedFunctionExpr::new(shape, value))
669    }
670
671    #[cfg(test)]
672    pub(crate) fn let_float_function(
673        local: FloatFunctionLocalId,
674        name: EcoString,
675        value: FloatFunctionExpr,
676    ) -> Self {
677        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
678        Self::let_float_function_expr(local, name, TypedFunctionExpr::new(shape, value))
679    }
680
681    #[cfg(test)]
682    pub(crate) fn let_string_function(
683        local: StringFunctionLocalId,
684        name: EcoString,
685        value: StringFunctionExpr,
686    ) -> Self {
687        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
688        Self::let_string_function_expr(local, name, TypedFunctionExpr::new(shape, value))
689    }
690
691    #[cfg(test)]
692    pub(crate) fn let_bit_array_function(
693        local: BitArrayFunctionLocalId,
694        name: EcoString,
695        value: BitArrayFunctionExpr,
696    ) -> Self {
697        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
698        Self::let_bit_array_function_expr(local, name, TypedFunctionExpr::new(shape, value))
699    }
700
701    #[cfg(test)]
702    pub(crate) fn let_utf_codepoint_function(
703        local: UtfCodepointFunctionLocalId,
704        name: EcoString,
705        value: UtfCodepointFunctionExpr,
706    ) -> Self {
707        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
708        Self::let_utf_codepoint_function_expr(local, name, TypedFunctionExpr::new(shape, value))
709    }
710
711    #[cfg(test)]
712    pub(crate) fn let_custom_function(
713        local: CustomFunctionLocalId,
714        name: EcoString,
715        value: CustomFunctionExpr,
716    ) -> Self {
717        let shape = crate::plan::FunctionShape::new(
718            value.custom_function_type().argument_shapes().to_vec(),
719            crate::plan::ValueShape::Custom(value.custom_function_type().return_().clone()),
720        );
721        Self::let_custom_function_expr(local, name, TypedFunctionExpr::new(shape, value))
722    }
723
724    #[cfg(test)]
725    pub(crate) fn let_bool_function(
726        local: BoolFunctionLocalId,
727        name: EcoString,
728        value: BoolFunctionExpr,
729    ) -> Self {
730        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
731        Self::let_bool_function_expr(local, name, TypedFunctionExpr::new(shape, value))
732    }
733
734    #[cfg(test)]
735    pub(crate) fn let_nil_function(
736        local: NilFunctionLocalId,
737        name: EcoString,
738        value: NilFunctionExpr,
739    ) -> Self {
740        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
741        Self::let_nil_function_expr(local, name, TypedFunctionExpr::new(shape, value))
742    }
743
744    #[cfg(test)]
745    pub(crate) fn let_tuple_function(
746        local: TupleFunctionLocalId,
747        name: EcoString,
748        value: TupleFunctionExpr,
749    ) -> Self {
750        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
751        Self::let_tuple_function_expr(local, name, TypedFunctionExpr::new(shape, value))
752    }
753
754    #[cfg(test)]
755    pub(crate) fn let_list_function(
756        local: ListFunctionLocal,
757        name: EcoString,
758        value: ListFunctionExpr,
759    ) -> Self {
760        let shape = crate::plan::FunctionShape::from_function_type(value.type_().clone());
761        Self::let_list_function_expr(local, name, TypedFunctionExpr::new(shape, value))
762    }
763
764    #[cfg(test)]
765    pub(crate) fn let_function_function(
766        local: FunctionFunctionLocalId,
767        name: EcoString,
768        value: FunctionFunctionExpr,
769    ) -> Self {
770        let shape = crate::plan::FunctionShape::from_function_type(value.type_());
771        Self::let_function_function_expr(local, name, TypedFunctionExpr::new(shape, value))
772    }
773
774    pub(crate) fn assert_pattern_at(
775        subject: AssertSubject,
776        pattern: AssertPattern,
777        message: Option<StringExpr>,
778        site: PanicSite,
779        pattern_span: SourceSpan,
780    ) -> Self {
781        Self {
782            kind: StepKind::AssertPattern {
783                subject,
784                pattern,
785                message,
786                site,
787                pattern_span,
788            },
789        }
790    }
791
792    pub(crate) fn bind_custom_fields(local: CustomLocalId, pattern: CustomBindingPattern) -> Self {
793        let local = CustomLocal::from_shape(local, pattern.source_shape().clone());
794        Self {
795            kind: StepKind::BindCustomFields { local, pattern },
796        }
797    }
798
799    pub(crate) fn assert_bool_at(
800        condition: BoolExpr,
801        message: Option<StringExpr>,
802        site: PanicSite,
803    ) -> Self {
804        Self {
805            kind: StepKind::AssertBool {
806                condition,
807                message,
808                site,
809            },
810        }
811    }
812
813    pub(crate) fn evaluate(value: Expr) -> Self {
814        Self {
815            kind: StepKind::Evaluate(value),
816        }
817    }
818
819    pub(crate) fn kind(&self) -> &StepKind {
820        &self.kind
821    }
822}
823
824impl Echo {
825    pub(crate) fn subject(&self) -> &EchoSubject {
826        &self.subject
827    }
828
829    pub(crate) fn message(&self) -> Option<&StringExpr> {
830        self.message.as_ref()
831    }
832
833    pub(crate) fn site(&self) -> &EchoSite {
834        &self.site
835    }
836}
837
838#[cfg(test)]
839mod tests {
840    use super::{Step, StepKind};
841    use crate::plan::module::TypedFunctionExpr;
842    use crate::plan::{
843        AssertPattern, AssertSubject, BoolExpr, CustomFunctionExpr, CustomFunctionLocal,
844        CustomFunctionLocalId, CustomFunctionType, CustomType, CustomTypeName, Expr,
845        FunctionFunctionExpr, FunctionFunctionLocal, FunctionFunctionLocalId, FunctionFunctionType,
846        FunctionType, IntExpr, IntFunctionLocalId, IntFunctionReference, IntListLocalId,
847        IntLocalId, ListAssertPattern, ListAssertTail, ListLocal, PanicExpr, PanicSite, StringExpr,
848        ValueShape, ValueType,
849    };
850    use num_bigint::BigInt;
851
852    #[test]
853    fn step_kind_accessors() {
854        assert_eq!(
855            Step::let_int(IntLocalId(0), "x".into(), IntExpr::value(BigInt::from(1))).kind(),
856            &StepKind::LetInt {
857                local: IntLocalId(0),
858                name: "x".into(),
859                value: IntExpr::value(BigInt::from(1)),
860            },
861        );
862        assert_eq!(
863            Step::let_int_function(IntFunctionLocalId(0), "f".into(), function_expr()).kind(),
864            &StepKind::LetIntFunction {
865                local: IntFunctionLocalId(0),
866                name: "f".into(),
867                value: TypedFunctionExpr::new(
868                    crate::plan::FunctionShape::from_function_type(function_expr().type_().clone()),
869                    function_expr(),
870                ),
871            },
872        );
873        assert_eq!(
874            Step::evaluate(Expr::int(IntExpr::value(BigInt::from(1)))).kind(),
875            &StepKind::Evaluate(Expr::int(IntExpr::value(BigInt::from(1)))),
876        );
877        assert_eq!(
878            Step::assert_bool_at(
879                BoolExpr::value(false),
880                Some(StringExpr::value("nope".into())),
881                crate::plan::PanicSite::unknown(),
882            )
883            .kind(),
884            &StepKind::AssertBool {
885                condition: BoolExpr::value(false),
886                message: Some(StringExpr::value("nope".into())),
887                site: crate::plan::PanicSite::unknown(),
888            },
889        );
890        assert_eq!(
891            Step::assert_pattern_at(
892                AssertSubject::List(ListLocal::int(IntListLocalId(0))),
893                AssertPattern::list(ListAssertPattern::new(
894                    ValueType::Int,
895                    vec![AssertPattern::Discard],
896                    Some(ListAssertTail::bind(
897                        ListLocal::int(IntListLocalId(1)),
898                        "tail".into()
899                    )),
900                )),
901                None,
902                crate::plan::PanicSite::unknown(),
903                crate::plan::SourceSpan::new(0, 0),
904            )
905            .kind(),
906            &StepKind::AssertPattern {
907                subject: AssertSubject::List(ListLocal::int(IntListLocalId(0))),
908                pattern: AssertPattern::list(ListAssertPattern::new(
909                    ValueType::Int,
910                    vec![AssertPattern::Discard],
911                    Some(ListAssertTail::bind(
912                        ListLocal::int(IntListLocalId(1)),
913                        "tail".into()
914                    )),
915                )),
916                message: None,
917                site: crate::plan::PanicSite::unknown(),
918                pattern_span: crate::plan::SourceSpan::new(0, 0),
919            },
920        );
921    }
922
923    #[test]
924    fn callable_let_steps_derive_the_local_type_from_the_value() {
925        let custom_type = CustomType::new(
926            CustomTypeName::new("geam".into(), "main".into(), "Boxed".into()),
927            Vec::new(),
928        );
929        let custom_function_type =
930            CustomFunctionType::new(vec![ValueType::Int], custom_type.clone());
931        let custom_value = CustomFunctionExpr::panic(
932            PanicExpr::panic_at(None, PanicSite::unknown()),
933            custom_function_type.clone(),
934        );
935        assert_eq!(
936            Step::let_custom_function(
937                CustomFunctionLocalId(3),
938                "custom".into(),
939                custom_value.clone(),
940            )
941            .kind(),
942            &StepKind::LetCustomFunction {
943                local: CustomFunctionLocal::new(CustomFunctionLocalId(3), custom_function_type,),
944                name: "custom".into(),
945                value: TypedFunctionExpr::new(
946                    crate::plan::FunctionShape::new(
947                        custom_value
948                            .custom_function_type()
949                            .argument_shapes()
950                            .to_vec(),
951                        ValueShape::Custom(custom_value.custom_function_type().return_().clone(),),
952                    ),
953                    custom_value,
954                ),
955            },
956        );
957
958        let function_function_type = FunctionFunctionType::new(
959            vec![ValueType::String],
960            FunctionType::new(vec![ValueType::Bool], ValueType::Int),
961        );
962        let function_value = FunctionFunctionExpr::panic(
963            PanicExpr::panic_at(None, PanicSite::unknown()),
964            function_function_type.clone(),
965        );
966        assert_eq!(
967            Step::let_function_function(
968                FunctionFunctionLocalId(4),
969                "function".into(),
970                function_value.clone(),
971            )
972            .kind(),
973            &StepKind::LetFunctionFunction {
974                local: FunctionFunctionLocal::new(
975                    FunctionFunctionLocalId(4),
976                    function_function_type,
977                ),
978                name: "function".into(),
979                value: TypedFunctionExpr::new(
980                    crate::plan::FunctionShape::from_function_type(function_value.type_()),
981                    function_value,
982                ),
983            },
984        );
985    }
986
987    fn function_expr() -> crate::plan::IntFunctionExpr {
988        crate::plan::IntFunctionExpr::reference(IntFunctionReference::new(
989            crate::plan::monomorphic_function_instantiation(
990                0,
991                crate::plan::FunctionShape::new(
992                    vec![crate::plan::ValueShape::Int],
993                    crate::plan::ValueShape::Int,
994                ),
995            ),
996        ))
997    }
998}