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