php_literal_parser/
parser.rs

1use crate::error::{ExpectToken, ParseError, ResultExt};
2use crate::lexer::{SpannedToken, Token, TokenStream};
3use crate::num::parse_int;
4use crate::string::{is_array_key_numeric, parse_string};
5use crate::{Key, Value};
6use logos::Logos;
7use std::iter::Peekable;
8use std::num::ParseFloatError;
9
10pub struct Parser<'source> {
11    source: &'source str,
12    tokens: Peekable<TokenStream<'source>>,
13}
14
15impl<'source> Parser<'source> {
16    pub fn new(source: &'source str) -> Self {
17        Parser {
18            source,
19            tokens: TokenStream::new(Token::lexer(source)).peekable(),
20        }
21    }
22
23    pub fn next_token(&mut self) -> Option<SpannedToken<'source>> {
24        self.tokens.next()
25    }
26
27    pub fn parse_literal(&self, token: SpannedToken) -> Result<Value, ParseError> {
28        let value = match token.token {
29            Token::Bool => Value::Bool(self.parse_bool_token(token)?),
30            Token::Integer => Value::Int(self.parse_int_token(token)?),
31            Token::Float => Value::Float(self.parse_float_token(token)?),
32            Token::LiteralString => Value::String(self.parse_string_token(token)?),
33            Token::Null => Value::Null,
34            _ => unreachable!(),
35        };
36
37        Ok(value)
38    }
39
40    pub fn parse_bool_token(&self, token: SpannedToken) -> Result<bool, ParseError> {
41        token
42            .slice()
43            .to_ascii_lowercase()
44            .parse()
45            .with_span(token.span, token.source)
46    }
47
48    pub fn parse_int_token(&self, token: SpannedToken) -> Result<i64, ParseError> {
49        parse_int(token.slice()).with_span(token.span, token.source)
50    }
51
52    pub fn parse_float_token(&self, token: SpannedToken) -> Result<f64, ParseError> {
53        parse_float(token.slice()).with_span(token.span, token.source)
54    }
55
56    pub fn parse_string_token(&self, token: SpannedToken) -> Result<String, ParseError> {
57        parse_string(token.slice()).with_span(token.span, token.source)
58    }
59
60    pub fn parse_array_key(&self, token: SpannedToken) -> Result<Key, ParseError> {
61        let token = token.expect_token(
62            &[
63                Token::Bool,
64                Token::Integer,
65                Token::Float,
66                Token::LiteralString,
67                Token::Null,
68            ],
69            self.source,
70        )?;
71        Ok(match self.parse_literal(token)? {
72            Value::Int(int) => Key::Int(int),
73            Value::Float(float) => Key::Int(float as i64),
74            Value::String(str) if is_array_key_numeric(&str) => Key::Int(parse_int(&str).unwrap()),
75            Value::String(str) => Key::String(str),
76            Value::Bool(bool) => Key::Int(if bool { 1 } else { 0 }),
77            Value::Null => Key::String(String::from("")),
78            _ => unreachable!(),
79        })
80    }
81
82    pub fn source(&self) -> &'source str {
83        self.source
84    }
85}
86
87fn parse_float(literal: &str) -> Result<f64, ParseFloatError> {
88    let stripped = literal.replace('_', "");
89    stripped.parse()
90}
91
92#[derive(Eq, PartialEq, Copy, Clone)]
93pub enum ArraySyntax {
94    Short,
95    Long,
96}
97
98impl ArraySyntax {
99    pub fn close_bracket(&self) -> Token {
100        match self {
101            ArraySyntax::Long => Token::BracketClose,
102            ArraySyntax::Short => Token::SquareClose,
103        }
104    }
105}