• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use winnow::combinator::alt;
2 use winnow::combinator::fail;
3 use winnow::combinator::peek;
4 use winnow::token::any;
5 
6 use crate::parser::array::array;
7 use crate::parser::datetime::date_time;
8 use crate::parser::inline_table::inline_table;
9 use crate::parser::numbers::{float, integer};
10 use crate::parser::prelude::*;
11 use crate::parser::strings::string;
12 use crate::repr::{Formatted, Repr};
13 use crate::RawString;
14 use crate::Value;
15 
16 // val = string / boolean / array / inline-table / date-time / float / integer
value(input: &mut Input<'_>) -> PResult<Value>17 pub(crate) fn value(input: &mut Input<'_>) -> PResult<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 
apply_raw(mut val: Value, span: std::ops::Range<usize>) -> Value87 fn 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")]
123 mod test {
124     use super::*;
125 
126     #[test]
values()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#"'''
135 The first newline is
136 trimmed 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 }
155