backyard-parser 0.1.10

Parse PHP code to AST node.
Documentation
use bumpalo::collections::Vec;
use backyard_lexer::token::TokenType;
use backyard_nodes::{
  CallArgumentNode,
  CallNode,
  Location,
  Node,
  utils::{ IntoBoxedNode, IntoBoxedOptionNode },
};

use crate::{
  error::ParserError,
  parser::{ LoopArgument, OptionNodeOrInternal, Parser },
  utils::{ match_pattern, Lookup, LookupResult, LookupResultWrapper },
};

use super::{ comment::CommentParser, identifier::IdentifierParser };

#[derive(Debug, Clone)]
pub struct CallParser;

impl CallParser {
  pub fn get_arguments<'arena, 'a>(
    parser: &mut Parser<'arena, 'a>
  ) -> Result<Vec<'arena, Node<'arena>>, ParserError> {
    parser.get_children(
      &mut LoopArgument::new(
        parser.arena,
        "call",
        &[TokenType::Comma],
        &[TokenType::RightParenthesis],
        &[
          (CommentParser::test, CommentParser::parse),
          (ArgumentParser::test, ArgumentParser::parse),
        ]
      )
    )
  }
}

impl CallParser {
  pub fn test<'arena, 'a>(
    parser: &mut Parser<'arena, 'a>,
    args: &mut LoopArgument
  ) -> Option<std::vec::Vec<LookupResult<'arena>>> {
    args.last_expr.as_ref()?;
    match_pattern(parser, &[Lookup::Equal(&[TokenType::LeftParenthesis])])
  }

  pub fn parse<'arena, 'a, 'b>(
    parser: &mut Parser<'arena, 'a>,
    matched: std::vec::Vec<LookupResult<'arena>>,
    start_loc: Location,
    args: &mut LoopArgument<'arena, 'b>
  ) -> Result<Node<'arena>, ParserError> {
    if let [_] = matched.as_slice() {
      return Ok(
        CallNode::loc(
          args.last_expr.take().unwrap().into_boxed(parser.arena),
          CallParser::get_arguments(parser)?,
          parser.gen_loc(start_loc)
        )
      );
    }
    Err(ParserError::Internal)
  }
}

#[derive(Debug, Clone)]
pub struct ArgumentParser;

impl ArgumentParser {
  pub fn test<'arena, 'a>(
    parser: &mut Parser<'arena, 'a>,
    _: &mut LoopArgument
  ) -> Option<std::vec::Vec<LookupResult<'arena>>> {
    if let Ok(is_colon) = parser.get_token(parser.position + 1) {
      if is_colon.token_type == TokenType::Colon && parser.get_token(parser.position).is_ok() {
        return Some(
          vec![
            LookupResult {
              size: 1,
              wrapper: LookupResultWrapper::Optional(Some(parser.position)),
            },
            LookupResult {
              size: 1,
              wrapper: LookupResultWrapper::Optional(Some(parser.position + 1)),
            }
          ]
        );
      }
    }
    Some(
      vec![
        LookupResult {
          size: 0,
          wrapper: LookupResultWrapper::Optional(None),
        },
        LookupResult {
          size: 0,
          wrapper: LookupResultWrapper::Optional(None),
        }
      ]
    )
  }

  pub fn parse<'arena, 'a, 'b>(
    parser: &mut Parser<'arena, 'a>,
    matched: std::vec::Vec<LookupResult<'arena>>,
    start_loc: Location,
    _: &mut LoopArgument<'arena, 'b>
  ) -> Result<Node<'arena>, ParserError> {
    if let [name, has_name] = matched.as_slice() {
      let name = has_name
        .as_optional(parser)
        .map(|_| name.as_optional(parser).map(IdentifierParser::from_token))
        .unwrap_or_default();
      let value = parser
        .get_statement(
          &mut LoopArgument::with_tokens(
            parser.arena,
            "argument",
            &[TokenType::Comma, TokenType::RightParenthesis],
            &[]
          )
        )?
        .ok_internal()?;
      return Ok(
        CallArgumentNode::loc(
          name.into_boxed(parser.arena),
          value.into_boxed(parser.arena),
          parser.gen_loc(start_loc)
        )
      );
    }
    Err(ParserError::Internal)
  }
}