toml_edit/parser/
value.rs

1use crate::parser::array::on_array;
2use crate::parser::inline_table::on_inline_table;
3use crate::parser::prelude::*;
4use crate::repr::{Formatted, Repr};
5use crate::RawString;
6use crate::Value;
7
8/// ```bnf
9/// val = string / boolean / array / inline-table / date-time / float / integer
10/// ```
11pub(crate) fn value(
12    input: &mut Input<'_>,
13    source: toml_parser::Source<'_>,
14    errors: &mut dyn ErrorSink,
15) -> Value {
16    #[cfg(feature = "debug")]
17    let _scope = TraceScope::new("value");
18    if let Some(event) = input.next_token() {
19        match event.kind() {
20            EventKind::StdTableOpen
21            | EventKind::ArrayTableOpen
22            | EventKind::InlineTableClose
23            | EventKind::ArrayClose
24            | EventKind::ValueSep
25            | EventKind::Comment
26            | EventKind::Newline
27            | EventKind::Error
28            | EventKind::SimpleKey
29            | EventKind::KeySep
30            | EventKind::KeyValSep
31            | EventKind::StdTableClose
32            | EventKind::ArrayTableClose => {
33                #[cfg(feature = "debug")]
34                trace(
35                    &format!("unexpected {event:?}"),
36                    anstyle::AnsiColor::Red.on_default(),
37                );
38            }
39            EventKind::Whitespace => {
40                #[cfg(feature = "debug")]
41                trace(
42                    &format!("unexpected {event:?}"),
43                    anstyle::AnsiColor::Red.on_default(),
44                );
45            }
46            EventKind::InlineTableOpen => {
47                return on_inline_table(event, input, source, errors);
48            }
49            EventKind::ArrayOpen => {
50                return on_array(event, input, source, errors);
51            }
52            EventKind::Scalar => {
53                return on_scalar(event, source, errors);
54            }
55        }
56    }
57
58    Value::from(0)
59}
60
61pub(crate) fn on_scalar(
62    event: &toml_parser::parser::Event,
63    source: toml_parser::Source<'_>,
64    errors: &mut dyn ErrorSink,
65) -> Value {
66    #[cfg(feature = "debug")]
67    let _scope = TraceScope::new("on_scalar");
68    let value_span = event.span();
69    let value_raw = RawString::with_span(value_span.start()..value_span.end());
70
71    let raw = source.get(event).unwrap();
72    let mut decoded = std::borrow::Cow::Borrowed("");
73    let kind = raw.decode_scalar(&mut decoded, errors);
74    match kind {
75        toml_parser::decoder::ScalarKind::String => {
76            let mut f = Formatted::new(decoded.into());
77            f.set_repr_unchecked(Repr::new_unchecked(value_raw));
78            Value::String(f)
79        }
80        toml_parser::decoder::ScalarKind::Boolean(value) => {
81            let mut f = Formatted::new(value);
82            f.set_repr_unchecked(Repr::new_unchecked(value_raw));
83            Value::Boolean(f)
84        }
85        toml_parser::decoder::ScalarKind::DateTime => {
86            let value = match decoded.parse::<toml_datetime::Datetime>() {
87                Ok(value) => value,
88                Err(err) => {
89                    errors.report_error(
90                        ParseError::new(err.to_string()).with_unexpected(event.span()),
91                    );
92                    toml_datetime::Datetime {
93                        date: None,
94                        time: None,
95                        offset: None,
96                    }
97                }
98            };
99            let mut f = Formatted::new(value);
100            f.set_repr_unchecked(Repr::new_unchecked(value_raw));
101            Value::Datetime(f)
102        }
103        toml_parser::decoder::ScalarKind::Float => {
104            let value = match decoded.parse::<f64>() {
105                Ok(value) => {
106                    if value.is_infinite()
107                        && !(decoded
108                            .strip_prefix(['+', '-'])
109                            .unwrap_or(&decoded)
110                            .chars()
111                            .all(|c| c.is_ascii_alphabetic()))
112                    {
113                        errors.report_error(
114                            ParseError::new("floating-point number overflowed")
115                                .with_unexpected(event.span()),
116                        );
117                    }
118                    value
119                }
120                Err(_) => {
121                    errors.report_error(
122                        ParseError::new(kind.invalid_description()).with_unexpected(event.span()),
123                    );
124                    f64::NAN
125                }
126            };
127            let mut f = Formatted::new(value);
128            f.set_repr_unchecked(Repr::new_unchecked(value_raw));
129            Value::Float(f)
130        }
131        toml_parser::decoder::ScalarKind::Integer(radix) => {
132            let value = match i64::from_str_radix(&decoded, radix.value()) {
133                Ok(value) => value,
134                Err(_) => {
135                    // Assuming the decoder fully validated it, leaving only overflow errors
136                    errors.report_error(
137                        ParseError::new("integer number overflowed").with_unexpected(event.span()),
138                    );
139                    i64::MAX
140                }
141            };
142            let mut f = Formatted::new(value);
143            f.set_repr_unchecked(Repr::new_unchecked(value_raw));
144            Value::Integer(f)
145        }
146    }
147}