1use winnow::stream::ContainsToken as _;
2use winnow::stream::FindSlice as _;
3use winnow::stream::Offset as _;
4use winnow::stream::Stream as _;
5
6use crate::decoder::StringBuilder;
7use crate::ErrorSink;
8use crate::Expected;
9use crate::ParseError;
10use crate::Raw;
11use crate::Span;
12
13const ALLOCATION_ERROR: &str = "could not allocate for string";
14
15#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
16pub enum ScalarKind {
17 String,
18 Boolean(bool),
19 DateTime,
20 Float,
21 Integer(IntegerRadix),
22}
23
24impl ScalarKind {
25 pub fn description(&self) -> &'static str {
26 match self {
27 Self::String => "string",
28 Self::Boolean(_) => "boolean",
29 Self::DateTime => "date-time",
30 Self::Float => "float",
31 Self::Integer(radix) => radix.description(),
32 }
33 }
34
35 pub fn invalid_description(&self) -> &'static str {
36 match self {
37 Self::String => "invalid string",
38 Self::Boolean(_) => "invalid boolean",
39 Self::DateTime => "invalid date-time",
40 Self::Float => "invalid float",
41 Self::Integer(radix) => radix.invalid_description(),
42 }
43 }
44}
45
46#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
47pub enum IntegerRadix {
48 #[default]
49 Dec,
50 Hex,
51 Oct,
52 Bin,
53}
54
55impl IntegerRadix {
56 pub fn description(&self) -> &'static str {
57 match self {
58 Self::Dec => "integer",
59 Self::Hex => "hexadecimal",
60 Self::Oct => "octal",
61 Self::Bin => "binary",
62 }
63 }
64
65 pub fn value(&self) -> u32 {
66 match self {
67 Self::Dec => 10,
68 Self::Hex => 16,
69 Self::Oct => 8,
70 Self::Bin => 2,
71 }
72 }
73
74 pub fn invalid_description(&self) -> &'static str {
75 match self {
76 Self::Dec => "invalid integer number",
77 Self::Hex => "invalid hexadecimal number",
78 Self::Oct => "invalid octal number",
79 Self::Bin => "invalid binary number",
80 }
81 }
82
83 fn validator(&self) -> fn(char) -> bool {
84 match self {
85 Self::Dec => |c| c.is_ascii_digit(),
86 Self::Hex => |c| c.is_ascii_hexdigit(),
87 Self::Oct => |c| matches!(c, '0'..='7'),
88 Self::Bin => |c| matches!(c, '0'..='1'),
89 }
90 }
91}
92
93pub(crate) fn decode_unquoted_scalar<'i>(
94 raw: Raw<'i>,
95 output: &mut dyn StringBuilder<'i>,
96 error: &mut dyn ErrorSink,
97) -> ScalarKind {
98 let s = raw.as_str();
99 let Some(first) = s.as_bytes().first() else {
100 return decode_invalid(raw, output, error);
101 };
102 if !first.is_ascii_digit() && s.contains(" ") {
103 return decode_invalid(raw, output, error);
105 }
106 match first {
107 b'+' | b'-' => {
109 let value = &raw.as_str()[1..];
110 decode_sign_prefix(raw, value, output, error)
111 }
112 b'_' => decode_datetime_or_float_or_integer(raw.as_str(), raw, output, error),
114 b'0' => decode_zero_prefix(raw.as_str(), false, raw, output, error),
116 b'1'..=b'9' => decode_datetime_or_float_or_integer(raw.as_str(), raw, output, error),
117 b'.' => {
119 let kind = ScalarKind::Float;
120 let stream = raw.as_str();
121 if ensure_float(stream, raw, error) {
122 decode_float_or_integer(stream, raw, kind, output, error)
123 } else {
124 kind
125 }
126 }
127 b't' | b'T' => {
128 const SYMBOL: &str = "true";
129 let kind = ScalarKind::Boolean(true);
130 let expected = &[Expected::Literal(SYMBOL)];
131 decode_symbol(raw, SYMBOL, kind, expected, output, error)
132 }
133 b'f' | b'F' => {
134 const SYMBOL: &str = "false";
135 let kind = ScalarKind::Boolean(false);
136 let expected = &[Expected::Literal(SYMBOL)];
137 decode_symbol(raw, SYMBOL, kind, expected, output, error)
138 }
139 b'i' | b'I' => {
140 const SYMBOL: &str = "inf";
141 let kind = ScalarKind::Float;
142 let expected = &[Expected::Literal(SYMBOL)];
143 decode_symbol(raw, SYMBOL, kind, expected, output, error)
144 }
145 b'n' | b'N' => {
146 const SYMBOL: &str = "nan";
147 let kind = ScalarKind::Float;
148 let expected = &[Expected::Literal(SYMBOL)];
149 decode_symbol(raw, SYMBOL, kind, expected, output, error)
150 }
151 _ => decode_invalid(raw, output, error),
152 }
153}
154
155fn decode_sign_prefix<'i>(
156 raw: Raw<'i>,
157 value: &'i str,
158 output: &mut dyn StringBuilder<'i>,
159 error: &mut dyn ErrorSink,
160) -> ScalarKind {
161 let Some(first) = value.as_bytes().first() else {
162 return decode_invalid(raw, output, error);
163 };
164 match first {
165 b'+' | b'-' => {
167 let start = value.offset_from(&raw.as_str());
168 let end = start + 1;
169 error.report_error(
170 ParseError::new("redundant numeric sign")
171 .with_context(Span::new_unchecked(0, raw.len()))
172 .with_expected(&[])
173 .with_unexpected(Span::new_unchecked(start, end)),
174 );
175
176 let value = &value[1..];
177 decode_sign_prefix(raw, value, output, error)
178 }
179 b'_' => decode_datetime_or_float_or_integer(value, raw, output, error),
181 b'0' => decode_zero_prefix(value, true, raw, output, error),
183 b'1'..=b'9' => decode_datetime_or_float_or_integer(value, raw, output, error),
184 b'.' => {
186 let kind = ScalarKind::Float;
187 let stream = raw.as_str();
188 if ensure_float(stream, raw, error) {
189 decode_float_or_integer(stream, raw, kind, output, error)
190 } else {
191 kind
192 }
193 }
194 b'i' | b'I' => {
195 const SYMBOL: &str = "inf";
196 let kind = ScalarKind::Float;
197 if value != SYMBOL {
198 let expected = &[Expected::Literal(SYMBOL)];
199 let start = value.offset_from(&raw.as_str());
200 let end = start + value.len();
201 error.report_error(
202 ParseError::new(kind.invalid_description())
203 .with_context(Span::new_unchecked(0, raw.len()))
204 .with_expected(expected)
205 .with_unexpected(Span::new_unchecked(start, end)),
206 );
207 decode_as(raw, SYMBOL, kind, output, error)
208 } else {
209 decode_as_is(raw, kind, output, error)
210 }
211 }
212 b'n' | b'N' => {
213 const SYMBOL: &str = "nan";
214 let kind = ScalarKind::Float;
215 if value != SYMBOL {
216 let expected = &[Expected::Literal(SYMBOL)];
217 let start = value.offset_from(&raw.as_str());
218 let end = start + value.len();
219 error.report_error(
220 ParseError::new(kind.invalid_description())
221 .with_context(Span::new_unchecked(0, raw.len()))
222 .with_expected(expected)
223 .with_unexpected(Span::new_unchecked(start, end)),
224 );
225 decode_as(raw, SYMBOL, kind, output, error)
226 } else {
227 decode_as_is(raw, kind, output, error)
228 }
229 }
230 _ => decode_invalid(raw, output, error),
231 }
232}
233
234fn decode_zero_prefix<'i>(
235 value: &'i str,
236 signed: bool,
237 raw: Raw<'i>,
238 output: &mut dyn StringBuilder<'i>,
239 error: &mut dyn ErrorSink,
240) -> ScalarKind {
241 debug_assert_eq!(value.as_bytes()[0], b'0');
242 if value.len() == 1 {
243 let kind = ScalarKind::Integer(IntegerRadix::Dec);
244 decode_float_or_integer(raw.as_str(), raw, kind, output, error)
246 } else {
247 let radix = value.as_bytes()[1];
248 match radix {
249 b'x' | b'X' => {
250 if value.contains(" ") {
251 return decode_invalid(raw, output, error);
253 }
254 if signed {
255 error.report_error(
256 ParseError::new("integers with a radix cannot be signed")
257 .with_context(Span::new_unchecked(0, raw.len()))
258 .with_expected(&[])
259 .with_unexpected(Span::new_unchecked(0, 1)),
260 );
261 }
262 if radix == b'X' {
263 let start = value.offset_from(&raw.as_str());
264 let end = start + 2;
265 error.report_error(
266 ParseError::new("radix must be lowercase")
267 .with_context(Span::new_unchecked(0, raw.len()))
268 .with_expected(&[Expected::Literal("0x")])
269 .with_unexpected(Span::new_unchecked(start, end)),
270 );
271 }
272 let radix = IntegerRadix::Hex;
273 let kind = ScalarKind::Integer(radix);
274 let stream = &value[2..];
275 if ensure_radixed_value(stream, raw, radix, error) {
276 decode_float_or_integer(stream, raw, kind, output, error)
277 } else {
278 kind
279 }
280 }
281 b'o' | b'O' => {
282 if value.contains(" ") {
283 return decode_invalid(raw, output, error);
285 }
286 if signed {
287 error.report_error(
288 ParseError::new("integers with a radix cannot be signed")
289 .with_context(Span::new_unchecked(0, raw.len()))
290 .with_expected(&[])
291 .with_unexpected(Span::new_unchecked(0, 1)),
292 );
293 }
294 if radix == b'O' {
295 let start = value.offset_from(&raw.as_str());
296 let end = start + 2;
297 error.report_error(
298 ParseError::new("radix must be lowercase")
299 .with_context(Span::new_unchecked(0, raw.len()))
300 .with_expected(&[Expected::Literal("0o")])
301 .with_unexpected(Span::new_unchecked(start, end)),
302 );
303 }
304 let radix = IntegerRadix::Oct;
305 let kind = ScalarKind::Integer(radix);
306 let stream = &value[2..];
307 if ensure_radixed_value(stream, raw, radix, error) {
308 decode_float_or_integer(stream, raw, kind, output, error)
309 } else {
310 kind
311 }
312 }
313 b'b' | b'B' => {
314 if value.contains(" ") {
315 return decode_invalid(raw, output, error);
317 }
318 if signed {
319 error.report_error(
320 ParseError::new("integers with a radix cannot be signed")
321 .with_context(Span::new_unchecked(0, raw.len()))
322 .with_expected(&[])
323 .with_unexpected(Span::new_unchecked(0, 1)),
324 );
325 }
326 if radix == b'B' {
327 let start = value.offset_from(&raw.as_str());
328 let end = start + 2;
329 error.report_error(
330 ParseError::new("radix must be lowercase")
331 .with_context(Span::new_unchecked(0, raw.len()))
332 .with_expected(&[Expected::Literal("0b")])
333 .with_unexpected(Span::new_unchecked(start, end)),
334 );
335 }
336 let radix = IntegerRadix::Bin;
337 let kind = ScalarKind::Integer(radix);
338 let stream = &value[2..];
339 if ensure_radixed_value(stream, raw, radix, error) {
340 decode_float_or_integer(stream, raw, kind, output, error)
341 } else {
342 kind
343 }
344 }
345 b'd' | b'D' => {
346 if value.contains(" ") {
347 return decode_invalid(raw, output, error);
349 }
350 if signed {
351 error.report_error(
352 ParseError::new("integers with a radix cannot be signed")
353 .with_context(Span::new_unchecked(0, raw.len()))
354 .with_expected(&[])
355 .with_unexpected(Span::new_unchecked(0, 1)),
356 );
357 }
358 let radix = IntegerRadix::Dec;
359 let kind = ScalarKind::Integer(radix);
360 let stream = &value[2..];
361 error.report_error(
362 ParseError::new("redundant integer number prefix")
363 .with_context(Span::new_unchecked(0, raw.len()))
364 .with_expected(&[])
365 .with_unexpected(Span::new_unchecked(0, 2)),
366 );
367 if ensure_radixed_value(stream, raw, radix, error) {
368 decode_float_or_integer(stream, raw, kind, output, error)
369 } else {
370 kind
371 }
372 }
373 _ => decode_datetime_or_float_or_integer(value, raw, output, error),
374 }
375 }
376}
377
378fn decode_datetime_or_float_or_integer<'i>(
379 value: &'i str,
380 raw: Raw<'i>,
381 output: &mut dyn StringBuilder<'i>,
382 error: &mut dyn ErrorSink,
383) -> ScalarKind {
384 let Some(digit_end) = value
385 .as_bytes()
386 .offset_for(|b| !(b'0'..=b'9').contains_token(b))
387 else {
388 let kind = ScalarKind::Integer(IntegerRadix::Dec);
389 let stream = raw.as_str();
390 if ensure_no_leading_zero(value, raw, error) {
391 return decode_float_or_integer(stream, raw, kind, output, error);
392 } else {
393 return kind;
394 }
395 };
396
397 #[cfg(feature = "unsafe")] let rest = unsafe { &value.get_unchecked(digit_end..) };
399 #[cfg(not(feature = "unsafe"))]
400 let rest = &value[digit_end..];
401
402 if rest.starts_with("-") || rest.starts_with(":") {
403 decode_as_is(raw, ScalarKind::DateTime, output, error)
404 } else if rest.contains(" ") {
405 decode_invalid(raw, output, error)
406 } else if is_float(rest) {
407 let kind = ScalarKind::Float;
408 let stream = raw.as_str();
409 if ensure_float(value, raw, error) {
410 decode_float_or_integer(stream, raw, kind, output, error)
411 } else {
412 kind
413 }
414 } else if rest.starts_with("_") {
415 let kind = ScalarKind::Integer(IntegerRadix::Dec);
416 let stream = raw.as_str();
417 if ensure_no_leading_zero(value, raw, error) {
418 decode_float_or_integer(stream, raw, kind, output, error)
419 } else {
420 kind
421 }
422 } else {
423 decode_invalid(raw, output, error)
424 }
425}
426
427#[must_use]
441fn ensure_float<'i>(mut value: &'i str, raw: Raw<'i>, error: &mut dyn ErrorSink) -> bool {
442 let mut is_valid = true;
443
444 is_valid &= ensure_dec_uint(&mut value, raw, false, "invalid mantissa", error);
445
446 if value.starts_with(".") {
447 let _ = value.next_token();
448 is_valid &= ensure_dec_uint(&mut value, raw, true, "invalid fraction", error);
449 }
450
451 if value.starts_with(['e', 'E']) {
452 let _ = value.next_token();
453 if value.starts_with(['+', '-']) {
454 let _ = value.next_token();
455 }
456 is_valid &= ensure_dec_uint(&mut value, raw, true, "invalid exponent", error);
457 }
458
459 if !value.is_empty() {
460 let start = value.offset_from(&raw.as_str());
461 let end = raw.len();
462 error.report_error(
463 ParseError::new(ScalarKind::Float.invalid_description())
464 .with_context(Span::new_unchecked(0, raw.len()))
465 .with_expected(&[])
466 .with_unexpected(Span::new_unchecked(start, end)),
467 );
468 is_valid = false;
469 }
470
471 is_valid
472}
473
474#[must_use]
475fn ensure_dec_uint<'i>(
476 value: &mut &'i str,
477 raw: Raw<'i>,
478 zero_prefix: bool,
479 invalid_description: &'static str,
480 error: &mut dyn ErrorSink,
481) -> bool {
482 let mut is_valid = true;
483
484 let start = *value;
485 let mut digit_count = 0;
486 while let Some(current) = value.chars().next() {
487 if current.is_ascii_digit() {
488 digit_count += 1;
489 } else if current == '_' {
490 } else {
491 break;
492 }
493 let _ = value.next_token();
494 }
495
496 match digit_count {
497 0 => {
498 let start = start.offset_from(&raw.as_str());
499 let end = start;
500 error.report_error(
501 ParseError::new(invalid_description)
502 .with_context(Span::new_unchecked(0, raw.len()))
503 .with_expected(&[Expected::Description("digits")])
504 .with_unexpected(Span::new_unchecked(start, end)),
505 );
506 is_valid = false;
507 }
508 1 => {}
509 _ if start.starts_with("0") && !zero_prefix => {
510 let start = start.offset_from(&raw.as_str());
511 let end = start + 1;
512 error.report_error(
513 ParseError::new("unexpected leading zero")
514 .with_context(Span::new_unchecked(0, raw.len()))
515 .with_expected(&[])
516 .with_unexpected(Span::new_unchecked(start, end)),
517 );
518 is_valid = false;
519 }
520 _ => {}
521 }
522
523 is_valid
524}
525
526#[must_use]
527fn ensure_no_leading_zero<'i>(value: &'i str, raw: Raw<'i>, error: &mut dyn ErrorSink) -> bool {
528 let mut is_valid = true;
529
530 if value.starts_with("0") {
531 let start = value.offset_from(&raw.as_str());
532 let end = start + 1;
533 error.report_error(
534 ParseError::new("unexpected leading zero")
535 .with_context(Span::new_unchecked(0, raw.len()))
536 .with_expected(&[])
537 .with_unexpected(Span::new_unchecked(start, end)),
538 );
539 is_valid = false;
540 }
541
542 is_valid
543}
544
545#[must_use]
546fn ensure_radixed_value(
547 value: &str,
548 raw: Raw<'_>,
549 radix: IntegerRadix,
550 error: &mut dyn ErrorSink,
551) -> bool {
552 let mut is_valid = true;
553
554 let invalid = ['+', '-'];
555 let value = if let Some(value) = value.strip_prefix(invalid) {
556 let pos = raw.as_str().find(invalid).unwrap();
557 error.report_error(
558 ParseError::new("unexpected sign")
559 .with_context(Span::new_unchecked(0, raw.len()))
560 .with_expected(&[])
561 .with_unexpected(Span::new_unchecked(pos, pos + 1)),
562 );
563 is_valid = false;
564 value
565 } else {
566 value
567 };
568
569 let valid = radix.validator();
570 for (index, c) in value.char_indices() {
571 if !valid(c) && c != '_' {
572 let pos = value.offset_from(&raw.as_str()) + index;
573 error.report_error(
574 ParseError::new(radix.invalid_description())
575 .with_context(Span::new_unchecked(0, raw.len()))
576 .with_unexpected(Span::new_unchecked(pos, pos)),
577 );
578 is_valid = false;
579 }
580 }
581
582 is_valid
583}
584
585fn decode_float_or_integer<'i>(
586 stream: &'i str,
587 raw: Raw<'i>,
588 kind: ScalarKind,
589 output: &mut dyn StringBuilder<'i>,
590 error: &mut dyn ErrorSink,
591) -> ScalarKind {
592 output.clear();
593
594 let underscore = "_";
595
596 if has_underscore(stream) {
597 if stream.starts_with(underscore) {
598 error.report_error(
599 ParseError::new("`_` may only go between digits")
600 .with_context(Span::new_unchecked(0, raw.len()))
601 .with_expected(&[])
602 .with_unexpected(Span::new_unchecked(0, underscore.len())),
603 );
604 }
605 if 1 < stream.len() && stream.ends_with(underscore) {
606 let start = stream.offset_from(&raw.as_str());
607 let end = start + stream.len();
608 error.report_error(
609 ParseError::new("`_` may only go between digits")
610 .with_context(Span::new_unchecked(0, raw.len()))
611 .with_expected(&[])
612 .with_unexpected(Span::new_unchecked(end - underscore.len(), end)),
613 );
614 }
615
616 for part in stream.split(underscore) {
617 let part_start = part.offset_from(&raw.as_str());
618 let part_end = part_start + part.len();
619
620 if 0 < part_start {
621 let first = part.as_bytes().first().copied().unwrap_or(b'0');
622 if !is_any_digit(first, kind) {
623 let start = part_start - underscore.len();
624 let end = part_start;
625 debug_assert_eq!(&raw.as_str()[start..end], underscore);
626 error.report_error(
627 ParseError::new("`_` may only go between digits")
628 .with_context(Span::new_unchecked(0, raw.len()))
629 .with_unexpected(Span::new_unchecked(start, end)),
630 );
631 }
632 }
633 if 1 < part.len() && part_end < raw.len() {
634 let last = part.as_bytes().last().copied().unwrap_or(b'0');
635 if !is_any_digit(last, kind) {
636 let start = part_end;
637 let end = start + underscore.len();
638 debug_assert_eq!(&raw.as_str()[start..end], underscore);
639 error.report_error(
640 ParseError::new("`_` may only go between digits")
641 .with_context(Span::new_unchecked(0, raw.len()))
642 .with_unexpected(Span::new_unchecked(start, end)),
643 );
644 }
645 }
646
647 if part.is_empty() && part_start != 0 && part_end != raw.len() {
648 let start = part_start;
649 let end = start + 1;
650 error.report_error(
651 ParseError::new("`_` may only go between digits")
652 .with_context(Span::new_unchecked(0, raw.len()))
653 .with_unexpected(Span::new_unchecked(start, end)),
654 );
655 }
656
657 if !part.is_empty() && !output.push_str(part) {
658 error.report_error(
659 ParseError::new(ALLOCATION_ERROR)
660 .with_unexpected(Span::new_unchecked(part_start, part_end)),
661 );
662 }
663 }
664 } else {
665 if !output.push_str(stream) {
666 error.report_error(
667 ParseError::new(ALLOCATION_ERROR)
668 .with_unexpected(Span::new_unchecked(0, raw.len())),
669 );
670 }
671 }
672
673 kind
674}
675
676fn is_any_digit(b: u8, kind: ScalarKind) -> bool {
677 if kind == ScalarKind::Float {
678 is_dec_integer_digit(b)
679 } else {
680 is_any_integer_digit(b)
681 }
682}
683
684fn is_any_integer_digit(b: u8) -> bool {
685 (b'0'..=b'9', b'a'..=b'f', b'A'..=b'F').contains_token(b)
686}
687
688fn is_dec_integer_digit(b: u8) -> bool {
689 (b'0'..=b'9').contains_token(b)
690}
691
692fn has_underscore(raw: &str) -> bool {
693 raw.as_bytes().find_slice(b'_').is_some()
694}
695
696fn is_float(raw: &str) -> bool {
697 raw.as_bytes().find_slice((b'.', b'e', b'E')).is_some()
698}
699
700fn decode_as_is<'i>(
701 raw: Raw<'i>,
702 kind: ScalarKind,
703 output: &mut dyn StringBuilder<'i>,
704 error: &mut dyn ErrorSink,
705) -> ScalarKind {
706 let kind = decode_as(raw, raw.as_str(), kind, output, error);
707 kind
708}
709
710fn decode_as<'i>(
711 raw: Raw<'i>,
712 symbol: &'i str,
713 kind: ScalarKind,
714 output: &mut dyn StringBuilder<'i>,
715 error: &mut dyn ErrorSink,
716) -> ScalarKind {
717 output.clear();
718 if !output.push_str(symbol) {
719 error.report_error(
720 ParseError::new(ALLOCATION_ERROR).with_unexpected(Span::new_unchecked(0, raw.len())),
721 );
722 }
723 kind
724}
725
726fn decode_symbol<'i>(
727 raw: Raw<'i>,
728 symbol: &'static str,
729 kind: ScalarKind,
730 expected: &'static [Expected],
731 output: &mut dyn StringBuilder<'i>,
732 error: &mut dyn ErrorSink,
733) -> ScalarKind {
734 if raw.as_str() != symbol {
735 if raw.as_str().contains(" ") {
736 return decode_invalid(raw, output, error);
737 } else {
738 error.report_error(
739 ParseError::new(kind.invalid_description())
740 .with_context(Span::new_unchecked(0, raw.len()))
741 .with_expected(expected)
742 .with_unexpected(Span::new_unchecked(0, raw.len())),
743 );
744 }
745 }
746
747 decode_as(raw, symbol, kind, output, error)
748}
749
750fn decode_invalid<'i>(
751 raw: Raw<'i>,
752 output: &mut dyn StringBuilder<'i>,
753 error: &mut dyn ErrorSink,
754) -> ScalarKind {
755 if raw.as_str().ends_with("'''") {
756 error.report_error(
757 ParseError::new("missing opening quote")
758 .with_context(Span::new_unchecked(0, raw.len()))
759 .with_expected(&[Expected::Literal(r#"'''"#)])
760 .with_unexpected(Span::new_unchecked(0, 0)),
761 );
762 } else if raw.as_str().ends_with(r#"""""#) {
763 error.report_error(
764 ParseError::new("missing opening quote")
765 .with_context(Span::new_unchecked(0, raw.len()))
766 .with_expected(&[Expected::Description("multi-line basic string")])
767 .with_expected(&[Expected::Literal(r#"""""#)])
768 .with_unexpected(Span::new_unchecked(0, 0)),
769 );
770 } else if raw.as_str().ends_with("'") {
771 error.report_error(
772 ParseError::new("missing opening quote")
773 .with_context(Span::new_unchecked(0, raw.len()))
774 .with_expected(&[Expected::Literal(r#"'"#)])
775 .with_unexpected(Span::new_unchecked(0, 0)),
776 );
777 } else if raw.as_str().ends_with(r#"""#) {
778 error.report_error(
779 ParseError::new("missing opening quote")
780 .with_context(Span::new_unchecked(0, raw.len()))
781 .with_expected(&[Expected::Literal(r#"""#)])
782 .with_unexpected(Span::new_unchecked(0, 0)),
783 );
784 } else {
785 error.report_error(
786 ParseError::new("string values must be quoted")
787 .with_context(Span::new_unchecked(0, raw.len()))
788 .with_expected(&[Expected::Description("literal string")])
789 .with_unexpected(Span::new_unchecked(0, raw.len())),
790 );
791 }
792
793 output.clear();
794 if !output.push_str(raw.as_str()) {
795 error.report_error(
796 ParseError::new(ALLOCATION_ERROR).with_unexpected(Span::new_unchecked(0, raw.len())),
797 );
798 }
799 ScalarKind::String
800}