php_literal_parser/
parser.rs1use 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}