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 ParamVar(String, Box<Type>),
23 Input(String, Box<Type>),
24 PartyDef(Box<PartyDef>),
25 PolicyDef(Box<PolicyDef>),
26 AssetDef(Box<AssetDef>),
27 TypeDef(Box<TypeDef>),
28 RecordField(Box<RecordField>),
29 VariantCase(Box<VariantCase>),
30 Fees,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Span {
35 dummy: bool,
36 pub start: usize,
37 pub end: usize,
38}
39
40impl Eq for Span {}
41
42impl PartialEq for Span {
43 fn eq(&self, other: &Self) -> bool {
44 if self.dummy || other.dummy {
45 return true;
46 }
47
48 self.start == other.start && self.end == other.end
49 }
50}
51
52impl std::hash::Hash for Span {
53 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
54 self.start.hash(state);
55 self.end.hash(state);
56 }
57}
58
59impl Span {
60 pub const DUMMY: Self = Self {
61 dummy: true,
62 start: 0,
63 end: 0,
64 };
65
66 pub fn new(start: usize, end: usize) -> Self {
67 Self {
68 dummy: false,
69 start,
70 end,
71 }
72 }
73}
74
75impl Symbol {
76 pub fn as_type_def(&self) -> Option<&TypeDef> {
77 match self {
78 Symbol::TypeDef(x) => Some(x.as_ref()),
79 _ => None,
80 }
81 }
82
83 pub fn as_variant_case(&self) -> Option<&VariantCase> {
84 match self {
85 Symbol::VariantCase(x) => Some(x.as_ref()),
86 _ => None,
87 }
88 }
89
90 pub fn as_field_def(&self) -> Option<&RecordField> {
91 match self {
92 Symbol::RecordField(x) => Some(x.as_ref()),
93 _ => None,
94 }
95 }
96
97 pub fn as_policy_def(&self) -> Option<&PolicyDef> {
98 match self {
99 Symbol::PolicyDef(x) => Some(x.as_ref()),
100 _ => None,
101 }
102 }
103
104 pub fn target_type(&self) -> Option<Type> {
105 match self {
106 Symbol::ParamVar(_, ty) => Some(ty.as_ref().clone()),
107 Symbol::RecordField(x) => Some(x.r#type.clone()),
108 Symbol::Input(_, ty) => Some(ty.as_ref().clone()),
109 x => {
110 dbg!(x);
111 None
112 }
113 }
114 }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
118pub struct Identifier {
119 pub value: String,
120 pub span: Span,
121
122 #[serde(skip)]
124 pub(crate) symbol: Option<Symbol>,
125}
126
127impl Identifier {
128 pub fn new(value: impl Into<String>) -> Self {
129 Self {
130 value: value.into(),
131 symbol: None,
132 span: Span::DUMMY,
133 }
134 }
135
136 pub fn try_symbol(&self) -> Result<&Symbol, crate::lowering::Error> {
137 match &self.symbol {
138 Some(symbol) => Ok(symbol),
139 None => Err(crate::lowering::Error::MissingAnalyzePhase),
140 }
141 }
142}
143
144impl AsRef<str> for Identifier {
145 fn as_ref(&self) -> &str {
146 &self.value
147 }
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
151pub struct Program {
152 pub txs: Vec<TxDef>,
153 pub types: Vec<TypeDef>,
154 pub assets: Vec<AssetDef>,
155 pub parties: Vec<PartyDef>,
156 pub policies: Vec<PolicyDef>,
157 pub span: Span,
158
159 #[serde(skip)]
161 pub(crate) scope: Option<Rc<Scope>>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
165pub struct ParameterList {
166 pub parameters: Vec<ParamDef>,
167 pub span: Span,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
171pub struct TxDef {
172 pub name: String,
173 pub parameters: ParameterList,
174 pub references: Vec<ReferenceBlock>,
175 pub inputs: Vec<InputBlock>,
176 pub outputs: Vec<OutputBlock>,
177 pub burn: Option<BurnBlock>,
178 pub mint: Option<MintBlock>,
179 pub adhoc: Vec<ChainSpecificBlock>,
180 pub span: Span,
181 pub collateral: Vec<CollateralBlock>,
182
183 #[serde(skip)]
185 pub(crate) scope: Option<Rc<Scope>>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
189pub struct StringLiteral {
190 pub value: String,
191 pub span: Span,
192}
193
194impl StringLiteral {
195 pub fn new(value: impl Into<String>) -> Self {
196 Self {
197 value: value.into(),
198 span: Span::DUMMY,
199 }
200 }
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
204pub struct HexStringLiteral {
205 pub value: String,
206 pub span: Span,
207}
208
209impl HexStringLiteral {
210 pub fn new(value: impl Into<String>) -> Self {
211 Self {
212 value: value.into(),
213 span: Span::DUMMY,
214 }
215 }
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
219pub enum CollateralBlockField {
220 From(AddressExpr),
221 MinAmount(AssetExpr),
222 Ref(DataExpr),
223}
224
225impl CollateralBlockField {
226 fn key(&self) -> &str {
227 match self {
228 CollateralBlockField::From(_) => "from",
229 CollateralBlockField::MinAmount(_) => "min_amount",
230 CollateralBlockField::Ref(_) => "ref",
231 }
232 }
233
234 pub fn as_address_expr(&self) -> Option<&AddressExpr> {
235 match self {
236 CollateralBlockField::From(x) => Some(x),
237 _ => None,
238 }
239 }
240
241 pub fn as_asset_expr(&self) -> Option<&AssetExpr> {
242 match self {
243 CollateralBlockField::MinAmount(x) => Some(x),
244 _ => None,
245 }
246 }
247
248 pub fn as_data_expr(&self) -> Option<&DataExpr> {
249 match self {
250 CollateralBlockField::Ref(x) => Some(x),
251 _ => None,
252 }
253 }
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
257pub struct CollateralBlock {
258 pub fields: Vec<CollateralBlockField>,
259 pub span: Span,
260}
261
262impl CollateralBlock {
263 pub(crate) fn find(&self, key: &str) -> Option<&CollateralBlockField> {
264 self.fields.iter().find(|x| x.key() == key)
265 }
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
269pub enum InputBlockField {
270 From(AddressExpr),
271 DatumIs(Type),
272 MinAmount(AssetExpr),
273 Redeemer(DataExpr),
274 Ref(DataExpr),
275}
276
277impl InputBlockField {
278 fn key(&self) -> &str {
279 match self {
280 InputBlockField::From(_) => "from",
281 InputBlockField::DatumIs(_) => "datum_is",
282 InputBlockField::MinAmount(_) => "min_amount",
283 InputBlockField::Redeemer(_) => "redeemer",
284 InputBlockField::Ref(_) => "ref",
285 }
286 }
287
288 pub fn as_address_expr(&self) -> Option<&AddressExpr> {
289 match self {
290 InputBlockField::From(x) => Some(x),
291 _ => None,
292 }
293 }
294
295 pub fn as_asset_expr(&self) -> Option<&AssetExpr> {
296 match self {
297 InputBlockField::MinAmount(x) => Some(x),
298 _ => None,
299 }
300 }
301
302 pub fn as_data_expr(&self) -> Option<&DataExpr> {
303 match self {
304 InputBlockField::Redeemer(x) => Some(x),
305 InputBlockField::Ref(x) => Some(x),
306 _ => None,
307 }
308 }
309
310 pub fn as_datum_type(&self) -> Option<&Type> {
311 match self {
312 InputBlockField::DatumIs(x) => Some(x),
313 _ => None,
314 }
315 }
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
319pub struct ReferenceBlock {
320 pub name: String,
321 pub r#ref: DataExpr,
322 pub span: Span,
323}
324
325#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
326pub struct InputBlock {
327 pub name: String,
328 pub is_many: bool,
329 pub fields: Vec<InputBlockField>,
330 pub span: Span,
331}
332
333impl InputBlock {
334 pub(crate) fn find(&self, key: &str) -> Option<&InputBlockField> {
335 self.fields.iter().find(|x| x.key() == key)
336 }
337
338 pub(crate) fn datum_is(&self) -> Option<&Type> {
339 self.find("datum_is").and_then(|x| x.as_datum_type())
340 }
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
344pub enum OutputBlockField {
345 To(Box<AddressExpr>),
346 Amount(Box<AssetExpr>),
347 Datum(Box<DataExpr>),
348}
349
350impl OutputBlockField {
351 fn key(&self) -> &str {
352 match self {
353 OutputBlockField::To(_) => "to",
354 OutputBlockField::Amount(_) => "amount",
355 OutputBlockField::Datum(_) => "datum",
356 }
357 }
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
361pub struct OutputBlock {
362 pub name: Option<String>,
363 pub fields: Vec<OutputBlockField>,
364 pub span: Span,
365}
366
367impl OutputBlock {
368 pub(crate) fn find(&self, key: &str) -> Option<&OutputBlockField> {
369 self.fields.iter().find(|x| x.key() == key)
370 }
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
374pub enum MintBlockField {
375 Amount(Box<AssetExpr>),
376 Redeemer(Box<DataExpr>),
377}
378
379impl MintBlockField {
380 fn key(&self) -> &str {
381 match self {
382 MintBlockField::Amount(_) => "amount",
383 MintBlockField::Redeemer(_) => "redeemer",
384 }
385 }
386}
387
388#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
389pub struct MintBlock {
390 pub fields: Vec<MintBlockField>,
391 pub span: Span,
392}
393
394impl MintBlock {
395 pub(crate) fn find(&self, key: &str) -> Option<&MintBlockField> {
396 self.fields.iter().find(|x| x.key() == key)
397 }
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
401pub struct BurnBlock {
402 pub fields: Vec<MintBlockField>,
403 pub span: Span,
404}
405
406#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
407pub struct RecordField {
408 pub name: String,
409 pub r#type: Type,
410 pub span: Span,
411}
412
413impl RecordField {
414 pub fn new(name: &str, r#type: Type) -> Self {
415 Self {
416 name: name.to_string(),
417 r#type,
418 span: Span::DUMMY,
419 }
420 }
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
424pub struct PartyDef {
425 pub name: String,
426 pub span: Span,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
430pub struct PartyField {
431 pub name: String,
432 pub party_type: String,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
436pub struct PolicyDef {
437 pub name: String,
438 pub value: PolicyValue,
439 pub span: Span,
440}
441
442#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
443pub enum PolicyField {
444 Hash(DataExpr),
445 Script(DataExpr),
446 Ref(DataExpr),
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
450pub struct PolicyConstructor {
451 pub fields: Vec<PolicyField>,
452 pub span: Span,
453}
454
455impl PolicyConstructor {
456 pub(crate) fn find_field(&self, field: &str) -> Option<&PolicyField> {
457 self.fields.iter().find(|x| match x {
458 PolicyField::Hash(_) => field == "hash",
459 PolicyField::Script(_) => field == "script",
460 PolicyField::Ref(_) => field == "ref",
461 })
462 }
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
466pub enum PolicyValue {
467 Constructor(PolicyConstructor),
468 Assign(HexStringLiteral),
469}
470
471#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
472pub struct StaticAssetConstructor {
473 pub r#type: Identifier,
474 pub amount: Box<DataExpr>,
475 pub span: Span,
476}
477
478#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
479pub struct AnyAssetConstructor {
480 pub policy: Box<DataExpr>,
481 pub asset_name: Box<DataExpr>,
482 pub amount: Box<DataExpr>,
483 pub span: Span,
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
487pub struct AssetBinaryOp {
488 pub left: Box<AssetExpr>,
489 pub operator: BinaryOperator,
490 pub right: Box<AssetExpr>,
491 pub span: Span,
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
495pub enum AssetExpr {
496 StaticConstructor(StaticAssetConstructor),
497 AnyConstructor(AnyAssetConstructor),
498 BinaryOp(AssetBinaryOp),
499 PropertyAccess(PropertyAccess),
500 Identifier(Identifier),
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
504pub struct PropertyAccess {
505 pub object: Identifier,
506 pub path: Vec<Identifier>,
507 pub span: Span,
508
509 #[serde(skip)]
511 pub(crate) scope: Option<Rc<Scope>>,
512}
513
514impl PropertyAccess {
515 pub fn new(object: &str, path: &[&str]) -> Self {
516 Self {
517 object: Identifier::new(object),
518 path: path.iter().map(|x| Identifier::new(*x)).collect(),
519 scope: None,
520 span: Span::DUMMY,
521 }
522 }
523}
524
525impl PropertyAccess {
526 pub fn shift(mut self) -> Option<Self> {
528 if self.path.is_empty() {
529 return None;
530 }
531
532 let new_object = self.path.remove(0);
533 self.object = new_object;
534
535 Some(self)
536 }
537}
538
539#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
540pub struct RecordConstructorField {
541 pub name: Identifier,
542 pub value: Box<DataExpr>,
543 pub span: Span,
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
547pub struct StructConstructor {
548 pub r#type: Identifier,
549 pub case: VariantCaseConstructor,
550 pub span: Span,
551
552 #[serde(skip)]
554 pub scope: Option<Rc<Scope>>,
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
558pub struct VariantCaseConstructor {
559 pub name: Identifier,
560 pub fields: Vec<RecordConstructorField>,
561 pub spread: Option<Box<DataExpr>>,
562 pub span: Span,
563
564 #[serde(skip)]
566 pub scope: Option<Rc<Scope>>,
567}
568
569impl VariantCaseConstructor {
570 pub fn find_field_value(&self, field: &str) -> Option<&DataExpr> {
571 self.fields
572 .iter()
573 .find(|x| x.name.value == field)
574 .map(|x| x.value.as_ref())
575 }
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
579pub struct ListConstructor {
580 pub elements: Vec<DataExpr>,
581 pub span: Span,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
585pub struct UtxoRef {
586 pub txid: Vec<u8>,
587 pub index: u64,
588 pub span: Span,
589}
590
591#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
592pub struct DataBinaryOp {
593 pub left: Box<DataExpr>,
594 pub operator: BinaryOperator,
595 pub right: Box<DataExpr>,
596 pub span: Span,
597}
598
599#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
600pub enum DataExpr {
601 None,
602 Unit,
603 Number(i64),
604 Bool(bool),
605 String(StringLiteral),
606 HexString(HexStringLiteral),
607 StructConstructor(StructConstructor),
608 ListConstructor(ListConstructor),
609 Identifier(Identifier),
610 PropertyAccess(PropertyAccess),
611 BinaryOp(DataBinaryOp),
612 UtxoRef(UtxoRef),
613}
614
615impl DataExpr {
616 pub fn as_identifier(&self) -> Option<&Identifier> {
617 match self {
618 DataExpr::Identifier(x) => Some(x),
619 _ => None,
620 }
621 }
622}
623
624#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
625pub enum AddressExpr {
626 String(StringLiteral),
627 HexString(HexStringLiteral),
628 Identifier(Identifier),
629}
630
631impl AddressExpr {
632 pub fn as_identifier(&self) -> Option<&Identifier> {
633 match self {
634 AddressExpr::Identifier(x) => Some(x),
635 _ => None,
636 }
637 }
638}
639#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
640pub enum BinaryOperator {
641 Add,
642 Subtract,
643}
644
645#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
646pub enum Type {
647 Undefined,
648 Unit,
649 Int,
650 Bool,
651 Bytes,
652 Address,
653 UtxoRef,
654 AnyAsset,
655 List(Box<Type>),
656 Custom(Identifier),
657}
658
659#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
660pub struct ParamDef {
661 pub name: String,
662 pub r#type: Type,
663}
664
665#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
666pub struct TypeDef {
667 pub name: String,
668 pub cases: Vec<VariantCase>,
669 pub span: Span,
670}
671
672impl TypeDef {
673 pub(crate) fn find_case_index(&self, case: &str) -> Option<usize> {
674 self.cases.iter().position(|x| x.name == case)
675 }
676
677 #[allow(dead_code)]
678 pub(crate) fn find_case(&self, case: &str) -> Option<&VariantCase> {
679 self.cases.iter().find(|x| x.name == case)
680 }
681}
682
683#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
684pub struct VariantCase {
685 pub name: String,
686 pub fields: Vec<RecordField>,
687 pub span: Span,
688}
689
690impl VariantCase {
691 #[allow(dead_code)]
692 pub(crate) fn find_field_index(&self, field: &str) -> Option<usize> {
693 self.fields.iter().position(|x| x.name == field)
694 }
695
696 #[allow(dead_code)]
697 pub(crate) fn find_field(&self, field: &str) -> Option<&RecordField> {
698 self.fields.iter().find(|x| x.name == field)
699 }
700}
701
702#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
703pub struct AssetDef {
704 pub name: String,
705 pub policy: Option<HexStringLiteral>,
706 pub asset_name: Option<String>,
707 pub span: Span,
708}
709
710#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
711pub enum ChainSpecificBlock {
712 Cardano(crate::cardano::CardanoBlock),
713}