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 datum_is(&self) -> Type {
280 self.find("datum_is")
281 .and_then(|x| x.as_datum_type())
282 .cloned()
283 .unwrap_or(Type::Unit)
284 }
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
288pub enum OutputBlockField {
289 To(Box<AddressExpr>),
290 Amount(Box<AssetExpr>),
291 Datum(Box<DataExpr>),
292}
293
294impl OutputBlockField {
295 fn key(&self) -> &str {
296 match self {
297 OutputBlockField::To(_) => "to",
298 OutputBlockField::Amount(_) => "amount",
299 OutputBlockField::Datum(_) => "datum",
300 }
301 }
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
305pub struct OutputBlock {
306 pub name: Option<String>,
307 pub fields: Vec<OutputBlockField>,
308 pub span: Span,
309}
310
311impl OutputBlock {
312 pub(crate) fn find(&self, key: &str) -> Option<&OutputBlockField> {
313 self.fields.iter().find(|x| x.key() == key)
314 }
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
318pub enum MintBlockField {
319 Amount(Box<AssetExpr>),
320 Redeemer(Box<DataExpr>),
321}
322
323impl MintBlockField {
324 fn key(&self) -> &str {
325 match self {
326 MintBlockField::Amount(_) => "amount",
327 MintBlockField::Redeemer(_) => "redeemer",
328 }
329 }
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
333pub struct MintBlock {
334 pub fields: Vec<MintBlockField>,
335 pub span: Span,
336}
337
338impl MintBlock {
339 pub(crate) fn find(&self, key: &str) -> Option<&MintBlockField> {
340 self.fields.iter().find(|x| x.key() == key)
341 }
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
345pub struct BurnBlock {
346 pub fields: Vec<MintBlockField>,
347 pub span: Span,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
351pub struct RecordField {
352 pub name: String,
353 pub r#type: Type,
354 pub span: Span,
355}
356
357impl RecordField {
358 pub fn new(name: &str, r#type: Type) -> Self {
359 Self {
360 name: name.to_string(),
361 r#type,
362 span: Span::DUMMY,
363 }
364 }
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
368pub struct PartyDef {
369 pub name: String,
370 pub span: Span,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
374pub struct PartyField {
375 pub name: String,
376 pub party_type: String,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
380pub struct PolicyDef {
381 pub name: String,
382 pub value: PolicyValue,
383 pub span: Span,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
387pub enum PolicyField {
388 Hash(DataExpr),
389 Script(DataExpr),
390 Ref(DataExpr),
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
394pub struct PolicyConstructor {
395 pub fields: Vec<PolicyField>,
396 pub span: Span,
397}
398
399impl PolicyConstructor {
400 pub(crate) fn find_field(&self, field: &str) -> Option<&PolicyField> {
401 self.fields.iter().find(|x| match x {
402 PolicyField::Hash(_) => field == "hash",
403 PolicyField::Script(_) => field == "script",
404 PolicyField::Ref(_) => field == "ref",
405 })
406 }
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
410pub enum PolicyValue {
411 Constructor(PolicyConstructor),
412 Assign(HexStringLiteral),
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
416pub struct AssetConstructor {
417 pub r#type: Identifier,
418 pub amount: Box<DataExpr>,
419 pub span: Span,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
423pub struct AssetBinaryOp {
424 pub left: Box<AssetExpr>,
425 pub operator: BinaryOperator,
426 pub right: Box<AssetExpr>,
427 pub span: Span,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
431pub enum AssetExpr {
432 Constructor(AssetConstructor),
433 BinaryOp(AssetBinaryOp),
434 PropertyAccess(PropertyAccess),
435 Identifier(Identifier),
436}
437
438#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
439pub struct PropertyAccess {
440 pub object: Identifier,
441 pub path: Vec<Identifier>,
442 pub span: Span,
443
444 #[serde(skip)]
446 pub(crate) scope: Option<Rc<Scope>>,
447}
448
449impl PropertyAccess {
450 pub fn new(object: &str, path: &[&str]) -> Self {
451 Self {
452 object: Identifier::new(object),
453 path: path.iter().map(|x| Identifier::new(*x)).collect(),
454 scope: None,
455 span: Span::DUMMY,
456 }
457 }
458}
459
460impl PropertyAccess {
461 pub fn shift(mut self) -> Option<Self> {
463 if self.path.is_empty() {
464 return None;
465 }
466
467 let new_object = self.path.remove(0);
468 self.object = new_object;
469
470 Some(self)
471 }
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
475pub struct RecordConstructorField {
476 pub name: Identifier,
477 pub value: Box<DataExpr>,
478 pub span: Span,
479}
480
481#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
482pub struct DatumConstructor {
483 pub r#type: Identifier,
484 pub case: VariantCaseConstructor,
485 pub span: Span,
486
487 #[serde(skip)]
489 pub scope: Option<Rc<Scope>>,
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
493pub struct VariantCaseConstructor {
494 pub name: Identifier,
495 pub fields: Vec<RecordConstructorField>,
496 pub spread: Option<Box<DataExpr>>,
497 pub span: Span,
498
499 #[serde(skip)]
501 pub scope: Option<Rc<Scope>>,
502}
503
504impl VariantCaseConstructor {
505 pub fn find_field_value(&self, field: &str) -> Option<&DataExpr> {
506 self.fields
507 .iter()
508 .find(|x| x.name.value == field)
509 .map(|x| x.value.as_ref())
510 }
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
514pub struct DataBinaryOp {
515 pub left: Box<DataExpr>,
516 pub operator: BinaryOperator,
517 pub right: Box<DataExpr>,
518 pub span: Span,
519}
520
521#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
522pub enum DataExpr {
523 None,
524 Unit,
525 Number(i64),
526 Bool(bool),
527 String(StringLiteral),
528 HexString(HexStringLiteral),
529 Constructor(DatumConstructor),
530 Identifier(Identifier),
531 PropertyAccess(PropertyAccess),
532 BinaryOp(DataBinaryOp),
533}
534
535impl DataExpr {
536 pub fn as_identifier(&self) -> Option<&Identifier> {
537 match self {
538 DataExpr::Identifier(x) => Some(x),
539 _ => None,
540 }
541 }
542}
543
544#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
545pub enum AddressExpr {
546 String(StringLiteral),
547 HexString(HexStringLiteral),
548 Identifier(Identifier),
549}
550
551impl AddressExpr {
552 pub fn as_identifier(&self) -> Option<&Identifier> {
553 match self {
554 AddressExpr::Identifier(x) => Some(x),
555 _ => None,
556 }
557 }
558}
559#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
560pub enum BinaryOperator {
561 Add,
562 Subtract,
563}
564
565#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
566pub enum Type {
567 Unit,
568 Int,
569 Bool,
570 Bytes,
571 Address,
572 UtxoRef,
573 AnyAsset,
574 Custom(Identifier),
575}
576
577#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
578pub struct ParamDef {
579 pub name: String,
580 pub r#type: Type,
581}
582
583#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
584pub struct TypeDef {
585 pub name: String,
586 pub cases: Vec<VariantCase>,
587 pub span: Span,
588}
589
590impl TypeDef {
591 pub(crate) fn find_case_index(&self, case: &str) -> Option<usize> {
592 self.cases.iter().position(|x| x.name == case)
593 }
594
595 #[allow(dead_code)]
596 pub(crate) fn find_case(&self, case: &str) -> Option<&VariantCase> {
597 self.cases.iter().find(|x| x.name == case)
598 }
599}
600
601#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
602pub struct VariantCase {
603 pub name: String,
604 pub fields: Vec<RecordField>,
605 pub span: Span,
606}
607
608impl VariantCase {
609 #[allow(dead_code)]
610 pub(crate) fn find_field_index(&self, field: &str) -> Option<usize> {
611 self.fields.iter().position(|x| x.name == field)
612 }
613
614 #[allow(dead_code)]
615 pub(crate) fn find_field(&self, field: &str) -> Option<&RecordField> {
616 self.fields.iter().find(|x| x.name == field)
617 }
618}
619
620#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
621pub struct AssetDef {
622 pub name: String,
623 pub policy: HexStringLiteral,
624 pub asset_name: String,
625 pub span: Span,
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
629pub enum ChainSpecificBlock {
630 Cardano(crate::cardano::CardanoBlock),
631}