mago-syntax 1.0.0-alpha.5

A correct, fast, and memory-efficient PHP syntax implementation, including Lexer, Parser, AST, and utilities for Mago.
Documentation
use crate::T;
use crate::ast::ast::*;
use crate::ast::sequence::TokenSeparatedSequence;
use crate::error::ParseError;
use crate::parser::internal::argument::parse_optional_argument_list;
use crate::parser::internal::expression::parse_expression;
use crate::parser::internal::expression::parse_expression_with_precedence;
use crate::parser::internal::token_stream::TokenStream;
use crate::parser::internal::utils;
use crate::token::Precedence;

pub fn parse_construct(stream: &mut TokenStream<'_, '_>) -> Result<Construct, ParseError> {
    let token = utils::peek(stream)?;

    Ok(match token.kind {
        T!["isset"] => Construct::Isset(IssetConstruct {
            isset: utils::expect_keyword(stream, T!["isset"])?,
            left_parenthesis: utils::expect_span(stream, T!["("])?,
            values: {
                let mut values = vec![];
                let mut commas = vec![];
                loop {
                    if matches!(utils::peek(stream)?.kind, T![")"]) {
                        break;
                    }

                    values.push(parse_expression(stream)?);

                    match utils::peek(stream)?.kind {
                        T![","] => {
                            commas.push(utils::expect_any(stream)?);
                        }
                        _ => {
                            break;
                        }
                    }
                }

                TokenSeparatedSequence::new(values, commas)
            },
            right_parenthesis: utils::expect_span(stream, T![")"])?,
        }),
        T!["empty"] => Construct::Empty(EmptyConstruct {
            empty: utils::expect_keyword(stream, T!["empty"])?,
            left_parenthesis: utils::expect_span(stream, T!["("])?,
            value: Box::new(parse_expression(stream)?),
            right_parenthesis: utils::expect_span(stream, T![")"])?,
        }),
        T!["eval"] => Construct::Eval(EvalConstruct {
            eval: utils::expect_keyword(stream, T!["eval"])?,
            left_parenthesis: utils::expect_span(stream, T!["("])?,
            value: Box::new(parse_expression(stream)?),
            right_parenthesis: utils::expect_span(stream, T![")"])?,
        }),
        T!["print"] => Construct::Print(PrintConstruct {
            print: utils::expect_keyword(stream, T!["print"])?,
            value: Box::new(parse_expression_with_precedence(stream, Precedence::Print)?),
        }),
        T!["require"] => Construct::Require(RequireConstruct {
            require: utils::expect_any_keyword(stream)?,
            value: Box::new(parse_expression(stream)?),
        }),
        T!["require_once"] => Construct::RequireOnce(RequireOnceConstruct {
            require_once: utils::expect_any_keyword(stream)?,
            value: Box::new(parse_expression(stream)?),
        }),
        T!["include"] => Construct::Include(IncludeConstruct {
            include: utils::expect_any_keyword(stream)?,
            value: Box::new(parse_expression(stream)?),
        }),
        T!["include_once"] => Construct::IncludeOnce(IncludeOnceConstruct {
            include_once: utils::expect_any_keyword(stream)?,
            value: Box::new(parse_expression(stream)?),
        }),
        T!["exit"] => Construct::Exit(ExitConstruct {
            exit: utils::expect_any_keyword(stream)?,
            arguments: parse_optional_argument_list(stream)?,
        }),
        T!["die"] => Construct::Die(DieConstruct {
            die: utils::expect_any_keyword(stream)?,
            arguments: parse_optional_argument_list(stream)?,
        }),
        _ => {
            return Err(utils::unexpected(
                stream,
                Some(token),
                T![
                    "isset",
                    "empty",
                    "eval",
                    "include",
                    "include_once",
                    "require",
                    "require_once",
                    "print",
                    "exit",
                    "die"
                ],
            ));
        }
    })
}