php-parser-rs 0.1.3

A handwritten recursive-descent parser for PHP written in Rust
Documentation
use crate::lexer::token::Token;
use crate::lexer::token::TokenKind;
use crate::parser;
use crate::parser::ast::literals::LiteralInteger;
use crate::parser::ast::loops::BreakStatement;
use crate::parser::ast::loops::ContinueStatement;
use crate::parser::ast::loops::DoWhileStatement;
use crate::parser::ast::loops::ForStatement;
use crate::parser::ast::loops::ForStatementBody;
use crate::parser::ast::loops::ForStatementIterator;
use crate::parser::ast::loops::ForeachStatement;
use crate::parser::ast::loops::ForeachStatementBody;
use crate::parser::ast::loops::ForeachStatementIterator;
use crate::parser::ast::loops::Level;
use crate::parser::ast::loops::WhileStatement;
use crate::parser::ast::loops::WhileStatementBody;
use crate::parser::ast::Statement;
use crate::parser::error::ParseResult;
use crate::parser::expressions;
use crate::parser::internal::blocks;
use crate::parser::internal::utils;
use crate::parser::state::State;

pub fn foreach_statement(state: &mut State) -> ParseResult<Statement> {
    let foreach = utils::skip(state, TokenKind::Foreach)?;

    let (left_parenthesis, iterator, right_parenthesis) =
        utils::parenthesized(state, &|state: &mut State| {
            let expression = expressions::create(state)?;

            let r#as = utils::skip(state, TokenKind::As)?;

            let current = state.stream.current();
            let ampersand = if current.kind == TokenKind::Ampersand {
                state.stream.next();
                Some(current.span)
            } else {
                None
            };

            let mut value = expressions::create(state)?;

            let current = state.stream.current();
            if current.kind == TokenKind::DoubleArrow {
                state.stream.next();
                let arrow = current.span;

                let current = state.stream.current();
                let ampersand = if current.kind == TokenKind::Ampersand {
                    state.stream.next();
                    Some(current.span)
                } else {
                    None
                };

                let mut key = expressions::create(state)?;

                std::mem::swap(&mut value, &mut key);

                Ok(ForeachStatementIterator::KeyAndValue {
                    expression,
                    r#as,
                    key,
                    double_arrow: arrow,
                    ampersand,
                    value,
                })
            } else {
                Ok(ForeachStatementIterator::Value {
                    expression,
                    r#as,
                    ampersand,
                    value,
                })
            }
        })?;

    let body = if state.stream.current().kind == TokenKind::Colon {
        ForeachStatementBody::Block {
            colon: utils::skip_colon(state)?,
            statements: blocks::multiple_statements_until(state, &TokenKind::EndForeach)?,
            endforeach: utils::skip(state, TokenKind::EndForeach)?,
            ending: utils::skip_ending(state)?,
        }
    } else {
        ForeachStatementBody::Statement {
            statement: parser::statement(state).map(Box::new)?,
        }
    };

    Ok(Statement::Foreach(ForeachStatement {
        foreach,
        left_parenthesis,
        iterator,
        right_parenthesis,
        body,
    }))
}

pub fn for_statement(state: &mut State) -> ParseResult<Statement> {
    let r#for = utils::skip(state, TokenKind::For)?;

    let (left_parenthesis, iterator, right_parenthesis) = utils::parenthesized(state, &|state| {
        let (initializations_semicolon, initializations) =
            utils::semicolon_terminated(state, &|state| {
                utils::comma_separated_no_trailing(
                    state,
                    &expressions::create,
                    TokenKind::SemiColon,
                )
            })?;

        let (conditions_semicolon, conditions) = utils::semicolon_terminated(state, &|state| {
            utils::comma_separated_no_trailing(state, &expressions::create, TokenKind::SemiColon)
        })?;

        Ok(ForStatementIterator {
            initializations,
            initializations_semicolon,
            conditions,
            conditions_semicolon,
            r#loop: utils::comma_separated_no_trailing(
                state,
                &expressions::create,
                TokenKind::RightParen,
            )?,
        })
    })?;

    let body = if state.stream.current().kind == TokenKind::Colon {
        ForStatementBody::Block {
            colon: utils::skip_colon(state)?,
            statements: blocks::multiple_statements_until(state, &TokenKind::EndFor)?,
            endfor: utils::skip(state, TokenKind::EndFor)?,
            ending: utils::skip_ending(state)?,
        }
    } else {
        ForStatementBody::Statement {
            statement: parser::statement(state).map(Box::new)?,
        }
    };

    Ok(Statement::For(ForStatement {
        r#for,
        left_parenthesis,
        iterator,
        right_parenthesis,
        body,
    }))
}

pub fn do_while_statement(state: &mut State) -> ParseResult<Statement> {
    let r#do = utils::skip(state, TokenKind::Do)?;

    let body = parser::statement(state).map(Box::new)?;

    let r#while = utils::skip(state, TokenKind::While)?;

    let (semicolon, (left_parenthesis, condition, right_parenthesis)) =
        utils::semicolon_terminated(state, &|state| {
            utils::parenthesized(state, &expressions::create)
        })?;

    Ok(Statement::DoWhile(DoWhileStatement {
        r#do,
        body,
        r#while,
        left_parenthesis,
        condition,
        right_parenthesis,
        semicolon,
    }))
}

pub fn while_statement(state: &mut State) -> ParseResult<Statement> {
    let r#while = utils::skip(state, TokenKind::While)?;

    let (left_parenthesis, condition, right_parenthesis) =
        utils::parenthesized(state, &expressions::create)?;

    let body = if state.stream.current().kind == TokenKind::Colon {
        WhileStatementBody::Block {
            colon: utils::skip_colon(state)?,
            statements: blocks::multiple_statements_until(state, &TokenKind::EndWhile)?,
            endwhile: utils::skip(state, TokenKind::EndWhile)?,
            ending: utils::skip_ending(state)?,
        }
    } else {
        WhileStatementBody::Statement {
            statement: parser::statement(state).map(Box::new)?,
        }
    };

    Ok(Statement::While(WhileStatement {
        r#while,
        left_parenthesis,
        condition,
        right_parenthesis,
        body,
    }))
}

pub fn continue_statement(state: &mut State) -> ParseResult<Statement> {
    Ok(Statement::Continue(ContinueStatement {
        r#continue: utils::skip(state, TokenKind::Continue)?,
        level: maybe_loop_level(state)?,
        ending: utils::skip_ending(state)?,
    }))
}

pub fn break_statement(state: &mut State) -> ParseResult<Statement> {
    Ok(Statement::Break(BreakStatement {
        r#break: utils::skip(state, TokenKind::Break)?,
        level: maybe_loop_level(state)?,
        ending: utils::skip_ending(state)?,
    }))
}

fn maybe_loop_level(state: &mut State) -> ParseResult<Option<Level>> {
    let current = &state.stream.current().kind;

    Ok(
        if current == &TokenKind::SemiColon || current == &TokenKind::CloseTag {
            None
        } else {
            Some(loop_level(state)?)
        },
    )
}

fn loop_level(state: &mut State) -> ParseResult<Level> {
    if let Token {
        kind: TokenKind::LiteralInteger,
        span,
        value,
    } = state.stream.current()
    {
        state.stream.next();

        return Ok(Level::Literal(LiteralInteger {
            value: value.clone(),
            span: *span,
        }));
    }

    let (left_parenthesis, level, right_parenthesis) =
        utils::parenthesized(state, &|state| loop_level(state).map(Box::new))?;

    Ok(Level::Parenthesized {
        left_parenthesis,
        level,
        right_parenthesis,
    })
}