tx3_lang/
parsing.rs

1//! Parses the Tx3 language.
2//!
3//! This module takes a string and parses it into Tx3 AST.
4
5use 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 DatumConstructor {
840    const RULE: Rule = Rule::datum_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(DatumConstructor {
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 DataExpr {
939    fn number_parse(pair: Pair<Rule>) -> Result<Self, Error> {
940        Ok(DataExpr::Number(pair.as_str().parse().unwrap()))
941    }
942
943    fn bool_parse(pair: Pair<Rule>) -> Result<Self, Error> {
944        Ok(DataExpr::Bool(pair.as_str().parse().unwrap()))
945    }
946
947    fn identifier_parse(pair: Pair<Rule>) -> Result<Self, Error> {
948        Ok(DataExpr::Identifier(Identifier::parse(pair)?))
949    }
950
951    fn property_access_parse(pair: Pair<Rule>) -> Result<Self, Error> {
952        Ok(DataExpr::PropertyAccess(PropertyAccess::parse(pair)?))
953    }
954
955    fn constructor_parse(pair: Pair<Rule>) -> Result<Self, Error> {
956        Ok(DataExpr::Constructor(DatumConstructor::parse(pair)?))
957    }
958
959    fn utxo_ref_parse(pair: Pair<Rule>) -> Result<Self, Error> {
960        Ok(DataExpr::UtxoRef(UtxoRef::parse(pair)?))
961    }
962
963    fn term_parse(pair: Pair<Rule>) -> Result<Self, Error> {
964        match pair.as_rule() {
965            Rule::number => DataExpr::number_parse(pair),
966            Rule::string => Ok(DataExpr::String(StringLiteral::parse(pair)?)),
967            Rule::bool => DataExpr::bool_parse(pair),
968            Rule::hex_string => Ok(DataExpr::HexString(HexStringLiteral::parse(pair)?)),
969            Rule::datum_constructor => DataExpr::constructor_parse(pair),
970            Rule::unit => Ok(DataExpr::Unit),
971            Rule::identifier => DataExpr::identifier_parse(pair),
972            Rule::property_access => DataExpr::property_access_parse(pair),
973            Rule::utxo_ref => DataExpr::utxo_ref_parse(pair),
974            x => unreachable!("Unexpected rule in data_expr: {:?}", x),
975        }
976    }
977}
978
979impl AstNode for DataExpr {
980    const RULE: Rule = Rule::data_expr;
981
982    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
983        let mut inner = pair.into_inner();
984
985        let mut final_expr = Self::term_parse(inner.next().unwrap())?;
986
987        while let Some(term) = inner.next() {
988            let span = term.as_span().into();
989            let operator = BinaryOperator::parse(term)?;
990            let next_expr = Self::term_parse(inner.next().unwrap())?;
991
992            final_expr = DataExpr::BinaryOp(DataBinaryOp {
993                operator,
994                left: Box::new(final_expr),
995                right: Box::new(next_expr),
996                span,
997            });
998        }
999
1000        Ok(final_expr)
1001    }
1002
1003    fn span(&self) -> &Span {
1004        match self {
1005            DataExpr::None => &Span::DUMMY,      // TODO
1006            DataExpr::Unit => &Span::DUMMY,      // TODO
1007            DataExpr::Number(_) => &Span::DUMMY, // TODO
1008            DataExpr::Bool(_) => &Span::DUMMY,   // TODO
1009            DataExpr::String(x) => x.span(),
1010            DataExpr::HexString(x) => x.span(),
1011            DataExpr::Constructor(x) => x.span(),
1012            DataExpr::Identifier(x) => x.span(),
1013            DataExpr::PropertyAccess(x) => x.span(),
1014            DataExpr::BinaryOp(x) => &x.span,
1015            DataExpr::UtxoRef(x) => &x.span(),
1016        }
1017    }
1018}
1019
1020impl AstNode for BinaryOperator {
1021    const RULE: Rule = Rule::binary_operator;
1022
1023    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1024        match pair.as_str() {
1025            "+" => Ok(BinaryOperator::Add),
1026            "-" => Ok(BinaryOperator::Subtract),
1027            x => unreachable!("Unexpected string in binary_operator: {:?}", x),
1028        }
1029    }
1030
1031    fn span(&self) -> &Span {
1032        &Span::DUMMY // TODO
1033    }
1034}
1035
1036impl AstNode for Type {
1037    const RULE: Rule = Rule::r#type;
1038
1039    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1040        match pair.as_str() {
1041            "Int" => Ok(Type::Int),
1042            "Bool" => Ok(Type::Bool),
1043            "Bytes" => Ok(Type::Bytes),
1044            "Address" => Ok(Type::Address),
1045            "UtxoRef" => Ok(Type::UtxoRef),
1046            "AnyAsset" => Ok(Type::AnyAsset),
1047            t => Ok(Type::Custom(Identifier::new(t.to_string()))),
1048        }
1049    }
1050
1051    fn span(&self) -> &Span {
1052        &Span::DUMMY // TODO
1053    }
1054}
1055
1056impl TypeDef {
1057    fn parse_variant_format(pair: Pair<Rule>) -> Result<Self, Error> {
1058        let span = pair.as_span().into();
1059        let mut inner = pair.into_inner();
1060
1061        let identifier = inner.next().unwrap().as_str().to_string();
1062
1063        let cases = inner
1064            .map(VariantCase::parse)
1065            .collect::<Result<Vec<_>, _>>()?;
1066
1067        Ok(TypeDef {
1068            name: identifier,
1069            cases,
1070            span,
1071        })
1072    }
1073
1074    fn parse_record_format(pair: Pair<Rule>) -> Result<Self, Error> {
1075        let span: Span = pair.as_span().into();
1076        let mut inner = pair.into_inner();
1077
1078        let identifier = inner.next().unwrap().as_str().to_string();
1079
1080        let fields = inner
1081            .map(RecordField::parse)
1082            .collect::<Result<Vec<_>, _>>()?;
1083
1084        Ok(TypeDef {
1085            name: identifier.clone(),
1086            cases: vec![VariantCase {
1087                name: "Default".to_string(),
1088                fields,
1089                span: span.clone(),
1090            }],
1091            span,
1092        })
1093    }
1094}
1095
1096impl AstNode for TypeDef {
1097    const RULE: Rule = Rule::type_def;
1098
1099    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1100        match pair.as_rule() {
1101            Rule::variant_def => Ok(Self::parse_variant_format(pair)?),
1102            Rule::record_def => Ok(Self::parse_record_format(pair)?),
1103            x => unreachable!("Unexpected rule in type_def: {:?}", x),
1104        }
1105    }
1106
1107    fn span(&self) -> &Span {
1108        &self.span
1109    }
1110}
1111
1112impl VariantCase {
1113    fn struct_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1114        let span = pair.as_span().into();
1115        let mut inner = pair.into_inner();
1116
1117        let identifier = inner.next().unwrap().as_str().to_string();
1118
1119        let fields = inner
1120            .map(RecordField::parse)
1121            .collect::<Result<Vec<_>, _>>()?;
1122
1123        Ok(Self {
1124            name: identifier,
1125            fields,
1126            span,
1127        })
1128    }
1129
1130    fn unit_case_parse(pair: pest::iterators::Pair<Rule>) -> Result<Self, Error> {
1131        let span = pair.as_span().into();
1132        let mut inner = pair.into_inner();
1133
1134        let identifier = inner.next().unwrap().as_str().to_string();
1135
1136        Ok(Self {
1137            name: identifier,
1138            fields: vec![],
1139            span,
1140        })
1141    }
1142}
1143
1144impl AstNode for VariantCase {
1145    const RULE: Rule = Rule::variant_case;
1146
1147    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1148        let case = match pair.as_rule() {
1149            Rule::variant_case_struct => Self::struct_case_parse(pair),
1150            Rule::variant_case_tuple => todo!("parse variant case tuple"),
1151            Rule::variant_case_unit => Self::unit_case_parse(pair),
1152            x => unreachable!("Unexpected rule in datum_variant: {:?}", x),
1153        }?;
1154
1155        Ok(case)
1156    }
1157
1158    fn span(&self) -> &Span {
1159        &self.span
1160    }
1161}
1162
1163impl AstNode for AssetDef {
1164    const RULE: Rule = Rule::asset_def;
1165
1166    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1167        let span = pair.as_span().into();
1168        let mut inner = pair.into_inner();
1169
1170        let identifier = inner.next().unwrap().as_str().to_string();
1171        let policy = HexStringLiteral::parse(inner.next().unwrap())?;
1172        let asset_name = inner.next().unwrap().as_str().to_string();
1173
1174        Ok(AssetDef {
1175            name: identifier,
1176            policy: Some(policy),
1177            asset_name: Some(asset_name),
1178            span,
1179        })
1180    }
1181
1182    fn span(&self) -> &Span {
1183        &self.span
1184    }
1185}
1186
1187impl AstNode for ChainSpecificBlock {
1188    const RULE: Rule = Rule::chain_specific_block;
1189
1190    fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
1191        let mut inner = pair.into_inner();
1192
1193        let block = inner.next().unwrap();
1194
1195        match block.as_rule() {
1196            Rule::cardano_block => {
1197                let block = crate::cardano::CardanoBlock::parse(block)?;
1198                Ok(ChainSpecificBlock::Cardano(block))
1199            }
1200            x => unreachable!("Unexpected rule in chain_specific_block: {:?}", x),
1201        }
1202    }
1203
1204    fn span(&self) -> &Span {
1205        match self {
1206            Self::Cardano(x) => x.span(),
1207        }
1208    }
1209}
1210
1211/// Parses a Tx3 source string into a Program AST.
1212///
1213/// # Arguments
1214///
1215/// * `input` - String containing Tx3 source code
1216///
1217/// # Returns
1218///
1219/// * `Result<Program, Error>` - The parsed Program AST or an error
1220///
1221/// # Errors
1222///
1223/// Returns an error if:
1224/// - The input string is not valid Tx3 syntax
1225/// - The AST construction fails
1226///
1227/// # Example
1228///
1229/// ```
1230/// use tx3_lang::parsing::parse_string;
1231/// let program = parse_string("tx swap() {}").unwrap();
1232/// ```
1233pub fn parse_string(input: &str) -> Result<Program, Error> {
1234    let pairs = Tx3Grammar::parse(Rule::program, input)?;
1235    Program::parse(pairs.into_iter().next().unwrap())
1236}
1237
1238#[cfg(test)]
1239pub fn parse_well_known_example(example: &str) -> Program {
1240    let manifest_dir = env!("CARGO_MANIFEST_DIR");
1241    let test_file = format!("{}/../../examples/{}.tx3", manifest_dir, example);
1242    let input = std::fs::read_to_string(&test_file).unwrap();
1243    parse_string(&input).unwrap()
1244}
1245
1246#[cfg(test)]
1247mod tests {
1248    use super::*;
1249    use assert_json_diff::assert_json_eq;
1250    use paste::paste;
1251    use pest::Parser;
1252
1253    #[test]
1254    fn smoke_test_parse_string() {
1255        let _ = parse_string("tx swap() {}").unwrap();
1256    }
1257
1258    macro_rules! input_to_ast_check {
1259        ($ast:ty, $name:expr, $input:expr, $expected:expr) => {
1260            paste::paste! {
1261                #[test]
1262                fn [<test_parse_ $ast:snake _ $name>]() {
1263                    let pairs = super::Tx3Grammar::parse(<$ast>::RULE, $input).unwrap();
1264                    let single_match = pairs.into_iter().next().unwrap();
1265                    let result = <$ast>::parse(single_match).unwrap();
1266
1267                    assert_eq!(result, $expected);
1268                }
1269            }
1270        };
1271    }
1272
1273    input_to_ast_check!(BinaryOperator, "plus", "+", BinaryOperator::Add);
1274
1275    input_to_ast_check!(Type, "int", "Int", Type::Int);
1276
1277    input_to_ast_check!(Type, "bool", "Bool", Type::Bool);
1278
1279    input_to_ast_check!(Type, "bytes", "Bytes", Type::Bytes);
1280
1281    input_to_ast_check!(Type, "address", "Address", Type::Address);
1282
1283    input_to_ast_check!(Type, "utxo_ref", "UtxoRef", Type::UtxoRef);
1284
1285    input_to_ast_check!(Type, "any_asset", "AnyAsset", Type::AnyAsset);
1286
1287    input_to_ast_check!(
1288        TypeDef,
1289        "type_def_record",
1290        "type MyRecord {
1291            field1: Int,
1292            field2: Bytes,
1293        }",
1294        TypeDef {
1295            name: "MyRecord".to_string(),
1296            cases: vec![VariantCase {
1297                name: "Default".to_string(),
1298                fields: vec![
1299                    RecordField::new("field1", Type::Int),
1300                    RecordField::new("field2", Type::Bytes)
1301                ],
1302                span: Span::DUMMY,
1303            }],
1304            span: Span::DUMMY,
1305        }
1306    );
1307
1308    input_to_ast_check!(
1309        TypeDef,
1310        "type_def_variant",
1311        "type MyVariant {
1312            Case1 {
1313                field1: Int,
1314                field2: Bytes,
1315            },
1316            Case2,
1317        }",
1318        TypeDef {
1319            name: "MyVariant".to_string(),
1320            cases: vec![
1321                VariantCase {
1322                    name: "Case1".to_string(),
1323                    fields: vec![
1324                        RecordField::new("field1", Type::Int),
1325                        RecordField::new("field2", Type::Bytes)
1326                    ],
1327                    span: Span::DUMMY,
1328                },
1329                VariantCase {
1330                    name: "Case2".to_string(),
1331                    fields: vec![],
1332                    span: Span::DUMMY,
1333                },
1334            ],
1335            span: Span::DUMMY,
1336        }
1337    );
1338
1339    input_to_ast_check!(
1340        StringLiteral,
1341        "literal_string",
1342        "\"Hello, world!\"",
1343        StringLiteral::new("Hello, world!".to_string())
1344    );
1345
1346    input_to_ast_check!(
1347        HexStringLiteral,
1348        "hex_string",
1349        "0xAFAFAF",
1350        HexStringLiteral::new("AFAFAF".to_string())
1351    );
1352
1353    input_to_ast_check!(
1354        StringLiteral,
1355        "literal_string_address",
1356        "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1357        StringLiteral::new("addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string())
1358    );
1359
1360    input_to_ast_check!(
1361        DataExpr,
1362        "identifier",
1363        "my_party",
1364        DataExpr::Identifier(Identifier::new("my_party".to_string()))
1365    );
1366
1367    input_to_ast_check!(DataExpr, "literal_bool_true", "true", DataExpr::Bool(true));
1368
1369    input_to_ast_check!(
1370        DataExpr,
1371        "literal_bool_false",
1372        "false",
1373        DataExpr::Bool(false)
1374    );
1375
1376    input_to_ast_check!(DataExpr, "unit_value", "())", DataExpr::Unit);
1377
1378    input_to_ast_check!(
1379        PropertyAccess,
1380        "single_property",
1381        "subject.property",
1382        PropertyAccess::new("subject", &["property"])
1383    );
1384
1385    input_to_ast_check!(
1386        PropertyAccess,
1387        "multiple_properties",
1388        "subject.property.subproperty",
1389        PropertyAccess::new("subject", &["property", "subproperty"])
1390    );
1391
1392    input_to_ast_check!(
1393        PolicyDef,
1394        "policy_def_assign",
1395        "policy MyPolicy = 0xAFAFAF;",
1396        PolicyDef {
1397            name: "MyPolicy".to_string(),
1398            value: PolicyValue::Assign(HexStringLiteral::new("AFAFAF".to_string())),
1399            span: Span::DUMMY,
1400        }
1401    );
1402
1403    input_to_ast_check!(
1404        PolicyDef,
1405        "policy_def_constructor",
1406        "policy MyPolicy {
1407            hash: 0x1234567890,
1408            script: 0x1234567890,
1409            ref: 0x1234567890,
1410        };",
1411        PolicyDef {
1412            name: "MyPolicy".to_string(),
1413            value: PolicyValue::Constructor(PolicyConstructor {
1414                fields: vec![
1415                    PolicyField::Hash(DataExpr::HexString(HexStringLiteral::new(
1416                        "1234567890".to_string()
1417                    ))),
1418                    PolicyField::Script(DataExpr::HexString(HexStringLiteral::new(
1419                        "1234567890".to_string()
1420                    ))),
1421                    PolicyField::Ref(DataExpr::HexString(HexStringLiteral::new(
1422                        "1234567890".to_string()
1423                    ))),
1424                ],
1425                span: Span::DUMMY,
1426            }),
1427            span: Span::DUMMY,
1428        }
1429    );
1430
1431    input_to_ast_check!(
1432        AssetDef,
1433        "hex_hex",
1434        "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.0xef7a1ceb;",
1435        AssetDef {
1436            name: "MyToken".to_string(),
1437            policy: Some(HexStringLiteral::new(
1438                "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1439            )),
1440            asset_name: Some("0xef7a1ceb".to_string()),
1441            span: Span::DUMMY,
1442        }
1443    );
1444
1445    input_to_ast_check!(
1446        AssetDef,
1447        "hex_ascii",
1448        "asset MyToken = 0xef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe.MYTOKEN;",
1449        AssetDef {
1450            name: "MyToken".to_string(),
1451            policy: Some(HexStringLiteral::new(
1452                "ef7a1cebb2dc7de884ddf82f8fcbc91fe9750dcd8c12ec7643a99bbe".to_string()
1453            )),
1454            asset_name: Some("MYTOKEN".to_string()),
1455            span: Span::DUMMY,
1456        }
1457    );
1458
1459    input_to_ast_check!(
1460        StaticAssetConstructor,
1461        "type_and_literal",
1462        "MyToken(15)",
1463        StaticAssetConstructor {
1464            r#type: Identifier::new("MyToken"),
1465            amount: Box::new(DataExpr::Number(15)),
1466            span: Span::DUMMY,
1467        }
1468    );
1469
1470    input_to_ast_check!(
1471        AnyAssetConstructor,
1472        "any_asset_constructor",
1473        "AnyAsset(0x1234567890, \"MyToken\", 15)",
1474        AnyAssetConstructor {
1475            policy: Box::new(DataExpr::HexString(HexStringLiteral::new(
1476                "1234567890".to_string()
1477            ))),
1478            asset_name: Box::new(DataExpr::String(StringLiteral::new("MyToken".to_string()))),
1479            amount: Box::new(DataExpr::Number(15)),
1480            span: Span::DUMMY,
1481        }
1482    );
1483
1484    input_to_ast_check!(
1485        AnyAssetConstructor,
1486        "any_asset_identifiers",
1487        "AnyAsset(my_policy, my_token, my_amount)",
1488        AnyAssetConstructor {
1489            policy: Box::new(DataExpr::Identifier(Identifier::new("my_policy"))),
1490            asset_name: Box::new(DataExpr::Identifier(Identifier::new("my_token"))),
1491            amount: Box::new(DataExpr::Identifier(Identifier::new("my_amount"))),
1492            span: Span::DUMMY,
1493        }
1494    );
1495
1496    input_to_ast_check!(
1497        AnyAssetConstructor,
1498        "any_asset_property_access",
1499        "AnyAsset(input1.policy, input1.asset_name, input1.amount)",
1500        AnyAssetConstructor {
1501            policy: Box::new(DataExpr::PropertyAccess(PropertyAccess::new(
1502                "input1",
1503                &["policy"],
1504            ))),
1505            asset_name: Box::new(DataExpr::PropertyAccess(PropertyAccess::new(
1506                "input1",
1507                &["asset_name"],
1508            ))),
1509            amount: Box::new(DataExpr::PropertyAccess(PropertyAccess::new(
1510                "input1",
1511                &["amount"],
1512            ))),
1513            span: Span::DUMMY,
1514        }
1515    );
1516
1517    input_to_ast_check!(
1518        DataExpr,
1519        "addition",
1520        "5 + var1",
1521        DataExpr::BinaryOp(DataBinaryOp {
1522            operator: BinaryOperator::Add,
1523            left: Box::new(DataExpr::Number(5)),
1524            right: Box::new(DataExpr::Identifier(Identifier::new("var1"))),
1525            span: Span::DUMMY,
1526        })
1527    );
1528
1529    input_to_ast_check!(
1530        AddressExpr,
1531        "address_string",
1532        "\"addr1qx234567890abcdefghijklmnopqrstuvwxyz\"",
1533        AddressExpr::String(StringLiteral::new(
1534            "addr1qx234567890abcdefghijklmnopqrstuvwxyz".to_string()
1535        ))
1536    );
1537
1538    input_to_ast_check!(
1539        AddressExpr,
1540        "address_hex_string",
1541        "0x1234567890abcdef",
1542        AddressExpr::HexString(HexStringLiteral::new("1234567890abcdef".to_string()))
1543    );
1544
1545    input_to_ast_check!(
1546        AddressExpr,
1547        "address_identifier",
1548        "my_address",
1549        AddressExpr::Identifier(Identifier::new("my_address"))
1550    );
1551
1552    input_to_ast_check!(
1553        DatumConstructor,
1554        "datum_constructor_record",
1555        "MyRecord {
1556            field1: 10,
1557            field2: abc,
1558        }",
1559        DatumConstructor {
1560            r#type: Identifier::new("MyRecord"),
1561            case: VariantCaseConstructor {
1562                name: Identifier::new("Default"),
1563                fields: vec![
1564                    RecordConstructorField {
1565                        name: Identifier::new("field1"),
1566                        value: Box::new(DataExpr::Number(10)),
1567                        span: Span::DUMMY,
1568                    },
1569                    RecordConstructorField {
1570                        name: Identifier::new("field2"),
1571                        value: Box::new(DataExpr::Identifier(Identifier::new("abc"))),
1572                        span: Span::DUMMY,
1573                    },
1574                ],
1575                spread: None,
1576                scope: None,
1577                span: Span::DUMMY,
1578            },
1579            scope: None,
1580            span: Span::DUMMY,
1581        }
1582    );
1583
1584    input_to_ast_check!(
1585        DatumConstructor,
1586        "datum_constructor_variant",
1587        "ShipCommand::MoveShip {
1588            delta_x: delta_x,
1589            delta_y: delta_y,
1590        }",
1591        DatumConstructor {
1592            r#type: Identifier::new("ShipCommand"),
1593            case: VariantCaseConstructor {
1594                name: Identifier::new("MoveShip"),
1595                fields: vec![
1596                    RecordConstructorField {
1597                        name: Identifier::new("delta_x"),
1598                        value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1599                        span: Span::DUMMY,
1600                    },
1601                    RecordConstructorField {
1602                        name: Identifier::new("delta_y"),
1603                        value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1604                        span: Span::DUMMY,
1605                    },
1606                ],
1607                spread: None,
1608                scope: None,
1609                span: Span::DUMMY,
1610            },
1611            scope: None,
1612            span: Span::DUMMY,
1613        }
1614    );
1615
1616    input_to_ast_check!(
1617        DatumConstructor,
1618        "datum_constructor_variant_with_spread",
1619        "ShipCommand::MoveShip {
1620            delta_x: delta_x,
1621            delta_y: delta_y,
1622            ...abc
1623        }",
1624        DatumConstructor {
1625            r#type: Identifier::new("ShipCommand"),
1626            case: VariantCaseConstructor {
1627                name: Identifier::new("MoveShip"),
1628                fields: vec![
1629                    RecordConstructorField {
1630                        name: Identifier::new("delta_x"),
1631                        value: Box::new(DataExpr::Identifier(Identifier::new("delta_x"))),
1632                        span: Span::DUMMY,
1633                    },
1634                    RecordConstructorField {
1635                        name: Identifier::new("delta_y"),
1636                        value: Box::new(DataExpr::Identifier(Identifier::new("delta_y"))),
1637                        span: Span::DUMMY,
1638                    },
1639                ],
1640                spread: Some(Box::new(DataExpr::Identifier(Identifier::new(
1641                    "abc".to_string()
1642                )))),
1643                scope: None,
1644                span: Span::DUMMY,
1645            },
1646            scope: None,
1647            span: Span::DUMMY,
1648        }
1649    );
1650
1651    input_to_ast_check!(
1652        OutputBlock,
1653        "output_block_anonymous",
1654        r#"output {
1655            to: my_party,
1656            amount: Ada(100),
1657        }"#,
1658        OutputBlock {
1659            name: None,
1660            fields: vec![
1661                OutputBlockField::To(Box::new(AddressExpr::Identifier(Identifier::new(
1662                    "my_party".to_string(),
1663                )))),
1664                OutputBlockField::Amount(Box::new(AssetExpr::StaticConstructor(
1665                    StaticAssetConstructor {
1666                        r#type: Identifier::new("Ada"),
1667                        amount: Box::new(DataExpr::Number(100)),
1668                        span: Span::DUMMY,
1669                    },
1670                ))),
1671            ],
1672            span: Span::DUMMY,
1673        }
1674    );
1675
1676    input_to_ast_check!(
1677        ChainSpecificBlock,
1678        "chain_specific_block_cardano",
1679        "cardano::vote_delegation_certificate {
1680            drep: 0x1234567890,
1681            stake: 0x1234567890,
1682        }",
1683        ChainSpecificBlock::Cardano(crate::cardano::CardanoBlock::VoteDelegationCertificate(
1684            crate::cardano::VoteDelegationCertificate {
1685                drep: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
1686                stake: DataExpr::HexString(HexStringLiteral::new("1234567890".to_string())),
1687                span: Span::DUMMY,
1688            },
1689        ))
1690    );
1691
1692    #[test]
1693    fn test_spans_are_respected() {
1694        let program = parse_well_known_example("lang_tour");
1695        assert_eq!(program.span, Span::new(0, 904));
1696
1697        assert_eq!(program.parties[0].span, Span::new(0, 14));
1698
1699        assert_eq!(program.types[0].span, Span::new(16, 88));
1700    }
1701
1702    fn make_snapshot_if_missing(example: &str, program: &Program) {
1703        let manifest_dir = env!("CARGO_MANIFEST_DIR");
1704        let path = format!("{}/../../examples/{}.ast", manifest_dir, example);
1705
1706        if !std::fs::exists(&path).unwrap() {
1707            let ast = serde_json::to_string_pretty(program).unwrap();
1708            std::fs::write(&path, ast).unwrap();
1709        }
1710    }
1711
1712    fn test_parsing_example(example: &str) {
1713        let program = parse_well_known_example(example);
1714
1715        make_snapshot_if_missing(example, &program);
1716
1717        let manifest_dir = env!("CARGO_MANIFEST_DIR");
1718        let ast_file = format!("{}/../../examples/{}.ast", manifest_dir, example);
1719        let ast = std::fs::read_to_string(ast_file).unwrap();
1720
1721        let expected: Program = serde_json::from_str(&ast).unwrap();
1722
1723        assert_json_eq!(program, expected);
1724    }
1725
1726    #[macro_export]
1727    macro_rules! test_parsing {
1728        ($name:ident) => {
1729            paste! {
1730                #[test]
1731                fn [<test_example_ $name>]() {
1732                    test_parsing_example(stringify!($name));
1733                }
1734            }
1735        };
1736    }
1737
1738    test_parsing!(lang_tour);
1739
1740    test_parsing!(transfer);
1741
1742    test_parsing!(swap);
1743
1744    test_parsing!(asteria);
1745
1746    test_parsing!(vesting);
1747
1748    test_parsing!(faucet);
1749}