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 inputs: Vec<InputBlock>,
175 pub outputs: Vec<OutputBlock>,
176 pub burn: Option<BurnBlock>,
177 pub mint: Option<MintBlock>,
178 pub adhoc: Vec<ChainSpecificBlock>,
179 pub span: Span,
180
181 #[serde(skip)]
183 pub(crate) scope: Option<Rc<Scope>>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
187pub struct StringLiteral {
188 pub value: String,
189 pub span: Span,
190}
191
192impl StringLiteral {
193 pub fn new(value: impl Into<String>) -> Self {
194 Self {
195 value: value.into(),
196 span: Span::DUMMY,
197 }
198 }
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
202pub struct HexStringLiteral {
203 pub value: String,
204 pub span: Span,
205}
206
207impl HexStringLiteral {
208 pub fn new(value: impl Into<String>) -> Self {
209 Self {
210 value: value.into(),
211 span: Span::DUMMY,
212 }
213 }
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
217pub enum InputBlockField {
218 From(AddressExpr),
219 DatumIs(Type),
220 MinAmount(AssetExpr),
221 Redeemer(DataExpr),
222 Ref(DataExpr),
223}
224
225impl InputBlockField {
226 fn key(&self) -> &str {
227 match self {
228 InputBlockField::From(_) => "from",
229 InputBlockField::DatumIs(_) => "datum_is",
230 InputBlockField::MinAmount(_) => "min_amount",
231 InputBlockField::Redeemer(_) => "redeemer",
232 InputBlockField::Ref(_) => "ref",
233 }
234 }
235
236 pub fn as_address_expr(&self) -> Option<&AddressExpr> {
237 match self {
238 InputBlockField::From(x) => Some(x),
239 _ => None,
240 }
241 }
242
243 pub fn as_asset_expr(&self) -> Option<&AssetExpr> {
244 match self {
245 InputBlockField::MinAmount(x) => Some(x),
246 _ => None,
247 }
248 }
249
250 pub fn as_data_expr(&self) -> Option<&DataExpr> {
251 match self {
252 InputBlockField::Redeemer(x) => Some(x),
253 InputBlockField::Ref(x) => Some(x),
254 _ => None,
255 }
256 }
257
258 pub fn as_datum_type(&self) -> Option<&Type> {
259 match self {
260 InputBlockField::DatumIs(x) => Some(x),
261 _ => None,
262 }
263 }
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
267pub struct InputBlock {
268 pub name: String,
269 pub is_many: bool,
270 pub fields: Vec<InputBlockField>,
271 pub span: Span,
272}
273
274impl InputBlock {
275 pub(crate) fn find(&self, key: &str) -> Option<&InputBlockField> {
276 self.fields.iter().find(|x| x.key() == key)
277 }
278
279 pub(crate) fn find_mut(&mut self, key: &str) -> Option<&mut InputBlockField> {
280 self.fields.iter_mut().find(|x| x.key() == key)
281 }
282
283 pub(crate) fn datum_is(&self) -> Option<&Type> {
284 self.find("datum_is").and_then(|x| x.as_datum_type())
285 }
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
289pub enum OutputBlockField {
290 To(Box<AddressExpr>),
291 Amount(Box<AssetExpr>),
292 Datum(Box<DataExpr>),
293}
294
295impl OutputBlockField {
296 fn key(&self) -> &str {
297 match self {
298 OutputBlockField::To(_) => "to",
299 OutputBlockField::Amount(_) => "amount",
300 OutputBlockField::Datum(_) => "datum",
301 }
302 }
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
306pub struct OutputBlock {
307 pub name: Option<String>,
308 pub fields: Vec<OutputBlockField>,
309 pub span: Span,
310}
311
312impl OutputBlock {
313 pub(crate) fn find(&self, key: &str) -> Option<&OutputBlockField> {
314 self.fields.iter().find(|x| x.key() == key)
315 }
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
319pub enum MintBlockField {
320 Amount(Box<AssetExpr>),
321 Redeemer(Box<DataExpr>),
322}
323
324impl MintBlockField {
325 fn key(&self) -> &str {
326 match self {
327 MintBlockField::Amount(_) => "amount",
328 MintBlockField::Redeemer(_) => "redeemer",
329 }
330 }
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
334pub struct MintBlock {
335 pub fields: Vec<MintBlockField>,
336 pub span: Span,
337}
338
339impl MintBlock {
340 pub(crate) fn find(&self, key: &str) -> Option<&MintBlockField> {
341 self.fields.iter().find(|x| x.key() == key)
342 }
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
346pub struct BurnBlock {
347 pub fields: Vec<MintBlockField>,
348 pub span: Span,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
352pub struct RecordField {
353 pub name: String,
354 pub r#type: Type,
355 pub span: Span,
356}
357
358impl RecordField {
359 pub fn new(name: &str, r#type: Type) -> Self {
360 Self {
361 name: name.to_string(),
362 r#type,
363 span: Span::DUMMY,
364 }
365 }
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
369pub struct PartyDef {
370 pub name: String,
371 pub span: Span,
372}
373
374#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
375pub struct PartyField {
376 pub name: String,
377 pub party_type: String,
378}
379
380#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
381pub struct PolicyDef {
382 pub name: String,
383 pub value: PolicyValue,
384 pub span: Span,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
388pub enum PolicyField {
389 Hash(DataExpr),
390 Script(DataExpr),
391 Ref(DataExpr),
392}
393
394#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
395pub struct PolicyConstructor {
396 pub fields: Vec<PolicyField>,
397 pub span: Span,
398}
399
400impl PolicyConstructor {
401 pub(crate) fn find_field(&self, field: &str) -> Option<&PolicyField> {
402 self.fields.iter().find(|x| match x {
403 PolicyField::Hash(_) => field == "hash",
404 PolicyField::Script(_) => field == "script",
405 PolicyField::Ref(_) => field == "ref",
406 })
407 }
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
411pub enum PolicyValue {
412 Constructor(PolicyConstructor),
413 Assign(HexStringLiteral),
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
417pub struct StaticAssetConstructor {
418 pub r#type: Identifier,
419 pub amount: Box<DataExpr>,
420 pub span: Span,
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
424pub struct AnyAssetConstructor {
425 pub policy: Box<DataExpr>,
426 pub asset_name: Box<DataExpr>,
427 pub amount: Box<DataExpr>,
428 pub span: Span,
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
432pub struct AssetBinaryOp {
433 pub left: Box<AssetExpr>,
434 pub operator: BinaryOperator,
435 pub right: Box<AssetExpr>,
436 pub span: Span,
437}
438
439#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
440pub enum AssetExpr {
441 StaticConstructor(StaticAssetConstructor),
442 AnyConstructor(AnyAssetConstructor),
443 BinaryOp(AssetBinaryOp),
444 PropertyAccess(PropertyAccess),
445 Identifier(Identifier),
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
449pub struct PropertyAccess {
450 pub object: Identifier,
451 pub path: Vec<Identifier>,
452 pub span: Span,
453
454 #[serde(skip)]
456 pub(crate) scope: Option<Rc<Scope>>,
457}
458
459impl PropertyAccess {
460 pub fn new(object: &str, path: &[&str]) -> Self {
461 Self {
462 object: Identifier::new(object),
463 path: path.iter().map(|x| Identifier::new(*x)).collect(),
464 scope: None,
465 span: Span::DUMMY,
466 }
467 }
468}
469
470impl PropertyAccess {
471 pub fn shift(mut self) -> Option<Self> {
473 if self.path.is_empty() {
474 return None;
475 }
476
477 let new_object = self.path.remove(0);
478 self.object = new_object;
479
480 Some(self)
481 }
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
485pub struct RecordConstructorField {
486 pub name: Identifier,
487 pub value: Box<DataExpr>,
488 pub span: Span,
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
492pub struct DatumConstructor {
493 pub r#type: Identifier,
494 pub case: VariantCaseConstructor,
495 pub span: Span,
496
497 #[serde(skip)]
499 pub scope: Option<Rc<Scope>>,
500}
501
502#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
503pub struct VariantCaseConstructor {
504 pub name: Identifier,
505 pub fields: Vec<RecordConstructorField>,
506 pub spread: Option<Box<DataExpr>>,
507 pub span: Span,
508
509 #[serde(skip)]
511 pub scope: Option<Rc<Scope>>,
512}
513
514impl VariantCaseConstructor {
515 pub fn find_field_value(&self, field: &str) -> Option<&DataExpr> {
516 self.fields
517 .iter()
518 .find(|x| x.name.value == field)
519 .map(|x| x.value.as_ref())
520 }
521}
522
523#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
524pub struct DataBinaryOp {
525 pub left: Box<DataExpr>,
526 pub operator: BinaryOperator,
527 pub right: Box<DataExpr>,
528 pub span: Span,
529}
530
531#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
532pub enum DataExpr {
533 None,
534 Unit,
535 Number(i64),
536 Bool(bool),
537 String(StringLiteral),
538 HexString(HexStringLiteral),
539 Constructor(DatumConstructor),
540 Identifier(Identifier),
541 PropertyAccess(PropertyAccess),
542 BinaryOp(DataBinaryOp),
543}
544
545impl DataExpr {
546 pub fn as_identifier(&self) -> Option<&Identifier> {
547 match self {
548 DataExpr::Identifier(x) => Some(x),
549 _ => None,
550 }
551 }
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
555pub enum AddressExpr {
556 String(StringLiteral),
557 HexString(HexStringLiteral),
558 Identifier(Identifier),
559}
560
561impl AddressExpr {
562 pub fn as_identifier(&self) -> Option<&Identifier> {
563 match self {
564 AddressExpr::Identifier(x) => Some(x),
565 _ => None,
566 }
567 }
568}
569#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
570pub enum BinaryOperator {
571 Add,
572 Subtract,
573}
574
575#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
576pub enum Type {
577 Undefined,
578 Unit,
579 Int,
580 Bool,
581 Bytes,
582 Address,
583 UtxoRef,
584 AnyAsset,
585 Custom(Identifier),
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
589pub struct ParamDef {
590 pub name: String,
591 pub r#type: Type,
592}
593
594#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
595pub struct TypeDef {
596 pub name: String,
597 pub cases: Vec<VariantCase>,
598 pub span: Span,
599}
600
601impl TypeDef {
602 pub(crate) fn find_case_index(&self, case: &str) -> Option<usize> {
603 self.cases.iter().position(|x| x.name == case)
604 }
605
606 #[allow(dead_code)]
607 pub(crate) fn find_case(&self, case: &str) -> Option<&VariantCase> {
608 self.cases.iter().find(|x| x.name == case)
609 }
610}
611
612#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
613pub struct VariantCase {
614 pub name: String,
615 pub fields: Vec<RecordField>,
616 pub span: Span,
617}
618
619impl VariantCase {
620 #[allow(dead_code)]
621 pub(crate) fn find_field_index(&self, field: &str) -> Option<usize> {
622 self.fields.iter().position(|x| x.name == field)
623 }
624
625 #[allow(dead_code)]
626 pub(crate) fn find_field(&self, field: &str) -> Option<&RecordField> {
627 self.fields.iter().find(|x| x.name == field)
628 }
629}
630
631#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
632pub struct AssetDef {
633 pub name: String,
634 pub policy: Option<HexStringLiteral>,
635 pub asset_name: Option<String>,
636 pub span: Span,
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
640pub enum ChainSpecificBlock {
641 Cardano(crate::cardano::CardanoBlock),
642}