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