meplang 0.1.8

An EVM low-level language that gives full control over the control flow of the smart contract.
Documentation
use std::ops::Deref;

use pest::iterators::Pair;
use quick_impl::QuickImpl;

use super::variable::RVariable;
use super::{RCompileVariable, RHexLiteral, RStringLiteral};
use crate::parser::parser::{get_next, map_unique_child, FromPair, Located, Rule};

#[derive(Debug, Clone, QuickImpl)]
pub enum RAttributeEqualityRight {
    #[quick_impl(impl From)]
    HexLiteral(RHexLiteral),
    #[quick_impl(impl From)]
    CompileVariable(RCompileVariable),
    #[quick_impl(impl From)]
    StringLiteral(#[allow(unused)] RStringLiteral),
}

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

        map_unique_child(attribute_equality_right, |inner| match inner.as_rule() {
            Rule::hex_literal => Ok(RHexLiteral::from_pair(inner)?.into()),
            Rule::compile_variable => Ok(RCompileVariable::from_pair(inner)?.into()),
            Rule::string_literal => Ok(RStringLiteral::from_pair(inner)?.into()),
            _ => unreachable!(),
        })
    }
}

#[derive(Debug, Clone)]
pub struct RAttributeEquality {
    pub name: Located<RVariable>,
    pub value: Located<RAttributeEqualityRight>,
}

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

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

        let mut inner = attribute_equality.into_inner();

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

        _ = get_next(&mut inner, Rule::eq);

        let value =
            Located::<RAttributeEqualityRight>::from_pair(get_next(&mut inner, Rule::attribute_equality_right))?;

        assert!(inner.next() == None);

        Ok(Self { name, value })
    }
}

#[derive(Debug, Clone, QuickImpl)]
pub enum RAttributeArg {
    #[quick_impl(impl From)]
    AttributeEquality(RAttributeEquality),
    #[quick_impl(impl From)]
    Variable(RVariable),
    #[quick_impl(impl From)]
    StringLiteral(#[allow(unused)] RStringLiteral),
}

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

        map_unique_child(attribute_arg, |inner| match inner.as_rule() {
            Rule::attribute_equality => Ok(RAttributeEquality::from_pair(inner)?.into()),
            Rule::variable => Ok(RVariable::from_pair(inner)?.into()),
            Rule::string_literal => Ok(RStringLiteral::from_pair(inner)?.into()),
            _ => unreachable!(),
        })
    }
}

#[derive(Debug, Clone)]
pub struct RAttribute {
    pub name: Located<RVariable>,
    pub arg: Option<Located<RAttributeArg>>,
}

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

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

        let mut attribute_inner = attribute.into_inner();

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

        if let Some(paren) = attribute_inner.next() {
            assert!(paren.as_rule() == Rule::open_paren);

            let arg = Some(Located::<RAttributeArg>::from_pair(get_next(
                &mut attribute_inner,
                Rule::attribute_arg,
            ))?);

            _ = get_next(&mut attribute_inner, Rule::close_paren);
            assert!(attribute_inner.next() == None);

            Ok(Self { name, arg })
        } else {
            Ok(Self { name, arg: None })
        }
    }
}

#[derive(Debug, Clone)]
pub struct WithAttributes<T> {
    pub attributes: Vec<Located<RAttribute>>,
    pub inner: T,
}

impl<T: FromPair> FromPair for WithAttributes<T> {
    fn from_pair(item_with_attr: Pair<Rule>) -> Result<Self, pest::error::Error<Rule>> {
        let mut inner = item_with_attr.into_inner();

        let mut attributes = Vec::<Located<RAttribute>>::new();
        while let Some(attr_or_item) = inner.next() {
            match attr_or_item.as_rule() {
                Rule::attribute => {
                    attributes.push(Located::<RAttribute>::from_pair(attr_or_item)?);
                },
                _ => {
                    let attr_inner = T::from_pair(attr_or_item)?;
                    assert!(inner.next() == None);
                    return Ok(Self {
                        attributes,
                        inner: attr_inner,
                    });
                },
            }
        }
        unreachable!()
    }
}

impl<T> WithAttributes<T> {
    pub fn inner(&self) -> &T {
        &self.inner
    }
}

impl<T> Deref for WithAttributes<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}