meplang 0.1.8

An EVM low-level language that gives full control over the control flow of the smart contract.
Documentation
use pest::iterators::Pair;
use quick_impl::QuickImpl;

use super::attribute::WithAttributes;
use super::function::RFunction;
use super::variable::{RVariable, RVariableWithField};
use super::RHexAlias;
use crate::parser::parser::{get_next, map_unique_child, FromPair, Located, Rule};

#[derive(Debug, Clone, QuickImpl)]
pub enum RBlockRefStar {
    #[quick_impl(impl From)]
    Variable(RVariable),
}

impl FromPair for RBlockRefStar {
    fn from_pair(block_ref_star: Pair<Rule>) -> Result<Self, pest::error::Error<Rule>> {
        assert!(block_ref_star.as_rule() == Rule::block_ref_star);

        map_unique_child(block_ref_star, |child| match child.as_rule() {
            Rule::variable => Ok(RVariable::from_pair(child)?.into()),
            _ => unreachable!(),
        })
    }
}

#[derive(Debug, Clone, QuickImpl)]
pub enum RBlockRefEsp {
    #[quick_impl(impl From)]
    Variable(RVariable),
    #[quick_impl(impl From)]
    VariableWithField(RVariableWithField),
}

impl FromPair for RBlockRefEsp {
    fn from_pair(block_ref_esp: Pair<Rule>) -> Result<Self, pest::error::Error<Rule>> {
        assert!(block_ref_esp.as_rule() == Rule::block_ref_esp);

        map_unique_child(block_ref_esp, |child| match child.as_rule() {
            Rule::variable => Ok(RVariable::from_pair(child)?.into()),
            Rule::variable_with_field => Ok(RVariableWithField::from_pair(child)?.into()),
            _ => unreachable!(),
        })
    }
}

#[derive(Debug, Clone, QuickImpl)]
pub enum RBlockRef {
    #[quick_impl(impl From)]
    Star(RBlockRefStar),
    #[quick_impl(impl From)]
    Esp(RBlockRefEsp),
}

impl FromPair for RBlockRef {
    fn from_pair(block_ref: Pair<Rule>) -> Result<Self, pest::error::Error<Rule>> {
        assert!(block_ref.as_rule() == Rule::block_ref);

        let mut inner = block_ref.into_inner();

        let res = match inner.next().unwrap().as_rule() {
            Rule::star => RBlockRefStar::from_pair(inner.next().unwrap())?.into(),
            Rule::esp => RBlockRefEsp::from_pair(inner.next().unwrap())?.into(),
            _ => unreachable!(),
        };

        assert!(inner.next().is_none());

        Ok(res)
    }
}

#[derive(Debug, Clone, QuickImpl)]
pub enum RBlockItem {
    #[quick_impl(impl From)]
    Function(RFunction),
    #[quick_impl(impl From)]
    HexAlias(RHexAlias),
    #[quick_impl(impl From)]
    BlockRef(RBlockRef),
}

impl FromPair for RBlockItem {
    fn from_pair(block_item: Pair<Rule>) -> Result<Self, pest::error::Error<Rule>> {
        assert!(block_item.as_rule() == Rule::block_item);

        map_unique_child(block_item, |child| match child.as_rule() {
            Rule::function => Ok(RFunction::from_pair(child)?.into()),
            Rule::hex_alias => Ok(RHexAlias::from_pair(child)?.into()),
            Rule::block_ref => Ok(RBlockRef::from_pair(child)?.into()),
            _ => unreachable!(),
        })
    }
}

#[derive(Debug, Clone)]
pub struct RBlock {
    pub name: Located<RVariable>,
    pub abstr: bool,
    pub items: Vec<Located<WithAttributes<Located<RBlockItem>>>>,
}

impl RBlock {
    pub fn name_str(&self) -> &str {
        self.name.as_str()
    }
}

impl FromPair for RBlock {
    fn from_pair(block_decl: Pair<Rule>) -> Result<Self, pest::error::Error<Rule>> {
        assert!(block_decl.as_rule() == Rule::block_decl);

        let mut block_decl_inner = block_decl.into_inner();

        let abstr = match block_decl_inner.next().unwrap().as_rule() {
            Rule::block_keyword => false,
            Rule::abstract_keyword => {
                _ = get_next(&mut block_decl_inner, Rule::block_keyword);
                true
            },
            _ => unreachable!(),
        };

        let name = Located::<RVariable>::from_pair(get_next(&mut block_decl_inner, Rule::variable))?;

        _ = get_next(&mut block_decl_inner, Rule::open_brace);

        let mut items = Vec::<Located<WithAttributes<Located<RBlockItem>>>>::new();
        while let Some(block_item_with_attr) = block_decl_inner.next() {
            match block_item_with_attr.as_rule() {
                Rule::block_item_with_attr => {
                    items.push(Located::<WithAttributes<Located<RBlockItem>>>::from_pair(
                        block_item_with_attr,
                    )?);
                },
                Rule::close_brace => {
                    assert!(block_decl_inner.next() == None);
                    return Ok(RBlock { name, abstr, items });
                },
                _ => unreachable!(),
            }
        }
        unreachable!();
    }
}