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
80impl AstNode for Program {
81 const RULE: Rule = Rule::program;
82
83 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
84 let span = pair.as_span().into();
85 let inner = pair.into_inner();
86
87 let mut program = Self {
88 env: None,
89 txs: Vec::new(),
90 assets: Vec::new(),
91 types: Vec::new(),
92 parties: Vec::new(),
93 policies: Vec::new(),
94 scope: None,
95 span,
96 };
97
98 for pair in inner {
99 match pair.as_rule() {
100 Rule::env_def => program.env = Some(EnvDef::parse(pair)?),
101 Rule::tx_def => program.txs.push(TxDef::parse(pair)?),
102 Rule::asset_def => program.assets.push(AssetDef::parse(pair)?),
103 Rule::record_def => program.types.push(TypeDef::parse(pair)?),
104 Rule::variant_def => program.types.push(TypeDef::parse(pair)?),
105 Rule::party_def => program.parties.push(PartyDef::parse(pair)?),
106 Rule::policy_def => program.policies.push(PolicyDef::parse(pair)?),
107 Rule::EOI => break,
108 x => unreachable!("Unexpected rule in program: {:?}", x),
109 }
110 }
111
112 Ok(program)
113 }
114
115 fn span(&self) -> &Span {
116 &self.span
117 }
118}
119
120impl AstNode for EnvField {
121 const RULE: Rule = Rule::env_field;
122
123 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
124 let span = pair.as_span().into();
125 let mut inner = pair.into_inner();
126 let identifier = inner.next().unwrap().as_str().to_string();
127 let r#type = Type::parse(inner.next().unwrap())?;
128
129 Ok(EnvField {
130 name: identifier,
131 r#type,
132 span,
133 })
134 }
135
136 fn span(&self) -> &Span {
137 &self.span
138 }
139}
140
141impl AstNode for EnvDef {
142 const RULE: Rule = Rule::env_def;
143
144 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
145 let span = pair.as_span().into();
146 let inner = pair.into_inner();
147
148 let fields = inner
149 .map(|x| EnvField::parse(x))
150 .collect::<Result<Vec<_>, _>>()?;
151
152 Ok(EnvDef { fields, span })
153 }
154
155 fn span(&self) -> &Span {
156 &self.span
157 }
158}
159
160impl AstNode for ParameterList {
161 const RULE: Rule = Rule::parameter_list;
162
163 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
164 let span = pair.as_span().into();
165 let inner = pair.into_inner();
166
167 let mut parameters = Vec::new();
168
169 for param in inner {
170 let mut inner = param.into_inner();
171 let name = Identifier::parse(inner.next().unwrap())?;
172 let r#type = Type::parse(inner.next().unwrap())?;
173
174 parameters.push(ParamDef { name, r#type });
175 }
176
177 Ok(ParameterList { parameters, span })
178 }
179
180 fn span(&self) -> &Span {
181 &self.span
182 }
183}
184
185impl AstNode for TxDef {
186 const RULE: Rule = Rule::tx_def;
187
188 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
189 let span = pair.as_span().into();
190 let mut inner = pair.into_inner();
191
192 let name = Identifier::parse(inner.next().unwrap())?;
193 let parameters = ParameterList::parse(inner.next().unwrap())?;
194
195 let mut locals = None;
196 let mut references = Vec::new();
197 let mut inputs = Vec::new();
198 let mut outputs = Vec::new();
199 let mut validity = None;
200 let mut burn = None;
201 let mut mints = Vec::new();
202 let mut adhoc = Vec::new();
203 let mut collateral = Vec::new();
204 let mut signers = None;
205 let mut metadata = None;
206
207 for item in inner {
208 match item.as_rule() {
209 Rule::locals_block => locals = Some(LocalsBlock::parse(item)?),
210 Rule::reference_block => references.push(ReferenceBlock::parse(item)?),
211 Rule::input_block => inputs.push(InputBlock::parse(item)?),
212 Rule::output_block => outputs.push(OutputBlock::parse(item)?),
213 Rule::validity_block => validity = Some(ValidityBlock::parse(item)?),
214 Rule::burn_block => burn = Some(BurnBlock::parse(item)?),
215 Rule::mint_block => mints.push(MintBlock::parse(item)?),
216 Rule::chain_specific_block => adhoc.push(ChainSpecificBlock::parse(item)?),
217 Rule::collateral_block => collateral.push(CollateralBlock::parse(item)?),
218 Rule::signers_block => signers = Some(SignersBlock::parse(item)?),
219 Rule::metadata_block => metadata = Some(MetadataBlock::parse(item)?),
220 x => unreachable!("Unexpected rule in tx_def: {:?}", x),
221 }
222 }
223
224 Ok(TxDef {
225 name,
226 parameters,
227 locals,
228 references,
229 inputs,
230 outputs,
231 validity,
232 burn,
233 mints,
234 signers,
235 adhoc,
236 scope: None,
237 span,
238 collateral,
239 metadata,
240 })
241 }
242
243 fn span(&self) -> &Span {
244 &self.span
245 }
246}
247
248impl AstNode for Identifier {
249 const RULE: Rule = Rule::identifier;
250
251 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
252 Ok(Identifier {
253 value: pair.as_str().to_string(),
254 symbol: None,
255 span: pair.as_span().into(),
256 })
257 }
258
259 fn span(&self) -> &Span {
260 &self.span
261 }
262}
263
264impl AstNode for StringLiteral {
265 const RULE: Rule = Rule::string;
266
267 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
268 Ok(StringLiteral {
269 value: pair.as_str()[1..pair.as_str().len() - 1].to_string(),
270 span: pair.as_span().into(),
271 })
272 }
273
274 fn span(&self) -> &Span {
275 &self.span
276 }
277}
278
279impl AstNode for HexStringLiteral {
280 const RULE: Rule = Rule::hex_string;
281
282 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
283 Ok(HexStringLiteral {
284 value: pair.as_str()[2..].to_string(),
285 span: pair.as_span().into(),
286 })
287 }
288
289 fn span(&self) -> &Span {
290 &self.span
291 }
292}
293
294impl AstNode for PartyDef {
295 const RULE: Rule = Rule::party_def;
296
297 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
298 let span = pair.as_span().into();
299 let mut inner = pair.into_inner();
300 let identifier = Identifier::parse(inner.next().unwrap())?;
301
302 Ok(PartyDef {
303 name: identifier,
304 span,
305 })
306 }
307
308 fn span(&self) -> &Span {
309 &self.span
310 }
311}
312
313impl AstNode for LocalsAssign {
314 const RULE: Rule = Rule::locals_assign;
315
316 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
317 let span = pair.as_span().into();
318 let mut inner = pair.into_inner();
319
320 let name = Identifier::parse(inner.next().unwrap())?;
321 let value = DataExpr::parse(inner.next().unwrap())?;
322
323 Ok(LocalsAssign { name, value, span })
324 }
325
326 fn span(&self) -> &Span {
327 &self.span
328 }
329}
330
331impl AstNode for LocalsBlock {
332 const RULE: Rule = Rule::locals_block;
333
334 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
335 let span = pair.as_span().into();
336 let inner = pair.into_inner();
337
338 let assigns = inner
339 .map(|x| LocalsAssign::parse(x))
340 .collect::<Result<Vec<_>, _>>()?;
341
342 Ok(LocalsBlock { assigns, span })
343 }
344
345 fn span(&self) -> &Span {
346 &self.span
347 }
348}
349
350impl AstNode for ReferenceBlock {
351 const RULE: Rule = Rule::reference_block;
352
353 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
354 let span = pair.as_span().into();
355 let mut inner = pair.into_inner();
356
357 let name = inner.next().unwrap().as_str().to_string();
358
359 let pair = inner.next().unwrap();
360 match pair.as_rule() {
361 Rule::input_block_ref => {
362 let pair = pair.into_inner().next().unwrap();
363 let r#ref = DataExpr::parse(pair)?;
364 Ok(ReferenceBlock { name, r#ref, span })
365 }
366 x => unreachable!("Unexpected rule in ref_input_block: {:?}", x),
367 }
368 }
369
370 fn span(&self) -> &Span {
371 &self.span
372 }
373}
374
375impl AstNode for CollateralBlockField {
376 const RULE: Rule = Rule::collateral_block_field;
377
378 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
379 match pair.as_rule() {
380 Rule::input_block_from => {
381 let pair = pair.into_inner().next().unwrap();
382 let x = CollateralBlockField::From(DataExpr::parse(pair)?);
383 Ok(x)
384 }
385 Rule::input_block_min_amount => {
386 let pair = pair.into_inner().next().unwrap();
387 let x = CollateralBlockField::MinAmount(DataExpr::parse(pair)?);
388 Ok(x)
389 }
390 Rule::input_block_ref => {
391 let pair = pair.into_inner().next().unwrap();
392 let x = CollateralBlockField::Ref(DataExpr::parse(pair)?);
393 Ok(x)
394 }
395 x => unreachable!("Unexpected rule in collateral_block: {:?}", x),
396 }
397 }
398
399 fn span(&self) -> &Span {
400 match self {
401 Self::From(x) => x.span(),
402 Self::MinAmount(x) => x.span(),
403 Self::Ref(x) => x.span(),
404 }
405 }
406}
407
408impl AstNode for CollateralBlock {
409 const RULE: Rule = Rule::collateral_block;
410
411 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
412 let span = pair.as_span().into();
413 let inner = pair.into_inner();
414
415 let fields = inner
416 .map(|x| CollateralBlockField::parse(x))
417 .collect::<Result<Vec<_>, _>>()?;
418
419 Ok(CollateralBlock { fields, span })
420 }
421
422 fn span(&self) -> &Span {
423 &self.span
424 }
425}
426
427impl AstNode for MetadataBlockField {
428 const RULE: Rule = Rule::metadata_block_field;
429
430 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
431 let span = pair.as_span().into();
432 match pair.as_rule() {
433 Rule::metadata_block_field => {
434 let mut inner = pair.into_inner();
435 let key = inner.next().unwrap();
436 let value = inner.next().unwrap();
437 Ok(MetadataBlockField {
438 key: DataExpr::parse(key)?,
439 value: DataExpr::parse(value)?,
440 span,
441 })
442 }
443 x => unreachable!("Unexpected rule in metadata_block: {:?}", x),
444 }
445 }
446
447 fn span(&self) -> &Span {
448 &self.span
449 }
450}
451
452impl AstNode for MetadataBlock {
453 const RULE: Rule = Rule::metadata_block;
454
455 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
456 let span = pair.as_span().into();
457 let inner = pair.into_inner();
458
459 let fields = inner
460 .map(|x| MetadataBlockField::parse(x))
461 .collect::<Result<Vec<_>, _>>()?;
462
463 Ok(MetadataBlock { fields, span })
464 }
465
466 fn span(&self) -> &Span {
467 &self.span
468 }
469}
470
471impl AstNode for InputBlockField {
472 const RULE: Rule = Rule::input_block_field;
473
474 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
475 match pair.as_rule() {
476 Rule::input_block_from => {
477 let pair = pair.into_inner().next().unwrap();
478 let x = InputBlockField::From(DataExpr::parse(pair)?);
479 Ok(x)
480 }
481 Rule::input_block_datum_is => {
482 let pair = pair.into_inner().next().unwrap();
483 let x = InputBlockField::DatumIs(Type::parse(pair)?);
484 Ok(x)
485 }
486 Rule::input_block_min_amount => {
487 let pair = pair.into_inner().next().unwrap();
488 let x = InputBlockField::MinAmount(DataExpr::parse(pair)?);
489 Ok(x)
490 }
491 Rule::input_block_redeemer => {
492 let pair = pair.into_inner().next().unwrap();
493 let x = InputBlockField::Redeemer(DataExpr::parse(pair)?);
494 Ok(x)
495 }
496 Rule::input_block_ref => {
497 let pair = pair.into_inner().next().unwrap();
498 let x = InputBlockField::Ref(DataExpr::parse(pair)?);
499 Ok(x)
500 }
501 x => unreachable!("Unexpected rule in input_block: {:?}", x),
502 }
503 }
504
505 fn span(&self) -> &Span {
506 match self {
507 Self::From(x) => x.span(),
508 Self::DatumIs(x) => x.span(),
509 Self::MinAmount(x) => x.span(),
510 Self::Redeemer(x) => x.span(),
511 Self::Ref(x) => x.span(),
512 }
513 }
514}
515
516impl AstNode for InputBlock {
517 const RULE: Rule = Rule::input_block;
518
519 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
520 let span = pair.as_span().into();
521 let mut inner = pair.into_inner();
522
523 let name = inner.next().unwrap().as_str().to_string();
524
525 let fields = inner
526 .map(|x| InputBlockField::parse(x))
527 .collect::<Result<Vec<_>, _>>()?;
528
529 Ok(InputBlock {
530 name,
531 is_many: false,
532 fields,
533 span,
534 })
535 }
536
537 fn span(&self) -> &Span {
538 &self.span
539 }
540}
541
542impl AstNode for OutputBlockField {
543 const RULE: Rule = Rule::output_block_field;
544
545 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
546 match pair.as_rule() {
547 Rule::output_block_to => {
548 let pair = pair.into_inner().next().unwrap();
549 let x = OutputBlockField::To(Box::new(DataExpr::parse(pair)?));
550 Ok(x)
551 }
552 Rule::output_block_amount => {
553 let pair = pair.into_inner().next().unwrap();
554 let x = OutputBlockField::Amount(DataExpr::parse(pair)?.into());
555 Ok(x)
556 }
557 Rule::output_block_datum => {
558 let pair = pair.into_inner().next().unwrap();
559 let x = OutputBlockField::Datum(DataExpr::parse(pair)?.into());
560 Ok(x)
561 }
562 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
563 }
564 }
565
566 fn span(&self) -> &Span {
567 match self {
568 Self::To(x) => x.span(),
569 Self::Amount(x) => x.span(),
570 Self::Datum(x) => x.span(),
571 }
572 }
573}
574
575impl AstNode for OutputBlock {
576 const RULE: Rule = Rule::output_block;
577
578 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
579 let span = pair.as_span().into();
580 let mut inner = pair.into_inner();
581
582 let has_name = inner
583 .peek()
584 .map(|x| x.as_rule() == Rule::identifier)
585 .unwrap_or_default();
586
587 let name = has_name.then(|| inner.next().unwrap().as_str().to_string());
588
589 let fields = inner
590 .map(|x| OutputBlockField::parse(x))
591 .collect::<Result<Vec<_>, _>>()?;
592
593 Ok(OutputBlock { name, fields, span })
594 }
595
596 fn span(&self) -> &Span {
597 &self.span
598 }
599}
600
601impl AstNode for ValidityBlockField {
602 const RULE: Rule = Rule::validity_block_field;
603
604 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
605 match pair.as_rule() {
606 Rule::validity_since_slot => {
607 let pair = pair.into_inner().next().unwrap();
608 let x = ValidityBlockField::SinceSlot(DataExpr::parse(pair)?.into());
609 Ok(x)
610 }
611 Rule::validity_until_slot => {
612 let pair = pair.into_inner().next().unwrap();
613 let x = ValidityBlockField::UntilSlot(DataExpr::parse(pair)?.into());
614 Ok(x)
615 }
616 x => unreachable!("Unexpected rule in validity_block: {:?}", x),
617 }
618 }
619
620 fn span(&self) -> &Span {
621 match self {
622 Self::UntilSlot(x) => x.span(),
623 Self::SinceSlot(x) => x.span(),
624 }
625 }
626}
627
628impl AstNode for ValidityBlock {
629 const RULE: Rule = Rule::validity_block;
630
631 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
632 let span = pair.as_span().into();
633 let inner = pair.into_inner();
634
635 let fields = inner
636 .map(|x| ValidityBlockField::parse(x))
637 .collect::<Result<Vec<_>, _>>()?;
638
639 Ok(ValidityBlock { fields, span })
640 }
641
642 fn span(&self) -> &Span {
643 &self.span
644 }
645}
646
647impl AstNode for MintBlockField {
648 const RULE: Rule = Rule::mint_block_field;
649
650 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
651 match pair.as_rule() {
652 Rule::mint_block_amount => {
653 let pair = pair.into_inner().next().unwrap();
654 let x = MintBlockField::Amount(DataExpr::parse(pair)?.into());
655 Ok(x)
656 }
657 Rule::mint_block_redeemer => {
658 let pair = pair.into_inner().next().unwrap();
659 let x = MintBlockField::Redeemer(DataExpr::parse(pair)?.into());
660 Ok(x)
661 }
662 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
663 }
664 }
665
666 fn span(&self) -> &Span {
667 match self {
668 Self::Amount(x) => x.span(),
669 Self::Redeemer(x) => x.span(),
670 }
671 }
672}
673
674impl AstNode for SignersBlock {
675 const RULE: Rule = Rule::signers_block;
676
677 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
678 let span = pair.as_span().into();
679 let inner = pair.into_inner();
680
681 let signers = inner
682 .map(|x| DataExpr::parse(x))
683 .collect::<Result<Vec<_>, _>>()?;
684
685 Ok(SignersBlock { signers, span })
686 }
687
688 fn span(&self) -> &Span {
689 &self.span
690 }
691}
692
693impl AstNode for MintBlock {
694 const RULE: Rule = Rule::mint_block;
695
696 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
697 let span = pair.as_span().into();
698 let inner = pair.into_inner();
699
700 let fields = inner
701 .map(|x| MintBlockField::parse(x))
702 .collect::<Result<Vec<_>, _>>()?;
703
704 Ok(MintBlock { fields, span })
705 }
706
707 fn span(&self) -> &Span {
708 &self.span
709 }
710}
711
712impl AstNode for BurnBlock {
713 const RULE: Rule = Rule::burn_block;
714
715 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
716 let span = pair.as_span().into();
717 let inner = pair.into_inner();
718
719 let fields = inner
720 .map(|x| MintBlockField::parse(x))
721 .collect::<Result<Vec<_>, _>>()?;
722
723 Ok(BurnBlock { fields, span })
724 }
725
726 fn span(&self) -> &Span {
727 &self.span
728 }
729}
730
731impl AstNode for RecordField {
732 const RULE: Rule = Rule::record_field;
733
734 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
735 let span = pair.as_span().into();
736 let mut inner = pair.into_inner();
737 let identifier = Identifier::parse(inner.next().unwrap())?;
738 let r#type = Type::parse(inner.next().unwrap())?;
739
740 Ok(RecordField {
741 name: identifier,
742 r#type,
743 span,
744 })
745 }
746
747 fn span(&self) -> &Span {
748 &self.span
749 }
750}
751
752impl AstNode for PolicyField {
753 const RULE: Rule = Rule::policy_def_field;
754
755 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
756 match pair.as_rule() {
757 Rule::policy_def_hash => Ok(PolicyField::Hash(DataExpr::parse(
758 pair.into_inner().next().unwrap(),
759 )?)),
760 Rule::policy_def_script => Ok(PolicyField::Script(DataExpr::parse(
761 pair.into_inner().next().unwrap(),
762 )?)),
763 Rule::policy_def_ref => Ok(PolicyField::Ref(DataExpr::parse(
764 pair.into_inner().next().unwrap(),
765 )?)),
766 x => unreachable!("Unexpected rule in policy_field: {:?}", x),
767 }
768 }
769
770 fn span(&self) -> &Span {
771 match self {
772 Self::Hash(x) => x.span(),
773 Self::Script(x) => x.span(),
774 Self::Ref(x) => x.span(),
775 }
776 }
777}
778
779impl AstNode for PolicyConstructor {
780 const RULE: Rule = Rule::policy_def_constructor;
781
782 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
783 let span = pair.as_span().into();
784 let inner = pair.into_inner();
785
786 let fields = inner
787 .map(|x| PolicyField::parse(x))
788 .collect::<Result<Vec<_>, _>>()?;
789
790 Ok(PolicyConstructor { fields, span })
791 }
792
793 fn span(&self) -> &Span {
794 &self.span
795 }
796}
797
798impl AstNode for PolicyValue {
799 const RULE: Rule = Rule::policy_def_value;
800
801 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
802 match pair.as_rule() {
803 Rule::policy_def_constructor => {
804 Ok(PolicyValue::Constructor(PolicyConstructor::parse(pair)?))
805 }
806 Rule::policy_def_assign => Ok(PolicyValue::Assign(HexStringLiteral::parse(
807 pair.into_inner().next().unwrap(),
808 )?)),
809 x => unreachable!("Unexpected rule in policy_value: {:?}", x),
810 }
811 }
812
813 fn span(&self) -> &Span {
814 match self {
815 Self::Constructor(x) => x.span(),
816 Self::Assign(x) => x.span(),
817 }
818 }
819}
820
821impl AstNode for PolicyDef {
822 const RULE: Rule = Rule::policy_def;
823
824 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
825 let span = pair.as_span().into();
826 let mut inner = pair.into_inner();
827 let name = Identifier::parse(inner.next().unwrap())?;
828 let value = PolicyValue::parse(inner.next().unwrap())?;
829
830 Ok(PolicyDef { name, value, span })
831 }
832
833 fn span(&self) -> &Span {
834 &self.span
835 }
836}
837
838impl AstNode for StaticAssetConstructor {
839 const RULE: Rule = Rule::static_asset_constructor;
840
841 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
842 let span = pair.as_span().into();
843 let mut inner = pair.into_inner();
844
845 let r#type = Identifier::parse(inner.next().unwrap())?;
846 let amount = DataExpr::parse(inner.next().unwrap())?;
847
848 Ok(StaticAssetConstructor {
849 r#type,
850 amount: Box::new(amount),
851 span,
852 })
853 }
854
855 fn span(&self) -> &Span {
856 &self.span
857 }
858}
859
860impl AstNode for AnyAssetConstructor {
861 const RULE: Rule = Rule::any_asset_constructor;
862
863 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
864 let span = pair.as_span().into();
865 let mut inner = pair.into_inner();
866
867 let policy = DataExpr::parse(inner.next().unwrap())?;
868 let asset_name = DataExpr::parse(inner.next().unwrap())?;
869 let amount = DataExpr::parse(inner.next().unwrap())?;
870
871 Ok(AnyAssetConstructor {
872 policy: Box::new(policy),
873 asset_name: Box::new(asset_name),
874 amount: Box::new(amount),
875 span,
876 })
877 }
878
879 fn span(&self) -> &Span {
880 &self.span
881 }
882}
883
884impl AstNode for RecordConstructorField {
885 const RULE: Rule = Rule::record_constructor_field;
886
887 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
888 let span = pair.as_span().into();
889 let mut inner = pair.into_inner();
890
891 let name = Identifier::parse(inner.next().unwrap())?;
892 let value = DataExpr::parse(inner.next().unwrap())?;
893
894 Ok(RecordConstructorField {
895 name,
896 value: Box::new(value),
897 span,
898 })
899 }
900
901 fn span(&self) -> &Span {
902 &self.span
903 }
904}
905
906impl AstNode for UtxoRef {
907 const RULE: Rule = Rule::utxo_ref;
908
909 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
910 let span = pair.as_span().into();
911 let raw_ref = pair.as_span().as_str()[2..].to_string();
912 let (raw_txid, raw_output_ix) = raw_ref.split_once("#").expect("Invalid utxo ref");
913
914 Ok(UtxoRef {
915 txid: hex::decode(raw_txid).expect("Invalid hex txid"),
916 index: raw_output_ix.parse().expect("Invalid output index"),
917 span,
918 })
919 }
920
921 fn span(&self) -> &Span {
922 &self.span
923 }
924}
925
926impl AstNode for StructConstructor {
927 const RULE: Rule = Rule::struct_constructor;
928
929 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
930 let span = pair.as_span().into();
931 let mut inner = pair.into_inner();
932
933 let r#type = Identifier::parse(inner.next().unwrap())?;
934 let case = VariantCaseConstructor::parse(inner.next().unwrap())?;
935
936 Ok(StructConstructor {
937 r#type,
938 case,
939 scope: None,
940 span,
941 })
942 }
943
944 fn span(&self) -> &Span {
945 &self.span
946 }
947}
948
949impl VariantCaseConstructor {
950 fn implicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
951 let span = pair.as_span().into();
952 let inner = pair.into_inner();
953
954 let mut fields = Vec::new();
955 let mut spread = None;
956
957 for pair in inner {
958 match pair.as_rule() {
959 Rule::record_constructor_field => {
960 fields.push(RecordConstructorField::parse(pair)?);
961 }
962 Rule::spread_expression => {
963 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
964 }
965 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
966 }
967 }
968
969 Ok(VariantCaseConstructor {
970 name: Identifier::new("Default"),
971 fields,
972 spread: spread.map(Box::new),
973 scope: None,
974 span,
975 })
976 }
977
978 fn explicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
979 let span = pair.as_span().into();
980 let mut inner = pair.into_inner();
981
982 let name = Identifier::parse(inner.next().unwrap())?;
983
984 let mut fields = Vec::new();
985 let mut spread = None;
986
987 for pair in inner {
988 match pair.as_rule() {
989 Rule::record_constructor_field => {
990 fields.push(RecordConstructorField::parse(pair)?);
991 }
992 Rule::spread_expression => {
993 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
994 }
995 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
996 }
997 }
998
999 Ok(VariantCaseConstructor {
1000 name,
1001 fields,
1002 spread: spread.map(Box::new),
1003 scope: None,
1004 span,
1005 })
1006 }
1007}
1008
1009impl AstNode for VariantCaseConstructor {
1010 const RULE: Rule = Rule::variant_case_constructor;
1011
1012 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1013 match pair.as_rule() {
1014 Rule::implicit_variant_case_constructor => Self::implicit_parse(pair),
1015 Rule::explicit_variant_case_constructor => Self::explicit_parse(pair),
1016 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
1017 }
1018 }
1019
1020 fn span(&self) -> &Span {
1021 &self.span
1022 }
1023}
1024
1025impl AstNode for ListConstructor {
1026 const RULE: Rule = Rule::list_constructor;
1027
1028 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1029 let span = pair.as_span().into();
1030 let inner = pair.into_inner();
1031
1032 let elements = inner.map(DataExpr::parse).collect::<Result<Vec<_>, _>>()?;
1033
1034 Ok(ListConstructor { elements, span })
1035 }
1036
1037 fn span(&self) -> &Span {
1038 &self.span
1039 }
1040}
1041
1042impl DataExpr {
1043 fn number_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1044 Ok(DataExpr::Number(pair.as_str().parse().unwrap()))
1045 }
1046
1047 fn bool_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1048 Ok(DataExpr::Bool(pair.as_str().parse().unwrap()))
1049 }
1050
1051 fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1052 Ok(DataExpr::Identifier(Identifier::parse(pair)?))
1053 }
1054
1055 fn struct_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1056 Ok(DataExpr::StructConstructor(StructConstructor::parse(pair)?))
1057 }
1058
1059 fn list_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1060 Ok(DataExpr::ListConstructor(ListConstructor::parse(pair)?))
1061 }
1062
1063 fn utxo_ref_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1064 Ok(DataExpr::UtxoRef(UtxoRef::parse(pair)?))
1065 }
1066
1067 fn static_asset_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1068 Ok(DataExpr::StaticAssetConstructor(
1069 StaticAssetConstructor::parse(pair)?,
1070 ))
1071 }
1072
1073 fn any_asset_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
1074 Ok(DataExpr::AnyAssetConstructor(AnyAssetConstructor::parse(
1075 pair,
1076 )?))
1077 }
1078
1079 fn negate_op_parse(pair: Pair<Rule>, right: DataExpr) -> Result<Self, Error> {
1080 Ok(DataExpr::NegateOp(NegateOp {
1081 operand: Box::new(right),
1082 span: pair.as_span().into(),
1083 }))
1084 }
1085
1086 fn property_op_parse(pair: Pair<Rule>, left: DataExpr) -> Result<Self, Error> {
1087 let span: Span = pair.as_span().into();
1088 let mut inner = pair.into_inner();
1089
1090 Ok(DataExpr::PropertyOp(PropertyOp {
1091 operand: Box::new(left),
1092 property: Box::new(Identifier::parse(inner.next().unwrap())?),
1093 span,
1094 scope: None,
1095 }))
1096 }
1097
1098 fn add_op_parse(left: DataExpr, pair: Pair<Rule>, right: DataExpr) -> Result<Self, Error> {
1099 let span = pair.as_span().into();
1100
1101 Ok(DataExpr::AddOp(AddOp {
1102 lhs: Box::new(left),
1103 rhs: Box::new(right),
1104 span,
1105 }))
1106 }
1107
1108 fn sub_op_parse(left: DataExpr, pair: Pair<Rule>, right: DataExpr) -> Result<Self, Error> {
1109 let span = pair.as_span().into();
1110
1111 Ok(DataExpr::SubOp(SubOp {
1112 lhs: Box::new(left),
1113 rhs: Box::new(right),
1114 span,
1115 }))
1116 }
1117}
1118
1119static DATA_EXPR_PRATT_PARSER: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
1120 PrattParser::new()
1121 .op(Op::infix(Rule::data_add, Assoc::Left) | Op::infix(Rule::data_sub, Assoc::Left))
1122 .op(Op::prefix(Rule::data_negate))
1123 .op(Op::postfix(Rule::data_property))
1124});
1125
1126impl AstNode for DataExpr {
1127 const RULE: Rule = Rule::data_expr;
1128
1129 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1130 let inner = pair.into_inner();
1131
1132 DATA_EXPR_PRATT_PARSER
1133 .map_primary(|x| match x.as_rule() {
1134 Rule::number => DataExpr::number_parse(x),
1135 Rule::string => Ok(DataExpr::String(StringLiteral::parse(x)?)),
1136 Rule::bool => DataExpr::bool_parse(x),
1137 Rule::hex_string => Ok(DataExpr::HexString(HexStringLiteral::parse(x)?)),
1138 Rule::struct_constructor => DataExpr::struct_constructor_parse(x),
1139 Rule::list_constructor => DataExpr::list_constructor_parse(x),
1140 Rule::unit => Ok(DataExpr::Unit),
1141 Rule::identifier => DataExpr::identifier_parse(x),
1142 Rule::utxo_ref => DataExpr::utxo_ref_parse(x),
1143 Rule::static_asset_constructor => DataExpr::static_asset_constructor_parse(x),
1144 Rule::any_asset_constructor => DataExpr::any_asset_constructor_parse(x),
1145 Rule::data_expr => DataExpr::parse(x),
1146 x => unreachable!("unexpected rule as data primary: {:?}", x),
1147 })
1148 .map_prefix(|op, right| match op.as_rule() {
1149 Rule::data_negate => DataExpr::negate_op_parse(op, right?),
1150 x => unreachable!("Unexpected rule as data prefix: {:?}", x),
1151 })
1152 .map_postfix(|left, op| match op.as_rule() {
1153 Rule::data_property => DataExpr::property_op_parse(op, left?),
1154 x => unreachable!("Unexpected rule as data postfix: {:?}", x),
1155 })
1156 .map_infix(|left, op, right| match op.as_rule() {
1157 Rule::data_add => DataExpr::add_op_parse(left?, op, right?),
1158 Rule::data_sub => DataExpr::sub_op_parse(left?, op, right?),
1159 x => unreachable!("Unexpected rule as data infix: {:?}", x),
1160 })
1161 .parse(inner)
1162 }
1163
1164 fn span(&self) -> &Span {
1165 match self {
1166 DataExpr::None => &Span::DUMMY, DataExpr::Unit => &Span::DUMMY, DataExpr::Number(_) => &Span::DUMMY, DataExpr::Bool(_) => &Span::DUMMY, DataExpr::String(x) => x.span(),
1171 DataExpr::HexString(x) => x.span(),
1172 DataExpr::StructConstructor(x) => x.span(),
1173 DataExpr::ListConstructor(x) => x.span(),
1174 DataExpr::StaticAssetConstructor(x) => x.span(),
1175 DataExpr::AnyAssetConstructor(x) => x.span(),
1176 DataExpr::Identifier(x) => x.span(),
1177 DataExpr::AddOp(x) => &x.span,
1178 DataExpr::SubOp(x) => &x.span,
1179 DataExpr::NegateOp(x) => &x.span,
1180 DataExpr::PropertyOp(x) => &x.span,
1181 DataExpr::UtxoRef(x) => x.span(),
1182 }
1183 }
1184}
1185
1186impl AstNode for Type {
1187 const RULE: Rule = Rule::r#type;
1188
1189 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1190 let inner = pair.into_inner().next().unwrap();
1191
1192 match inner.as_rule() {
1193 Rule::primitive_type => match inner.as_str() {
1194 "Int" => Ok(Type::Int),
1195 "Bool" => Ok(Type::Bool),
1196 "Bytes" => Ok(Type::Bytes),
1197 "Address" => Ok(Type::Address),
1198 "UtxoRef" => Ok(Type::UtxoRef),
1199 "AnyAsset" => Ok(Type::AnyAsset),
1200 _ => unreachable!("Unexpected string in primitive_type: {:?}", inner.as_str()),
1201 },
1202 Rule::list_type => {
1203 let inner = inner.into_inner().next().unwrap();
1204 Ok(Type::List(Box::new(Type::parse(inner)?)))
1205 }
1206 Rule::custom_type => Ok(Type::Custom(Identifier::new(inner.as_str().to_owned()))),
1207 x => unreachable!("Unexpected rule in type: {:?}", x),
1208 }
1209 }
1210
1211 fn span(&self) -> &Span {
1212 &Span::DUMMY }
1214}
1215
1216impl TypeDef {
1217 fn parse_variant_format(pair: Pair<Rule>) -> Result<Self, Error> {
1218 let span = pair.as_span().into();
1219 let mut inner = pair.into_inner();
1220
1221 let identifier = Identifier::parse(inner.next().unwrap())?;
1222
1223 let cases = inner
1224 .map(VariantCase::parse)
1225 .collect::<Result<Vec<_>, _>>()?;
1226
1227 Ok(TypeDef {
1228 name: identifier,
1229 cases,
1230 span,
1231 })
1232 }
1233
1234 fn parse_record_format(pair: Pair<Rule>) -> Result<Self, Error> {
1235 let span: Span = pair.as_span().into();
1236 let mut inner = pair.into_inner();
1237
1238 let identifier = Identifier::parse(inner.next().unwrap())?;
1239
1240 let fields = inner
1241 .map(RecordField::parse)
1242 .collect::<Result<Vec<_>, _>>()?;
1243
1244 Ok(TypeDef {
1245 name: identifier.clone(),
1246 cases: vec![VariantCase {
1247 name: Identifier::new("Default"),
1248 fields,
1249 span: span.clone(),
1250 }],
1251 span,
1252 })
1253 }
1254}
1255
1256impl AstNode for TypeDef {
1257 const RULE: Rule = Rule::type_def;
1258
1259 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1260 match pair.as_rule() {
1261 Rule::variant_def => Ok(Self::parse_variant_format(pair)?),
1262 Rule::record_def => Ok(Self::parse_record_format(pair)?),
1263 x => unreachable!("Unexpected rule in type_def: {:?}", x),
1264 }
1265 }
1266
1267 fn span(&self) -> &Span {
1268 &self.span
1269 }
1270}
1271
1272impl VariantCase {
1273 fn struct_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1274 let span = pair.as_span().into();
1275 let mut inner = pair.into_inner();
1276
1277 let identifier = Identifier::parse(inner.next().unwrap())?;
1278
1279 let fields = inner
1280 .map(RecordField::parse)
1281 .collect::<Result<Vec<_>, _>>()?;
1282
1283 Ok(Self {
1284 name: identifier,
1285 fields,
1286 span,
1287 })
1288 }
1289
1290 fn unit_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1291 let span = pair.as_span().into();
1292 let mut inner = pair.into_inner();
1293
1294 let identifier = Identifier::parse(inner.next().unwrap())?;
1295
1296 Ok(Self {
1297 name: identifier,
1298 fields: vec![],
1299 span,
1300 })
1301 }
1302}
1303
1304impl AstNode for VariantCase {
1305 const RULE: Rule = Rule::variant_case;
1306
1307 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1308 let case = match pair.as_rule() {
1309 Rule::variant_case_struct => Self::struct_case_parse(pair),
1310 Rule::variant_case_tuple => todo!("parse variant case tuple"),
1311 Rule::variant_case_unit => Self::unit_case_parse(pair),
1312 x => unreachable!("Unexpected rule in datum_variant: {:?}", x),
1313 }?;
1314
1315 Ok(case)
1316 }
1317
1318 fn span(&self) -> &Span {
1319 &self.span
1320 }
1321}
1322
1323impl AstNode for AssetDef {
1324 const RULE: Rule = Rule::asset_def;
1325
1326 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1327 let span = pair.as_span().into();
1328 let mut inner = pair.into_inner();
1329
1330 let identifier = Identifier::parse(inner.next().unwrap())?;
1331 let policy = DataExpr::parse(inner.next().unwrap())?;
1332 let asset_name = DataExpr::parse(inner.next().unwrap())?;
1333
1334 Ok(AssetDef {
1335 name: identifier,
1336 policy,
1337 asset_name,
1338 span,
1339 })
1340 }
1341
1342 fn span(&self) -> &Span {
1343 &self.span
1344 }
1345}
1346
1347impl AstNode for ChainSpecificBlock {
1348 const RULE: Rule = Rule::chain_specific_block;
1349
1350 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1351 let mut inner = pair.into_inner();
1352
1353 let block = inner.next().unwrap();
1354
1355 match block.as_rule() {
1356 Rule::cardano_block => {
1357 let block = crate::cardano::CardanoBlock::parse(block)?;
1358 Ok(ChainSpecificBlock::Cardano(block))
1359 }
1360 x => unreachable!("Unexpected rule in chain_specific_block: {:?}", x),
1361 }
1362 }
1363
1364 fn span(&self) -> &Span {
1365 match self {
1366 Self::Cardano(x) => x.span(),
1367 }
1368 }
1369}
1370
1371pub fn parse_string(input: &str) -> Result<Program, Error> {
1394 let pairs = Tx3Grammar::parse(Rule::program, input)?;
1395 Program::parse(pairs.into_iter().next().unwrap())
1396}
1397
1398#[cfg(test)]
1399pub fn parse_well_known_example(example: &str) -> Program {
1400 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1401 let test_file = format!("{}/../../examples/{}.tx3", manifest_dir, example);
1402 let input = std::fs::read_to_string(&test_file).unwrap();
1403 parse_string(&input).unwrap()
1404}
1405
1406#[cfg(test)]
1407mod tests {
1408 use super::*;
1409 use assert_json_diff::assert_json_eq;
1410 use paste::paste;
1411 use pest::Parser;
1412
1413 #[test]
1414 fn smoke_test_parse_string() {
1415 let _ = parse_string("tx swap() {}").unwrap();
1416 }
1417
1418 macro_rules! input_to_ast_check {
1419 ($ast:ty, $name:expr, $input:expr, $expected:expr) => {
1420 paste::paste! {
1421 #[test]
1422 fn [<test_parse_ $ast:snake _ $name>]() {
1423 let pairs = super::Tx3Grammar::parse(<$ast>::RULE, $input).unwrap();
1424 let single_match = pairs.into_iter().next().unwrap();
1425 let result = <$ast>::parse(single_match).unwrap();
1426
1427 assert_eq!(result, $expected);
1428 }
1429 }
1430 };
1431 }
1432
1433 input_to_ast_check!(Type, "int", "Int", Type::Int);
1434
1435 input_to_ast_check!(Type, "bool", "Bool", Type::Bool);
1436
1437 input_to_ast_check!(Type, "bytes", "Bytes", Type::Bytes);
1438
1439 input_to_ast_check!(Type, "address", "Address", Type::Address);
1440
1441 input_to_ast_check!(Type, "utxo_ref", "UtxoRef", Type::UtxoRef);
1442
1443 input_to_ast_check!(Type, "any_asset", "AnyAsset", Type::AnyAsset);
1444
1445 input_to_ast_check!(Type, "list", "List<Int>", Type::List(Box::new(Type::Int)));
1446
1447 input_to_ast_check!(
1448 Type,
1449 "identifier",
1450 "MyType",
1451 Type::Custom(Identifier::new("MyType".to_string()))
1452 );
1453
1454 input_to_ast_check!(
1455 Type,
1456 "other_type",
1457 "List<Bytes>",
1458 Type::List(Box::new(Type::Bytes))
1459 );
1460
1461 input_to_ast_check!(
1462 Type,
1463 "within_list",
1464 "List<List<Int>>",
1465 Type::List(Box::new(Type::List(Box::new(Type::Int))))
1466 );
1467
1468 input_to_ast_check!(
1469 TypeDef,
1470 "type_def_record",
1471 "type MyRecord {
1472 field1: Int,
1473 field2: Bytes,
1474 }",
1475 TypeDef {
1476 name: Identifier::new("MyRecord"),
1477 cases: vec![VariantCase {
1478 name: Identifier::new("Default"),
1479 fields: vec![
1480 RecordField::new("field1", Type::Int),
1481 RecordField::new("field2", Type::Bytes)
1482 ],
1483 span: Span::DUMMY,
1484 }],
1485 span: Span::DUMMY,
1486 }
1487 );
1488
1489 input_to_ast_check!(
1490 TypeDef,
1491 "type_def_variant",
1492 "type MyVariant {
1493 Case1 {
1494 field1: Int,
1495 field2: Bytes,
1496 },
1497 Case2,
1498 }",
1499 TypeDef {
1500 name: Identifier::new("MyVariant"),
1501 cases: vec![
1502 VariantCase {
1503 name: Identifier::new("Case1"),
1504 fields: vec![
1505 RecordField::new("field1", Type::Int),
1506 RecordField::new("field2", Type::Bytes)
1507 ],
1508 span: Span::DUMMY,
1509 },
1510 VariantCase {
1511 name: Identifier::new("Case2"),
1512 fields: vec![],
1513 span: Span::DUMMY,
1514 },
1515 ],
1516 span: Span::DUMMY,
1517 }
1518 );
1519
1520 input_to_ast_check!(
1521 StringLiteral,
1522 "literal_string",
1523 "\"Hello, world!\"",
1524 StringLiteral::new("Hello, world!".to_string())
1525 );
1526
1527 input_to_ast_check!(
1528 HexStringLiteral,
1529 "hex_string",
1530 "0xAFAFAF",
1531 HexStringLiteral::new("AFAFAF".to_string())
1532 );
1533
1534 input_to_ast_check!(
1535 StringLiteral,
1536 "literal_string_address",
1537 "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1538 StringLiteral::new("addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string())
1539 );
1540
1541 input_to_ast_check!(
1542 ListConstructor,
1543 "empty_list",
1544 "[]",
1545 ListConstructor {
1546 elements: vec![],
1547 span: Span::DUMMY,
1548 }
1549 );
1550
1551 input_to_ast_check!(
1552 ListConstructor,
1553 "trailing_comma",
1554 "[1, 2,]",
1555 ListConstructor {
1556 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1557 span: Span::DUMMY,
1558 }
1559 );
1560
1561 input_to_ast_check!(
1562 ListConstructor,
1563 "int_list",
1564 "[1, 2]",
1565 ListConstructor {
1566 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1567 span: Span::DUMMY,
1568 }
1569 );
1570
1571 input_to_ast_check!(
1572 ListConstructor,
1573 "string_list",
1574 "[\"Hello\", \"World\"]",
1575 ListConstructor {
1576 elements: vec![
1577 DataExpr::String(StringLiteral::new("Hello".to_string())),
1578 DataExpr::String(StringLiteral::new("World".to_string()))
1579 ],
1580 span: Span::DUMMY,
1581 }
1582 );
1583
1584 input_to_ast_check!(
1585 ListConstructor,
1586 "mixed_list",
1587 "[1, \"Hello\", true]",
1588 ListConstructor {
1589 elements: vec![
1590 DataExpr::Number(1),
1591 DataExpr::String(StringLiteral::new("Hello".to_string())),
1592 DataExpr::Bool(true)
1593 ],
1594 span: Span::DUMMY,
1595 }
1596 );
1597
1598 input_to_ast_check!(
1599 ListConstructor,
1600 "list_within_list",
1601 "[[1, 2], [3, 4]]",
1602 ListConstructor {
1603 elements: vec![
1604 DataExpr::ListConstructor(ListConstructor {
1605 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1606 span: Span::DUMMY,
1607 }),
1608 DataExpr::ListConstructor(ListConstructor {
1609 elements: vec![DataExpr::Number(3), DataExpr::Number(4),],
1610 span: Span::DUMMY,
1611 }),
1612 ],
1613 span: Span::DUMMY,
1614 }
1615 );
1616
1617 input_to_ast_check!(DataExpr, "literal_bool_true", "true", DataExpr::Bool(true));
1618
1619 input_to_ast_check!(
1620 DataExpr,
1621 "literal_bool_false",
1622 "false",
1623 DataExpr::Bool(false)
1624 );
1625
1626 input_to_ast_check!(DataExpr, "unit_value", "())", DataExpr::Unit);
1627
1628 input_to_ast_check!(DataExpr, "number_value", "123", DataExpr::Number(123));
1629
1630 input_to_ast_check!(
1631 PolicyDef,
1632 "policy_def_assign",
1633 "policy MyPolicy = 0xAFAFAF;",
1634 PolicyDef {
1635 name: Identifier::new("MyPolicy"),
1636 value: PolicyValue::Assign(HexStringLiteral::new("AFAFAF".to_string())),
1637 span: Span::DUMMY,
1638 }
1639 );
1640
1641 input_to_ast_check!(
1642 PolicyDef,
1643 "policy_def_constructor",
1644 "policy MyPolicy {
1645 hash: 0x1234567890,
1646 script: 0x1234567890,
1647 ref: 0x1234567890,
1648 };",
1649 PolicyDef {
1650 name: Identifier::new("MyPolicy"),
1651 value: PolicyValue::Constructor(PolicyConstructor {
1652 fields: vec![
1653 PolicyField::Hash(DataExpr::HexString(HexStringLiteral::new(
1654 "1234567890".to_string()
1655 ))),
1656 PolicyField::Script(DataExpr::HexString(HexStringLiteral::new(
1657 "1234567890".to_string()
1658 ))),
1659 PolicyField::Ref(DataExpr::HexString(HexStringLiteral::new(
1660 "1234567890".to_string()
1661 ))),
1662 ],
1663 span: Span::DUMMY,
1664 }),
1665 span: Span::DUMMY,
1666 }
1667 );
1668
1669 input_to_ast_check!(
1670 AssetDef,
1671 "hex_hex",
1672 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.0xef7a1ceb;",
1673 AssetDef {
1674 name: Identifier::new("MyToken"),
1675 policy: DataExpr::HexString(HexStringLiteral::new(
1676 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1677 )),
1678 asset_name: DataExpr::HexString(HexStringLiteral::new("ef7a1ceb".to_string())),
1679 span: Span::DUMMY,
1680 }
1681 );
1682
1683 input_to_ast_check!(
1684 AssetDef,
1685 "hex_string",
1686 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.\"MY TOKEN\";",
1687 AssetDef {
1688 name: Identifier::new("MyToken"),
1689 policy: DataExpr::HexString(HexStringLiteral::new(
1690 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1691 )),
1692 asset_name: DataExpr::String(StringLiteral::new("MY TOKEN".to_string())),
1693 span: Span::DUMMY,
1694 }
1695 );
1696
1697 input_to_ast_check!(
1698 StaticAssetConstructor,
1699 "type_and_literal",
1700 "MyToken(15)",
1701 StaticAssetConstructor {
1702 r#type: Identifier::new("MyToken"),
1703 amount: Box::new(DataExpr::Number(15)),
1704 span: Span::DUMMY,
1705 }
1706 );
1707
1708 input_to_ast_check!(
1709 AnyAssetConstructor,
1710 "any_asset_constructor",
1711 "AnyAsset(0x1234567890, \"MyToken\", 15)",
1712 AnyAssetConstructor {
1713 policy: Box::new(DataExpr::HexString(HexStringLiteral::new(
1714 "1234567890".to_string()
1715 ))),
1716 asset_name: Box::new(DataExpr::String(StringLiteral::new("MyToken".to_string()))),
1717 amount: Box::new(DataExpr::Number(15)),
1718 span: Span::DUMMY,
1719 }
1720 );
1721
1722 input_to_ast_check!(
1723 AnyAssetConstructor,
1724 "any_asset_identifiers",
1725 "AnyAsset(my_policy, my_token, my_amount)",
1726 AnyAssetConstructor {
1727 policy: Box::new(DataExpr::Identifier(Identifier::new("my_policy"))),
1728 asset_name: Box::new(DataExpr::Identifier(Identifier::new("my_token"))),
1729 amount: Box::new(DataExpr::Identifier(Identifier::new("my_amount"))),
1730 span: Span::DUMMY,
1731 }
1732 );
1733
1734 input_to_ast_check!(
1735 AnyAssetConstructor,
1736 "any_asset_property_access",
1737 "AnyAsset(input1.policy, input1.asset_name, input1.amount)",
1738 AnyAssetConstructor {
1739 policy: Box::new(DataExpr::PropertyOp(PropertyOp {
1740 operand: Box::new(DataExpr::Identifier(Identifier::new("input1"))),
1741 property: Box::new(Identifier::new("policy")),
1742 span: Span::DUMMY,
1743 scope: None,
1744 })),
1745 asset_name: Box::new(DataExpr::PropertyOp(PropertyOp {
1746 operand: Box::new(DataExpr::Identifier(Identifier::new("input1"))),
1747 property: Box::new(Identifier::new("asset_name")),
1748 span: Span::DUMMY,
1749 scope: None,
1750 })),
1751 amount: Box::new(DataExpr::PropertyOp(PropertyOp {
1752 operand: Box::new(DataExpr::Identifier(Identifier::new("input1"))),
1753 property: Box::new(Identifier::new("amount")),
1754 span: Span::DUMMY,
1755 scope: None,
1756 })),
1757 span: Span::DUMMY,
1758 }
1759 );
1760
1761 input_to_ast_check!(DataExpr, "literal", "5", DataExpr::Number(5));
1762
1763 input_to_ast_check!(
1764 DataExpr,
1765 "add_op",
1766 "5 + var1",
1767 DataExpr::AddOp(AddOp {
1768 lhs: Box::new(DataExpr::Number(5)),
1769 rhs: Box::new(DataExpr::Identifier(Identifier::new("var1"))),
1770 span: Span::DUMMY,
1771 })
1772 );
1773
1774 input_to_ast_check!(
1775 DataExpr,
1776 "property_access",
1777 "subject.property",
1778 DataExpr::PropertyOp(PropertyOp {
1779 operand: Box::new(DataExpr::Identifier(Identifier::new("subject"))),
1780 property: Box::new(Identifier::new("property")),
1781 span: Span::DUMMY,
1782 scope: None,
1783 })
1784 );
1785
1786 input_to_ast_check!(
1787 DataExpr,
1788 "multiple_properties",
1789 "subject.property.subproperty",
1790 DataExpr::PropertyOp(PropertyOp {
1791 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
1792 operand: Box::new(DataExpr::Identifier(Identifier::new("subject"))),
1793 property: Box::new(Identifier::new("property")),
1794 span: Span::DUMMY,
1795 scope: None,
1796 })),
1797 property: Box::new(Identifier::new("subproperty")),
1798 span: Span::DUMMY,
1799 scope: None,
1800 })
1801 );
1802
1803 input_to_ast_check!(DataExpr, "empty_parentheses", "()", DataExpr::Unit);
1804
1805 input_to_ast_check!(DataExpr, "nested_parentheses", "((()))", DataExpr::Unit);
1806
1807 input_to_ast_check!(
1808 DataExpr,
1809 "nested_arithmetic_expression",
1810 "(1 + ((6 - 3) + 4))",
1811 DataExpr::AddOp(AddOp {
1812 lhs: Box::new(DataExpr::Number(1)),
1813 rhs: Box::new(DataExpr::AddOp(AddOp {
1814 lhs: Box::new(DataExpr::SubOp(SubOp {
1815 lhs: Box::new(DataExpr::Number(6)),
1816 rhs: Box::new(DataExpr::Number(3)),
1817 span: Span::DUMMY,
1818 })),
1819 rhs: Box::new(DataExpr::Number(4)),
1820 span: Span::DUMMY,
1821 })),
1822 span: Span::DUMMY,
1823 })
1824 );
1825
1826 input_to_ast_check!(
1827 DataExpr,
1828 "negate_op",
1829 "!a",
1830 DataExpr::NegateOp(NegateOp {
1831 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
1832 span: Span::DUMMY,
1833 })
1834 );
1835
1836 input_to_ast_check!(
1837 DataExpr,
1838 "negate_precedence",
1839 "!a.b",
1840 DataExpr::NegateOp(NegateOp {
1841 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
1842 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
1843 property: Box::new(Identifier::new("b")),
1844 span: Span::DUMMY,
1845 scope: None,
1846 })),
1847 span: Span::DUMMY,
1848 })
1849 );
1850
1851 input_to_ast_check!(
1852 DataExpr,
1853 "negate_override_precedence",
1854 "(!a).b",
1855 DataExpr::PropertyOp(PropertyOp {
1856 operand: Box::new(DataExpr::NegateOp(NegateOp {
1857 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
1858 span: Span::DUMMY,
1859 })),
1860 property: Box::new(Identifier::new("b")),
1861 span: Span::DUMMY,
1862 scope: None,
1863 })
1864 );
1865
1866 input_to_ast_check!(
1867 DataExpr,
1868 "overly_complex",
1869 "(1 + 5) - ((a.b.c - 3) + !d.f)",
1870 DataExpr::SubOp(SubOp {
1871 lhs: Box::new(DataExpr::AddOp(AddOp {
1872 lhs: Box::new(DataExpr::Number(1)),
1873 rhs: Box::new(DataExpr::Number(5)),
1874 span: Span::DUMMY,
1875 })),
1876 rhs: Box::new(DataExpr::AddOp(AddOp {
1877 lhs: Box::new(DataExpr::SubOp(SubOp {
1878 lhs: Box::new(DataExpr::PropertyOp(PropertyOp {
1879 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
1880 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
1881 property: Box::new(Identifier::new("b")),
1882 span: Span::DUMMY,
1883 scope: None,
1884 })),
1885 property: Box::new(Identifier::new("c")),
1886 span: Span::DUMMY,
1887 scope: None,
1888 })),
1889 rhs: Box::new(DataExpr::Number(3)),
1890 span: Span::DUMMY,
1891 })),
1892 rhs: Box::new(DataExpr::NegateOp(NegateOp {
1893 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
1894 operand: Box::new(DataExpr::Identifier(Identifier::new("d"))),
1895 property: Box::new(Identifier::new("f")),
1896 span: Span::DUMMY,
1897 scope: None,
1898 })),
1899 span: Span::DUMMY,
1900 })),
1901
1902 span: Span::DUMMY,
1903 })),
1904 span: Span::DUMMY,
1905 })
1906 );
1907
1908 input_to_ast_check!(
1909 StructConstructor,
1910 "struct_constructor_record",
1911 "MyRecord {
1912 field1: 10,
1913 field2: abc,
1914 }",
1915 StructConstructor {
1916 r#type: Identifier::new("MyRecord"),
1917 case: VariantCaseConstructor {
1918 name: Identifier::new("Default"),
1919 fields: vec![
1920 RecordConstructorField {
1921 name: Identifier::new("field1"),
1922 value: Box::new(DataExpr::Number(10)),
1923 span: Span::DUMMY,
1924 },
1925 RecordConstructorField {
1926 name: Identifier::new("field2"),
1927 value: Box::new(DataExpr::Identifier(Identifier::new("abc"))),
1928 span: Span::DUMMY,
1929 },
1930 ],
1931 spread: None,
1932 scope: None,
1933 span: Span::DUMMY,
1934 },
1935 scope: None,
1936 span: Span::DUMMY,
1937 }
1938 );
1939
1940 input_to_ast_check!(
1941 StructConstructor,
1942 "struct_constructor_variant",
1943 "ShipCommand::MoveShip {
1944 delta_x: delta_x,
1945 delta_y: delta_y,
1946 }",
1947 StructConstructor {
1948 r#type: Identifier::new("ShipCommand"),
1949 case: VariantCaseConstructor {
1950 name: Identifier::new("MoveShip"),
1951 fields: vec![
1952 RecordConstructorField {
1953 name: Identifier::new("delta_x"),
1954 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1955 span: Span::DUMMY,
1956 },
1957 RecordConstructorField {
1958 name: Identifier::new("delta_y"),
1959 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1960 span: Span::DUMMY,
1961 },
1962 ],
1963 spread: None,
1964 scope: None,
1965 span: Span::DUMMY,
1966 },
1967 scope: None,
1968 span: Span::DUMMY,
1969 }
1970 );
1971
1972 input_to_ast_check!(
1973 StructConstructor,
1974 "struct_constructor_variant_with_spread",
1975 "ShipCommand::MoveShip {
1976 delta_x: delta_x,
1977 delta_y: delta_y,
1978 ...abc
1979 }",
1980 StructConstructor {
1981 r#type: Identifier::new("ShipCommand"),
1982 case: VariantCaseConstructor {
1983 name: Identifier::new("MoveShip"),
1984 fields: vec![
1985 RecordConstructorField {
1986 name: Identifier::new("delta_x"),
1987 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1988 span: Span::DUMMY,
1989 },
1990 RecordConstructorField {
1991 name: Identifier::new("delta_y"),
1992 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1993 span: Span::DUMMY,
1994 },
1995 ],
1996 spread: Some(Box::new(DataExpr::Identifier(Identifier::new(
1997 "abc".to_string()
1998 )))),
1999 scope: None,
2000 span: Span::DUMMY,
2001 },
2002 scope: None,
2003 span: Span::DUMMY,
2004 }
2005 );
2006
2007 input_to_ast_check!(
2008 LocalsBlock,
2009 "basic",
2010 "locals {
2011 a: 10,
2012 }",
2013 LocalsBlock {
2014 assigns: vec![LocalsAssign {
2015 name: Identifier::new("a"),
2016 value: DataExpr::Number(10),
2017 span: Span::DUMMY,
2018 },],
2019 span: Span::DUMMY,
2020 }
2021 );
2022
2023 input_to_ast_check!(
2024 LocalsBlock,
2025 "multiple",
2026 "locals {
2027 a: 10,
2028 b: 20,
2029 }",
2030 LocalsBlock {
2031 assigns: vec![
2032 LocalsAssign {
2033 name: Identifier::new("a"),
2034 value: DataExpr::Number(10),
2035 span: Span::DUMMY,
2036 },
2037 LocalsAssign {
2038 name: Identifier::new("b"),
2039 value: DataExpr::Number(20),
2040 span: Span::DUMMY,
2041 },
2042 ],
2043 span: Span::DUMMY,
2044 }
2045 );
2046
2047 input_to_ast_check!(
2048 LocalsBlock,
2049 "complex_expression",
2050 "locals {
2051 a: (10 + 20) - 8,
2052 b: a.b.c + (5 - d),
2053 }",
2054 LocalsBlock {
2055 assigns: vec![
2056 LocalsAssign {
2057 name: Identifier::new("a"),
2058 value: DataExpr::SubOp(SubOp {
2059 lhs: Box::new(DataExpr::AddOp(AddOp {
2060 lhs: Box::new(DataExpr::Number(10)),
2061 rhs: Box::new(DataExpr::Number(20)),
2062 span: Span::DUMMY,
2063 })),
2064 rhs: Box::new(DataExpr::Number(8)),
2065 span: Span::DUMMY,
2066 }),
2067 span: Span::DUMMY,
2068 },
2069 LocalsAssign {
2070 name: Identifier::new("b"),
2071 value: DataExpr::AddOp(AddOp {
2072 lhs: Box::new(DataExpr::PropertyOp(PropertyOp {
2073 operand: Box::new(DataExpr::PropertyOp(PropertyOp {
2074 operand: Box::new(DataExpr::Identifier(Identifier::new("a"))),
2075 property: Box::new(Identifier::new("b")),
2076 span: Span::DUMMY,
2077 scope: None,
2078 })),
2079 property: Box::new(Identifier::new("c")),
2080 span: Span::DUMMY,
2081 scope: None,
2082 })),
2083 rhs: Box::new(DataExpr::SubOp(SubOp {
2084 lhs: Box::new(DataExpr::Number(5)),
2085 rhs: Box::new(DataExpr::Identifier(Identifier::new("d"))),
2086 span: Span::DUMMY,
2087 })),
2088 span: Span::DUMMY,
2089 }),
2090 span: Span::DUMMY,
2091 },
2092 ],
2093 span: Span::DUMMY,
2094 }
2095 );
2096
2097 input_to_ast_check!(
2098 OutputBlock,
2099 "output_block_anonymous",
2100 r#"output {
2101 to: my_party,
2102 amount: Ada(100),
2103 }"#,
2104 OutputBlock {
2105 name: None,
2106 fields: vec![
2107 OutputBlockField::To(Box::new(DataExpr::Identifier(Identifier::new(
2108 "my_party".to_string(),
2109 )))),
2110 OutputBlockField::Amount(Box::new(DataExpr::StaticAssetConstructor(
2111 StaticAssetConstructor {
2112 r#type: Identifier::new("Ada"),
2113 amount: Box::new(DataExpr::Number(100)),
2114 span: Span::DUMMY,
2115 },
2116 ))),
2117 ],
2118 span: Span::DUMMY,
2119 }
2120 );
2121
2122 input_to_ast_check!(
2123 ChainSpecificBlock,
2124 "chain_specific_block_cardano",
2125 "cardano::vote_delegation_certificate {
2126 drep: 0x1234567890,
2127 stake: 0x1234567890,
2128 }",
2129 ChainSpecificBlock::Cardano(crate::cardano::CardanoBlock::VoteDelegationCertificate(
2130 crate::cardano::VoteDelegationCertificate {
2131 drep: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
2132 stake: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
2133 span: Span::DUMMY,
2134 },
2135 ))
2136 );
2137
2138 input_to_ast_check!(
2139 EnvDef,
2140 "basic",
2141 "env {
2142 field_a: Int,
2143 field_b: Bytes,
2144 }",
2145 EnvDef {
2146 fields: vec![
2147 EnvField {
2148 name: "field_a".to_string(),
2149 r#type: Type::Int,
2150 span: Span::DUMMY,
2151 },
2152 EnvField {
2153 name: "field_b".to_string(),
2154 r#type: Type::Bytes,
2155 span: Span::DUMMY,
2156 },
2157 ],
2158 span: Span::DUMMY,
2159 }
2160 );
2161
2162 input_to_ast_check!(
2163 TxDef,
2164 "empty",
2165 "tx my_tx() {}",
2166 TxDef {
2167 name: Identifier::new("my_tx"),
2168 parameters: ParameterList {
2169 parameters: vec![],
2170 span: Span::DUMMY,
2171 },
2172 locals: None,
2173 references: vec![],
2174 inputs: vec![],
2175 outputs: vec![],
2176 validity: None,
2177 burn: None,
2178 mints: vec![],
2179 signers: None,
2180 adhoc: vec![],
2181 collateral: vec![],
2182 metadata: None,
2183 scope: None,
2184 span: Span::DUMMY,
2185 }
2186 );
2187
2188 input_to_ast_check!(
2189 TxDef,
2190 "with_parameters",
2191 "tx my_tx(a: Int, b: Bytes) {}",
2192 TxDef {
2193 name: Identifier::new("my_tx"),
2194 parameters: ParameterList {
2195 parameters: vec![
2196 ParamDef {
2197 name: Identifier::new("a"),
2198 r#type: Type::Int,
2199 },
2200 ParamDef {
2201 name: Identifier::new("b"),
2202 r#type: Type::Bytes,
2203 },
2204 ],
2205 span: Span::DUMMY,
2206 },
2207 locals: None,
2208 references: vec![],
2209 inputs: vec![],
2210 outputs: vec![],
2211 validity: None,
2212 burn: None,
2213 mints: vec![],
2214 signers: None,
2215 adhoc: vec![],
2216 collateral: vec![],
2217 metadata: None,
2218 scope: None,
2219 span: Span::DUMMY,
2220 }
2221 );
2222
2223 input_to_ast_check!(
2224 Program,
2225 "basic",
2226 "party Abc; tx my_tx() {}",
2227 Program {
2228 parties: vec![PartyDef {
2229 name: Identifier::new("Abc"),
2230 span: Span::DUMMY,
2231 }],
2232 types: vec![],
2233 txs: vec![TxDef {
2234 name: Identifier::new("my_tx"),
2235 parameters: ParameterList {
2236 parameters: vec![],
2237 span: Span::DUMMY,
2238 },
2239 locals: None,
2240 references: vec![],
2241 inputs: vec![],
2242 outputs: vec![],
2243 validity: None,
2244 burn: None,
2245 mints: vec![],
2246 signers: None,
2247 adhoc: vec![],
2248 collateral: vec![],
2249 metadata: None,
2250 scope: None,
2251 span: Span::DUMMY,
2252 }],
2253 env: None,
2254 assets: vec![],
2255 policies: vec![],
2256 span: Span::DUMMY,
2257 scope: None,
2258 }
2259 );
2260
2261 #[test]
2262 fn test_spans_are_respected() {
2263 let program = parse_well_known_example("lang_tour");
2264 assert_eq!(program.span, Span::new(0, 1497));
2265
2266 assert_eq!(program.parties[0].span, Span::new(47, 61));
2267
2268 assert_eq!(program.types[0].span, Span::new(63, 158));
2269 }
2270
2271 fn make_snapshot_if_missing(example: &str, program: &Program) {
2272 let manifest_dir = env!("CARGO_MANIFEST_DIR");
2273 let path = format!("{}/../../examples/{}.ast", manifest_dir, example);
2274
2275 if !std::fs::exists(&path).unwrap() {
2276 let ast = serde_json::to_string_pretty(program).unwrap();
2277 std::fs::write(&path, ast).unwrap();
2278 }
2279 }
2280
2281 fn test_parsing_example(example: &str) {
2282 let program = parse_well_known_example(example);
2283
2284 make_snapshot_if_missing(example, &program);
2285
2286 let manifest_dir = env!("CARGO_MANIFEST_DIR");
2287 let ast_file = format!("{}/../../examples/{}.ast", manifest_dir, example);
2288 let ast = std::fs::read_to_string(ast_file).unwrap();
2289
2290 let expected: Program = serde_json::from_str(&ast).unwrap();
2291
2292 assert_json_eq!(program, expected);
2293 }
2294
2295 #[macro_export]
2296 macro_rules! test_parsing {
2297 ($name:ident) => {
2298 paste! {
2299 #[test]
2300 fn [<test_example_ $name>]() {
2301 test_parsing_example(stringify!($name));
2302 }
2303 }
2304 };
2305 }
2306
2307 test_parsing!(lang_tour);
2308
2309 test_parsing!(transfer);
2310
2311 test_parsing!(swap);
2312
2313 test_parsing!(asteria);
2314
2315 test_parsing!(vesting);
2316
2317 test_parsing!(faucet);
2318
2319 test_parsing!(disordered);
2320
2321 test_parsing!(input_datum);
2322
2323 test_parsing!(withdrawal);
2324
2325 test_parsing!(env_vars);
2326
2327 test_parsing!(local_vars);
2328
2329 test_parsing!(cardano_witness);
2330}