toml_edit/parser/
value.rs1use 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
16pub(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 b'+' | b'-' | b'0'..=b'9' => {
29 alt((
31 date_time
32 .map(Value::from),
33 float
34 .map(Value::from),
35 integer
36 .map(Value::from),
37 ))
38 },
39 b'_' => {
41 integer
42 .map(Value::from)
43 .context(StrContext::Expected(StrContextValue::Description("leading digit")))
44 },
45 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}