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 inputs = Vec::new();
148 let mut outputs = Vec::new();
149 let mut burn = None;
150 let mut mint = None;
151 let mut adhoc = Vec::new();
152
153 for item in inner {
154 match item.as_rule() {
155 Rule::input_block => inputs.push(InputBlock::parse(item)?),
156 Rule::output_block => outputs.push(OutputBlock::parse(item)?),
157 Rule::burn_block => burn = Some(BurnBlock::parse(item)?),
158 Rule::mint_block => mint = Some(MintBlock::parse(item)?),
159 Rule::chain_specific_block => adhoc.push(ChainSpecificBlock::parse(item)?),
160 x => unreachable!("Unexpected rule in tx_def: {:?}", x),
161 }
162 }
163
164 Ok(TxDef {
165 name,
166 parameters,
167 inputs,
168 outputs,
169 burn,
170 mint,
171 adhoc,
172 scope: None,
173 span,
174 })
175 }
176
177 fn span(&self) -> &Span {
178 &self.span
179 }
180}
181
182impl AstNode for Identifier {
183 const RULE: Rule = Rule::identifier;
184
185 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
186 Ok(Identifier {
187 value: pair.as_str().to_string(),
188 symbol: None,
189 span: pair.as_span().into(),
190 })
191 }
192
193 fn span(&self) -> &Span {
194 &self.span
195 }
196}
197
198impl AstNode for StringLiteral {
199 const RULE: Rule = Rule::string;
200
201 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
202 Ok(StringLiteral {
203 value: pair.as_str()[1..pair.as_str().len() - 1].to_string(),
204 span: pair.as_span().into(),
205 })
206 }
207
208 fn span(&self) -> &Span {
209 &self.span
210 }
211}
212
213impl AstNode for HexStringLiteral {
214 const RULE: Rule = Rule::hex_string;
215
216 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
217 Ok(HexStringLiteral {
218 value: pair.as_str()[2..].to_string(),
219 span: pair.as_span().into(),
220 })
221 }
222
223 fn span(&self) -> &Span {
224 &self.span
225 }
226}
227
228impl AstNode for PartyDef {
229 const RULE: Rule = Rule::party_def;
230
231 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
232 let span = pair.as_span().into();
233 let mut inner = pair.into_inner();
234 let identifier = inner.next().unwrap().as_str().to_string();
235
236 Ok(PartyDef {
237 name: identifier,
238 span,
239 })
240 }
241
242 fn span(&self) -> &Span {
243 &self.span
244 }
245}
246
247impl AstNode for InputBlockField {
248 const RULE: Rule = Rule::input_block_field;
249
250 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
251 match pair.as_rule() {
252 Rule::input_block_from => {
253 let pair = pair.into_inner().next().unwrap();
254 let x = InputBlockField::From(AddressExpr::parse(pair)?);
255 Ok(x)
256 }
257 Rule::input_block_datum_is => {
258 let pair = pair.into_inner().next().unwrap();
259 let x = InputBlockField::DatumIs(Type::parse(pair)?);
260 Ok(x)
261 }
262 Rule::input_block_min_amount => {
263 let pair = pair.into_inner().next().unwrap();
264 let x = InputBlockField::MinAmount(AssetExpr::parse(pair)?);
265 Ok(x)
266 }
267 Rule::input_block_redeemer => {
268 let pair = pair.into_inner().next().unwrap();
269 let x = InputBlockField::Redeemer(DataExpr::parse(pair)?);
270 Ok(x)
271 }
272 Rule::input_block_ref => {
273 let pair = pair.into_inner().next().unwrap();
274 let x = InputBlockField::Ref(DataExpr::parse(pair)?);
275 Ok(x)
276 }
277 x => unreachable!("Unexpected rule in input_block: {:?}", x),
278 }
279 }
280
281 fn span(&self) -> &Span {
282 match self {
283 Self::From(x) => x.span(),
284 Self::DatumIs(x) => x.span(),
285 Self::MinAmount(x) => x.span(),
286 Self::Redeemer(x) => x.span(),
287 Self::Ref(x) => x.span(),
288 }
289 }
290}
291
292impl AstNode for InputBlock {
293 const RULE: Rule = Rule::input_block;
294
295 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
296 let span = pair.as_span().into();
297 let mut inner = pair.into_inner();
298
299 let name = inner.next().unwrap().as_str().to_string();
300
301 let fields = inner
302 .map(|x| InputBlockField::parse(x))
303 .collect::<Result<Vec<_>, _>>()?;
304
305 Ok(InputBlock {
306 name,
307 is_many: false,
308 fields,
309 span,
310 })
311 }
312
313 fn span(&self) -> &Span {
314 &self.span
315 }
316}
317
318impl AstNode for OutputBlockField {
319 const RULE: Rule = Rule::output_block_field;
320
321 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
322 match pair.as_rule() {
323 Rule::output_block_to => {
324 let pair = pair.into_inner().next().unwrap();
325 let x = OutputBlockField::To(Box::new(AddressExpr::parse(pair)?));
326 Ok(x)
327 }
328 Rule::output_block_amount => {
329 let pair = pair.into_inner().next().unwrap();
330 let x = OutputBlockField::Amount(AssetExpr::parse(pair)?.into());
331 Ok(x)
332 }
333 Rule::output_block_datum => {
334 let pair = pair.into_inner().next().unwrap();
335 let x = OutputBlockField::Datum(DataExpr::parse(pair)?.into());
336 Ok(x)
337 }
338 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
339 }
340 }
341
342 fn span(&self) -> &Span {
343 match self {
344 Self::To(x) => x.span(),
345 Self::Amount(x) => x.span(),
346 Self::Datum(x) => x.span(),
347 }
348 }
349}
350
351impl AstNode for OutputBlock {
352 const RULE: Rule = Rule::output_block;
353
354 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
355 let span = pair.as_span().into();
356 let mut inner = pair.into_inner();
357
358 let has_name = inner
359 .peek()
360 .map(|x| x.as_rule() == Rule::identifier)
361 .unwrap_or_default();
362
363 let name = has_name.then(|| inner.next().unwrap().as_str().to_string());
364
365 let fields = inner
366 .map(|x| OutputBlockField::parse(x))
367 .collect::<Result<Vec<_>, _>>()?;
368
369 Ok(OutputBlock { name, fields, span })
370 }
371
372 fn span(&self) -> &Span {
373 &self.span
374 }
375}
376
377impl AstNode for MintBlockField {
378 const RULE: Rule = Rule::mint_block_field;
379
380 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
381 match pair.as_rule() {
382 Rule::mint_block_amount => {
383 let pair = pair.into_inner().next().unwrap();
384 let x = MintBlockField::Amount(AssetExpr::parse(pair)?.into());
385 Ok(x)
386 }
387 Rule::mint_block_redeemer => {
388 let pair = pair.into_inner().next().unwrap();
389 let x = MintBlockField::Redeemer(DataExpr::parse(pair)?.into());
390 Ok(x)
391 }
392 x => unreachable!("Unexpected rule in output_block_field: {:?}", x),
393 }
394 }
395
396 fn span(&self) -> &Span {
397 match self {
398 Self::Amount(x) => x.span(),
399 Self::Redeemer(x) => x.span(),
400 }
401 }
402}
403
404impl AstNode for MintBlock {
405 const RULE: Rule = Rule::mint_block;
406
407 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
408 let span = pair.as_span().into();
409 let inner = pair.into_inner();
410
411 let fields = inner
412 .map(|x| MintBlockField::parse(x))
413 .collect::<Result<Vec<_>, _>>()?;
414
415 Ok(MintBlock { fields, span })
416 }
417
418 fn span(&self) -> &Span {
419 &self.span
420 }
421}
422
423impl AstNode for BurnBlock {
424 const RULE: Rule = Rule::burn_block;
425
426 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
427 let span = pair.as_span().into();
428 let inner = pair.into_inner();
429
430 let fields = inner
431 .map(|x| MintBlockField::parse(x))
432 .collect::<Result<Vec<_>, _>>()?;
433
434 Ok(BurnBlock { fields, span })
435 }
436
437 fn span(&self) -> &Span {
438 &self.span
439 }
440}
441
442impl AstNode for RecordField {
443 const RULE: Rule = Rule::record_field;
444
445 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
446 let span = pair.as_span().into();
447 let mut inner = pair.into_inner();
448 let identifier = inner.next().unwrap().as_str().to_string();
449 let r#type = Type::parse(inner.next().unwrap())?;
450
451 Ok(RecordField {
452 name: identifier,
453 r#type,
454 span,
455 })
456 }
457
458 fn span(&self) -> &Span {
459 &self.span
460 }
461}
462
463impl AstNode for PolicyField {
464 const RULE: Rule = Rule::policy_def_field;
465
466 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
467 match pair.as_rule() {
468 Rule::policy_def_hash => Ok(PolicyField::Hash(DataExpr::parse(
469 pair.into_inner().next().unwrap(),
470 )?)),
471 Rule::policy_def_script => Ok(PolicyField::Script(DataExpr::parse(
472 pair.into_inner().next().unwrap(),
473 )?)),
474 Rule::policy_def_ref => Ok(PolicyField::Ref(DataExpr::parse(
475 pair.into_inner().next().unwrap(),
476 )?)),
477 x => unreachable!("Unexpected rule in policy_field: {:?}", x),
478 }
479 }
480
481 fn span(&self) -> &Span {
482 match self {
483 Self::Hash(x) => x.span(),
484 Self::Script(x) => x.span(),
485 Self::Ref(x) => x.span(),
486 }
487 }
488}
489
490impl AstNode for PolicyConstructor {
491 const RULE: Rule = Rule::policy_def_constructor;
492
493 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
494 let span = pair.as_span().into();
495 let inner = pair.into_inner();
496
497 let fields = inner
498 .map(|x| PolicyField::parse(x))
499 .collect::<Result<Vec<_>, _>>()?;
500
501 Ok(PolicyConstructor { fields, span })
502 }
503
504 fn span(&self) -> &Span {
505 &self.span
506 }
507}
508
509impl AstNode for PolicyValue {
510 const RULE: Rule = Rule::policy_def_value;
511
512 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
513 match pair.as_rule() {
514 Rule::policy_def_constructor => {
515 Ok(PolicyValue::Constructor(PolicyConstructor::parse(pair)?))
516 }
517 Rule::policy_def_assign => Ok(PolicyValue::Assign(HexStringLiteral::parse(
518 pair.into_inner().next().unwrap(),
519 )?)),
520 x => unreachable!("Unexpected rule in policy_value: {:?}", x),
521 }
522 }
523
524 fn span(&self) -> &Span {
525 match self {
526 Self::Constructor(x) => x.span(),
527 Self::Assign(x) => x.span(),
528 }
529 }
530}
531
532impl AstNode for PolicyDef {
533 const RULE: Rule = Rule::policy_def;
534
535 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
536 let span = pair.as_span().into();
537 let mut inner = pair.into_inner();
538 let name = inner.next().unwrap().as_str().to_string();
539 let value = PolicyValue::parse(inner.next().unwrap())?;
540
541 Ok(PolicyDef { name, value, span })
542 }
543
544 fn span(&self) -> &Span {
545 &self.span
546 }
547}
548
549impl AstNode for AddressExpr {
550 const RULE: Rule = Rule::address_expr;
551
552 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
553 let mut inner = pair.into_inner();
554
555 let value = inner.next().unwrap();
556
557 match value.as_rule() {
558 Rule::string => Ok(AddressExpr::String(StringLiteral::parse(value)?)),
559 Rule::hex_string => Ok(AddressExpr::HexString(HexStringLiteral::parse(value)?)),
560 Rule::identifier => Ok(AddressExpr::Identifier(Identifier::parse(value)?)),
561 x => unreachable!("Unexpected rule in address_expr: {:?}", x),
562 }
563 }
564
565 fn span(&self) -> &Span {
566 match self {
567 Self::String(x) => x.span(),
568 Self::HexString(x) => x.span(),
569 Self::Identifier(x) => x.span(),
570 }
571 }
572}
573
574impl AstNode for AssetConstructor {
575 const RULE: Rule = Rule::asset_constructor;
576
577 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
578 let span = pair.as_span().into();
579 let mut inner = pair.into_inner();
580
581 let r#type = Identifier::parse(inner.next().unwrap())?;
582 let amount = DataExpr::parse(inner.next().unwrap())?;
583
584 Ok(AssetConstructor {
585 r#type,
586 amount: Box::new(amount),
587 span,
588 })
589 }
590
591 fn span(&self) -> &Span {
592 &self.span
593 }
594}
595
596impl AssetExpr {
597 fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
598 Ok(AssetExpr::Identifier(Identifier::parse(pair)?))
599 }
600
601 fn constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
602 Ok(AssetExpr::Constructor(AssetConstructor::parse(pair)?))
603 }
604
605 fn property_access_parse(pair: Pair<Rule>) -> Result<Self, Error> {
606 Ok(AssetExpr::PropertyAccess(PropertyAccess::parse(pair)?))
607 }
608
609 fn term_parse(pair: Pair<Rule>) -> Result<Self, Error> {
610 match pair.as_rule() {
611 Rule::asset_constructor => AssetExpr::constructor_parse(pair),
612 Rule::property_access => AssetExpr::property_access_parse(pair),
613 Rule::identifier => AssetExpr::identifier_parse(pair),
614 x => unreachable!("Unexpected rule in asset_expr: {:?}", x),
615 }
616 }
617}
618
619impl AstNode for AssetExpr {
620 const RULE: Rule = Rule::asset_expr;
621
622 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
623 let mut inner = pair.into_inner();
624
625 let mut final_expr = Self::term_parse(inner.next().unwrap())?;
626
627 while let Some(term) = inner.next() {
628 let span = term.as_span().into();
629 let operator = BinaryOperator::parse(term)?;
630 let next_expr = Self::term_parse(inner.next().unwrap())?;
631
632 final_expr = AssetExpr::BinaryOp(AssetBinaryOp {
633 operator,
634 left: Box::new(final_expr),
635 right: Box::new(next_expr),
636 span,
637 });
638 }
639
640 Ok(final_expr)
641 }
642
643 fn span(&self) -> &Span {
644 match self {
645 AssetExpr::Constructor(x) => x.span(),
646 AssetExpr::BinaryOp(x) => &x.span,
647 AssetExpr::PropertyAccess(x) => x.span(),
648 AssetExpr::Identifier(x) => x.span(),
649 }
650 }
651}
652
653impl AstNode for PropertyAccess {
654 const RULE: Rule = Rule::property_access;
655
656 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
657 let span = pair.as_span().into();
658 let mut inner = pair.into_inner();
659
660 let object = Identifier::parse(inner.next().unwrap())?;
661
662 let mut identifiers = Vec::new();
663 identifiers.push(Identifier::parse(inner.next().unwrap())?);
664
665 for identifier in inner {
666 identifiers.push(Identifier::parse(identifier)?);
667 }
668
669 Ok(PropertyAccess {
670 object,
671 path: identifiers,
672 scope: None,
673 span,
674 })
675 }
676
677 fn span(&self) -> &Span {
678 &self.span
679 }
680}
681
682impl AstNode for RecordConstructorField {
683 const RULE: Rule = Rule::record_constructor_field;
684
685 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
686 let span = pair.as_span().into();
687 let mut inner = pair.into_inner();
688
689 let name = Identifier::parse(inner.next().unwrap())?;
690 let value = DataExpr::parse(inner.next().unwrap())?;
691
692 Ok(RecordConstructorField {
693 name,
694 value: Box::new(value),
695 span,
696 })
697 }
698
699 fn span(&self) -> &Span {
700 &self.span
701 }
702}
703
704impl AstNode for DatumConstructor {
705 const RULE: Rule = Rule::datum_constructor;
706
707 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
708 let span = pair.as_span().into();
709 let mut inner = pair.into_inner();
710
711 let r#type = Identifier::parse(inner.next().unwrap())?;
712 let case = VariantCaseConstructor::parse(inner.next().unwrap())?;
713
714 Ok(DatumConstructor {
715 r#type,
716 case,
717 scope: None,
718 span,
719 })
720 }
721
722 fn span(&self) -> &Span {
723 &self.span
724 }
725}
726
727impl VariantCaseConstructor {
728 fn implicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
729 let span = pair.as_span().into();
730 let inner = pair.into_inner();
731
732 let mut fields = Vec::new();
733 let mut spread = None;
734
735 for pair in inner {
736 match pair.as_rule() {
737 Rule::record_constructor_field => {
738 fields.push(RecordConstructorField::parse(pair)?);
739 }
740 Rule::spread_expression => {
741 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
742 }
743 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
744 }
745 }
746
747 Ok(VariantCaseConstructor {
748 name: Identifier::new("Default"),
749 fields,
750 spread: spread.map(Box::new),
751 scope: None,
752 span,
753 })
754 }
755
756 fn explicit_parse(pair: Pair<Rule>) -> Result<Self, Error> {
757 let span = pair.as_span().into();
758 let mut inner = pair.into_inner();
759
760 let name = Identifier::parse(inner.next().unwrap())?;
761
762 let mut fields = Vec::new();
763 let mut spread = None;
764
765 for pair in inner {
766 match pair.as_rule() {
767 Rule::record_constructor_field => {
768 fields.push(RecordConstructorField::parse(pair)?);
769 }
770 Rule::spread_expression => {
771 spread = Some(DataExpr::parse(pair.into_inner().next().unwrap())?);
772 }
773 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
774 }
775 }
776
777 Ok(VariantCaseConstructor {
778 name,
779 fields,
780 spread: spread.map(Box::new),
781 scope: None,
782 span,
783 })
784 }
785}
786
787impl AstNode for VariantCaseConstructor {
788 const RULE: Rule = Rule::variant_case_constructor;
789
790 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
791 match pair.as_rule() {
792 Rule::implicit_variant_case_constructor => Self::implicit_parse(pair),
793 Rule::explicit_variant_case_constructor => Self::explicit_parse(pair),
794 x => unreachable!("Unexpected rule in datum_constructor: {:?}", x),
795 }
796 }
797
798 fn span(&self) -> &Span {
799 &self.span
800 }
801}
802
803impl DataExpr {
804 fn number_parse(pair: Pair<Rule>) -> Result<Self, Error> {
805 Ok(DataExpr::Number(pair.as_str().parse().unwrap()))
806 }
807
808 fn bool_parse(pair: Pair<Rule>) -> Result<Self, Error> {
809 Ok(DataExpr::Bool(pair.as_str().parse().unwrap()))
810 }
811
812 fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
813 Ok(DataExpr::Identifier(Identifier::parse(pair)?))
814 }
815
816 fn property_access_parse(pair: Pair<Rule>) -> Result<Self, Error> {
817 Ok(DataExpr::PropertyAccess(PropertyAccess::parse(pair)?))
818 }
819
820 fn constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
821 Ok(DataExpr::Constructor(DatumConstructor::parse(pair)?))
822 }
823
824 fn term_parse(pair: Pair<Rule>) -> Result<Self, Error> {
825 match pair.as_rule() {
826 Rule::number => DataExpr::number_parse(pair),
827 Rule::string => Ok(DataExpr::String(StringLiteral::parse(pair)?)),
828 Rule::bool => DataExpr::bool_parse(pair),
829 Rule::hex_string => Ok(DataExpr::HexString(HexStringLiteral::parse(pair)?)),
830 Rule::datum_constructor => DataExpr::constructor_parse(pair),
831 Rule::unit => Ok(DataExpr::Unit),
832 Rule::identifier => DataExpr::identifier_parse(pair),
833 Rule::property_access => DataExpr::property_access_parse(pair),
834 x => unreachable!("Unexpected rule in data_expr: {:?}", x),
835 }
836 }
837}
838
839impl AstNode for DataExpr {
840 const RULE: Rule = Rule::data_expr;
841
842 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
843 let mut inner = pair.into_inner();
844
845 let mut final_expr = Self::term_parse(inner.next().unwrap())?;
846
847 while let Some(term) = inner.next() {
848 let span = term.as_span().into();
849 let operator = BinaryOperator::parse(term)?;
850 let next_expr = Self::term_parse(inner.next().unwrap())?;
851
852 final_expr = DataExpr::BinaryOp(DataBinaryOp {
853 operator,
854 left: Box::new(final_expr),
855 right: Box::new(next_expr),
856 span,
857 });
858 }
859
860 Ok(final_expr)
861 }
862
863 fn span(&self) -> &Span {
864 match self {
865 DataExpr::None => &Span::DUMMY, DataExpr::Unit => &Span::DUMMY, DataExpr::Number(_) => &Span::DUMMY, DataExpr::Bool(_) => &Span::DUMMY, DataExpr::String(x) => x.span(),
870 DataExpr::HexString(x) => x.span(),
871 DataExpr::Constructor(x) => x.span(),
872 DataExpr::Identifier(x) => x.span(),
873 DataExpr::PropertyAccess(x) => x.span(),
874 DataExpr::BinaryOp(x) => &x.span,
875 }
876 }
877}
878
879impl AstNode for BinaryOperator {
880 const RULE: Rule = Rule::binary_operator;
881
882 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
883 match pair.as_str() {
884 "+" => Ok(BinaryOperator::Add),
885 "-" => Ok(BinaryOperator::Subtract),
886 x => unreachable!("Unexpected string in binary_operator: {:?}", x),
887 }
888 }
889
890 fn span(&self) -> &Span {
891 &Span::DUMMY }
893}
894
895impl AstNode for Type {
896 const RULE: Rule = Rule::r#type;
897
898 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
899 match pair.as_str() {
900 "Int" => Ok(Type::Int),
901 "Bool" => Ok(Type::Bool),
902 "Bytes" => Ok(Type::Bytes),
903 "Address" => Ok(Type::Address),
904 "UtxoRef" => Ok(Type::UtxoRef),
905 "AnyAsset" => Ok(Type::AnyAsset),
906 t => Ok(Type::Custom(Identifier::new(t.to_string()))),
907 }
908 }
909
910 fn span(&self) -> &Span {
911 &Span::DUMMY }
913}
914
915impl TypeDef {
916 fn parse_variant_format(pair: Pair<Rule>) -> Result<Self, Error> {
917 let span = pair.as_span().into();
918 let mut inner = pair.into_inner();
919
920 let identifier = inner.next().unwrap().as_str().to_string();
921
922 let cases = inner
923 .map(VariantCase::parse)
924 .collect::<Result<Vec<_>, _>>()?;
925
926 Ok(TypeDef {
927 name: identifier,
928 cases,
929 span,
930 })
931 }
932
933 fn parse_record_format(pair: Pair<Rule>) -> Result<Self, Error> {
934 let span: Span = pair.as_span().into();
935 let mut inner = pair.into_inner();
936
937 let identifier = inner.next().unwrap().as_str().to_string();
938
939 let fields = inner
940 .map(RecordField::parse)
941 .collect::<Result<Vec<_>, _>>()?;
942
943 Ok(TypeDef {
944 name: identifier.clone(),
945 cases: vec![VariantCase {
946 name: "Default".to_string(),
947 fields,
948 span: span.clone(),
949 }],
950 span,
951 })
952 }
953}
954
955impl AstNode for TypeDef {
956 const RULE: Rule = Rule::type_def;
957
958 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
959 match pair.as_rule() {
960 Rule::variant_def => Ok(Self::parse_variant_format(pair)?),
961 Rule::record_def => Ok(Self::parse_record_format(pair)?),
962 x => unreachable!("Unexpected rule in type_def: {:?}", x),
963 }
964 }
965
966 fn span(&self) -> &Span {
967 &self.span
968 }
969}
970
971impl VariantCase {
972 fn struct_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
973 let span = pair.as_span().into();
974 let mut inner = pair.into_inner();
975
976 let identifier = inner.next().unwrap().as_str().to_string();
977
978 let fields = inner
979 .map(RecordField::parse)
980 .collect::<Result<Vec<_>, _>>()?;
981
982 Ok(Self {
983 name: identifier,
984 fields,
985 span,
986 })
987 }
988
989 fn unit_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
990 let span = pair.as_span().into();
991 let mut inner = pair.into_inner();
992
993 let identifier = inner.next().unwrap().as_str().to_string();
994
995 Ok(Self {
996 name: identifier,
997 fields: vec![],
998 span,
999 })
1000 }
1001}
1002
1003impl AstNode for VariantCase {
1004 const RULE: Rule = Rule::variant_case;
1005
1006 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1007 let case = match pair.as_rule() {
1008 Rule::variant_case_struct => Self::struct_case_parse(pair),
1009 Rule::variant_case_tuple => todo!("parse variant case tuple"),
1010 Rule::variant_case_unit => Self::unit_case_parse(pair),
1011 x => unreachable!("Unexpected rule in datum_variant: {:?}", x),
1012 }?;
1013
1014 Ok(case)
1015 }
1016
1017 fn span(&self) -> &Span {
1018 &self.span
1019 }
1020}
1021
1022impl AstNode for AssetDef {
1023 const RULE: Rule = Rule::asset_def;
1024
1025 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1026 let span = pair.as_span().into();
1027 let mut inner = pair.into_inner();
1028
1029 let identifier = inner.next().unwrap().as_str().to_string();
1030 let policy = HexStringLiteral::parse(inner.next().unwrap())?;
1031 let asset_name = inner.next().unwrap().as_str().to_string();
1032
1033 Ok(AssetDef {
1034 name: identifier,
1035 policy,
1036 asset_name,
1037 span,
1038 })
1039 }
1040
1041 fn span(&self) -> &Span {
1042 &self.span
1043 }
1044}
1045
1046impl AstNode for ChainSpecificBlock {
1047 const RULE: Rule = Rule::chain_specific_block;
1048
1049 fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1050 let mut inner = pair.into_inner();
1051
1052 let block = inner.next().unwrap();
1053
1054 match block.as_rule() {
1055 Rule::cardano_block => {
1056 let block = crate::cardano::CardanoBlock::parse(block)?;
1057 Ok(ChainSpecificBlock::Cardano(block))
1058 }
1059 x => unreachable!("Unexpected rule in chain_specific_block: {:?}", x),
1060 }
1061 }
1062
1063 fn span(&self) -> &Span {
1064 match self {
1065 Self::Cardano(x) => x.span(),
1066 }
1067 }
1068}
1069
1070pub fn parse_string(input: &str) -> Result<Program, Error> {
1093 let pairs = Tx3Grammar::parse(Rule::program, input)?;
1094 Program::parse(pairs.into_iter().next().unwrap())
1095}
1096
1097#[cfg(test)]
1098pub fn parse_well_known_example(example: &str) -> Program {
1099 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1100 let test_file = format!("{}/../../examples/{}.tx3", manifest_dir, example);
1101 let input = std::fs::read_to_string(&test_file).unwrap();
1102 parse_string(&input).unwrap()
1103}
1104
1105#[cfg(test)]
1106mod tests {
1107 use super::*;
1108 use assert_json_diff::assert_json_eq;
1109 use paste::paste;
1110 use pest::Parser;
1111
1112 #[test]
1113 fn smoke_test_parse_string() {
1114 let _ = parse_string("tx swap() {}").unwrap();
1115 }
1116
1117 macro_rules! input_to_ast_check {
1118 ($ast:ty, $name:expr, $input:expr, $expected:expr) => {
1119 paste::paste! {
1120 #[test]
1121 fn [<test_parse_ $ast:snake _ $name>]() {
1122 let pairs = super::Tx3Grammar::parse(<$ast>::RULE, $input).unwrap();
1123 let single_match = pairs.into_iter().next().unwrap();
1124 let result = <$ast>::parse(single_match).unwrap();
1125
1126 assert_eq!(result, $expected);
1127 }
1128 }
1129 };
1130 }
1131
1132 input_to_ast_check!(BinaryOperator, "plus", "+", BinaryOperator::Add);
1133
1134 input_to_ast_check!(Type, "int", "Int", Type::Int);
1135
1136 input_to_ast_check!(Type, "bool", "Bool", Type::Bool);
1137
1138 input_to_ast_check!(Type, "bytes", "Bytes", Type::Bytes);
1139
1140 input_to_ast_check!(Type, "address", "Address", Type::Address);
1141
1142 input_to_ast_check!(Type, "utxo_ref", "UtxoRef", Type::UtxoRef);
1143
1144 input_to_ast_check!(Type, "any_asset", "AnyAsset", Type::AnyAsset);
1145
1146 input_to_ast_check!(
1147 TypeDef,
1148 "type_def_record",
1149 "type MyRecord {
1150 field1: Int,
1151 field2: Bytes,
1152 }",
1153 TypeDef {
1154 name: "MyRecord".to_string(),
1155 cases: vec![VariantCase {
1156 name: "Default".to_string(),
1157 fields: vec![
1158 RecordField::new("field1", Type::Int),
1159 RecordField::new("field2", Type::Bytes)
1160 ],
1161 span: Span::DUMMY,
1162 }],
1163 span: Span::DUMMY,
1164 }
1165 );
1166
1167 input_to_ast_check!(
1168 TypeDef,
1169 "type_def_variant",
1170 "type MyVariant {
1171 Case1 {
1172 field1: Int,
1173 field2: Bytes,
1174 },
1175 Case2,
1176 }",
1177 TypeDef {
1178 name: "MyVariant".to_string(),
1179 cases: vec![
1180 VariantCase {
1181 name: "Case1".to_string(),
1182 fields: vec![
1183 RecordField::new("field1", Type::Int),
1184 RecordField::new("field2", Type::Bytes)
1185 ],
1186 span: Span::DUMMY,
1187 },
1188 VariantCase {
1189 name: "Case2".to_string(),
1190 fields: vec![],
1191 span: Span::DUMMY,
1192 },
1193 ],
1194 span: Span::DUMMY,
1195 }
1196 );
1197
1198 input_to_ast_check!(
1199 StringLiteral,
1200 "literal_string",
1201 "\"Hello, world!\"",
1202 StringLiteral::new("Hello, world!".to_string())
1203 );
1204
1205 input_to_ast_check!(
1206 HexStringLiteral,
1207 "hex_string",
1208 "0xAFAFAF",
1209 HexStringLiteral::new("AFAFAF".to_string())
1210 );
1211
1212 input_to_ast_check!(
1213 StringLiteral,
1214 "literal_string_address",
1215 "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1216 StringLiteral::new("addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string())
1217 );
1218
1219 input_to_ast_check!(
1220 DataExpr,
1221 "identifier",
1222 "my_party",
1223 DataExpr::Identifier(Identifier::new("my_party".to_string()))
1224 );
1225
1226 input_to_ast_check!(DataExpr, "literal_bool_true", "true", DataExpr::Bool(true));
1227
1228 input_to_ast_check!(
1229 DataExpr,
1230 "literal_bool_false",
1231 "false",
1232 DataExpr::Bool(false)
1233 );
1234
1235 input_to_ast_check!(DataExpr, "unit_value", "())", DataExpr::Unit);
1236
1237 input_to_ast_check!(
1238 PropertyAccess,
1239 "single_property",
1240 "subject.property",
1241 PropertyAccess::new("subject", &["property"])
1242 );
1243
1244 input_to_ast_check!(
1245 PropertyAccess,
1246 "multiple_properties",
1247 "subject.property.subproperty",
1248 PropertyAccess::new("subject", &["property", "subproperty"])
1249 );
1250
1251 input_to_ast_check!(
1252 PolicyDef,
1253 "policy_def_assign",
1254 "policy MyPolicy = 0xAFAFAF;",
1255 PolicyDef {
1256 name: "MyPolicy".to_string(),
1257 value: PolicyValue::Assign(HexStringLiteral::new("AFAFAF".to_string())),
1258 span: Span::DUMMY,
1259 }
1260 );
1261
1262 input_to_ast_check!(
1263 PolicyDef,
1264 "policy_def_constructor",
1265 "policy MyPolicy {
1266 hash: 0x1234567890,
1267 script: 0x1234567890,
1268 ref: 0x1234567890,
1269 };",
1270 PolicyDef {
1271 name: "MyPolicy".to_string(),
1272 value: PolicyValue::Constructor(PolicyConstructor {
1273 fields: vec![
1274 PolicyField::Hash(DataExpr::HexString(HexStringLiteral::new(
1275 "1234567890".to_string()
1276 ))),
1277 PolicyField::Script(DataExpr::HexString(HexStringLiteral::new(
1278 "1234567890".to_string()
1279 ))),
1280 PolicyField::Ref(DataExpr::HexString(HexStringLiteral::new(
1281 "1234567890".to_string()
1282 ))),
1283 ],
1284 span: Span::DUMMY,
1285 }),
1286 span: Span::DUMMY,
1287 }
1288 );
1289
1290 input_to_ast_check!(
1291 AssetDef,
1292 "hex_hex",
1293 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.0xef7a1ceb;",
1294 AssetDef {
1295 name: "MyToken".to_string(),
1296 policy: HexStringLiteral::new(
1297 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1298 ),
1299 asset_name: "0xef7a1ceb".to_string(),
1300 span: Span::DUMMY,
1301 }
1302 );
1303
1304 input_to_ast_check!(
1305 AssetDef,
1306 "hex_ascii",
1307 "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.MYTOKEN;",
1308 AssetDef {
1309 name: "MyToken".to_string(),
1310 policy: HexStringLiteral::new(
1311 "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1312 ),
1313 asset_name: "MYTOKEN".to_string(),
1314 span: Span::DUMMY,
1315 }
1316 );
1317
1318 input_to_ast_check!(
1319 AssetConstructor,
1320 "type_and_literal",
1321 "MyToken(15)",
1322 AssetConstructor {
1323 r#type: Identifier::new("MyToken"),
1324 amount: Box::new(DataExpr::Number(15)),
1325 span: Span::DUMMY,
1326 }
1327 );
1328
1329 input_to_ast_check!(
1330 DataExpr,
1331 "addition",
1332 "5 + var1",
1333 DataExpr::BinaryOp(DataBinaryOp {
1334 operator: BinaryOperator::Add,
1335 left: Box::new(DataExpr::Number(5)),
1336 right: Box::new(DataExpr::Identifier(Identifier::new("var1"))),
1337 span: Span::DUMMY,
1338 })
1339 );
1340
1341 input_to_ast_check!(
1342 AddressExpr,
1343 "address_string",
1344 "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1345 AddressExpr::String(StringLiteral::new(
1346 "addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string()
1347 ))
1348 );
1349
1350 input_to_ast_check!(
1351 AddressExpr,
1352 "address_hex_string",
1353 "0x1234567890abcdef",
1354 AddressExpr::HexString(HexStringLiteral::new("1234567890abcdef".to_string()))
1355 );
1356
1357 input_to_ast_check!(
1358 AddressExpr,
1359 "address_identifier",
1360 "my_address",
1361 AddressExpr::Identifier(Identifier::new("my_address"))
1362 );
1363
1364 input_to_ast_check!(
1365 DatumConstructor,
1366 "datum_constructor_record",
1367 "MyRecord {
1368 field1: 10,
1369 field2: abc,
1370 }",
1371 DatumConstructor {
1372 r#type: Identifier::new("MyRecord"),
1373 case: VariantCaseConstructor {
1374 name: Identifier::new("Default"),
1375 fields: vec![
1376 RecordConstructorField {
1377 name: Identifier::new("field1"),
1378 value: Box::new(DataExpr::Number(10)),
1379 span: Span::DUMMY,
1380 },
1381 RecordConstructorField {
1382 name: Identifier::new("field2"),
1383 value: Box::new(DataExpr::Identifier(Identifier::new("abc"))),
1384 span: Span::DUMMY,
1385 },
1386 ],
1387 spread: None,
1388 scope: None,
1389 span: Span::DUMMY,
1390 },
1391 scope: None,
1392 span: Span::DUMMY,
1393 }
1394 );
1395
1396 input_to_ast_check!(
1397 DatumConstructor,
1398 "datum_constructor_variant",
1399 "ShipCommand::MoveShip {
1400 delta_x: delta_x,
1401 delta_y: delta_y,
1402 }",
1403 DatumConstructor {
1404 r#type: Identifier::new("ShipCommand"),
1405 case: VariantCaseConstructor {
1406 name: Identifier::new("MoveShip"),
1407 fields: vec![
1408 RecordConstructorField {
1409 name: Identifier::new("delta_x"),
1410 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1411 span: Span::DUMMY,
1412 },
1413 RecordConstructorField {
1414 name: Identifier::new("delta_y"),
1415 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1416 span: Span::DUMMY,
1417 },
1418 ],
1419 spread: None,
1420 scope: None,
1421 span: Span::DUMMY,
1422 },
1423 scope: None,
1424 span: Span::DUMMY,
1425 }
1426 );
1427
1428 input_to_ast_check!(
1429 DatumConstructor,
1430 "datum_constructor_variant_with_spread",
1431 "ShipCommand::MoveShip {
1432 delta_x: delta_x,
1433 delta_y: delta_y,
1434 ...abc
1435 }",
1436 DatumConstructor {
1437 r#type: Identifier::new("ShipCommand"),
1438 case: VariantCaseConstructor {
1439 name: Identifier::new("MoveShip"),
1440 fields: vec![
1441 RecordConstructorField {
1442 name: Identifier::new("delta_x"),
1443 value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1444 span: Span::DUMMY,
1445 },
1446 RecordConstructorField {
1447 name: Identifier::new("delta_y"),
1448 value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1449 span: Span::DUMMY,
1450 },
1451 ],
1452 spread: Some(Box::new(DataExpr::Identifier(Identifier::new(
1453 "abc".to_string()
1454 )))),
1455 scope: None,
1456 span: Span::DUMMY,
1457 },
1458 scope: None,
1459 span: Span::DUMMY,
1460 }
1461 );
1462
1463 input_to_ast_check!(
1464 OutputBlock,
1465 "output_block_anonymous",
1466 r#"output {
1467 to: my_party,
1468 amount: Ada(100),
1469 }"#,
1470 OutputBlock {
1471 name: None,
1472 fields: vec![
1473 OutputBlockField::To(Box::new(AddressExpr::Identifier(Identifier::new(
1474 "my_party".to_string(),
1475 )))),
1476 OutputBlockField::Amount(Box::new(AssetExpr::Constructor(AssetConstructor {
1477 r#type: Identifier::new("Ada"),
1478 amount: Box::new(DataExpr::Number(100)),
1479 span: Span::DUMMY,
1480 }))),
1481 ],
1482 span: Span::DUMMY,
1483 }
1484 );
1485
1486 input_to_ast_check!(
1487 ChainSpecificBlock,
1488 "chain_specific_block_cardano",
1489 "cardano::vote_delegation_certificate {
1490 drep: 0x1234567890,
1491 stake: 0x1234567890,
1492 }",
1493 ChainSpecificBlock::Cardano(crate::cardano::CardanoBlock::VoteDelegationCertificate(
1494 crate::cardano::VoteDelegationCertificate {
1495 drep: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
1496 stake: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
1497 span: Span::DUMMY,
1498 },
1499 ))
1500 );
1501
1502 #[test]
1503 fn test_spans_are_respected() {
1504 let program = parse_well_known_example("lang_tour");
1505 assert_eq!(program.span, Span::new(0, 738));
1506
1507 assert_eq!(program.parties[0].span, Span::new(0, 14));
1508
1509 assert_eq!(program.types[0].span, Span::new(16, 69));
1510 }
1511
1512 fn make_snapshot_if_missing(example: &str, program: &Program) {
1513 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1514 let path = format!("{}/../../examples/{}.ast", manifest_dir, example);
1515
1516 if !std::fs::exists(&path).unwrap() {
1517 let ast = serde_json::to_string_pretty(program).unwrap();
1518 std::fs::write(&path, ast).unwrap();
1519 }
1520 }
1521
1522 fn test_parsing_example(example: &str) {
1523 let program = parse_well_known_example(example);
1524
1525 make_snapshot_if_missing(example, &program);
1526
1527 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1528 let ast_file = format!("{}/../../examples/{}.ast", manifest_dir, example);
1529 let ast = std::fs::read_to_string(ast_file).unwrap();
1530
1531 let expected: Program = serde_json::from_str(&ast).unwrap();
1532
1533 assert_json_eq!(program, expected);
1534 }
1535
1536 #[macro_export]
1537 macro_rules! test_parsing {
1538 ($name:ident) => {
1539 paste! {
1540 #[test]
1541 fn [<test_example_ $name>]() {
1542 test_parsing_example(stringify!($name));
1543 }
1544 }
1545 };
1546 }
1547
1548 test_parsing!(lang_tour);
1549
1550 test_parsing!(transfer);
1551
1552 test_parsing!(swap);
1553
1554 test_parsing!(asteria);
1555
1556 test_parsing!(vesting);
1557
1558 test_parsing!(faucet);
1559}