mago-syntax 1.20.1

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::AttributeList;
use crate::ast::ast::HookedProperty;
use crate::ast::ast::Modifier;
use crate::ast::ast::PlainProperty;
use crate::ast::ast::Property;
use crate::ast::ast::PropertyAbstractItem;
use crate::ast::ast::PropertyConcreteItem;
use crate::ast::ast::PropertyHook;
use crate::ast::ast::PropertyHookAbstractBody;
use crate::ast::ast::PropertyHookBody;
use crate::ast::ast::PropertyHookConcreteBody;
use crate::ast::ast::PropertyHookConcreteExpressionBody;
use crate::ast::ast::PropertyHookList;
use crate::ast::ast::PropertyItem;
use crate::ast::sequence::Sequence;
use crate::ast::sequence::TokenSeparatedSequence;
use crate::error::ParseError;
use crate::parser::Parser;

impl<'input, 'arena> Parser<'input, 'arena> {
    pub(crate) fn parse_property_with_attributes_and_modifiers(
        &mut self,
        attributes: Sequence<'arena, AttributeList<'arena>>,
        modifiers: Sequence<'arena, Modifier<'arena>>,
    ) -> Result<Property<'arena>, ParseError> {
        let var = self.maybe_expect_keyword(T!["var"])?;
        let hint = self.parse_optional_type_hint()?;
        let item = self.parse_property_item()?;

        let next = self.stream.peek_kind(0)?;
        if matches!(next, Some(T!["{"])) {
            return Ok(Property::Hooked(HookedProperty {
                attribute_lists: attributes,
                modifiers,
                var,
                hint,
                item,
                hook_list: self.parse_property_hook_list()?,
            }));
        }

        Ok(Property::Plain(PlainProperty {
            attribute_lists: attributes,
            modifiers,
            var,
            hint,
            items: {
                let mut items = self.new_vec_of(item);
                let mut commas = self.new_vec();
                if matches!(next, Some(T![","])) {
                    commas.push(self.stream.consume()?);

                    loop {
                        let item = self.parse_property_item()?;
                        items.push(item);

                        match self.stream.peek_kind(0)? {
                            Some(T![","]) => {
                                commas.push(self.stream.consume()?);
                            }
                            _ => {
                                break;
                            }
                        }
                    }
                }

                TokenSeparatedSequence::new(items, commas)
            },
            terminator: self.parse_terminator()?,
        }))
    }

    fn parse_property_item(&mut self) -> Result<PropertyItem<'arena>, ParseError> {
        Ok(match self.stream.peek_kind(1)? {
            Some(T!["="]) => PropertyItem::Concrete(self.parse_property_concrete_item()?),
            _ => PropertyItem::Abstract(self.parse_property_abstract_item()?),
        })
    }

    fn parse_property_abstract_item(&mut self) -> Result<PropertyAbstractItem<'arena>, ParseError> {
        Ok(PropertyAbstractItem { variable: self.parse_direct_variable()? })
    }

    fn parse_property_concrete_item(&mut self) -> Result<PropertyConcreteItem<'arena>, ParseError> {
        Ok(PropertyConcreteItem {
            variable: self.parse_direct_variable()?,
            equals: self.stream.eat_span(T!["="])?,
            value: self.parse_expression()?,
        })
    }

    pub(crate) fn parse_optional_property_hook_list(&mut self) -> Result<Option<PropertyHookList<'arena>>, ParseError> {
        Ok(match self.stream.peek_kind(0)? {
            Some(T!["{"]) => Some(self.parse_property_hook_list()?),
            _ => None,
        })
    }

    fn parse_property_hook_list(&mut self) -> Result<PropertyHookList<'arena>, ParseError> {
        Ok(PropertyHookList {
            left_brace: self.stream.eat_span(T!["{"])?,
            hooks: {
                let mut hooks = self.new_vec();
                loop {
                    if matches!(self.stream.peek_kind(0)?, Some(T!["}"])) {
                        break;
                    }

                    let hook = self.parse_property_hook()?;
                    hooks.push(hook);
                }

                Sequence::new(hooks)
            },
            right_brace: self.stream.eat_span(T!["}"])?,
        })
    }

    fn parse_property_hook(&mut self) -> Result<PropertyHook<'arena>, ParseError> {
        Ok(PropertyHook {
            attribute_lists: self.parse_attribute_list_sequence()?,
            ampersand: if self.stream.is_at(T!["&"])? { Some(self.stream.eat_span(T!["&"])?) } else { None },
            modifiers: self.parse_modifier_sequence()?,
            name: self.parse_local_identifier()?,
            parameter_list: self.parse_optional_function_like_parameter_list()?,
            body: self.parse_property_hook_body()?,
        })
    }

    fn parse_property_hook_body(&mut self) -> Result<PropertyHookBody<'arena>, ParseError> {
        let next = self.stream.lookahead(0)?.ok_or_else(|| self.stream.unexpected(None, &[]))?;

        Ok(match next.kind {
            T![";"] => PropertyHookBody::Abstract(self.parse_property_hook_abstract_body()?),
            T!["{"] | T!["=>"] => PropertyHookBody::Concrete(self.parse_property_hook_concrete_body()?),
            _ => return Err(self.stream.unexpected(Some(next), T![";", "{", "=>"])),
        })
    }

    fn parse_property_hook_abstract_body(&mut self) -> Result<PropertyHookAbstractBody, ParseError> {
        Ok(PropertyHookAbstractBody { semicolon: self.stream.eat_span(T![";"])? })
    }

    fn parse_property_hook_concrete_body(&mut self) -> Result<PropertyHookConcreteBody<'arena>, ParseError> {
        let next = self.stream.lookahead(0)?.ok_or_else(|| self.stream.unexpected(None, &[]))?;

        Ok(match next.kind {
            T!["{"] => PropertyHookConcreteBody::Block(self.parse_block()?),
            T!["=>"] => PropertyHookConcreteBody::Expression(self.parse_property_hook_concrete_expression_body()?),
            _ => return Err(self.stream.unexpected(Some(next), T!["{", "=>"])),
        })
    }

    fn parse_property_hook_concrete_expression_body(
        &mut self,
    ) -> Result<PropertyHookConcreteExpressionBody<'arena>, ParseError> {
        Ok(PropertyHookConcreteExpressionBody {
            arrow: self.stream.eat_span(T!["=>"])?,
            expression: self.parse_expression()?,
            semicolon: self.stream.eat_span(T![";"])?,
        })
    }
}