lunarity-parser 0.2.1

A high performance Solidity language Parser
use ast::*;
use Parser;
use lexer::Token;

pub trait TypeNameContext<'ast> {
    fn parse(&mut Parser<'ast>) -> Option<TypeNameNode<'ast>>;
}

pub struct RegularTypeNameContext;
pub struct StatementTypeNameContext;

impl<'ast> TypeNameContext<'ast> for RegularTypeNameContext {
    fn parse(par: &mut Parser<'ast>) -> Option<TypeNameNode<'ast>> {
        match par.lexer.token {
            Token::KeywordMapping => par.mapping(),
            Token::Identifier     => par.user_defined_type(),
            _                     => par.elementary_type_name(),
        }
    }
}


impl<'ast> TypeNameContext<'ast> for StatementTypeNameContext {
    fn parse(par: &mut Parser<'ast>) -> Option<TypeNameNode<'ast>> {
        match par.lexer.token {
            Token::KeywordMapping => par.mapping(),
            _                     => par.elementary_type_name(),
        }
    }
}

impl<'ast> Parser<'ast> {
    #[inline]
    pub fn type_name<Context>(&mut self) -> Option<TypeNameNode<'ast>>
    where
        Context: TypeNameContext<'ast>,
    {
        Context::parse(self)
    }

    pub fn elementary_type_name<E>(&mut self) -> Option<Node<'ast, E>>
    where
        E: From<ElementaryTypeName> + Copy,
    {
        let elementary = {
            let ref size = self.lexer.extras;

            match self.lexer.token {
                Token::TypeBool       => ElementaryTypeName::Bool,
                Token::TypeAddress    => ElementaryTypeName::Address,
                Token::TypeString     => ElementaryTypeName::String,
                Token::TypeByte       => ElementaryTypeName::Byte(size.0),
                Token::TypeBytes      => ElementaryTypeName::Bytes,
                Token::TypeInt        => ElementaryTypeName::Int(size.0),
                Token::TypeUint       => ElementaryTypeName::Uint(size.0),
                Token::TypeFixed      => ElementaryTypeName::Fixed(size.0, size.1),
                Token::TypeUfixed     => ElementaryTypeName::Ufixed(size.0, size.1),
                _                     => return None,
            }
        };

        self.node_at_token(elementary)
    }

    pub fn variable_declaration<Context>(&mut self) -> Option<VariableDeclarationNode<'ast>>
    where
        Context: TypeNameContext<'ast>,
    {
        let type_name = self.type_name::<Context>()?;

        let location = match self.lexer.token {
            Token::KeywordStorage => self.node_at_token(StorageLocation::Storage),
            Token::KeywordMemory  => self.node_at_token(StorageLocation::Memory),
            _                     => None,
        };

        let id = self.expect_str_node(Token::Identifier);

        self.node_at(type_name.start, id.end, VariableDeclaration {
            type_name,
            location,
            id,
        })
    }

    fn user_defined_type(&mut self) -> Option<TypeNameNode<'ast>> {
        let (start, end) = self.loc();
        let identifier = self.lexer.slice();

        self.lexer.advance();

        self.node_at(start, end, identifier)
    }

    fn mapping(&mut self) -> Option<TypeNameNode<'ast>> {
        let start = self.start_then_advance();

        self.expect(Token::ParenOpen);

        let from = expect!(self, self.elementary_type_name());

        self.expect(Token::Arrow);

        let to  = expect!(self, self.type_name::<RegularTypeNameContext>());
        let end = self.expect_end(Token::ParenClose);

        self.node_at(start, end, Mapping {
            from,
            to,
        })
    }
}