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                comment: None,
1084            }),
1085        }
1086    }
1087}
1088
1089#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1090pub struct UntypedArg {
1091    pub by: ArgBy,
1092    pub location: Span,
1093    pub annotation: Option<Annotation>,
1094    pub doc: Option<String>,
1095    pub is_validator_param: bool,
1096}
1097
1098impl UntypedArg {
1099    pub fn arg_name(&self, ix: usize) -> ArgName {
1100        match self.by {
1101            ArgBy::ByName(ref name) => name.clone(),
1102            ArgBy::ByPattern(..) => {
1103                // NOTE: We use ordinal here not only because it's cute, but because
1104                // such a name cannot be parsed to begin with and thus, will not clash
1105                // with any user-defined name.
1106                let name = format!("{}{}_arg", ix + 1, Ordinal::<usize>(ix + 1).suffix());
1107                ArgName::Named {
1108                    label: name.clone(),
1109                    name,
1110                    location: self.location,
1111                }
1112            }
1113        }
1114    }
1115
1116    pub fn set_type(self, tipo: Rc<Type>, ix: usize) -> TypedArg {
1117        TypedArg {
1118            tipo,
1119            arg_name: self.arg_name(ix),
1120            location: self.location,
1121            annotation: self.annotation,
1122            is_validator_param: self.is_validator_param,
1123            doc: self.doc,
1124        }
1125    }
1126}
1127
1128#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1129pub struct TypedArg {
1130    pub arg_name: ArgName,
1131    pub location: Span,
1132    pub annotation: Option<Annotation>,
1133    pub doc: Option<String>,
1134    pub is_validator_param: bool,
1135    pub tipo: Rc<Type>,
1136}
1137
1138impl TypedArg {
1139    pub fn new(name: &str, tipo: Rc<Type>) -> Self {
1140        TypedArg {
1141            arg_name: ArgName::Named {
1142                name: name.to_string(),
1143                label: name.to_string(),
1144                location: Span::empty(),
1145            },
1146            location: Span::empty(),
1147            annotation: None,
1148            doc: None,
1149            is_validator_param: false,
1150            tipo: tipo.clone(),
1151        }
1152    }
1153
1154    pub fn put_doc(&mut self, new_doc: String) {
1155        self.doc = Some(new_doc);
1156    }
1157
1158    pub fn get_variable_name(&self) -> Option<&str> {
1159        self.arg_name.get_variable_name()
1160    }
1161
1162    pub fn get_name(&self) -> String {
1163        self.arg_name.get_name()
1164    }
1165
1166    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
1167        if self.arg_name.location().contains(byte_index) {
1168            Some(Located::Argument(&self.arg_name, self.tipo.clone()))
1169        } else {
1170            self.annotation
1171                .as_ref()
1172                .and_then(|annotation| annotation.find_node(byte_index))
1173        }
1174    }
1175}
1176
1177pub type TypedArgVia = ArgVia<TypedArg, TypedExpr>;
1178pub type UntypedArgVia = ArgVia<UntypedArg, UntypedExpr>;
1179
1180#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1181pub struct ArgVia<Arg, Expr> {
1182    pub arg: Arg,
1183    pub via: Expr,
1184}
1185
1186impl<Expr> From<ArgVia<TypedArg, Expr>> for TypedArg {
1187    fn from(this: ArgVia<TypedArg, Expr>) -> TypedArg {
1188        this.arg
1189    }
1190}
1191
1192impl<Expr> From<ArgVia<UntypedArg, Expr>> for UntypedArg {
1193    fn from(this: ArgVia<UntypedArg, Expr>) -> UntypedArg {
1194        this.arg
1195    }
1196}
1197
1198impl TypedArgVia {
1199    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
1200        if self.arg.arg_name.location().contains(byte_index) {
1201            Some(Located::Argument(&self.arg.arg_name, self.arg.tipo.clone()))
1202        } else {
1203            // `via` is done first here because when there is no manually written
1204            // annotation, it seems one is injected leading to a `found` returning too early
1205            // because the span of the filled in annotation matches the span of the via expr.
1206            self.via.find_node(byte_index).or_else(|| {
1207                self.arg
1208                    .annotation
1209                    .as_ref()
1210                    .and_then(|annotation| annotation.find_node(byte_index))
1211            })
1212        }
1213    }
1214}
1215
1216#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1217pub enum ArgName {
1218    Discarded {
1219        name: String,
1220        label: String,
1221        location: Span,
1222    },
1223    Named {
1224        name: String,
1225        label: String,
1226        location: Span,
1227    },
1228}
1229
1230impl ArgName {
1231    pub fn location(&self) -> Span {
1232        match self {
1233            ArgName::Discarded { location, .. } => *location,
1234            ArgName::Named { location, .. } => *location,
1235        }
1236    }
1237
1238    /// Returns the name of the variable if it is named, otherwise None.
1239    /// Code gen uses the fact that this returns None to do certain things.
1240    pub fn get_variable_name(&self) -> Option<&str> {
1241        match self {
1242            ArgName::Discarded { .. } => None,
1243            ArgName::Named { name, .. } => Some(name),
1244        }
1245    }
1246
1247    pub fn get_name(&self) -> String {
1248        match self {
1249            ArgName::Discarded { name, .. } | ArgName::Named { name, .. } => name.clone(),
1250        }
1251    }
1252
1253    pub fn get_label(&self) -> String {
1254        match self {
1255            ArgName::Discarded { label, .. } | ArgName::Named { label, .. } => label.to_string(),
1256        }
1257    }
1258}
1259
1260#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1261pub struct UnqualifiedImport {
1262    pub location: Span,
1263    pub name: String,
1264    pub as_name: Option<String>,
1265}
1266
1267impl UnqualifiedImport {
1268    pub fn variable_name(&self) -> &str {
1269        self.as_name.as_deref().unwrap_or(&self.name)
1270    }
1271}
1272
1273// TypeAst
1274#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
1275pub enum Annotation {
1276    Constructor {
1277        location: Span,
1278        module: Option<String>,
1279        name: String,
1280        arguments: Vec<Self>,
1281    },
1282
1283    Fn {
1284        location: Span,
1285        arguments: Vec<Self>,
1286        ret: Box<Self>,
1287    },
1288
1289    Var {
1290        location: Span,
1291        name: String,
1292    },
1293
1294    Hole {
1295        location: Span,
1296        name: String,
1297    },
1298
1299    Tuple {
1300        location: Span,
1301        elems: Vec<Self>,
1302    },
1303
1304    Pair {
1305        location: Span,
1306        fst: Box<Self>,
1307        snd: Box<Self>,
1308    },
1309}
1310
1311impl Annotation {
1312    pub fn location(&self) -> Span {
1313        match self {
1314            Annotation::Fn { location, .. }
1315            | Annotation::Tuple { location, .. }
1316            | Annotation::Var { location, .. }
1317            | Annotation::Hole { location, .. }
1318            | Annotation::Constructor { location, .. }
1319            | Annotation::Pair { location, .. } => *location,
1320        }
1321    }
1322
1323    pub fn boolean(location: Span) -> Self {
1324        Annotation::Constructor {
1325            name: "Bool".to_string(),
1326            module: None,
1327            arguments: vec![],
1328            location,
1329        }
1330    }
1331
1332    pub fn int(location: Span) -> Self {
1333        Annotation::Constructor {
1334            name: "Int".to_string(),
1335            module: None,
1336            arguments: vec![],
1337            location,
1338        }
1339    }
1340
1341    pub fn bytearray(location: Span) -> Self {
1342        Annotation::Constructor {
1343            name: "ByteArray".to_string(),
1344            module: None,
1345            arguments: vec![],
1346            location,
1347        }
1348    }
1349
1350    pub fn data(location: Span) -> Self {
1351        Annotation::Constructor {
1352            name: "Data".to_string(),
1353            module: None,
1354            arguments: vec![],
1355            location,
1356        }
1357    }
1358
1359    pub fn option(inner: Annotation) -> Self {
1360        Annotation::Constructor {
1361            name: "Option".to_string(),
1362            module: None,
1363            location: inner.location(),
1364            arguments: vec![inner],
1365        }
1366    }
1367
1368    pub fn list(inner: Annotation, location: Span) -> Self {
1369        Annotation::Constructor {
1370            name: "List".to_string(),
1371            module: None,
1372            arguments: vec![inner],
1373            location,
1374        }
1375    }
1376
1377    pub fn tuple(elems: Vec<Annotation>, location: Span) -> Self {
1378        Annotation::Tuple { elems, location }
1379    }
1380
1381    pub fn is_logically_equal(&self, other: &Annotation) -> bool {
1382        match self {
1383            Annotation::Constructor {
1384                module,
1385                name,
1386                arguments,
1387                location: _,
1388            } => match other {
1389                Annotation::Constructor {
1390                    module: o_module,
1391                    name: o_name,
1392                    arguments: o_arguments,
1393                    location: _,
1394                } => {
1395                    module == o_module
1396                        && name == o_name
1397                        && arguments.len() == o_arguments.len()
1398                        && arguments
1399                            .iter()
1400                            .zip(o_arguments)
1401                            .all(|a| a.0.is_logically_equal(a.1))
1402                }
1403                _ => false,
1404            },
1405            Annotation::Tuple { elems, location: _ } => match other {
1406                Annotation::Tuple {
1407                    elems: o_elems,
1408                    location: _,
1409                } => {
1410                    elems.len() == o_elems.len()
1411                        && elems
1412                            .iter()
1413                            .zip(o_elems)
1414                            .all(|a| a.0.is_logically_equal(a.1))
1415                }
1416                _ => false,
1417            },
1418            Annotation::Fn {
1419                arguments,
1420                ret,
1421                location: _,
1422            } => match other {
1423                Annotation::Fn {
1424                    arguments: o_arguments,
1425                    ret: o_return,
1426                    location: _,
1427                } => {
1428                    arguments.len() == o_arguments.len()
1429                        && arguments
1430                            .iter()
1431                            .zip(o_arguments)
1432                            .all(|a| a.0.is_logically_equal(a.1))
1433                        && ret.is_logically_equal(o_return)
1434                }
1435                _ => false,
1436            },
1437            Annotation::Var { name, location: _ } => match other {
1438                Annotation::Var {
1439                    name: o_name,
1440                    location: _,
1441                } => name == o_name,
1442                _ => false,
1443            },
1444
1445            Annotation::Hole { name, location: _ } => match other {
1446                Annotation::Hole {
1447                    name: o_name,
1448                    location: _,
1449                } => name == o_name,
1450                _ => false,
1451            },
1452            Annotation::Pair { fst, snd, .. } => {
1453                if let Annotation::Pair {
1454                    fst: o_fst,
1455                    snd: o_snd,
1456                    ..
1457                } = other
1458                {
1459                    fst.is_logically_equal(o_fst) && snd.is_logically_equal(o_snd)
1460                } else {
1461                    false
1462                }
1463            }
1464        }
1465    }
1466
1467    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
1468        if !self.location().contains(byte_index) {
1469            return None;
1470        }
1471
1472        let located = match self {
1473            Annotation::Constructor { arguments, .. } => {
1474                arguments.iter().find_map(|arg| arg.find_node(byte_index))
1475            }
1476            Annotation::Fn { arguments, ret, .. } => arguments
1477                .iter()
1478                .find_map(|arg| arg.find_node(byte_index))
1479                .or_else(|| ret.find_node(byte_index)),
1480            Annotation::Tuple { elems, .. } => {
1481                elems.iter().find_map(|arg| arg.find_node(byte_index))
1482            }
1483            Annotation::Var { .. } | Annotation::Hole { .. } => None,
1484            Annotation::Pair { fst, snd, .. } => fst
1485                .find_node(byte_index)
1486                .or_else(|| snd.find_node(byte_index)),
1487        };
1488
1489        located.or(Some(Located::Annotation(self)))
1490    }
1491}
1492
1493#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1494pub enum BinOp {
1495    // Boolean logic
1496    And,
1497    Or,
1498
1499    // Equality
1500    Eq,
1501    NotEq,
1502
1503    // Order comparison
1504    LtInt,
1505    LtEqInt,
1506    GtEqInt,
1507    GtInt,
1508
1509    // Maths
1510    AddInt,
1511    SubInt,
1512    MultInt,
1513    DivInt,
1514    ModInt,
1515}
1516
1517impl From<LogicalOpChainKind> for BinOp {
1518    fn from(value: LogicalOpChainKind) -> Self {
1519        match value {
1520            LogicalOpChainKind::And => BinOp::And,
1521            LogicalOpChainKind::Or => BinOp::Or,
1522        }
1523    }
1524}
1525
1526#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1527pub enum UnOp {
1528    /// !
1529    Not,
1530    /// -
1531    Negate,
1532}
1533
1534impl BinOp {
1535    pub fn precedence(&self) -> u8 {
1536        // Ensure that this matches the other precedence function for guards
1537        match self {
1538            // Pipe is 0
1539            // Unary operators are 1
1540            Self::Or => 2,
1541
1542            Self::And => 3,
1543
1544            Self::Eq | Self::NotEq | Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => 4,
1545
1546            // Concatenation operators are typically 5, so we skip it.
1547            Self::AddInt | Self::SubInt => 6,
1548
1549            Self::MultInt | Self::DivInt | Self::ModInt => 7,
1550        }
1551    }
1552}
1553
1554pub type UntypedPattern = Pattern<(), (), Namespace, (u8, Span)>;
1555pub type TypedPattern = Pattern<PatternConstructor, Rc<Type>, String, u8>;
1556
1557impl TypedPattern {
1558    pub fn var(name: &str) -> Self {
1559        TypedPattern::Var {
1560            name: name.to_string(),
1561            location: Span::empty(),
1562        }
1563    }
1564
1565    pub fn constructor(
1566        name: &str,
1567        arguments: &[CallArg<TypedPattern>],
1568        tipo: Rc<Type>,
1569        location: Span,
1570    ) -> Self {
1571        TypedPattern::Constructor {
1572            is_record: false,
1573            location,
1574            name: name.to_string(),
1575            arguments: arguments.to_vec(),
1576            module: None,
1577            constructor: PatternConstructor::Record {
1578                name: name.to_string(),
1579                field_map: None,
1580            },
1581            spread_location: None,
1582            tipo: tipo.clone(),
1583        }
1584    }
1585
1586    pub fn mint_purpose(
1587        (var_purpose_arg, purpose_span): (&str, Span),
1588        redeemer_span: Span,
1589    ) -> Self {
1590        TypedPattern::constructor(
1591            well_known::SCRIPT_PURPOSE_MINT,
1592            &[CallArg::var(var_purpose_arg, purpose_span)],
1593            Type::function(vec![Type::byte_array()], Type::script_purpose()),
1594            redeemer_span,
1595        )
1596    }
1597
1598    pub fn spend_purpose(
1599        (var_purpose_arg, purpose_span): (&str, Span),
1600        (var_datum, datum_span): (&str, Span),
1601        redeemer_span: Span,
1602    ) -> Self {
1603        TypedPattern::constructor(
1604            well_known::SCRIPT_PURPOSE_SPEND,
1605            &[
1606                CallArg::var(var_purpose_arg, purpose_span),
1607                CallArg::var(var_datum, datum_span),
1608            ],
1609            Type::function(
1610                vec![Type::data(), Type::option(Type::data())],
1611                Type::script_purpose(),
1612            ),
1613            redeemer_span,
1614        )
1615    }
1616
1617    pub fn withdraw_purpose(
1618        (var_purpose_arg, purpose_span): (&str, Span),
1619        redeemer_span: Span,
1620    ) -> Self {
1621        TypedPattern::constructor(
1622            well_known::SCRIPT_PURPOSE_WITHDRAW,
1623            &[CallArg::var(var_purpose_arg, purpose_span)],
1624            Type::function(vec![Type::data()], Type::script_purpose()),
1625            redeemer_span,
1626        )
1627    }
1628
1629    pub fn publish_purpose(
1630        (var_purpose_arg, purpose_span): (&str, Span),
1631        redeemer_span: Span,
1632    ) -> Self {
1633        TypedPattern::constructor(
1634            well_known::SCRIPT_PURPOSE_PUBLISH,
1635            &[
1636                CallArg::var("__discarded_purpose_ix__", purpose_span),
1637                CallArg::var(var_purpose_arg, purpose_span),
1638            ],
1639            Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
1640            redeemer_span,
1641        )
1642    }
1643
1644    pub fn vote_purpose(
1645        (var_purpose_arg, purpose_span): (&str, Span),
1646        redeemer_span: Span,
1647    ) -> Self {
1648        TypedPattern::constructor(
1649            well_known::SCRIPT_PURPOSE_VOTE,
1650            &[CallArg::var(var_purpose_arg, purpose_span)],
1651            Type::function(vec![Type::data()], Type::script_purpose()),
1652            redeemer_span,
1653        )
1654    }
1655
1656    pub fn propose_purpose(
1657        (var_purpose_arg, purpose_span): (&str, Span),
1658        redeemer_span: Span,
1659    ) -> Self {
1660        TypedPattern::constructor(
1661            well_known::SCRIPT_PURPOSE_PROPOSE,
1662            &[
1663                CallArg::var("__discarded_purpose_ix__", purpose_span),
1664                CallArg::var(var_purpose_arg, purpose_span),
1665            ],
1666            Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
1667            redeemer_span,
1668        )
1669    }
1670}
1671
1672#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1673pub enum Namespace {
1674    Module(String),
1675    Type(Option<String>, String),
1676}
1677
1678#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
1679pub enum Pattern<Constructor, Type, NamespaceKind, ByteValue> {
1680    Int {
1681        location: Span,
1682        value: String,
1683        base: Base,
1684    },
1685
1686    ByteArray {
1687        location: Span,
1688        value: Vec<ByteValue>,
1689        preferred_format: ByteArrayFormatPreference,
1690    },
1691
1692    /// The creation of a variable.
1693    /// e.g. `expect [this_is_a_var, .._] = x`
1694    /// e.g. `let foo = 42`
1695    Var {
1696        location: Span,
1697        name: String,
1698    },
1699
1700    /// A name given to a sub-pattern using the `as` keyword.
1701    ///
1702    /// ```aiken
1703    /// when foo is {
1704    ///    [_, _] as the_list -> ...
1705    /// }
1706    /// ```
1707    Assign {
1708        name: String,
1709        location: Span,
1710        pattern: Box<Self>,
1711    },
1712
1713    /// A pattern that binds to any value but does not assign a variable.
1714    /// Always starts with an underscore.
1715    Discard {
1716        name: String,
1717        location: Span,
1718    },
1719
1720    List {
1721        location: Span,
1722        elements: Vec<Self>,
1723        tail: Option<Box<Self>>,
1724    },
1725
1726    /// The constructor for a custom type. Starts with an uppercase letter.
1727    Constructor {
1728        is_record: bool,
1729        location: Span,
1730        name: String,
1731        arguments: Vec<CallArg<Self>>,
1732        module: Option<NamespaceKind>,
1733        constructor: Constructor,
1734        spread_location: Option<Span>,
1735        tipo: Type,
1736    },
1737
1738    Pair {
1739        location: Span,
1740        fst: Box<Self>,
1741        snd: Box<Self>,
1742    },
1743
1744    Tuple {
1745        location: Span,
1746        elems: Vec<Self>,
1747    },
1748}
1749
1750impl<A, B, C, BV> Pattern<A, B, C, BV> {
1751    pub fn location(&self) -> Span {
1752        match self {
1753            Pattern::Assign { pattern, .. } => pattern.location(),
1754            Pattern::Int { location, .. }
1755            | Pattern::Var { location, .. }
1756            | Pattern::List { location, .. }
1757            | Pattern::Discard { location, .. }
1758            | Pattern::Tuple { location, .. }
1759            | Pattern::Pair { location, .. }
1760            | Pattern::ByteArray { location, .. }
1761            | Pattern::Constructor { location, .. } => *location,
1762        }
1763    }
1764
1765    /// Returns true when a Pattern can be displayed in a flex-break manner (i.e. tries to fit as
1766    /// much as possible on a single line). When false, long lines with several of those patterns
1767    /// will be broken down to one pattern per line.
1768    pub fn is_simple_pattern_to_format(&self) -> bool {
1769        match self {
1770            Self::ByteArray { .. } | Self::Int { .. } | Self::Var { .. } | Self::Discard { .. } => {
1771                true
1772            }
1773            Self::Pair { fst, snd, .. } => {
1774                fst.is_simple_pattern_to_format() && snd.is_simple_pattern_to_format()
1775            }
1776            Self::Tuple { elems, .. } => elems.iter().all(|e| e.is_simple_pattern_to_format()),
1777            Self::List { elements, .. } if elements.len() <= 3 => {
1778                elements.iter().all(|e| e.is_simple_pattern_to_format())
1779            }
1780            Self::Constructor { arguments, .. } => arguments.is_empty(),
1781            _ => false,
1782        }
1783    }
1784
1785    pub fn with_spread(&self) -> bool {
1786        match self {
1787            Pattern::Constructor {
1788                spread_location, ..
1789            } => spread_location.is_some(),
1790            _ => false,
1791        }
1792    }
1793
1794    /// Returns `true` if the pattern is [`Discard`].
1795    ///
1796    /// [`Discard`]: Pattern::Discard
1797    pub fn is_discard(&self) -> bool {
1798        matches!(self, Self::Discard { .. })
1799    }
1800
1801    /// Returns `true` if the pattern is [`Var`].
1802    ///
1803    /// [`Var`]: Pattern::Discard
1804    pub fn is_var(&self) -> bool {
1805        matches!(self, Self::Var { .. })
1806    }
1807}
1808
1809impl UntypedPattern {
1810    pub fn true_(location: Span) -> UntypedPattern {
1811        UntypedPattern::Constructor {
1812            location,
1813            name: "True".to_string(),
1814            arguments: vec![],
1815            constructor: (),
1816            spread_location: None,
1817            tipo: (),
1818            module: None,
1819            is_record: false,
1820        }
1821    }
1822
1823    pub fn collect_identifiers<F>(&self, collect: &mut F)
1824    where
1825        F: FnMut((String, Span)),
1826    {
1827        match self {
1828            Pattern::Var { name, location } => {
1829                collect((name.to_string(), *location));
1830            }
1831            Pattern::List { elements, .. } => {
1832                elements.iter().for_each(|e| e.collect_identifiers(collect));
1833            }
1834            Pattern::Pair { fst, snd, .. } => {
1835                fst.collect_identifiers(collect);
1836                snd.collect_identifiers(collect);
1837            }
1838            Pattern::Tuple { elems, .. } => {
1839                elems.iter().for_each(|e| e.collect_identifiers(collect));
1840            }
1841            Pattern::Constructor { arguments, .. } => {
1842                arguments
1843                    .iter()
1844                    .for_each(|arg| arg.value.collect_identifiers(collect));
1845            }
1846            Pattern::Int { .. }
1847            | Pattern::ByteArray { .. }
1848            | Pattern::Discard { .. }
1849            | Pattern::Assign { .. } => {}
1850        }
1851    }
1852}
1853
1854impl TypedPattern {
1855    pub fn find_node<'a>(&'a self, byte_index: usize, value: &Rc<Type>) -> Option<Located<'a>> {
1856        if !self.location().contains(byte_index) {
1857            return None;
1858        }
1859
1860        match self {
1861            Pattern::Int { .. }
1862            | Pattern::Var { .. }
1863            | Pattern::Assign { .. }
1864            | Pattern::ByteArray { .. }
1865            | Pattern::Discard { .. } => Some(Located::Pattern(self, value.clone())),
1866
1867            Pattern::List { elements, .. }
1868            | Pattern::Tuple {
1869                elems: elements, ..
1870            } => match &**value {
1871                Type::Tuple { elems, .. } => elements
1872                    .iter()
1873                    .zip(elems.iter())
1874                    .find_map(|(e, t)| e.find_node(byte_index, t))
1875                    .or(Some(Located::Pattern(self, value.clone()))),
1876                Type::App {
1877                    module, name, args, ..
1878                } if module.is_empty() && name == "List" => elements
1879                    .iter()
1880                    // this is the same as above but this uses
1881                    // cycle to repeat the single type arg for a list
1882                    // there's probably a cleaner way to re-use the code
1883                    // from this branch and the above.
1884                    .zip(args.iter().cycle())
1885                    .find_map(|(e, t)| e.find_node(byte_index, t))
1886                    .or(Some(Located::Pattern(self, value.clone()))),
1887                _ => None,
1888            },
1889
1890            Pattern::Pair { fst, snd, .. } => match &**value {
1891                Type::Pair {
1892                    fst: fst_v,
1893                    snd: snd_v,
1894                    ..
1895                } => [fst, snd]
1896                    .into_iter()
1897                    .zip([fst_v, snd_v].iter())
1898                    .find_map(|(e, t)| e.find_node(byte_index, t))
1899                    .or(Some(Located::Pattern(self, value.clone()))),
1900                _ => None,
1901            },
1902
1903            Pattern::Constructor {
1904                arguments, tipo, ..
1905            } => match &**tipo {
1906                Type::Fn { args, .. } => arguments
1907                    .iter()
1908                    .zip(args.iter())
1909                    .find_map(|(e, t)| e.value.find_node(byte_index, t))
1910                    .or(Some(Located::Pattern(self, value.clone()))),
1911                _ => None,
1912            },
1913        }
1914    }
1915
1916    // TODO: This function definition is weird, see where this is used and how.
1917    pub fn tipo(&self, value: &TypedExpr) -> Option<Rc<Type>> {
1918        match self {
1919            Pattern::Int { .. } => Some(Type::int()),
1920            Pattern::ByteArray { .. } => Some(Type::byte_array()),
1921            Pattern::Constructor { tipo, .. } => Some(tipo.clone()),
1922            Pattern::Var { .. } | Pattern::Assign { .. } | Pattern::Discard { .. } => {
1923                Some(value.tipo())
1924            }
1925            Pattern::List { .. } | Pattern::Tuple { .. } | Pattern::Pair { .. } => None,
1926        }
1927    }
1928}
1929
1930#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
1931pub enum ByteArrayFormatPreference {
1932    HexadecimalString,
1933    ArrayOfBytes(Base),
1934    Utf8String,
1935}
1936
1937#[derive(Debug, Clone, PartialEq, Eq, Copy)]
1938pub enum CurveType {
1939    Bls12_381(Bls12_381PointType),
1940}
1941
1942impl Display for CurveType {
1943    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1944        match self {
1945            CurveType::Bls12_381(point) => write!(f, "<Bls12_381, {point}>"),
1946        }
1947    }
1948}
1949impl From<&Curve> for CurveType {
1950    fn from(value: &Curve) -> Self {
1951        match value {
1952            Curve::Bls12_381(point) => CurveType::Bls12_381(point.into()),
1953        }
1954    }
1955}
1956
1957#[derive(Debug, Clone, PartialEq, Eq, Copy)]
1958pub enum Bls12_381PointType {
1959    G1,
1960    G2,
1961}
1962
1963impl From<&Bls12_381Point> for Bls12_381PointType {
1964    fn from(value: &Bls12_381Point) -> Self {
1965        match value {
1966            Bls12_381Point::G1(_) => Bls12_381PointType::G1,
1967            Bls12_381Point::G2(_) => Bls12_381PointType::G2,
1968        }
1969    }
1970}
1971
1972impl Display for Bls12_381PointType {
1973    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1974        match self {
1975            Bls12_381PointType::G1 => write!(f, "G1"),
1976            Bls12_381PointType::G2 => write!(f, "G2"),
1977        }
1978    }
1979}
1980
1981#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
1982pub enum Curve {
1983    Bls12_381(Bls12_381Point),
1984}
1985
1986impl Curve {
1987    pub fn compress(&self) -> Vec<u8> {
1988        match self {
1989            Curve::Bls12_381(point) => match point {
1990                Bls12_381Point::G1(g1) => g1.compress(),
1991                Bls12_381Point::G2(g2) => g2.compress(),
1992            },
1993        }
1994    }
1995
1996    pub fn tipo(&self) -> Rc<Type> {
1997        match self {
1998            Curve::Bls12_381(point) => point.tipo(),
1999        }
2000    }
2001}
2002
2003#[derive(Debug, Clone, PartialEq, Eq, Copy)]
2004pub enum Bls12_381Point {
2005    G1(blst::blst_p1),
2006    G2(blst::blst_p2),
2007}
2008
2009impl serde::Serialize for Bls12_381Point {
2010    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2011    where
2012        S: serde::Serializer,
2013    {
2014        match *self {
2015            Bls12_381Point::G1(ref p1) => {
2016                // Assuming `to_bytes` for compression to Vec<u8>
2017                let bytes = p1.compress();
2018
2019                // Serialize as a tuple with a tag for differentiation
2020                serializer.serialize_newtype_variant("Bls12_381Point", 0, "G1", &bytes)
2021            }
2022            Bls12_381Point::G2(ref p2) => {
2023                let bytes = p2.compress();
2024
2025                serializer.serialize_newtype_variant("Bls12_381Point", 1, "G2", &bytes)
2026            }
2027        }
2028    }
2029}
2030
2031impl<'de> serde::Deserialize<'de> for Bls12_381Point {
2032    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2033    where
2034        D: serde::Deserializer<'de>,
2035    {
2036        enum Field {
2037            G1,
2038            G2,
2039        }
2040
2041        impl<'de> serde::Deserialize<'de> for Field {
2042            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
2043            where
2044                D: serde::Deserializer<'de>,
2045            {
2046                struct FieldVisitor;
2047
2048                impl serde::de::Visitor<'_> for FieldVisitor {
2049                    type Value = Field;
2050
2051                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2052                        formatter.write_str("`G1` or `G2`")
2053                    }
2054
2055                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
2056                    where
2057                        E: serde::de::Error,
2058                    {
2059                        match value {
2060                            "G1" => Ok(Field::G1),
2061                            "G2" => Ok(Field::G2),
2062                            _ => Err(serde::de::Error::unknown_field(value, FIELDS)),
2063                        }
2064                    }
2065                }
2066
2067                deserializer.deserialize_identifier(FieldVisitor)
2068            }
2069        }
2070
2071        struct Bls12_381PointVisitor;
2072
2073        impl<'de> serde::de::Visitor<'de> for Bls12_381PointVisitor {
2074            type Value = Bls12_381Point;
2075
2076            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2077                formatter.write_str("struct Bls12_381Point")
2078            }
2079
2080            fn visit_seq<V>(self, mut seq: V) -> Result<Bls12_381Point, V::Error>
2081            where
2082                V: serde::de::SeqAccess<'de>,
2083            {
2084                let tag = seq
2085                    .next_element::<Field>()?
2086                    .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
2087
2088                let bytes = seq
2089                    .next_element::<Vec<u8>>()?
2090                    .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
2091
2092                match tag {
2093                    Field::G1 => {
2094                        let p1 =
2095                            blst::blst_p1::uncompress(&bytes).map_err(serde::de::Error::custom)?;
2096
2097                        Ok(Bls12_381Point::G1(p1))
2098                    }
2099                    Field::G2 => {
2100                        let p2 =
2101                            blst::blst_p2::uncompress(&bytes).map_err(serde::de::Error::custom)?;
2102
2103                        Ok(Bls12_381Point::G2(p2))
2104                    }
2105                }
2106            }
2107        }
2108
2109        const FIELDS: &[&str] = &["G1", "G2"];
2110
2111        deserializer.deserialize_enum("Bls12_381Point", FIELDS, Bls12_381PointVisitor)
2112    }
2113}
2114
2115impl Bls12_381Point {
2116    pub fn tipo(&self) -> Rc<Type> {
2117        match self {
2118            Bls12_381Point::G1(_) => Type::g1_element(),
2119            Bls12_381Point::G2(_) => Type::g2_element(),
2120        }
2121    }
2122}
2123
2124impl Default for Bls12_381Point {
2125    fn default() -> Self {
2126        Bls12_381Point::G1(Default::default())
2127    }
2128}
2129
2130#[derive(Debug, Clone, PartialEq)]
2131pub struct AssignmentPattern {
2132    pub pattern: UntypedPattern,
2133    pub annotation: Option<Annotation>,
2134    pub location: Span,
2135}
2136
2137impl AssignmentPattern {
2138    pub fn new(
2139        pattern: UntypedPattern,
2140        annotation: Option<Annotation>,
2141        location: Span,
2142    ) -> AssignmentPattern {
2143        Self {
2144            pattern,
2145            annotation,
2146            location,
2147        }
2148    }
2149}
2150
2151impl From<AssignmentPattern> for Vec1<AssignmentPattern> {
2152    fn from(value: AssignmentPattern) -> Self {
2153        Vec1::new(value)
2154    }
2155}
2156
2157pub type UntypedAssignmentKind = AssignmentKind<bool>;
2158pub type TypedAssignmentKind = AssignmentKind<()>;
2159
2160#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
2161pub enum AssignmentKind<T> {
2162    Is,
2163    Let { backpassing: T },
2164    Expect { backpassing: T },
2165}
2166
2167impl From<UntypedAssignmentKind> for TypedAssignmentKind {
2168    fn from(kind: UntypedAssignmentKind) -> TypedAssignmentKind {
2169        match kind {
2170            AssignmentKind::Is => AssignmentKind::Is,
2171            AssignmentKind::Let { .. } => AssignmentKind::Let { backpassing: () },
2172            AssignmentKind::Expect { .. } => AssignmentKind::Expect { backpassing: () },
2173        }
2174    }
2175}
2176
2177impl<T> AssignmentKind<T> {
2178    pub fn is_let(&self) -> bool {
2179        matches!(self, AssignmentKind::Let { .. })
2180    }
2181
2182    pub fn is_expect(&self) -> bool {
2183        matches!(self, AssignmentKind::Expect { .. })
2184    }
2185
2186    pub fn if_is(&self) -> bool {
2187        matches!(self, AssignmentKind::Is)
2188    }
2189
2190    pub fn location_offset(&self) -> usize {
2191        match self {
2192            AssignmentKind::Is => 2,
2193            AssignmentKind::Let { .. } => 3,
2194            AssignmentKind::Expect { .. } => 6,
2195        }
2196    }
2197}
2198
2199impl AssignmentKind<bool> {
2200    pub fn is_backpassing(&self) -> bool {
2201        match self {
2202            Self::Is => unreachable!(),
2203            Self::Let { backpassing } | Self::Expect { backpassing } => *backpassing,
2204        }
2205    }
2206}
2207
2208impl<T: Default> AssignmentKind<T> {
2209    pub fn let_() -> Self {
2210        AssignmentKind::Let {
2211            backpassing: Default::default(),
2212        }
2213    }
2214
2215    pub fn is() -> Self {
2216        AssignmentKind::Is
2217    }
2218
2219    pub fn expect() -> Self {
2220        AssignmentKind::Expect {
2221            backpassing: Default::default(),
2222        }
2223    }
2224}
2225
2226pub type MultiPattern<PatternConstructor, Type, NamespaceKind, ByteValue> =
2227    Vec<Pattern<PatternConstructor, Type, NamespaceKind, ByteValue>>;
2228
2229pub type UntypedMultiPattern = MultiPattern<(), (), Namespace, (u8, Span)>;
2230pub type TypedMultiPattern = MultiPattern<PatternConstructor, Rc<Type>, String, u8>;
2231
2232#[derive(Debug, Clone, PartialEq)]
2233pub struct UntypedClause {
2234    pub location: Span,
2235    pub patterns: Vec1<UntypedPattern>,
2236    pub then: UntypedExpr,
2237}
2238
2239#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2240pub struct TypedClause {
2241    pub location: Span,
2242    pub pattern: TypedPattern,
2243    pub then: TypedExpr,
2244}
2245
2246impl TypedClause {
2247    pub fn location(&self) -> Span {
2248        Span {
2249            start: self.pattern.location().start,
2250            end: self.then.location().end,
2251        }
2252    }
2253
2254    pub fn find_node(&self, byte_index: usize, subject_type: &Rc<Type>) -> Option<Located<'_>> {
2255        self.pattern
2256            .find_node(byte_index, subject_type)
2257            .or_else(|| self.then.find_node(byte_index))
2258    }
2259}
2260
2261pub struct UntypedClauseGuard {}
2262
2263pub type TypedIfBranch = IfBranch<TypedExpr, (TypedPattern, Rc<Type>)>;
2264pub type UntypedIfBranch = IfBranch<UntypedExpr, AssignmentPattern>;
2265
2266#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
2267pub struct IfBranch<Expr, Is> {
2268    pub condition: Expr,
2269    pub body: Expr,
2270    pub is: Option<Is>,
2271    pub location: Span,
2272}
2273
2274#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2275pub struct TypedRecordUpdateArg {
2276    pub label: String,
2277    pub location: Span,
2278    pub value: TypedExpr,
2279    pub index: usize,
2280}
2281
2282impl TypedRecordUpdateArg {
2283    pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
2284        self.value.find_node(byte_index)
2285    }
2286}
2287
2288#[derive(Debug, Clone, PartialEq)]
2289pub struct UntypedRecordUpdateArg {
2290    pub label: String,
2291    pub location: Span,
2292    pub value: UntypedExpr,
2293}
2294
2295#[derive(Debug, Clone, PartialEq)]
2296pub struct RecordUpdateSpread {
2297    pub base: Box<UntypedExpr>,
2298    pub location: Span,
2299}
2300
2301#[derive(Debug, Clone, PartialEq, Eq)]
2302pub enum TraceKind {
2303    Trace,
2304    Todo,
2305    Error,
2306}
2307
2308#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2309pub enum Tracing {
2310    UserDefined(TraceLevel),
2311    CompilerGenerated(TraceLevel),
2312    All(TraceLevel),
2313}
2314
2315#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2316pub enum TraceLevel {
2317    Silent,  // No traces
2318    Compact, // Line numbers only
2319    Verbose, // Full verbose traces as provided by the user or the compiler
2320}
2321
2322impl Tracing {
2323    pub fn verbose() -> Self {
2324        Tracing::All(TraceLevel::Verbose)
2325    }
2326
2327    pub fn silent() -> Self {
2328        Tracing::All(TraceLevel::Silent)
2329    }
2330
2331    /// Get the tracing level based on the context we're in.
2332    pub fn trace_level(&self, is_code_gen: bool) -> TraceLevel {
2333        match self {
2334            Tracing::UserDefined(lvl) => {
2335                if is_code_gen {
2336                    TraceLevel::Silent
2337                } else {
2338                    *lvl
2339                }
2340            }
2341            Tracing::CompilerGenerated(lvl) => {
2342                if is_code_gen {
2343                    *lvl
2344                } else {
2345                    TraceLevel::Silent
2346                }
2347            }
2348            Tracing::All(lvl) => *lvl,
2349        }
2350    }
2351}
2352
2353impl Display for TraceLevel {
2354    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
2355        match self {
2356            TraceLevel::Silent => f.write_str("silent"),
2357            TraceLevel::Compact => f.write_str("compact"),
2358            TraceLevel::Verbose => f.write_str("verbose"),
2359        }
2360    }
2361}
2362
2363#[derive(Copy, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
2364pub struct Span {
2365    pub start: usize,
2366    pub end: usize,
2367}
2368
2369impl From<Span> for miette::SourceSpan {
2370    fn from(span: Span) -> Self {
2371        Self::new(span.start.into(), span.end - span.start)
2372    }
2373}
2374
2375impl Span {
2376    pub fn empty() -> Self {
2377        use chumsky::Span;
2378
2379        Self::new((), 0..0)
2380    }
2381
2382    pub fn create(i: usize, n: usize) -> Self {
2383        use chumsky::Span;
2384
2385        Self::new((), i..i + n)
2386    }
2387
2388    pub fn range(&self) -> Range<usize> {
2389        use chumsky::Span;
2390
2391        self.start()..self.end()
2392    }
2393
2394    pub fn union(self, other: Self) -> Self {
2395        use chumsky::Span;
2396
2397        Self {
2398            start: self.start().min(other.start()),
2399            end: self.end().max(other.end()),
2400        }
2401    }
2402
2403    /// Map the current start and end of the Span to new values.
2404    ///
2405    /// # Examples
2406    ///
2407    /// ```
2408    /// use aiken_lang::ast::Span;
2409    ///
2410    /// let span = Span { start: 0, end: 1 };
2411    ///
2412    /// let other = span.map(|start, end| (start + 2, end + 4));
2413    ///
2414    /// assert_eq!(other.start, 2);
2415    /// assert_eq!(other.end, 5);
2416    /// ```
2417    pub fn map<F: FnOnce(usize, usize) -> (usize, usize)>(&self, f: F) -> Self {
2418        let (start, end) = f(self.start, self.end);
2419
2420        Self { start, end }
2421    }
2422
2423    /// Map the current end of the Span to a new value.
2424    ///
2425    /// # Examples
2426    ///
2427    /// ```
2428    /// use aiken_lang::ast::Span;
2429    ///
2430    /// let span = Span { start: 0, end: 1 };
2431    ///
2432    /// let other = span.map_end(|end| end + 1);
2433    ///
2434    /// assert_eq!(other.start, 0);
2435    /// assert_eq!(other.end, 2);
2436    /// ```
2437    pub fn map_end<F: FnOnce(usize) -> usize>(&self, f: F) -> Self {
2438        Self {
2439            start: self.start,
2440            end: f(self.end),
2441        }
2442    }
2443
2444    pub fn contains(&self, byte_index: usize) -> bool {
2445        byte_index >= self.start && byte_index < self.end
2446    }
2447}
2448
2449impl fmt::Debug for Span {
2450    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2451        write!(f, "{:?}", self.range())
2452    }
2453}
2454
2455impl chumsky::Span for Span {
2456    type Context = ();
2457
2458    type Offset = usize;
2459
2460    fn new(_context: Self::Context, range: Range<Self::Offset>) -> Self {
2461        assert!(range.start <= range.end);
2462
2463        Self {
2464            start: range.start,
2465            end: range.end,
2466        }
2467    }
2468
2469    fn context(&self) -> Self::Context {}
2470
2471    fn start(&self) -> Self::Offset {
2472        self.start
2473    }
2474
2475    fn end(&self) -> Self::Offset {
2476        self.end
2477    }
2478}
2479
2480#[derive(Debug, Clone, PartialEq, Eq)]
2481pub enum LogicalOpChainKind {
2482    And,
2483    Or,
2484}
2485
2486impl Display for LogicalOpChainKind {
2487    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2488        match self {
2489            LogicalOpChainKind::And => write!(f, "and"),
2490            LogicalOpChainKind::Or => write!(f, "or"),
2491        }
2492    }
2493}
2494
2495#[derive(Debug, thiserror::Error, Diagnostic)]
2496pub enum Error {
2497    #[error(
2498      "I realized the module '{}' contains the keyword '{}', which is forbidden.\n",
2499      name.if_supports_color(Stdout, |s| s.purple()),
2500      keyword.if_supports_color(Stdout, |s| s.purple())
2501    )]
2502    #[diagnostic(url("https://aiken-lang.org/language-tour/modules"))]
2503    #[diagnostic(code("illegal::module_name"))]
2504    #[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):
2505
2506    as, expect, check, const, else, fn, if, is, let, opaque, pub, test, todo, trace, type, use, when"#))]
2507    KeywordInModuleName { name: String, keyword: String },
2508
2509    #[error("I realized you used '{}' as a module name, which is reserved (and not available).\n",
2510        name.if_supports_color(Stdout, |s| s.purple())
2511    )]
2512    #[diagnostic(code("illegal::module_name"))]
2513    #[diagnostic(help(r#"Some module names are reserved for internal use. This the case of:
2514
2515- aiken: where the prelude is located;
2516- aiken/builtin: where I store low-level Plutus builtins.
2517
2518Note 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."#
2519    ))]
2520    ReservedModuleName { name: String },
2521}