toml_edit/parser/
value.rs

1use winnow::combinator::alt;
2use winnow::combinator::fail;
3use winnow::combinator::peek;
4use winnow::token::any;
5
6use crate::parser::array::array;
7use crate::parser::datetime::date_time;
8use crate::parser::inline_table::inline_table;
9use crate::parser::numbers::{float, integer};
10use crate::parser::prelude::*;
11use crate::parser::strings::string;
12use crate::repr::{Formatted, Repr};
13use crate::RawString;
14use crate::Value;
15
16// val = string / boolean / array / inline-table / date-time / float / integer
17pub(crate) fn value(input: &mut Input<'_>) -> ModalResult<Value> {
18    dispatch! {peek(any);
19            crate::parser::strings::QUOTATION_MARK |
20            crate::parser::strings::APOSTROPHE => string.map(|s| {
21                Value::String(Formatted::new(
22                    s.into_owned()
23                ))
24            }),
25            crate::parser::array::ARRAY_OPEN => check_recursion(array).map(Value::Array),
26            crate::parser::inline_table::INLINE_TABLE_OPEN => check_recursion(inline_table).map(Value::InlineTable),
27            // Date/number starts
28            b'+' | b'-' | b'0'..=b'9' => {
29                // Uncommon enough not to be worth optimizing at this time
30                alt((
31                    date_time
32                        .map(Value::from),
33                    float
34                        .map(Value::from),
35                    integer
36                        .map(Value::from),
37                ))
38            },
39            // Report as if they were numbers because its most likely a typo
40            b'_' => {
41                    integer
42                        .map(Value::from)
43                .context(StrContext::Expected(StrContextValue::Description("leading digit")))
44            },
45            // Report as if they were numbers because its most likely a typo
46            b'.' =>  {
47                    float
48                        .map(Value::from)
49                .context(StrContext::Expected(StrContextValue::Description("leading digit")))
50            },
51            b't' => {
52                crate::parser::numbers::true_.map(Value::from)
53                    .context(StrContext::Label("string"))
54                    .context(StrContext::Expected(StrContextValue::CharLiteral('"')))
55                    .context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
56            },
57            b'f' => {
58                crate::parser::numbers::false_.map(Value::from)
59                    .context(StrContext::Label("string"))
60                    .context(StrContext::Expected(StrContextValue::CharLiteral('"')))
61                    .context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
62            },
63            b'i' => {
64                crate::parser::numbers::inf.map(Value::from)
65                    .context(StrContext::Label("string"))
66                    .context(StrContext::Expected(StrContextValue::CharLiteral('"')))
67                    .context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
68            },
69            b'n' => {
70                crate::parser::numbers::nan.map(Value::from)
71                    .context(StrContext::Label("string"))
72                    .context(StrContext::Expected(StrContextValue::CharLiteral('"')))
73                    .context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
74            },
75            _ => {
76                fail
77                    .context(StrContext::Label("string"))
78                    .context(StrContext::Expected(StrContextValue::CharLiteral('"')))
79                    .context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
80            },
81    }
82    .with_span()
83    .map(|(value, span)| apply_raw(value, span))
84    .parse_next(input)
85}
86
87fn apply_raw(mut val: Value, span: std::ops::Range<usize>) -> Value {
88    match val {
89        Value::String(ref mut f) => {
90            let raw = RawString::with_span(span);
91            f.set_repr_unchecked(Repr::new_unchecked(raw));
92        }
93        Value::Integer(ref mut f) => {
94            let raw = RawString::with_span(span);
95            f.set_repr_unchecked(Repr::new_unchecked(raw));
96        }
97        Value::Float(ref mut f) => {
98            let raw = RawString::with_span(span);
99            f.set_repr_unchecked(Repr::new_unchecked(raw));
100        }
101        Value::Boolean(ref mut f) => {
102            let raw = RawString::with_span(span);
103            f.set_repr_unchecked(Repr::new_unchecked(raw));
104        }
105        Value::Datetime(ref mut f) => {
106            let raw = RawString::with_span(span);
107            f.set_repr_unchecked(Repr::new_unchecked(raw));
108        }
109        Value::Array(ref mut arr) => {
110            arr.span = Some(span);
111        }
112        Value::InlineTable(ref mut table) => {
113            table.span = Some(span);
114        }
115    };
116    val.decorate("", "");
117    val
118}
119
120#[cfg(test)]
121#[cfg(feature = "parse")]
122#[cfg(feature = "display")]
123mod test {
124    use super::*;
125
126    #[test]
127    fn values() {
128        let inputs = [
129            "1979-05-27T00:32:00.999999",
130            "-239",
131            "1e200",
132            "9_224_617.445_991_228_313",
133            r"'''I [dw]on't need \d{2} apples'''",
134            r#"'''
135The first newline is
136trimmed in raw strings.
137   All other whitespace
138   is preserved.
139'''"#,
140            r#""Jos\u00E9\n""#,
141            r#""\\\"\b/\f\n\r\t\u00E9\U000A0000""#,
142            r#"{ hello = "world", a = 1}"#,
143            r#"[ { x = 1, a = "2" }, {a = "a",b = "b",     c =    "c"} ]"#,
144        ];
145        for input in inputs {
146            dbg!(input);
147            let mut parsed = value.parse(new_input(input));
148            if let Ok(parsed) = &mut parsed {
149                parsed.despan(input);
150            }
151            assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned()));
152        }
153    }
154}