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