aiken_lang/
ast.rs

1pub mod well_known;
2
3use crate::{
4    ast::well_known::VALIDATOR_ELSE,
5    expr::{TypedExpr, UntypedExpr},
6    line_numbers::LineNumbers,
7    parser::token::{Base, Token},
8    tipo::{PatternConstructor, Type, TypeInfo},
9};
10use indexmap::IndexMap;
11use miette::Diagnostic;
12use ordinal::Ordinal;
13use owo_colors::{OwoColorize, Stream::Stdout};
14use std::{
15    fmt::{self, Display},
16    ops::Range,
17    rc::Rc,
18};
19use uplc::machine::runtime::Compressable;
20use vec1::{Vec1, vec1};
21
22pub const BACKPASS_VARIABLE: &str = "_backpass";
23pub const CAPTURE_VARIABLE: &str = "_capture";
24pub const PIPE_VARIABLE: &str = "_pipe";
25
26pub const ENV_MODULE: &str = "env";
27pub const CONFIG_MODULE: &str = "config";
28pub const DEFAULT_ENV_MODULE: &str = "default";
29
30pub const HANDLER_SPEND: &str = "spend";
31pub const HANDLER_MINT: &str = "mint";
32pub const HANDLER_WITHDRAW: &str = "withdraw";
33pub const HANDLER_PUBLISH: &str = "publish";
34pub const HANDLER_VOTE: &str = "vote";
35pub const HANDLER_PROPOSE: &str = "propose";
36
37pub type TypedModule = Module<TypeInfo, TypedDefinition>;
38pub type UntypedModule = Module<(), UntypedDefinition>;
39
40#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
41pub enum ModuleKind {
42    Lib,
43    Validator,
44    Env,
45    Config,
46}
47
48impl ModuleKind {
49    pub fn is_validator(&self) -> bool {
50        matches!(self, ModuleKind::Validator)
51    }
52
53    pub fn is_lib(&self) -> bool {
54        matches!(self, ModuleKind::Lib)
55    }
56
57    pub fn is_env(&self) -> bool {
58        matches!(self, ModuleKind::Env)
59    }
60
61    pub fn is_config(&self) -> bool {
62        matches!(self, ModuleKind::Config)
63    }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
67pub struct Module<Info, Definitions> {
68    pub name: String,
69    pub docs: Vec<String>,
70    pub type_info: Info,
71    pub definitions: Vec<Definitions>,
72    pub lines: LineNumbers,
73    pub kind: ModuleKind,
74}
75
76impl<Info, Definitions> Module<Info, Definitions> {
77    pub fn definitions(&self) -> impl Iterator<Item = &Definitions> {
78        self.definitions.iter()
79    }
80
81    pub fn into_definitions(self) -> impl Iterator<Item = Definitions> {
82        self.definitions.into_iter()
83    }
84}
85
86impl UntypedModule {
87    pub fn dependencies(&self, env_modules: &[String]) -> Vec<String> {
88        self.definitions()
89            .flat_map(|def| {
90                if let Definition::Use(Use { module, .. }) = def {
91                    let name = module.join("/");
92                    if name == ENV_MODULE {
93                        env_modules.to_vec()
94                    } else {
95                        vec![name]
96                    }
97                } else {
98                    Vec::new()
99                }
100            })
101            .collect()
102    }
103}
104
105impl TypedModule {
106    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
107        self.definitions
108            .iter()
109            .find_map(|definition| definition.find_node(byte_index))
110    }
111
112    pub fn has_definition(&self, name: &str) -> bool {
113        self.definitions.iter().any(|def| match def {
114            Definition::Fn(f) => f.public && f.name == name,
115            Definition::TypeAlias(alias) => alias.public && alias.alias == name,
116            Definition::ModuleConstant(cst) => cst.public && cst.name == name,
117            Definition::DataType(t) => t.public && t.name == name,
118            Definition::Use(_) => false,
119            Definition::Test(_) => false,
120            Definition::Validator(_) => false,
121            Definition::Benchmark(_) => false,
122        })
123    }
124
125    pub fn has_constructor(&self, name: &str) -> bool {
126        self.definitions.iter().any(|def| match def {
127            Definition::DataType(t) if t.public && !t.opaque => t
128                .constructors
129                .iter()
130                .any(|constructor| constructor.name == name),
131            Definition::DataType(_) => false,
132            Definition::Fn(_) => false,
133            Definition::TypeAlias(_) => false,
134            Definition::ModuleConstant(_) => false,
135            Definition::Use(_) => false,
136            Definition::Test(_) => false,
137            Definition::Validator(_) => false,
138            Definition::Benchmark(_) => false,
139        })
140    }
141
142    pub fn validate_module_name(&self) -> Result<(), Error> {
143        if self.name == "aiken" || self.name == "aiken/builtin" {
144            return Err(Error::ReservedModuleName {
145                name: self.name.to_string(),
146            });
147        };
148
149        for segment in self.name.split('/') {
150            if str_to_keyword(segment).is_some() {
151                return Err(Error::KeywordInModuleName {
152                    name: self.name.to_string(),
153                    keyword: segment.to_string(),
154                });
155            }
156        }
157
158        Ok(())
159    }
160
161    // TODO: Avoid cloning definitions here. This would likely require having a lifetime on
162    // 'Project', so that we can enforce that those references live from the ast to here.
163    pub fn register_definitions(
164        &self,
165        functions: &mut IndexMap<FunctionAccessKey, TypedFunction>,
166        constants: &mut IndexMap<FunctionAccessKey, TypedExpr>,
167        data_types: &mut IndexMap<DataTypeKey, TypedDataType>,
168    ) {
169        for def in self.definitions() {
170            match def {
171                Definition::Fn(func) => {
172                    functions.insert(
173                        FunctionAccessKey {
174                            module_name: self.name.clone(),
175                            function_name: func.name.clone(),
176                        },
177                        func.clone(),
178                    );
179                }
180
181                Definition::Test(test) => {
182                    functions.insert(
183                        FunctionAccessKey {
184                            module_name: self.name.clone(),
185                            function_name: test.name.clone(),
186                        },
187                        test.clone().into(),
188                    );
189                }
190
191                Definition::Benchmark(benchmark) => {
192                    functions.insert(
193                        FunctionAccessKey {
194                            module_name: self.name.clone(),
195                            function_name: benchmark.name.clone(),
196                        },
197                        benchmark.clone().into(),
198                    );
199                }
200
201                Definition::DataType(dt) => {
202                    data_types.insert(
203                        DataTypeKey {
204                            module_name: self.name.clone(),
205                            defined_type: dt.name.clone(),
206                        },
207                        dt.clone(),
208                    );
209                }
210
211                Definition::Validator(v) => {
212                    let module_name = self.name.as_str();
213
214                    for (k, v) in v.into_function_definitions(module_name) {
215                        functions.insert(k, v);
216                    }
217                }
218
219                Definition::ModuleConstant(ModuleConstant { name, value, .. }) => {
220                    constants.insert(
221                        FunctionAccessKey {
222                            module_name: self.name.clone(),
223                            function_name: name.clone(),
224                        },
225                        value.clone(),
226                    );
227                }
228
229                Definition::TypeAlias(_) | Definition::Use(_) => {}
230            }
231        }
232    }
233}
234
235fn str_to_keyword(word: &str) -> Option<Token> {
236    // Alphabetical keywords:
237    match word {
238        "expect" => Some(Token::Expect),
239        "else" => Some(Token::Else),
240        "is" => Some(Token::Is),
241        "as" => Some(Token::As),
242        "when" => Some(Token::When),
243        "const" => Some(Token::Const),
244        "fn" => Some(Token::Fn),
245        "if" => Some(Token::If),
246        "use" => Some(Token::Use),
247        "let" => Some(Token::Let),
248        "opaque" => Some(Token::Opaque),
249        "pub" => Some(Token::Pub),
250        "todo" => Some(Token::Todo),
251        "type" => Some(Token::Type),
252        "trace" => Some(Token::Trace),
253        "test" => Some(Token::Test),
254        // TODO: remove this in a future release
255        "error" => Some(Token::Fail),
256        "fail" => Some(Token::Fail),
257        "and" => Some(Token::And),
258        "or" => Some(Token::Or),
259        "validator" => Some(Token::Validator),
260        "via" => Some(Token::Via),
261        "bench" => Some(Token::Benchmark),
262        _ => None,
263    }
264}
265
266pub type TypedFunction = Function<Rc<Type>, TypedExpr, TypedArg>;
267pub type UntypedFunction = Function<(), UntypedExpr, UntypedArg>;
268
269impl UntypedFunction {
270    pub fn is_default_fallback(&self) -> bool {
271        matches!(
272            &self.arguments[..],
273            [UntypedArg {
274                by: ArgBy::ByName(ArgName::Discarded { .. }),
275                ..
276            }]
277        ) && matches!(&self.body, UntypedExpr::ErrorTerm { .. })
278            && self.name.as_str() == well_known::VALIDATOR_ELSE
279    }
280}
281
282pub type TypedTest = Function<Rc<Type>, TypedExpr, TypedArgVia>;
283pub type UntypedTest = Function<(), UntypedExpr, UntypedArgVia>;
284
285#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
286pub enum OnTestFailure {
287    FailImmediately,
288    SucceedImmediately,
289    SucceedEventually,
290}
291
292#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
293pub struct Function<T, Expr, Arg> {
294    pub arguments: Vec<Arg>,
295    pub body: Expr,
296    pub doc: Option<String>,
297    pub location: Span,
298    pub name: String,
299    pub public: bool,
300    pub return_annotation: Option<Annotation>,
301    pub return_type: T,
302    pub end_position: usize,
303    pub on_test_failure: OnTestFailure,
304}
305
306impl<T, Expr, Arg> Function<T, Expr, Arg> {
307    pub fn is_spend(&self) -> bool {
308        self.name == HANDLER_SPEND
309    }
310
311    pub fn is_mint(&self) -> bool {
312        self.name == HANDLER_MINT
313    }
314}
315
316impl TypedFunction {
317    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
318        self.arguments
319            .iter()
320            .find_map(|arg| arg.find_node(byte_index))
321            .or_else(|| self.body.find_node(byte_index))
322            .or_else(|| {
323                self.return_annotation
324                    .as_ref()
325                    .and_then(|a| a.find_node(byte_index))
326            })
327    }
328
329    pub fn has_valid_purpose_name(&self) -> bool {
330        self.name == HANDLER_SPEND
331            || self.name == HANDLER_PUBLISH
332            || self.name == HANDLER_PROPOSE
333            || self.name == HANDLER_MINT
334            || self.name == HANDLER_WITHDRAW
335            || self.name == HANDLER_VOTE
336    }
337
338    pub fn validator_arity(&self) -> usize {
339        if self.name == HANDLER_SPEND {
340            4
341        } else if self.name == HANDLER_MINT
342            || self.name == HANDLER_WITHDRAW
343            || self.name == HANDLER_VOTE
344            || self.name == HANDLER_PUBLISH
345            || self.name == HANDLER_PROPOSE
346        {
347            3
348        } else {
349            panic!(
350                "tried to get validator arity of a non-validator function {}",
351                &self.name
352            );
353        }
354    }
355}
356
357impl TypedTest {
358    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
359        self.arguments
360            .iter()
361            .find_map(|arg| arg.find_node(byte_index))
362            .or_else(|| self.body.find_node(byte_index))
363            .or_else(|| {
364                self.return_annotation
365                    .as_ref()
366                    .and_then(|a| a.find_node(byte_index))
367            })
368    }
369}
370
371pub type TypedTypeAlias = TypeAlias<Rc<Type>>;
372pub type UntypedTypeAlias = TypeAlias<()>;
373
374impl From<UntypedTest> for UntypedFunction {
375    fn from(f: UntypedTest) -> Self {
376        Function {
377            doc: f.doc,
378            location: f.location,
379            name: f.name,
380            public: f.public,
381            arguments: f.arguments.into_iter().map(|arg| arg.into()).collect(),
382            return_annotation: f.return_annotation,
383            return_type: f.return_type,
384            body: f.body,
385            on_test_failure: f.on_test_failure,
386            end_position: f.end_position,
387        }
388    }
389}
390
391impl From<TypedTest> for TypedFunction {
392    fn from(f: TypedTest) -> Self {
393        Function {
394            doc: f.doc,
395            location: f.location,
396            name: f.name,
397            public: f.public,
398            arguments: f.arguments.into_iter().map(|arg| arg.into()).collect(),
399            return_annotation: f.return_annotation,
400            return_type: f.return_type,
401            body: f.body,
402            on_test_failure: f.on_test_failure,
403            end_position: f.end_position,
404        }
405    }
406}
407
408#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
409pub struct TypeAlias<T> {
410    pub alias: String,
411    pub annotation: Annotation,
412    pub doc: Option<String>,
413    pub location: Span,
414    pub parameters: Vec<String>,
415    pub public: bool,
416    pub tipo: T,
417}
418
419#[derive(Clone, Debug, Eq, PartialEq, Hash)]
420pub struct DataTypeKey {
421    pub module_name: String,
422    pub defined_type: String,
423}
424
425#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
426pub struct FunctionAccessKey {
427    pub module_name: String,
428    pub function_name: String,
429}
430
431pub type UntypedDataType = DataType<()>;
432pub type TypedDataType = DataType<Rc<Type>>;
433
434impl TypedDataType {
435    pub fn known_enum(name: &str, constructors: &[&str]) -> Self {
436        Self::known_data_type(name, &RecordConstructor::known_enum(constructors))
437    }
438
439    pub fn known_data_type(name: &str, constructors: &[RecordConstructor<Rc<Type>>]) -> Self {
440        Self {
441            decorators: vec![],
442            name: name.to_string(),
443            constructors: constructors.to_vec(),
444            location: Span::empty(),
445            opaque: false,
446            public: true,
447            parameters: vec![],
448            typed_parameters: vec![],
449            doc: None,
450        }
451    }
452
453    pub fn is_never(&self) -> bool {
454        self.name == well_known::NEVER
455            && self.constructors.len() == well_known::NEVER_CONSTRUCTORS.len()
456            && self.location == Span::empty()
457            && self
458                .constructors
459                .iter()
460                .zip(well_known::NEVER_CONSTRUCTORS)
461                .all(|(constructor, name)| {
462                    name == &constructor.name && constructor.arguments.is_empty()
463                })
464    }
465}
466
467#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
468pub struct Decorator {
469    pub kind: DecoratorKind,
470    pub location: Span,
471}
472
473#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
474pub enum DecoratorKind {
475    Tag { value: String, base: Base },
476    List,
477}
478
479#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
480pub struct DataType<T> {
481    pub decorators: Vec<Decorator>,
482    pub constructors: Vec<RecordConstructor<T>>,
483    pub doc: Option<String>,
484    pub location: Span,
485    pub name: String,
486    pub opaque: bool,
487    pub parameters: Vec<String>,
488    pub public: bool,
489    pub typed_parameters: Vec<T>,
490}
491
492pub type TypedUse = Use<String>;
493pub type UntypedUse = Use<()>;
494
495#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
496pub struct Use<PackageName> {
497    pub as_name: Option<String>,
498    pub location: Span,
499    pub module: Vec<String>,
500    pub package: PackageName,
501    pub unqualified: (usize, Vec<UnqualifiedImport>),
502}
503
504pub type TypedModuleConstant = ModuleConstant<TypedExpr>;
505pub type UntypedModuleConstant = ModuleConstant<UntypedExpr>;
506
507#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
508pub struct ModuleConstant<Expr> {
509    pub doc: Option<String>,
510    pub location: Span,
511    pub public: bool,
512    pub name: String,
513    pub annotation: Option<Annotation>,
514    pub value: Expr,
515}
516
517pub type TypedValidator = Validator<Rc<Type>, TypedArg, TypedExpr>;
518pub type UntypedValidator = Validator<(), UntypedArg, UntypedExpr>;
519
520#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
521pub enum Purpose {
522    Spend,
523    Mint,
524    Withdraw,
525    Publish,
526    Propose,
527    Vote,
528}
529
530#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
531pub struct Validator<T, Arg, Expr> {
532    pub doc: Option<String>,
533    pub end_position: usize,
534    pub handlers: Vec<Function<T, Expr, Arg>>,
535    pub location: Span,
536    pub name: String,
537    pub params: Vec<Arg>,
538    pub fallback: Function<T, Expr, Arg>,
539}
540
541impl<T, Arg, Expr> Validator<T, Arg, Expr> {
542    pub fn handler_name(validator: &str, handler: &str) -> String {
543        format!("{validator}.{handler}")
544    }
545}
546
547impl UntypedValidator {
548    pub fn default_fallback(location: Span) -> UntypedFunction {
549        Function {
550            arguments: vec![UntypedArg {
551                by: ArgBy::ByName(ArgName::Discarded {
552                    name: "_".to_string(),
553                    label: "_".to_string(),
554                    location,
555                }),
556                location,
557                annotation: None,
558                doc: None,
559                is_validator_param: false,
560            }],
561            body: UntypedExpr::fail(None, location),
562            doc: None,
563            location,
564            end_position: location.end - 1,
565            name: well_known::VALIDATOR_ELSE.to_string(),
566            public: true,
567            return_annotation: Some(Annotation::boolean(location)),
568            return_type: (),
569            on_test_failure: OnTestFailure::FailImmediately,
570        }
571    }
572}
573
574impl TypedValidator {
575    pub fn available_handler_names() -> Vec<String> {
576        vec![
577            HANDLER_SPEND.to_string(),
578            HANDLER_MINT.to_string(),
579            HANDLER_WITHDRAW.to_string(),
580            HANDLER_PUBLISH.to_string(),
581            HANDLER_VOTE.to_string(),
582            HANDLER_PROPOSE.to_string(),
583            VALIDATOR_ELSE.to_string(),
584        ]
585    }
586
587    // Define a validator wrapper extracting and matching on script purpose for
588    // users.
589    pub fn into_script_context_handler(&self) -> TypedExpr {
590        let var_context = "__context__";
591        let var_transaction = "__transaction__";
592        let var_redeemer = "__redeemer__";
593        let var_purpose = "__purpose__";
594        let var_purpose_arg = "__purpose_arg__";
595        let var_datum = "__datum__";
596
597        let context_handler = TypedExpr::sequence(&[
598            TypedExpr::let_(
599                TypedExpr::local_var(var_context, Type::script_context(), self.location),
600                TypedPattern::Constructor {
601                    is_record: false,
602                    location: Span::empty(),
603                    name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(),
604                    arguments: vec![
605                        CallArg::var(var_transaction, Span::empty()),
606                        CallArg::var(var_redeemer, Span::empty()),
607                        CallArg::var(var_purpose, Span::empty()),
608                    ],
609                    module: None,
610                    constructor: PatternConstructor::Record {
611                        name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(),
612                        field_map: None,
613                    },
614                    spread_location: None,
615                    tipo: Type::function(
616                        vec![Type::data(), Type::data(), Type::script_purpose()],
617                        Type::data(),
618                    ),
619                },
620                Type::script_context(),
621                Span::empty(),
622            ),
623            TypedExpr::When {
624                location: Span::empty(),
625                tipo: Type::bool(),
626                subject: TypedExpr::local_var(var_purpose, Type::script_purpose(), Span::empty())
627                    .into(),
628                clauses: self
629                    .handlers
630                    .iter()
631                    .map(|handler| {
632                        let datum = if handler.name.as_str() == "spend" {
633                            handler.arguments.first()
634                        } else {
635                            None
636                        };
637
638                        let redeemer = handler
639                            .arguments
640                            .get(if datum.is_some() { 1 } else { 0 })
641                            .unwrap();
642
643                        let purpose_arg = handler.arguments.iter().nth_back(1).unwrap();
644
645                        let transaction = handler.arguments.last().unwrap();
646
647                        let pattern = match handler.name.as_str() {
648                            "spend" => TypedPattern::spend_purpose(
649                                (var_purpose_arg, purpose_arg.location),
650                                (
651                                    var_datum,
652                                    datum.map(|x| x.location).unwrap_or(Span::empty()),
653                                ),
654                                redeemer.location,
655                            ),
656                            "mint" => TypedPattern::mint_purpose(
657                                (var_purpose_arg, purpose_arg.location),
658                                redeemer.location,
659                            ),
660                            "withdraw" => TypedPattern::withdraw_purpose(
661                                (var_purpose_arg, purpose_arg.location),
662                                redeemer.location,
663                            ),
664                            "publish" => TypedPattern::publish_purpose(
665                                (var_purpose_arg, purpose_arg.location),
666                                redeemer.location,
667                            ),
668                            "propose" => TypedPattern::propose_purpose(
669                                (var_purpose_arg, purpose_arg.location),
670                                redeemer.location,
671                            ),
672                            "vote" => TypedPattern::vote_purpose(
673                                (var_purpose_arg, purpose_arg.location),
674                                redeemer.location,
675                            ),
676                            purpose => {
677                                unreachable!("unexpected/unknown purpose: {:?}", purpose)
678                            }
679                        };
680
681                        let mut then = vec![];
682
683                        // expect redeemer: tipo = __redeemer__
684                        then.push(TypedExpr::flexible_expect(
685                            TypedExpr::local_var(var_redeemer, Type::data(), redeemer.location),
686                            TypedPattern::var(redeemer.get_variable_name().unwrap_or("_")),
687                            redeemer.tipo.clone(),
688                            redeemer.location,
689                        ));
690
691                        // Cast the datum, if any
692                        if let Some(datum) = datum {
693                            // expect datum: tipo = __datum__
694                            then.push(TypedExpr::flexible_expect(
695                                TypedExpr::local_var(
696                                    var_datum,
697                                    Type::option(Type::data()),
698                                    datum.location,
699                                ),
700                                TypedPattern::var(datum.get_variable_name().unwrap_or("_")),
701                                datum.tipo.clone(),
702                                datum.location,
703                            ))
704                        }
705
706                        // let purpose_arg = __purpose_arg__
707                        if let Some(arg_name) = purpose_arg.get_variable_name() {
708                            then.push(TypedExpr::let_(
709                                TypedExpr::local_var(
710                                    var_purpose_arg,
711                                    Type::data(),
712                                    purpose_arg.location,
713                                ),
714                                TypedPattern::var(arg_name),
715                                purpose_arg.tipo.clone(),
716                                purpose_arg.location,
717                            ));
718                        }
719
720                        // let last_arg_name = __transaction__
721                        if let Some(arg_name) = transaction.get_variable_name() {
722                            then.push(TypedExpr::let_(
723                                TypedExpr::local_var(
724                                    var_transaction,
725                                    Type::data(),
726                                    transaction.location,
727                                ),
728                                TypedPattern::var(arg_name),
729                                Type::data(),
730                                transaction.location,
731                            ));
732                        }
733
734                        then.push(handler.body.clone());
735
736                        TypedClause {
737                            location: Span::empty(),
738                            pattern,
739                            then: TypedExpr::Sequence {
740                                location: Span::empty(),
741                                expressions: then,
742                            },
743                        }
744                    })
745                    .chain(std::iter::once(&self.fallback).map(|fallback| {
746                        let arg = fallback.arguments.first().unwrap();
747
748                        let then = match arg.get_variable_name() {
749                            Some(arg_name) => TypedExpr::sequence(&[
750                                TypedExpr::let_(
751                                    TypedExpr::local_var(
752                                        var_context,
753                                        arg.tipo.clone(),
754                                        arg.location,
755                                    ),
756                                    TypedPattern::var(arg_name),
757                                    arg.tipo.clone(),
758                                    arg.location,
759                                ),
760                                fallback.body.clone(),
761                            ]),
762                            None => fallback.body.clone(),
763                        };
764
765                        TypedClause {
766                            location: Span::empty(),
767                            pattern: TypedPattern::Discard {
768                                name: "_".to_string(),
769                                location: arg.location,
770                            },
771                            then,
772                        }
773                    }))
774                    .collect(),
775            },
776        ]);
777
778        if self.handlers.is_empty() {
779            let fallback = &self.fallback;
780            let arg = fallback.arguments.first().unwrap();
781
782            match arg.get_variable_name() {
783                Some(arg_name) => TypedExpr::sequence(&[
784                    TypedExpr::let_(
785                        TypedExpr::local_var(var_context, arg.tipo.clone(), arg.location),
786                        TypedPattern::var(arg_name),
787                        arg.tipo.clone(),
788                        arg.location,
789                    ),
790                    fallback.body.clone(),
791                ]),
792                None => fallback.body.clone(),
793            }
794        } else {
795            context_handler
796        }
797    }
798
799    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
800        self.params
801            .iter()
802            .find_map(|arg| arg.find_node(byte_index))
803            .or_else(|| {
804                self.handlers
805                    .iter()
806                    .find_map(|func| func.find_node(byte_index))
807            })
808            .or_else(|| self.fallback.find_node(byte_index))
809    }
810
811    pub fn into_function_definitions(
812        &self,
813        module_name: &str,
814    ) -> Vec<(FunctionAccessKey, TypedFunction)> {
815        self.handlers
816            .iter()
817            .chain(std::iter::once(&self.fallback))
818            .map(|handler| {
819                let mut handler = handler.clone();
820
821                handler.arguments = self
822                    .params
823                    .clone()
824                    .into_iter()
825                    .chain(handler.arguments)
826                    .collect();
827
828                (
829                    FunctionAccessKey {
830                        module_name: module_name.to_string(),
831                        function_name: TypedValidator::handler_name(
832                            self.name.as_str(),
833                            handler.name.as_str(),
834                        ),
835                    },
836                    handler,
837                )
838            })
839            .collect()
840    }
841}
842
843pub type TypedDefinition = Definition<Rc<Type>, TypedArg, TypedExpr, String>;
844pub type UntypedDefinition = Definition<(), UntypedArg, UntypedExpr, ()>;
845
846#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
847pub enum Definition<T, Arg, Expr, PackageName> {
848    Fn(Function<T, Expr, Arg>),
849
850    TypeAlias(TypeAlias<T>),
851
852    DataType(DataType<T>),
853
854    Use(Use<PackageName>),
855
856    ModuleConstant(ModuleConstant<Expr>),
857
858    Test(Function<T, Expr, ArgVia<Arg, Expr>>),
859
860    Benchmark(Function<T, Expr, ArgVia<Arg, Expr>>),
861
862    Validator(Validator<T, Arg, Expr>),
863}
864
865impl<A, B, C, D> Definition<A, B, C, D> {
866    pub fn location(&self) -> Span {
867        match self {
868            Definition::Fn(Function { location, .. })
869            | Definition::Use(Use { location, .. })
870            | Definition::TypeAlias(TypeAlias { location, .. })
871            | Definition::DataType(DataType { location, .. })
872            | Definition::ModuleConstant(ModuleConstant { location, .. })
873            | Definition::Validator(Validator { location, .. })
874            | Definition::Benchmark(Function { location, .. })
875            | Definition::Test(Function { location, .. }) => *location,
876        }
877    }
878
879    pub fn put_doc(&mut self, new_doc: String) {
880        match self {
881            Definition::Use { .. } => (),
882            Definition::Fn(Function { doc, .. })
883            | Definition::TypeAlias(TypeAlias { doc, .. })
884            | Definition::DataType(DataType { doc, .. })
885            | Definition::ModuleConstant(ModuleConstant { doc, .. })
886            | Definition::Validator(Validator { doc, .. })
887            | Definition::Benchmark(Function { doc, .. })
888            | Definition::Test(Function { doc, .. }) => {
889                let _ = doc.replace(new_doc);
890            }
891        }
892    }
893
894    pub fn doc(&self) -> Option<String> {
895        match self {
896            Definition::Use { .. } => None,
897            Definition::Fn(Function { doc, .. })
898            | Definition::TypeAlias(TypeAlias { doc, .. })
899            | Definition::DataType(DataType { doc, .. })
900            | Definition::ModuleConstant(ModuleConstant { doc, .. })
901            | Definition::Validator(Validator { doc, .. })
902            | Definition::Benchmark(Function { doc, .. })
903            | Definition::Test(Function { doc, .. }) => doc.clone(),
904        }
905    }
906}
907
908impl TypedDefinition {
909    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
910        // Note that the fn span covers the function head, not
911        // the entire statement.
912        let located = match self {
913            Definition::Validator(validator) => validator.find_node(byte_index),
914            Definition::Fn(func) => func.find_node(byte_index),
915            Definition::Test(func) => func.find_node(byte_index),
916            _ => None,
917        };
918
919        if located.is_none() && self.location().contains(byte_index) {
920            return Some(Located::Definition(self));
921        }
922
923        located
924    }
925}
926
927#[derive(Debug, Clone, PartialEq)]
928pub enum Located<'a> {
929    Expression(&'a TypedExpr),
930    Pattern(&'a TypedPattern, Rc<Type>),
931    Definition(&'a TypedDefinition),
932    Argument(&'a ArgName, Rc<Type>),
933    Annotation(&'a Annotation),
934}
935
936impl Located<'_> {
937    pub fn definition_location(&self) -> Option<DefinitionLocation<'_>> {
938        match self {
939            Self::Expression(expression) => expression.definition_location(),
940            Self::Definition(definition) => Some(DefinitionLocation {
941                module: None,
942                span: definition.location(),
943            }),
944            // TODO: Revise definition location semantic for 'Pattern'
945            // e.g. for constructors, we might want to show the type definition
946            // for that constructor.
947            Self::Pattern(_, _) | Located::Argument(_, _) | Located::Annotation(_) => None,
948        }
949    }
950}
951
952#[derive(Debug, PartialEq, Eq, Clone)]
953pub struct DefinitionLocation<'module> {
954    pub module: Option<&'module str>,
955    pub span: Span,
956}
957
958pub type TypedCallArg = CallArg<TypedExpr>;
959pub type ParsedCallArg = CallArg<Option<UntypedExpr>>;
960
961#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
962pub struct CallArg<A> {
963    pub label: Option<String>,
964    pub location: Span,
965    pub value: A,
966}
967
968impl CallArg<UntypedExpr> {
969    pub fn is_capture_hole(&self) -> bool {
970        match &self.value {
971            UntypedExpr::Var { name, .. } => name.contains(CAPTURE_VARIABLE),
972            _ => false,
973        }
974    }
975}
976
977impl TypedCallArg {
978    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
979        self.value.find_node(byte_index)
980    }
981}
982
983impl CallArg<TypedPattern> {
984    pub fn var(name: &str, location: Span) -> Self {
985        CallArg {
986            label: None,
987            location: Span::empty(),
988            value: TypedPattern::Var {
989                location,
990                name: name.to_string(),
991            },
992        }
993    }
994}
995
996#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
997pub struct RecordConstructor<T> {
998    pub decorators: Vec<Decorator>,
999    pub location: Span,
1000    pub name: String,
1001    pub arguments: Vec<RecordConstructorArg<T>>,
1002    pub doc: Option<String>,
1003    pub sugar: bool,
1004}
1005
1006impl<A> RecordConstructor<A>
1007where
1008    A: Clone,
1009{
1010    pub fn put_doc(&mut self, new_doc: String) {
1011        self.doc = Some(new_doc);
1012    }
1013
1014    pub fn known_enum(names: &[&str]) -> Vec<RecordConstructor<A>> {
1015        names
1016            .iter()
1017            .map(|name| RecordConstructor {
1018                decorators: vec![],
1019                location: Span::empty(),
1020                name: name.to_string(),
1021                arguments: vec![],
1022                doc: None,
1023                sugar: false,
1024            })
1025            .collect()
1026    }
1027
1028    pub fn known_record(name: &str, args: &[RecordConstructorArg<A>]) -> Self {
1029        RecordConstructor {
1030            decorators: vec![],
1031            location: Span::empty(),
1032            name: name.to_string(),
1033            arguments: args.to_vec(),
1034            doc: None,
1035            sugar: false,
1036        }
1037    }
1038}
1039
1040#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1041pub struct RecordConstructorArg<T> {
1042    pub label: Option<String>,
1043    // ast
1044    pub annotation: Annotation,
1045    pub location: Span,
1046    pub tipo: T,
1047    pub doc: Option<String>,
1048}
1049
1050impl<T: PartialEq> RecordConstructorArg<T> {
1051    pub fn put_doc(&mut self, new_doc: String) {
1052        self.doc = Some(new_doc);
1053    }
1054}
1055
1056#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1057pub enum ArgBy {
1058    ByName(ArgName),
1059    ByPattern(UntypedPattern),
1060}
1061
1062impl ArgBy {
1063    pub fn into_extra_assignment(
1064        self,
1065        name: &ArgName,
1066        annotation: Option<&Annotation>,
1067        location: Span,
1068    ) -> Option<UntypedExpr> {
1069        match self {
1070            ArgBy::ByName(..) => None,
1071            ArgBy::ByPattern(pattern) => Some(UntypedExpr::Assignment {
1072                location,
1073                value: Box::new(UntypedExpr::Var {
1074                    location,
1075                    name: name.get_name(),
1076                }),
1077                patterns: vec1![AssignmentPattern {
1078                    pattern,
1079                    location,
1080                    annotation: annotation.cloned(),
1081                }],
1082                kind: AssignmentKind::Let { backpassing: false },
1083            }),
1084        }
1085    }
1086}
1087
1088#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1089pub struct UntypedArg {
1090    pub by: ArgBy,
1091    pub location: Span,
1092    pub annotation: Option<Annotation>,
1093    pub doc: Option<String>,
1094    pub is_validator_param: bool,
1095}
1096
1097impl UntypedArg {
1098    pub fn arg_name(&self, ix: usize) -> ArgName {
1099        match self.by {
1100            ArgBy::ByName(ref name) => name.clone(),
1101            ArgBy::ByPattern(..) => {
1102                // NOTE: We use ordinal here not only because it's cute, but because
1103                // such a name cannot be parsed to begin with and thus, will not clash
1104                // with any user-defined name.
1105                let name = format!("{}{}_arg", ix + 1, Ordinal::<usize>(ix + 1).suffix());
1106                ArgName::Named {
1107                    label: name.clone(),
1108                    name,
1109                    location: self.location,
1110                }
1111            }
1112        }
1113    }
1114
1115    pub fn set_type(self, tipo: Rc<Type>, ix: usize) -> TypedArg {
1116        TypedArg {
1117            tipo,
1118            arg_name: self.arg_name(ix),
1119            location: self.location,
1120            annotation: self.annotation,
1121            is_validator_param: self.is_validator_param,
1122            doc: self.doc,
1123        }
1124    }
1125}
1126
1127#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1128pub struct TypedArg {
1129    pub arg_name: ArgName,
1130    pub location: Span,
1131    pub annotation: Option<Annotation>,
1132    pub doc: Option<String>,
1133    pub is_validator_param: bool,
1134    pub tipo: Rc<Type>,
1135}
1136
1137impl TypedArg {
1138    pub fn new(name: &str, tipo: Rc<Type>) -> Self {
1139        TypedArg {
1140            arg_name: ArgName::Named {
1141                name: name.to_string(),
1142                label: name.to_string(),
1143                location: Span::empty(),
1144            },
1145            location: Span::empty(),
1146            annotation: None,
1147            doc: None,
1148            is_validator_param: false,
1149            tipo: tipo.clone(),
1150        }
1151    }
1152
1153    pub fn put_doc(&mut self, new_doc: String) {
1154        self.doc = Some(new_doc);
1155    }
1156
1157    pub fn get_variable_name(&self) -> Option<&str> {
1158        self.arg_name.get_variable_name()
1159    }
1160
1161    pub fn get_name(&self) -> String {
1162        self.arg_name.get_name()
1163    }
1164
1165    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
1166        if self.arg_name.location().contains(byte_index) {
1167            Some(Located::Argument(&self.arg_name, self.tipo.clone()))
1168        } else {
1169            self.annotation
1170                .as_ref()
1171                .and_then(|annotation| annotation.find_node(byte_index))
1172        }
1173    }
1174}
1175
1176pub type TypedArgVia = ArgVia<TypedArg, TypedExpr>;
1177pub type UntypedArgVia = ArgVia<UntypedArg, UntypedExpr>;
1178
1179#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1180pub struct ArgVia<Arg, Expr> {
1181    pub arg: Arg,
1182    pub via: Expr,
1183}
1184
1185impl<Expr> From<ArgVia<TypedArg, Expr>> for TypedArg {
1186    fn from(this: ArgVia<TypedArg, Expr>) -> TypedArg {
1187        this.arg
1188    }
1189}
1190
1191impl<Expr> From<ArgVia<UntypedArg, Expr>> for UntypedArg {
1192    fn from(this: ArgVia<UntypedArg, Expr>) -> UntypedArg {
1193        this.arg
1194    }
1195}
1196
1197impl TypedArgVia {
1198    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
1199        if self.arg.arg_name.location().contains(byte_index) {
1200            Some(Located::Argument(&self.arg.arg_name, self.arg.tipo.clone()))
1201        } else {
1202            // `via` is done first here because when there is no manually written
1203            // annotation, it seems one is injected leading to a `found` returning too early
1204            // because the span of the filled in annotation matches the span of the via expr.
1205            self.via.find_node(byte_index).or_else(|| {
1206                self.arg
1207                    .annotation
1208                    .as_ref()
1209                    .and_then(|annotation| annotation.find_node(byte_index))
1210            })
1211        }
1212    }
1213}
1214
1215#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1216pub enum ArgName {
1217    Discarded {
1218        name: String,
1219        label: String,
1220        location: Span,
1221    },
1222    Named {
1223        name: String,
1224        label: String,
1225        location: Span,
1226    },
1227}
1228
1229impl ArgName {
1230    pub fn location(&self) -> Span {
1231        match self {
1232            ArgName::Discarded { location, .. } => *location,
1233            ArgName::Named { location, .. } => *location,
1234        }
1235    }
1236
1237    /// Returns the name of the variable if it is named, otherwise None.
1238    /// Code gen uses the fact that this returns None to do certain things.
1239    pub fn get_variable_name(&self) -> Option<&str> {
1240        match self {
1241            ArgName::Discarded { .. } => None,
1242            ArgName::Named { name, .. } => Some(name),
1243        }
1244    }
1245
1246    pub fn get_name(&self) -> String {
1247        match self {
1248            ArgName::Discarded { name, .. } | ArgName::Named { name, .. } => name.clone(),
1249        }
1250    }
1251
1252    pub fn get_label(&self) -> String {
1253        match self {
1254            ArgName::Discarded { label, .. } | ArgName::Named { label, .. } => label.to_string(),
1255        }
1256    }
1257}
1258
1259#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1260pub struct UnqualifiedImport {
1261    pub location: Span,
1262    pub name: String,
1263    pub as_name: Option<String>,
1264}
1265
1266impl UnqualifiedImport {
1267    pub fn variable_name(&self) -> &str {
1268        self.as_name.as_deref().unwrap_or(&self.name)
1269    }
1270}
1271
1272// TypeAst
1273#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1274pub enum Annotation {
1275    Constructor {
1276        location: Span,
1277        module: Option<String>,
1278        name: String,
1279        arguments: Vec<Self>,
1280    },
1281
1282    Fn {
1283        location: Span,
1284        arguments: Vec<Self>,
1285        ret: Box<Self>,
1286    },
1287
1288    Var {
1289        location: Span,
1290        name: String,
1291    },
1292
1293    Hole {
1294        location: Span,
1295        name: String,
1296    },
1297
1298    Tuple {
1299        location: Span,
1300        elems: Vec<Self>,
1301    },
1302
1303    Pair {
1304        location: Span,
1305        fst: Box<Self>,
1306        snd: Box<Self>,
1307    },
1308}
1309
1310impl Annotation {
1311    pub fn location(&self) -> Span {
1312        match self {
1313            Annotation::Fn { location, .. }
1314            | Annotation::Tuple { location, .. }
1315            | Annotation::Var { location, .. }
1316            | Annotation::Hole { location, .. }
1317            | Annotation::Constructor { location, .. }
1318            | Annotation::Pair { location, .. } => *location,
1319        }
1320    }
1321
1322    pub fn boolean(location: Span) -> Self {
1323        Annotation::Constructor {
1324            name: "Bool".to_string(),
1325            module: None,
1326            arguments: vec![],
1327            location,
1328        }
1329    }
1330
1331    pub fn int(location: Span) -> Self {
1332        Annotation::Constructor {
1333            name: "Int".to_string(),
1334            module: None,
1335            arguments: vec![],
1336            location,
1337        }
1338    }
1339
1340    pub fn bytearray(location: Span) -> Self {
1341        Annotation::Constructor {
1342            name: "ByteArray".to_string(),
1343            module: None,
1344            arguments: vec![],
1345            location,
1346        }
1347    }
1348
1349    pub fn data(location: Span) -> Self {
1350        Annotation::Constructor {
1351            name: "Data".to_string(),
1352            module: None,
1353            arguments: vec![],
1354            location,
1355        }
1356    }
1357
1358    pub fn option(inner: Annotation) -> Self {
1359        Annotation::Constructor {
1360            name: "Option".to_string(),
1361            module: None,
1362            location: inner.location(),
1363            arguments: vec![inner],
1364        }
1365    }
1366
1367    pub fn list(inner: Annotation, location: Span) -> Self {
1368        Annotation::Constructor {
1369            name: "List".to_string(),
1370            module: None,
1371            arguments: vec![inner],
1372            location,
1373        }
1374    }
1375
1376    pub fn tuple(elems: Vec<Annotation>, location: Span) -> Self {
1377        Annotation::Tuple { elems, location }
1378    }
1379
1380    pub fn is_logically_equal(&self, other: &Annotation) -> bool {
1381        match self {
1382            Annotation::Constructor {
1383                module,
1384                name,
1385                arguments,
1386                location: _,
1387            } => match other {
1388                Annotation::Constructor {
1389                    module: o_module,
1390                    name: o_name,
1391                    arguments: o_arguments,
1392                    location: _,
1393                } => {
1394                    module == o_module
1395                        && name == o_name
1396                        && arguments.len() == o_arguments.len()
1397                        && arguments
1398                            .iter()
1399                            .zip(o_arguments)
1400                            .all(|a| a.0.is_logically_equal(a.1))
1401                }
1402                _ => false,
1403            },
1404            Annotation::Tuple { elems, location: _ } => match other {
1405                Annotation::Tuple {
1406                    elems: o_elems,
1407                    location: _,
1408                } => {
1409                    elems.len() == o_elems.len()
1410                        && elems
1411                            .iter()
1412                            .zip(o_elems)
1413                            .all(|a| a.0.is_logically_equal(a.1))
1414                }
1415                _ => false,
1416            },
1417            Annotation::Fn {
1418                arguments,
1419                ret,
1420                location: _,
1421            } => match other {
1422                Annotation::Fn {
1423                    arguments: o_arguments,
1424                    ret: o_return,
1425                    location: _,
1426                } => {
1427                    arguments.len() == o_arguments.len()
1428                        && arguments
1429                            .iter()
1430                            .zip(o_arguments)
1431                            .all(|a| a.0.is_logically_equal(a.1))
1432                        && ret.is_logically_equal(o_return)
1433                }
1434                _ => false,
1435            },
1436            Annotation::Var { name, location: _ } => match other {
1437                Annotation::Var {
1438                    name: o_name,
1439                    location: _,
1440                } => name == o_name,
1441                _ => false,
1442            },
1443
1444            Annotation::Hole { name, location: _ } => match other {
1445                Annotation::Hole {
1446                    name: o_name,
1447                    location: _,
1448                } => name == o_name,
1449                _ => false,
1450            },
1451            Annotation::Pair { fst, snd, .. } => {
1452                if let Annotation::Pair {
1453                    fst: o_fst,
1454                    snd: o_snd,
1455                    ..
1456                } = other
1457                {
1458                    fst.is_logically_equal(o_fst) && snd.is_logically_equal(o_snd)
1459                } else {
1460                    false
1461                }
1462            }
1463        }
1464    }
1465
1466    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
1467        if !self.location().contains(byte_index) {
1468            return None;
1469        }
1470
1471        let located = match self {
1472            Annotation::Constructor { arguments, .. } => {
1473                arguments.iter().find_map(|arg| arg.find_node(byte_index))
1474            }
1475            Annotation::Fn { arguments, ret, .. } => arguments
1476                .iter()
1477                .find_map(|arg| arg.find_node(byte_index))
1478                .or_else(|| ret.find_node(byte_index)),
1479            Annotation::Tuple { elems, .. } => {
1480                elems.iter().find_map(|arg| arg.find_node(byte_index))
1481            }
1482            Annotation::Var { .. } | Annotation::Hole { .. } => None,
1483            Annotation::Pair { fst, snd, .. } => fst
1484                .find_node(byte_index)
1485                .or_else(|| snd.find_node(byte_index)),
1486        };
1487
1488        located.or(Some(Located::Annotation(self)))
1489    }
1490}
1491
1492#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1493pub enum BinOp {
1494    // Boolean logic
1495    And,
1496    Or,
1497
1498    // Equality
1499    Eq,
1500    NotEq,
1501
1502    // Order comparison
1503    LtInt,
1504    LtEqInt,
1505    GtEqInt,
1506    GtInt,
1507
1508    // Maths
1509    AddInt,
1510    SubInt,
1511    MultInt,
1512    DivInt,
1513    ModInt,
1514}
1515
1516impl From<LogicalOpChainKind> for BinOp {
1517    fn from(value: LogicalOpChainKind) -> Self {
1518        match value {
1519            LogicalOpChainKind::And => BinOp::And,
1520            LogicalOpChainKind::Or => BinOp::Or,
1521        }
1522    }
1523}
1524
1525#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1526pub enum UnOp {
1527    /// !
1528    Not,
1529    /// -
1530    Negate,
1531}
1532
1533impl BinOp {
1534    pub fn precedence(&self) -> u8 {
1535        // Ensure that this matches the other precedence function for guards
1536        match self {
1537            // Pipe is 0
1538            // Unary operators are 1
1539            Self::Or => 2,
1540
1541            Self::And => 3,
1542
1543            Self::Eq | Self::NotEq | Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => 4,
1544
1545            // Concatenation operators are typically 5, so we skip it.
1546            Self::AddInt | Self::SubInt => 6,
1547
1548            Self::MultInt | Self::DivInt | Self::ModInt => 7,
1549        }
1550    }
1551}
1552
1553pub type UntypedPattern = Pattern<(), (), Namespace, (u8, Span)>;
1554pub type TypedPattern = Pattern<PatternConstructor, Rc<Type>, String, u8>;
1555
1556impl TypedPattern {
1557    pub fn var(name: &str) -> Self {
1558        TypedPattern::Var {
1559            name: name.to_string(),
1560            location: Span::empty(),
1561        }
1562    }
1563
1564    pub fn constructor(
1565        name: &str,
1566        arguments: &[CallArg<TypedPattern>],
1567        tipo: Rc<Type>,
1568        location: Span,
1569    ) -> Self {
1570        TypedPattern::Constructor {
1571            is_record: false,
1572            location,
1573            name: name.to_string(),
1574            arguments: arguments.to_vec(),
1575            module: None,
1576            constructor: PatternConstructor::Record {
1577                name: name.to_string(),
1578                field_map: None,
1579            },
1580            spread_location: None,
1581            tipo: tipo.clone(),
1582        }
1583    }
1584
1585    pub fn mint_purpose(
1586        (var_purpose_arg, purpose_span): (&str, Span),
1587        redeemer_span: Span,
1588    ) -> Self {
1589        TypedPattern::constructor(
1590            well_known::SCRIPT_PURPOSE_MINT,
1591            &[CallArg::var(var_purpose_arg, purpose_span)],
1592            Type::function(vec![Type::byte_array()], Type::script_purpose()),
1593            redeemer_span,
1594        )
1595    }
1596
1597    pub fn spend_purpose(
1598        (var_purpose_arg, purpose_span): (&str, Span),
1599        (var_datum, datum_span): (&str, Span),
1600        redeemer_span: Span,
1601    ) -> Self {
1602        TypedPattern::constructor(
1603            well_known::SCRIPT_PURPOSE_SPEND,
1604            &[
1605                CallArg::var(var_purpose_arg, purpose_span),
1606                CallArg::var(var_datum, datum_span),
1607            ],
1608            Type::function(
1609                vec![Type::data(), Type::option(Type::data())],
1610                Type::script_purpose(),
1611            ),
1612            redeemer_span,
1613        )
1614    }
1615
1616    pub fn withdraw_purpose(
1617        (var_purpose_arg, purpose_span): (&str, Span),
1618        redeemer_span: Span,
1619    ) -> Self {
1620        TypedPattern::constructor(
1621            well_known::SCRIPT_PURPOSE_WITHDRAW,
1622            &[CallArg::var(var_purpose_arg, purpose_span)],
1623            Type::function(vec![Type::data()], Type::script_purpose()),
1624            redeemer_span,
1625        )
1626    }
1627
1628    pub fn publish_purpose(
1629        (var_purpose_arg, purpose_span): (&str, Span),
1630        redeemer_span: Span,
1631    ) -> Self {
1632        TypedPattern::constructor(
1633            well_known::SCRIPT_PURPOSE_PUBLISH,
1634            &[
1635                CallArg::var("__discarded_purpose_ix__", purpose_span),
1636                CallArg::var(var_purpose_arg, purpose_span),
1637            ],
1638            Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
1639            redeemer_span,
1640        )
1641    }
1642
1643    pub fn vote_purpose(
1644        (var_purpose_arg, purpose_span): (&str, Span),
1645        redeemer_span: Span,
1646    ) -> Self {
1647        TypedPattern::constructor(
1648            well_known::SCRIPT_PURPOSE_VOTE,
1649            &[CallArg::var(var_purpose_arg, purpose_span)],
1650            Type::function(vec![Type::data()], Type::script_purpose()),
1651            redeemer_span,
1652        )
1653    }
1654
1655    pub fn propose_purpose(
1656        (var_purpose_arg, purpose_span): (&str, Span),
1657        redeemer_span: Span,
1658    ) -> Self {
1659        TypedPattern::constructor(
1660            well_known::SCRIPT_PURPOSE_PROPOSE,
1661            &[
1662                CallArg::var("__discarded_purpose_ix__", purpose_span),
1663                CallArg::var(var_purpose_arg, purpose_span),
1664            ],
1665            Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
1666            redeemer_span,
1667        )
1668    }
1669}
1670
1671#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1672pub enum Namespace {
1673    Module(String),
1674    Type(Option<String>, String),
1675}
1676
1677#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1678pub enum Pattern<Constructor, Type, NamespaceKind, ByteValue> {
1679    Int {
1680        location: Span,
1681        value: String,
1682        base: Base,
1683    },
1684
1685    ByteArray {
1686        location: Span,
1687        value: Vec<ByteValue>,
1688        preferred_format: ByteArrayFormatPreference,
1689    },
1690
1691    /// The creation of a variable.
1692    /// e.g. `expect [this_is_a_var, .._] = x`
1693    /// e.g. `let foo = 42`
1694    Var {
1695        location: Span,
1696        name: String,
1697    },
1698
1699    /// A name given to a sub-pattern using the `as` keyword.
1700    ///
1701    /// ```aiken
1702    /// when foo is {
1703    ///    [_, _] as the_list -> ...
1704    /// }
1705    /// ```
1706    Assign {
1707        name: String,
1708        location: Span,
1709        pattern: Box<Self>,
1710    },
1711
1712    /// A pattern that binds to any value but does not assign a variable.
1713    /// Always starts with an underscore.
1714    Discard {
1715        name: String,
1716        location: Span,
1717    },
1718
1719    List {
1720        location: Span,
1721        elements: Vec<Self>,
1722        tail: Option<Box<Self>>,
1723    },
1724
1725    /// The constructor for a custom type. Starts with an uppercase letter.
1726    Constructor {
1727        is_record: bool,
1728        location: Span,
1729        name: String,
1730        arguments: Vec<CallArg<Self>>,
1731        module: Option<NamespaceKind>,
1732        constructor: Constructor,
1733        spread_location: Option<Span>,
1734        tipo: Type,
1735    },
1736
1737    Pair {
1738        location: Span,
1739        fst: Box<Self>,
1740        snd: Box<Self>,
1741    },
1742
1743    Tuple {
1744        location: Span,
1745        elems: Vec<Self>,
1746    },
1747}
1748
1749impl<A, B, C, BV> Pattern<A, B, C, BV> {
1750    pub fn location(&self) -> Span {
1751        match self {
1752            Pattern::Assign { pattern, .. } => pattern.location(),
1753            Pattern::Int { location, .. }
1754            | Pattern::Var { location, .. }
1755            | Pattern::List { location, .. }
1756            | Pattern::Discard { location, .. }
1757            | Pattern::Tuple { location, .. }
1758            | Pattern::Pair { location, .. }
1759            | Pattern::ByteArray { location, .. }
1760            | Pattern::Constructor { location, .. } => *location,
1761        }
1762    }
1763
1764    /// Returns true when a Pattern can be displayed in a flex-break manner (i.e. tries to fit as
1765    /// much as possible on a single line). When false, long lines with several of those patterns
1766    /// will be broken down to one pattern per line.
1767    pub fn is_simple_pattern_to_format(&self) -> bool {
1768        match self {
1769            Self::ByteArray { .. } | Self::Int { .. } | Self::Var { .. } | Self::Discard { .. } => {
1770                true
1771            }
1772            Self::Pair { fst, snd, .. } => {
1773                fst.is_simple_pattern_to_format() && snd.is_simple_pattern_to_format()
1774            }
1775            Self::Tuple { elems, .. } => elems.iter().all(|e| e.is_simple_pattern_to_format()),
1776            Self::List { elements, .. } if elements.len() <= 3 => {
1777                elements.iter().all(|e| e.is_simple_pattern_to_format())
1778            }
1779            Self::Constructor { arguments, .. } => arguments.is_empty(),
1780            _ => false,
1781        }
1782    }
1783
1784    pub fn with_spread(&self) -> bool {
1785        match self {
1786            Pattern::Constructor {
1787                spread_location, ..
1788            } => spread_location.is_some(),
1789            _ => false,
1790        }
1791    }
1792
1793    /// Returns `true` if the pattern is [`Discard`].
1794    ///
1795    /// [`Discard`]: Pattern::Discard
1796    pub fn is_discard(&self) -> bool {
1797        matches!(self, Self::Discard { .. })
1798    }
1799
1800    /// Returns `true` if the pattern is [`Var`].
1801    ///
1802    /// [`Var`]: Pattern::Discard
1803    pub fn is_var(&self) -> bool {
1804        matches!(self, Self::Var { .. })
1805    }
1806}
1807
1808impl UntypedPattern {
1809    pub fn true_(location: Span) -> UntypedPattern {
1810        UntypedPattern::Constructor {
1811            location,
1812            name: "True".to_string(),
1813            arguments: vec![],
1814            constructor: (),
1815            spread_location: None,
1816            tipo: (),
1817            module: None,
1818            is_record: false,
1819        }
1820    }
1821
1822    pub fn collect_identifiers<F>(&self, collect: &mut F)
1823    where
1824        F: FnMut((String, Span)),
1825    {
1826        match self {
1827            Pattern::Var { name, location } => {
1828                collect((name.to_string(), *location));
1829            }
1830            Pattern::List { elements, .. } => {
1831                elements.iter().for_each(|e| e.collect_identifiers(collect));
1832            }
1833            Pattern::Pair { fst, snd, .. } => {
1834                fst.collect_identifiers(collect);
1835                snd.collect_identifiers(collect);
1836            }
1837            Pattern::Tuple { elems, .. } => {
1838                elems.iter().for_each(|e| e.collect_identifiers(collect));
1839            }
1840            Pattern::Constructor { arguments, .. } => {
1841                arguments
1842                    .iter()
1843                    .for_each(|arg| arg.value.collect_identifiers(collect));
1844            }
1845            Pattern::Int { .. }
1846            | Pattern::ByteArray { .. }
1847            | Pattern::Discard { .. }
1848            | Pattern::Assign { .. } => {}
1849        }
1850    }
1851}
1852
1853impl TypedPattern {
1854    pub fn find_node<'a>(&'a self, byte_index: usize, value: &Rc<Type>) -> Option<Located<'a>> {
1855        if !self.location().contains(byte_index) {
1856            return None;
1857        }
1858
1859        match self {
1860            Pattern::Int { .. }
1861            | Pattern::Var { .. }
1862            | Pattern::Assign { .. }
1863            | Pattern::ByteArray { .. }
1864            | Pattern::Discard { .. } => Some(Located::Pattern(self, value.clone())),
1865
1866            Pattern::List { elements, .. }
1867            | Pattern::Tuple {
1868                elems: elements, ..
1869            } => match &**value {
1870                Type::Tuple { elems, .. } => elements
1871                    .iter()
1872                    .zip(elems.iter())
1873                    .find_map(|(e, t)| e.find_node(byte_index, t))
1874                    .or(Some(Located::Pattern(self, value.clone()))),
1875                Type::App {
1876                    module, name, args, ..
1877                } if module.is_empty() && name == "List" => elements
1878                    .iter()
1879                    // this is the same as above but this uses
1880                    // cycle to repeat the single type arg for a list
1881                    // there's probably a cleaner way to re-use the code
1882                    // from this branch and the above.
1883                    .zip(args.iter().cycle())
1884                    .find_map(|(e, t)| e.find_node(byte_index, t))
1885                    .or(Some(Located::Pattern(self, value.clone()))),
1886                _ => None,
1887            },
1888
1889            Pattern::Pair { fst, snd, .. } => match &**value {
1890                Type::Pair {
1891                    fst: fst_v,
1892                    snd: snd_v,
1893                    ..
1894                } => [fst, snd]
1895                    .into_iter()
1896                    .zip([fst_v, snd_v].iter())
1897                    .find_map(|(e, t)| e.find_node(byte_index, t))
1898                    .or(Some(Located::Pattern(self, value.clone()))),
1899                _ => None,
1900            },
1901
1902            Pattern::Constructor {
1903                arguments, tipo, ..
1904            } => match &**tipo {
1905                Type::Fn { args, .. } => arguments
1906                    .iter()
1907                    .zip(args.iter())
1908                    .find_map(|(e, t)| e.value.find_node(byte_index, t))
1909                    .or(Some(Located::Pattern(self, value.clone()))),
1910                _ => None,
1911            },
1912        }
1913    }
1914
1915    // TODO: This function definition is weird, see where this is used and how.
1916    pub fn tipo(&self, value: &TypedExpr) -> Option<Rc<Type>> {
1917        match self {
1918            Pattern::Int { .. } => Some(Type::int()),
1919            Pattern::ByteArray { .. } => Some(Type::byte_array()),
1920            Pattern::Constructor { tipo, .. } => Some(tipo.clone()),
1921            Pattern::Var { .. } | Pattern::Assign { .. } | Pattern::Discard { .. } => {
1922                Some(value.tipo())
1923            }
1924            Pattern::List { .. } | Pattern::Tuple { .. } | Pattern::Pair { .. } => None,
1925        }
1926    }
1927}
1928
1929#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
1930pub enum ByteArrayFormatPreference {
1931    HexadecimalString,
1932    ArrayOfBytes(Base),
1933    Utf8String,
1934}
1935
1936#[derive(Debug, Clone, PartialEq, Eq, Copy)]
1937pub enum CurveType {
1938    Bls12_381(Bls12_381PointType),
1939}
1940
1941impl Display for CurveType {
1942    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1943        match self {
1944            CurveType::Bls12_381(point) => write!(f, "<Bls12_381, {point}>"),
1945        }
1946    }
1947}
1948impl From<&Curve> for CurveType {
1949    fn from(value: &Curve) -> Self {
1950        match value {
1951            Curve::Bls12_381(point) => CurveType::Bls12_381(point.into()),
1952        }
1953    }
1954}
1955
1956#[derive(Debug, Clone, PartialEq, Eq, Copy)]
1957pub enum Bls12_381PointType {
1958    G1,
1959    G2,
1960}
1961
1962impl From<&Bls12_381Point> for Bls12_381PointType {
1963    fn from(value: &Bls12_381Point) -> Self {
1964        match value {
1965            Bls12_381Point::G1(_) => Bls12_381PointType::G1,
1966            Bls12_381Point::G2(_) => Bls12_381PointType::G2,
1967        }
1968    }
1969}
1970
1971impl Display for Bls12_381PointType {
1972    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1973        match self {
1974            Bls12_381PointType::G1 => write!(f, "G1"),
1975            Bls12_381PointType::G2 => write!(f, "G2"),
1976        }
1977    }
1978}
1979
1980#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
1981pub enum Curve {
1982    Bls12_381(Bls12_381Point),
1983}
1984
1985impl Curve {
1986    pub fn compress(&self) -> Vec<u8> {
1987        match self {
1988            Curve::Bls12_381(point) => match point {
1989                Bls12_381Point::G1(g1) => g1.compress(),
1990                Bls12_381Point::G2(g2) => g2.compress(),
1991            },
1992        }
1993    }
1994
1995    pub fn tipo(&self) -> Rc<Type> {
1996        match self {
1997            Curve::Bls12_381(point) => point.tipo(),
1998        }
1999    }
2000}
2001
2002#[derive(Debug, Clone, PartialEq, Eq, Copy)]
2003pub enum Bls12_381Point {
2004    G1(blst::blst_p1),
2005    G2(blst::blst_p2),
2006}
2007
2008impl serde::Serialize for Bls12_381Point {
2009    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2010    where
2011        S: serde::Serializer,
2012    {
2013        match *self {
2014            Bls12_381Point::G1(ref p1) => {
2015                // Assuming `to_bytes` for compression to Vec<u8>
2016                let bytes = p1.compress();
2017
2018                // Serialize as a tuple with a tag for differentiation
2019                serializer.serialize_newtype_variant("Bls12_381Point", 0, "G1", &bytes)
2020            }
2021            Bls12_381Point::G2(ref p2) => {
2022                let bytes = p2.compress();
2023
2024                serializer.serialize_newtype_variant("Bls12_381Point", 1, "G2", &bytes)
2025            }
2026        }
2027    }
2028}
2029
2030impl<'de> serde::Deserialize<'de> for Bls12_381Point {
2031    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2032    where
2033        D: serde::Deserializer<'de>,
2034    {
2035        enum Field {
2036            G1,
2037            G2,
2038        }
2039
2040        impl<'de> serde::Deserialize<'de> for Field {
2041            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
2042            where
2043                D: serde::Deserializer<'de>,
2044            {
2045                struct FieldVisitor;
2046
2047                impl serde::de::Visitor<'_> for FieldVisitor {
2048                    type Value = Field;
2049
2050                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2051                        formatter.write_str("`G1` or `G2`")
2052                    }
2053
2054                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
2055                    where
2056                        E: serde::de::Error,
2057                    {
2058                        match value {
2059                            "G1" => Ok(Field::G1),
2060                            "G2" => Ok(Field::G2),
2061                            _ => Err(serde::de::Error::unknown_field(value, FIELDS)),
2062                        }
2063                    }
2064                }
2065
2066                deserializer.deserialize_identifier(FieldVisitor)
2067            }
2068        }
2069
2070        struct Bls12_381PointVisitor;
2071
2072        impl<'de> serde::de::Visitor<'de> for Bls12_381PointVisitor {
2073            type Value = Bls12_381Point;
2074
2075            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2076                formatter.write_str("struct Bls12_381Point")
2077            }
2078
2079            fn visit_seq<V>(self, mut seq: V) -> Result<Bls12_381Point, V::Error>
2080            where
2081                V: serde::de::SeqAccess<'de>,
2082            {
2083                let tag = seq
2084                    .next_element::<Field>()?
2085                    .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
2086
2087                let bytes = seq
2088                    .next_element::<Vec<u8>>()?
2089                    .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
2090
2091                match tag {
2092                    Field::G1 => {
2093                        let p1 =
2094                            blst::blst_p1::uncompress(&bytes).map_err(serde::de::Error::custom)?;
2095
2096                        Ok(Bls12_381Point::G1(p1))
2097                    }
2098                    Field::G2 => {
2099                        let p2 =
2100                            blst::blst_p2::uncompress(&bytes).map_err(serde::de::Error::custom)?;
2101
2102                        Ok(Bls12_381Point::G2(p2))
2103                    }
2104                }
2105            }
2106        }
2107
2108        const FIELDS: &[&str] = &["G1", "G2"];
2109
2110        deserializer.deserialize_enum("Bls12_381Point", FIELDS, Bls12_381PointVisitor)
2111    }
2112}
2113
2114impl Bls12_381Point {
2115    pub fn tipo(&self) -> Rc<Type> {
2116        match self {
2117            Bls12_381Point::G1(_) => Type::g1_element(),
2118            Bls12_381Point::G2(_) => Type::g2_element(),
2119        }
2120    }
2121}
2122
2123impl Default for Bls12_381Point {
2124    fn default() -> Self {
2125        Bls12_381Point::G1(Default::default())
2126    }
2127}
2128
2129#[derive(Debug, Clone, PartialEq)]
2130pub struct AssignmentPattern {
2131    pub pattern: UntypedPattern,
2132    pub annotation: Option<Annotation>,
2133    pub location: Span,
2134}
2135
2136impl AssignmentPattern {
2137    pub fn new(
2138        pattern: UntypedPattern,
2139        annotation: Option<Annotation>,
2140        location: Span,
2141    ) -> AssignmentPattern {
2142        Self {
2143            pattern,
2144            annotation,
2145            location,
2146        }
2147    }
2148}
2149
2150impl From<AssignmentPattern> for Vec1<AssignmentPattern> {
2151    fn from(value: AssignmentPattern) -> Self {
2152        Vec1::new(value)
2153    }
2154}
2155
2156pub type UntypedAssignmentKind = AssignmentKind<bool>;
2157pub type TypedAssignmentKind = AssignmentKind<()>;
2158
2159#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
2160pub enum AssignmentKind<T> {
2161    Is,
2162    Let { backpassing: T },
2163    Expect { backpassing: T },
2164}
2165
2166impl From<UntypedAssignmentKind> for TypedAssignmentKind {
2167    fn from(kind: UntypedAssignmentKind) -> TypedAssignmentKind {
2168        match kind {
2169            AssignmentKind::Is => AssignmentKind::Is,
2170            AssignmentKind::Let { .. } => AssignmentKind::Let { backpassing: () },
2171            AssignmentKind::Expect { .. } => AssignmentKind::Expect { backpassing: () },
2172        }
2173    }
2174}
2175
2176impl<T> AssignmentKind<T> {
2177    pub fn is_let(&self) -> bool {
2178        matches!(self, AssignmentKind::Let { .. })
2179    }
2180
2181    pub fn is_expect(&self) -> bool {
2182        matches!(self, AssignmentKind::Expect { .. })
2183    }
2184
2185    pub fn if_is(&self) -> bool {
2186        matches!(self, AssignmentKind::Is)
2187    }
2188
2189    pub fn location_offset(&self) -> usize {
2190        match self {
2191            AssignmentKind::Is => 2,
2192            AssignmentKind::Let { .. } => 3,
2193            AssignmentKind::Expect { .. } => 6,
2194        }
2195    }
2196}
2197
2198impl AssignmentKind<bool> {
2199    pub fn is_backpassing(&self) -> bool {
2200        match self {
2201            Self::Is => unreachable!(),
2202            Self::Let { backpassing } | Self::Expect { backpassing } => *backpassing,
2203        }
2204    }
2205}
2206
2207impl<T: Default> AssignmentKind<T> {
2208    pub fn let_() -> Self {
2209        AssignmentKind::Let {
2210            backpassing: Default::default(),
2211        }
2212    }
2213
2214    pub fn is() -> Self {
2215        AssignmentKind::Is
2216    }
2217
2218    pub fn expect() -> Self {
2219        AssignmentKind::Expect {
2220            backpassing: Default::default(),
2221        }
2222    }
2223}
2224
2225pub type MultiPattern<PatternConstructor, Type, NamespaceKind, ByteValue> =
2226    Vec<Pattern<PatternConstructor, Type, NamespaceKind, ByteValue>>;
2227
2228pub type UntypedMultiPattern = MultiPattern<(), (), Namespace, (u8, Span)>;
2229pub type TypedMultiPattern = MultiPattern<PatternConstructor, Rc<Type>, String, u8>;
2230
2231#[derive(Debug, Clone, PartialEq)]
2232pub struct UntypedClause {
2233    pub location: Span,
2234    pub patterns: Vec1<UntypedPattern>,
2235    pub then: UntypedExpr,
2236}
2237
2238#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2239pub struct TypedClause {
2240    pub location: Span,
2241    pub pattern: TypedPattern,
2242    pub then: TypedExpr,
2243}
2244
2245impl TypedClause {
2246    pub fn location(&self) -> Span {
2247        Span {
2248            start: self.pattern.location().start,
2249            end: self.then.location().end,
2250        }
2251    }
2252
2253    pub fn find_node(&self, byte_index: usize, subject_type: &Rc<Type>) -> Option<Located<'_>> {
2254        self.pattern
2255            .find_node(byte_index, subject_type)
2256            .or_else(|| self.then.find_node(byte_index))
2257    }
2258}
2259
2260pub struct UntypedClauseGuard {}
2261
2262pub type TypedIfBranch = IfBranch<TypedExpr, (TypedPattern, Rc<Type>)>;
2263pub type UntypedIfBranch = IfBranch<UntypedExpr, AssignmentPattern>;
2264
2265#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
2266pub struct IfBranch<Expr, Is> {
2267    pub condition: Expr,
2268    pub body: Expr,
2269    pub is: Option<Is>,
2270    pub location: Span,
2271}
2272
2273#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2274pub struct TypedRecordUpdateArg {
2275    pub label: String,
2276    pub location: Span,
2277    pub value: TypedExpr,
2278    pub index: usize,
2279}
2280
2281impl TypedRecordUpdateArg {
2282    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
2283        self.value.find_node(byte_index)
2284    }
2285}
2286
2287#[derive(Debug, Clone, PartialEq)]
2288pub struct UntypedRecordUpdateArg {
2289    pub label: String,
2290    pub location: Span,
2291    pub value: UntypedExpr,
2292}
2293
2294#[derive(Debug, Clone, PartialEq)]
2295pub struct RecordUpdateSpread {
2296    pub base: Box<UntypedExpr>,
2297    pub location: Span,
2298}
2299
2300#[derive(Debug, Clone, PartialEq, Eq)]
2301pub enum TraceKind {
2302    Trace,
2303    Todo,
2304    Error,
2305}
2306
2307#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2308pub enum Tracing {
2309    UserDefined(TraceLevel),
2310    CompilerGenerated(TraceLevel),
2311    All(TraceLevel),
2312}
2313
2314#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2315pub enum TraceLevel {
2316    Silent,  // No traces
2317    Compact, // Line numbers only
2318    Verbose, // Full verbose traces as provided by the user or the compiler
2319}
2320
2321impl Tracing {
2322    pub fn verbose() -> Self {
2323        Tracing::All(TraceLevel::Verbose)
2324    }
2325
2326    pub fn silent() -> Self {
2327        Tracing::All(TraceLevel::Silent)
2328    }
2329
2330    /// Get the tracing level based on the context we're in.
2331    pub fn trace_level(&self, is_code_gen: bool) -> TraceLevel {
2332        match self {
2333            Tracing::UserDefined(lvl) => {
2334                if is_code_gen {
2335                    TraceLevel::Silent
2336                } else {
2337                    *lvl
2338                }
2339            }
2340            Tracing::CompilerGenerated(lvl) => {
2341                if is_code_gen {
2342                    *lvl
2343                } else {
2344                    TraceLevel::Silent
2345                }
2346            }
2347            Tracing::All(lvl) => *lvl,
2348        }
2349    }
2350}
2351
2352impl Display for TraceLevel {
2353    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
2354        match self {
2355            TraceLevel::Silent => f.write_str("silent"),
2356            TraceLevel::Compact => f.write_str("compact"),
2357            TraceLevel::Verbose => f.write_str("verbose"),
2358        }
2359    }
2360}
2361
2362#[derive(Copy, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
2363pub struct Span {
2364    pub start: usize,
2365    pub end: usize,
2366}
2367
2368impl From<Span> for miette::SourceSpan {
2369    fn from(span: Span) -> Self {
2370        Self::new(span.start.into(), span.end - span.start)
2371    }
2372}
2373
2374impl Span {
2375    pub fn empty() -> Self {
2376        use chumsky::Span;
2377
2378        Self::new((), 0..0)
2379    }
2380
2381    pub fn create(i: usize, n: usize) -> Self {
2382        use chumsky::Span;
2383
2384        Self::new((), i..i + n)
2385    }
2386
2387    pub fn range(&self) -> Range<usize> {
2388        use chumsky::Span;
2389
2390        self.start()..self.end()
2391    }
2392
2393    pub fn union(self, other: Self) -> Self {
2394        use chumsky::Span;
2395
2396        Self {
2397            start: self.start().min(other.start()),
2398            end: self.end().max(other.end()),
2399        }
2400    }
2401
2402    /// Map the current start and end of the Span to new values.
2403    ///
2404    /// # Examples
2405    ///
2406    /// ```
2407    /// use aiken_lang::ast::Span;
2408    ///
2409    /// let span = Span { start: 0, end: 1 };
2410    ///
2411    /// let other = span.map(|start, end| (start + 2, end + 4));
2412    ///
2413    /// assert_eq!(other.start, 2);
2414    /// assert_eq!(other.end, 5);
2415    /// ```
2416    pub fn map<F: FnOnce(usize, usize) -> (usize, usize)>(&self, f: F) -> Self {
2417        let (start, end) = f(self.start, self.end);
2418
2419        Self { start, end }
2420    }
2421
2422    /// Map the current end of the Span to a new value.
2423    ///
2424    /// # Examples
2425    ///
2426    /// ```
2427    /// use aiken_lang::ast::Span;
2428    ///
2429    /// let span = Span { start: 0, end: 1 };
2430    ///
2431    /// let other = span.map_end(|end| end + 1);
2432    ///
2433    /// assert_eq!(other.start, 0);
2434    /// assert_eq!(other.end, 2);
2435    /// ```
2436    pub fn map_end<F: FnOnce(usize) -> usize>(&self, f: F) -> Self {
2437        Self {
2438            start: self.start,
2439            end: f(self.end),
2440        }
2441    }
2442
2443    pub fn contains(&self, byte_index: usize) -> bool {
2444        byte_index >= self.start && byte_index < self.end
2445    }
2446}
2447
2448impl fmt::Debug for Span {
2449    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2450        write!(f, "{:?}", self.range())
2451    }
2452}
2453
2454impl chumsky::Span for Span {
2455    type Context = ();
2456
2457    type Offset = usize;
2458
2459    fn new(_context: Self::Context, range: Range<Self::Offset>) -> Self {
2460        assert!(range.start <= range.end);
2461
2462        Self {
2463            start: range.start,
2464            end: range.end,
2465        }
2466    }
2467
2468    fn context(&self) -> Self::Context {}
2469
2470    fn start(&self) -> Self::Offset {
2471        self.start
2472    }
2473
2474    fn end(&self) -> Self::Offset {
2475        self.end
2476    }
2477}
2478
2479#[derive(Debug, Clone, PartialEq, Eq)]
2480pub enum LogicalOpChainKind {
2481    And,
2482    Or,
2483}
2484
2485impl Display for LogicalOpChainKind {
2486    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2487        match self {
2488            LogicalOpChainKind::And => write!(f, "and"),
2489            LogicalOpChainKind::Or => write!(f, "or"),
2490        }
2491    }
2492}
2493
2494#[derive(Debug, thiserror::Error, Diagnostic)]
2495pub enum Error {
2496    #[error(
2497      "I realized the module '{}' contains the keyword '{}', which is forbidden.\n",
2498      name.if_supports_color(Stdout, |s| s.purple()),
2499      keyword.if_supports_color(Stdout, |s| s.purple())
2500    )]
2501    #[diagnostic(url("https://aiken-lang.org/language-tour/modules"))]
2502    #[diagnostic(code("illegal::module_name"))]
2503    #[diagnostic(help(r#"You cannot use keywords as part of a module path name. As a quick reminder, here's a list of all the keywords (and thus, of invalid module path names):
2504
2505    as, expect, check, const, else, fn, if, is, let, opaque, pub, test, todo, trace, type, use, when"#))]
2506    KeywordInModuleName { name: String, keyword: String },
2507
2508    #[error("I realized you used '{}' as a module name, which is reserved (and not available).\n",
2509        name.if_supports_color(Stdout, |s| s.purple())
2510    )]
2511    #[diagnostic(code("illegal::module_name"))]
2512    #[diagnostic(help(r#"Some module names are reserved for internal use. This the case of:
2513
2514- aiken: where the prelude is located;
2515- aiken/builtin: where I store low-level Plutus builtins.
2516
2517Note that 'aiken' is also imported by default; but you can refer to it explicitly to disambiguate with a local value that would clash with one from that module."#
2518    ))]
2519    ReservedModuleName { name: String },
2520}