tx3_lang/
parsing.rs

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