1use serde::{Deserialize, Serialize};
12use std::{collections::HashMap, rc::Rc};
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct Scope {
16 pub(crate) symbols: HashMap<String, Symbol>,
17 pub(crate) parent: Option<Rc<Scope>>,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum Symbol {
22 EnvVar(String, Box<Type>),
23 ParamVar(String, Box<Type>),
24 LocalExpr(Box<DataExpr>),
25 Output(usize),
26 Input(Box<InputBlock>),
27 Reference(Box<ReferenceBlock>),
28 PartyDef(Box<PartyDef>),
29 PolicyDef(Box<PolicyDef>),
30 AssetDef(Box<AssetDef>),
31 TypeDef(Box<TypeDef>),
32 AliasDef(Box<AliasDef>),
33 RecordField(Box<RecordField>),
34 VariantCase(Box<VariantCase>),
35 Function(String),
36 Fees,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct Span {
41 dummy: bool,
42 pub start: usize,
43 pub end: usize,
44}
45
46impl Default for Span {
47 fn default() -> Self {
48 Self::DUMMY
49 }
50}
51
52impl Eq for Span {}
53
54impl PartialEq for Span {
55 fn eq(&self, other: &Self) -> bool {
56 if self.dummy || other.dummy {
57 return true;
58 }
59
60 self.start == other.start && self.end == other.end
61 }
62}
63
64impl std::hash::Hash for Span {
65 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
66 self.start.hash(state);
67 self.end.hash(state);
68 }
69}
70
71impl Span {
72 pub const DUMMY: Self = Self {
73 dummy: true,
74 start: 0,
75 end: 0,
76 };
77
78 pub fn new(start: usize, end: usize) -> Self {
79 Self {
80 dummy: false,
81 start,
82 end,
83 }
84 }
85}
86
87impl Symbol {
88 pub fn as_type_def(&self) -> Option<&TypeDef> {
89 match self {
90 Symbol::TypeDef(x) => Some(x.as_ref()),
91 _ => None,
92 }
93 }
94
95 pub fn as_alias_def(&self) -> Option<&AliasDef> {
96 match self {
97 Symbol::AliasDef(x) => Some(x.as_ref()),
98 _ => None,
99 }
100 }
101
102 pub fn as_variant_case(&self) -> Option<&VariantCase> {
103 match self {
104 Symbol::VariantCase(x) => Some(x.as_ref()),
105 _ => None,
106 }
107 }
108
109 pub fn as_field_def(&self) -> Option<&RecordField> {
110 match self {
111 Symbol::RecordField(x) => Some(x.as_ref()),
112 _ => None,
113 }
114 }
115
116 pub fn as_policy_def(&self) -> Option<&PolicyDef> {
117 match self {
118 Symbol::PolicyDef(x) => Some(x.as_ref()),
119 _ => None,
120 }
121 }
122
123 pub fn target_type(&self) -> Option<Type> {
124 match self {
125 Symbol::ParamVar(_, ty) => Some(ty.as_ref().clone()),
126 Symbol::RecordField(x) => Some(x.r#type.clone()),
127 Symbol::Input(x) => x.datum_is().cloned(),
128 Symbol::Reference(x) => x.datum_is.clone(),
129 x => {
130 dbg!(x);
131 None
132 }
133 }
134 }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
138pub struct Identifier {
139 pub value: String,
140 pub span: Span,
141
142 #[serde(skip)]
144 pub(crate) symbol: Option<Symbol>,
145}
146
147impl Identifier {
148 pub fn new(value: impl Into<String>) -> Self {
149 Self {
150 value: value.into(),
151 symbol: None,
152 span: Span::DUMMY,
153 }
154 }
155
156 pub fn try_symbol(&self) -> Result<&Symbol, crate::lowering::Error> {
157 match &self.symbol {
158 Some(symbol) => Ok(symbol),
159 None => Err(crate::lowering::Error::MissingAnalyzePhase(
160 self.value.clone(),
161 )),
162 }
163 }
164
165 pub fn target_type(&self) -> Option<Type> {
166 self.symbol.as_ref().and_then(|x| x.target_type())
167 }
168}
169
170impl AsRef<str> for Identifier {
171 fn as_ref(&self) -> &str {
172 &self.value
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
177pub struct Program {
178 pub env: Option<EnvDef>,
179 pub txs: Vec<TxDef>,
180 pub types: Vec<TypeDef>,
181 pub aliases: Vec<AliasDef>,
182 pub assets: Vec<AssetDef>,
183 pub parties: Vec<PartyDef>,
184 pub policies: Vec<PolicyDef>,
185 pub span: Span,
186
187 #[serde(skip)]
189 pub(crate) scope: Option<Rc<Scope>>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
193pub struct EnvField {
194 pub name: String,
195 pub r#type: Type,
196 #[serde(default, skip_serializing_if = "Option::is_none")]
197 pub docstring: Option<String>,
198 pub span: Span,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
202pub struct EnvDef {
203 pub fields: Vec<EnvField>,
204 pub span: Span,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
208pub struct ParameterList {
209 pub parameters: Vec<ParamDef>,
210 pub span: Span,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
214pub struct TxDef {
215 pub name: Identifier,
216 #[serde(default, skip_serializing_if = "Option::is_none")]
217 pub docstring: Option<String>,
218 pub parameters: ParameterList,
219 pub locals: Option<LocalsBlock>,
220 pub references: Vec<ReferenceBlock>,
221 pub inputs: Vec<InputBlock>,
222 pub outputs: Vec<OutputBlock>,
223 pub validity: Option<ValidityBlock>,
224 pub mints: Vec<MintBlock>,
225 pub burns: Vec<MintBlock>,
226 pub signers: Option<SignersBlock>,
227 pub adhoc: Vec<ChainSpecificBlock>,
228 pub span: Span,
229 pub collateral: Vec<CollateralBlock>,
230 pub metadata: Option<MetadataBlock>,
231
232 #[serde(skip)]
234 pub(crate) scope: Option<Rc<Scope>>,
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
238pub struct LocalsAssign {
239 pub name: Identifier,
240 pub value: DataExpr,
241 pub span: Span,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
245pub struct LocalsBlock {
246 pub assigns: Vec<LocalsAssign>,
247 pub span: Span,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
251pub struct StringLiteral {
252 pub value: String,
253 pub span: Span,
254}
255
256impl StringLiteral {
257 pub fn new(value: impl Into<String>) -> Self {
258 Self {
259 value: value.into(),
260 span: Span::DUMMY,
261 }
262 }
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
266pub struct HexStringLiteral {
267 pub value: String,
268 pub span: Span,
269}
270
271impl HexStringLiteral {
272 pub fn new(value: impl Into<String>) -> Self {
273 Self {
274 value: value.into(),
275 span: Span::DUMMY,
276 }
277 }
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
281pub enum CollateralBlockField {
282 From(DataExpr),
283 MinAmount(DataExpr),
284 Ref(DataExpr),
285}
286
287impl CollateralBlockField {
288 fn key(&self) -> &str {
289 match self {
290 CollateralBlockField::From(_) => "from",
291 CollateralBlockField::MinAmount(_) => "min_amount",
292 CollateralBlockField::Ref(_) => "ref",
293 }
294 }
295
296 pub fn as_data_expr(&self) -> Option<&DataExpr> {
297 match self {
298 CollateralBlockField::Ref(x) => Some(x),
299 _ => None,
300 }
301 }
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
305pub struct CollateralBlock {
306 pub fields: Vec<CollateralBlockField>,
307 pub span: Span,
308}
309
310impl CollateralBlock {
311 pub(crate) fn find(&self, key: &str) -> Option<&CollateralBlockField> {
312 self.fields.iter().find(|x| x.key() == key)
313 }
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
317pub enum InputBlockField {
318 From(DataExpr),
319 DatumIs(Type),
320 MinAmount(DataExpr),
321 Redeemer(DataExpr),
322 Ref(DataExpr),
323}
324
325impl InputBlockField {
326 fn key(&self) -> &str {
327 match self {
328 InputBlockField::From(_) => "from",
329 InputBlockField::DatumIs(_) => "datum_is",
330 InputBlockField::MinAmount(_) => "min_amount",
331 InputBlockField::Redeemer(_) => "redeemer",
332 InputBlockField::Ref(_) => "ref",
333 }
334 }
335
336 pub fn as_data_expr(&self) -> Option<&DataExpr> {
337 match self {
338 InputBlockField::Redeemer(x) => Some(x),
339 InputBlockField::Ref(x) => Some(x),
340 _ => None,
341 }
342 }
343
344 pub fn as_datum_type(&self) -> Option<&Type> {
345 match self {
346 InputBlockField::DatumIs(x) => Some(x),
347 _ => None,
348 }
349 }
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
353pub struct ReferenceBlock {
354 pub name: String,
355 pub r#ref: DataExpr,
356 pub datum_is: Option<Type>,
357 pub span: Span,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
361pub struct MetadataBlockField {
362 pub key: DataExpr,
363 pub value: DataExpr,
364 pub span: Span,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
368pub struct MetadataBlock {
369 pub fields: Vec<MetadataBlockField>,
370 pub span: Span,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
374pub struct InputBlock {
375 pub name: String,
376 pub many: bool,
377 pub fields: Vec<InputBlockField>,
378 pub span: Span,
379}
380
381impl InputBlock {
382 pub(crate) fn find(&self, key: &str) -> Option<&InputBlockField> {
383 self.fields.iter().find(|x| x.key() == key)
384 }
385
386 pub(crate) fn datum_is(&self) -> Option<&Type> {
387 self.find("datum_is").and_then(|x| x.as_datum_type())
388 }
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
392pub enum OutputBlockField {
393 To(Box<DataExpr>),
394 Amount(Box<DataExpr>),
395 Datum(Box<DataExpr>),
396}
397
398impl OutputBlockField {
399 fn key(&self) -> &str {
400 match self {
401 OutputBlockField::To(_) => "to",
402 OutputBlockField::Amount(_) => "amount",
403 OutputBlockField::Datum(_) => "datum",
404 }
405 }
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
409pub struct OutputBlock {
410 pub name: Option<Identifier>,
411 pub optional: bool,
412 pub fields: Vec<OutputBlockField>,
413 pub span: Span,
414}
415
416impl OutputBlock {
417 pub(crate) fn find(&self, key: &str) -> Option<&OutputBlockField> {
418 self.fields.iter().find(|x| x.key() == key)
419 }
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
423pub enum ValidityBlockField {
424 UntilSlot(Box<DataExpr>),
425 SinceSlot(Box<DataExpr>),
426}
427
428impl ValidityBlockField {
429 fn key(&self) -> &str {
430 match self {
431 ValidityBlockField::UntilSlot(_) => "until_slot",
432 ValidityBlockField::SinceSlot(_) => "since_slot",
433 }
434 }
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
438pub struct ValidityBlock {
439 pub fields: Vec<ValidityBlockField>,
440 pub span: Span,
441}
442
443impl ValidityBlock {
444 pub(crate) fn find(&self, key: &str) -> Option<&ValidityBlockField> {
445 self.fields.iter().find(|x| x.key() == key)
446 }
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
450pub enum MintBlockField {
451 Amount(Box<DataExpr>),
452 Redeemer(Box<DataExpr>),
453}
454
455impl MintBlockField {
456 fn key(&self) -> &str {
457 match self {
458 MintBlockField::Amount(_) => "amount",
459 MintBlockField::Redeemer(_) => "redeemer",
460 }
461 }
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
465pub struct MintBlock {
466 pub fields: Vec<MintBlockField>,
467 pub span: Span,
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
471pub struct SignersBlock {
472 pub signers: Vec<DataExpr>,
473 pub span: Span,
474}
475
476impl MintBlock {
477 pub(crate) fn find(&self, key: &str) -> Option<&MintBlockField> {
478 self.fields.iter().find(|x| x.key() == key)
479 }
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
483pub struct RecordField {
484 pub name: Identifier,
485 pub r#type: Type,
486 pub span: Span,
487}
488
489impl RecordField {
490 pub fn new(name: &str, r#type: Type) -> Self {
491 Self {
492 name: Identifier::new(name),
493 r#type,
494 span: Span::DUMMY,
495 }
496 }
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
500pub struct PartyDef {
501 pub name: Identifier,
502 #[serde(default, skip_serializing_if = "Option::is_none")]
503 pub docstring: Option<String>,
504 pub span: Span,
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
508pub struct PartyField {
509 pub name: String,
510 pub party_type: String,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
514pub struct PolicyDef {
515 pub name: Identifier,
516 pub value: PolicyValue,
517 pub span: Span,
518}
519
520#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
521pub enum PolicyField {
522 Hash(DataExpr),
523 Script(DataExpr),
524 Ref(DataExpr),
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
528pub struct PolicyConstructor {
529 pub fields: Vec<PolicyField>,
530 pub span: Span,
531}
532
533impl PolicyConstructor {
534 pub(crate) fn find_field(&self, field: &str) -> Option<&PolicyField> {
535 self.fields.iter().find(|x| match x {
536 PolicyField::Hash(_) => field == "hash",
537 PolicyField::Script(_) => field == "script",
538 PolicyField::Ref(_) => field == "ref",
539 })
540 }
541}
542
543#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
544pub enum PolicyValue {
545 Constructor(PolicyConstructor),
546 Assign(HexStringLiteral),
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
550pub struct AnyAssetConstructor {
551 pub policy: Box<DataExpr>,
552 pub asset_name: Box<DataExpr>,
553 pub amount: Box<DataExpr>,
554 pub span: Span,
555}
556
557impl AnyAssetConstructor {
558 pub fn target_type(&self) -> Option<Type> {
559 Some(Type::AnyAsset)
560 }
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
564pub struct RecordConstructorField {
565 pub name: Identifier,
566 pub value: Box<DataExpr>,
567 pub span: Span,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
571pub struct StructConstructor {
572 pub r#type: Identifier,
573 pub case: VariantCaseConstructor,
574 pub span: Span,
575
576 #[serde(skip)]
578 pub scope: Option<Rc<Scope>>,
579}
580
581impl StructConstructor {
582 pub fn target_type(&self) -> Option<Type> {
583 self.r#type.symbol.as_ref().and_then(|x| x.target_type())
584 }
585}
586
587#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
588pub struct VariantCaseConstructor {
589 pub name: Identifier,
590 pub fields: Vec<RecordConstructorField>,
591 pub spread: Option<Box<DataExpr>>,
592 pub span: Span,
593
594 #[serde(skip)]
596 pub scope: Option<Rc<Scope>>,
597}
598
599impl VariantCaseConstructor {
600 pub fn find_field_value(&self, field: &str) -> Option<&DataExpr> {
601 self.fields
602 .iter()
603 .find(|x| x.name.value == field)
604 .map(|x| x.value.as_ref())
605 }
606}
607
608#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
609pub struct ListConstructor {
610 pub elements: Vec<DataExpr>,
611 pub span: Span,
612}
613
614impl ListConstructor {
615 pub fn target_type(&self) -> Option<Type> {
616 self.elements.first().and_then(|x| x.target_type())
617 }
618}
619
620#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
621pub struct MapField {
622 pub key: DataExpr,
623 pub value: DataExpr,
624 pub span: Span,
625}
626
627impl MapField {
628 pub fn target_type(&self) -> Option<Type> {
629 self.key.target_type()
630 }
631}
632
633#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
634pub struct MapConstructor {
635 pub fields: Vec<MapField>,
636 pub span: Span,
637}
638
639impl MapConstructor {
640 pub fn target_type(&self) -> Option<Type> {
641 if let Some(first_field) = self.fields.first() {
642 let key_type = first_field.key.target_type()?;
643 let value_type = first_field.value.target_type()?;
644 Some(Type::Map(Box::new(key_type), Box::new(value_type)))
645 } else {
646 None
647 }
648 }
649}
650
651#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
652pub struct UtxoRef {
653 pub txid: Vec<u8>,
654 pub index: u64,
655 pub span: Span,
656}
657
658#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
659pub struct NegateOp {
660 pub operand: Box<DataExpr>,
661 pub span: Span,
662}
663
664impl NegateOp {
665 pub fn target_type(&self) -> Option<Type> {
666 self.operand.target_type()
667 }
668}
669
670#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
671pub struct PropertyOp {
672 pub operand: Box<DataExpr>,
673 pub property: Box<DataExpr>,
674 pub span: Span,
675
676 #[serde(skip)]
678 pub(crate) scope: Option<Rc<Scope>>,
679}
680
681impl PropertyOp {
682 pub fn target_type(&self) -> Option<Type> {
683 self.property.target_type()
684 }
685}
686
687#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
688pub struct AddOp {
689 pub lhs: Box<DataExpr>,
690 pub rhs: Box<DataExpr>,
691 pub span: Span,
692}
693
694impl AddOp {
695 pub fn target_type(&self) -> Option<Type> {
696 self.lhs.target_type()
697 }
698}
699
700#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
701pub struct SubOp {
702 pub lhs: Box<DataExpr>,
703 pub rhs: Box<DataExpr>,
704 pub span: Span,
705}
706
707impl SubOp {
708 pub fn target_type(&self) -> Option<Type> {
709 self.lhs.target_type()
710 }
711}
712
713#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
714pub struct ConcatOp {
715 pub lhs: Box<DataExpr>,
716 pub rhs: Box<DataExpr>,
717 pub span: Span,
718}
719
720impl ConcatOp {
721 pub fn target_type(&self) -> Option<Type> {
722 self.lhs.target_type()
723 }
724}
725
726#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
727pub struct FnCall {
728 pub callee: Identifier,
729 pub args: Vec<DataExpr>,
730 pub span: Span,
731}
732
733#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
734pub enum DataExpr {
735 None,
736 Unit,
737 Number(i64),
738 Bool(bool),
739 String(StringLiteral),
740 HexString(HexStringLiteral),
741 StructConstructor(StructConstructor),
742 ListConstructor(ListConstructor),
743 MapConstructor(MapConstructor),
744 AnyAssetConstructor(AnyAssetConstructor),
745 Identifier(Identifier),
746 MinUtxo(Identifier),
747 ComputeTipSlot,
748 SlotToTime(Box<DataExpr>),
749 TimeToSlot(Box<DataExpr>),
750 AddOp(AddOp),
751 SubOp(SubOp),
752 ConcatOp(ConcatOp),
753 NegateOp(NegateOp),
754 PropertyOp(PropertyOp),
755 UtxoRef(UtxoRef),
756 FnCall(FnCall),
757}
758
759impl DataExpr {
760 pub fn as_identifier(&self) -> Option<&Identifier> {
761 match self {
762 DataExpr::Identifier(x) => Some(x),
763 _ => None,
764 }
765 }
766
767 pub fn target_type(&self) -> Option<Type> {
768 match self {
769 DataExpr::Identifier(x) => x.target_type(),
770 DataExpr::None => Some(Type::Undefined),
771 DataExpr::Unit => Some(Type::Unit),
772 DataExpr::Number(_) => Some(Type::Int),
773 DataExpr::Bool(_) => Some(Type::Bool),
774 DataExpr::String(_) => Some(Type::Bytes),
775 DataExpr::HexString(_) => Some(Type::Bytes),
776 DataExpr::StructConstructor(x) => x.target_type(),
777 DataExpr::MapConstructor(x) => x.target_type(),
778 DataExpr::ListConstructor(x) => match x.target_type() {
779 Some(inner) => Some(Type::List(Box::new(inner))),
780 None => None,
781 },
782 DataExpr::AddOp(x) => x.target_type(),
783 DataExpr::SubOp(x) => x.target_type(),
784 DataExpr::ConcatOp(x) => x.target_type(),
785 DataExpr::NegateOp(x) => x.target_type(),
786 DataExpr::PropertyOp(x) => x.target_type(),
787 DataExpr::AnyAssetConstructor(x) => x.target_type(),
788 DataExpr::UtxoRef(_) => Some(Type::UtxoRef),
789 DataExpr::MinUtxo(_) => Some(Type::AnyAsset),
790 DataExpr::ComputeTipSlot => Some(Type::Int),
791 DataExpr::SlotToTime(_) => Some(Type::Int),
792 DataExpr::TimeToSlot(_) => Some(Type::Int),
793 DataExpr::FnCall(_) => None, }
795 }
796}
797
798#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
799pub enum AddressExpr {
800 String(StringLiteral),
801 HexString(HexStringLiteral),
802 Identifier(Identifier),
803}
804
805impl AddressExpr {
806 pub fn as_identifier(&self) -> Option<&Identifier> {
807 match self {
808 AddressExpr::Identifier(x) => Some(x),
809 _ => None,
810 }
811 }
812}
813
814#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
815pub enum Type {
816 Undefined,
817 Unit,
818 Int,
819 Bool,
820 Bytes,
821 Address,
822 Utxo,
823 UtxoRef,
824 AnyAsset,
825 List(Box<Type>),
826 Map(Box<Type>, Box<Type>),
827 Custom(Identifier),
828}
829
830impl std::fmt::Display for Type {
831 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
832 match self {
833 Type::Undefined => write!(f, "Undefined"),
834 Type::Unit => write!(f, "Unit"),
835 Type::Int => write!(f, "Int"),
836 Type::Bool => write!(f, "Bool"),
837 Type::Bytes => write!(f, "Bytes"),
838 Type::Address => write!(f, "Address"),
839 Type::UtxoRef => write!(f, "UtxoRef"),
840 Type::AnyAsset => write!(f, "AnyAsset"),
841 Type::Utxo => write!(f, "Utxo"),
842 Type::Map(key, value) => write!(f, "Map<{}, {}>", key, value),
843 Type::List(inner) => write!(f, "List<{inner}>"),
844 Type::Custom(id) => write!(f, "{}", id.value),
845 }
846 }
847}
848
849impl Type {
850 pub fn properties(&self) -> Vec<(String, Type)> {
851 match self {
852 Type::AnyAsset => {
853 vec![
854 ("amount".to_string(), Type::Int),
855 ("policy".to_string(), Type::Bytes),
856 ("asset_name".to_string(), Type::Bytes),
857 ]
858 }
859 Type::UtxoRef => {
860 vec![
861 ("tx_hash".to_string(), Type::Bytes),
862 ("output_index".to_string(), Type::Int),
863 ]
864 }
865 Type::Custom(identifier) => {
866 let def = identifier.symbol.as_ref().and_then(|s| s.as_type_def());
867
868 match def {
869 Some(ty) if ty.cases.len() == 1 => ty.cases[0]
870 .fields
871 .iter()
872 .map(|f| (f.name.value.clone(), f.r#type.clone()))
873 .collect(),
874 _ => vec![],
875 }
876 }
877 _ => vec![],
878 }
879 }
880
881 pub fn property_index(&self, property: DataExpr) -> Option<DataExpr> {
882 match self {
883 Type::AnyAsset | Type::UtxoRef | Type::Custom(_) => {
884 let identifier = property.as_identifier()?;
885 let properties = Self::properties(self);
886 properties
887 .iter()
888 .position(|(name, _)| name == &identifier.value)
889 .map(|index| DataExpr::Number(index as i64))
890 }
891 Type::List(_) => property
892 .target_type()
893 .filter(|ty| *ty == Type::Int)
894 .map(|_| property),
895 _ => None,
896 }
897 }
898}
899
900#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
901pub struct ParamDef {
902 pub name: Identifier,
903 pub r#type: Type,
904 #[serde(default, skip_serializing_if = "Option::is_none")]
905 pub docstring: Option<String>,
906}
907
908#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
909pub struct AliasDef {
910 pub name: Identifier,
911 pub alias_type: Type,
912 pub span: Span,
913}
914
915impl AliasDef {
916 pub fn resolve_alias_chain(&self) -> Option<&TypeDef> {
917 match &self.alias_type {
918 Type::Custom(identifier) => match &identifier.symbol {
919 Some(Symbol::TypeDef(type_def)) => Some(type_def),
920 Some(Symbol::AliasDef(next_alias)) => next_alias.resolve_alias_chain(),
921 _ => None,
922 },
923 _ => None,
924 }
925 }
926
927 pub fn is_alias_chain_resolved(&self) -> bool {
928 self.resolve_alias_chain().is_some()
929 }
930}
931
932#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
933pub struct TypeDef {
934 pub name: Identifier,
935 pub cases: Vec<VariantCase>,
936 pub span: Span,
937}
938
939impl TypeDef {
940 pub(crate) fn find_case_index(&self, case: &str) -> Option<usize> {
941 self.cases.iter().position(|x| x.name.value == case)
942 }
943
944 #[allow(dead_code)]
945 pub(crate) fn find_case(&self, case: &str) -> Option<&VariantCase> {
946 self.cases.iter().find(|x| x.name.value == case)
947 }
948}
949
950#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
951pub struct VariantCase {
952 pub name: Identifier,
953 pub fields: Vec<RecordField>,
954 pub span: Span,
955}
956
957impl VariantCase {
958 #[allow(dead_code)]
959 pub(crate) fn find_field_index(&self, field: &str) -> Option<usize> {
960 self.fields.iter().position(|x| x.name.value == field)
961 }
962
963 #[allow(dead_code)]
964 pub(crate) fn find_field(&self, field: &str) -> Option<&RecordField> {
965 self.fields.iter().find(|x| x.name.value == field)
966 }
967}
968
969#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
970pub struct AssetDef {
971 pub name: Identifier,
972 pub policy: DataExpr,
973 pub asset_name: DataExpr,
974 pub span: Span,
975}
976
977#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
978pub enum ChainSpecificBlock {
979 Cardano(crate::cardano::CardanoBlock),
980}