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 ordered_float::OrderedFloat;

use mago_syntax_core::utils::parse_literal_float;
use mago_syntax_core::utils::parse_literal_integer;
use mago_syntax_core::utils::parse_literal_string;

use crate::T;
use crate::ast::ast::*;
use crate::error::ParseError;
use crate::parser::internal::token_stream::TokenStream;
use crate::parser::internal::utils;

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

    Ok(match &token.kind {
        T![LiteralFloat] => {
            let source = stream.interner().lookup(&token.value);

            Literal::Float(LiteralFloat {
                span: token.span,
                raw: token.value,
                value: OrderedFloat(parse_literal_float(source).unwrap_or_else(|| {
                    unreachable!("lexer generated invalid float `{}`; this should never happen.", source)
                })),
            })
        }
        T![LiteralInteger] => {
            let source = stream.interner().lookup(&token.value);

            Literal::Integer(LiteralInteger {
                span: token.span,
                raw: token.value,
                value: parse_literal_integer(source),
            })
        }
        T!["true"] => Literal::True(utils::to_keyword(token)),
        T!["false"] => Literal::False(utils::to_keyword(token)),
        T!["null"] => Literal::Null(utils::to_keyword(token)),
        T![LiteralString] => {
            let value = stream.interner().lookup(&token.value);

            Literal::String(LiteralString {
                kind: Some(if value.starts_with('"') {
                    LiteralStringKind::DoubleQuoted
                } else {
                    LiteralStringKind::SingleQuoted
                }),
                span: token.span,
                raw: token.value,
                value: parse_literal_string(value, None, true),
            })
        }
        T![PartialLiteralString] => {
            let value = stream.interner().lookup(&token.value);

            let kind =
                if value.starts_with('"') { LiteralStringKind::DoubleQuoted } else { LiteralStringKind::SingleQuoted };

            return Err(ParseError::UnclosedLiteralString(kind, token.span));
        }
        _ => {
            return Err(utils::unexpected(
                stream,
                Some(token),
                T!["true", "false", "null", LiteralFloat, LiteralInteger, LiteralString, PartialLiteralString],
            ));
        }
    })
}