1use std::sync::LazyLock;
6
7use miette::SourceOffset;
8use pest::{
9 iterators::Pair,
10 pratt_parser::{Assoc, Op, PrattParser},
11 Parser,
12};
13use pest_derive::Parser;
14
15use crate::ast::*;
16
17#[derive(Parser)]
18#[grammar = "tx3.pest"]
19pub(crate) struct Tx3Grammar;
20
21#[derive(Debug, thiserror::Error, miette::Diagnostic)]
22#[error("Parsing error: {message}")]
23#[diagnostic(code(tx3::parsing))]
24pub struct Error {
25 pub message: String,
26
27 #[source_code]
28 pub src: String,
29
30 #[label]
31 pub span: Span,
32}
33
34impl From<pest::error::Error<Rule>> for Error {
35 fn from(error: pest::error::Error<Rule>) -> Self {
36 match &error.variant {
37 pest::error::ErrorVariant::ParsingError { positives, .. } => Error {
38 message: format!("expected {positives:?}"),
39 src: error.line().to_string(),
40 span: error.location.into(),
41 },
42 pest::error::ErrorVariant::CustomError { message } => Error {
43 message: message.clone(),
44 src: error.line().to_string(),
45 span: error.location.into(),
46 },
47 }
48 }
49}
50
51impl From<pest::error::InputLocation> for Span {
52 fn from(value: pest::error::InputLocation) -> Self {
53 match value {
54 pest::error::InputLocation::Pos(pos) => Self::new(pos, pos),
55 pest::error::InputLocation::Span((start, end)) => Self::new(start, end),
56 }
57 }
58}
59
60impl From<pest::Span<'_>> for Span {
61 fn from(span: pest::Span<'_>) -> Self {
62 Self::new(span.start(), span.end())
63 }
64}
65
66impl From<Span> for miette::SourceSpan {
67 fn from(span: Span) -> Self {
68 miette::SourceSpan::new(SourceOffset::from(span.start), span.end - span.start)
69 }
70}
71
72pub trait AstNode: Sized {
73 const RULE: Rule;
74
75 fn parse(pair: Pair<Rule>) -> Result<Self, Error>;
76
77 fn span(&self) -> &Span;
78}
79
80fn take_docstring(inner: &mut pest::iterators::Pairs<Rule>) -> Option<String> {
84 let next = inner.peek()?;
85 if next.as_rule() != Rule::docstring {
86 return None;
87 }
88 let pair = inner.next().unwrap();
89
90 let mut lines = Vec::new();
91 for line in pair.into_inner() {
92 debug_assert_eq!(line.as_rule(), Rule::doc_line);
93 let raw = line.as_str();
94 let trimmed = raw.strip_prefix("///").unwrap_or(raw);
95 let trimmed = trimmed.strip_prefix(' ').unwrap_or(trimmed);
96 lines.push(trimmed.trim_end().to_string());
97 }
98
99 let joined = lines.join("\n");
100 if joined.trim().is_empty() {
101 None
102 } else {
103 Some(joined)
104 }
105}
106
107impl AstNode for Program {
108 const RULE: Rule = Rule::program;
109
110 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
111 let span = pair.as_span().into();
112 let inner = pair.into_inner();
113
114 let mut program = Self {
115 env: None,
116 txs: Vec::new(),
117 assets: Vec::new(),
118 types: Vec::new(),
119 aliases: Vec::new(),
120 parties: Vec::new(),
121 policies: Vec::new(),
122 functions: Vec::new(),
123 scope: None,
124 span,
125 };
126
127 for pair in inner {
128 match pair.as_rule() {
129 Rule::env_def => program.env = Some(EnvDef::parse(pair)?),
130 Rule::tx_def => program.txs.push(TxDef::parse(pair)?),
131 Rule::asset_def => program.assets.push(AssetDef::parse(pair)?),
132 Rule::record_def => program.types.push(TypeDef::parse(pair)?),
133 Rule::variant_def => program.types.push(TypeDef::parse(pair)?),
134 Rule::alias_def => program.aliases.push(AliasDef::parse(pair)?),
135 Rule::party_def => program.parties.push(PartyDef::parse(pair)?),
136 Rule::policy_def => program.policies.push(PolicyDef::parse(pair)?),
137 Rule::fn_def => program.functions.push(FnDef::parse(pair)?),
138 Rule::EOI => break,
139 x => unreachable!("Unexpected rule in program: {:?}", x),
140 }
141 }
142
143 Ok(program)
144 }
145
146 fn span(&self) -> &Span {
147 &self.span
148 }
149}
150
151impl AstNode for EnvField {
152 const RULE: Rule = Rule::env_field;
153
154 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
155 let span = pair.as_span().into();
156 let mut inner = pair.into_inner();
157 let docstring = take_docstring(&mut inner);
158 let identifier = inner.next().unwrap().as_str().to_string();
159 let r#type = Type::parse(inner.next().unwrap())?;
160
161 Ok(EnvField {
162 name: identifier,
163 r#type,
164 docstring,
165 span,
166 })
167 }
168
169 fn span(&self) -> &Span {
170 &self.span
171 }
172}
173
174impl AstNode for EnvDef {
175 const RULE: Rule = Rule::env_def;
176
177 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
178 let span = pair.as_span().into();
179 let inner = pair.into_inner();
180
181 let fields = inner
182 .map(|x| EnvField::parse(x))
183 .collect::<Result<Vec<_>, _>>()?;
184
185 Ok(EnvDef { fields, span })
186 }
187
188 fn span(&self) -> &Span {
189 &self.span
190 }
191}
192
193impl AstNode for ParameterList {
194 const RULE: Rule = Rule::parameter_list;
195
196 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
197 let span = pair.as_span().into();
198 let inner = pair.into_inner();
199
200 let mut parameters = Vec::new();
201
202 for param in inner {
203 let mut inner = param.into_inner();
204 let docstring = take_docstring(&mut inner);
205 let name = Identifier::parse(inner.next().unwrap())?;
206 let r#type = Type::parse(inner.next().unwrap())?;
207
208 parameters.push(ParamDef {
209 name,
210 r#type,
211 docstring,
212 });
213 }
214
215 Ok(ParameterList { parameters, span })
216 }
217
218 fn span(&self) -> &Span {
219 &self.span
220 }
221}
222
223impl AstNode for TxDef {
224 const RULE: Rule = Rule::tx_def;
225
226 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
227 let span = pair.as_span().into();
228 let mut inner = pair.into_inner();
229
230 let docstring = take_docstring(&mut inner);
231 let name = Identifier::parse(inner.next().unwrap())?;
232 let parameters = ParameterList::parse(inner.next().unwrap())?;
233
234 let mut locals = None;
235 let mut references = Vec::new();
236 let mut inputs = Vec::new();
237 let mut outputs = Vec::new();
238 let mut validity = None;
239 let mut burns = Vec::new();
240 let mut mints = Vec::new();
241 let mut adhoc = Vec::new();
242 let mut collateral = Vec::new();
243 let mut signers = None;
244 let mut metadata = None;
245
246 for item in inner {
247 match item.as_rule() {
248 Rule::locals_block => locals = Some(LocalsBlock::parse(item)?),
249 Rule::reference_block => references.push(ReferenceBlock::parse(item)?),
250 Rule::input_block => inputs.push(InputBlock::parse(item)?),
251 Rule::output_block => outputs.push(OutputBlock::parse(item)?),
252 Rule::validity_block => validity = Some(ValidityBlock::parse(item)?),
253 Rule::mint_block => mints.push(MintBlock::parse(item)?),
254 Rule::burn_block => burns.push(MintBlock::parse(item)?),
255 Rule::chain_specific_block => adhoc.push(ChainSpecificBlock::parse(item)?),
256 Rule::collateral_block => collateral.push(CollateralBlock::parse(item)?),
257 Rule::signers_block => signers = Some(SignersBlock::parse(item)?),
258 Rule::metadata_block => metadata = Some(MetadataBlock::parse(item)?),
259 x => unreachable!("Unexpected rule in tx_def: {:?}", x),
260 }
261 }
262
263 Ok(TxDef {
264 name,
265 docstring,
266 parameters,
267 locals,
268 references,
269 inputs,
270 outputs,
271 validity,
272 mints,
273 burns,
274 signers,
275 adhoc,
276 scope: None,
277 span,
278 collateral,
279 metadata,
280 })
281 }
282
283 fn span(&self) -> &Span {
284 &self.span
285 }
286}
287
288impl AstNode for Identifier {
289 const RULE: Rule = Rule::identifier;
290
291 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
292 Ok(Identifier {
293 value: pair.as_str().to_string(),
294 symbol: None,
295 span: pair.as_span().into(),
296 })
297 }
298
299 fn span(&self) -> &Span {
300 &self.span
301 }
302}
303
304impl AstNode for StringLiteral {
305 const RULE: Rule = Rule::string;
306
307 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
308 Ok(StringLiteral {
309 value: pair.as_str()[1..pair.as_str().len() - 1].to_string(),
310 span: pair.as_span().into(),
311 })
312 }
313
314 fn span(&self) -> &Span {
315 &self.span
316 }
317}
318
319impl AstNode for HexStringLiteral {
320 const RULE: Rule = Rule::hex_string;
321
322 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
323 Ok(HexStringLiteral {
324 value: pair.as_str()[2..].to_string(),
325 span: pair.as_span().into(),
326 })
327 }
328
329 fn span(&self) -> &Span {
330 &self.span
331 }
332}
333
334impl AstNode for PartyDef {
335 const RULE: Rule = Rule::party_def;
336
337 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
338 let span = pair.as_span().into();
339 let mut inner = pair.into_inner();
340 let docstring = take_docstring(&mut inner);
341 let identifier = Identifier::parse(inner.next().unwrap())?;
342
343 Ok(PartyDef {
344 name: identifier,
345 docstring,
346 span,
347 })
348 }
349
350 fn span(&self) -> &Span {
351 &self.span
352 }
353}
354
355impl AstNode for LocalsAssign {
356 const RULE: Rule = Rule::locals_assign;
357
358 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
359 let span = pair.as_span().into();
360 let mut inner = pair.into_inner();
361
362 let name = Identifier::parse(inner.next().unwrap())?;
363 let value = DataExpr::parse(inner.next().unwrap())?;
364
365 Ok(LocalsAssign { name, value, span })
366 }
367
368 fn span(&self) -> &Span {
369 &self.span
370 }
371}
372
373impl AstNode for LocalsBlock {
374 const RULE: Rule = Rule::locals_block;
375
376 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
377 let span = pair.as_span().into();
378 let inner = pair.into_inner();
379
380 let assigns = inner
381 .map(|x| LocalsAssign::parse(x))
382 .collect::<Result<Vec<_>, _>>()?;
383
384 Ok(LocalsBlock { assigns, span })
385 }
386
387 fn span(&self) -> &Span {
388 &self.span
389 }
390}
391
392impl AstNode for ReferenceBlock {
393 const RULE: Rule = Rule::reference_block;
394
395 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
396 let span = pair.as_span().into();
397 let mut inner = pair.into_inner();
398
399 let name = inner.next().unwrap().as_str().to_string();
400
401 let pair = inner.next().unwrap();
402 let r#ref = match pair.as_rule() {
403 Rule::input_block_ref => {
404 let pair = pair.into_inner().next().unwrap();
405 DataExpr::parse(pair)?
406 }
407 x => unreachable!("Unexpected rule in ref_input_block: {:?}", x),
408 };
409
410 let datum_is = inner
411 .next()
412 .map(|pair| {
413 let pair = pair.into_inner().next().unwrap();
414 Type::parse(pair)
415 })
416 .transpose()?;
417
418 Ok(ReferenceBlock {
419 name,
420 r#ref,
421 datum_is,
422 span,
423 })
424 }
425
426 fn span(&self) -> &Span {
427 &self.span
428 }
429}
430
431impl AstNode for CollateralBlockField {
432 const RULE: Rule = Rule::collateral_block_field;
433
434 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
435 match pair.as_rule() {
436 Rule::input_block_from => {
437 let pair = pair.into_inner().next().unwrap();
438 let x = CollateralBlockField::From(DataExpr::parse(pair)?);
439 Ok(x)
440 }
441 Rule::input_block_min_amount => {
442 let pair = pair.into_inner().next().unwrap();
443 let x = CollateralBlockField::MinAmount(DataExpr::parse(pair)?);
444 Ok(x)
445 }
446 Rule::input_block_ref => {
447 let pair = pair.into_inner().next().unwrap();
448 let x = CollateralBlockField::Ref(DataExpr::parse(pair)?);
449 Ok(x)
450 }
451 x => unreachable!("Unexpected rule in collateral_block: {:?}", x),
452 }
453 }
454
455 fn span(&self) -> &Span {
456 match self {
457 Self::From(x) => x.span(),
458 Self::MinAmount(x) => x.span(),
459 Self::Ref(x) => x.span(),
460 }
461 }
462}
463
464impl AstNode for CollateralBlock {
465 const RULE: Rule = Rule::collateral_block;
466
467 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
468 let span = pair.as_span().into();
469 let inner = pair.into_inner();
470
471 let fields = inner
472 .map(|x| CollateralBlockField::parse(x))
473 .collect::<Result<Vec<_>, _>>()?;
474
475 Ok(CollateralBlock { fields, span })
476 }
477
478 fn span(&self) -> &Span {
479 &self.span
480 }
481}
482
483impl AstNode for MetadataBlockField {
484 const RULE: Rule = Rule::metadata_block_field;
485
486 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
487 let span = pair.as_span().into();
488 match pair.as_rule() {
489 Rule::metadata_block_field => {
490 let mut inner = pair.into_inner();
491 let key = inner.next().unwrap();
492 let value = inner.next().unwrap();
493 Ok(MetadataBlockField {
494 key: DataExpr::parse(key)?,
495 value: DataExpr::parse(value)?,
496 span,
497 })
498 }
499 x => unreachable!("Unexpected rule in metadata_block: {:?}", x),
500 }
501 }
502
503 fn span(&self) -> &Span {
504 &self.span
505 }
506}
507
508impl AstNode for MetadataBlock {
509 const RULE: Rule = Rule::metadata_block;
510
511 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
512 let span = pair.as_span().into();
513 let inner = pair.into_inner();
514
515 let fields = inner
516 .map(|x| MetadataBlockField::parse(x))
517 .collect::<Result<Vec<_>, _>>()?;
518
519 Ok(MetadataBlock { fields, span })
520 }
521
522 fn span(&self) -> &Span {
523 &self.span
524 }
525}
526
527impl AstNode for InputBlockField {
528 const RULE: Rule = Rule::input_block_field;
529
530 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
531 match pair.as_rule() {
532 Rule::input_block_from => {
533 let pair = pair.into_inner().next().unwrap();
534 let x = InputBlockField::From(DataExpr::parse(pair)?);
535 Ok(x)
536 }
537 Rule::input_block_datum_is => {
538 let pair = pair.into_inner().next().unwrap();
539 let x = InputBlockField::DatumIs(Type::parse(pair)?);
540 Ok(x)
541 }
542 Rule::input_block_min_amount => {
543 let pair = pair.into_inner().next().unwrap();
544 let x = InputBlockField::MinAmount(DataExpr::parse(pair)?);
545 Ok(x)
546 }
547 Rule::input_block_redeemer => {
548 let pair = pair.into_inner().next().unwrap();
549 let x = InputBlockField::Redeemer(DataExpr::parse(pair)?);
550 Ok(x)
551 }
552 Rule::input_block_ref => {
553 let pair = pair.into_inner().next().unwrap();
554 let x = InputBlockField::Ref(DataExpr::parse(pair)?);
555 Ok(x)
556 }
557 x => unreachable!("Unexpected rule in input_block: {:?}", x),
558 }
559 }
560
561 fn span(&self) -> &Span {
562 match self {
563 Self::From(x) => x.span(),
564 Self::DatumIs(x) => x.span(),
565 Self::MinAmount(x) => x.span(),
566 Self::Redeemer(x) => x.span(),
567 Self::Ref(x) => x.span(),
568 }
569 }
570}
571
572impl AstNode for InputBlock {
573 const RULE: Rule = Rule::input_block;
574
575 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
576 let span = pair.as_span().into();
577 let mut inner = pair.into_inner();
578
579 let next = inner.next().unwrap();
580
581 let (many, name) = match next.as_rule() {
582 Rule::input_many => (true, inner.next().unwrap().as_str().to_string()),
583 Rule::identifier => (false, next.as_str().to_string()),
584 _ => unreachable!("Unexpected rule in input_block: {:?}", next.as_rule()),
585 };
586
587 let fields = inner
588 .map(|x| InputBlockField::parse(x))
589 .collect::<Result<Vec<_>, _>>()?;
590
591 Ok(InputBlock {
592 name,
593 many,
594 fields,
595 span,
596 })
597 }
598
599 fn span(&self) -> &Span {
600 &self.span
601 }
602}
603
604impl AstNode for OutputBlockField {
605 const RULE: Rule = Rule::output_block_field;
606
607 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
608 match pair.as_rule() {
609 Rule::output_block_to => {
610 let pair = pair.into_inner().next().unwrap();
611 let x = OutputBlockField::To(Box::new(DataExpr::parse(pair)?));
612 Ok(x)
613 }
614 Rule::output_block_amount => {
615 let pair = pair.into_inner().next().unwrap();
616 let x = OutputBlockField::Amount(DataExpr::parse(pair)?.into());
617 Ok(x)
618 }
619 Rule::output_block_datum => {
620 let pair = pair.into_inner().next().unwrap();
621 let x = OutputBlockField::Datum(DataExpr::parse(pair)?.into());
622 Ok(x)
623 }
624 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
625 }
626 }
627
628 fn span(&self) -> &Span {
629 match self {
630 Self::To(x) => x.span(),
631 Self::Amount(x) => x.span(),
632 Self::Datum(x) => x.span(),
633 }
634 }
635}
636
637impl AstNode for OutputBlock {
638 const RULE: Rule = Rule::output_block;
639
640 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
641 let span = pair.as_span().into();
642 let mut inner = pair.into_inner();
643
644 let optional = inner
645 .peek()
646 .map_or(false, |first| first.as_rule() == Rule::output_optional);
647
648 if optional {
649 inner.next();
650 }
651
652 let has_name = inner
653 .peek()
654 .map(|x| x.as_rule() == Rule::identifier)
655 .unwrap_or_default();
656
657 let name = if has_name {
658 Some(Identifier::parse(inner.next().unwrap())?)
659 } else {
660 None
661 };
662
663 let fields = inner
664 .map(|x| OutputBlockField::parse(x))
665 .collect::<Result<Vec<_>, _>>()?;
666
667 Ok(OutputBlock {
668 name,
669 optional,
670 fields,
671 span,
672 })
673 }
674
675 fn span(&self) -> &Span {
676 &self.span
677 }
678}
679
680impl AstNode for ValidityBlockField {
681 const RULE: Rule = Rule::validity_block_field;
682
683 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
684 match pair.as_rule() {
685 Rule::validity_since_slot => {
686 let pair = pair.into_inner().next().unwrap();
687 let x = ValidityBlockField::SinceSlot(DataExpr::parse(pair)?.into());
688 Ok(x)
689 }
690 Rule::validity_until_slot => {
691 let pair = pair.into_inner().next().unwrap();
692 let x = ValidityBlockField::UntilSlot(DataExpr::parse(pair)?.into());
693 Ok(x)
694 }
695 x => unreachable!("Unexpected rule in validity_block: {:?}", x),
696 }
697 }
698
699 fn span(&self) -> &Span {
700 match self {
701 Self::UntilSlot(x) => x.span(),
702 Self::SinceSlot(x) => x.span(),
703 }
704 }
705}
706
707impl AstNode for ValidityBlock {
708 const RULE: Rule = Rule::validity_block;
709
710 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
711 let span = pair.as_span().into();
712 let inner = pair.into_inner();
713
714 let fields = inner
715 .map(|x| ValidityBlockField::parse(x))
716 .collect::<Result<Vec<_>, _>>()?;
717
718 Ok(ValidityBlock { fields, span })
719 }
720
721 fn span(&self) -> &Span {
722 &self.span
723 }
724}
725
726impl AstNode for MintBlockField {
727 const RULE: Rule = Rule::mint_block_field;
728
729 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
730 match pair.as_rule() {
731 Rule::mint_block_amount => {
732 let pair = pair.into_inner().next().unwrap();
733 let x = MintBlockField::Amount(DataExpr::parse(pair)?.into());
734 Ok(x)
735 }
736 Rule::mint_block_redeemer => {
737 let pair = pair.into_inner().next().unwrap();
738 let x = MintBlockField::Redeemer(DataExpr::parse(pair)?.into());
739 Ok(x)
740 }
741 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
742 }
743 }
744
745 fn span(&self) -> &Span {
746 match self {
747 Self::Amount(x) => x.span(),
748 Self::Redeemer(x) => x.span(),
749 }
750 }
751}
752
753impl AstNode for SignersBlock {
754 const RULE: Rule = Rule::signers_block;
755
756 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
757 let span = pair.as_span().into();
758 let inner = pair.into_inner();
759
760 let signers = inner
761 .map(|x| DataExpr::parse(x))
762 .collect::<Result<Vec<_>, _>>()?;
763
764 Ok(SignersBlock { signers, span })
765 }
766
767 fn span(&self) -> &Span {
768 &self.span
769 }
770}
771
772impl AstNode for MintBlock {
773 const RULE: Rule = Rule::mint_block;
774
775 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
776 let span = pair.as_span().into();
777 let inner = pair.into_inner();
778
779 let fields = inner
780 .map(|x| MintBlockField::parse(x))
781 .collect::<Result<Vec<_>, _>>()?;
782
783 Ok(MintBlock { fields, span })
784 }
785
786 fn span(&self) -> &Span {
787 &self.span
788 }
789}
790
791impl AstNode for RecordField {
792 const RULE: Rule = Rule::record_field;
793
794 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
795 let span = pair.as_span().into();
796 let mut inner = pair.into_inner();
797 let identifier = Identifier::parse(inner.next().unwrap())?;
798 let r#type = Type::parse(inner.next().unwrap())?;
799
800 Ok(RecordField {
801 name: identifier,
802 r#type,
803 span,
804 })
805 }
806
807 fn span(&self) -> &Span {
808 &self.span
809 }
810}
811
812impl AstNode for PolicyField {
813 const RULE: Rule = Rule::policy_def_field;
814
815 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
816 match pair.as_rule() {
817 Rule::policy_def_hash => Ok(PolicyField::Hash(DataExpr::parse(
818 pair.into_inner().next().unwrap(),
819 )?)),
820 Rule::policy_def_script => Ok(PolicyField::Script(DataExpr::parse(
821 pair.into_inner().next().unwrap(),
822 )?)),
823 Rule::policy_def_ref => Ok(PolicyField::Ref(DataExpr::parse(
824 pair.into_inner().next().unwrap(),
825 )?)),
826 x => unreachable!("Unexpected rule in policy_field: {:?}", x),
827 }
828 }
829
830 fn span(&self) -> &Span {
831 match self {
832 Self::Hash(x) => x.span(),
833 Self::Script(x) => x.span(),
834 Self::Ref(x) => x.span(),
835 }
836 }
837}
838
839impl AstNode for PolicyConstructor {
840 const RULE: Rule = Rule::policy_def_constructor;
841
842 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
843 let span = pair.as_span().into();
844 let inner = pair.into_inner();
845
846 let fields = inner
847 .map(|x| PolicyField::parse(x))
848 .collect::<Result<Vec<_>, _>>()?;
849
850 Ok(PolicyConstructor { fields, span })
851 }
852
853 fn span(&self) -> &Span {
854 &self.span
855 }
856}
857
858impl AstNode for PolicyValue {
859 const RULE: Rule = Rule::policy_def_value;
860
861 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
862 match pair.as_rule() {
863 Rule::policy_def_constructor => {
864 Ok(PolicyValue::Constructor(PolicyConstructor::parse(pair)?))
865 }
866 Rule::policy_def_assign => Ok(PolicyValue::Assign(HexStringLiteral::parse(
867 pair.into_inner().next().unwrap(),
868 )?)),
869 x => unreachable!("Unexpected rule in policy_value: {:?}", x),
870 }
871 }
872
873 fn span(&self) -> &Span {
874 match self {
875 Self::Constructor(x) => x.span(),
876 Self::Assign(x) => x.span(),
877 }
878 }
879}
880
881impl AstNode for PolicyDef {
882 const RULE: Rule = Rule::policy_def;
883
884 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
885 let span = pair.as_span().into();
886 let mut inner = pair.into_inner();
887 let name = Identifier::parse(inner.next().unwrap())?;
888 let value = PolicyValue::parse(inner.next().unwrap())?;
889
890 Ok(PolicyDef { name, value, span })
891 }
892
893 fn span(&self) -> &Span {
894 &self.span
895 }
896}
897
898impl AstNode for AnyAssetConstructor {
899 const RULE: Rule = Rule::any_asset_constructor;
900
901 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
902 let span = pair.as_span().into();
903 let mut inner = pair.into_inner();
904
905 let policy = DataExpr::parse(inner.next().unwrap())?;
906 let asset_name = DataExpr::parse(inner.next().unwrap())?;
907 let amount = DataExpr::parse(inner.next().unwrap())?;
908
909 Ok(AnyAssetConstructor {
910 policy: Box::new(policy),
911 asset_name: Box::new(asset_name),
912 amount: Box::new(amount),
913 span,
914 })
915 }
916
917 fn span(&self) -> &Span {
918 &self.span
919 }
920}
921
922impl AstNode for ConcatOp {
923 const RULE: Rule = Rule::concat_constructor;
924
925 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
926 let span = pair.as_span().into();
927 let mut inner = pair.into_inner();
928
929 let lhs = DataExpr::parse(inner.next().unwrap())?;
930 let rhs = DataExpr::parse(inner.next().unwrap())?;
931
932 Ok(ConcatOp {
933 lhs: Box::new(lhs),
934 rhs: Box::new(rhs),
935 span,
936 })
937 }
938
939 fn span(&self) -> &Span {
940 &self.span
941 }
942}
943
944impl AstNode for crate::ast::FnCall {
945 const RULE: Rule = Rule::fn_call;
946
947 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
948 let span = pair.as_span().into();
949 let mut inner = pair.into_inner();
950
951 let callee = Identifier::parse(inner.next().unwrap())?;
952
953 let mut args = Vec::new();
954 for arg_pair in inner {
955 args.push(DataExpr::parse(arg_pair)?);
956 }
957
958 Ok(crate::ast::FnCall { callee, args, span })
959 }
960
961 fn span(&self) -> &Span {
962 &self.span
963 }
964}
965
966impl AstNode for LetBinding {
967 const RULE: Rule = Rule::let_binding;
968
969 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
970 let span = pair.as_span().into();
971 let mut inner = pair.into_inner();
972
973 let name = Identifier::parse(inner.next().unwrap())?;
974 let value = DataExpr::parse(inner.next().unwrap())?;
975
976 Ok(LetBinding { name, value, span })
977 }
978
979 fn span(&self) -> &Span {
980 &self.span
981 }
982}
983
984impl AstNode for FnBody {
985 const RULE: Rule = Rule::fn_body;
986
987 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
988 let span = pair.as_span().into();
989 let inner = pair.into_inner();
990
991 let mut let_bindings = Vec::new();
992 let mut result_expr = None;
993
994 for pair in inner {
995 match pair.as_rule() {
996 Rule::let_binding => let_bindings.push(LetBinding::parse(pair)?),
997 Rule::data_expr => result_expr = Some(DataExpr::parse(pair)?),
998 x => unreachable!("Unexpected rule in fn_body: {:?}", x),
999 }
1000 }
1001
1002 Ok(FnBody {
1003 let_bindings,
1004 result: Box::new(result_expr.expect("fn_body must have a result expression")),
1005 span,
1006 })
1007 }
1008
1009 fn span(&self) -> &Span {
1010 &self.span
1011 }
1012}
1013
1014impl AstNode for FnDef {
1015 const RULE: Rule = Rule::fn_def;
1016
1017 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1018 let span = pair.as_span().into();
1019 let mut inner = pair.into_inner();
1020
1021 let name = Identifier::parse(inner.next().unwrap())?;
1022 let parameters = ParameterList::parse(inner.next().unwrap())?;
1023 let return_type = Type::parse(inner.next().unwrap())?;
1024 let body = FnBody::parse(inner.next().unwrap())?;
1025
1026 Ok(FnDef {
1027 name,
1028 parameters,
1029 return_type,
1030 body: Some(body),
1031 builtin: None,
1032 span,
1033 scope: None,
1034 })
1035 }
1036
1037 fn span(&self) -> &Span {
1038 &self.span
1039 }
1040}
1041
1042impl AstNode for RecordConstructorField {
1043 const RULE: Rule = Rule::record_constructor_field;
1044
1045 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1046 let span = pair.as_span().into();
1047 let mut inner = pair.into_inner();
1048
1049 let name = Identifier::parse(inner.next().unwrap())?;
1050 let value = DataExpr::parse(inner.next().unwrap())?;
1051
1052 Ok(RecordConstructorField {
1053 name,
1054 value: Box::new(value),
1055 span,
1056 })
1057 }
1058
1059 fn span(&self) -> &Span {
1060 &self.span
1061 }
1062}
1063
1064impl AstNode for UtxoRef {
1065 const RULE: Rule = Rule::utxo_ref;
1066
1067 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1068 let span = pair.as_span().into();
1069 let raw_ref = pair.as_span().as_str()[2..].to_string();
1070 let (raw_txid, raw_output_ix) = raw_ref.split_once("#").expect("Invalid utxo ref");
1071
1072 Ok(UtxoRef {
1073 txid: hex::decode(raw_txid).expect("Invalid hex txid"),
1074 index: raw_output_ix.parse().expect("Invalid output index"),
1075 span,
1076 })
1077 }
1078
1079 fn span(&self) -> &Span {
1080 &self.span
1081 }
1082}
1083
1084impl AstNode for StructConstructor {
1085 const RULE: Rule = Rule::struct_constructor;
1086
1087 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1088 let span = pair.as_span().into();
1089 let mut inner = pair.into_inner();
1090
1091 let r#type = Identifier::parse(inner.next().unwrap())?;
1092 let case = VariantCaseConstructor::parse(inner.next().unwrap())?;
1093
1094 Ok(StructConstructor {
1095 r#type,
1096 case,
1097 scope: None,
1098 span,
1099 })
1100 }
1101
1102 fn span(&self) -> &Span {
1103 &self.span
1104 }
1105}
1106
1107impl VariantCaseConstructor {
1108 fn implicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1109 let span = pair.as_span().into();
1110 let inner = pair.into_inner();
1111
1112 let mut fields = Vec::new();
1113 let mut spread = None;
1114
1115 for pair in inner {
1116 match pair.as_rule() {
1117 Rule::record_constructor_field => {
1118 fields.push(RecordConstructorField::parse(pair)?);
1119 }
1120 Rule::spread_expression => {
1121 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
1122 }
1123 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
1124 }
1125 }
1126
1127 Ok(VariantCaseConstructor {
1128 name: Identifier::new("Default"),
1129 fields,
1130 spread: spread.map(Box::new),
1131 scope: None,
1132 span,
1133 })
1134 }
1135
1136 fn explicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1137 let span = pair.as_span().into();
1138 let mut inner = pair.into_inner();
1139
1140 let name = Identifier::parse(inner.next().unwrap())?;
1141
1142 let mut fields = Vec::new();
1143 let mut spread = None;
1144
1145 for pair in inner {
1146 match pair.as_rule() {
1147 Rule::record_constructor_field => {
1148 fields.push(RecordConstructorField::parse(pair)?);
1149 }
1150 Rule::spread_expression => {
1151 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
1152 }
1153 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
1154 }
1155 }
1156
1157 Ok(VariantCaseConstructor {
1158 name,
1159 fields,
1160 spread: spread.map(Box::new),
1161 scope: None,
1162 span,
1163 })
1164 }
1165}
1166
1167impl AstNode for VariantCaseConstructor {
1168 const RULE: Rule = Rule::variant_case_constructor;
1169
1170 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1171 match pair.as_rule() {
1172 Rule::implicit_variant_case_constructor => Self::implicit_parse(pair),
1173 Rule::explicit_variant_case_constructor => Self::explicit_parse(pair),
1174 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
1175 }
1176 }
1177
1178 fn span(&self) -> &Span {
1179 &self.span
1180 }
1181}
1182
1183impl AstNode for ListConstructor {
1184 const RULE: Rule = Rule::list_constructor;
1185
1186 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1187 let span = pair.as_span().into();
1188 let inner = pair.into_inner();
1189
1190 let elements = inner.map(DataExpr::parse).collect::<Result<Vec<_>, _>>()?;
1191
1192 Ok(ListConstructor { elements, span })
1193 }
1194
1195 fn span(&self) -> &Span {
1196 &self.span
1197 }
1198}
1199
1200impl AstNode for MapField {
1201 const RULE: Rule = Rule::map_field;
1202
1203 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1204 let span = pair.as_span().into();
1205 let mut inner = pair.into_inner();
1206
1207 let key = DataExpr::parse(inner.next().unwrap())?;
1208 let value = DataExpr::parse(inner.next().unwrap())?;
1209
1210 Ok(MapField { key, value, span })
1211 }
1212
1213 fn span(&self) -> &Span {
1214 &self.span
1215 }
1216}
1217
1218impl AstNode for MapConstructor {
1219 const RULE: Rule = Rule::map_constructor;
1220
1221 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1222 let span = pair.as_span().into();
1223 let inner = pair.into_inner();
1224
1225 let fields = inner.map(MapField::parse).collect::<Result<Vec<_>, _>>()?;
1226
1227 Ok(MapConstructor { fields, span })
1228 }
1229
1230 fn span(&self) -> &Span {
1231 &self.span
1232 }
1233}
1234
1235impl DataExpr {
1236 fn number_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1237 Ok(DataExpr::Number(pair.as_str().parse().unwrap()))
1238 }
1239
1240 fn bool_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1241 Ok(DataExpr::Bool(pair.as_str().parse().unwrap()))
1242 }
1243
1244 fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1245 Ok(DataExpr::Identifier(Identifier::parse(pair)?))
1246 }
1247
1248 fn struct_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1249 Ok(DataExpr::StructConstructor(StructConstructor::parse(pair)?))
1250 }
1251
1252 fn list_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1253 Ok(DataExpr::ListConstructor(ListConstructor::parse(pair)?))
1254 }
1255
1256 fn map_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1257 Ok(DataExpr::MapConstructor(MapConstructor::parse(pair)?))
1258 }
1259
1260 fn utxo_ref_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1261 Ok(DataExpr::UtxoRef(UtxoRef::parse(pair)?))
1262 }
1263
1264 fn any_asset_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1265 Ok(DataExpr::AnyAssetConstructor(AnyAssetConstructor::parse(
1266 pair,
1267 )?))
1268 }
1269
1270 fn concat_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1271 Ok(DataExpr::ConcatOp(ConcatOp::parse(pair)?))
1272 }
1273
1274 fn fn_call_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1275 Ok(DataExpr::FnCall(crate::ast::FnCall::parse(pair)?))
1276 }
1277
1278 fn negate_op_parse(pair: Pair<Rule>, right: DataExpr) -> Result<Self, Error> {
1279 Ok(DataExpr::NegateOp(NegateOp {
1280 operand: Box::new(right),
1281 span: pair.as_span().into(),
1282 }))
1283 }
1284
1285 fn property_op_parse(pair: Pair<Rule>, left: DataExpr) -> Result<Self, Error> {
1286 let span: Span = pair.as_span().into();
1287 let mut inner = pair.into_inner();
1288
1289 Ok(DataExpr::PropertyOp(PropertyOp {
1290 operand: Box::new(left),
1291 property: Box::new(DataExpr::Identifier(Identifier::parse(
1292 inner.next().unwrap(),
1293 )?)),
1294 span,
1295 scope: None,
1296 }))
1297 }
1298
1299 fn index_op_parse(pair: Pair<Rule>, left: DataExpr) -> Result<Self, Error> {
1300 let span: Span = pair.as_span().into();
1301 let mut inner = pair.into_inner();
1302
1303 Ok(DataExpr::PropertyOp(PropertyOp {
1304 operand: Box::new(left),
1305 property: Box::new(DataExpr::parse(inner.next().unwrap())?),
1306 span,
1307 scope: None,
1308 }))
1309 }
1310
1311 fn add_op_parse(left: DataExpr, pair: Pair<Rule>, right: DataExpr) -> Result<Self, Error> {
1312 let span = pair.as_span().into();
1313
1314 Ok(DataExpr::AddOp(AddOp {
1315 lhs: Box::new(left),
1316 rhs: Box::new(right),
1317 span,
1318 }))
1319 }
1320
1321 fn sub_op_parse(left: DataExpr, pair: Pair<Rule>, right: DataExpr) -> Result<Self, Error> {
1322 let span = pair.as_span().into();
1323
1324 Ok(DataExpr::SubOp(SubOp {
1325 lhs: Box::new(left),
1326 rhs: Box::new(right),
1327 span,
1328 }))
1329 }
1330}
1331
1332static DATA_EXPR_PRATT_PARSER: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
1333 PrattParser::new()
1334 .op(Op::infix(Rule::data_add, Assoc::Left) | Op::infix(Rule::data_sub, Assoc::Left))
1335 .op(Op::prefix(Rule::data_negate))
1336 .op(Op::postfix(Rule::data_property) | Op::postfix(Rule::data_index))
1337});
1338
1339impl AstNode for DataExpr {
1340 const RULE: Rule = Rule::data_expr;
1341
1342 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1343 let inner = pair.into_inner();
1344
1345 DATA_EXPR_PRATT_PARSER
1346 .map_primary(|x| match x.as_rule() {
1347 Rule::number => DataExpr::number_parse(x),
1348 Rule::string => Ok(DataExpr::String(StringLiteral::parse(x)?)),
1349 Rule::bool => DataExpr::bool_parse(x),
1350 Rule::hex_string => Ok(DataExpr::HexString(HexStringLiteral::parse(x)?)),
1351 Rule::struct_constructor => DataExpr::struct_constructor_parse(x),
1352 Rule::list_constructor => DataExpr::list_constructor_parse(x),
1353 Rule::map_constructor => DataExpr::map_constructor_parse(x),
1354 Rule::unit => Ok(DataExpr::Unit),
1355 Rule::identifier => DataExpr::identifier_parse(x),
1356 Rule::utxo_ref => DataExpr::utxo_ref_parse(x),
1357 Rule::any_asset_constructor => DataExpr::any_asset_constructor_parse(x),
1358 Rule::concat_constructor => DataExpr::concat_constructor_parse(x),
1359 Rule::fn_call => DataExpr::fn_call_parse(x),
1360 Rule::data_expr => DataExpr::parse(x),
1361 x => unreachable!("unexpected rule as data primary: {:?}", x),
1362 })
1363 .map_prefix(|op, right| match op.as_rule() {
1364 Rule::data_negate => DataExpr::negate_op_parse(op, right?),
1365 x => unreachable!("Unexpected rule as data prefix: {:?}", x),
1366 })
1367 .map_postfix(|left, op| match op.as_rule() {
1368 Rule::data_property => DataExpr::property_op_parse(op, left?),
1369 Rule::data_index => DataExpr::index_op_parse(op, left?),
1370 x => unreachable!("Unexpected rule as data postfix: {:?}", x),
1371 })
1372 .map_infix(|left, op, right| match op.as_rule() {
1373 Rule::data_add => DataExpr::add_op_parse(left?, op, right?),
1374 Rule::data_sub => DataExpr::sub_op_parse(left?, op, right?),
1375 x => unreachable!("Unexpected rule as data infix: {:?}", x),
1376 })
1377 .parse(inner)
1378 }
1379
1380 fn span(&self) -> &Span {
1381 match self {
1382 DataExpr::None => &Span::DUMMY, DataExpr::Unit => &Span::DUMMY, DataExpr::Number(_) => &Span::DUMMY, DataExpr::Bool(_) => &Span::DUMMY, DataExpr::String(x) => x.span(),
1387 DataExpr::HexString(x) => x.span(),
1388 DataExpr::StructConstructor(x) => x.span(),
1389 DataExpr::ListConstructor(x) => x.span(),
1390 DataExpr::MapConstructor(x) => x.span(),
1391 DataExpr::AnyAssetConstructor(x) => x.span(),
1392 DataExpr::Identifier(x) => x.span(),
1393 DataExpr::AddOp(x) => &x.span,
1394 DataExpr::SubOp(x) => &x.span,
1395 DataExpr::ConcatOp(x) => &x.span,
1396 DataExpr::NegateOp(x) => &x.span,
1397 DataExpr::PropertyOp(x) => &x.span,
1398 DataExpr::UtxoRef(x) => x.span(),
1399 DataExpr::FnCall(x) => &x.span,
1400 }
1401 }
1402}
1403
1404impl AstNode for Type {
1405 const RULE: Rule = Rule::r#type;
1406
1407 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1408 let inner = pair.into_inner().next().unwrap();
1409
1410 match inner.as_rule() {
1411 Rule::primitive_type => match inner.as_str() {
1412 "Int" => Ok(Type::Int),
1413 "Bool" => Ok(Type::Bool),
1414 "Bytes" => Ok(Type::Bytes),
1415 "Address" => Ok(Type::Address),
1416 "UtxoRef" => Ok(Type::UtxoRef),
1417 "AnyAsset" => Ok(Type::AnyAsset),
1418 _ => unreachable!("Unexpected string in primitive_type: {:?}", inner.as_str()),
1419 },
1420 Rule::list_type => {
1421 let inner = inner.into_inner().next().unwrap();
1422 Ok(Type::List(Box::new(Type::parse(inner)?)))
1423 }
1424 Rule::map_type => {
1425 let mut inner = inner.into_inner();
1426 let key_type = Type::parse(inner.next().unwrap())?;
1427 let value_type = Type::parse(inner.next().unwrap())?;
1428 Ok(Type::Map(Box::new(key_type), Box::new(value_type)))
1429 }
1430 Rule::custom_type => Ok(Type::Custom(Identifier::new(inner.as_str().to_owned()))),
1431 x => unreachable!("Unexpected rule in type: {:?}", x),
1432 }
1433 }
1434
1435 fn span(&self) -> &Span {
1436 &Span::DUMMY }
1438}
1439
1440impl TypeDef {
1441 fn parse_variant_format(pair: Pair<Rule>) -> Result<Self, Error> {
1442 let span = pair.as_span().into();
1443 let mut inner = pair.into_inner();
1444
1445 let identifier = Identifier::parse(inner.next().unwrap())?;
1446
1447 let cases = inner
1448 .map(VariantCase::parse)
1449 .collect::<Result<Vec<_>, _>>()?;
1450
1451 Ok(TypeDef {
1452 name: identifier,
1453 cases,
1454 span,
1455 })
1456 }
1457
1458 fn parse_record_format(pair: Pair<Rule>) -> Result<Self, Error> {
1459 let span: Span = pair.as_span().into();
1460 let mut inner = pair.into_inner();
1461
1462 let identifier = Identifier::parse(inner.next().unwrap())?;
1463
1464 let fields = inner
1465 .map(RecordField::parse)
1466 .collect::<Result<Vec<_>, _>>()?;
1467
1468 Ok(TypeDef {
1469 name: identifier.clone(),
1470 cases: vec![VariantCase {
1471 name: Identifier::new("Default"),
1472 fields,
1473 span: span.clone(),
1474 }],
1475 span,
1476 })
1477 }
1478}
1479
1480impl AstNode for TypeDef {
1481 const RULE: Rule = Rule::type_def;
1482
1483 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1484 match pair.as_rule() {
1485 Rule::variant_def => Ok(Self::parse_variant_format(pair)?),
1486 Rule::record_def => Ok(Self::parse_record_format(pair)?),
1487 x => unreachable!("Unexpected rule in type_def: {:?}", x),
1488 }
1489 }
1490
1491 fn span(&self) -> &Span {
1492 &self.span
1493 }
1494}
1495
1496impl AstNode for AliasDef {
1497 const RULE: Rule = Rule::alias_def;
1498
1499 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1500 let span: Span = pair.as_span().into();
1501 let mut inner = pair.into_inner();
1502
1503 let identifier = Identifier::parse(inner.next().unwrap())?;
1504 let r#type = Type::parse(inner.next().unwrap())?;
1505
1506 Ok(AliasDef {
1507 name: identifier,
1508 alias_type: r#type,
1509 span,
1510 })
1511 }
1512
1513 fn span(&self) -> &Span {
1514 &self.span
1515 }
1516}
1517
1518impl VariantCase {
1519 fn struct_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1520 let span = pair.as_span().into();
1521 let mut inner = pair.into_inner();
1522
1523 let identifier = Identifier::parse(inner.next().unwrap())?;
1524
1525 let fields = inner
1526 .map(RecordField::parse)
1527 .collect::<Result<Vec<_>, _>>()?;
1528
1529 Ok(Self {
1530 name: identifier,
1531 fields,
1532 span,
1533 })
1534 }
1535
1536 fn unit_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1537 let span = pair.as_span().into();
1538 let mut inner = pair.into_inner();
1539
1540 let identifier = Identifier::parse(inner.next().unwrap())?;
1541
1542 Ok(Self {
1543 name: identifier,
1544 fields: vec![],
1545 span,
1546 })
1547 }
1548}
1549
1550impl AstNode for VariantCase {
1551 const RULE: Rule = Rule::variant_case;
1552
1553 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1554 let case = match pair.as_rule() {
1555 Rule::variant_case_struct => Self::struct_case_parse(pair),
1556 Rule::variant_case_tuple => todo!("parse variant case tuple"),
1557 Rule::variant_case_unit => Self::unit_case_parse(pair),
1558 x => unreachable!("Unexpected rule in datum_variant: {:?}", x),
1559 }?;
1560
1561 Ok(case)
1562 }
1563
1564 fn span(&self) -> &Span {
1565 &self.span
1566 }
1567}
1568
1569impl AstNode for AssetDef {
1570 const RULE: Rule = Rule::asset_def;
1571
1572 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1573 let span = pair.as_span().into();
1574 let mut inner = pair.into_inner();
1575
1576 let identifier = Identifier::parse(inner.next().unwrap())?;
1577 let policy = DataExpr::parse(inner.next().unwrap())?;
1578 let asset_name = DataExpr::parse(inner.next().unwrap())?;
1579
1580 Ok(AssetDef {
1581 name: identifier,
1582 policy,
1583 asset_name,
1584 span,
1585 })
1586 }
1587
1588 fn span(&self) -> &Span {
1589 &self.span
1590 }
1591}
1592
1593impl AstNode for ChainSpecificBlock {
1594 const RULE: Rule = Rule::chain_specific_block;
1595
1596 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1597 let mut inner = pair.into_inner();
1598
1599 let block = inner.next().unwrap();
1600
1601 match block.as_rule() {
1602 Rule::cardano_block => {
1603 let block = crate::cardano::CardanoBlock::parse(block)?;
1604 Ok(ChainSpecificBlock::Cardano(block))
1605 }
1606 x => unreachable!("Unexpected rule in chain_specific_block: {:?}", x),
1607 }
1608 }
1609
1610 fn span(&self) -> &Span {
1611 match self {
1612 Self::Cardano(x) => x.span(),
1613 }
1614 }
1615}
1616
1617pub fn parse_string(input: &str) -> Result<Program, Error> {
1640 let pairs = Tx3Grammar::parse(Rule::program, input)?;
1641 Program::parse(pairs.into_iter().next().unwrap())
1642}
1643
1644#[cfg(test)]
1645pub fn parse_well_known_example(example: &str) -> Program {
1646 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1647 let test_file = format!("{}/../../examples/{}.tx3", manifest_dir, example);
1648 let input = std::fs::read_to_string(&test_file).unwrap();
1649 parse_string(&input).unwrap()
1650}
1651
1652#[cfg(test)]
1653mod tests {
1654 use super::*;
1655 use crate::ast;
1656 use assert_json_diff::assert_json_eq;
1657 use paste::paste;
1658 use pest::Parser;
1659
1660 #[test]
1661 fn smoke_test_parse_string() {
1662 let _ = parse_string("tx swap() {}").unwrap();
1663 }
1664
1665 macro_rules! input_to_ast_check {
1666 ($ast:ty, $name:expr, $input:expr, $expected:expr) => {
1667 paste::paste! {
1668 #[test]
1669 fn [<test_parse_ $ast:snake _ $name>]() {
1670 let pairs = super::Tx3Grammar::parse(<$ast>::RULE, $input).unwrap();
1671 let single_match = pairs.into_iter().next().unwrap();
1672 let result = <$ast>::parse(single_match).unwrap();
1673
1674 assert_eq!(result, $expected);
1675 }
1676 }
1677 };
1678 }
1679
1680 input_to_ast_check!(
1681 ConcatOp,
1682 "basic",
1683 r#"concat("hello", "world")"#,
1684 ast::ConcatOp {
1685 lhs: Box::new(ast::DataExpr::String(ast::StringLiteral {
1686 value: "hello".to_string(),
1687 span: ast::Span::DUMMY,
1688 })),
1689 rhs: Box::new(ast::DataExpr::String(ast::StringLiteral {
1690 value: "world".to_string(),
1691 span: ast::Span::DUMMY,
1692 })),
1693 span: ast::Span::DUMMY,
1694 }
1695 );
1696 input_to_ast_check!(Type, "int", "Int", Type::Int);
1697
1698 input_to_ast_check!(Type, "bool", "Bool", Type::Bool);
1699
1700 input_to_ast_check!(Type, "bytes", "Bytes", Type::Bytes);
1701
1702 input_to_ast_check!(Type, "address", "Address", Type::Address);
1703
1704 input_to_ast_check!(Type, "utxo_ref", "UtxoRef", Type::UtxoRef);
1705
1706 input_to_ast_check!(Type, "any_asset", "AnyAsset", Type::AnyAsset);
1707
1708 input_to_ast_check!(Type, "list", "List<Int>", Type::List(Box::new(Type::Int)));
1709
1710 input_to_ast_check!(
1711 Type,
1712 "identifier",
1713 "MyType",
1714 Type::Custom(Identifier::new("MyType".to_string()))
1715 );
1716
1717 input_to_ast_check!(
1718 Type,
1719 "other_type",
1720 "List<Bytes>",
1721 Type::List(Box::new(Type::Bytes))
1722 );
1723
1724 input_to_ast_check!(
1725 Type,
1726 "within_list",
1727 "List<List<Int>>",
1728 Type::List(Box::new(Type::List(Box::new(Type::Int))))
1729 );
1730
1731 input_to_ast_check!(
1732 TypeDef,
1733 "type_def_record",
1734 "type MyRecord {
1735 field1: Int,
1736 field2: Bytes,
1737 }",
1738 TypeDef {
1739 name: Identifier::new("MyRecord"),
1740 cases: vec![VariantCase {
1741 name: Identifier::new("Default"),
1742 fields: vec![
1743 RecordField::new("field1", Type::Int),
1744 RecordField::new("field2", Type::Bytes)
1745 ],
1746 span: Span::DUMMY,
1747 }],
1748 span: Span::DUMMY,
1749 }
1750 );
1751
1752 input_to_ast_check!(
1753 TypeDef,
1754 "type_def_variant",
1755 "type MyVariant {
1756 Case1 {
1757 field1: Int,
1758 field2: Bytes,
1759 },
1760 Case2,
1761 }",
1762 TypeDef {
1763 name: Identifier::new("MyVariant"),
1764 cases: vec![
1765 VariantCase {
1766 name: Identifier::new("Case1"),
1767 fields: vec![
1768 RecordField::new("field1", Type::Int),
1769 RecordField::new("field2", Type::Bytes)
1770 ],
1771 span: Span::DUMMY,
1772 },
1773 VariantCase {
1774 name: Identifier::new("Case2"),
1775 fields: vec![],
1776 span: Span::DUMMY,
1777 },
1778 ],
1779 span: Span::DUMMY,
1780 }
1781 );
1782
1783 input_to_ast_check!(
1784 AliasDef,
1785 "type_def_alias",
1786 "type MyAlias = Bytes;",
1787 AliasDef {
1788 name: Identifier::new("MyAlias"),
1789 alias_type: Type::Bytes,
1790 span: Span::DUMMY,
1791 }
1792 );
1793
1794 input_to_ast_check!(
1795 AliasDef,
1796 "type_alias_custom_type",
1797 "type UserAlias = UserType;",
1798 AliasDef {
1799 name: Identifier::new("UserAlias"),
1800 alias_type: Type::Custom(Identifier::new("UserType")),
1801 span: Span::DUMMY,
1802 }
1803 );
1804
1805 input_to_ast_check!(
1806 AliasDef,
1807 "type_alias_list",
1808 "type StringList = List<Bytes>;",
1809 AliasDef {
1810 name: Identifier::new("StringList"),
1811 alias_type: Type::List(Box::new(Type::Bytes)),
1812 span: Span::DUMMY,
1813 }
1814 );
1815
1816 input_to_ast_check!(
1817 AliasDef,
1818 "type_alias_map",
1819 "type StringIntMap = Map<Bytes, Int>;",
1820 AliasDef {
1821 name: Identifier::new("StringIntMap"),
1822 alias_type: Type::Map(Box::new(Type::Bytes), Box::new(Type::Int)),
1823 span: Span::DUMMY,
1824 }
1825 );
1826
1827 input_to_ast_check!(
1828 AliasDef,
1829 "type_alias_complex_nested",
1830 "type ComplexType = List<Map<Bytes, Int>>;",
1831 AliasDef {
1832 name: Identifier::new("ComplexType"),
1833 alias_type: Type::List(Box::new(Type::Map(
1834 Box::new(Type::Bytes),
1835 Box::new(Type::Int)
1836 ))),
1837 span: Span::DUMMY,
1838 }
1839 );
1840
1841 input_to_ast_check!(
1842 AliasDef,
1843 "type_alias_all_primitives",
1844 "type MyInt = Int;",
1845 AliasDef {
1846 name: Identifier::new("MyInt"),
1847 alias_type: Type::Int,
1848 span: Span::DUMMY,
1849 }
1850 );
1851
1852 input_to_ast_check!(
1853 AliasDef,
1854 "type_alias_bool",
1855 "type MyBool = Bool;",
1856 AliasDef {
1857 name: Identifier::new("MyBool"),
1858 alias_type: Type::Bool,
1859 span: Span::DUMMY,
1860 }
1861 );
1862
1863 input_to_ast_check!(
1864 AliasDef,
1865 "type_alias_address",
1866 "type MyAddress = Address;",
1867 AliasDef {
1868 name: Identifier::new("MyAddress"),
1869 alias_type: Type::Address,
1870 span: Span::DUMMY,
1871 }
1872 );
1873
1874 input_to_ast_check!(
1875 AliasDef,
1876 "type_alias_utxo_ref",
1877 "type MyUtxoRef = UtxoRef;",
1878 AliasDef {
1879 name: Identifier::new("MyUtxoRef"),
1880 alias_type: Type::UtxoRef,
1881 span: Span::DUMMY,
1882 }
1883 );
1884
1885 input_to_ast_check!(
1886 AliasDef,
1887 "type_alias_any_asset",
1888 "type MyAsset = AnyAsset;",
1889 AliasDef {
1890 name: Identifier::new("MyAsset"),
1891 alias_type: Type::AnyAsset,
1892 span: Span::DUMMY,
1893 }
1894 );
1895
1896 input_to_ast_check!(
1897 StringLiteral,
1898 "literal_string",
1899 "\"Hello, world!\"",
1900 StringLiteral::new("Hello, world!".to_string())
1901 );
1902
1903 input_to_ast_check!(
1904 HexStringLiteral,
1905 "hex_string",
1906 "0xAFAFAF",
1907 HexStringLiteral::new("AFAFAF".to_string())
1908 );
1909
1910 input_to_ast_check!(
1911 StringLiteral,
1912 "literal_string_address",
1913 "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1914 StringLiteral::new("addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string())
1915 );
1916
1917 input_to_ast_check!(
1918 ListConstructor,
1919 "empty_list",
1920 "[]",
1921 ListConstructor {
1922 elements: vec![],
1923 span: Span::DUMMY,
1924 }
1925 );
1926
1927 input_to_ast_check!(
1928 ListConstructor,
1929 "trailing_comma",
1930 "[1, 2,]",
1931 ListConstructor {
1932 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1933 span: Span::DUMMY,
1934 }
1935 );
1936
1937 input_to_ast_check!(
1938 ListConstructor,
1939 "int_list",
1940 "[1, 2]",
1941 ListConstructor {
1942 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1943 span: Span::DUMMY,
1944 }
1945 );
1946
1947 input_to_ast_check!(
1948 ListConstructor,
1949 "string_list",
1950 "[\"Hello\", \"World\"]",
1951 ListConstructor {
1952 elements: vec![
1953 DataExpr::String(StringLiteral::new("Hello".to_string())),
1954 DataExpr::String(StringLiteral::new("World".to_string()))
1955 ],
1956 span: Span::DUMMY,
1957 }
1958 );
1959
1960 input_to_ast_check!(
1961 ListConstructor,
1962 "mixed_list",
1963 "[1, \"Hello\", true]",
1964 ListConstructor {
1965 elements: vec![
1966 DataExpr::Number(1),
1967 DataExpr::String(StringLiteral::new("Hello".to_string())),
1968 DataExpr::Bool(true)
1969 ],
1970 span: Span::DUMMY,
1971 }
1972 );
1973
1974 input_to_ast_check!(
1975 ListConstructor,
1976 "list_within_list",
1977 "[[1, 2], [3, 4]]",
1978 ListConstructor {
1979 elements: vec![
1980 DataExpr::ListConstructor(ListConstructor {
1981 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1982 span: Span::DUMMY,
1983 }),
1984 DataExpr::ListConstructor(ListConstructor {
1985 elements: vec![DataExpr::Number(3), DataExpr::Number(4),],
1986 span: Span::DUMMY,
1987 }),
1988 ],
1989 span: Span::DUMMY,
1990 }
1991 );
1992
1993 input_to_ast_check!(DataExpr, "literal_bool_true", "true", DataExpr::Bool(true));
1994
1995 input_to_ast_check!(
1996 DataExpr,
1997 "literal_bool_false",
1998 "false",
1999 DataExpr::Bool(false)
2000 );
2001
2002 input_to_ast_check!(DataExpr, "unit_value", "())", DataExpr::Unit);
2003
2004 input_to_ast_check!(DataExpr, "number_value", "123", DataExpr::Number(123));
2005
2006 input_to_ast_check!(
2007 PolicyDef,
2008 "policy_def_assign",
2009 "policy MyPolicy = 0xAFAFAF;",
2010 PolicyDef {
2011 name: Identifier::new("MyPolicy"),
2012 value: PolicyValue::Assign(HexStringLiteral::new("AFAFAF".to_string())),
2013 span: Span::DUMMY,
2014 }
2015 );
2016
2017 input_to_ast_check!(
2018 PolicyDef,
2019 "policy_def_constructor",
2020 "policy MyPolicy {
2021 hash: 0x1234567890,
2022 script: 0x1234567890,
2023 ref: 0x1234567890,
2024 };",
2025 PolicyDef {
2026 name: Identifier::new("MyPolicy"),
2027 value: PolicyValue::Constructor(PolicyConstructor {
2028 fields: vec![
2029 PolicyField::Hash(DataExpr::HexString(HexStringLiteral::new(
2030 "1234567890".to_string()
2031 ))),
2032 PolicyField::Script(DataExpr::HexString(HexStringLiteral::new(
2033 "1234567890".to_string()
2034 ))),
2035 PolicyField::Ref(DataExpr::HexString(HexStringLiteral::new(
2036 "1234567890".to_string()
2037 ))),
2038 ],
2039 span: Span::DUMMY,
2040 }),
2041 span: Span::DUMMY,
2042 }
2043 );
2044
2045 input_to_ast_check!(
2046 AssetDef,
2047 "hex_hex",
2048 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.0xef7a1ceb;",
2049 AssetDef {
2050 name: Identifier::new("MyToken"),
2051 policy: DataExpr::HexString(HexStringLiteral::new(
2052 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
2053 )),
2054 asset_name: DataExpr::HexString(HexStringLiteral::new("ef7a1ceb".to_string())),
2055 span: Span::DUMMY,
2056 }
2057 );
2058
2059 input_to_ast_check!(
2060 AssetDef,
2061 "hex_string",
2062 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.\"MY TOKEN\";",
2063 AssetDef {
2064 name: Identifier::new("MyToken"),
2065 policy: DataExpr::HexString(HexStringLiteral::new(
2066 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
2067 )),
2068 asset_name: DataExpr::String(StringLiteral::new("MY TOKEN".to_string())),
2069 span: Span::DUMMY,
2070 }
2071 );
2072
2073 input_to_ast_check!(
2074 DataExpr,
2075 "type_and_literal",
2076 "MyToken(15)",
2077 DataExpr::FnCall(crate::ast::FnCall {
2078 callee: Identifier::new("MyToken"),
2079 args: vec![DataExpr::Number(15)],
2080 span: Span::DUMMY,
2081 })
2082 );
2083
2084 input_to_ast_check!(
2085 AnyAssetConstructor,
2086 "any_asset_constructor",
2087 "AnyAsset(0x1234567890, \"MyToken\", 15)",
2088 AnyAssetConstructor {
2089 policy: Box::new(DataExpr::HexString(HexStringLiteral::new(
2090 "1234567890".to_string()
2091 ))),
2092 asset_name: Box::new(DataExpr::String(StringLiteral::new("MyToken".to_string()))),
2093 amount: Box::new(DataExpr::Number(15)),
2094 span: Span::DUMMY,
2095 }
2096 );
2097
2098 input_to_ast_check!(
2099 AnyAssetConstructor,
2100 "any_asset_identifiers",
2101 "AnyAsset(my_policy, my_token, my_amount)",
2102 AnyAssetConstructor {
2103 policy: Box::new(DataExpr::Identifier(Identifier::new("my_policy"))),
2104 asset_name: Box::new(DataExpr::Identifier(Identifier::new("my_token"))),
2105 amount: Box::new(DataExpr::Identifier(Identifier::new("my_amount"))),
2106 span: Span::DUMMY,
2107 }
2108 );
2109
2110 input_to_ast_check!(
2111 AnyAssetConstructor,
2112 "any_asset_property_access",
2113 "AnyAsset(input1.policy, input1.asset_name, input1.amount)",
2114 AnyAssetConstructor {
2115 policy: Box::new(DataExpr::PropertyOp(PropertyOp {
2116 operand: Box::new(DataExpr::Identifier(Identifier::new("input1"))),
2117 property: Box::new(DataExpr::Identifier(Identifier::new("policy"))),
2118 span: Span::DUMMY,
2119 scope: None,
2120 })),
2121 asset_name: Box::new(DataExpr::PropertyOp(PropertyOp {
2122 operand: Box::new(DataExpr::Identifier(Identifier::new("input1"))),
2123 property: Box::new(DataExpr::Identifier(Identifier::new("asset_name"))),
2124 span: Span::DUMMY,
2125 scope: None,
2126 })),
2127 amount: Box::new(DataExpr::PropertyOp(PropertyOp {
2128 operand: Box::new(DataExpr::Identifier(Identifier::new("input1"))),
2129 property: Box::new(DataExpr::Identifier(Identifier::new("amount"))),
2130 span: Span::DUMMY,
2131 scope: None,
2132 })),
2133 span: Span::DUMMY,
2134 }
2135 );
2136
2137 input_to_ast_check!(DataExpr, "literal", "5", DataExpr::Number(5));
2138
2139 input_to_ast_check!(
2140 DataExpr,
2141 "add_op",
2142 "5 + var1",
2143 DataExpr::AddOp(AddOp {
2144 lhs: Box::new(DataExpr::Number(5)),
2145 rhs: Box::new(DataExpr::Identifier(Identifier::new("var1"))),
2146 span: Span::DUMMY,
2147 })
2148 );
2149
2150 input_to_ast_check!(
2151 DataExpr,
2152 "concat_op",
2153 r#"concat("hello", "world")"#,
2154 DataExpr::ConcatOp(ConcatOp {
2155 lhs: Box::new(ast::DataExpr::String(ast::StringLiteral {
2156 value: "hello".to_string(),
2157 span: ast::Span::DUMMY,
2158 })),
2159 rhs: Box::new(ast::DataExpr::String(ast::StringLiteral {
2160 value: "world".to_string(),
2161 span: ast::Span::DUMMY,
2162 })),
2163 span: ast::Span::DUMMY,
2164 })
2165 );
2166
2167 input_to_ast_check!(
2168 DataExpr,
2169 "property_access",
2170 "subject.property",
2171 DataExpr::PropertyOp(PropertyOp {
2172 operand: Box::new(DataExpr::Identifier(Identifier::new("subject"))),
2173 property: Box::new(DataExpr::Identifier(Identifier::new("property"))),
2174 span: Span::DUMMY,
2175 scope: None,
2176 })
2177 );
2178
2179 input_to_ast_check!(
2180 DataExpr,
2181 "multiple_properties",
2182 "subject.property.subproperty",
2183 DataExpr::PropertyOp(PropertyOp {
2184 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2185 operand: Box::new(DataExpr::Identifier(Identifier::new("subject"))),
2186 property: Box::new(DataExpr::Identifier(Identifier::new("property"))),
2187 span: Span::DUMMY,
2188 scope: None,
2189 })),
2190 property: Box::new(DataExpr::Identifier(Identifier::new("subproperty"))),
2191 span: Span::DUMMY,
2192 scope: None,
2193 })
2194 );
2195
2196 input_to_ast_check!(DataExpr, "empty_parentheses", "()", DataExpr::Unit);
2197
2198 input_to_ast_check!(DataExpr, "nested_parentheses", "((()))", DataExpr::Unit);
2199
2200 input_to_ast_check!(
2201 DataExpr,
2202 "nested_arithmetic_expression",
2203 "(1 + ((6 - 3) + 4))",
2204 DataExpr::AddOp(AddOp {
2205 lhs: Box::new(DataExpr::Number(1)),
2206 rhs: Box::new(DataExpr::AddOp(AddOp {
2207 lhs: Box::new(DataExpr::SubOp(SubOp {
2208 lhs: Box::new(DataExpr::Number(6)),
2209 rhs: Box::new(DataExpr::Number(3)),
2210 span: Span::DUMMY,
2211 })),
2212 rhs: Box::new(DataExpr::Number(4)),
2213 span: Span::DUMMY,
2214 })),
2215 span: Span::DUMMY,
2216 })
2217 );
2218
2219 input_to_ast_check!(
2220 DataExpr,
2221 "negate_op",
2222 "!a",
2223 DataExpr::NegateOp(NegateOp {
2224 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
2225 span: Span::DUMMY,
2226 })
2227 );
2228
2229 input_to_ast_check!(
2230 DataExpr,
2231 "negate_precedence",
2232 "!a.b",
2233 DataExpr::NegateOp(NegateOp {
2234 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2235 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
2236 property: Box::new(DataExpr::Identifier(Identifier::new("b"))),
2237 span: Span::DUMMY,
2238 scope: None,
2239 })),
2240 span: Span::DUMMY,
2241 })
2242 );
2243
2244 input_to_ast_check!(
2245 DataExpr,
2246 "negate_override_precedence",
2247 "(!a).b",
2248 DataExpr::PropertyOp(PropertyOp {
2249 operand: Box::new(DataExpr::NegateOp(NegateOp {
2250 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
2251 span: Span::DUMMY,
2252 })),
2253 property: Box::new(DataExpr::Identifier(Identifier::new("b"))),
2254 span: Span::DUMMY,
2255 scope: None,
2256 })
2257 );
2258
2259 input_to_ast_check!(
2260 DataExpr,
2261 "overly_complex",
2262 "(1 + 5) - ((a.b.c - 3) + !d.f)",
2263 DataExpr::SubOp(SubOp {
2264 lhs: Box::new(DataExpr::AddOp(AddOp {
2265 lhs: Box::new(DataExpr::Number(1)),
2266 rhs: Box::new(DataExpr::Number(5)),
2267 span: Span::DUMMY,
2268 })),
2269 rhs: Box::new(DataExpr::AddOp(AddOp {
2270 lhs: Box::new(DataExpr::SubOp(SubOp {
2271 lhs: Box::new(DataExpr::PropertyOp(PropertyOp {
2272 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2273 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
2274 property: Box::new(DataExpr::Identifier(Identifier::new("b"))),
2275 span: Span::DUMMY,
2276 scope: None,
2277 })),
2278 property: Box::new(DataExpr::Identifier(Identifier::new("c"))),
2279 span: Span::DUMMY,
2280 scope: None,
2281 })),
2282 rhs: Box::new(DataExpr::Number(3)),
2283 span: Span::DUMMY,
2284 })),
2285 rhs: Box::new(DataExpr::NegateOp(NegateOp {
2286 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2287 operand: Box::new(DataExpr::Identifier(Identifier::new("d"))),
2288 property: Box::new(DataExpr::Identifier(Identifier::new("f"))),
2289 span: Span::DUMMY,
2290 scope: None,
2291 })),
2292 span: Span::DUMMY,
2293 })),
2294
2295 span: Span::DUMMY,
2296 })),
2297 span: Span::DUMMY,
2298 })
2299 );
2300
2301 input_to_ast_check!(
2302 DataExpr,
2303 "min_utxo_basic",
2304 "min_utxo(output1)",
2305 DataExpr::FnCall(crate::ast::FnCall {
2306 callee: Identifier::new("min_utxo"),
2307 args: vec![DataExpr::Identifier(Identifier::new("output1"))],
2308 span: Span::DUMMY,
2309 })
2310 );
2311
2312 input_to_ast_check!(
2313 DataExpr,
2314 "min_utxo_in_expression",
2315 "Ada(100) + min_utxo(my_output)",
2316 DataExpr::AddOp(AddOp {
2317 lhs: Box::new(DataExpr::FnCall(crate::ast::FnCall {
2318 callee: Identifier::new("Ada"),
2319 args: vec![DataExpr::Number(100)],
2320 span: Span::DUMMY,
2321 })),
2322 rhs: Box::new(DataExpr::FnCall(crate::ast::FnCall {
2323 callee: Identifier::new("min_utxo"),
2324 args: vec![DataExpr::Identifier(Identifier::new("my_output"))],
2325 span: Span::DUMMY,
2326 })),
2327 span: Span::DUMMY,
2328 })
2329 );
2330
2331 input_to_ast_check!(
2332 DataExpr,
2333 "tip_slot_basic",
2334 "tip_slot()",
2335 DataExpr::FnCall(crate::ast::FnCall {
2336 callee: Identifier::new("tip_slot"),
2337 args: vec![],
2338 span: Span::DUMMY,
2339 })
2340 );
2341
2342 input_to_ast_check!(
2343 DataExpr,
2344 "tip_slot_in_expression",
2345 "1000 + tip_slot()",
2346 DataExpr::AddOp(AddOp {
2347 lhs: Box::new(DataExpr::Number(1000)),
2348 rhs: Box::new(DataExpr::FnCall(crate::ast::FnCall {
2349 callee: Identifier::new("tip_slot"),
2350 args: vec![],
2351 span: Span::DUMMY,
2352 })),
2353 span: Span::DUMMY,
2354 })
2355 );
2356
2357 input_to_ast_check!(
2358 StructConstructor,
2359 "struct_constructor_record",
2360 "MyRecord {
2361 field1: 10,
2362 field2: abc,
2363 }",
2364 StructConstructor {
2365 r#type: Identifier::new("MyRecord"),
2366 case: VariantCaseConstructor {
2367 name: Identifier::new("Default"),
2368 fields: vec![
2369 RecordConstructorField {
2370 name: Identifier::new("field1"),
2371 value: Box::new(DataExpr::Number(10)),
2372 span: Span::DUMMY,
2373 },
2374 RecordConstructorField {
2375 name: Identifier::new("field2"),
2376 value: Box::new(DataExpr::Identifier(Identifier::new("abc"))),
2377 span: Span::DUMMY,
2378 },
2379 ],
2380 spread: None,
2381 scope: None,
2382 span: Span::DUMMY,
2383 },
2384 scope: None,
2385 span: Span::DUMMY,
2386 }
2387 );
2388
2389 input_to_ast_check!(
2390 StructConstructor,
2391 "struct_constructor_variant",
2392 "ShipCommand::MoveShip {
2393 delta_x: delta_x,
2394 delta_y: delta_y,
2395 }",
2396 StructConstructor {
2397 r#type: Identifier::new("ShipCommand"),
2398 case: VariantCaseConstructor {
2399 name: Identifier::new("MoveShip"),
2400 fields: vec![
2401 RecordConstructorField {
2402 name: Identifier::new("delta_x"),
2403 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
2404 span: Span::DUMMY,
2405 },
2406 RecordConstructorField {
2407 name: Identifier::new("delta_y"),
2408 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
2409 span: Span::DUMMY,
2410 },
2411 ],
2412 spread: None,
2413 scope: None,
2414 span: Span::DUMMY,
2415 },
2416 scope: None,
2417 span: Span::DUMMY,
2418 }
2419 );
2420
2421 input_to_ast_check!(
2422 StructConstructor,
2423 "struct_constructor_variant_with_spread",
2424 "ShipCommand::MoveShip {
2425 delta_x: delta_x,
2426 delta_y: delta_y,
2427 ...abc
2428 }",
2429 StructConstructor {
2430 r#type: Identifier::new("ShipCommand"),
2431 case: VariantCaseConstructor {
2432 name: Identifier::new("MoveShip"),
2433 fields: vec![
2434 RecordConstructorField {
2435 name: Identifier::new("delta_x"),
2436 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
2437 span: Span::DUMMY,
2438 },
2439 RecordConstructorField {
2440 name: Identifier::new("delta_y"),
2441 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
2442 span: Span::DUMMY,
2443 },
2444 ],
2445 spread: Some(Box::new(DataExpr::Identifier(Identifier::new(
2446 "abc".to_string()
2447 )))),
2448 scope: None,
2449 span: Span::DUMMY,
2450 },
2451 scope: None,
2452 span: Span::DUMMY,
2453 }
2454 );
2455
2456 input_to_ast_check!(
2457 LocalsBlock,
2458 "basic",
2459 "locals {
2460 a: 10,
2461 }",
2462 LocalsBlock {
2463 assigns: vec![LocalsAssign {
2464 name: Identifier::new("a"),
2465 value: DataExpr::Number(10),
2466 span: Span::DUMMY,
2467 },],
2468 span: Span::DUMMY,
2469 }
2470 );
2471
2472 input_to_ast_check!(
2473 LocalsBlock,
2474 "multiple",
2475 "locals {
2476 a: 10,
2477 b: 20,
2478 }",
2479 LocalsBlock {
2480 assigns: vec![
2481 LocalsAssign {
2482 name: Identifier::new("a"),
2483 value: DataExpr::Number(10),
2484 span: Span::DUMMY,
2485 },
2486 LocalsAssign {
2487 name: Identifier::new("b"),
2488 value: DataExpr::Number(20),
2489 span: Span::DUMMY,
2490 },
2491 ],
2492 span: Span::DUMMY,
2493 }
2494 );
2495
2496 input_to_ast_check!(
2497 LocalsBlock,
2498 "complex_expression",
2499 "locals {
2500 a: (10 + 20) - 8,
2501 b: a.b.c + (5 - d),
2502 }",
2503 LocalsBlock {
2504 assigns: vec![
2505 LocalsAssign {
2506 name: Identifier::new("a"),
2507 value: DataExpr::SubOp(SubOp {
2508 lhs: Box::new(DataExpr::AddOp(AddOp {
2509 lhs: Box::new(DataExpr::Number(10)),
2510 rhs: Box::new(DataExpr::Number(20)),
2511 span: Span::DUMMY,
2512 })),
2513 rhs: Box::new(DataExpr::Number(8)),
2514 span: Span::DUMMY,
2515 }),
2516 span: Span::DUMMY,
2517 },
2518 LocalsAssign {
2519 name: Identifier::new("b"),
2520 value: DataExpr::AddOp(AddOp {
2521 lhs: Box::new(DataExpr::PropertyOp(PropertyOp {
2522 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2523 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
2524 property: Box::new(DataExpr::Identifier(Identifier::new("b"))),
2525 span: Span::DUMMY,
2526 scope: None,
2527 })),
2528 property: Box::new(DataExpr::Identifier(Identifier::new("c"))),
2529 span: Span::DUMMY,
2530 scope: None,
2531 })),
2532 rhs: Box::new(DataExpr::SubOp(SubOp {
2533 lhs: Box::new(DataExpr::Number(5)),
2534 rhs: Box::new(DataExpr::Identifier(Identifier::new("d"))),
2535 span: Span::DUMMY,
2536 })),
2537 span: Span::DUMMY,
2538 }),
2539 span: Span::DUMMY,
2540 },
2541 ],
2542 span: Span::DUMMY,
2543 }
2544 );
2545
2546 input_to_ast_check!(
2547 InputBlock,
2548 "single",
2549 r#"input source {}"#,
2550 InputBlock {
2551 many: false,
2552 name: "source".to_string(),
2553 fields: vec![],
2554 span: Span::DUMMY,
2555 }
2556 );
2557
2558 input_to_ast_check!(
2559 InputBlock,
2560 "multiple",
2561 r#"input* source {}"#,
2562 InputBlock {
2563 many: true,
2564 name: "source".to_string(),
2565 fields: vec![],
2566 span: Span::DUMMY,
2567 }
2568 );
2569
2570 input_to_ast_check!(
2571 OutputBlock,
2572 "output_block_anonymous",
2573 r#"output {
2574 to: my_party,
2575 amount: Ada(100),
2576 }"#,
2577 OutputBlock {
2578 name: None,
2579 optional: false,
2580 fields: vec![
2581 OutputBlockField::To(Box::new(DataExpr::Identifier(Identifier::new(
2582 "my_party".to_string(),
2583 )))),
2584 OutputBlockField::Amount(Box::new(DataExpr::FnCall(crate::ast::FnCall {
2585 callee: Identifier::new("Ada"),
2586 args: vec![DataExpr::Number(100)],
2587 span: Span::DUMMY,
2588 }))),
2589 ],
2590 span: Span::DUMMY,
2591 }
2592 );
2593
2594 input_to_ast_check!(
2595 ChainSpecificBlock,
2596 "chain_specific_block_cardano",
2597 "cardano::vote_delegation_certificate {
2598 drep: 0x1234567890,
2599 stake: 0x1234567890,
2600 }",
2601 ChainSpecificBlock::Cardano(crate::cardano::CardanoBlock::VoteDelegationCertificate(
2602 crate::cardano::VoteDelegationCertificate {
2603 drep: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
2604 stake: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
2605 span: Span::DUMMY,
2606 },
2607 ))
2608 );
2609
2610 input_to_ast_check!(
2611 ChainSpecificBlock,
2612 "chain_specific_block_cardano_treasury",
2613 "cardano::treasury_donation {
2614 coin: 20,
2615 }",
2616 ChainSpecificBlock::Cardano(crate::cardano::CardanoBlock::TreasuryDonation(
2617 crate::cardano::TreasuryDonationBlock {
2618 coin: DataExpr::Number(20),
2619 span: Span::DUMMY,
2620 },
2621 ))
2622 );
2623
2624 input_to_ast_check!(
2625 EnvDef,
2626 "basic",
2627 "env {
2628 field_a: Int,
2629 field_b: Bytes,
2630 }",
2631 EnvDef {
2632 fields: vec![
2633 EnvField {
2634 name: "field_a".to_string(),
2635 r#type: Type::Int,
2636 docstring: None,
2637 span: Span::DUMMY,
2638 },
2639 EnvField {
2640 name: "field_b".to_string(),
2641 r#type: Type::Bytes,
2642 docstring: None,
2643 span: Span::DUMMY,
2644 },
2645 ],
2646 span: Span::DUMMY,
2647 }
2648 );
2649
2650 input_to_ast_check!(
2651 TxDef,
2652 "empty",
2653 "tx my_tx() {}",
2654 TxDef {
2655 name: Identifier::new("my_tx"),
2656 docstring: None,
2657 parameters: ParameterList {
2658 parameters: vec![],
2659 span: Span::DUMMY,
2660 },
2661 locals: None,
2662 references: vec![],
2663 inputs: vec![],
2664 outputs: vec![],
2665 validity: None,
2666 mints: vec![],
2667 burns: vec![],
2668 signers: None,
2669 adhoc: vec![],
2670 collateral: vec![],
2671 metadata: None,
2672 scope: None,
2673 span: Span::DUMMY,
2674 }
2675 );
2676
2677 input_to_ast_check!(
2678 TxDef,
2679 "with_parameters",
2680 "tx my_tx(a: Int, b: Bytes) {}",
2681 TxDef {
2682 name: Identifier::new("my_tx"),
2683 docstring: None,
2684 parameters: ParameterList {
2685 parameters: vec![
2686 ParamDef {
2687 name: Identifier::new("a"),
2688 r#type: Type::Int,
2689 docstring: None,
2690 },
2691 ParamDef {
2692 name: Identifier::new("b"),
2693 r#type: Type::Bytes,
2694 docstring: None,
2695 },
2696 ],
2697 span: Span::DUMMY,
2698 },
2699 locals: None,
2700 references: vec![],
2701 inputs: vec![],
2702 outputs: vec![],
2703 validity: None,
2704 mints: vec![],
2705 burns: vec![],
2706 signers: None,
2707 adhoc: vec![],
2708 collateral: vec![],
2709 metadata: None,
2710 scope: None,
2711 span: Span::DUMMY,
2712 }
2713 );
2714
2715 input_to_ast_check!(
2716 Program,
2717 "basic",
2718 "party Abc; tx my_tx() {}",
2719 Program {
2720 parties: vec![PartyDef {
2721 name: Identifier::new("Abc"),
2722 docstring: None,
2723 span: Span::DUMMY,
2724 }],
2725 types: vec![],
2726 aliases: vec![],
2727 txs: vec![TxDef {
2728 name: Identifier::new("my_tx"),
2729 docstring: None,
2730 parameters: ParameterList {
2731 parameters: vec![],
2732 span: Span::DUMMY,
2733 },
2734 locals: None,
2735 references: vec![],
2736 inputs: vec![],
2737 outputs: vec![],
2738 validity: None,
2739 mints: vec![],
2740 burns: vec![],
2741 signers: None,
2742 adhoc: vec![],
2743 collateral: vec![],
2744 metadata: None,
2745 scope: None,
2746 span: Span::DUMMY,
2747 }],
2748 env: None,
2749 assets: vec![],
2750 policies: vec![],
2751 functions: vec![],
2752 span: Span::DUMMY,
2753 scope: None,
2754 }
2755 );
2756
2757 input_to_ast_check!(
2758 DataExpr,
2759 "array_index_literal",
2760 "my_list[0]",
2761 DataExpr::PropertyOp(PropertyOp {
2762 operand: Box::new(DataExpr::Identifier(Identifier::new("my_list"))),
2763 property: Box::new(DataExpr::Number(0)),
2764 span: Span::DUMMY,
2765 scope: None,
2766 })
2767 );
2768
2769 input_to_ast_check!(
2770 DataExpr,
2771 "array_index_variable",
2772 "my_list[index]",
2773 DataExpr::PropertyOp(PropertyOp {
2774 operand: Box::new(DataExpr::Identifier(Identifier::new("my_list"))),
2775 property: Box::new(DataExpr::Identifier(Identifier::new("index"))),
2776 span: Span::DUMMY,
2777 scope: None,
2778 })
2779 );
2780
2781 input_to_ast_check!(
2782 DataExpr,
2783 "nested_array_index",
2784 "matrix[row][col]",
2785 DataExpr::PropertyOp(PropertyOp {
2786 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2787 operand: Box::new(DataExpr::Identifier(Identifier::new("matrix"))),
2788 property: Box::new(DataExpr::Identifier(Identifier::new("row"))),
2789 span: Span::DUMMY,
2790 scope: None,
2791 })),
2792 property: Box::new(DataExpr::Identifier(Identifier::new("col"))),
2793 span: Span::DUMMY,
2794 scope: None,
2795 })
2796 );
2797
2798 input_to_ast_check!(
2799 DataExpr,
2800 "array_index_with_property_access",
2801 "items[index].name",
2802 DataExpr::PropertyOp(PropertyOp {
2803 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2804 operand: Box::new(DataExpr::Identifier(Identifier::new("items"))),
2805 property: Box::new(DataExpr::Identifier(Identifier::new("index"))),
2806 span: Span::DUMMY,
2807 scope: None,
2808 })),
2809 property: Box::new(DataExpr::Identifier(Identifier::new("name"))),
2810 span: Span::DUMMY,
2811 scope: None,
2812 })
2813 );
2814
2815 input_to_ast_check!(
2816 DataExpr,
2817 "property_access_then_array_index",
2818 "object.list[0]",
2819 DataExpr::PropertyOp(PropertyOp {
2820 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2821 operand: Box::new(DataExpr::Identifier(Identifier::new("object"))),
2822 property: Box::new(DataExpr::Identifier(Identifier::new("list"))),
2823 span: Span::DUMMY,
2824 scope: None,
2825 })),
2826 property: Box::new(DataExpr::Number(0)),
2827 span: Span::DUMMY,
2828 scope: None,
2829 })
2830 );
2831
2832 input_to_ast_check!(
2833 DataExpr,
2834 "array_index_with_function_call",
2835 "values[min_utxo(output)]",
2836 DataExpr::PropertyOp(PropertyOp {
2837 operand: Box::new(DataExpr::Identifier(Identifier::new("values"))),
2838 property: Box::new(DataExpr::FnCall(crate::ast::FnCall {
2839 callee: Identifier::new("min_utxo"),
2840 args: vec![DataExpr::Identifier(Identifier::new("output"))],
2841 span: Span::DUMMY,
2842 })),
2843 span: Span::DUMMY,
2844 scope: None,
2845 })
2846 );
2847
2848 input_to_ast_check!(
2849 DataExpr,
2850 "mixed_property_and_index_access",
2851 "container.items[index].metadata[\"key\"]",
2852 DataExpr::PropertyOp(PropertyOp {
2853 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2854 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2855 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2856 operand: Box::new(DataExpr::Identifier(Identifier::new("container"))),
2857 property: Box::new(DataExpr::Identifier(Identifier::new("items"))),
2858 span: Span::DUMMY,
2859 scope: None,
2860 })),
2861 property: Box::new(DataExpr::Identifier(Identifier::new("index"))),
2862 span: Span::DUMMY,
2863 scope: None,
2864 })),
2865 property: Box::new(DataExpr::Identifier(Identifier::new("metadata"))),
2866 span: Span::DUMMY,
2867 scope: None,
2868 })),
2869 property: Box::new(DataExpr::String(StringLiteral::new("key".to_string()))),
2870 span: Span::DUMMY,
2871 scope: None,
2872 })
2873 );
2874
2875 input_to_ast_check!(
2876 ReferenceBlock,
2877 "with_datum_type",
2878 "reference oracle_data { ref: oracle_utxo, datum_is: OracleDatum, }",
2879 ReferenceBlock {
2880 name: "oracle_data".to_string(),
2881 r#ref: DataExpr::Identifier(Identifier::new("oracle_utxo")),
2882 datum_is: Some(Type::Custom(Identifier::new("OracleDatum"))),
2883 span: Span::DUMMY,
2884 }
2885 );
2886
2887 input_to_ast_check!(
2888 MapConstructor,
2889 "empty",
2890 "{}",
2891 MapConstructor {
2892 fields: vec![],
2893 span: Span::DUMMY,
2894 }
2895 );
2896
2897 input_to_ast_check!(
2898 PartyDef,
2899 "with_docstring",
2900 "/// the protocol treasury\nparty Treasury;",
2901 PartyDef {
2902 name: Identifier::new("Treasury"),
2903 docstring: Some("the protocol treasury".to_string()),
2904 span: Span::DUMMY,
2905 }
2906 );
2907
2908 input_to_ast_check!(
2909 EnvField,
2910 "with_docstring",
2911 "/// network magic\nnetwork: Int",
2912 EnvField {
2913 name: "network".to_string(),
2914 r#type: Type::Int,
2915 docstring: Some("network magic".to_string()),
2916 span: Span::DUMMY,
2917 }
2918 );
2919
2920 input_to_ast_check!(
2921 TxDef,
2922 "with_multiline_docstring",
2923 "/// transfer funds from a to b\n/// across two lines\ntx transfer() {}",
2924 TxDef {
2925 name: Identifier::new("transfer"),
2926 docstring: Some("transfer funds from a to b\nacross two lines".to_string()),
2927 parameters: ParameterList {
2928 parameters: vec![],
2929 span: Span::DUMMY,
2930 },
2931 locals: None,
2932 references: vec![],
2933 inputs: vec![],
2934 outputs: vec![],
2935 validity: None,
2936 mints: vec![],
2937 burns: vec![],
2938 signers: None,
2939 adhoc: vec![],
2940 collateral: vec![],
2941 metadata: None,
2942 scope: None,
2943 span: Span::DUMMY,
2944 }
2945 );
2946
2947 input_to_ast_check!(
2948 ParameterList,
2949 "with_param_docstrings",
2950 "(/// amount in lovelace\nquantity: Int, target: Address)",
2951 ParameterList {
2952 parameters: vec![
2953 ParamDef {
2954 name: Identifier::new("quantity"),
2955 r#type: Type::Int,
2956 docstring: Some("amount in lovelace".to_string()),
2957 },
2958 ParamDef {
2959 name: Identifier::new("target"),
2960 r#type: Type::Address,
2961 docstring: None,
2962 },
2963 ],
2964 span: Span::DUMMY,
2965 }
2966 );
2967
2968 #[test]
2969 fn test_spans_are_respected() {
2970 let program = parse_well_known_example("spans");
2971 assert_eq!(program.span, Span::new(0, 759));
2972
2973 assert_eq!(program.parties[0].span, Span::new(27, 41));
2974
2975 assert_eq!(program.types[0].span, Span::new(43, 77));
2976 }
2977
2978 fn make_snapshot_if_missing(example: &str, program: &Program) {
2979 let manifest_dir = env!("CARGO_MANIFEST_DIR");
2980 let path = format!("{}/../../examples/{}.ast", manifest_dir, example);
2981
2982 if !std::fs::exists(&path).unwrap() {
2983 let ast = serde_json::to_string_pretty(program).unwrap();
2984 std::fs::write(&path, ast).unwrap();
2985 }
2986 }
2987
2988 fn test_parsing_example(example: &str) {
2989 let program = parse_well_known_example(example);
2990 make_snapshot_if_missing(example, &program);
2991
2992 let manifest_dir = env!("CARGO_MANIFEST_DIR");
2993 let ast_file = format!("{}/../../examples/{}.ast", manifest_dir, example);
2994 let ast = std::fs::read_to_string(ast_file).unwrap();
2995
2996 let expected: Program = serde_json::from_str(&ast).unwrap();
2997
2998 assert_json_eq!(program, expected);
2999 }
3000
3001 #[macro_export]
3002 macro_rules! test_parsing {
3003 ($name:ident) => {
3004 paste! {
3005 #[test]
3006 fn [<test_example_ $name>]() {
3007 test_parsing_example(stringify!($name));
3008 }
3009 }
3010 };
3011 }
3012
3013 test_parsing!(lang_tour);
3014
3015 test_parsing!(transfer);
3016
3017 test_parsing!(swap);
3018
3019 test_parsing!(asteria);
3020
3021 test_parsing!(vesting);
3022
3023 test_parsing!(faucet);
3024
3025 test_parsing!(disordered);
3026
3027 test_parsing!(input_datum);
3028
3029 test_parsing!(withdrawal);
3030
3031 test_parsing!(env_vars);
3032
3033 test_parsing!(local_vars);
3034
3035 test_parsing!(cardano_witness);
3036
3037 test_parsing!(reference_script);
3038
3039 test_parsing!(map);
3040
3041 test_parsing!(burn);
3042
3043 test_parsing!(donation);
3044
3045 test_parsing!(list_concat);
3046
3047 test_parsing!(buidler_fest_2026);
3048
3049 test_parsing!(functions);
3050
3051 test_parsing!(nested_functions);
3052}