use std::{collections::HashMap, rc::Rc};
use pest::iterators::Pair;
use serde::{Deserialize, Serialize};
use tx3_tir::model::v1beta0 as ir;
use crate::{
analyzing::{Analyzable, AnalyzeReport},
ast::{DataExpr, Identifier, Scope, Span, Type},
lowering::IntoLower,
parsing::{AstNode, Error, Rule},
};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum WithdrawalField {
From(Box<DataExpr>),
Amount(Box<DataExpr>),
Redeemer(Box<DataExpr>),
}
impl WithdrawalField {
fn key(&self) -> &str {
match self {
WithdrawalField::From(_) => "from",
WithdrawalField::Amount(_) => "amount",
WithdrawalField::Redeemer(_) => "redeemer",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WithdrawalBlock {
pub fields: Vec<WithdrawalField>,
pub span: Span,
}
impl WithdrawalBlock {
pub(crate) fn find(&self, key: &str) -> Option<&WithdrawalField> {
self.fields.iter().find(|x| x.key() == key)
}
}
impl AstNode for WithdrawalField {
const RULE: Rule = Rule::cardano_withdrawal_field;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
match pair.as_rule() {
Rule::cardano_withdrawal_from => {
let pair = pair.into_inner().next().unwrap();
Ok(WithdrawalField::From(DataExpr::parse(pair)?.into()))
}
Rule::cardano_withdrawal_amount => {
let pair = pair.into_inner().next().unwrap();
Ok(WithdrawalField::Amount(DataExpr::parse(pair)?.into()))
}
Rule::cardano_withdrawal_redeemer => {
let pair = pair.into_inner().next().unwrap();
Ok(WithdrawalField::Redeemer(DataExpr::parse(pair)?.into()))
}
x => unreachable!("Unexpected rule in cardano_withdrawal_field: {:?}", x),
}
}
fn span(&self) -> &Span {
match self {
Self::From(x) => x.span(),
Self::Amount(x) => x.span(),
Self::Redeemer(x) => x.span(),
}
}
}
impl AstNode for WithdrawalBlock {
const RULE: Rule = Rule::cardano_withdrawal_block;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let inner = pair.into_inner();
let fields = inner
.map(|x| WithdrawalField::parse(x))
.collect::<Result<Vec<_>, _>>()?;
Ok(WithdrawalBlock { fields, span })
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for WithdrawalField {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
match self {
WithdrawalField::From(x) => x.analyze(parent),
WithdrawalField::Amount(x) => {
let amount = x.analyze(parent.clone());
let amount_type = AnalyzeReport::expect_data_expr_type(x, &Type::Int);
amount + amount_type
}
WithdrawalField::Redeemer(x) => x.analyze(parent),
}
}
fn is_resolved(&self) -> bool {
match self {
WithdrawalField::From(x) => x.is_resolved(),
WithdrawalField::Amount(x) => x.is_resolved(),
WithdrawalField::Redeemer(x) => x.is_resolved(),
}
}
}
impl Analyzable for WithdrawalBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
self.fields.analyze(parent)
}
fn is_resolved(&self) -> bool {
self.fields.is_resolved()
}
}
impl IntoLower for WithdrawalField {
type Output = ir::Expression;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
match self {
WithdrawalField::From(x) => x.into_lower(ctx),
WithdrawalField::Amount(x) => x.into_lower(ctx),
WithdrawalField::Redeemer(x) => x.into_lower(ctx),
}
}
}
impl IntoLower for WithdrawalBlock {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
let credential = self
.find("from")
.ok_or_else(|| {
crate::lowering::Error::MissingRequiredField("from".to_string(), "WithdrawalBlock")
})?
.into_lower(ctx)?;
let amount = self
.find("amount")
.ok_or_else(|| {
crate::lowering::Error::MissingRequiredField(
"amount".to_string(),
"WithdrawalBlock",
)
})?
.into_lower(ctx)?;
let redeemer = self
.find("redeemer")
.map(|r| r.into_lower(ctx))
.transpose()?
.unwrap_or(ir::Expression::None);
Ok(ir::AdHocDirective {
name: "withdrawal".to_string(),
data: std::collections::HashMap::from([
("credential".to_string(), credential),
("amount".to_string(), amount),
("redeemer".to_string(), redeemer),
]),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct VoteDelegationCertificate {
pub drep: DataExpr,
pub stake: DataExpr,
pub span: Span,
}
impl AstNode for VoteDelegationCertificate {
const RULE: Rule = Rule::cardano_vote_delegation_certificate;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let mut inner = pair.into_inner();
Ok(VoteDelegationCertificate {
drep: DataExpr::parse(inner.next().unwrap())?,
stake: DataExpr::parse(inner.next().unwrap())?,
span,
})
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for VoteDelegationCertificate {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
let drep = self.drep.analyze(parent.clone());
let stake = self.stake.analyze(parent.clone());
drep + stake
}
fn is_resolved(&self) -> bool {
self.drep.is_resolved() && self.stake.is_resolved()
}
}
impl IntoLower for VoteDelegationCertificate {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
Ok(ir::AdHocDirective {
name: "vote_delegation_certificate".to_string(),
data: HashMap::from([
("drep".to_string(), self.drep.into_lower(ctx)?),
("stake".to_string(), self.stake.into_lower(ctx)?),
]),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct StakeDelegationCertificate {
pub pool: DataExpr,
pub stake: DataExpr,
pub span: Span,
}
impl AstNode for StakeDelegationCertificate {
const RULE: Rule = Rule::cardano_stake_delegation_certificate;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let mut inner = pair.into_inner();
Ok(StakeDelegationCertificate {
pool: DataExpr::parse(inner.next().unwrap())?,
stake: DataExpr::parse(inner.next().unwrap())?,
span,
})
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for StakeDelegationCertificate {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
let pool = self.pool.analyze(parent.clone());
let stake = self.stake.analyze(parent.clone());
pool + stake
}
fn is_resolved(&self) -> bool {
self.pool.is_resolved() && self.stake.is_resolved()
}
}
impl IntoLower for StakeDelegationCertificate {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
_ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
todo!("StakeDelegationCertificate lowering not implemented")
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum PlutusWitnessField {
Version(DataExpr, Span),
Script(DataExpr, Span),
}
impl IntoLower for PlutusWitnessField {
type Output = (String, ir::Expression);
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
match self {
PlutusWitnessField::Version(x, _) => Ok(("version".to_string(), x.into_lower(ctx)?)),
PlutusWitnessField::Script(x, _) => Ok(("script".to_string(), x.into_lower(ctx)?)),
}
}
}
impl AstNode for PlutusWitnessField {
const RULE: Rule = Rule::cardano_plutus_witness_field;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
match pair.as_rule() {
Rule::cardano_plutus_witness_version => {
Ok(PlutusWitnessField::Version(DataExpr::parse(pair)?, span))
}
Rule::cardano_plutus_witness_script => {
Ok(PlutusWitnessField::Script(DataExpr::parse(pair)?, span))
}
x => unreachable!("Unexpected rule in cardano_plutus_witness_field: {:?}", x),
}
}
fn span(&self) -> &Span {
match self {
PlutusWitnessField::Version(_, span) => span,
PlutusWitnessField::Script(_, span) => span,
}
}
}
impl Analyzable for PlutusWitnessField {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
match self {
PlutusWitnessField::Version(x, _) => x.analyze(parent),
PlutusWitnessField::Script(x, _) => x.analyze(parent),
}
}
fn is_resolved(&self) -> bool {
match self {
PlutusWitnessField::Version(x, _) => x.is_resolved(),
PlutusWitnessField::Script(x, _) => x.is_resolved(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PlutusWitnessBlock {
pub fields: Vec<PlutusWitnessField>,
pub span: Span,
}
impl AstNode for PlutusWitnessBlock {
const RULE: Rule = Rule::cardano_plutus_witness_block;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let inner = pair.into_inner();
let fields = inner
.map(|x| PlutusWitnessField::parse(x))
.collect::<Result<Vec<_>, _>>()?;
Ok(PlutusWitnessBlock { fields, span })
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for PlutusWitnessBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
self.fields.analyze(parent)
}
fn is_resolved(&self) -> bool {
self.fields.is_resolved()
}
}
impl IntoLower for PlutusWitnessBlock {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
let data = self
.fields
.iter()
.map(|x| x.into_lower(ctx))
.collect::<Result<_, _>>()?;
Ok(ir::AdHocDirective {
name: "plutus_witness".to_string(),
data,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NativeWitnessField {
Script(DataExpr, Span),
}
impl IntoLower for NativeWitnessField {
type Output = (String, ir::Expression);
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
match self {
NativeWitnessField::Script(x, _) => Ok(("script".to_string(), x.into_lower(ctx)?)),
}
}
}
impl AstNode for NativeWitnessField {
const RULE: Rule = Rule::cardano_native_witness_field;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
match pair.as_rule() {
Rule::cardano_native_witness_script => {
Ok(NativeWitnessField::Script(DataExpr::parse(pair)?, span))
}
x => unreachable!("Unexpected rule in cardano_native_witness_field: {:?}", x),
}
}
fn span(&self) -> &Span {
match self {
NativeWitnessField::Script(_, span) => span,
}
}
}
impl Analyzable for NativeWitnessField {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
match self {
NativeWitnessField::Script(x, _) => x.analyze(parent),
}
}
fn is_resolved(&self) -> bool {
match self {
NativeWitnessField::Script(x, _) => x.is_resolved(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct NativeWitnessBlock {
pub fields: Vec<NativeWitnessField>,
pub span: Span,
}
impl AstNode for NativeWitnessBlock {
const RULE: Rule = Rule::cardano_native_witness_block;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let inner = pair.into_inner();
let fields = inner
.map(|x| NativeWitnessField::parse(x))
.collect::<Result<Vec<_>, _>>()?;
Ok(NativeWitnessBlock { fields, span })
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for NativeWitnessBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
self.fields.analyze(parent)
}
fn is_resolved(&self) -> bool {
self.fields.is_resolved()
}
}
impl IntoLower for NativeWitnessBlock {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
let data = self
.fields
.iter()
.map(|x| x.into_lower(ctx))
.collect::<Result<_, _>>()?;
Ok(ir::AdHocDirective {
name: "native_witness".to_string(),
data,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TreasuryDonationBlock {
pub coin: DataExpr,
pub span: Span,
}
impl AstNode for TreasuryDonationBlock {
const RULE: Rule = Rule::cardano_treasury_donation_block;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let mut inner = pair.into_inner();
let coin = DataExpr::parse(inner.next().unwrap())?;
Ok(TreasuryDonationBlock { coin, span })
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for TreasuryDonationBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
let coin = self.coin.analyze(parent);
let coin_type = AnalyzeReport::expect_data_expr_type(&self.coin, &Type::Int);
coin + coin_type
}
fn is_resolved(&self) -> bool {
self.coin.is_resolved()
}
}
impl IntoLower for TreasuryDonationBlock {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
let coin = self.coin.into_lower(ctx)?;
Ok(ir::AdHocDirective {
name: "treasury_donation".to_string(),
data: std::collections::HashMap::from([("coin".to_string(), coin)]),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum CardanoPublishBlockField {
To(Box<DataExpr>),
Amount(Box<DataExpr>),
Datum(Box<DataExpr>),
Version(Box<DataExpr>),
Script(Box<DataExpr>),
}
impl CardanoPublishBlockField {
fn key(&self) -> &str {
match self {
CardanoPublishBlockField::To(_) => "to",
CardanoPublishBlockField::Amount(_) => "amount",
CardanoPublishBlockField::Datum(_) => "datum",
CardanoPublishBlockField::Version(_) => "version",
CardanoPublishBlockField::Script(_) => "script",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct CardanoPublishBlock {
pub name: Option<Identifier>,
pub fields: Vec<CardanoPublishBlockField>,
pub span: Span,
}
impl CardanoPublishBlock {
pub(crate) fn find(&self, key: &str) -> Option<&CardanoPublishBlockField> {
self.fields.iter().find(|x| x.key() == key)
}
}
impl AstNode for CardanoPublishBlockField {
const RULE: Rule = Rule::cardano_publish_block_field;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
match pair.as_rule() {
Rule::cardano_publish_block_to => {
let pair = pair.into_inner().next().unwrap();
Ok(CardanoPublishBlockField::To(DataExpr::parse(pair)?.into()))
}
Rule::cardano_publish_block_amount => {
let pair = pair.into_inner().next().unwrap();
Ok(CardanoPublishBlockField::Amount(
DataExpr::parse(pair)?.into(),
))
}
Rule::cardano_publish_block_datum => {
let pair = pair.into_inner().next().unwrap();
Ok(CardanoPublishBlockField::Datum(
DataExpr::parse(pair)?.into(),
))
}
Rule::cardano_publish_block_version => {
let pair = pair.into_inner().next().unwrap();
Ok(CardanoPublishBlockField::Version(
DataExpr::parse(pair)?.into(),
))
}
Rule::cardano_publish_block_script => {
let pair = pair.into_inner().next().unwrap();
Ok(CardanoPublishBlockField::Script(
DataExpr::parse(pair)?.into(),
))
}
x => unreachable!("Unexpected rule in cardano_publish_block_field: {:?}", x),
}
}
fn span(&self) -> &Span {
match self {
Self::To(x) => x.span(),
Self::Amount(x) => x.span(),
Self::Datum(x) => x.span(),
Self::Version(x) => x.span(),
Self::Script(x) => x.span(),
}
}
}
impl AstNode for CardanoPublishBlock {
const RULE: Rule = Rule::cardano_publish_block;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let span = pair.as_span().into();
let mut inner = pair.into_inner();
let has_name = inner
.peek()
.map(|x| x.as_rule() == Rule::identifier)
.unwrap_or_default();
let name = if has_name {
Some(Identifier::parse(inner.next().unwrap())?)
} else {
None
};
let fields = inner
.map(|x| CardanoPublishBlockField::parse(x))
.collect::<Result<Vec<_>, _>>()?;
Ok(CardanoPublishBlock { name, fields, span })
}
fn span(&self) -> &Span {
&self.span
}
}
impl Analyzable for CardanoPublishBlockField {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
match self {
CardanoPublishBlockField::To(x) => x.analyze(parent),
CardanoPublishBlockField::Amount(x) => x.analyze(parent),
CardanoPublishBlockField::Datum(x) => x.analyze(parent),
CardanoPublishBlockField::Version(x) => x.analyze(parent),
CardanoPublishBlockField::Script(x) => x.analyze(parent),
}
}
fn is_resolved(&self) -> bool {
match self {
CardanoPublishBlockField::To(x) => x.is_resolved(),
CardanoPublishBlockField::Amount(x) => x.is_resolved(),
CardanoPublishBlockField::Datum(x) => x.is_resolved(),
CardanoPublishBlockField::Version(x) => x.is_resolved(),
CardanoPublishBlockField::Script(x) => x.is_resolved(),
}
}
}
impl Analyzable for CardanoPublishBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
self.fields.analyze(parent)
}
fn is_resolved(&self) -> bool {
self.fields.is_resolved()
}
}
impl IntoLower for CardanoPublishBlockField {
type Output = (String, ir::Expression);
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
match self {
CardanoPublishBlockField::To(x) => {
let ctx = ctx.enter_address_expr();
Ok(("to".to_string(), x.into_lower(&ctx)?))
}
CardanoPublishBlockField::Amount(x) => {
let ctx = ctx.enter_asset_expr();
Ok(("amount".to_string(), x.into_lower(&ctx)?))
}
CardanoPublishBlockField::Datum(x) => {
let ctx = ctx.enter_datum_expr();
Ok(("datum".to_string(), x.into_lower(&ctx)?))
}
CardanoPublishBlockField::Version(x) => Ok(("version".to_string(), x.into_lower(ctx)?)),
CardanoPublishBlockField::Script(x) => Ok(("script".to_string(), x.into_lower(ctx)?)),
}
}
}
impl IntoLower for CardanoPublishBlock {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<Self::Output, crate::lowering::Error> {
let data = self
.fields
.iter()
.map(|x| x.into_lower(ctx))
.collect::<Result<_, _>>()?;
Ok(ir::AdHocDirective {
name: "cardano_publish".to_string(),
data,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum CardanoBlock {
VoteDelegationCertificate(VoteDelegationCertificate),
StakeDelegationCertificate(StakeDelegationCertificate),
Withdrawal(WithdrawalBlock),
PlutusWitness(PlutusWitnessBlock),
NativeWitness(NativeWitnessBlock),
TreasuryDonation(TreasuryDonationBlock),
Publish(CardanoPublishBlock),
}
impl AstNode for CardanoBlock {
const RULE: Rule = Rule::cardano_block;
fn parse(pair: Pair<Rule>) -> Result<Self, Error> {
let mut inner = pair.into_inner();
let item = inner.next().unwrap();
match item.as_rule() {
Rule::cardano_vote_delegation_certificate => Ok(
CardanoBlock::VoteDelegationCertificate(VoteDelegationCertificate::parse(item)?),
),
Rule::cardano_stake_delegation_certificate => Ok(
CardanoBlock::StakeDelegationCertificate(StakeDelegationCertificate::parse(item)?),
),
Rule::cardano_withdrawal_block => {
Ok(CardanoBlock::Withdrawal(WithdrawalBlock::parse(item)?))
}
Rule::cardano_plutus_witness_block => Ok(CardanoBlock::PlutusWitness(
PlutusWitnessBlock::parse(item)?,
)),
Rule::cardano_native_witness_block => Ok(CardanoBlock::NativeWitness(
NativeWitnessBlock::parse(item)?,
)),
Rule::cardano_treasury_donation_block => Ok(CardanoBlock::TreasuryDonation(
TreasuryDonationBlock::parse(item)?,
)),
Rule::cardano_publish_block => {
Ok(CardanoBlock::Publish(CardanoPublishBlock::parse(item)?))
}
x => unreachable!("Unexpected rule in cardano_block: {:?}", x),
}
}
fn span(&self) -> &Span {
match self {
CardanoBlock::VoteDelegationCertificate(x) => x.span(),
CardanoBlock::StakeDelegationCertificate(x) => x.span(),
CardanoBlock::Withdrawal(x) => x.span(),
CardanoBlock::PlutusWitness(x) => x.span(),
CardanoBlock::NativeWitness(x) => x.span(),
CardanoBlock::TreasuryDonation(x) => x.span(),
CardanoBlock::Publish(x) => x.span(),
}
}
}
impl Analyzable for CardanoBlock {
fn analyze(&mut self, parent: Option<Rc<Scope>>) -> AnalyzeReport {
match self {
CardanoBlock::VoteDelegationCertificate(x) => x.analyze(parent),
CardanoBlock::StakeDelegationCertificate(x) => x.analyze(parent),
CardanoBlock::Withdrawal(x) => x.analyze(parent),
CardanoBlock::PlutusWitness(x) => x.analyze(parent),
CardanoBlock::NativeWitness(x) => x.analyze(parent),
CardanoBlock::TreasuryDonation(x) => x.analyze(parent),
CardanoBlock::Publish(x) => x.analyze(parent),
}
}
fn is_resolved(&self) -> bool {
match self {
CardanoBlock::VoteDelegationCertificate(x) => x.is_resolved(),
CardanoBlock::StakeDelegationCertificate(x) => x.is_resolved(),
CardanoBlock::Withdrawal(x) => x.is_resolved(),
CardanoBlock::PlutusWitness(x) => x.is_resolved(),
CardanoBlock::NativeWitness(x) => x.is_resolved(),
Self::TreasuryDonation(x) => x.is_resolved(),
CardanoBlock::Publish(x) => x.is_resolved(),
}
}
}
impl IntoLower for CardanoBlock {
type Output = ir::AdHocDirective;
fn into_lower(
&self,
ctx: &crate::lowering::Context,
) -> Result<<CardanoBlock as IntoLower>::Output, crate::lowering::Error> {
match self {
CardanoBlock::VoteDelegationCertificate(x) => x.into_lower(ctx),
CardanoBlock::StakeDelegationCertificate(x) => x.into_lower(ctx),
CardanoBlock::Withdrawal(x) => x.into_lower(ctx),
CardanoBlock::PlutusWitness(x) => x.into_lower(ctx),
CardanoBlock::NativeWitness(x) => x.into_lower(ctx),
CardanoBlock::TreasuryDonation(x) => x.into_lower(ctx),
CardanoBlock::Publish(x) => x.into_lower(ctx),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
analyzing::analyze,
ast::{self, *},
};
use pest::Parser;
macro_rules! input_to_ast_check {
($ast:ty, $name:expr, $input:expr, $expected:expr) => {
paste::paste! {
#[test]
fn [<test_parse_ $ast:snake _ $name>]() {
let pairs = crate::parsing::Tx3Grammar::parse(<$ast>::RULE, $input).unwrap();
let single_match = pairs.into_iter().next().unwrap();
let result = <$ast>::parse(single_match).unwrap();
assert_eq!(result, $expected);
}
}
};
}
input_to_ast_check!(
PlutusWitnessBlock,
"basic",
"plutus_witness {
version: 3,
script: 0xABCDEF,
}",
PlutusWitnessBlock {
fields: vec![
PlutusWitnessField::Version(DataExpr::Number(3), Span::DUMMY),
PlutusWitnessField::Script(
DataExpr::HexString(HexStringLiteral::new("ABCDEF".to_string())),
Span::DUMMY
)
],
span: Span::DUMMY,
}
);
input_to_ast_check!(
NativeWitnessBlock,
"basic",
"native_witness {
script: 0xABCDEF,
}",
NativeWitnessBlock {
fields: vec![NativeWitnessField::Script(
DataExpr::HexString(HexStringLiteral::new("ABCDEF".to_string())),
Span::DUMMY
)],
span: Span::DUMMY,
}
);
input_to_ast_check!(
TreasuryDonationBlock,
"basic",
"treasury_donation {
coin: 2020,
}",
TreasuryDonationBlock {
coin: DataExpr::Number(2020),
span: Span::DUMMY,
}
);
input_to_ast_check!(
CardanoPublishBlock,
"basic",
"publish {
to: Receiver,
amount: Ada(quantity),
version: 3,
script: 0xABCDEF,
}",
CardanoPublishBlock {
name: None,
fields: vec![
CardanoPublishBlockField::To(Box::new(DataExpr::Identifier(Identifier::new(
"Receiver"
)))),
CardanoPublishBlockField::Amount(Box::new(DataExpr::FnCall(crate::ast::FnCall {
callee: Identifier::new("Ada"),
args: vec![DataExpr::Identifier(Identifier::new("quantity"))],
span: Span::DUMMY,
}))),
CardanoPublishBlockField::Version(Box::new(DataExpr::Number(3))),
CardanoPublishBlockField::Script(Box::new(DataExpr::HexString(
HexStringLiteral::new("ABCDEF".to_string())
))),
],
span: Span::DUMMY,
}
);
input_to_ast_check!(
CardanoPublishBlock,
"basic_with_name",
"publish test_publish {
to: Receiver,
amount: Ada(quantity),
version: 3,
script: 0xABCDEF,
}",
CardanoPublishBlock {
name: Some(Identifier::new("test_publish")),
fields: vec![
CardanoPublishBlockField::To(Box::new(DataExpr::Identifier(Identifier::new(
"Receiver"
)))),
CardanoPublishBlockField::Amount(Box::new(DataExpr::FnCall(crate::ast::FnCall {
callee: Identifier::new("Ada"),
args: vec![DataExpr::Identifier(Identifier::new("quantity"))],
span: Span::DUMMY,
}))),
CardanoPublishBlockField::Version(Box::new(DataExpr::Number(3))),
CardanoPublishBlockField::Script(Box::new(DataExpr::HexString(
HexStringLiteral::new("ABCDEF".to_string())
))),
],
span: Span::DUMMY,
}
);
#[test]
fn test_treasury_donation_type() {
let mut ast = crate::parsing::parse_string(
r#"
tx test(quantity: Int) {
cardano::treasury_donation {
coin: quantity,
}
}
"#,
)
.unwrap();
let result = analyze(&mut ast);
assert!(result.errors.is_empty());
}
#[test]
fn test_treasury_donation_type_not_ok() {
let mut ast = crate::parsing::parse_string(
r#"
tx test(quantity: Bytes) {
cardano::treasury_donation {
coin: quantity,
}
}
"#,
)
.unwrap();
let result = analyze(&mut ast);
assert!(!result.errors.is_empty());
}
#[test]
fn test_publish_type_ok() {
let mut ast = crate::parsing::parse_string(
r#"
party Receiver;
tx test(quantity: Int) {
cardano::publish {
to: Receiver,
amount: Ada(quantity),
version: 3,
script: 0xABCDEF,
}
}
"#,
)
.unwrap();
let result = analyze(&mut ast);
assert!(result.errors.is_empty());
}
#[test]
fn test_publish_type_with_name_ok() {
let mut ast = crate::parsing::parse_string(
r#"
party Receiver;
tx test(quantity: Int) {
cardano::publish deploy {
to: Receiver,
amount: Ada(quantity),
version: 3,
script: 0xABCDEF,
}
}
"#,
)
.unwrap();
let result = analyze(&mut ast);
assert!(result.errors.is_empty());
}
}