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::attribute;
use crate::parser::internal::class_like::property;
use crate::parser::internal::expression;
use crate::parser::internal::modifier;
use crate::parser::internal::token_stream::TokenStream;
use crate::parser::internal::type_hint;
use crate::parser::internal::utils;
use crate::parser::internal::variable;
use crate::token::Token;

pub fn parse_optional_function_like_parameter_list(
    stream: &mut TokenStream<'_, '_>,
) -> Result<Option<FunctionLikeParameterList>, ParseError> {
    Ok(match utils::maybe_peek(stream)?.map(|t| t.kind) {
        Some(T!["("]) => Some(parse_function_like_parameter_list(stream)?),
        _ => None,
    })
}

pub fn parse_function_like_parameter_list(
    stream: &mut TokenStream<'_, '_>,
) -> Result<FunctionLikeParameterList, ParseError> {
    Ok(FunctionLikeParameterList {
        left_parenthesis: utils::expect_span(stream, T!["("])?,
        parameters: {
            let mut parameters = Vec::new();
            let mut commas = Vec::new();
            loop {
                let token = utils::peek(stream)?;
                if T![")"] == token.kind {
                    break;
                }

                let parameter = parse_function_like_parameter(stream)?;
                parameters.push(parameter);

                match utils::maybe_expect(stream, T![","])? {
                    Some(comma) => {
                        commas.push(comma);
                    }
                    None => break,
                }
            }

            TokenSeparatedSequence::new(parameters, commas)
        },
        right_parenthesis: utils::expect_span(stream, T![")"])?,
    })
}

pub fn parse_function_like_parameter(stream: &mut TokenStream<'_, '_>) -> Result<FunctionLikeParameter, ParseError> {
    Ok(FunctionLikeParameter {
        attribute_lists: attribute::parse_attribute_list_sequence(stream)?,
        modifiers: modifier::parse_modifier_sequence(stream)?,
        hint: type_hint::parse_optional_type_hint(stream)?,
        ampersand: utils::maybe_expect(stream, T!["&"])?.map(|token| token.span),
        ellipsis: utils::maybe_expect(stream, T!["..."])?.map(|token| token.span),
        variable: variable::parse_direct_variable(stream)?,
        default_value: parse_optional_function_like_parameter_default_value(stream)?,
        hooks: property::parse_optional_property_hook_list(stream)?,
    })
}

pub fn parse_optional_function_like_parameter_default_value(
    stream: &mut TokenStream<'_, '_>,
) -> Result<Option<FunctionLikeParameterDefaultValue>, ParseError> {
    let token = utils::maybe_peek(stream)?;
    if let Some(Token { kind: T!["="], .. }) = token {
        Ok(Some(FunctionLikeParameterDefaultValue {
            equals: utils::expect_any(stream)?.span,
            value: expression::parse_expression(stream)?,
        }))
    } else {
        Ok(None)
    }
}