1use crate::error::TabnasError;
4use crate::options::{LexCheck, LexCheckResult, MatchTokenMatcher, Options};
5use crate::token::{
6 Point, Token, TIN_BD, TIN_CM, TIN_LN, TIN_NR, TIN_SP, TIN_ST, TIN_TX, TIN_VL, TIN_ZZ,
7};
8use crate::value::Value;
9use regex::Regex;
10use std::panic::{catch_unwind, AssertUnwindSafe};
11use std::sync::Arc;
12
13pub struct Lexer<'a> {
14 src: &'a str,
15 chars: Vec<char>,
16 byte_indices: Vec<usize>,
17 char_len: usize,
18 idx: usize,
19 ri: usize,
20 ci: usize,
21 options: Arc<Options>,
22 ignore_tins: Vec<crate::Tin>,
23 char_sets: crate::text::CharSets,
24 err: Option<TabnasError>,
25 end_reached: bool,
26 exclude_regex: Option<Arc<Regex>>,
29 want: Option<Vec<crate::Tin>>,
30 standalone: Option<(crate::Rule, crate::Context)>,
31}
32
33#[derive(Clone)]
34pub(crate) struct LexerState {
35 idx: usize,
36 ri: usize,
37 ci: usize,
38 err: Option<TabnasError>,
39 end_reached: bool,
40}
41
42#[derive(Clone)]
45pub struct RelexCheckpoint {
46 state: LexerState,
47 replay: std::collections::VecDeque<Token>,
48}
49
50enum CheckFlow {
51 Continue,
52 Skip,
53 Token(Box<Token>),
54}
55
56type LexResult<T> = Result<T, Box<TabnasError>>;
68
69pub(crate) fn compile_number_exclude(options: &Options) -> Option<Arc<Regex>> {
80 let pattern = options.number.exclude.as_deref()?;
81 Regex::new(pattern).ok().map(Arc::new)
82}
83
84impl<'a> Lexer<'a> {
85 pub fn new(src: &'a str, mut options: Options) -> Self {
86 options.sort_for_lexing();
91 let exclude_regex = compile_number_exclude(&options);
92 Self::with_shared(src, Arc::new(options), exclude_regex)
93 }
94
95 pub(crate) fn with_shared(
98 src: &'a str,
99 options: Arc<Options>,
100 exclude_regex: Option<Arc<Regex>>,
101 ) -> Self {
102 let mut chars = Vec::new();
103 let mut byte_indices = Vec::new();
104 for (b_idx, c) in src.char_indices() {
105 chars.push(c);
106 byte_indices.push(b_idx);
107 }
108 let char_len = chars.len();
109
110 Lexer {
111 src,
112 chars,
113 byte_indices,
114 char_len,
115 idx: 0,
116 ri: 1,
117 ci: 1,
118 ignore_tins: options.ignore_tins(),
119 char_sets: options.char_sets(),
120 options,
121 err: None,
122 end_reached: false,
123 exclude_regex,
124 want: None,
125 standalone: None,
126 }
127 }
128
129 fn current_point(&self) -> Point {
130 Point {
131 len: self.src.len(),
132 site: crate::Site {
133 si: self.byte_position(),
134 pos: self.idx,
135 ri: self.ri,
136 ci: self.ci,
137 },
138 }
139 }
140
141 fn source_span(&self, start: usize, end: usize) -> String {
156 self.chars[start..end.min(self.char_len)].iter().collect()
157 }
158
159 fn state(&self) -> LexerState {
160 LexerState {
161 idx: self.idx,
162 ri: self.ri,
163 ci: self.ci,
164 err: self.err.clone(),
165 end_reached: self.end_reached,
166 }
167 }
168
169 pub fn source(&self) -> &str {
171 self.src
172 }
173
174 pub fn remaining(&self) -> &str {
176 &self.src[self.byte_position()..]
177 }
178
179 pub fn forward(&self, max_chars: usize) -> &str {
182 let remaining = self.remaining();
183 let end = remaining
184 .char_indices()
185 .nth(max_chars)
186 .map_or(remaining.len(), |(index, _)| index);
187 &remaining[..end]
188 }
189
190 pub fn point(&self) -> Point {
192 self.current_point()
193 }
194
195 pub fn advance_chars(&mut self, count: usize) -> bool {
198 if self.idx.saturating_add(count) > self.char_len {
199 return false;
200 }
201 for _ in 0..count {
202 self.advance();
203 }
204 true
205 }
206
207 pub fn token(
209 &self,
210 name: impl AsRef<str>,
211 tin: crate::Tin,
212 value: Value,
213 source: impl Into<crate::TokenText>,
214 point: Point,
215 ) -> Token {
216 Token::new(name, tin, value, source, point)
217 }
218
219 pub fn token_tin(&mut self, name: impl Into<String>) -> crate::Tin {
221 Arc::make_mut(&mut self.options).register_token(name)
222 }
223
224 pub fn token_name(&self, tin: crate::Tin) -> String {
226 self.options.token_name(tin)
227 }
228
229 pub fn alt_enabled(&self, alt: &crate::AltSpec) -> bool {
237 crate::parser::groups_enabled(alt, &self.options)
238 }
239
240 pub fn bad(&self, why: impl Into<String>) -> Token {
242 let point = self.current_point();
243 let source = self
244 .peek()
245 .map_or_else(String::new, |character| character.to_string());
246 let mut token = Token::new("#BD", TIN_BD, Value::Undefined, source, point);
247 token.err = crate::TokenCode::from(why.into());
248 token.why = token.err.clone();
249 token
250 }
251
252 pub fn bad_span(&self, why: impl Into<String>, start: usize, end: usize) -> Token {
255 let point = self.current_point();
256 let source = if start <= end && end <= self.char_len {
257 let start_byte = self
258 .byte_indices
259 .get(start)
260 .copied()
261 .unwrap_or(self.src.len());
262 let end_byte = self
263 .byte_indices
264 .get(end)
265 .copied()
266 .unwrap_or(self.src.len());
267 self.src[start_byte..end_byte].to_string()
268 } else {
269 self.peek()
270 .map_or_else(String::new, |character| character.to_string())
271 };
272 let mut token = Token::new("#BD", TIN_BD, Value::Undefined, source, point);
273 token.err = crate::TokenCode::from(why.into());
274 token.why = token.err.clone();
275 token
276 }
277
278 fn byte_position(&self) -> usize {
279 self.byte_indices
280 .get(self.idx)
281 .copied()
282 .unwrap_or(self.src.len())
283 }
284
285 fn advance(&mut self) -> Option<char> {
286 if self.idx < self.char_len {
287 let c = self.chars[self.idx];
288 self.idx += 1;
289 if self.char_sets.row.contains(c) {
290 self.ri += 1;
291 self.ci = 1;
292 } else {
293 self.ci += 1;
294 }
295 Some(c)
296 } else {
297 None
298 }
299 }
300
301 fn peek(&self) -> Option<char> {
302 if self.idx < self.char_len {
303 Some(self.chars[self.idx])
304 } else {
305 None
306 }
307 }
308
309 fn peek_at(&self, offset: usize) -> Option<char> {
310 let i = self.idx + offset;
311 if i < self.char_len {
312 Some(self.chars[i])
313 } else {
314 None
315 }
316 }
317
318 fn wants(&self, tin: crate::Tin) -> bool {
319 self.want
320 .as_ref()
321 .is_none_or(|wanted| wanted.contains(&tin))
322 }
323
324 fn run_check(&mut self, check: Option<LexCheck>, point: Point) -> CheckFlow {
325 let Some(check) = check else {
326 return CheckFlow::Continue;
327 };
328 let remaining = &self.src[self.byte_position()..];
329 let result = check
330 .run_imperative(self)
331 .or_else(|| check.run(remaining))
332 .unwrap_or(LexCheckResult::Continue);
333 match result {
334 LexCheckResult::Continue => CheckFlow::Continue,
335 LexCheckResult::Skip => CheckFlow::Skip,
336 LexCheckResult::NativeToken(token) => CheckFlow::Token(token),
337 LexCheckResult::Token(token)
338 if !token.source.is_empty() && remaining.starts_with(&token.source) =>
339 {
340 let tin = if token.tin < 0 {
341 self.options.token(&token.name).unwrap_or(token.tin)
342 } else {
343 token.tin
344 };
345 if tin < 0 {
346 return CheckFlow::Skip;
347 }
348 for _ in token.source.chars() {
349 self.advance();
350 }
351 CheckFlow::Token(Box::new(Token::new(
352 token.name,
353 tin,
354 token.value,
355 token.source,
356 point,
357 )))
358 }
359 LexCheckResult::Token(_) => CheckFlow::Skip,
360 }
361 }
362
363 #[inline]
371 fn run_custom_matchers(
372 &mut self,
373 index: &mut usize,
374 before: f64,
375 point: Point,
376 plugin: &mut Option<(&mut crate::Rule, &mut crate::Context)>,
377 ) -> Option<Token> {
378 if *index >= self.options.lex.matchers.len() {
379 return None;
380 }
381 self.run_remaining_custom_matchers(index, before, point, plugin)
382 }
383
384 #[inline(never)]
385 fn run_remaining_custom_matchers(
386 &mut self,
387 index: &mut usize,
388 before: f64,
389 point: Point,
390 plugin: &mut Option<(&mut crate::Rule, &mut crate::Context)>,
391 ) -> Option<Token> {
392 while let Some(matcher) = self
393 .options
394 .lex
395 .matchers
396 .get_index(*index)
397 .map(|(_, matcher)| matcher)
398 .filter(|matcher| matcher.order < before)
399 .cloned()
400 {
401 *index += 1;
402 let remaining = &self.src[self.byte_position()..];
403 let saved = self.state();
404 let token = if let Some(callback) = matcher.imperative.as_ref() {
405 let Some((rule, context)) = plugin.as_mut() else {
406 continue;
407 };
408 callback(self, rule, context)
409 } else {
410 matcher
411 .matcher
412 .as_ref()
413 .and_then(|callback| callback(remaining))
414 .filter(|token| {
415 !token.source.is_empty() && remaining.starts_with(&token.source)
416 })
417 .map(|token| {
418 Token::new(token.name, token.tin, token.value, token.source, point)
419 })
420 };
421 let Some(mut token) = token else {
422 if self.want.is_some() {
423 self.restore(saved);
424 }
425 continue;
426 };
427
428 let tin = if token.tin < 0 {
432 self.options.token(&token.name).unwrap_or(token.tin)
433 } else {
434 token.tin
435 };
436 if tin < 0 || !self.wants(tin) {
437 self.restore(saved);
438 continue;
439 }
440 if matcher.imperative.is_none() {
441 for _ in token.src.chars() {
442 self.advance();
443 }
444 }
445 token.tin = tin;
446 return Some(token);
447 }
448 None
449 }
450
451 fn is_text_delimiter_here(&self) -> bool {
452 self.is_text_delimiter_at(self.idx)
453 }
454
455 fn is_text_delimiter_at(&self, index: usize) -> bool {
456 let Some(ch) = self.chars.get(index).copied() else {
457 return true;
458 };
459 let remaining = &self.src[self.byte_indices[index]..];
460 (self.options.space.lex && self.char_sets.space.contains(ch))
461 || (self.options.fixed.lex
462 && self
463 .options
464 .fixed
465 .tokens
466 .values()
467 .any(|token| !token.source.is_empty() && remaining.starts_with(&token.source)))
468 || (self.options.line.lex
469 && (self.char_sets.line_ends.contains(ch) || matches!(ch, '\u{2028}' | '\u{2029}')))
470 || (self.options.comment.lex
471 && self.options.comment.definitions.values().any(|definition| {
472 definition.lex
473 && !definition.start.is_empty()
474 && remaining.starts_with(&definition.start)
475 }))
476 || self
477 .options
478 .ender
479 .iter()
480 .any(|ender| !ender.is_empty() && remaining.starts_with(ender))
481 }
482
483 pub fn next_token(&mut self) -> Result<Token, TabnasError> {
485 let point = self.current_point();
486 let result = match catch_unwind(AssertUnwindSafe(|| {
487 if let Some(ref error) = self.err {
488 return Err(Box::new(error.clone()));
489 }
490
491 loop {
492 let token = self.next_raw(None)?;
493 if !self.ignore_tins.contains(&token.tin) {
494 return Ok(token);
495 }
496 }
497 })) {
498 Ok(result) => result,
499 Err(payload) => self.record_panic(payload, "Lexer::next_token", point),
500 };
501 result.map_err(|error| *error)
503 }
504
505 pub fn next_raw_token(&mut self) -> Result<Token, TabnasError> {
507 let point = self.current_point();
508 let result = match catch_unwind(AssertUnwindSafe(|| self.next_raw(None))) {
509 Ok(result) => result,
510 Err(payload) => self.record_panic(payload, "Lexer::next_raw_token", point),
511 };
512 result.map_err(|error| *error)
513 }
514
515 pub fn next_raw_for_rule(
519 &mut self,
520 rule: &mut crate::Rule,
521 context: &mut crate::Context,
522 ) -> LexResult<Token> {
523 if let Some(token) = context.next_replay() {
524 Ok(token)
525 } else {
526 self.next_raw_with(None, Some((rule, context)))
527 }
528 }
529
530 pub fn next_for_rule(
532 &mut self,
533 rule: &mut crate::Rule,
534 context: &mut crate::Context,
535 ) -> LexResult<Token> {
536 loop {
537 let token = self.next_raw_for_rule(rule, context)?;
538 if !self.ignore_tins.contains(&token.tin) {
539 return Ok(token);
540 }
541 }
542 }
543
544 pub fn relex_for_rule(
548 &mut self,
549 from: &Token,
550 wanted: &[crate::Tin],
551 rule: &mut crate::Rule,
552 context: &mut crate::Context,
553 ) -> Option<(Token, RelexCheckpoint)> {
554 self.relex(from, wanted, rule, context)
555 }
556
557 pub fn unrelex(&mut self, checkpoint: RelexCheckpoint, context: &mut crate::Context) {
560 self.restore(checkpoint.state);
561 context.restore_replay(checkpoint.replay);
562 }
563
564 fn record_panic(
565 &mut self,
566 payload: Box<dyn std::any::Any + Send>,
567 api: &str,
568 point: Point,
569 ) -> LexResult<Token> {
570 let error = TabnasError::from_panic(
571 payload,
572 api,
573 self.src,
574 point.site.pos,
575 point.site.ri,
576 point.site.ci,
577 &self.options,
578 );
579 self.err = Some(error.clone());
580 Err(Box::new(error))
581 }
582
583 pub(crate) fn next_rule_token(
587 &mut self,
588 expected_match_tins: &[crate::Tin],
589 rule: &mut crate::Rule,
590 context: &mut crate::Context,
591 ) -> LexResult<Token> {
592 self.next_raw_with(Some(expected_match_tins), Some((rule, context)))
593 }
594
595 pub(crate) fn recover_after_error(&mut self, to_line_end: bool) {
599 if to_line_end {
600 while let Some(character) = self.peek() {
601 self.advance();
602 if matches!(character, '\n' | '\r' | '\u{2028}' | '\u{2029}') {
603 break;
604 }
605 }
606 }
607 self.err = None;
608 if self.idx < self.char_len {
609 self.end_reached = false;
610 }
611 }
612
613 pub(crate) fn relex(
618 &mut self,
619 from: &Token,
620 wanted: &[crate::Tin],
621 rule: &mut crate::Rule,
622 context: &mut crate::Context,
623 ) -> Option<(Token, RelexCheckpoint)> {
624 if from.src.is_empty() || from.site.pos > self.char_len || wanted.is_empty() {
625 return None;
626 }
627 let saved = self.state();
628 let replay = context.take_replay();
632 self.idx = from.site.pos;
633 self.ri = from.site.ri;
634 self.ci = from.site.ci;
635 self.err = None;
636 self.end_reached = false;
637 self.want = Some(wanted.to_vec());
638 let recut = self.next_raw_with(None, Some((rule, context))).ok();
639 self.want = None;
640 match recut.filter(|token| wanted.contains(&token.tin)) {
641 Some(mut token) => {
642 token.ignored = from.ignored.clone();
643 Some((
644 token,
645 RelexCheckpoint {
646 state: saved,
647 replay,
648 },
649 ))
650 }
651 None => {
652 self.restore(saved);
653 context.restore_replay(replay);
656 None
657 }
658 }
659 }
660
661 pub(crate) fn restore(&mut self, state: LexerState) {
662 self.idx = state.idx;
663 self.ri = state.ri;
664 self.ci = state.ci;
665 self.err = state.err;
666 self.end_reached = state.end_reached;
667 self.want = None;
668 }
669
670 fn next_raw(&mut self, expected_match_tins: Option<&[crate::Tin]>) -> LexResult<Token> {
671 let (mut rule, mut context) = match self.standalone.take() {
676 Some(pair) => pair,
677 None => (
678 crate::Rule::new("#NORULE", Value::Undefined),
679 crate::Context::new(
680 self.options.rewind.history,
681 self.src,
682 Value::Undefined,
683 Arc::clone(&self.options),
684 crate::InstanceInfo::default(),
685 ),
686 ),
687 };
688 let result = self.next_raw_with(expected_match_tins, Some((&mut rule, &mut context)));
689 self.standalone = Some((rule, context));
690 result
691 }
692
693 fn modify_text_value(
694 &mut self,
695 mut value: Value,
696 plugin: &mut Option<(&mut crate::Rule, &mut crate::Context)>,
697 ) -> Value {
698 if self.options.text.modify.is_empty() {
699 return value;
700 }
701 let modifiers = self.options.text.modify.clone();
702 let options = self.options.clone();
703 let Some((rule, context)) = plugin.as_mut() else {
704 panic!("imperative text modifier requires an active lexer context");
705 };
706 for modifier in modifiers {
707 value = modifier.run(value, self, rule, context, &options);
708 }
709 value
710 }
711
712 fn next_raw_with(
713 &mut self,
714 expected_match_tins: Option<&[crate::Tin]>,
715 plugin: Option<(&mut crate::Rule, &mut crate::Context)>,
716 ) -> LexResult<Token> {
717 let result = self.next_raw_inner(expected_match_tins, plugin);
718 match result {
719 Ok(token) => Ok(token),
720 Err(mut error) => {
721 error.apply_options(&self.options);
722 self.err = Some((*error).clone());
723 Err(error)
724 }
725 }
726 }
727
728 fn next_raw_inner(
729 &mut self,
730 expected_match_tins: Option<&[crate::Tin]>,
731 mut plugin: Option<(&mut crate::Rule, &mut crate::Context)>,
732 ) -> LexResult<Token> {
733 if self.end_reached {
734 return Ok(Token::new(
735 "#ZZ",
736 TIN_ZZ,
737 Value::Undefined,
738 "",
739 self.current_point(),
740 ));
741 }
742
743 if self.idx >= self.char_len {
744 self.end_reached = true;
745 return Ok(Token::new(
746 "#ZZ",
747 TIN_ZZ,
748 Value::Undefined,
749 "",
750 self.current_point(),
751 ));
752 }
753
754 let pnt = self.current_point();
755 let c = self.peek().unwrap();
756 let mut custom_index = 0;
757
758 if let Some(token) =
759 self.run_custom_matchers(&mut custom_index, 1_000_000.0, pnt, &mut plugin)
760 {
761 return Ok(token);
762 }
763
764 let match_skipped = if self.options.match_lex
766 && (!self.options.match_values.is_empty()
767 || self
768 .options
769 .match_tokens
770 .values()
771 .any(|matcher| self.wants(matcher.tin)))
772 {
773 match self.run_check(self.options.match_check.clone(), pnt) {
774 CheckFlow::Continue => false,
775 CheckFlow::Skip => true,
776 CheckFlow::Token(token) => return Ok(*token),
777 }
778 } else {
779 false
780 };
781 let remaining = &self.src[self.byte_position()..];
782 let custom_value = (self.options.match_lex && !match_skipped && self.want.is_none())
783 .then(|| {
784 self.options
785 .match_values
786 .values()
787 .find_map(|matcher| match &matcher.matcher {
788 MatchTokenMatcher::Callback(callback) => callback(remaining)
789 .filter(|result| {
790 !result.source.is_empty() && remaining.starts_with(&result.source)
791 })
792 .map(|result| (result.source, result.value)),
793 MatchTokenMatcher::Regex(regex) => {
794 let captures = regex.captures(remaining)?;
795 let found = captures
796 .get(0)
797 .filter(|found| found.start() == 0 && !found.as_str().is_empty())?;
798 let source = found.as_str().to_string();
799 let value = matcher.transform.as_ref().map_or_else(
800 || {
801 matcher
802 .val
803 .clone()
804 .unwrap_or_else(|| Value::String(source.clone()))
805 },
806 |transform| {
807 let groups = captures
808 .iter()
809 .map(|capture| {
810 capture.map_or_else(String::new, |value| {
811 value.as_str().into()
812 })
813 })
814 .collect::<Vec<_>>();
815 transform(&groups)
816 },
817 );
818 Some((source, value))
819 }
820 })
821 })
822 .flatten();
823 if let Some((source, value)) = custom_value {
824 for _ in source.chars() {
825 self.advance();
826 }
827 return Ok(Token::new("#VL", TIN_VL, value, source, pnt));
828 }
829
830 let remaining = &self.src[self.byte_position()..];
831 let custom = (self.options.match_lex
842 && !match_skipped
843 && !self.options.match_tokens.is_empty())
844 .then(|| {
845 let mut fix_len: Option<usize> = None;
881 let compute_fix_len = || {
882 if self.want.is_none() && self.options.fixed.lex {
883 expected_match_tins.map_or(0, |expected| {
884 self.options
885 .fixed
886 .tokens
887 .values()
888 .filter(|token| {
889 !token.source.is_empty()
890 && expected.contains(&token.tin)
891 && remaining.starts_with(&token.source)
892 })
893 .map(|token| token.source.len())
894 .max()
895 .unwrap_or(0)
896 })
897 } else {
898 0
899 }
900 };
901 let passes = if self.want.is_some() { 1 } else { 2 };
902 (0..passes).find_map(|pass| {
903 self.options.match_tokens.values().find_map(|matcher| {
904 if !self.wants(matcher.tin) {
905 return None;
906 }
907 if self.want.is_none() {
908 let expected = expected_match_tins
909 .is_none_or(|expected| expected.contains(&matcher.tin));
910 if pass == 0 {
911 if !expected {
912 return None;
913 }
914 } else if expected || !matcher.eager {
915 return None;
916 }
917 }
918 let result = match &matcher.matcher {
919 MatchTokenMatcher::Regex(regex) => regex
920 .find(remaining)
921 .filter(|found| found.start() == 0)
922 .filter(|found| {
927 pass == 0 || {
928 let fix_len = *fix_len.get_or_insert_with(compute_fix_len);
929 fix_len == 0 || found.len() > fix_len
930 }
931 })
932 .map(|found| {
933 let source = found.as_str().to_string();
934 (source.clone(), Value::String(source))
935 }),
936 MatchTokenMatcher::Callback(callback) => callback(remaining)
937 .filter(|result| {
938 !result.source.is_empty() && remaining.starts_with(&result.source)
939 })
940 .map(|result| (result.source, result.value)),
941 };
942 result.map(|(source, value)| (matcher.name.clone(), matcher.tin, source, value))
943 })
944 })
945 });
946 if let Some(Some((name, tin, matched, value))) = custom {
947 for _ in matched.chars() {
948 self.advance();
949 }
950 return Ok(Token::new(name, tin, value, matched, pnt));
951 }
952
953 if let Some(token) =
954 self.run_custom_matchers(&mut custom_index, 2_000_000.0, pnt, &mut plugin)
955 {
956 return Ok(token);
957 }
958
959 let fixed_skipped = if self.options.fixed.lex {
961 match self.run_check(self.options.fixed.check.clone(), pnt) {
962 CheckFlow::Continue => false,
963 CheckFlow::Skip => true,
964 CheckFlow::Token(token) => return Ok(*token),
965 }
966 } else {
967 false
968 };
969 let remaining = &self.src[self.byte_position()..];
970 let first_byte = remaining.as_bytes().first().copied();
984 let fixed = (self.options.fixed.lex && !fixed_skipped)
985 .then(|| {
986 self.options
987 .fixed
988 .tokens
989 .values()
990 .enumerate()
991 .filter(|(_, token)| {
992 token.source.as_bytes().first().copied() == first_byte
993 && !token.source.is_empty()
994 && self.wants(token.tin)
995 && remaining.starts_with(&token.source)
996 })
997 .max_by_key(|(_, token)| token.source.len())
998 .map(|(index, token)| (index, token.source.chars().count()))
999 })
1000 .flatten();
1001 if let Some((index, source_chars)) = fixed {
1002 for _ in 0..source_chars {
1003 self.advance();
1004 }
1005 let (_, token) = self
1006 .options
1007 .fixed
1008 .tokens
1009 .get_index(index)
1010 .expect("index came from this table, which nothing writes to mid-parse");
1011 return Ok(Token::new(
1012 &token.name,
1013 token.tin,
1014 Value::String(token.source.clone()),
1015 token.source.as_str(),
1016 pnt,
1017 ));
1018 }
1019
1020 if let Some(token) =
1021 self.run_custom_matchers(&mut custom_index, 3_000_000.0, pnt, &mut plugin)
1022 {
1023 return Ok(token);
1024 }
1025
1026 let space_skipped = if self.options.space.lex && self.wants(TIN_SP) {
1028 match self.run_check(self.options.space.check.clone(), pnt) {
1029 CheckFlow::Continue => false,
1030 CheckFlow::Skip => true,
1031 CheckFlow::Token(token) => return Ok(*token),
1032 }
1033 } else {
1034 false
1035 };
1036 if self.options.space.lex
1037 && !space_skipped
1038 && self.wants(TIN_SP)
1039 && self.char_sets.space.contains(c)
1040 {
1041 let mut src = String::new();
1042 while let Some(ch) = self.peek() {
1043 if self.char_sets.space.contains(ch) {
1044 src.push(ch);
1045 self.advance();
1046 } else {
1047 break;
1048 }
1049 }
1050 return Ok(Token::new(
1051 "#SP",
1052 TIN_SP,
1053 Value::String(src.clone()),
1054 src,
1055 pnt,
1056 ));
1057 }
1058
1059 if let Some(token) =
1060 self.run_custom_matchers(&mut custom_index, 4_000_000.0, pnt, &mut plugin)
1061 {
1062 return Ok(token);
1063 }
1064
1065 let line_skipped = if self.options.line.lex && self.wants(TIN_LN) {
1067 match self.run_check(self.options.line.check.clone(), pnt) {
1068 CheckFlow::Continue => false,
1069 CheckFlow::Skip => true,
1070 CheckFlow::Token(token) => return Ok(*token),
1071 }
1072 } else {
1073 false
1074 };
1075 if self.options.line.lex
1076 && !line_skipped
1077 && self.wants(TIN_LN)
1078 && (self.char_sets.line_ends.contains(c))
1079 {
1080 let mut src = String::new();
1081 let mut seen = std::collections::HashSet::new();
1082 while let Some(ch) = self.peek() {
1083 if !self.char_sets.line_ends.contains(ch) {
1084 break;
1085 }
1086 if self.options.line.single && !seen.insert(ch) {
1087 break;
1088 }
1089 src.push(self.advance().expect("peeked character must advance"));
1090 }
1091 self.ci = 1;
1092 return Ok(Token::new(
1093 "#LN",
1094 TIN_LN,
1095 Value::String(src.clone()),
1096 src,
1097 pnt,
1098 ));
1099 }
1100
1101 if self.options.line.lex
1102 && !line_skipped
1103 && self.wants(TIN_LN)
1104 && (c == '\u{2028}' || c == '\u{2029}')
1105 {
1106 let bad_char = self.advance().expect("peeked character must advance");
1107 let err = TabnasError::new(
1108 "unexpected",
1109 bad_char.to_string(),
1110 self.src,
1111 pnt.site.pos,
1112 pnt.site.ri,
1113 pnt.site.ci,
1114 );
1115 self.err = Some(err.clone());
1116 return Err(Box::new(err));
1117 }
1118
1119 if let Some(token) =
1120 self.run_custom_matchers(&mut custom_index, 5_000_000.0, pnt, &mut plugin)
1121 {
1122 return Ok(token);
1123 }
1124
1125 let string_skipped = if self.options.string.lex && self.wants(TIN_ST) {
1129 match self.run_check(self.options.string.check.clone(), pnt) {
1130 CheckFlow::Continue => false,
1131 CheckFlow::Skip => true,
1132 CheckFlow::Token(token) => return Ok(*token),
1133 }
1134 } else {
1135 false
1136 };
1137 if self.options.string.lex
1138 && !string_skipped
1139 && self.wants(TIN_ST)
1140 && self.char_sets.string.contains(c)
1141 {
1142 let start = (self.idx, self.ri, self.ci);
1143 match self.match_string(c, pnt) {
1144 result @ Ok(_) => return result,
1145 Err(error) if !self.options.string.abandon => return Err(error),
1146 Err(_) => {
1147 (self.idx, self.ri, self.ci) = start;
1148 self.err = None;
1149 }
1150 }
1151 }
1152
1153 if let Some(token) =
1154 self.run_custom_matchers(&mut custom_index, 6_000_000.0, pnt, &mut plugin)
1155 {
1156 return Ok(token);
1157 }
1158
1159 let comment_skipped = if self.options.comment.lex && self.wants(TIN_CM) {
1161 match self.run_check(self.options.comment.check.clone(), pnt) {
1162 CheckFlow::Continue => false,
1163 CheckFlow::Skip => true,
1164 CheckFlow::Token(token) => return Ok(*token),
1165 }
1166 } else {
1167 false
1168 };
1169 if self.options.comment.lex && !comment_skipped && self.wants(TIN_CM) {
1170 if let Some(token) = self.match_comment(pnt)? {
1171 return Ok(token);
1172 }
1173 }
1174
1175 if let Some(token) =
1176 self.run_custom_matchers(&mut custom_index, 7_000_000.0, pnt, &mut plugin)
1177 {
1178 return Ok(token);
1179 }
1180
1181 let number_skipped = if self.options.number.lex && self.wants(TIN_NR) {
1183 match self.run_check(self.options.number.check.clone(), pnt) {
1184 CheckFlow::Continue => false,
1185 CheckFlow::Skip => true,
1186 CheckFlow::Token(token) => return Ok(*token),
1187 }
1188 } else {
1189 false
1190 };
1191 if self.options.number.lex
1192 && !number_skipped
1193 && self.wants(TIN_NR)
1194 && (c == '-' || c == '+' || c == '.' || c.is_ascii_digit())
1195 {
1196 if let Some(tkn) = self.match_number(pnt)? {
1197 return Ok(tkn);
1198 }
1199 }
1200
1201 if let Some(token) =
1202 self.run_custom_matchers(&mut custom_index, 8_000_000.0, pnt, &mut plugin)
1203 {
1204 return Ok(token);
1205 }
1206
1207 let text_matcher_wanted = self.wants(TIN_TX);
1214 let value_lex = self.options.value.lex && text_matcher_wanted;
1215 let text_lex = self.options.text.lex && text_matcher_wanted;
1216 let text_skipped = if text_lex || value_lex {
1217 match self.run_check(self.options.text.check.clone(), pnt) {
1218 CheckFlow::Continue => false,
1219 CheckFlow::Skip => true,
1220 CheckFlow::Token(token) => return Ok(*token),
1221 }
1222 } else {
1223 false
1224 };
1225 if (text_lex || value_lex) && !text_skipped && !self.is_text_delimiter_here() {
1226 let start = (self.idx, self.ri, self.ci);
1227 let source: &'a str = self.src;
1235 let remaining = &source[self.byte_position()..];
1236 let mut src = String::new();
1237 while let Some(ch) = self.peek() {
1238 if self.is_text_delimiter_here() {
1239 break;
1240 }
1241 src.push(ch);
1242 self.advance();
1243 }
1244
1245 let mut output = None;
1246 if value_lex {
1247 if let Some(definition) = self
1248 .options
1249 .value
1250 .definitions
1251 .get(&src)
1252 .filter(|definition| definition.matcher.is_none())
1253 .cloned()
1254 {
1255 output = Some(Token::new(
1256 "#VL",
1257 TIN_VL,
1258 definition
1259 .val
1260 .clone()
1261 .unwrap_or_else(|| Value::String(src.clone())),
1262 src.clone(),
1263 pnt,
1264 ));
1265 }
1266
1267 if output.is_none() {
1268 let mut definitions: Vec<_> = self
1269 .options
1270 .value
1271 .definitions
1272 .iter()
1273 .filter(|(_, definition)| definition.matcher.is_some())
1274 .map(|(name, definition)| (name.clone(), definition.clone()))
1275 .collect();
1276 definitions.sort_by(|(name_a, _), (name_b, _)| name_a.cmp(name_b));
1277 for (_, definition) in definitions {
1278 let regex = definition.matcher.as_ref().expect("filtered matcher");
1279 let target: &str = if definition.consume { remaining } else { &src };
1280 let Some(captures) = regex.captures(target) else {
1281 continue;
1282 };
1283 let Some(found) = captures.get(0).filter(|found| found.start() == 0) else {
1284 continue;
1285 };
1286 if !definition.consume && found.end() != target.len() {
1287 continue;
1288 }
1289 let matched = found.as_str().to_string();
1290 let value = definition.transform.as_ref().map_or_else(
1291 || {
1292 definition
1293 .val
1294 .clone()
1295 .unwrap_or_else(|| Value::String(matched.clone()))
1296 },
1297 |transform| {
1298 let groups = captures
1299 .iter()
1300 .map(|capture| {
1301 capture
1302 .map_or_else(String::new, |value| value.as_str().into())
1303 })
1304 .collect::<Vec<_>>();
1305 transform(&groups)
1306 },
1307 );
1308 if definition.consume {
1309 (self.idx, self.ri, self.ci) = start;
1310 for _ in matched.chars() {
1311 self.advance();
1312 }
1313 }
1314 output = Some(Token::new("#VL", TIN_VL, value, matched, pnt));
1315 break;
1316 }
1317 }
1318 }
1319
1320 if output.is_none() && (!text_lex || text_skipped) {
1321 (self.idx, self.ri, self.ci) = start;
1322 } else if output.is_none() {
1323 output = Some(Token::new(
1324 "#TX",
1325 TIN_TX,
1326 Value::String(src.clone()),
1327 src,
1328 pnt,
1329 ));
1330 }
1331
1332 if let Some(mut token) = output {
1333 let value = std::mem::replace(&mut token.val, Value::Undefined);
1334 token.val = self.modify_text_value(value, &mut plugin);
1335 return Ok(token);
1336 }
1337 }
1338
1339 if let Some(token) =
1340 self.run_custom_matchers(&mut custom_index, f64::INFINITY, pnt, &mut plugin)
1341 {
1342 return Ok(token);
1343 }
1344
1345 let bad_char = self.advance().unwrap();
1347 let err = TabnasError::new(
1348 "unexpected",
1349 bad_char.to_string(),
1350 self.src,
1351 pnt.site.pos,
1352 pnt.site.ri,
1353 pnt.site.ci,
1354 );
1355 self.err = Some(err.clone());
1356 Err(Box::new(err))
1357 }
1358
1359 fn match_comment(&mut self, pnt: Point) -> LexResult<Option<Token>> {
1360 let remaining = &self.src[self.byte_position()..];
1361 let mut definitions: Vec<_> = self
1362 .options
1363 .comment
1364 .definitions
1365 .iter()
1366 .filter(|(_, definition)| {
1367 definition.start.as_bytes().first().copied()
1369 == remaining.as_bytes().first().copied()
1370 && !definition.start.is_empty()
1371 && definition.lex
1372 && remaining.starts_with(&definition.start)
1373 })
1374 .collect();
1375 definitions.sort_by(|(name_a, a), (name_b, b)| {
1376 b.start
1377 .len()
1378 .cmp(&a.start.len())
1379 .then_with(|| name_a.cmp(name_b))
1380 });
1381 let Some((_, definition)) = definitions.first() else {
1382 return Ok(None);
1383 };
1384 let definition = (*definition).clone();
1385 let mut src = String::new();
1386 for _ in definition.start.chars() {
1387 src.push(self.advance().expect("comment marker must advance"));
1388 }
1389
1390 let mut terminated_by_suffix = false;
1391 let mut closed = definition.line;
1392 loop {
1393 let remainder = &self.src[self.byte_position()..];
1394 let suffix = definition
1395 .suffixes
1396 .iter()
1397 .filter(|suffix| !suffix.is_empty() && remainder.starts_with(*suffix))
1398 .max_by_key(|suffix| suffix.len())
1399 .cloned();
1400 let suffix = suffix.or_else(|| {
1401 let matcher = definition.suffix_matcher.as_ref()?;
1402 let effect = matcher.run(remainder);
1403 if effect.is_some() {
1404 return effect;
1405 }
1406 let saved = self.state();
1407 let wanted = self.want.clone();
1408 let token = matcher.run_imperative(self);
1409 self.restore(saved);
1410 self.want = wanted;
1411 token.map(|token| token.src.to_string())
1412 });
1413 let remainder = &self.src[self.byte_position()..];
1414 let suffix =
1415 suffix.filter(|suffix| !suffix.is_empty() && remainder.starts_with(suffix));
1416 if let Some(suffix) = suffix {
1417 for _ in suffix.chars() {
1418 src.push(self.advance().expect("comment suffix must advance"));
1419 }
1420 terminated_by_suffix = true;
1421 closed = true;
1422 break;
1423 }
1424 if !definition.line
1425 && !definition.end.is_empty()
1426 && remainder.starts_with(&definition.end)
1427 {
1428 for _ in definition.end.chars() {
1429 src.push(self.advance().expect("comment end must advance"));
1430 }
1431 closed = true;
1432 break;
1433 }
1434 let Some(ch) = self.peek() else {
1435 break;
1436 };
1437 if definition.line && (self.char_sets.line_ends.contains(ch)) {
1438 break;
1439 }
1440 src.push(self.advance().expect("comment body must advance"));
1441 }
1442
1443 if !closed {
1444 let err = TabnasError::new(
1445 "unterminated_comment",
1446 src,
1447 self.src,
1448 pnt.site.pos,
1449 pnt.site.ri,
1450 pnt.site.ci,
1451 );
1452 self.err = Some(err.clone());
1453 return Err(Box::new(err));
1454 }
1455
1456 if definition.eat_line && !terminated_by_suffix {
1457 while let Some(ch) = self.peek() {
1458 if !self.char_sets.line_ends.contains(ch) {
1459 break;
1460 }
1461 src.push(self.advance().expect("comment line tail must advance"));
1462 }
1463 }
1464
1465 Ok(Some(Token::new(
1466 "#CM",
1467 TIN_CM,
1468 Value::String(src.clone()),
1469 src,
1470 pnt,
1471 )))
1472 }
1473
1474 fn match_number(&mut self, pnt: Point) -> LexResult<Option<Token>> {
1475 let start_idx = self.idx;
1476 let mut src = String::new();
1477
1478 if matches!(self.peek(), Some('-' | '+')) {
1480 src.push(self.advance().unwrap());
1481 }
1482
1483 if self.peek() == Some('0') {
1485 if let Some(prefix) = self.peek_at(1) {
1486 let radix = match prefix {
1487 'x' | 'X' if self.options.number.hex => Some(16),
1488 'o' | 'O' if self.options.number.oct => Some(8),
1489 'b' | 'B' if self.options.number.bin => Some(2),
1490 _ => None,
1491 };
1492 if let Some(radix) = radix {
1493 src.push(self.advance().expect("peeked zero"));
1494 src.push(self.advance().expect("peeked base prefix"));
1495 let mut saw_digit = false;
1496 while let Some(ch) = self.peek() {
1497 if ch.is_digit(radix) {
1498 saw_digit = true;
1499 src.push(self.advance().expect("peeked base digit"));
1500 } else if self
1501 .options
1502 .number
1503 .sep
1504 .as_ref()
1505 .is_some_and(|separator| separator.contains(ch))
1506 {
1507 src.push(self.advance().expect("peeked base digit"));
1508 } else {
1509 break;
1510 }
1511 }
1512 if saw_digit && self.is_text_delimiter_here() {
1513 if self
1514 .exclude_regex
1515 .as_ref()
1516 .is_some_and(|regex| regex.is_match(&src))
1517 {
1518 self.reset_number(start_idx, pnt);
1519 return Ok(None);
1520 }
1521 if self.options.value.lex {
1522 if let Some(definition) = self
1523 .options
1524 .value
1525 .definitions
1526 .get(&src)
1527 .filter(|definition| definition.matcher.is_none())
1528 {
1529 return Ok(Some(Token::new(
1530 "#VL",
1531 TIN_VL,
1532 definition
1533 .val
1534 .clone()
1535 .unwrap_or_else(|| Value::String(src.clone())),
1536 src,
1537 pnt,
1538 )));
1539 }
1540 }
1541 let mut fold = DigitFold::new(radix.trailing_zeros());
1549 for ch in src.chars().skip_while(|ch| matches!(ch, '-' | '+')).skip(2) {
1550 if self
1551 .options
1552 .number
1553 .sep
1554 .as_ref()
1555 .is_some_and(|separator| separator.contains(ch))
1556 {
1557 continue;
1558 }
1559 fold.push(ch.to_digit(radix).expect("validated base digit"));
1560 }
1561 let mut value = fold.finish();
1562 if src.starts_with('-') {
1563 value = -value;
1564 }
1565 return Ok(Some(Token::new(
1566 "#NR",
1567 TIN_NR,
1568 Value::Number(value),
1569 src,
1570 pnt,
1571 )));
1572 }
1573 self.reset_number(start_idx, pnt);
1574 return Ok(None);
1575 }
1576 }
1577 }
1578
1579 let Some(ch) = self.peek() else {
1580 self.reset_number(start_idx, pnt);
1581 return Ok(None);
1582 };
1583 if ch == '.' {
1584 if !self.peek_at(1).is_some_and(|next| next.is_ascii_digit()) {
1585 self.reset_number(start_idx, pnt);
1586 return Ok(None);
1587 }
1588 src.push(self.advance().expect("peeked leading decimal point"));
1589 } else if !ch.is_ascii_digit() {
1590 self.reset_number(start_idx, pnt);
1591 return Ok(None);
1592 }
1593
1594 let (has_digits, edge_separator) = self.scan_number_digits(&mut src);
1595 if !has_digits || edge_separator {
1596 self.reset_number(start_idx, pnt);
1597 return Ok(None);
1598 }
1599
1600 if self.peek() == Some('.') {
1603 let next = self.peek_at(1);
1604 let exponent_after_dot = matches!(next, Some('e' | 'E'))
1605 && match self.peek_at(2) {
1606 Some('+' | '-') => self.peek_at(3).is_some_and(|ch| ch.is_ascii_digit()),
1607 Some(ch) => ch.is_ascii_digit(),
1608 None => false,
1609 };
1610 if next.is_some_and(|ch| ch.is_ascii_digit()) {
1611 src.push(self.advance().expect("peeked decimal point"));
1612 let (_, edge_separator) = self.scan_number_digits(&mut src);
1613 if edge_separator {
1614 self.reset_number(start_idx, pnt);
1615 return Ok(None);
1616 }
1617 } else if next.is_some()
1618 && !self.is_text_delimiter_at(self.idx + 1)
1619 && next != Some('.')
1620 && !exponent_after_dot
1621 {
1622 self.reset_number(start_idx, pnt);
1623 return Ok(None);
1624 } else {
1625 src.push(self.advance().expect("peeked trailing decimal point"));
1626 }
1627 }
1628
1629 if matches!(self.peek(), Some('e' | 'E')) {
1630 let exponent_start = self.idx;
1631 let source_len = src.len();
1632 src.push(self.advance().expect("peeked exponent marker"));
1633 if matches!(self.peek(), Some('+' | '-')) {
1634 src.push(self.advance().expect("peeked exponent sign"));
1635 }
1636 let (has_exponent_digits, edge_separator) = self.scan_number_digits(&mut src);
1637 if edge_separator {
1638 self.reset_number(start_idx, pnt);
1639 return Ok(None);
1640 }
1641 if !has_exponent_digits {
1642 self.idx = exponent_start;
1643 src.truncate(source_len);
1644 }
1645 }
1646
1647 if !self.is_text_delimiter_here() {
1648 self.reset_number(start_idx, pnt);
1649 return Ok(None);
1650 }
1651
1652 if let Some(ref re) = self.exclude_regex {
1654 if re.is_match(&src) {
1655 self.reset_number(start_idx, pnt);
1657 return Ok(None);
1658 }
1659 }
1660
1661 if self.options.value.lex {
1662 if let Some(definition) = self
1663 .options
1664 .value
1665 .definitions
1666 .get(&src)
1667 .filter(|definition| definition.matcher.is_none())
1668 {
1669 return Ok(Some(Token::new(
1670 "#VL",
1671 TIN_VL,
1672 definition
1673 .val
1674 .clone()
1675 .unwrap_or_else(|| Value::String(src.clone())),
1676 src,
1677 pnt,
1678 )));
1679 }
1680 }
1681
1682 let parse_src = self.options.number.sep.as_ref().map_or_else(
1684 || src.clone(),
1685 |separator| src.chars().filter(|ch| !separator.contains(*ch)).collect(),
1686 );
1687 match parse_src.parse::<f64>() {
1688 Ok(num) => Ok(Some(Token::new(
1689 "#NR",
1690 TIN_NR,
1691 Value::Number(num),
1692 src,
1693 pnt,
1694 ))),
1695 Err(_) => {
1696 self.reset_number(start_idx, pnt);
1697 Ok(None)
1698 }
1699 }
1700 }
1701
1702 fn reset_number(&mut self, start_idx: usize, pnt: Point) {
1703 self.idx = start_idx;
1704 self.ri = pnt.site.ri;
1705 self.ci = pnt.site.ci;
1706 }
1707
1708 fn scan_number_digits(&mut self, src: &mut String) -> (bool, bool) {
1712 let run_start = self.idx;
1719 let mut saw_digit = false;
1720 let mut last_was_separator = false;
1721 let mut end = run_start;
1722 {
1723 let separator = self.options.number.sep.as_deref();
1724 while let Some(ch) = self.chars.get(end).copied() {
1725 if ch.is_ascii_digit() {
1726 saw_digit = true;
1727 last_was_separator = false;
1728 } else if separator.is_some_and(|separator| separator.contains(ch)) {
1729 last_was_separator = true;
1730 } else {
1731 break;
1732 }
1733 end += 1;
1734 }
1735 }
1736 while self.idx < end {
1737 src.push(self.advance().expect("scanned number character"));
1738 }
1739 let starts_with_separator = self.idx > run_start
1740 && self.options.number.sep.as_deref().is_some_and(|separator| {
1741 self.chars[run_start..self.idx]
1742 .first()
1743 .is_some_and(|ch| separator.contains(*ch))
1744 });
1745 (saw_digit, starts_with_separator || last_was_separator)
1746 }
1747
1748 fn match_string(&mut self, quote: char, pnt: Point) -> LexResult<Token> {
1749 let quote_char = self.advance().unwrap();
1750 let mut out_str = String::new();
1751 let mut raw_src = String::new();
1752 raw_src.push(quote_char);
1753
1754 let mut pending_high_surrogate: Option<u16> = None;
1755
1756 while let Some(c) = self.peek() {
1757 if c == quote {
1758 raw_src.push(self.advance().unwrap());
1759 self.flush_surrogate(&mut pending_high_surrogate, &mut out_str);
1762 return Ok(Token::new(
1763 "#ST",
1764 TIN_ST,
1765 Value::String(out_str),
1766 raw_src,
1767 pnt,
1768 ));
1769 }
1770
1771 if let Some(replacement) = self.options.string.replace.get(&c).cloned() {
1772 raw_src.push(self.advance().expect("peeked character must advance"));
1773 self.flush_surrogate(&mut pending_high_surrogate, &mut out_str);
1774 out_str.push_str(&replacement);
1775 continue;
1776 }
1777
1778 if self.char_sets.line.contains(c) {
1779 if self.options.string.multi_chars.contains(quote) {
1780 raw_src.push(self.advance().expect("peeked character must advance"));
1781 out_str.push(c);
1782 continue;
1783 }
1784 let site = self.current_point().site;
1791 let err = TabnasError::new(
1792 "unprintable",
1793 c.to_string(),
1794 self.src,
1795 site.pos,
1796 site.ri,
1797 site.ci,
1798 );
1799 self.err = Some(err.clone());
1800 return Err(Box::new(err));
1801 }
1802
1803 if (c as u32) < 32 && !self.options.string.allow_control {
1805 let err = TabnasError::new(
1806 "unprintable",
1807 c.to_string(),
1808 self.src,
1809 self.current_point().site.pos,
1810 self.current_point().site.ri,
1811 self.current_point().site.ci,
1812 );
1813 self.err = Some(err.clone());
1814 return Err(Box::new(err));
1815 }
1816
1817 if c == self.options.string.escape_char {
1818 raw_src.push(self.advance().unwrap());
1819 let esc_point = self.current_point();
1820 if let Some(esc) = self.advance() {
1821 raw_src.push(esc);
1822 if let Some(replacement) = self.options.string.escape.get(&esc).cloned() {
1823 self.flush_surrogate(&mut pending_high_surrogate, &mut out_str);
1824 out_str.push_str(&replacement);
1825 continue;
1826 }
1827 match esc {
1828 'u' => {
1829 if self.peek() == Some('{') && !self.options.string.escape_strict {
1839 raw_src.push(self.advance().unwrap()); let mut hex = String::new();
1841 let mut closed = false;
1842 while let Some(h) = self.peek() {
1843 if h == '}' {
1844 raw_src.push(self.advance().unwrap());
1845 closed = true;
1846 break;
1847 }
1848 raw_src.push(self.advance().unwrap());
1849 hex.push(h);
1850 }
1851
1852 if !closed
1853 || hex.is_empty()
1854 || hex.len() > 6
1855 || !hex.chars().all(|ch| ch.is_ascii_hexdigit())
1856 {
1857 let err = TabnasError::new(
1858 "invalid_unicode",
1859 self.source_span(esc_point.site.pos - 1, self.idx),
1860 self.src,
1861 esc_point.site.pos - 1,
1862 esc_point.site.ri,
1863 esc_point.site.ci - 1,
1864 );
1865 self.err = Some(err.clone());
1866 return Err(Box::new(err));
1867 }
1868
1869 let cp = match u32::from_str_radix(&hex, 16) {
1870 Ok(val) if val <= 0x10FFFF => val,
1871 _ => {
1872 let err = TabnasError::new(
1873 "invalid_unicode",
1874 self.source_span(esc_point.site.pos - 1, self.idx),
1875 self.src,
1876 esc_point.site.pos - 1,
1877 esc_point.site.ri,
1878 esc_point.site.ci - 1,
1879 );
1880 self.err = Some(err.clone());
1881 return Err(Box::new(err));
1882 }
1883 };
1884
1885 self.emit_unicode_escape(
1886 cp,
1887 &mut pending_high_surrogate,
1888 &mut out_str,
1889 );
1890 } else {
1891 let mut hex = String::new();
1893 for _ in 0..4 {
1894 if let Some(h) = self.peek() {
1895 if h.is_ascii_hexdigit() {
1896 raw_src.push(self.advance().unwrap());
1897 hex.push(h);
1898 } else {
1899 break;
1900 }
1901 } else {
1902 break;
1903 }
1904 }
1905
1906 if hex.len() != 4 {
1907 let err = TabnasError::new(
1908 "invalid_unicode",
1909 self.source_span(
1910 esc_point.site.pos - 1,
1911 esc_point.site.pos + 5,
1912 ),
1913 self.src,
1914 esc_point.site.pos - 1,
1915 esc_point.site.ri,
1916 esc_point.site.ci - 1,
1917 );
1918 self.err = Some(err.clone());
1919 return Err(Box::new(err));
1920 }
1921
1922 let cp = u16::from_str_radix(&hex, 16).map_err(|_| {
1923 let err = TabnasError::new(
1924 "invalid_unicode",
1925 self.source_span(
1926 esc_point.site.pos - 1,
1927 esc_point.site.pos + 5,
1928 ),
1929 self.src,
1930 esc_point.site.pos - 1,
1931 esc_point.site.ri,
1932 esc_point.site.ci - 1,
1933 );
1934 self.err = Some(err.clone());
1935 err
1936 })?;
1937
1938 self.emit_unicode_escape(
1939 u32::from(cp),
1940 &mut pending_high_surrogate,
1941 &mut out_str,
1942 );
1943 }
1944 }
1945 'x' if !self.options.string.escape_strict => {
1946 let mut hex = String::new();
1947 for _ in 0..2 {
1948 if let Some(h) = self.peek() {
1949 if h.is_ascii_hexdigit() {
1950 raw_src.push(
1951 self.advance().expect("peeked character must advance"),
1952 );
1953 hex.push(h);
1954 }
1955 }
1956 }
1957 if hex.len() != 2 {
1958 let err = TabnasError::new(
1959 "invalid_ascii",
1960 self.source_span(
1961 esc_point.site.pos - 1,
1962 esc_point.site.pos + 3,
1963 ),
1964 self.src,
1965 esc_point.site.pos - 1,
1966 esc_point.site.ri,
1967 esc_point.site.ci - 1,
1968 );
1969 self.err = Some(err.clone());
1970 return Err(Box::new(err));
1971 }
1972 let byte = u8::from_str_radix(&hex, 16).expect("validated ASCII hex");
1973 self.flush_surrogate(&mut pending_high_surrogate, &mut out_str);
1974 out_str.push(char::from(byte));
1975 }
1976 other => {
1977 if !self.options.string.allow_unknown {
1978 let err = TabnasError::new(
1985 "unexpected",
1986 other.to_string(),
1987 self.src,
1988 esc_point.site.pos,
1989 esc_point.site.ri,
1990 esc_point.site.ci,
1991 );
1992 self.err = Some(err.clone());
1993 return Err(Box::new(err));
1994 }
1995 self.flush_surrogate(&mut pending_high_surrogate, &mut out_str);
1996 out_str.push(other);
1997 }
1998 }
1999 } else {
2000 let err = TabnasError::new(
2001 "unterminated_string",
2002 raw_src,
2003 self.src,
2004 pnt.site.pos,
2005 pnt.site.ri,
2006 pnt.site.ci,
2007 );
2008 self.err = Some(err.clone());
2009 return Err(Box::new(err));
2010 }
2011 } else {
2012 self.flush_surrogate(&mut pending_high_surrogate, &mut out_str);
2013 raw_src.push(self.advance().unwrap());
2014 out_str.push(c);
2015 }
2016 }
2017
2018 let err = TabnasError::new(
2019 "unterminated_string",
2020 raw_src,
2021 self.src,
2022 pnt.site.pos,
2023 pnt.site.ri,
2024 pnt.site.ci,
2025 );
2026 self.err = Some(err.clone());
2027 Err(Box::new(err))
2028 }
2029
2030 fn flush_surrogate(&self, pending: &mut Option<u16>, out: &mut String) {
2031 if pending.take().is_some() {
2032 out.push('\u{FFFD}');
2033 }
2034 }
2035
2036 fn emit_unicode_escape(&self, cp: u32, pending: &mut Option<u16>, out: &mut String) {
2039 if (0xD800..=0xDBFF).contains(&cp) {
2040 self.flush_surrogate(pending, out);
2041 *pending = Some(cp as u16);
2042 } else if (0xDC00..=0xDFFF).contains(&cp) {
2043 if let Some(high) = pending.take() {
2044 let scalar = 0x10000 + (((u32::from(high)) - 0xD800) << 10) + (cp - 0xDC00);
2045 out.push(char::from_u32(scalar).expect("paired surrogates form a Unicode scalar"));
2046 } else {
2047 out.push('\u{FFFD}');
2048 }
2049 } else {
2050 self.flush_surrogate(pending, out);
2051 out.push(char::from_u32(cp).expect("validated escape is a Unicode scalar"));
2052 }
2053 }
2054}
2055
2056fn pow2(k: i64) -> f64 {
2081 debug_assert!(k >= 0, "only non-negative exponents arise here");
2082 if k > 1023 {
2083 f64::INFINITY
2084 } else {
2085 f64::from_bits(((k + 1023) as u64) << 52)
2086 }
2087}
2088
2089struct DigitFold {
2103 bits: u32,
2104 head: u128,
2106 len: usize,
2108 sticky: bool,
2110 started: bool,
2114}
2115
2116impl DigitFold {
2117 fn new(bits: u32) -> Self {
2118 debug_assert!(
2119 (1..=4).contains(&bits),
2120 "only the power-of-two bases the lexer reads"
2121 );
2122 DigitFold {
2123 bits,
2124 head: 0,
2125 len: 0,
2126 sticky: false,
2127 started: false,
2128 }
2129 }
2130
2131 fn head_len(&self) -> usize {
2133 (128 / self.bits) as usize
2134 }
2135
2136 fn push(&mut self, digit: u32) {
2137 if !self.started {
2138 if 0 == digit {
2139 return;
2140 }
2141 self.started = true;
2142 }
2143 if self.len < self.head_len() {
2144 self.head = (self.head << self.bits) | u128::from(digit);
2145 } else if 0 != digit {
2146 self.sticky = true;
2147 }
2148 self.len += 1;
2149 }
2150
2151 fn finish(&self) -> f64 {
2152 if !self.started {
2153 return 0.0;
2154 }
2155 let head_len = self.head_len();
2156 if self.len <= head_len {
2157 return self.head as f64;
2160 }
2161
2162 let dropped = i64::from(self.bits) * (self.len - head_len) as i64;
2168 let shift = 128 - self.head.leading_zeros() - 53;
2169
2170 let mut mantissa = (self.head >> shift) as u64;
2171 let half = (self.head >> (shift - 1)) & 1 == 1;
2172 let sticky = self.head & ((1u128 << (shift - 1)) - 1) != 0 || self.sticky;
2173 if half && (sticky || mantissa & 1 == 1) {
2174 mantissa += 1;
2176 }
2177 mantissa as f64 * pow2(dropped + i64::from(shift))
2181 }
2182}