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