1use miette::SourceOffset;
6use pest::{iterators::Pair, Parser};
7use pest_derive::Parser;
8
9use crate::ast::*;
10
11#[derive(Parser)]
12#[grammar = "tx3.pest"]
13pub(crate) struct Tx3Grammar;
14
15#[derive(Debug, thiserror::Error, miette::Diagnostic)]
16#[error("Parsing error: {message}")]
17#[diagnostic(code(tx3::parsing))]
18pub struct Error {
19 pub message: String,
20
21 #[source_code]
22 pub src: String,
23
24 #[label]
25 pub span: Span,
26}
27
28impl From<pest::error::Error<Rule>> for Error {
29 fn from(error: pest::error::Error<Rule>) -> Self {
30 match &error.variant {
31 pest::error::ErrorVariant::ParsingError { positives, .. } => Error {
32 message: format!("expected {:?}", positives),
33 src: error.line().to_string(),
34 span: error.location.into(),
35 },
36 pest::error::ErrorVariant::CustomError { message } => Error {
37 message: message.clone(),
38 src: error.line().to_string(),
39 span: error.location.into(),
40 },
41 }
42 }
43}
44
45impl From<pest::error::InputLocation> for Span {
46 fn from(value: pest::error::InputLocation) -> Self {
47 match value {
48 pest::error::InputLocation::Pos(pos) => Self::new(pos, pos),
49 pest::error::InputLocation::Span((start, end)) => Self::new(start, end),
50 }
51 }
52}
53
54impl From<pest::Span<'_>> for Span {
55 fn from(span: pest::Span<'_>) -> Self {
56 Self::new(span.start(), span.end())
57 }
58}
59
60impl From<Span> for miette::SourceSpan {
61 fn from(span: Span) -> Self {
62 miette::SourceSpan::new(SourceOffset::from(span.start), span.end - span.start)
63 }
64}
65
66pub trait AstNode: Sized {
67 const RULE: Rule;
68
69 fn parse(pair: Pair<Rule>) -> Result<Self, Error>;
70
71 fn span(&self) -> &Span;
72}
73
74impl AstNode for Program {
75 const RULE: Rule = Rule::program;
76
77 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
78 let span = pair.as_span().into();
79 let inner = pair.into_inner();
80
81 let mut program = Self {
82 txs: Vec::new(),
83 assets: Vec::new(),
84 types: Vec::new(),
85 parties: Vec::new(),
86 policies: Vec::new(),
87 scope: None,
88 span,
89 };
90
91 for pair in inner {
92 match pair.as_rule() {
93 Rule::tx_def => program.txs.push(TxDef::parse(pair)?),
94 Rule::asset_def => program.assets.push(AssetDef::parse(pair)?),
95 Rule::record_def => program.types.push(TypeDef::parse(pair)?),
96 Rule::variant_def => program.types.push(TypeDef::parse(pair)?),
97 Rule::party_def => program.parties.push(PartyDef::parse(pair)?),
98 Rule::policy_def => program.policies.push(PolicyDef::parse(pair)?),
99 Rule::EOI => break,
100 x => unreachable!("Unexpected rule in program: {:?}", x),
101 }
102 }
103
104 Ok(program)
105 }
106
107 fn span(&self) -> &Span {
108 &self.span
109 }
110}
111
112impl AstNode for ParameterList {
113 const RULE: Rule = Rule::parameter_list;
114
115 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
116 let span = pair.as_span().into();
117 let inner = pair.into_inner();
118
119 let mut parameters = Vec::new();
120
121 for param in inner {
122 let mut inner = param.into_inner();
123 let name = inner.next().unwrap().as_str().to_string();
124 let r#type = Type::parse(inner.next().unwrap())?;
125
126 parameters.push(ParamDef { name, r#type });
127 }
128
129 Ok(ParameterList { parameters, span })
130 }
131
132 fn span(&self) -> &Span {
133 &self.span
134 }
135}
136
137impl AstNode for TxDef {
138 const RULE: Rule = Rule::tx_def;
139
140 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
141 let span = pair.as_span().into();
142 let mut inner = pair.into_inner();
143
144 let name = inner.next().unwrap().as_str().to_string();
145 let parameters = ParameterList::parse(inner.next().unwrap())?;
146
147 let mut references = Vec::new();
148 let mut inputs = Vec::new();
149 let mut outputs = Vec::new();
150 let mut burn = None;
151 let mut mint = None;
152 let mut adhoc = Vec::new();
153 let mut collateral = Vec::new();
154
155 for item in inner {
156 match item.as_rule() {
157 Rule::reference_block => references.push(ReferenceBlock::parse(item)?),
158 Rule::input_block => inputs.push(InputBlock::parse(item)?),
159 Rule::output_block => outputs.push(OutputBlock::parse(item)?),
160 Rule::burn_block => burn = Some(BurnBlock::parse(item)?),
161 Rule::mint_block => mint = Some(MintBlock::parse(item)?),
162 Rule::chain_specific_block => adhoc.push(ChainSpecificBlock::parse(item)?),
163 Rule::collateral_block => collateral.push(CollateralBlock::parse(item)?),
164 x => unreachable!("Unexpected rule in tx_def: {:?}", x),
165 }
166 }
167
168 Ok(TxDef {
169 name,
170 parameters,
171 references,
172 inputs,
173 outputs,
174 burn,
175 mint,
176 adhoc,
177 scope: None,
178 span,
179 collateral,
180 })
181 }
182
183 fn span(&self) -> &Span {
184 &self.span
185 }
186}
187
188impl AstNode for Identifier {
189 const RULE: Rule = Rule::identifier;
190
191 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
192 Ok(Identifier {
193 value: pair.as_str().to_string(),
194 symbol: None,
195 span: pair.as_span().into(),
196 })
197 }
198
199 fn span(&self) -> &Span {
200 &self.span
201 }
202}
203
204impl AstNode for StringLiteral {
205 const RULE: Rule = Rule::string;
206
207 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
208 Ok(StringLiteral {
209 value: pair.as_str()[1..pair.as_str().len() - 1].to_string(),
210 span: pair.as_span().into(),
211 })
212 }
213
214 fn span(&self) -> &Span {
215 &self.span
216 }
217}
218
219impl AstNode for HexStringLiteral {
220 const RULE: Rule = Rule::hex_string;
221
222 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
223 Ok(HexStringLiteral {
224 value: pair.as_str()[2..].to_string(),
225 span: pair.as_span().into(),
226 })
227 }
228
229 fn span(&self) -> &Span {
230 &self.span
231 }
232}
233
234impl AstNode for PartyDef {
235 const RULE: Rule = Rule::party_def;
236
237 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
238 let span = pair.as_span().into();
239 let mut inner = pair.into_inner();
240 let identifier = inner.next().unwrap().as_str().to_string();
241
242 Ok(PartyDef {
243 name: identifier,
244 span,
245 })
246 }
247
248 fn span(&self) -> &Span {
249 &self.span
250 }
251}
252
253impl AstNode for ReferenceBlock {
254 const RULE: Rule = Rule::reference_block;
255
256 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
257 let span = pair.as_span().into();
258 let mut inner = pair.into_inner();
259
260 let name = inner.next().unwrap().as_str().to_string();
261
262 let pair = inner.next().unwrap();
263 match pair.as_rule() {
264 Rule::input_block_ref => {
265 let pair = pair.into_inner().next().unwrap();
266 let r#ref = DataExpr::parse(pair)?;
267 Ok(ReferenceBlock { name, r#ref, span })
268 }
269 x => unreachable!("Unexpected rule in ref_input_block: {:?}", x),
270 }
271 }
272
273 fn span(&self) -> &Span {
274 &self.span
275 }
276}
277
278impl AstNode for CollateralBlockField {
279 const RULE: Rule = Rule::collateral_block_field;
280
281 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
282 match pair.as_rule() {
283 Rule::input_block_from => {
284 let pair = pair.into_inner().next().unwrap();
285 let x = CollateralBlockField::From(AddressExpr::parse(pair)?);
286 Ok(x)
287 }
288 Rule::input_block_min_amount => {
289 let pair = pair.into_inner().next().unwrap();
290 let x = CollateralBlockField::MinAmount(AssetExpr::parse(pair)?);
291 Ok(x)
292 }
293 Rule::input_block_ref => {
294 let pair = pair.into_inner().next().unwrap();
295 let x = CollateralBlockField::Ref(DataExpr::UtxoRef(UtxoRef::parse(pair)?));
296 Ok(x)
297 }
298 x => unreachable!("Unexpected rule in collateral_block: {:?}", x),
299 }
300 }
301
302 fn span(&self) -> &Span {
303 match self {
304 Self::From(x) => x.span(),
305 Self::MinAmount(x) => x.span(),
306 Self::Ref(x) => x.span(),
307 }
308 }
309}
310
311impl AstNode for CollateralBlock {
312 const RULE: Rule = Rule::collateral_block;
313
314 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
315 let span = pair.as_span().into();
316 let inner = pair.into_inner();
317
318 let fields = inner
319 .map(|x| CollateralBlockField::parse(x))
320 .collect::<Result<Vec<_>, _>>()?;
321
322 Ok(CollateralBlock { fields, span })
323 }
324
325 fn span(&self) -> &Span {
326 &self.span
327 }
328}
329
330impl AstNode for InputBlockField {
331 const RULE: Rule = Rule::input_block_field;
332
333 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
334 match pair.as_rule() {
335 Rule::input_block_from => {
336 let pair = pair.into_inner().next().unwrap();
337 let x = InputBlockField::From(AddressExpr::parse(pair)?);
338 Ok(x)
339 }
340 Rule::input_block_datum_is => {
341 let pair = pair.into_inner().next().unwrap();
342 let x = InputBlockField::DatumIs(Type::parse(pair)?);
343 Ok(x)
344 }
345 Rule::input_block_min_amount => {
346 let pair = pair.into_inner().next().unwrap();
347 let x = InputBlockField::MinAmount(AssetExpr::parse(pair)?);
348 Ok(x)
349 }
350 Rule::input_block_redeemer => {
351 let pair = pair.into_inner().next().unwrap();
352 let x = InputBlockField::Redeemer(DataExpr::parse(pair)?);
353 Ok(x)
354 }
355 Rule::input_block_ref => {
356 let pair = pair.into_inner().next().unwrap();
357 let x = InputBlockField::Ref(DataExpr::parse(pair)?);
358 Ok(x)
359 }
360 x => unreachable!("Unexpected rule in input_block: {:?}", x),
361 }
362 }
363
364 fn span(&self) -> &Span {
365 match self {
366 Self::From(x) => x.span(),
367 Self::DatumIs(x) => x.span(),
368 Self::MinAmount(x) => x.span(),
369 Self::Redeemer(x) => x.span(),
370 Self::Ref(x) => x.span(),
371 }
372 }
373}
374
375impl AstNode for InputBlock {
376 const RULE: Rule = Rule::input_block;
377
378 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
379 let span = pair.as_span().into();
380 let mut inner = pair.into_inner();
381
382 let name = inner.next().unwrap().as_str().to_string();
383
384 let fields = inner
385 .map(|x| InputBlockField::parse(x))
386 .collect::<Result<Vec<_>, _>>()?;
387
388 Ok(InputBlock {
389 name,
390 is_many: false,
391 fields,
392 span,
393 })
394 }
395
396 fn span(&self) -> &Span {
397 &self.span
398 }
399}
400
401impl AstNode for OutputBlockField {
402 const RULE: Rule = Rule::output_block_field;
403
404 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
405 match pair.as_rule() {
406 Rule::output_block_to => {
407 let pair = pair.into_inner().next().unwrap();
408 let x = OutputBlockField::To(Box::new(AddressExpr::parse(pair)?));
409 Ok(x)
410 }
411 Rule::output_block_amount => {
412 let pair = pair.into_inner().next().unwrap();
413 let x = OutputBlockField::Amount(AssetExpr::parse(pair)?.into());
414 Ok(x)
415 }
416 Rule::output_block_datum => {
417 let pair = pair.into_inner().next().unwrap();
418 let x = OutputBlockField::Datum(DataExpr::parse(pair)?.into());
419 Ok(x)
420 }
421 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
422 }
423 }
424
425 fn span(&self) -> &Span {
426 match self {
427 Self::To(x) => x.span(),
428 Self::Amount(x) => x.span(),
429 Self::Datum(x) => x.span(),
430 }
431 }
432}
433
434impl AstNode for OutputBlock {
435 const RULE: Rule = Rule::output_block;
436
437 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
438 let span = pair.as_span().into();
439 let mut inner = pair.into_inner();
440
441 let has_name = inner
442 .peek()
443 .map(|x| x.as_rule() == Rule::identifier)
444 .unwrap_or_default();
445
446 let name = has_name.then(|| inner.next().unwrap().as_str().to_string());
447
448 let fields = inner
449 .map(|x| OutputBlockField::parse(x))
450 .collect::<Result<Vec<_>, _>>()?;
451
452 Ok(OutputBlock { name, fields, span })
453 }
454
455 fn span(&self) -> &Span {
456 &self.span
457 }
458}
459
460impl AstNode for MintBlockField {
461 const RULE: Rule = Rule::mint_block_field;
462
463 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
464 match pair.as_rule() {
465 Rule::mint_block_amount => {
466 let pair = pair.into_inner().next().unwrap();
467 let x = MintBlockField::Amount(AssetExpr::parse(pair)?.into());
468 Ok(x)
469 }
470 Rule::mint_block_redeemer => {
471 let pair = pair.into_inner().next().unwrap();
472 let x = MintBlockField::Redeemer(DataExpr::parse(pair)?.into());
473 Ok(x)
474 }
475 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
476 }
477 }
478
479 fn span(&self) -> &Span {
480 match self {
481 Self::Amount(x) => x.span(),
482 Self::Redeemer(x) => x.span(),
483 }
484 }
485}
486
487impl AstNode for MintBlock {
488 const RULE: Rule = Rule::mint_block;
489
490 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
491 let span = pair.as_span().into();
492 let inner = pair.into_inner();
493
494 let fields = inner
495 .map(|x| MintBlockField::parse(x))
496 .collect::<Result<Vec<_>, _>>()?;
497
498 Ok(MintBlock { fields, span })
499 }
500
501 fn span(&self) -> &Span {
502 &self.span
503 }
504}
505
506impl AstNode for BurnBlock {
507 const RULE: Rule = Rule::burn_block;
508
509 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
510 let span = pair.as_span().into();
511 let inner = pair.into_inner();
512
513 let fields = inner
514 .map(|x| MintBlockField::parse(x))
515 .collect::<Result<Vec<_>, _>>()?;
516
517 Ok(BurnBlock { fields, span })
518 }
519
520 fn span(&self) -> &Span {
521 &self.span
522 }
523}
524
525impl AstNode for RecordField {
526 const RULE: Rule = Rule::record_field;
527
528 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
529 let span = pair.as_span().into();
530 let mut inner = pair.into_inner();
531 let identifier = inner.next().unwrap().as_str().to_string();
532 let r#type = Type::parse(inner.next().unwrap())?;
533
534 Ok(RecordField {
535 name: identifier,
536 r#type,
537 span,
538 })
539 }
540
541 fn span(&self) -> &Span {
542 &self.span
543 }
544}
545
546impl AstNode for PolicyField {
547 const RULE: Rule = Rule::policy_def_field;
548
549 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
550 match pair.as_rule() {
551 Rule::policy_def_hash => Ok(PolicyField::Hash(DataExpr::parse(
552 pair.into_inner().next().unwrap(),
553 )?)),
554 Rule::policy_def_script => Ok(PolicyField::Script(DataExpr::parse(
555 pair.into_inner().next().unwrap(),
556 )?)),
557 Rule::policy_def_ref => Ok(PolicyField::Ref(DataExpr::parse(
558 pair.into_inner().next().unwrap(),
559 )?)),
560 x => unreachable!("Unexpected rule in policy_field: {:?}", x),
561 }
562 }
563
564 fn span(&self) -> &Span {
565 match self {
566 Self::Hash(x) => x.span(),
567 Self::Script(x) => x.span(),
568 Self::Ref(x) => x.span(),
569 }
570 }
571}
572
573impl AstNode for PolicyConstructor {
574 const RULE: Rule = Rule::policy_def_constructor;
575
576 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
577 let span = pair.as_span().into();
578 let inner = pair.into_inner();
579
580 let fields = inner
581 .map(|x| PolicyField::parse(x))
582 .collect::<Result<Vec<_>, _>>()?;
583
584 Ok(PolicyConstructor { fields, span })
585 }
586
587 fn span(&self) -> &Span {
588 &self.span
589 }
590}
591
592impl AstNode for PolicyValue {
593 const RULE: Rule = Rule::policy_def_value;
594
595 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
596 match pair.as_rule() {
597 Rule::policy_def_constructor => {
598 Ok(PolicyValue::Constructor(PolicyConstructor::parse(pair)?))
599 }
600 Rule::policy_def_assign => Ok(PolicyValue::Assign(HexStringLiteral::parse(
601 pair.into_inner().next().unwrap(),
602 )?)),
603 x => unreachable!("Unexpected rule in policy_value: {:?}", x),
604 }
605 }
606
607 fn span(&self) -> &Span {
608 match self {
609 Self::Constructor(x) => x.span(),
610 Self::Assign(x) => x.span(),
611 }
612 }
613}
614
615impl AstNode for PolicyDef {
616 const RULE: Rule = Rule::policy_def;
617
618 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
619 let span = pair.as_span().into();
620 let mut inner = pair.into_inner();
621 let name = inner.next().unwrap().as_str().to_string();
622 let value = PolicyValue::parse(inner.next().unwrap())?;
623
624 Ok(PolicyDef { name, value, span })
625 }
626
627 fn span(&self) -> &Span {
628 &self.span
629 }
630}
631
632impl AstNode for AddressExpr {
633 const RULE: Rule = Rule::address_expr;
634
635 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
636 let mut inner = pair.into_inner();
637
638 let value = inner.next().unwrap();
639
640 match value.as_rule() {
641 Rule::string => Ok(AddressExpr::String(StringLiteral::parse(value)?)),
642 Rule::hex_string => Ok(AddressExpr::HexString(HexStringLiteral::parse(value)?)),
643 Rule::identifier => Ok(AddressExpr::Identifier(Identifier::parse(value)?)),
644 x => unreachable!("Unexpected rule in address_expr: {:?}", x),
645 }
646 }
647
648 fn span(&self) -> &Span {
649 match self {
650 Self::String(x) => x.span(),
651 Self::HexString(x) => x.span(),
652 Self::Identifier(x) => x.span(),
653 }
654 }
655}
656
657impl AstNode for StaticAssetConstructor {
658 const RULE: Rule = Rule::static_asset_constructor;
659
660 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
661 let span = pair.as_span().into();
662 let mut inner = pair.into_inner();
663
664 let r#type = Identifier::parse(inner.next().unwrap())?;
665 let amount = DataExpr::parse(inner.next().unwrap())?;
666
667 Ok(StaticAssetConstructor {
668 r#type,
669 amount: Box::new(amount),
670 span,
671 })
672 }
673
674 fn span(&self) -> &Span {
675 &self.span
676 }
677}
678
679impl AstNode for AnyAssetConstructor {
680 const RULE: Rule = Rule::any_asset_constructor;
681
682 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
683 let span = pair.as_span().into();
684 let mut inner = pair.into_inner();
685
686 let policy = DataExpr::parse(inner.next().unwrap())?;
687 let asset_name = DataExpr::parse(inner.next().unwrap())?;
688 let amount = DataExpr::parse(inner.next().unwrap())?;
689
690 Ok(AnyAssetConstructor {
691 policy: Box::new(policy),
692 asset_name: Box::new(asset_name),
693 amount: Box::new(amount),
694 span,
695 })
696 }
697
698 fn span(&self) -> &Span {
699 &self.span
700 }
701}
702
703impl AssetExpr {
704 fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
705 Ok(AssetExpr::Identifier(Identifier::parse(pair)?))
706 }
707
708 fn static_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
709 Ok(AssetExpr::StaticConstructor(StaticAssetConstructor::parse(
710 pair,
711 )?))
712 }
713
714 fn any_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
715 Ok(AssetExpr::AnyConstructor(AnyAssetConstructor::parse(pair)?))
716 }
717
718 fn property_access_parse(pair: Pair<Rule>) -> Result<Self, Error> {
719 Ok(AssetExpr::PropertyAccess(PropertyAccess::parse(pair)?))
720 }
721
722 fn term_parse(pair: Pair<Rule>) -> Result<Self, Error> {
723 match pair.as_rule() {
724 Rule::static_asset_constructor => AssetExpr::static_constructor_parse(pair),
725 Rule::any_asset_constructor => AssetExpr::any_constructor_parse(pair),
726 Rule::property_access => AssetExpr::property_access_parse(pair),
727 Rule::identifier => AssetExpr::identifier_parse(pair),
728 x => unreachable!("Unexpected rule in asset_expr: {:?}", x),
729 }
730 }
731}
732
733impl AstNode for AssetExpr {
734 const RULE: Rule = Rule::asset_expr;
735
736 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
737 let mut inner = pair.into_inner();
738
739 let mut final_expr = Self::term_parse(inner.next().unwrap())?;
740
741 while let Some(term) = inner.next() {
742 let span = term.as_span().into();
743 let operator = BinaryOperator::parse(term)?;
744 let next_expr = Self::term_parse(inner.next().unwrap())?;
745
746 final_expr = AssetExpr::BinaryOp(AssetBinaryOp {
747 operator,
748 left: Box::new(final_expr),
749 right: Box::new(next_expr),
750 span,
751 });
752 }
753
754 Ok(final_expr)
755 }
756
757 fn span(&self) -> &Span {
758 match self {
759 AssetExpr::StaticConstructor(x) => x.span(),
760 AssetExpr::AnyConstructor(x) => x.span(),
761 AssetExpr::BinaryOp(x) => &x.span,
762 AssetExpr::PropertyAccess(x) => x.span(),
763 AssetExpr::Identifier(x) => x.span(),
764 }
765 }
766}
767
768impl AstNode for PropertyAccess {
769 const RULE: Rule = Rule::property_access;
770
771 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
772 let span = pair.as_span().into();
773 let mut inner = pair.into_inner();
774
775 let object = Identifier::parse(inner.next().unwrap())?;
776
777 let mut identifiers = Vec::new();
778 identifiers.push(Identifier::parse(inner.next().unwrap())?);
779
780 for identifier in inner {
781 identifiers.push(Identifier::parse(identifier)?);
782 }
783
784 Ok(PropertyAccess {
785 object,
786 path: identifiers,
787 scope: None,
788 span,
789 })
790 }
791
792 fn span(&self) -> &Span {
793 &self.span
794 }
795}
796
797impl AstNode for RecordConstructorField {
798 const RULE: Rule = Rule::record_constructor_field;
799
800 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
801 let span = pair.as_span().into();
802 let mut inner = pair.into_inner();
803
804 let name = Identifier::parse(inner.next().unwrap())?;
805 let value = DataExpr::parse(inner.next().unwrap())?;
806
807 Ok(RecordConstructorField {
808 name,
809 value: Box::new(value),
810 span,
811 })
812 }
813
814 fn span(&self) -> &Span {
815 &self.span
816 }
817}
818
819impl AstNode for UtxoRef {
820 const RULE: Rule = Rule::utxo_ref;
821
822 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
823 let span = pair.as_span().into();
824 let raw_ref = pair.as_span().as_str()[2..].to_string();
825 let (raw_txid, raw_output_ix) = raw_ref.split_once("#").expect("Invalid utxo ref");
826
827 Ok(UtxoRef {
828 txid: hex::decode(raw_txid).expect("Invalid hex txid"),
829 index: raw_output_ix.parse().expect("Invalid output index"),
830 span,
831 })
832 }
833
834 fn span(&self) -> &Span {
835 &self.span
836 }
837}
838
839impl AstNode for StructConstructor {
840 const RULE: Rule = Rule::struct_constructor;
841
842 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
843 let span = pair.as_span().into();
844 let mut inner = pair.into_inner();
845
846 let r#type = Identifier::parse(inner.next().unwrap())?;
847 let case = VariantCaseConstructor::parse(inner.next().unwrap())?;
848
849 Ok(StructConstructor {
850 r#type,
851 case,
852 scope: None,
853 span,
854 })
855 }
856
857 fn span(&self) -> &Span {
858 &self.span
859 }
860}
861
862impl VariantCaseConstructor {
863 fn implicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
864 let span = pair.as_span().into();
865 let inner = pair.into_inner();
866
867 let mut fields = Vec::new();
868 let mut spread = None;
869
870 for pair in inner {
871 match pair.as_rule() {
872 Rule::record_constructor_field => {
873 fields.push(RecordConstructorField::parse(pair)?);
874 }
875 Rule::spread_expression => {
876 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
877 }
878 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
879 }
880 }
881
882 Ok(VariantCaseConstructor {
883 name: Identifier::new("Default"),
884 fields,
885 spread: spread.map(Box::new),
886 scope: None,
887 span,
888 })
889 }
890
891 fn explicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
892 let span = pair.as_span().into();
893 let mut inner = pair.into_inner();
894
895 let name = Identifier::parse(inner.next().unwrap())?;
896
897 let mut fields = Vec::new();
898 let mut spread = None;
899
900 for pair in inner {
901 match pair.as_rule() {
902 Rule::record_constructor_field => {
903 fields.push(RecordConstructorField::parse(pair)?);
904 }
905 Rule::spread_expression => {
906 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
907 }
908 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
909 }
910 }
911
912 Ok(VariantCaseConstructor {
913 name,
914 fields,
915 spread: spread.map(Box::new),
916 scope: None,
917 span,
918 })
919 }
920}
921
922impl AstNode for VariantCaseConstructor {
923 const RULE: Rule = Rule::variant_case_constructor;
924
925 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
926 match pair.as_rule() {
927 Rule::implicit_variant_case_constructor => Self::implicit_parse(pair),
928 Rule::explicit_variant_case_constructor => Self::explicit_parse(pair),
929 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
930 }
931 }
932
933 fn span(&self) -> &Span {
934 &self.span
935 }
936}
937
938impl AstNode for ListConstructor {
939 const RULE: Rule = Rule::list_constructor;
940
941 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
942 let span = pair.as_span().into();
943 let inner = pair.into_inner();
944
945 let elements = inner.map(DataExpr::parse).collect::<Result<Vec<_>, _>>()?;
946
947 Ok(ListConstructor { elements, span })
948 }
949
950 fn span(&self) -> &Span {
951 &self.span
952 }
953}
954
955impl DataExpr {
956 fn number_parse(pair: Pair<Rule>) -> Result<Self, Error> {
957 Ok(DataExpr::Number(pair.as_str().parse().unwrap()))
958 }
959
960 fn bool_parse(pair: Pair<Rule>) -> Result<Self, Error> {
961 Ok(DataExpr::Bool(pair.as_str().parse().unwrap()))
962 }
963
964 fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
965 Ok(DataExpr::Identifier(Identifier::parse(pair)?))
966 }
967
968 fn property_access_parse(pair: Pair<Rule>) -> Result<Self, Error> {
969 Ok(DataExpr::PropertyAccess(PropertyAccess::parse(pair)?))
970 }
971
972 fn struct_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
973 Ok(DataExpr::StructConstructor(StructConstructor::parse(pair)?))
974 }
975
976 fn list_constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
977 Ok(DataExpr::ListConstructor(ListConstructor::parse(pair)?))
978 }
979
980 fn utxo_ref_parse(pair: Pair<Rule>) -> Result<Self, Error> {
981 Ok(DataExpr::UtxoRef(UtxoRef::parse(pair)?))
982 }
983
984 fn term_parse(pair: Pair<Rule>) -> Result<Self, Error> {
985 match pair.as_rule() {
986 Rule::number => DataExpr::number_parse(pair),
987 Rule::string => Ok(DataExpr::String(StringLiteral::parse(pair)?)),
988 Rule::bool => DataExpr::bool_parse(pair),
989 Rule::hex_string => Ok(DataExpr::HexString(HexStringLiteral::parse(pair)?)),
990 Rule::struct_constructor => DataExpr::struct_constructor_parse(pair),
991 Rule::list_constructor => DataExpr::list_constructor_parse(pair),
992 Rule::unit => Ok(DataExpr::Unit),
993 Rule::identifier => DataExpr::identifier_parse(pair),
994 Rule::property_access => DataExpr::property_access_parse(pair),
995 Rule::utxo_ref => DataExpr::utxo_ref_parse(pair),
996 x => unreachable!("Unexpected rule in data_expr: {:?}", x),
997 }
998 }
999}
1000
1001impl AstNode for DataExpr {
1002 const RULE: Rule = Rule::data_expr;
1003
1004 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1005 let mut inner = pair.into_inner();
1006
1007 let mut final_expr = Self::term_parse(inner.next().unwrap())?;
1008
1009 while let Some(term) = inner.next() {
1010 let span = term.as_span().into();
1011 let operator = BinaryOperator::parse(term)?;
1012 let next_expr = Self::term_parse(inner.next().unwrap())?;
1013
1014 final_expr = DataExpr::BinaryOp(DataBinaryOp {
1015 operator,
1016 left: Box::new(final_expr),
1017 right: Box::new(next_expr),
1018 span,
1019 });
1020 }
1021
1022 Ok(final_expr)
1023 }
1024
1025 fn span(&self) -> &Span {
1026 match self {
1027 DataExpr::None => &Span::DUMMY, DataExpr::Unit => &Span::DUMMY, DataExpr::Number(_) => &Span::DUMMY, DataExpr::Bool(_) => &Span::DUMMY, DataExpr::String(x) => x.span(),
1032 DataExpr::HexString(x) => x.span(),
1033 DataExpr::StructConstructor(x) => x.span(),
1034 DataExpr::ListConstructor(x) => x.span(),
1035 DataExpr::Identifier(x) => x.span(),
1036 DataExpr::PropertyAccess(x) => x.span(),
1037 DataExpr::BinaryOp(x) => &x.span,
1038 DataExpr::UtxoRef(x) => &x.span(),
1039 }
1040 }
1041}
1042
1043impl AstNode for BinaryOperator {
1044 const RULE: Rule = Rule::binary_operator;
1045
1046 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1047 match pair.as_str() {
1048 "+" => Ok(BinaryOperator::Add),
1049 "-" => Ok(BinaryOperator::Subtract),
1050 x => unreachable!("Unexpected string in binary_operator: {:?}", x),
1051 }
1052 }
1053
1054 fn span(&self) -> &Span {
1055 &Span::DUMMY }
1057}
1058
1059impl AstNode for Type {
1060 const RULE: Rule = Rule::r#type;
1061
1062 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1063 let inner = pair.into_inner().next().unwrap();
1064
1065 match inner.as_rule() {
1066 Rule::primitive_type => match inner.as_str() {
1067 "Int" => Ok(Type::Int),
1068 "Bool" => Ok(Type::Bool),
1069 "Bytes" => Ok(Type::Bytes),
1070 "Address" => Ok(Type::Address),
1071 "UtxoRef" => Ok(Type::UtxoRef),
1072 "AnyAsset" => Ok(Type::AnyAsset),
1073 _ => unreachable!("Unexpected string in primitive_type: {:?}", inner.as_str()),
1074 },
1075 Rule::list_type => {
1076 let inner = inner.into_inner().next().unwrap();
1077 Ok(Type::List(Box::new(Type::parse(inner)?)))
1078 }
1079 Rule::custom_type => Ok(Type::Custom(Identifier::new(inner.as_str().to_owned()))),
1080 x => unreachable!("Unexpected rule in type: {:?}", x),
1081 }
1082 }
1083
1084 fn span(&self) -> &Span {
1085 &Span::DUMMY }
1087}
1088
1089impl TypeDef {
1090 fn parse_variant_format(pair: Pair<Rule>) -> Result<Self, Error> {
1091 let span = pair.as_span().into();
1092 let mut inner = pair.into_inner();
1093
1094 let identifier = inner.next().unwrap().as_str().to_string();
1095
1096 let cases = inner
1097 .map(VariantCase::parse)
1098 .collect::<Result<Vec<_>, _>>()?;
1099
1100 Ok(TypeDef {
1101 name: identifier,
1102 cases,
1103 span,
1104 })
1105 }
1106
1107 fn parse_record_format(pair: Pair<Rule>) -> Result<Self, Error> {
1108 let span: Span = pair.as_span().into();
1109 let mut inner = pair.into_inner();
1110
1111 let identifier = inner.next().unwrap().as_str().to_string();
1112
1113 let fields = inner
1114 .map(RecordField::parse)
1115 .collect::<Result<Vec<_>, _>>()?;
1116
1117 Ok(TypeDef {
1118 name: identifier.clone(),
1119 cases: vec![VariantCase {
1120 name: "Default".to_string(),
1121 fields,
1122 span: span.clone(),
1123 }],
1124 span,
1125 })
1126 }
1127}
1128
1129impl AstNode for TypeDef {
1130 const RULE: Rule = Rule::type_def;
1131
1132 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1133 match pair.as_rule() {
1134 Rule::variant_def => Ok(Self::parse_variant_format(pair)?),
1135 Rule::record_def => Ok(Self::parse_record_format(pair)?),
1136 x => unreachable!("Unexpected rule in type_def: {:?}", x),
1137 }
1138 }
1139
1140 fn span(&self) -> &Span {
1141 &self.span
1142 }
1143}
1144
1145impl VariantCase {
1146 fn struct_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1147 let span = pair.as_span().into();
1148 let mut inner = pair.into_inner();
1149
1150 let identifier = inner.next().unwrap().as_str().to_string();
1151
1152 let fields = inner
1153 .map(RecordField::parse)
1154 .collect::<Result<Vec<_>, _>>()?;
1155
1156 Ok(Self {
1157 name: identifier,
1158 fields,
1159 span,
1160 })
1161 }
1162
1163 fn unit_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1164 let span = pair.as_span().into();
1165 let mut inner = pair.into_inner();
1166
1167 let identifier = inner.next().unwrap().as_str().to_string();
1168
1169 Ok(Self {
1170 name: identifier,
1171 fields: vec![],
1172 span,
1173 })
1174 }
1175}
1176
1177impl AstNode for VariantCase {
1178 const RULE: Rule = Rule::variant_case;
1179
1180 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1181 let case = match pair.as_rule() {
1182 Rule::variant_case_struct => Self::struct_case_parse(pair),
1183 Rule::variant_case_tuple => todo!("parse variant case tuple"),
1184 Rule::variant_case_unit => Self::unit_case_parse(pair),
1185 x => unreachable!("Unexpected rule in datum_variant: {:?}", x),
1186 }?;
1187
1188 Ok(case)
1189 }
1190
1191 fn span(&self) -> &Span {
1192 &self.span
1193 }
1194}
1195
1196impl AstNode for AssetDef {
1197 const RULE: Rule = Rule::asset_def;
1198
1199 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1200 let span = pair.as_span().into();
1201 let mut inner = pair.into_inner();
1202
1203 let identifier = inner.next().unwrap().as_str().to_string();
1204 let policy = HexStringLiteral::parse(inner.next().unwrap())?;
1205 let asset_name = inner.next().unwrap().as_str().to_string();
1206
1207 Ok(AssetDef {
1208 name: identifier,
1209 policy: Some(policy),
1210 asset_name: Some(asset_name),
1211 span,
1212 })
1213 }
1214
1215 fn span(&self) -> &Span {
1216 &self.span
1217 }
1218}
1219
1220impl AstNode for ChainSpecificBlock {
1221 const RULE: Rule = Rule::chain_specific_block;
1222
1223 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1224 let mut inner = pair.into_inner();
1225
1226 let block = inner.next().unwrap();
1227
1228 match block.as_rule() {
1229 Rule::cardano_block => {
1230 let block = crate::cardano::CardanoBlock::parse(block)?;
1231 Ok(ChainSpecificBlock::Cardano(block))
1232 }
1233 x => unreachable!("Unexpected rule in chain_specific_block: {:?}", x),
1234 }
1235 }
1236
1237 fn span(&self) -> &Span {
1238 match self {
1239 Self::Cardano(x) => x.span(),
1240 }
1241 }
1242}
1243
1244pub fn parse_string(input: &str) -> Result<Program, Error> {
1267 let pairs = Tx3Grammar::parse(Rule::program, input)?;
1268 Program::parse(pairs.into_iter().next().unwrap())
1269}
1270
1271#[cfg(test)]
1272pub fn parse_well_known_example(example: &str) -> Program {
1273 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1274 let test_file = format!("{}/../../examples/{}.tx3", manifest_dir, example);
1275 let input = std::fs::read_to_string(&test_file).unwrap();
1276 parse_string(&input).unwrap()
1277}
1278
1279#[cfg(test)]
1280mod tests {
1281 use super::*;
1282 use assert_json_diff::assert_json_eq;
1283 use paste::paste;
1284 use pest::Parser;
1285
1286 #[test]
1287 fn smoke_test_parse_string() {
1288 let _ = parse_string("tx swap() {}").unwrap();
1289 }
1290
1291 macro_rules! input_to_ast_check {
1292 ($ast:ty, $name:expr, $input:expr, $expected:expr) => {
1293 paste::paste! {
1294 #[test]
1295 fn [<test_parse_ $ast:snake _ $name>]() {
1296 let pairs = super::Tx3Grammar::parse(<$ast>::RULE, $input).unwrap();
1297 let single_match = pairs.into_iter().next().unwrap();
1298 let result = <$ast>::parse(single_match).unwrap();
1299
1300 assert_eq!(result, $expected);
1301 }
1302 }
1303 };
1304 }
1305
1306 input_to_ast_check!(BinaryOperator, "plus", "+", BinaryOperator::Add);
1307
1308 input_to_ast_check!(Type, "int", "Int", Type::Int);
1309
1310 input_to_ast_check!(Type, "bool", "Bool", Type::Bool);
1311
1312 input_to_ast_check!(Type, "bytes", "Bytes", Type::Bytes);
1313
1314 input_to_ast_check!(Type, "address", "Address", Type::Address);
1315
1316 input_to_ast_check!(Type, "utxo_ref", "UtxoRef", Type::UtxoRef);
1317
1318 input_to_ast_check!(Type, "any_asset", "AnyAsset", Type::AnyAsset);
1319
1320 input_to_ast_check!(Type, "list", "List<Int>", Type::List(Box::new(Type::Int)));
1321
1322 input_to_ast_check!(
1323 Type,
1324 "identifier",
1325 "MyType",
1326 Type::Custom(Identifier::new("MyType".to_string()))
1327 );
1328
1329 input_to_ast_check!(
1330 Type,
1331 "other_type",
1332 "List<Bytes>",
1333 Type::List(Box::new(Type::Bytes))
1334 );
1335
1336 input_to_ast_check!(
1337 Type,
1338 "within_list",
1339 "List<List<Int>>",
1340 Type::List(Box::new(Type::List(Box::new(Type::Int))))
1341 );
1342
1343 input_to_ast_check!(
1344 TypeDef,
1345 "type_def_record",
1346 "type MyRecord {
1347 field1: Int,
1348 field2: Bytes,
1349 }",
1350 TypeDef {
1351 name: "MyRecord".to_string(),
1352 cases: vec![VariantCase {
1353 name: "Default".to_string(),
1354 fields: vec![
1355 RecordField::new("field1", Type::Int),
1356 RecordField::new("field2", Type::Bytes)
1357 ],
1358 span: Span::DUMMY,
1359 }],
1360 span: Span::DUMMY,
1361 }
1362 );
1363
1364 input_to_ast_check!(
1365 TypeDef,
1366 "type_def_variant",
1367 "type MyVariant {
1368 Case1 {
1369 field1: Int,
1370 field2: Bytes,
1371 },
1372 Case2,
1373 }",
1374 TypeDef {
1375 name: "MyVariant".to_string(),
1376 cases: vec![
1377 VariantCase {
1378 name: "Case1".to_string(),
1379 fields: vec![
1380 RecordField::new("field1", Type::Int),
1381 RecordField::new("field2", Type::Bytes)
1382 ],
1383 span: Span::DUMMY,
1384 },
1385 VariantCase {
1386 name: "Case2".to_string(),
1387 fields: vec![],
1388 span: Span::DUMMY,
1389 },
1390 ],
1391 span: Span::DUMMY,
1392 }
1393 );
1394
1395 input_to_ast_check!(
1396 StringLiteral,
1397 "literal_string",
1398 "\"Hello, world!\"",
1399 StringLiteral::new("Hello, world!".to_string())
1400 );
1401
1402 input_to_ast_check!(
1403 HexStringLiteral,
1404 "hex_string",
1405 "0xAFAFAF",
1406 HexStringLiteral::new("AFAFAF".to_string())
1407 );
1408
1409 input_to_ast_check!(
1410 StringLiteral,
1411 "literal_string_address",
1412 "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1413 StringLiteral::new("addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string())
1414 );
1415
1416 input_to_ast_check!(
1417 ListConstructor,
1418 "empty_list",
1419 "[]",
1420 ListConstructor {
1421 elements: vec![],
1422 span: Span::DUMMY,
1423 }
1424 );
1425
1426 input_to_ast_check!(
1427 ListConstructor,
1428 "trailing_comma",
1429 "[1, 2,]",
1430 ListConstructor {
1431 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1432 span: Span::DUMMY,
1433 }
1434 );
1435
1436 input_to_ast_check!(
1437 ListConstructor,
1438 "int_list",
1439 "[1, 2]",
1440 ListConstructor {
1441 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1442 span: Span::DUMMY,
1443 }
1444 );
1445
1446 input_to_ast_check!(
1447 ListConstructor,
1448 "string_list",
1449 "[\"Hello\", \"World\"]",
1450 ListConstructor {
1451 elements: vec![
1452 DataExpr::String(StringLiteral::new("Hello".to_string())),
1453 DataExpr::String(StringLiteral::new("World".to_string()))
1454 ],
1455 span: Span::DUMMY,
1456 }
1457 );
1458
1459 input_to_ast_check!(
1460 ListConstructor,
1461 "mixed_list",
1462 "[1, \"Hello\", true]",
1463 ListConstructor {
1464 elements: vec![
1465 DataExpr::Number(1),
1466 DataExpr::String(StringLiteral::new("Hello".to_string())),
1467 DataExpr::Bool(true)
1468 ],
1469 span: Span::DUMMY,
1470 }
1471 );
1472
1473 input_to_ast_check!(
1474 ListConstructor,
1475 "list_within_list",
1476 "[[1, 2], [3, 4]]",
1477 ListConstructor {
1478 elements: vec![
1479 DataExpr::ListConstructor(ListConstructor {
1480 elements: vec![DataExpr::Number(1), DataExpr::Number(2),],
1481 span: Span::DUMMY,
1482 }),
1483 DataExpr::ListConstructor(ListConstructor {
1484 elements: vec![DataExpr::Number(3), DataExpr::Number(4),],
1485 span: Span::DUMMY,
1486 }),
1487 ],
1488 span: Span::DUMMY,
1489 }
1490 );
1491
1492 input_to_ast_check!(DataExpr, "literal_bool_true", "true", DataExpr::Bool(true));
1493
1494 input_to_ast_check!(
1495 DataExpr,
1496 "literal_bool_false",
1497 "false",
1498 DataExpr::Bool(false)
1499 );
1500
1501 input_to_ast_check!(DataExpr, "unit_value", "())", DataExpr::Unit);
1502
1503 input_to_ast_check!(DataExpr, "number_value", "123", DataExpr::Number(123));
1504
1505 input_to_ast_check!(
1506 PropertyAccess,
1507 "single_property",
1508 "subject.property",
1509 PropertyAccess::new("subject", &["property"])
1510 );
1511
1512 input_to_ast_check!(
1513 PropertyAccess,
1514 "multiple_properties",
1515 "subject.property.subproperty",
1516 PropertyAccess::new("subject", &["property", "subproperty"])
1517 );
1518
1519 input_to_ast_check!(
1520 PolicyDef,
1521 "policy_def_assign",
1522 "policy MyPolicy = 0xAFAFAF;",
1523 PolicyDef {
1524 name: "MyPolicy".to_string(),
1525 value: PolicyValue::Assign(HexStringLiteral::new("AFAFAF".to_string())),
1526 span: Span::DUMMY,
1527 }
1528 );
1529
1530 input_to_ast_check!(
1531 PolicyDef,
1532 "policy_def_constructor",
1533 "policy MyPolicy {
1534 hash: 0x1234567890,
1535 script: 0x1234567890,
1536 ref: 0x1234567890,
1537 };",
1538 PolicyDef {
1539 name: "MyPolicy".to_string(),
1540 value: PolicyValue::Constructor(PolicyConstructor {
1541 fields: vec![
1542 PolicyField::Hash(DataExpr::HexString(HexStringLiteral::new(
1543 "1234567890".to_string()
1544 ))),
1545 PolicyField::Script(DataExpr::HexString(HexStringLiteral::new(
1546 "1234567890".to_string()
1547 ))),
1548 PolicyField::Ref(DataExpr::HexString(HexStringLiteral::new(
1549 "1234567890".to_string()
1550 ))),
1551 ],
1552 span: Span::DUMMY,
1553 }),
1554 span: Span::DUMMY,
1555 }
1556 );
1557
1558 input_to_ast_check!(
1559 AssetDef,
1560 "hex_hex",
1561 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.0xef7a1ceb;",
1562 AssetDef {
1563 name: "MyToken".to_string(),
1564 policy: Some(HexStringLiteral::new(
1565 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1566 )),
1567 asset_name: Some("0xef7a1ceb".to_string()),
1568 span: Span::DUMMY,
1569 }
1570 );
1571
1572 input_to_ast_check!(
1573 AssetDef,
1574 "hex_ascii",
1575 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.MYTOKEN;",
1576 AssetDef {
1577 name: "MyToken".to_string(),
1578 policy: Some(HexStringLiteral::new(
1579 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1580 )),
1581 asset_name: Some("MYTOKEN".to_string()),
1582 span: Span::DUMMY,
1583 }
1584 );
1585
1586 input_to_ast_check!(
1587 StaticAssetConstructor,
1588 "type_and_literal",
1589 "MyToken(15)",
1590 StaticAssetConstructor {
1591 r#type: Identifier::new("MyToken"),
1592 amount: Box::new(DataExpr::Number(15)),
1593 span: Span::DUMMY,
1594 }
1595 );
1596
1597 input_to_ast_check!(
1598 AnyAssetConstructor,
1599 "any_asset_constructor",
1600 "AnyAsset(0x1234567890, \"MyToken\", 15)",
1601 AnyAssetConstructor {
1602 policy: Box::new(DataExpr::HexString(HexStringLiteral::new(
1603 "1234567890".to_string()
1604 ))),
1605 asset_name: Box::new(DataExpr::String(StringLiteral::new("MyToken".to_string()))),
1606 amount: Box::new(DataExpr::Number(15)),
1607 span: Span::DUMMY,
1608 }
1609 );
1610
1611 input_to_ast_check!(
1612 AnyAssetConstructor,
1613 "any_asset_identifiers",
1614 "AnyAsset(my_policy, my_token, my_amount)",
1615 AnyAssetConstructor {
1616 policy: Box::new(DataExpr::Identifier(Identifier::new("my_policy"))),
1617 asset_name: Box::new(DataExpr::Identifier(Identifier::new("my_token"))),
1618 amount: Box::new(DataExpr::Identifier(Identifier::new("my_amount"))),
1619 span: Span::DUMMY,
1620 }
1621 );
1622
1623 input_to_ast_check!(
1624 AnyAssetConstructor,
1625 "any_asset_property_access",
1626 "AnyAsset(input1.policy, input1.asset_name, input1.amount)",
1627 AnyAssetConstructor {
1628 policy: Box::new(DataExpr::PropertyAccess(PropertyAccess::new(
1629 "input1",
1630 &["policy"],
1631 ))),
1632 asset_name: Box::new(DataExpr::PropertyAccess(PropertyAccess::new(
1633 "input1",
1634 &["asset_name"],
1635 ))),
1636 amount: Box::new(DataExpr::PropertyAccess(PropertyAccess::new(
1637 "input1",
1638 &["amount"],
1639 ))),
1640 span: Span::DUMMY,
1641 }
1642 );
1643
1644 input_to_ast_check!(
1645 DataExpr,
1646 "addition",
1647 "5 + var1",
1648 DataExpr::BinaryOp(DataBinaryOp {
1649 operator: BinaryOperator::Add,
1650 left: Box::new(DataExpr::Number(5)),
1651 right: Box::new(DataExpr::Identifier(Identifier::new("var1"))),
1652 span: Span::DUMMY,
1653 })
1654 );
1655
1656 input_to_ast_check!(
1657 AddressExpr,
1658 "address_string",
1659 "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1660 AddressExpr::String(StringLiteral::new(
1661 "addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string()
1662 ))
1663 );
1664
1665 input_to_ast_check!(
1666 AddressExpr,
1667 "address_hex_string",
1668 "0x1234567890abcdef",
1669 AddressExpr::HexString(HexStringLiteral::new("1234567890abcdef".to_string()))
1670 );
1671
1672 input_to_ast_check!(
1673 AddressExpr,
1674 "address_identifier",
1675 "my_address",
1676 AddressExpr::Identifier(Identifier::new("my_address"))
1677 );
1678
1679 input_to_ast_check!(
1680 StructConstructor,
1681 "struct_constructor_record",
1682 "MyRecord {
1683 field1: 10,
1684 field2: abc,
1685 }",
1686 StructConstructor {
1687 r#type: Identifier::new("MyRecord"),
1688 case: VariantCaseConstructor {
1689 name: Identifier::new("Default"),
1690 fields: vec![
1691 RecordConstructorField {
1692 name: Identifier::new("field1"),
1693 value: Box::new(DataExpr::Number(10)),
1694 span: Span::DUMMY,
1695 },
1696 RecordConstructorField {
1697 name: Identifier::new("field2"),
1698 value: Box::new(DataExpr::Identifier(Identifier::new("abc"))),
1699 span: Span::DUMMY,
1700 },
1701 ],
1702 spread: None,
1703 scope: None,
1704 span: Span::DUMMY,
1705 },
1706 scope: None,
1707 span: Span::DUMMY,
1708 }
1709 );
1710
1711 input_to_ast_check!(
1712 StructConstructor,
1713 "struct_constructor_variant",
1714 "ShipCommand::MoveShip {
1715 delta_x: delta_x,
1716 delta_y: delta_y,
1717 }",
1718 StructConstructor {
1719 r#type: Identifier::new("ShipCommand"),
1720 case: VariantCaseConstructor {
1721 name: Identifier::new("MoveShip"),
1722 fields: vec![
1723 RecordConstructorField {
1724 name: Identifier::new("delta_x"),
1725 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1726 span: Span::DUMMY,
1727 },
1728 RecordConstructorField {
1729 name: Identifier::new("delta_y"),
1730 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1731 span: Span::DUMMY,
1732 },
1733 ],
1734 spread: None,
1735 scope: None,
1736 span: Span::DUMMY,
1737 },
1738 scope: None,
1739 span: Span::DUMMY,
1740 }
1741 );
1742
1743 input_to_ast_check!(
1744 StructConstructor,
1745 "struct_constructor_variant_with_spread",
1746 "ShipCommand::MoveShip {
1747 delta_x: delta_x,
1748 delta_y: delta_y,
1749 ...abc
1750 }",
1751 StructConstructor {
1752 r#type: Identifier::new("ShipCommand"),
1753 case: VariantCaseConstructor {
1754 name: Identifier::new("MoveShip"),
1755 fields: vec![
1756 RecordConstructorField {
1757 name: Identifier::new("delta_x"),
1758 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1759 span: Span::DUMMY,
1760 },
1761 RecordConstructorField {
1762 name: Identifier::new("delta_y"),
1763 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1764 span: Span::DUMMY,
1765 },
1766 ],
1767 spread: Some(Box::new(DataExpr::Identifier(Identifier::new(
1768 "abc".to_string()
1769 )))),
1770 scope: None,
1771 span: Span::DUMMY,
1772 },
1773 scope: None,
1774 span: Span::DUMMY,
1775 }
1776 );
1777
1778 input_to_ast_check!(
1779 OutputBlock,
1780 "output_block_anonymous",
1781 r#"output {
1782 to: my_party,
1783 amount: Ada(100),
1784 }"#,
1785 OutputBlock {
1786 name: None,
1787 fields: vec![
1788 OutputBlockField::To(Box::new(AddressExpr::Identifier(Identifier::new(
1789 "my_party".to_string(),
1790 )))),
1791 OutputBlockField::Amount(Box::new(AssetExpr::StaticConstructor(
1792 StaticAssetConstructor {
1793 r#type: Identifier::new("Ada"),
1794 amount: Box::new(DataExpr::Number(100)),
1795 span: Span::DUMMY,
1796 },
1797 ))),
1798 ],
1799 span: Span::DUMMY,
1800 }
1801 );
1802
1803 input_to_ast_check!(
1804 ChainSpecificBlock,
1805 "chain_specific_block_cardano",
1806 "cardano::vote_delegation_certificate {
1807 drep: 0x1234567890,
1808 stake: 0x1234567890,
1809 }",
1810 ChainSpecificBlock::Cardano(crate::cardano::CardanoBlock::VoteDelegationCertificate(
1811 crate::cardano::VoteDelegationCertificate {
1812 drep: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
1813 stake: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
1814 span: Span::DUMMY,
1815 },
1816 ))
1817 );
1818
1819 #[test]
1820 fn test_spans_are_respected() {
1821 let program = parse_well_known_example("lang_tour");
1822 assert_eq!(program.span, Span::new(0, 972));
1823
1824 assert_eq!(program.parties[0].span, Span::new(0, 14));
1825
1826 assert_eq!(program.types[0].span, Span::new(16, 111));
1827 }
1828
1829 fn make_snapshot_if_missing(example: &str, program: &Program) {
1830 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1831 let path = format!("{}/../../examples/{}.ast", manifest_dir, example);
1832
1833 if !std::fs::exists(&path).unwrap() {
1834 let ast = serde_json::to_string_pretty(program).unwrap();
1835 std::fs::write(&path, ast).unwrap();
1836 }
1837 }
1838
1839 fn test_parsing_example(example: &str) {
1840 let program = parse_well_known_example(example);
1841
1842 make_snapshot_if_missing(example, &program);
1843
1844 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1845 let ast_file = format!("{}/../../examples/{}.ast", manifest_dir, example);
1846 let ast = std::fs::read_to_string(ast_file).unwrap();
1847
1848 let expected: Program = serde_json::from_str(&ast).unwrap();
1849
1850 assert_json_eq!(program, expected);
1851 }
1852
1853 #[macro_export]
1854 macro_rules! test_parsing {
1855 ($name:ident) => {
1856 paste! {
1857 #[test]
1858 fn [<test_example_ $name>]() {
1859 test_parsing_example(stringify!($name));
1860 }
1861 }
1862 };
1863 }
1864
1865 test_parsing!(lang_tour);
1866
1867 test_parsing!(transfer);
1868
1869 test_parsing!(swap);
1870
1871 test_parsing!(asteria);
1872
1873 test_parsing!(vesting);
1874
1875 test_parsing!(faucet);
1876}