aiken_lang/
expr.rs

1pub(crate) use crate::{
2    ast::{
3        self, Annotation, ArgBy, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
4        ByteArrayFormatPreference, CallArg, Curve, DataType, DataTypeKey, DefinitionLocation,
5        Located, LogicalOpChainKind, ParsedCallArg, RecordConstructorArg, RecordUpdateSpread, Span,
6        TraceKind, TypedArg, TypedAssignmentKind, TypedClause, TypedDataType, TypedIfBranch,
7        TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg, UntypedAssignmentKind, UntypedClause,
8        UntypedIfBranch, UntypedRecordUpdateArg,
9    },
10    parser::token::Base,
11    tipo::{
12        ModuleValueConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant,
13        check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
14    },
15};
16use indexmap::IndexMap;
17use pallas_primitives::alonzo::{Constr, PlutusData};
18use std::{fmt::Debug, ops::Deref, rc::Rc};
19use uplc::{
20    KeyValuePairs,
21    ast::Data,
22    machine::{runtime::convert_tag_to_constr, value::from_pallas_bigint},
23};
24use vec1::Vec1;
25
26#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
27pub enum TypedExpr {
28    UInt {
29        location: Span,
30        tipo: Rc<Type>,
31        value: String,
32        base: Base,
33    },
34
35    String {
36        location: Span,
37        tipo: Rc<Type>,
38        value: String,
39    },
40
41    ByteArray {
42        location: Span,
43        tipo: Rc<Type>,
44        bytes: Vec<u8>,
45        preferred_format: ByteArrayFormatPreference,
46    },
47
48    CurvePoint {
49        location: Span,
50        tipo: Rc<Type>,
51        point: Box<Curve>,
52        preferred_format: ByteArrayFormatPreference,
53    },
54
55    Sequence {
56        location: Span,
57        expressions: Vec<Self>,
58    },
59
60    /// A chain of pipe expressions.
61    /// By this point the type checker has expanded it into a series of
62    /// assignments and function calls, but we still have a Pipeline AST node as
63    /// even though it is identical to `Sequence` we want to use different
64    /// locations when showing it in error messages, etc.
65    Pipeline {
66        location: Span,
67        expressions: Vec<Self>,
68    },
69
70    Var {
71        location: Span,
72        constructor: ValueConstructor,
73        name: String,
74    },
75
76    Fn {
77        location: Span,
78        tipo: Rc<Type>,
79        is_capture: bool,
80        args: Vec<TypedArg>,
81        body: Box<Self>,
82        return_annotation: Option<Annotation>,
83    },
84
85    List {
86        location: Span,
87        tipo: Rc<Type>,
88        elements: Vec<Self>,
89        tail: Option<Box<Self>>,
90    },
91
92    Call {
93        location: Span,
94        tipo: Rc<Type>,
95        fun: Box<Self>,
96        args: Vec<CallArg<Self>>,
97    },
98
99    BinOp {
100        location: Span,
101        tipo: Rc<Type>,
102        name: BinOp,
103        left: Box<Self>,
104        right: Box<Self>,
105    },
106
107    Assignment {
108        location: Span,
109        tipo: Rc<Type>,
110        value: Box<Self>,
111        pattern: TypedPattern,
112        kind: TypedAssignmentKind,
113    },
114
115    Trace {
116        location: Span,
117        tipo: Rc<Type>,
118        then: Box<Self>,
119        text: Box<Self>,
120    },
121
122    When {
123        location: Span,
124        tipo: Rc<Type>,
125        subject: Box<Self>,
126        clauses: Vec<TypedClause>,
127    },
128
129    If {
130        location: Span,
131        #[serde(with = "Vec1Ref")]
132        branches: Vec1<TypedIfBranch>,
133        final_else: Box<Self>,
134        tipo: Rc<Type>,
135    },
136
137    RecordAccess {
138        location: Span,
139        tipo: Rc<Type>,
140        label: String,
141        index: u64,
142        record: Box<Self>,
143    },
144
145    ModuleSelect {
146        location: Span,
147        tipo: Rc<Type>,
148        label: String,
149        module_name: String,
150        module_alias: String,
151        constructor: ModuleValueConstructor,
152    },
153
154    Tuple {
155        location: Span,
156        tipo: Rc<Type>,
157        elems: Vec<Self>,
158    },
159
160    Pair {
161        location: Span,
162        tipo: Rc<Type>,
163        fst: Box<Self>,
164        snd: Box<Self>,
165    },
166
167    TupleIndex {
168        location: Span,
169        tipo: Rc<Type>,
170        index: usize,
171        tuple: Box<Self>,
172    },
173
174    ErrorTerm {
175        location: Span,
176        tipo: Rc<Type>,
177    },
178
179    RecordUpdate {
180        location: Span,
181        tipo: Rc<Type>,
182        spread: Box<Self>,
183        args: Vec<TypedRecordUpdateArg>,
184    },
185
186    UnOp {
187        location: Span,
188        value: Box<Self>,
189        tipo: Rc<Type>,
190        op: UnOp,
191    },
192}
193
194#[derive(serde::Serialize, serde::Deserialize)]
195#[serde(remote = "Vec1")]
196struct Vec1Ref<T>(#[serde(getter = "Vec1::as_vec")] Vec<T>);
197
198impl<T> From<Vec1Ref<T>> for Vec1<T> {
199    fn from(v: Vec1Ref<T>) -> Self {
200        Vec1::try_from_vec(v.0).unwrap()
201    }
202}
203
204impl TypedExpr {
205    pub fn is_simple_expr_to_format(&self) -> bool {
206        match self {
207            Self::String { .. } | Self::UInt { .. } | Self::ByteArray { .. } | Self::Var { .. } => {
208                true
209            }
210            Self::Pair { fst, snd, .. } => {
211                fst.is_simple_expr_to_format() && snd.is_simple_expr_to_format()
212            }
213            Self::Tuple { elems, .. } => elems.iter().all(|e| e.is_simple_expr_to_format()),
214            Self::List { elements, .. } if elements.len() <= 3 => {
215                elements.iter().all(|e| e.is_simple_expr_to_format())
216            }
217            _ => false,
218        }
219    }
220
221    pub fn and_then(self, next: Self) -> Self {
222        if let TypedExpr::Trace {
223            tipo,
224            location,
225            then,
226            text,
227        } = self
228        {
229            return TypedExpr::Trace {
230                tipo,
231                location,
232                then: Box::new(then.and_then(next)),
233                text,
234            };
235        }
236
237        TypedExpr::Sequence {
238            location: self.location(),
239            expressions: vec![self, next],
240        }
241    }
242
243    pub fn sequence(exprs: &[TypedExpr]) -> Self {
244        TypedExpr::Sequence {
245            location: Span::empty(),
246            expressions: exprs.to_vec(),
247        }
248    }
249
250    pub fn let_(value: Self, pattern: TypedPattern, tipo: Rc<Type>, location: Span) -> Self {
251        TypedExpr::Assignment {
252            tipo: tipo.clone(),
253            value: value.into(),
254            pattern,
255            kind: AssignmentKind::let_(),
256            location,
257        }
258    }
259
260    // Create an expect assignment, unless the target type is `Data`; then fallback to a let.
261    pub fn flexible_expect(
262        value: Self,
263        pattern: TypedPattern,
264        tipo: Rc<Type>,
265        location: Span,
266    ) -> Self {
267        TypedExpr::Assignment {
268            tipo: tipo.clone(),
269            value: value.into(),
270            pattern,
271            kind: if tipo.is_data() {
272                AssignmentKind::let_()
273            } else {
274                AssignmentKind::expect()
275            },
276            location,
277        }
278    }
279
280    pub fn local_var(name: &str, tipo: Rc<Type>, location: Span) -> Self {
281        TypedExpr::Var {
282            constructor: ValueConstructor {
283                public: true,
284                variant: ValueConstructorVariant::LocalVariable {
285                    location: Span::empty(),
286                },
287                tipo: tipo.clone(),
288            },
289            name: name.to_string(),
290            location,
291        }
292    }
293
294    pub fn tipo(&self) -> Rc<Type> {
295        match self {
296            Self::Var { constructor, .. } => constructor.tipo.clone(),
297            Self::Trace { then, .. } => then.tipo(),
298            Self::Fn { tipo, .. }
299            | Self::UInt { tipo, .. }
300            | Self::ErrorTerm { tipo, .. }
301            | Self::When { tipo, .. }
302            | Self::List { tipo, .. }
303            | Self::Call { tipo, .. }
304            | Self::If { tipo, .. }
305            | Self::UnOp { tipo, .. }
306            | Self::BinOp { tipo, .. }
307            | Self::Tuple { tipo, .. }
308            | Self::Pair { tipo, .. }
309            | Self::String { tipo, .. }
310            | Self::ByteArray { tipo, .. }
311            | Self::TupleIndex { tipo, .. }
312            | Self::Assignment { tipo, .. }
313            | Self::ModuleSelect { tipo, .. }
314            | Self::RecordAccess { tipo, .. }
315            | Self::RecordUpdate { tipo, .. }
316            | Self::CurvePoint { tipo, .. } => tipo.clone(),
317            Self::Pipeline { expressions, .. } | Self::Sequence { expressions, .. } => expressions
318                .last()
319                .map(TypedExpr::tipo)
320                .unwrap_or_else(Type::void),
321        }
322    }
323
324    pub fn is_literal(&self) -> bool {
325        matches!(
326            self,
327            Self::UInt { .. }
328                | Self::List { .. }
329                | Self::Tuple { .. }
330                | Self::String { .. }
331                | Self::ByteArray { .. }
332        )
333    }
334
335    pub fn is_error_term(&self) -> bool {
336        matches!(self, Self::ErrorTerm { .. })
337    }
338
339    /// Returns `true` if the typed expr is [`Assignment`].
340    pub fn is_assignment(&self) -> bool {
341        matches!(self, Self::Assignment { .. })
342    }
343
344    pub fn definition_location(&self) -> Option<DefinitionLocation<'_>> {
345        match self {
346            TypedExpr::Fn { .. }
347            | TypedExpr::UInt { .. }
348            | TypedExpr::Trace { .. }
349            | TypedExpr::List { .. }
350            | TypedExpr::Call { .. }
351            | TypedExpr::When { .. }
352            | TypedExpr::ErrorTerm { .. }
353            | TypedExpr::BinOp { .. }
354            | TypedExpr::Tuple { .. }
355            | TypedExpr::Pair { .. }
356            | TypedExpr::UnOp { .. }
357            | TypedExpr::String { .. }
358            | TypedExpr::Sequence { .. }
359            | TypedExpr::Pipeline { .. }
360            | TypedExpr::ByteArray { .. }
361            | TypedExpr::Assignment { .. }
362            | TypedExpr::TupleIndex { .. }
363            | TypedExpr::RecordAccess { .. }
364            | TypedExpr::CurvePoint { .. } => None,
365            TypedExpr::If { .. } => None,
366
367            // TODO: test
368            // TODO: definition
369            TypedExpr::RecordUpdate { .. } => None,
370
371            // TODO: test
372            TypedExpr::ModuleSelect {
373                module_name,
374                constructor,
375                ..
376            } => Some(DefinitionLocation {
377                module: Some(module_name.as_str()),
378                span: constructor.location(),
379            }),
380
381            // TODO: test
382            TypedExpr::Var { constructor, .. } => Some(constructor.definition_location()),
383        }
384    }
385
386    pub fn type_defining_location(&self) -> Span {
387        match self {
388            Self::Fn { location, .. }
389            | Self::UInt { location, .. }
390            | Self::Var { location, .. }
391            | Self::Trace { location, .. }
392            | Self::ErrorTerm { location, .. }
393            | Self::When { location, .. }
394            | Self::Call { location, .. }
395            | Self::List { location, .. }
396            | Self::BinOp { location, .. }
397            | Self::Tuple { location, .. }
398            | Self::Pair { location, .. }
399            | Self::String { location, .. }
400            | Self::UnOp { location, .. }
401            | Self::Pipeline { location, .. }
402            | Self::ByteArray { location, .. }
403            | Self::Assignment { location, .. }
404            | Self::TupleIndex { location, .. }
405            | Self::ModuleSelect { location, .. }
406            | Self::RecordAccess { location, .. }
407            | Self::RecordUpdate { location, .. }
408            | Self::CurvePoint { location, .. } => *location,
409
410            Self::If { branches, .. } => branches.first().body.type_defining_location(),
411
412            Self::Sequence {
413                expressions,
414                location,
415                ..
416            } => expressions
417                .last()
418                .map(TypedExpr::location)
419                .unwrap_or(*location),
420        }
421    }
422
423    pub fn location(&self) -> Span {
424        match self {
425            Self::Fn { location, .. }
426            | Self::UInt { location, .. }
427            | Self::Trace { location, .. }
428            | Self::Var { location, .. }
429            | Self::ErrorTerm { location, .. }
430            | Self::When { location, .. }
431            | Self::Call { location, .. }
432            | Self::If { location, .. }
433            | Self::List { location, .. }
434            | Self::BinOp { location, .. }
435            | Self::Tuple { location, .. }
436            | Self::Pair { location, .. }
437            | Self::String { location, .. }
438            | Self::UnOp { location, .. }
439            | Self::Sequence { location, .. }
440            | Self::Pipeline { location, .. }
441            | Self::ByteArray { location, .. }
442            | Self::Assignment { location, .. }
443            | Self::TupleIndex { location, .. }
444            | Self::ModuleSelect { location, .. }
445            | Self::RecordAccess { location, .. }
446            | Self::RecordUpdate { location, .. }
447            | Self::CurvePoint { location, .. } => *location,
448        }
449    }
450
451    // This could be optimised in places to exit early if the first of a series
452    // of expressions is after the byte index.
453    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
454        if !self.location().contains(byte_index) {
455            return None;
456        }
457
458        match self {
459            TypedExpr::ErrorTerm { .. }
460            | TypedExpr::Var { .. }
461            | TypedExpr::UInt { .. }
462            | TypedExpr::String { .. }
463            | TypedExpr::ByteArray { .. }
464            | TypedExpr::ModuleSelect { .. }
465            | TypedExpr::CurvePoint { .. } => Some(Located::Expression(self)),
466
467            TypedExpr::Trace { text, then, .. } => text
468                .find_node(byte_index)
469                .or_else(|| then.find_node(byte_index))
470                .or(Some(Located::Expression(self))),
471
472            TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => {
473                expressions.iter().find_map(|e| e.find_node(byte_index))
474            }
475
476            TypedExpr::Fn {
477                body,
478                args,
479                return_annotation,
480                ..
481            } => args
482                .iter()
483                .find_map(|arg| arg.find_node(byte_index))
484                .or_else(|| body.find_node(byte_index))
485                .or_else(|| {
486                    return_annotation
487                        .as_ref()
488                        .and_then(|a| a.find_node(byte_index))
489                })
490                .or(Some(Located::Expression(self))),
491
492            TypedExpr::Tuple {
493                elems: elements, ..
494            } => elements
495                .iter()
496                .find_map(|e| e.find_node(byte_index))
497                .or(Some(Located::Expression(self))),
498
499            TypedExpr::Pair { fst, snd, .. } => [fst, snd]
500                .iter()
501                .find_map(|e| e.find_node(byte_index))
502                .or(Some(Located::Expression(self))),
503
504            TypedExpr::List { elements, tail, .. } => elements
505                .iter()
506                .find_map(|e| e.find_node(byte_index))
507                .or_else(|| tail.as_ref().and_then(|t| t.find_node(byte_index)))
508                .or(Some(Located::Expression(self))),
509
510            TypedExpr::Call { fun, args, .. } => args
511                .iter()
512                .find_map(|arg| arg.find_node(byte_index))
513                .or_else(|| fun.find_node(byte_index))
514                .or(Some(Located::Expression(self))),
515
516            TypedExpr::BinOp { left, right, .. } => left
517                .find_node(byte_index)
518                .or_else(|| right.find_node(byte_index))
519                .or(Some(Located::Expression(self))),
520
521            TypedExpr::Assignment { value, pattern, .. } => pattern
522                .find_node(byte_index, &value.tipo())
523                .or_else(|| value.find_node(byte_index)),
524
525            TypedExpr::When {
526                subject, clauses, ..
527            } => subject
528                .find_node(byte_index)
529                .or_else(|| {
530                    clauses
531                        .iter()
532                        .find_map(|clause| clause.find_node(byte_index, &subject.tipo()))
533                })
534                .or(Some(Located::Expression(self))),
535
536            TypedExpr::RecordAccess {
537                record: expression, ..
538            }
539            | TypedExpr::TupleIndex {
540                tuple: expression, ..
541            } => expression
542                .find_node(byte_index)
543                .or(Some(Located::Expression(self))),
544
545            TypedExpr::RecordUpdate { spread, args, .. } => args
546                .iter()
547                .find_map(|arg| arg.find_node(byte_index))
548                .or_else(|| spread.find_node(byte_index))
549                .or(Some(Located::Expression(self))),
550
551            TypedExpr::If {
552                branches,
553                final_else,
554                ..
555            } => branches
556                .iter()
557                .find_map(|branch| {
558                    branch
559                        .condition
560                        .find_node(byte_index)
561                        .or_else(|| branch.body.find_node(byte_index))
562                })
563                .or_else(|| final_else.find_node(byte_index))
564                .or(Some(Located::Expression(self))),
565
566            TypedExpr::UnOp { value, .. } => value
567                .find_node(byte_index)
568                .or(Some(Located::Expression(self))),
569        }
570    }
571
572    pub fn void(location: Span) -> Self {
573        TypedExpr::Var {
574            name: "Void".to_string(),
575            constructor: ValueConstructor {
576                public: true,
577                variant: ValueConstructorVariant::Record {
578                    name: "Void".to_string(),
579                    arity: 0,
580                    field_map: None,
581                    location: Span::empty(),
582                    module: String::new(),
583                    constructors_count: 1,
584                },
585                tipo: Type::void(),
586            },
587            location,
588        }
589    }
590}
591
592// Represent how a function was written so that we can format it back.
593#[derive(Debug, Clone, PartialEq, Copy)]
594pub enum FnStyle {
595    Plain,
596    Capture,
597    BinOp(BinOp),
598}
599
600#[derive(Debug, Clone, PartialEq)]
601pub enum UntypedExpr {
602    UInt {
603        location: Span,
604        value: String,
605        base: Base,
606    },
607
608    String {
609        location: Span,
610        value: String,
611    },
612
613    Sequence {
614        location: Span,
615        expressions: Vec<Self>,
616    },
617
618    Var {
619        location: Span,
620        name: String,
621    },
622
623    Fn {
624        location: Span,
625        fn_style: FnStyle,
626        arguments: Vec<UntypedArg>,
627        body: Box<Self>,
628        return_annotation: Option<Annotation>,
629    },
630
631    List {
632        location: Span,
633        elements: Vec<Self>,
634        tail: Option<Box<Self>>,
635    },
636
637    Call {
638        arguments: Vec<CallArg<Self>>,
639        fun: Box<Self>,
640        location: Span,
641    },
642
643    BinOp {
644        location: Span,
645        name: BinOp,
646        left: Box<Self>,
647        right: Box<Self>,
648    },
649
650    ByteArray {
651        location: Span,
652        bytes: Vec<(u8, Span)>,
653        preferred_format: ByteArrayFormatPreference,
654    },
655
656    CurvePoint {
657        location: Span,
658        point: Box<Curve>,
659        preferred_format: ByteArrayFormatPreference,
660    },
661
662    PipeLine {
663        expressions: Vec1<Self>,
664        one_liner: bool,
665    },
666
667    Assignment {
668        location: Span,
669        value: Box<Self>,
670        patterns: Vec1<AssignmentPattern>,
671        kind: UntypedAssignmentKind,
672    },
673
674    Trace {
675        kind: TraceKind,
676        location: Span,
677        then: Box<Self>,
678        label: Box<Self>,
679        arguments: Vec<Self>,
680    },
681
682    TraceIfFalse {
683        location: Span,
684        value: Box<Self>,
685    },
686
687    When {
688        location: Span,
689        subject: Box<Self>,
690        clauses: Vec<UntypedClause>,
691    },
692
693    If {
694        location: Span,
695        branches: Vec1<UntypedIfBranch>,
696        final_else: Box<Self>,
697    },
698
699    FieldAccess {
700        location: Span,
701        label: String,
702        container: Box<Self>,
703    },
704
705    Tuple {
706        location: Span,
707        elems: Vec<Self>,
708    },
709
710    Pair {
711        location: Span,
712        fst: Box<Self>,
713        snd: Box<Self>,
714    },
715
716    TupleIndex {
717        location: Span,
718        index: usize,
719        tuple: Box<Self>,
720    },
721
722    ErrorTerm {
723        location: Span,
724    },
725
726    RecordUpdate {
727        location: Span,
728        constructor: Box<Self>,
729        spread: RecordUpdateSpread,
730        arguments: Vec<UntypedRecordUpdateArg>,
731    },
732
733    UnOp {
734        op: UnOp,
735        location: Span,
736        value: Box<Self>,
737    },
738
739    LogicalOpChain {
740        kind: LogicalOpChainKind,
741        expressions: Vec<Self>,
742        location: Span,
743    },
744}
745
746pub const DEFAULT_TODO_STR: &str = "aiken::todo";
747
748pub const DEFAULT_ERROR_STR: &str = "aiken::error";
749
750impl UntypedExpr {
751    // Reify some opaque 'Constant' into an 'UntypedExpr', using a Type annotation. We also need
752    // an extra map to lookup record & enum constructor's names as they're completely erased when
753    // in their PlutusData form, and the Type annotation only contains type name.
754    //
755    // The function performs some sanity check to ensure that the type does indeed somewhat
756    // correspond to the data being given.
757    pub fn reify_constant(
758        data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
759        cst: uplc::ast::Constant,
760        tipo: Rc<Type>,
761    ) -> Result<Self, String> {
762        UntypedExpr::do_reify_constant(&mut IndexMap::new(), data_types, cst, tipo)
763    }
764
765    pub fn is_discard(&self) -> bool {
766        matches!(self, UntypedExpr::Var { name, ..} if name.starts_with("_"))
767    }
768
769    // Reify some opaque 'PlutusData' into an 'UntypedExpr', using a Type annotation. We also need
770    // an extra map to lookup record & enum constructor's names as they're completely erased when
771    // in their PlutusData form, and the Type annotation only contains type name.
772    //
773    // The function performs some sanity check to ensure that the type does indeed somewhat
774    // correspond to the data being given.
775    pub fn reify_data(
776        data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
777        data: PlutusData,
778        tipo: Rc<Type>,
779    ) -> Result<Self, String> {
780        UntypedExpr::do_reify_data(&mut IndexMap::new(), data_types, data, tipo)
781    }
782
783    fn reify_with<T, F>(
784        generics: &mut IndexMap<u64, Rc<Type>>,
785        data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
786        t: T,
787        tipo: Rc<Type>,
788        with: F,
789    ) -> Result<Self, String>
790    where
791        T: Debug,
792        F: Fn(
793            &mut IndexMap<u64, Rc<Type>>,
794            &IndexMap<&DataTypeKey, &TypedDataType>,
795            T,
796            Rc<Type>,
797        ) -> Result<Self, String>,
798    {
799        if let Type::Var { tipo: var_tipo, .. } = tipo.deref() {
800            match &*var_tipo.borrow() {
801                TypeVar::Link { tipo } => {
802                    return Self::reify_with(generics, data_types, t, tipo.clone(), with);
803                }
804                TypeVar::Generic { id } => {
805                    if let Some(tipo) = generics.get(id) {
806                        return Self::reify_with(generics, data_types, t, tipo.clone(), with);
807                    }
808                }
809                _ => unreachable!("unbound type during reification {tipo:?} -> {t:?}"),
810            }
811        }
812
813        // NOTE: Opaque types are tricky. We can't tell from a type only if it is
814        // opaque or not. We have to lookup its datatype definition.
815        //
816        // Also, we can't -- in theory -- peak into an opaque type. More so, if it
817        // has a single constructor with a single argument, it is an zero-cost
818        // wrapper. That means the underlying PlutusData has no residue of that
819        // wrapper. So we have to manually reconstruct it before crawling further
820        // down the type tree.
821        if check_replaceable_opaque_type(&tipo, data_types) {
822            let DataType { name, .. } = lookup_data_type_by_tipo(data_types, &tipo)
823                .expect("Type just disappeared from known types? {tipo:?}");
824
825            let inner_type = convert_opaque_type(&tipo, data_types, false);
826
827            let value = Self::reify_with(generics, data_types, t, inner_type, with)?;
828
829            return Ok(UntypedExpr::Call {
830                location: Span::empty(),
831                arguments: vec![CallArg {
832                    label: None,
833                    location: Span::empty(),
834                    value,
835                }],
836                fun: Box::new(UntypedExpr::Var {
837                    name,
838                    location: Span::empty(),
839                }),
840            });
841        }
842
843        with(generics, data_types, t, tipo)
844    }
845
846    fn do_reify_constant(
847        generics: &mut IndexMap<u64, Rc<Type>>,
848        data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
849        cst: uplc::ast::Constant,
850        tipo: Rc<Type>,
851    ) -> Result<Self, String> {
852        Self::reify_with(
853            generics,
854            data_types,
855            cst,
856            tipo,
857            |generics, data_types, cst, tipo| match cst {
858                uplc::ast::Constant::Data(data) => {
859                    UntypedExpr::do_reify_data(generics, data_types, data, tipo)
860                }
861
862                uplc::ast::Constant::Integer(i) => {
863                    UntypedExpr::do_reify_data(generics, data_types, Data::integer(i), tipo)
864                }
865
866                uplc::ast::Constant::ByteString(bytes) => {
867                    UntypedExpr::do_reify_data(generics, data_types, Data::bytestring(bytes), tipo)
868                }
869
870                uplc::ast::Constant::ProtoList(_, args) => match tipo.deref() {
871                    Type::App {
872                        module,
873                        name,
874                        args: type_args,
875                        ..
876                    } if module.is_empty() && name.as_str() == "List" => {
877                        if let [inner] = &type_args[..] {
878                            Ok(UntypedExpr::List {
879                                location: Span::empty(),
880                                elements: args
881                                    .into_iter()
882                                    .map(|arg| {
883                                        UntypedExpr::do_reify_constant(
884                                            generics,
885                                            data_types,
886                                            arg,
887                                            inner.clone(),
888                                        )
889                                    })
890                                    .collect::<Result<Vec<_>, _>>()?,
891                                tail: None,
892                            })
893                        } else {
894                            Err(
895                                "invalid List type annotation: the list has multiple type-parameters."
896                                    .to_string(),
897                            )
898                        }
899                    }
900                    Type::Tuple { elems, .. } => Ok(UntypedExpr::Tuple {
901                        location: Span::empty(),
902                        elems: args
903                            .into_iter()
904                            .zip(elems)
905                            .map(|(arg, arg_type)| {
906                                UntypedExpr::do_reify_constant(
907                                    generics,
908                                    data_types,
909                                    arg,
910                                    arg_type.clone(),
911                                )
912                            })
913                            .collect::<Result<Vec<_>, _>>()?,
914                    }),
915                    _ => Err(format!(
916                        "invalid type annotation. expected List but got: {tipo:?}"
917                    )),
918                },
919
920                uplc::ast::Constant::ProtoPair(_, _, left, right) => match tipo.deref() {
921                    Type::Pair { fst, snd, .. } => {
922                        let elems = [left.as_ref(), right.as_ref()]
923                            .into_iter()
924                            .zip([fst, snd])
925                            .map(|(arg, arg_type)| {
926                                UntypedExpr::do_reify_constant(
927                                    generics,
928                                    data_types,
929                                    arg.to_owned(),
930                                    arg_type.clone(),
931                                )
932                            })
933                            .collect::<Result<Vec<_>, _>>()?;
934
935                        Ok(UntypedExpr::Pair {
936                            location: Span::empty(),
937                            fst: elems.first().unwrap().to_owned().into(),
938                            snd: elems.last().unwrap().to_owned().into(),
939                        })
940                    }
941                    _ => Err(format!(
942                        "invalid type annotation. expected Pair but got: {tipo:?}"
943                    )),
944                },
945
946                uplc::ast::Constant::Unit => Ok(UntypedExpr::Var {
947                    location: Span::empty(),
948                    name: "Void".to_string(),
949                }),
950
951                uplc::ast::Constant::Bool(is_true) => Ok(UntypedExpr::Var {
952                    location: Span::empty(),
953                    name: if is_true { "True" } else { "False" }.to_string(),
954                }),
955
956                uplc::ast::Constant::String(value) => Ok(UntypedExpr::String {
957                    location: Span::empty(),
958                    value,
959                }),
960
961                uplc::ast::Constant::Bls12_381G1Element(pt) => Ok(UntypedExpr::CurvePoint {
962                    location: Span::empty(),
963                    point: Curve::Bls12_381(Bls12_381Point::G1(*pt)).into(),
964                    preferred_format: ByteArrayFormatPreference::HexadecimalString,
965                }),
966
967                uplc::ast::Constant::Bls12_381G2Element(pt) => Ok(UntypedExpr::CurvePoint {
968                    location: Span::empty(),
969                    point: Curve::Bls12_381(Bls12_381Point::G2(*pt)).into(),
970                    preferred_format: ByteArrayFormatPreference::HexadecimalString,
971                }),
972
973                uplc::ast::Constant::Bls12_381MlResult(ml) => {
974                    let mut bytes = Vec::new();
975
976                    bytes.extend((*ml).to_bendian());
977
978                    // NOTE: We don't actually have a syntax for representing MillerLoop results, so we
979                    // just fake it as a constructor with a bytearray. Note also that the bytearray is
980                    // *large*.
981                    Ok(UntypedExpr::Call {
982                        location: Span::empty(),
983                        arguments: vec![CallArg {
984                            label: None,
985                            location: Span::empty(),
986                            value: UntypedExpr::ByteArray {
987                                location: Span::empty(),
988                                bytes: bytes.into_iter().map(|b| (b, Span::empty())).collect(),
989                                preferred_format: ByteArrayFormatPreference::HexadecimalString,
990                            },
991                        }],
992                        fun: Box::new(UntypedExpr::Var {
993                            name: "MillerLoopResult".to_string(),
994                            location: Span::empty(),
995                        }),
996                    })
997                }
998            },
999        )
1000    }
1001
1002    fn reify_blind(data: PlutusData) -> Self {
1003        match data {
1004            PlutusData::BigInt(ref i) => UntypedExpr::UInt {
1005                location: Span::empty(),
1006                base: Base::Decimal {
1007                    numeric_underscore: false,
1008                },
1009                value: from_pallas_bigint(i).to_string(),
1010            },
1011
1012            PlutusData::BoundedBytes(bytes) => {
1013                let bytes: Vec<u8> = bytes.into();
1014
1015                UntypedExpr::ByteArray {
1016                    location: Span::empty(),
1017                    bytes: bytes.into_iter().map(|b| (b, Span::empty())).collect(),
1018                    preferred_format: ByteArrayFormatPreference::HexadecimalString,
1019                }
1020            }
1021
1022            PlutusData::Array(elems) => UntypedExpr::List {
1023                location: Span::empty(),
1024                elements: elems
1025                    .to_vec()
1026                    .into_iter()
1027                    .map(UntypedExpr::reify_blind)
1028                    .collect::<Vec<_>>(),
1029                tail: None,
1030            },
1031
1032            PlutusData::Map(indef_or_def) => {
1033                let kvs = match indef_or_def {
1034                    KeyValuePairs::Def(kvs) => kvs,
1035                    KeyValuePairs::Indef(kvs) => kvs,
1036                };
1037
1038                UntypedExpr::List {
1039                    location: Span::empty(),
1040                    elements: kvs
1041                        .into_iter()
1042                        .map(|(k, v)| UntypedExpr::Pair {
1043                            location: Span::empty(),
1044                            fst: UntypedExpr::reify_blind(k).into(),
1045                            snd: UntypedExpr::reify_blind(v).into(),
1046                        })
1047                        .collect::<Vec<_>>(),
1048                    tail: None,
1049                }
1050            }
1051
1052            PlutusData::Constr(Constr {
1053                tag,
1054                any_constructor,
1055                fields,
1056            }) => {
1057                let ix = convert_tag_to_constr(tag).or(any_constructor).unwrap() as usize;
1058
1059                let fields = fields
1060                    .to_vec()
1061                    .into_iter()
1062                    .map(|field| CallArg {
1063                        location: Span::empty(),
1064                        label: None,
1065                        value: UntypedExpr::reify_blind(field),
1066                    })
1067                    .collect::<Vec<_>>();
1068
1069                let mut arguments = vec![CallArg {
1070                    location: Span::empty(),
1071                    label: None,
1072                    value: UntypedExpr::UInt {
1073                        location: Span::empty(),
1074                        value: ix.to_string(),
1075                        base: Base::Decimal {
1076                            numeric_underscore: false,
1077                        },
1078                    },
1079                }];
1080                arguments.extend(fields);
1081
1082                UntypedExpr::Call {
1083                    location: Span::empty(),
1084                    arguments,
1085                    fun: UntypedExpr::Var {
1086                        name: "Constr".to_string(),
1087                        location: Span::empty(),
1088                    }
1089                    .into(),
1090                }
1091            }
1092        }
1093    }
1094
1095    fn do_reify_data(
1096        generics: &mut IndexMap<u64, Rc<Type>>,
1097        data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
1098        data: PlutusData,
1099        tipo: Rc<Type>,
1100    ) -> Result<Self, String> {
1101        let tipo = Type::collapse_links(tipo);
1102
1103        if let Type::App { name, module, .. } = tipo.deref() {
1104            if module.is_empty() && name == "Data" {
1105                return Ok(Self::reify_blind(data));
1106            }
1107        }
1108
1109        Self::reify_with(
1110            generics,
1111            data_types,
1112            data,
1113            tipo,
1114            |generics, data_types, data, tipo| match data {
1115                PlutusData::BigInt(ref i) => Ok(UntypedExpr::UInt {
1116                    location: Span::empty(),
1117                    base: Base::Decimal {
1118                        numeric_underscore: false,
1119                    },
1120                    value: from_pallas_bigint(i).to_string(),
1121                }),
1122
1123                PlutusData::BoundedBytes(bytes) => {
1124                    if tipo.is_string() {
1125                        Ok(UntypedExpr::String {
1126                            location: Span::empty(),
1127                            value: String::from_utf8(bytes.to_vec()).expect("invalid UTF-8 string"),
1128                        })
1129                    } else {
1130                        let bytes: Vec<u8> = bytes.into();
1131                        Ok(UntypedExpr::ByteArray {
1132                            location: Span::empty(),
1133                            bytes: bytes.into_iter().map(|b| (b, Span::empty())).collect(),
1134                            preferred_format: ByteArrayFormatPreference::HexadecimalString,
1135                        })
1136                    }
1137                }
1138
1139                PlutusData::Array(args) => match tipo.deref() {
1140                    Type::App {
1141                        module,
1142                        name,
1143                        args: type_args,
1144                        ..
1145                    } if module.is_empty() && name.as_str() == "List" => {
1146                        if let [inner] = &type_args[..] {
1147                            Ok(UntypedExpr::List {
1148                                location: Span::empty(),
1149                                elements: args
1150                                    .to_vec()
1151                                    .into_iter()
1152                                    .map(|arg| {
1153                                        UntypedExpr::do_reify_data(
1154                                            generics,
1155                                            data_types,
1156                                            arg,
1157                                            inner.clone(),
1158                                        )
1159                                    })
1160                                    .collect::<Result<Vec<_>, _>>()?,
1161                                tail: None,
1162                            })
1163                        } else {
1164                            Err(
1165                                "invalid List type annotation: the list has multiple type-parameters."
1166                                    .to_string(),
1167                            )
1168                        }
1169                    }
1170                    Type::Tuple { elems, .. } => Ok(UntypedExpr::Tuple {
1171                        location: Span::empty(),
1172                        elems: args
1173                            .to_vec()
1174                            .into_iter()
1175                            .zip(elems)
1176                            .map(|(arg, arg_type)| {
1177                                UntypedExpr::do_reify_data(
1178                                    generics,
1179                                    data_types,
1180                                    arg,
1181                                    arg_type.clone(),
1182                                )
1183                            })
1184                            .collect::<Result<Vec<_>, _>>()?,
1185                    }),
1186                    Type::Pair { fst, snd, .. } => {
1187                        let mut elems = args
1188                            .to_vec()
1189                            .into_iter()
1190                            .zip([fst, snd])
1191                            .map(|(arg, arg_type)| {
1192                                UntypedExpr::do_reify_data(
1193                                    generics,
1194                                    data_types,
1195                                    arg,
1196                                    arg_type.clone(),
1197                                )
1198                            })
1199                            .collect::<Result<Vec<_>, _>>()?;
1200
1201                        Ok(UntypedExpr::Pair {
1202                            location: Span::empty(),
1203                            fst: elems.remove(0).into(),
1204                            snd: elems.remove(0).into(),
1205                        })
1206                    }
1207                    _ => Err(format!(
1208                        "invalid type annotation. expected List but got: {tipo:?}"
1209                    )),
1210                },
1211
1212                PlutusData::Constr(Constr {
1213                    tag,
1214                    any_constructor,
1215                    fields,
1216                }) => {
1217                    let ix = convert_tag_to_constr(tag).or(any_constructor).unwrap() as usize;
1218
1219                    if let Type::App { args, .. } = tipo.deref() {
1220                        if let Some(DataType {
1221                            constructors,
1222                            typed_parameters,
1223                            ..
1224                        }) = lookup_data_type_by_tipo(data_types, &tipo)
1225                        {
1226                            if constructors.is_empty() {
1227                                return Ok(UntypedExpr::Var {
1228                                    location: Span::empty(),
1229                                    name: "Data".to_string(),
1230                                });
1231                            }
1232
1233                            let constructor = &constructors[ix];
1234
1235                            typed_parameters
1236                                .iter()
1237                                .zip(args)
1238                                .for_each(|(generic, arg)| {
1239                                    if let Some(ix) = generic.get_generic_id() {
1240                                        if !generics.contains_key(&ix) {
1241                                            generics.insert(ix, arg.clone());
1242                                        }
1243                                    }
1244                                });
1245
1246                            return if fields.is_empty() {
1247                                Ok(UntypedExpr::Var {
1248                                    location: Span::empty(),
1249                                    name: constructor.name.to_string(),
1250                                })
1251                            } else {
1252                                let arguments = fields
1253                                    .to_vec()
1254                                    .into_iter()
1255                                    .zip(constructor.arguments.iter())
1256                                    .map(|(field, RecordConstructorArg { label, tipo, .. })| {
1257                                        UntypedExpr::do_reify_data(
1258                                            generics,
1259                                            data_types,
1260                                            field,
1261                                            tipo.clone(),
1262                                        )
1263                                        .map(|value| {
1264                                            CallArg {
1265                                                label: label.clone(),
1266                                                location: Span::empty(),
1267                                                value,
1268                                            }
1269                                        })
1270                                    })
1271                                    .collect::<Result<Vec<_>, _>>()?;
1272
1273                                Ok(UntypedExpr::Call {
1274                                    location: Span::empty(),
1275                                    arguments,
1276                                    fun: Box::new(UntypedExpr::Var {
1277                                        name: constructor.name.to_string(),
1278                                        location: Span::empty(),
1279                                    }),
1280                                })
1281                            };
1282                        }
1283                    }
1284
1285                    Err(format!(
1286                        "invalid type annotation {tipo:?} for {}{} constructor with fields: {fields:?}",
1287                        ix + 1,
1288                        ordinal::Ordinal::<usize>(ix + 1).suffix(),
1289                    ))
1290                }
1291
1292                PlutusData::Map(indef_or_def) => {
1293                    let kvs = match indef_or_def {
1294                        KeyValuePairs::Def(kvs) => kvs,
1295                        KeyValuePairs::Indef(kvs) => kvs,
1296                    };
1297
1298                    UntypedExpr::do_reify_data(
1299                        generics,
1300                        data_types,
1301                        Data::list(
1302                            kvs.into_iter()
1303                                .map(|(k, v)| Data::list(vec![k, v]))
1304                                .collect(),
1305                        ),
1306                        tipo,
1307                    )
1308                }
1309            },
1310        )
1311    }
1312
1313    pub fn todo(reason: Option<Self>, location: Span) -> Self {
1314        UntypedExpr::Trace {
1315            location,
1316            kind: TraceKind::Todo,
1317            then: Box::new(UntypedExpr::ErrorTerm { location }),
1318            label: Box::new(reason.unwrap_or_else(|| UntypedExpr::String {
1319                location,
1320                value: DEFAULT_TODO_STR.to_string(),
1321            })),
1322            arguments: Vec::new(),
1323        }
1324    }
1325
1326    pub fn fail(reason: Option<Self>, location: Span) -> Self {
1327        if let Some(reason) = reason {
1328            UntypedExpr::Trace {
1329                location,
1330                kind: TraceKind::Error,
1331                then: Box::new(UntypedExpr::ErrorTerm { location }),
1332                label: Box::new(reason),
1333                arguments: Vec::new(),
1334            }
1335        } else {
1336            UntypedExpr::ErrorTerm { location }
1337        }
1338    }
1339
1340    pub fn tuple_index(self, index: usize, location: Span) -> Self {
1341        UntypedExpr::TupleIndex {
1342            location: self.location().union(location),
1343            index,
1344            tuple: Box::new(self),
1345        }
1346    }
1347
1348    pub fn field_access(self, label: String, location: Span) -> Self {
1349        UntypedExpr::FieldAccess {
1350            location: self.location().union(location),
1351            label,
1352            container: Box::new(self),
1353        }
1354    }
1355
1356    pub fn call(self, args: Vec<ParsedCallArg>, location: Span) -> Self {
1357        let mut holes = Vec::new();
1358
1359        let args = args
1360            .into_iter()
1361            .enumerate()
1362            .map(|(index, a)| match a {
1363                CallArg {
1364                    value: Some(value),
1365                    label,
1366                    location,
1367                } if !value.is_discard() => CallArg {
1368                    value,
1369                    label,
1370                    location,
1371                },
1372                CallArg {
1373                    value,
1374                    label,
1375                    location,
1376                } => {
1377                    let name = format!(
1378                        "{}__{index}_{}",
1379                        ast::CAPTURE_VARIABLE,
1380                        match value {
1381                            Some(UntypedExpr::Var { ref name, .. }) => name,
1382                            _ => "_",
1383                        }
1384                    );
1385
1386                    holes.push(ast::UntypedArg {
1387                        location: Span::empty(),
1388                        annotation: None,
1389                        doc: None,
1390                        by: ArgBy::ByName(ast::ArgName::Named {
1391                            label: name.clone(),
1392                            name: name.clone(),
1393                            location: Span::empty(),
1394                        }),
1395                        is_validator_param: false,
1396                    });
1397
1398                    ast::CallArg {
1399                        label,
1400                        location,
1401                        value: UntypedExpr::Var { location, name },
1402                    }
1403                }
1404            })
1405            .collect();
1406
1407        let call = UntypedExpr::Call {
1408            location: self.location().union(location),
1409            fun: Box::new(self),
1410            arguments: args,
1411        };
1412
1413        if holes.is_empty() {
1414            call
1415        } else {
1416            UntypedExpr::Fn {
1417                location: call.location(),
1418                fn_style: FnStyle::Capture,
1419                arguments: holes,
1420                body: Box::new(call),
1421                return_annotation: None,
1422            }
1423        }
1424    }
1425
1426    pub fn append_in_sequence(self, next: Self) -> Self {
1427        let location = Span {
1428            start: self.location().start,
1429            end: next.location().end,
1430        };
1431
1432        match (self.clone(), next.clone()) {
1433            (left @ Self::Sequence { .. }, right @ Self::Sequence { .. }) => Self::Sequence {
1434                location,
1435                expressions: vec![left, right],
1436            },
1437            (
1438                _,
1439                Self::Sequence {
1440                    expressions: mut next_expressions,
1441                    ..
1442                },
1443            ) => {
1444                let mut current_expressions = vec![self];
1445
1446                current_expressions.append(&mut next_expressions);
1447
1448                Self::Sequence {
1449                    location,
1450                    expressions: current_expressions,
1451                }
1452            }
1453
1454            (_, _) => Self::Sequence {
1455                location,
1456                expressions: vec![self, next],
1457            },
1458        }
1459    }
1460
1461    pub fn location(&self) -> Span {
1462        match self {
1463            Self::PipeLine { expressions, .. } => expressions.last().location(),
1464            Self::Trace { then, .. } => then.location(),
1465            Self::TraceIfFalse { location, .. }
1466            | Self::Fn { location, .. }
1467            | Self::Var { location, .. }
1468            | Self::UInt { location, .. }
1469            | Self::ErrorTerm { location, .. }
1470            | Self::When { location, .. }
1471            | Self::Call { location, .. }
1472            | Self::List { location, .. }
1473            | Self::ByteArray { location, .. }
1474            | Self::BinOp { location, .. }
1475            | Self::Tuple { location, .. }
1476            | Self::Pair { location, .. }
1477            | Self::String { location, .. }
1478            | Self::Assignment { location, .. }
1479            | Self::TupleIndex { location, .. }
1480            | Self::FieldAccess { location, .. }
1481            | Self::RecordUpdate { location, .. }
1482            | Self::UnOp { location, .. }
1483            | Self::LogicalOpChain { location, .. }
1484            | Self::If { location, .. }
1485            | Self::CurvePoint { location, .. } => *location,
1486            Self::Sequence {
1487                location,
1488                expressions,
1489                ..
1490            } => expressions.last().map(Self::location).unwrap_or(*location),
1491        }
1492    }
1493
1494    pub fn start_byte_index(&self) -> usize {
1495        match self {
1496            Self::Sequence {
1497                expressions,
1498                location,
1499                ..
1500            } => expressions
1501                .first()
1502                .map(|e| e.start_byte_index())
1503                .unwrap_or(location.start),
1504            Self::PipeLine { expressions, .. } => expressions.first().start_byte_index(),
1505            Self::Trace { location, .. } | Self::Assignment { location, .. } => location.start,
1506            _ => self.location().start,
1507        }
1508    }
1509
1510    pub fn binop_precedence(&self) -> u8 {
1511        match self {
1512            Self::BinOp { name, .. } => name.precedence(),
1513            Self::PipeLine { .. } => 0,
1514            _ => u8::MAX,
1515        }
1516    }
1517
1518    /// Returns true when an UntypedExpr can be displayed in a flex-break manner (i.e. tries to fit as
1519    /// much as possible on a single line). When false, long lines with several of those patterns
1520    /// will be broken down to one expr per line.
1521    pub fn is_simple_expr_to_format(&self) -> bool {
1522        match self {
1523            Self::String { .. } | Self::UInt { .. } | Self::ByteArray { .. } | Self::Var { .. } => {
1524                true
1525            }
1526            Self::Pair { fst, snd, .. } => {
1527                fst.is_simple_expr_to_format() && snd.is_simple_expr_to_format()
1528            }
1529            Self::Tuple { elems, .. } => elems.iter().all(|e| e.is_simple_expr_to_format()),
1530            Self::List { elements, .. } if elements.len() <= 3 => {
1531                elements.iter().all(|e| e.is_simple_expr_to_format())
1532            }
1533            _ => false,
1534        }
1535    }
1536
1537    pub fn lambda(
1538        names: Vec<(ArgName, Span, Option<Annotation>)>,
1539        expressions: Vec<UntypedExpr>,
1540        location: Span,
1541    ) -> Self {
1542        Self::Fn {
1543            location,
1544            fn_style: FnStyle::Plain,
1545            arguments: names
1546                .into_iter()
1547                .map(|(arg_name, location, annotation)| UntypedArg {
1548                    location,
1549                    doc: None,
1550                    annotation,
1551                    is_validator_param: false,
1552                    by: ArgBy::ByName(arg_name),
1553                })
1554                .collect(),
1555            body: Self::Sequence {
1556                location,
1557                expressions,
1558            }
1559            .into(),
1560            return_annotation: None,
1561        }
1562    }
1563}