1use crate::encoding::Encoding;
31use crate::{TermToken, TokenID, Value};
32use lexer_data::{LexData, Mode, Rule};
33use parlex::{Lexer, LexerData, LexerDriver, LexerStats, ParlexError, Span};
34use std::marker::PhantomData;
35use try_next::TryNextWithContext;
36
37use arena_terms::{Arena, Fixity, OperDef, Term};
38use chrono::{DateTime, FixedOffset, Utc};
39use smartstring::alias::String;
40
41pub mod lexer_data {
52 include!(concat!(env!("OUT_DIR"), "/lexer_data.rs"));
53}
54
55fn parse_date_to_epoch(s: &str, fmt: Option<&str>) -> Result<i64, ParlexError> {
75 let dt_fixed: DateTime<FixedOffset> = match fmt {
76 None => DateTime::parse_from_rfc3339(s).map_err(|e| ParlexError::from_err(e, None))?,
77 Some(layout) => {
78 DateTime::parse_from_str(s, layout).map_err(|e| ParlexError::from_err(e, None))?
79 }
80 };
81 let dt_utc = dt_fixed.with_timezone(&Utc);
82 Ok(dt_utc.timestamp_millis())
83}
84
85fn parse_i64(s: &str, base: u32) -> Result<i64, std::num::ParseIntError> {
102 if s.is_empty() {
103 return Ok(0);
104 }
105 let n = i64::from_str_radix(s, base)?;
106 Ok(n)
107}
108
109pub struct TermLexerDriver<I> {
135 _marker: PhantomData<I>,
137
138 encoding: Encoding,
140
141 pub buffer2: Vec<u8>,
143
144 pub span2: Span,
146
147 nest_count: isize,
149
150 comment_nest_count: isize,
152
153 curly_nest_count: isize,
155
156 script_curly_nest_count: isize,
158
159 bin_count: isize,
161
162 bin_label: Vec<u8>,
165
166 date_format: String,
169}
170
171#[inline]
172fn yield_id<I>(lexer: &mut Lexer<I, TermLexerDriver<I>, Arena>, token_id: TokenID)
173where
174 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
175{
176 lexer.yield_token(TermToken {
177 token_id,
178 value: Value::None,
179 span: Some(lexer.span()),
180 op_tab_index: None,
181 });
182}
183
184#[inline]
185fn yield_term<I>(
186 lexer: &mut Lexer<I, TermLexerDriver<I>, Arena>,
187 token_id: TokenID,
188 term: Term,
189 span: Span,
190) where
191 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
192{
193 lexer.yield_token(TermToken {
194 token_id,
195 value: Value::Term(term),
196 span: Some(span),
197 op_tab_index: None,
198 });
199}
200
201#[inline]
202fn yield_optab<I>(
203 lexer: &mut Lexer<I, TermLexerDriver<I>, Arena>,
204 token_id: TokenID,
205 term: Term,
206 op_tab_index: Option<usize>,
207 span: Span,
208) where
209 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
210{
211 lexer.yield_token(TermToken {
212 token_id,
213 value: Value::Term(term),
214 span: Some(span),
215 op_tab_index,
216 });
217}
218
219impl<I> TermLexerDriver<I> {
220 #[inline]
221 fn take_bytes(&mut self, lexer: &mut Lexer<I, Self, Arena>) -> Vec<u8>
222 where
223 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
224 {
225 lexer.accum_flag = false;
226 std::mem::take(&mut lexer.buffer)
227 }
228
229 #[inline]
230 fn take_str(&mut self, lexer: &mut Lexer<I, Self, Arena>) -> Result<String, ParlexError>
231 where
232 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
233 {
234 let bytes = self.take_bytes(lexer);
235 let s = self.encoding.decode(&bytes)
236 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
237 Ok(String::from(s))
238 }
239
240 #[inline]
241 fn take_bytes2(&mut self, lexer: &mut Lexer<I, Self, Arena>) -> Vec<u8>
242 where
243 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
244 {
245 lexer.accum_flag = false;
246 std::mem::take(&mut self.buffer2)
247 }
248
249 #[inline]
250 fn take_str2(&mut self, lexer: &mut Lexer<I, Self, Arena>) -> Result<String, ParlexError>
251 where
252 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
253 {
254 let bytes = self.take_bytes2(lexer);
255 let s = self.encoding.decode(&bytes)
256 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
257 Ok(String::from(s))
258 }
259}
260
261impl<I> LexerDriver for TermLexerDriver<I>
262where
263 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
264{
265 type LexerData = LexData;
267
268 type Token = TermToken;
270
271 type Lexer = Lexer<I, Self, Self::Context>;
273
274 type Context = Arena;
276
277 fn action(
293 &mut self,
294 lexer: &mut Self::Lexer,
295 arena: &mut Self::Context,
296 rule: <Self::LexerData as LexerData>::LexerRule,
297 ) -> Result<(), ParlexError> {
298 log::trace!(
299 "ACTION begin: mode {:?}, rule {:?}, buf {:?}, buf2 {:?}, label {:?}, accum {}",
300 lexer.mode(),
301 rule,
302 std::string::String::from_utf8_lossy(&lexer.buffer),
303 std::string::String::from_utf8_lossy(&self.buffer2),
304 std::string::String::from_utf8_lossy(&self.bin_label),
305 lexer.accum_flag,
306 );
307 match rule {
308 Rule::Empty => {
309 unreachable!()
310 }
311 Rule::LineComment => {}
312 Rule::CommentStart => {
313 if self.comment_nest_count == 0 {
314 lexer.begin(Mode::Comment);
315 }
316 self.comment_nest_count += 1;
317 }
318 Rule::CommentEnd => {
319 self.comment_nest_count -= 1;
320 if self.comment_nest_count == 0 {
321 lexer.begin(Mode::Expr);
322 }
323 }
324 Rule::CommentChar | Rule::ExprSpace | Rule::CommentAnyChar => {}
325 Rule::ExprNewLine | Rule::CommentNewLine => {
326 }
328 Rule::LeftParen => {
329 self.nest_count += 1;
330 yield_id(lexer, TokenID::LeftParen);
331 }
332 Rule::RightParen => {
333 self.nest_count -= 1;
334 yield_id(lexer, TokenID::RightParen);
335 }
336 Rule::LeftBrack => {
337 self.nest_count += 1;
338 yield_id(lexer, TokenID::LeftBrack);
339 }
340 Rule::RightBrack => {
341 self.nest_count -= 1;
342 yield_id(lexer, TokenID::RightBrack);
343 }
344 Rule::Comma => {
345 yield_id(lexer, TokenID::Comma);
346 }
347 Rule::Pipe => {
348 yield_id(lexer, TokenID::Pipe);
349 }
350 Rule::RightBrace => {
351 self.nest_count -= 1;
352 self.curly_nest_count -= 1;
353 if self.curly_nest_count >= 0 {
354 lexer.begin(Mode::Str);
355 yield_id(lexer, TokenID::RightParen);
356 let op_tab_idx = arena.lookup_oper("++");
357 yield_optab(
358 lexer,
359 TokenID::AtomOper,
360 arena.atom("++"),
361 op_tab_idx,
362 lexer.span(),
363 );
364 lexer.clear();
365 lexer.accum();
366 } else {
367 return Err(ParlexError {
368 message: format!("error on lexeme `}}`"),
369 span: Some(lexer.span()),
370 });
371 }
372 }
373 Rule::Func => {
374 self.nest_count += 1;
375 lexer.buffer.pop();
376 let s = self.take_str(lexer)?;
377 let atom = arena.atom(&s);
378 let op_tab_idx = arena.lookup_oper(&s);
379 let op_tab = arena.get_oper(op_tab_idx);
380 if op_tab.is_oper() {
381 let (has_empty, has_non_empty) =
382 [Fixity::Prefix, Fixity::Infix, Fixity::Postfix]
383 .iter()
384 .filter_map(|f| {
385 op_tab
386 .get_op_def(*f)
387 .map(|x| x.args.len() <= OperDef::required_arity(*f))
388 })
389 .fold((false, false), |(e, ne), is_empty| {
390 if is_empty { (true, ne) } else { (e, true) }
391 });
392
393 match (has_empty, has_non_empty) {
394 (false, false) => unreachable!(),
395 (true, false) => {
396 yield_optab(lexer, TokenID::AtomOper, atom, op_tab_idx, lexer.span());
397 yield_id(lexer, TokenID::LeftParen);
398 }
399 (false, true) => {
400 yield_optab(lexer, TokenID::FuncOper, atom, op_tab_idx, lexer.span());
401 }
402 (true, true) => {
403 return Err(ParlexError {
404 message: format!("arguments conflict in op defs for {:?}", atom),
405 span: Some(lexer.span()),
406 });
407 }
408 }
409 } else {
410 yield_optab(lexer, TokenID::Func, atom, op_tab_idx, lexer.span());
411 }
412 }
413 Rule::Var => {
414 let s = self.take_str(lexer)?;
415 yield_term(lexer, TokenID::Var, arena.var(s), lexer.span());
416 }
417 Rule::Atom => {
418 if lexer.buffer == b"." && self.nest_count == 0 {
419 yield_id(lexer, TokenID::Dot);
420 yield_id(lexer, TokenID::End);
421 } else {
422 let s = self.take_str(lexer)?;
423 let atom = arena.atom(&s);
424 let op_tab_idx = arena.lookup_oper(&s);
425 let op_tab = arena.get_oper(op_tab_idx);
426 if op_tab.is_oper() {
427 yield_optab(lexer, TokenID::AtomOper, atom, op_tab_idx, lexer.span());
428 } else {
429 yield_optab(lexer, TokenID::Atom, atom, op_tab_idx, lexer.span());
430 }
431 }
432 }
433
434 Rule::DateEpoch => {
435 let mut s = self.take_str(lexer)?;
436 s.pop();
437 s.drain(0..5);
438 let s = s.trim();
439 let d =
440 parse_i64(s, 10).map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
441 yield_term(lexer, TokenID::Date, arena.date(d), lexer.span());
442 }
443 Rule::Date => {
444 lexer.begin(Mode::Date);
445 lexer.clear();
446 self.buffer2.clear();
447 self.date_format.clear();
448 self.span2 = lexer.span();
449 }
450 Rule::Date1 => {
451 lexer.begin(Mode::Time);
452 self.date_format.push_str("%Y-%m-%d");
453 self.buffer2.extend(&lexer.buffer);
454 self.span2.merge(lexer.span_ref());
455 }
456 Rule::Date2 => {
457 lexer.begin(Mode::Time);
458 self.date_format.push_str("%m/%d/%Y");
459 self.buffer2.extend(&lexer.buffer);
460 self.span2.merge(lexer.span_ref());
461 }
462 Rule::Date3 => {
463 lexer.begin(Mode::Time);
464 self.date_format.push_str("%d-%b-%Y");
465 self.buffer2.extend(&lexer.buffer);
466 self.span2.merge(lexer.span_ref());
467 }
468 Rule::Time1 => {
469 lexer.begin(Mode::Zone);
470 self.date_format.push_str("T%H:%M:%S%.f");
471 self.buffer2.extend(&lexer.buffer);
472 self.span2.merge(lexer.span_ref());
473 }
474 Rule::Time2 => {
475 lexer.begin(Mode::Zone);
476 self.date_format.push_str("T%H:%M:%S");
477 self.buffer2.extend(&lexer.buffer);
478 self.buffer2.extend(b":00");
479 self.span2.merge(lexer.span_ref());
480 }
481 Rule::Time3 => {
482 lexer.begin(Mode::Zone);
483 self.date_format.push_str(" %H:%M:%S%.f");
484 self.buffer2.extend(&lexer.buffer);
485 self.span2.merge(lexer.span_ref());
486 }
487 Rule::Time4 => {
488 lexer.begin(Mode::Zone);
489 self.date_format.push_str(" %H:%M:%S");
490 self.buffer2.extend(&lexer.buffer);
491 self.buffer2.extend(b":00");
492 self.span2.merge(lexer.span_ref());
493 }
494 Rule::Time5 => {
495 lexer.begin(Mode::Zone);
496 self.date_format.push_str(" %I:%M:%S%.f %p");
497 self.buffer2.extend(&lexer.buffer);
498 self.span2.merge(lexer.span_ref());
499 }
500 Rule::Time6 => {
501 lexer.begin(Mode::Zone);
502 self.date_format.push_str(" %I:%M:%S %p");
503 self.buffer2.extend(&lexer.buffer[..lexer.buffer.len() - 3]);
504 self.buffer2.extend(b":00");
505 self.buffer2.extend(&lexer.buffer[lexer.buffer.len() - 3..]);
506 self.span2.merge(lexer.span_ref());
507 }
508 Rule::Zone1 => {
509 if lexer.mode() == Mode::Time {
510 self.date_format.push_str(" %H:%M:%S");
511 self.buffer2.extend(b" 00:00:00");
512 }
513 lexer.begin(Mode::Expr);
514 self.date_format.push_str("%:z");
515 self.buffer2.extend(b"+00:00");
516 let s = self.take_str2(lexer)?;
517 let d = parse_date_to_epoch(s.trim_end(), Some(self.date_format.as_str()))?;
518 self.span2.merge(lexer.span_ref());
519 yield_term(lexer, TokenID::Date, arena.date(d), self.span2);
520 }
521 Rule::Zone2 => {
522 self.span2.merge(lexer.span_ref());
523 if lexer.mode() == Mode::Time {
524 self.date_format.push_str(" %H:%M:%S");
525 self.buffer2.extend(b" 00:00:00");
526 }
527 lexer.begin(Mode::Expr);
528 if lexer.buffer[0] == b' ' {
529 self.date_format.push(' ');
530 }
531 self.date_format.push_str("%:z");
532 lexer.buffer.pop();
533 self.buffer2.extend(&lexer.buffer);
534 let s = self.take_str2(lexer)?;
535 let d = parse_date_to_epoch(s.trim_end(), Some(self.date_format.as_str()))?;
536 yield_term(lexer, TokenID::Date, arena.date(d), self.span2);
537 }
538 Rule::TimeRightBrace => {
539 self.span2.merge(lexer.span_ref());
540 lexer.begin(Mode::Expr);
541 self.date_format.push_str(" %H:%M:%S%:z");
542 self.buffer2.extend(b" 00:00:00+00:00");
543 let s = self.take_str2(lexer)?;
544 let d = parse_date_to_epoch(&s, Some(self.date_format.as_str()))?;
545 yield_term(lexer, TokenID::Date, arena.date(d), self.span2);
546 }
547 Rule::ZoneRightBrace => {
548 self.span2.merge(lexer.span_ref());
549 lexer.begin(Mode::Expr);
550 self.date_format.push_str("%:z");
551 self.buffer2.extend(b"+00:00");
552 let s = self.take_str2(lexer)?;
553 let d = parse_date_to_epoch(&s, Some(self.date_format.as_str()))?;
554 yield_term(lexer, TokenID::Date, arena.date(d), self.span2);
555 }
556
557 Rule::Hex => {
558 lexer.begin(Mode::Hex);
559 self.buffer2.clear();
560 self.span2 = lexer.span();
561 }
562 Rule::HexSpace => {
563 self.span2.merge(lexer.span_ref());
564 }
565 Rule::HexNewLine => {
566 self.span2.merge(lexer.span_ref());
568 }
569 Rule::HexByte => {
570 let s = str::from_utf8(&lexer.buffer)
571 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
572 self.span2.merge(lexer.span_ref());
573 let b = u8::from_str_radix(s, 16)
574 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
575 self.buffer2.push(b);
576 }
577 Rule::HexRightBrace => {
578 lexer.buffer.pop();
579 let bytes = self.take_bytes2(lexer);
580 self.span2.merge(lexer.span_ref());
581 yield_term(lexer, TokenID::Bin, arena.bin(bytes), self.span2);
582 lexer.begin(Mode::Expr);
583 }
584 Rule::Bin => {
585 lexer.begin(Mode::Bin);
586 self.span2 = lexer.span();
587 }
588 Rule::Text => {
589 lexer.begin(Mode::Text);
590 self.span2 = lexer.span();
591 }
592 Rule::BinSpace | Rule::TextSpace => {
593 self.span2.merge(lexer.span_ref());
594 }
595 Rule::BinNewLine | Rule::TextNewLine => {
596 self.span2.merge(lexer.span_ref());
598 }
599 r @ (Rule::BinCount | Rule::TextCount) => {
600 let s = str::from_utf8(&lexer.buffer)
601 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
602 let mut s = String::from(s.trim());
603 self.span2.merge(lexer.span_ref());
604 if &s[s.len() - 1..] == "\n" {
605 }
607 if &s[s.len() - 1..] == ":" {
608 s.pop();
609 }
610 self.bin_count = s
611 .parse()
612 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
613 if self.bin_count > 0 {
614 if r == Rule::BinCount {
615 lexer.begin(Mode::BinCount);
616 } else {
617 lexer.begin(Mode::TextCount);
618 }
619 lexer.clear();
620 lexer.accum();
621 }
622 }
623 r @ (Rule::BinCountAnyChar | Rule::TextCountAnyChar) => {
624 self.span2.merge(lexer.span_ref());
625 self.bin_count -= 1;
626 if self.bin_count == 0 {
627 self.buffer2.extend(&lexer.buffer);
628 lexer.clear();
629 if r == Rule::BinCountAnyChar {
630 lexer.begin(Mode::Bin);
631 } else {
632 lexer.begin(Mode::Text);
633 }
634 }
635 }
636 r @ (Rule::BinCountNLChar | Rule::TextCountNewLine) => {
637 self.span2.merge(lexer.span_ref());
644 if r == Rule::TextCountNewLine {
645 let len = lexer.buffer.len();
646 if len >= 2 && lexer.buffer[len - 2] == b'\r' {
647 lexer.buffer.truncate(len - 2);
648 lexer.buffer.push(b'\n');
649 }
650 }
651 self.bin_count -= 1;
652 if self.bin_count == 0 {
653 self.buffer2.extend(&lexer.buffer);
654 lexer.clear();
655 if r == Rule::BinCountNLChar {
656 lexer.begin(Mode::Bin);
657 } else {
658 lexer.begin(Mode::Text);
659 }
660 }
661 }
662 r @ (Rule::BinRightBrace | Rule::TextRightBrace) => {
663 self.span2.merge(lexer.span_ref());
664 if r == Rule::BinRightBrace {
665 let bytes = self.take_bytes2(lexer);
666 yield_term(lexer, TokenID::Bin, arena.bin(bytes), self.span2);
667 } else {
668 let s = self.take_str2(lexer)?;
669 yield_term(lexer, TokenID::Str, arena.str(s), self.span2);
670 }
671 lexer.begin(Mode::Expr);
672 }
673 r @ (Rule::BinLabelStart | Rule::TextLabelStart) => {
674 self.span2.merge(lexer.span_ref());
675
676 self.bin_label.clear();
677 let len = lexer.buffer.len();
678 if lexer.buffer[len - 1] == b'\n' {
679 self.bin_label.push(b'\n');
681 lexer.buffer.pop();
682 let len = lexer.buffer.len();
683 if lexer.buffer[len - 1] == b'\r' {
684 self.bin_label.insert(0, b'\r');
685 lexer.buffer.pop();
686 }
687 } else {
688 let len = lexer.buffer.len();
689 let b = lexer.buffer[len - 1];
690 self.bin_label.push(b);
691 lexer.buffer.pop();
692 }
693
694 let buf = std::mem::take(&mut lexer.buffer);
695 self.bin_label.extend(buf);
696
697 if r == Rule::BinLabelStart {
698 lexer.begin(Mode::BinLabel);
699 } else {
700 lexer.begin(Mode::TextLabel);
701 }
702 }
703 r @ (Rule::BinLabelEnd | Rule::TextLabelEnd) => {
704 self.span2.merge(lexer.span_ref());
705
706 if lexer.buffer[0] != b':' {
707 }
709 if lexer.buffer == self.bin_label {
710 if r == Rule::BinLabelEnd {
711 lexer.begin(Mode::Bin);
712 } else {
713 lexer.begin(Mode::Text);
714 }
715 } else {
716 if r == Rule::TextLabelEnd && lexer.buffer[0] == b'\r' {
717 lexer.buffer.remove(0);
718 }
719 self.buffer2.extend(&lexer.buffer);
720 }
721 }
722 r @ (Rule::BinLabelNLChar | Rule::TextLabelNewLine) => {
723 self.span2.merge(lexer.span_ref());
725
726 if r == Rule::TextLabelNewLine && lexer.buffer[0] == b'\r' {
727 lexer.buffer.remove(0);
728 }
729 self.buffer2.extend(&lexer.buffer);
730 }
731 Rule::BinLabelAnyChar | Rule::TextLabelAnyChar => {
732 self.span2.merge(lexer.span_ref());
733 self.buffer2.extend(&lexer.buffer);
734 }
735 Rule::LeftBrace => {
736 lexer.begin(Mode::Script);
737 lexer.clear();
738 lexer.accum();
739 self.span2 = lexer.span();
740 }
741 Rule::ScriptNotBraces => {
742 self.span2.merge(lexer.span_ref());
743 }
744 Rule::ScriptLeftBrace => {
745 self.span2.merge(lexer.span_ref());
746 self.script_curly_nest_count += 1;
747 }
748 Rule::ScriptRightBrace => {
749 self.span2.merge(lexer.span_ref());
750 if self.script_curly_nest_count != 0 {
751 self.script_curly_nest_count -= 1;
752 } else {
753 lexer.buffer.pop();
754 let s = self.take_str(lexer)?;
755 yield_term(lexer, TokenID::Str, arena.str(s), self.span2);
756 lexer.begin(Mode::Expr);
757 }
758 }
759 Rule::ScriptNewLine => {
760 self.span2.merge(lexer.span_ref());
763 let len = lexer.buffer.len();
764 if len >= 2 && lexer.buffer[len - 2] == b'\r' {
765 lexer.buffer.truncate(len - 2);
766 lexer.buffer.push(b'\n');
767 }
768 }
769 Rule::HexConst => {
770 lexer.buffer.drain(0..2);
771 let s = self.take_str(lexer)?;
772 let val = parse_i64(s.as_str(), 16)
773 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
774 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
775 }
776 Rule::BaseConst => {
777 let s = self.take_str(lexer)?;
778 let (base_str, digits) = s.split_once('\'').ok_or(ParlexError {
779 message: format!("missing `'` separator"),
780 span: Some(lexer.span()),
781 })?;
782 let base: u32 = base_str
783 .parse()
784 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
785 let val = parse_i64(digits, base)
786 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
787 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
788 }
789 Rule::CharHex => {
790 let mut s = self.take_str(lexer)?;
791 s.drain(0..4);
792 let val = parse_i64(s.as_str(), 16)
793 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
794 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
795 }
796 Rule::CharOct => {
797 let mut s = self.take_str(lexer)?;
798 s.drain(0..3);
799 let val = parse_i64(s.as_str(), 8)
800 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
801 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
802 }
803 Rule::CharNewLine1 | Rule::CharNewLine2 | Rule::CharNewLine4 => {
804 yield_term(lexer, TokenID::Int, arena.int('\n' as i64), lexer.span());
806 }
807 Rule::CharNotBackslash => {
808 let mut s = self.take_str(lexer)?;
809 s.drain(0..2);
810 let val = s.chars().next().ok_or(ParlexError {
811 message: format!("invalid char"),
812 span: Some(lexer.span()),
813 })? as i64;
814 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
815 }
816 Rule::CharCtrl => {
817 let mut s = self.take_str(lexer)?;
818 s.drain(0..4);
819 let val = s.chars().next().ok_or(ParlexError {
820 message: format!("invalid char"),
821 span: Some(lexer.span()),
822 })? as i64
823 - '@' as i64;
824 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
825 }
826 Rule::CharDel1 | Rule::CharDel2 => {
827 yield_term(lexer, TokenID::Int, arena.int('\x7F' as i64), lexer.span());
828 }
829 Rule::CharEsc => {
830 yield_term(lexer, TokenID::Int, arena.int('\x1B' as i64), lexer.span());
831 }
832 Rule::CharBell => {
833 yield_term(
834 lexer,
835 TokenID::Int,
836 arena.int('\u{0007}' as i64),
837 lexer.span(),
838 );
839 }
840 Rule::CharBackspace => {
841 yield_term(
842 lexer,
843 TokenID::Int,
844 arena.int('\u{0008}' as i64),
845 lexer.span(),
846 );
847 }
848 Rule::CharFormFeed => {
849 yield_term(
850 lexer,
851 TokenID::Int,
852 arena.int('\u{000C}' as i64),
853 lexer.span(),
854 );
855 }
856 Rule::CharNewLine3 => {
857 yield_term(lexer, TokenID::Int, arena.int('\n' as i64), lexer.span());
858 }
859 Rule::CharCarriageReturn => {
860 yield_term(lexer, TokenID::Int, arena.int('\r' as i64), lexer.span());
861 }
862 Rule::CharTab => {
863 yield_term(lexer, TokenID::Int, arena.int('\t' as i64), lexer.span());
864 }
865 Rule::CharVerticalTab => {
866 yield_term(
867 lexer,
868 TokenID::Int,
869 arena.int('\u{000B}' as i64),
870 lexer.span(),
871 );
872 }
873 Rule::CharAny => {
874 let mut s = self.take_str(lexer)?;
875 s.drain(0..3);
876 let val = s.chars().next().ok_or(ParlexError {
877 message: format!("invalid char"),
878 span: Some(lexer.span()),
879 })? as i64;
880 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
881 }
882 Rule::OctConst => {
883 let s = self.take_str(lexer)?;
884 let val = parse_i64(s.as_str(), 8)
885 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
886 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
887 }
888 Rule::DecConst => {
889 let s = self.take_str(lexer)?;
890 let val = parse_i64(s.as_str(), 10)
891 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
892 yield_term(lexer, TokenID::Int, arena.int(val), lexer.span());
893 }
894 Rule::FPConst => {
895 let s = self.take_str(lexer)?;
896 let val: f64 = s
897 .parse()
898 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
899 yield_term(lexer, TokenID::Real, arena.real(val), lexer.span());
900 }
901 Rule::DoubleQuote => {
902 self.nest_count += 1;
907 yield_id(lexer, TokenID::LeftParen);
908 lexer.begin(Mode::Str);
909 lexer.clear();
910 lexer.accum();
911 }
912 Rule::SingleQuote => {
913 lexer.begin(Mode::Atom);
914 lexer.clear();
915 lexer.accum();
916 }
917 Rule::StrAtomCharHex => {
918 let len = lexer.buffer.len();
919 let b: u8 = parse_i64(
920 str::from_utf8(&lexer.buffer[len - 2..])
921 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?,
922 16,
923 )
924 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?
925 .try_into()
926 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
927 lexer.buffer.truncate(len - 4);
928 lexer.buffer.push(b);
929 }
930 Rule::StrAtomCharOct => {
931 let slash_pos = lexer.buffer.iter().rposition(|&b| b == b'\\').unwrap();
932 let b: u8 = parse_i64(
933 str::from_utf8(&lexer.buffer[slash_pos + 1..])
934 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?,
935 8,
936 )
937 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?
938 .try_into()
939 .map_err(|e| ParlexError::from_err(e, Some(lexer.span())))?;
940 lexer.buffer.truncate(slash_pos);
941 lexer.buffer.push(b);
942 }
943 Rule::StrAtomCharCtrl => {
944 let len = lexer.buffer.len();
945 let b = lexer.buffer[len - 1] - b'@';
946 lexer.buffer.truncate(len - 3);
947 lexer.buffer.push(b);
948 }
949 Rule::StrAtomCharDel1 => {
950 let idx = lexer.buffer.len() - 2;
951 lexer.buffer.truncate(idx);
952 lexer.buffer.push(b'\x7F');
953 }
954 Rule::StrAtomCharDel2 => {
955 let idx = lexer.buffer.len() - 3;
956 lexer.buffer.truncate(idx);
957 lexer.buffer.push(b'\x7F');
958 }
959 Rule::StrAtomCharEsc => {
960 let idx = lexer.buffer.len() - 2;
961 lexer.buffer.truncate(idx);
962 lexer.buffer.push(b'\x1B');
963 }
964 Rule::StrAtomCharBell => {
965 let idx = lexer.buffer.len() - 2;
966 lexer.buffer.truncate(idx);
967 lexer.buffer.push(b'\x07');
968 }
969 Rule::StrAtomCharBackspace => {
970 let idx = lexer.buffer.len() - 2;
971 lexer.buffer.truncate(idx);
972 lexer.buffer.push(b'\x08');
973 }
974 Rule::StrAtomCharFormFeed => {
975 let idx = lexer.buffer.len() - 2;
976 lexer.buffer.truncate(idx);
977 lexer.buffer.push(b'\x0C');
978 }
979 Rule::StrAtomCharNewLine => {
980 let idx = lexer.buffer.len() - 2;
981 lexer.buffer.truncate(idx);
982 lexer.buffer.push(b'\n');
983 }
984 Rule::StrAtomCharCarriageReturn => {
985 let idx = lexer.buffer.len() - 2;
986 lexer.buffer.truncate(idx);
987 lexer.buffer.push(b'\r');
988 }
989 Rule::StrAtomCharTab => {
990 let idx = lexer.buffer.len() - 2;
991 lexer.buffer.truncate(idx);
992 lexer.buffer.push(b'\t');
993 }
994 Rule::StrAtomVerticalTab => {
995 let idx = lexer.buffer.len() - 2;
996 lexer.buffer.truncate(idx);
997 lexer.buffer.push(b'\x0B');
998 }
999 Rule::StrAtomCharSkipNewLine => {
1000 lexer.buffer.pop();
1002 let idx = lexer.buffer.len() - 1;
1003 if lexer.buffer[idx] == b'\r' {
1004 lexer.buffer.pop();
1005 }
1006 lexer.buffer.pop();
1007 }
1008 Rule::StrAtomCharAny | Rule::StrAtomCharBackslash => {
1009 let idx = lexer.buffer.len() - 2;
1010 lexer.buffer.remove(idx);
1011 }
1012 Rule::StrChar | Rule::AtomChar | Rule::StrAtomCarriageReturn => {}
1013 Rule::StrDoubleQuote => {
1014 lexer.begin(Mode::Expr);
1015 lexer.buffer.pop();
1016 let s = self.take_str(lexer)?;
1017 yield_term(lexer, TokenID::Str, arena.str(s), lexer.span());
1018 self.nest_count -= 1;
1020 yield_id(lexer, TokenID::RightParen);
1021 }
1022 Rule::AtomSingleQuote => {
1023 lexer.begin(Mode::Expr);
1024 lexer.buffer.pop();
1025 let s = self.take_str(lexer)?;
1026 yield_term(lexer, TokenID::Atom, arena.atom(s), lexer.span());
1027 }
1028 Rule::AtomLeftParen => {
1029 lexer.begin(Mode::Expr);
1030 self.nest_count += 1;
1031 let mut s = self.take_str(lexer)?;
1032 s.truncate(s.len() - 2);
1033 yield_term(lexer, TokenID::Func, arena.atom(s), lexer.span());
1034 }
1035 Rule::AtomLeftBrace => {}
1036 Rule::StrLeftBrace => {
1037 lexer.begin(Mode::Expr);
1038 self.nest_count += 1;
1039 self.curly_nest_count += 1;
1040 let mut s = self.take_str(lexer)?;
1041 s.pop();
1042 yield_term(lexer, TokenID::Str, arena.str(s), lexer.span());
1043 let op_tab_idx = arena.lookup_oper("++");
1044 yield_optab(
1045 lexer,
1046 TokenID::AtomOper,
1047 arena.atom("++"),
1048 op_tab_idx,
1049 lexer.span(),
1050 );
1051 yield_id(lexer, TokenID::LeftParen);
1052 }
1053 Rule::StrAtomNewLine => {
1054 let len = lexer.buffer.len();
1058 if len >= 2 && lexer.buffer[len - 2] == b'\r' {
1059 lexer.buffer.truncate(len - 2);
1060 lexer.buffer.push(b'\n');
1061 }
1062 }
1063 Rule::Error => {
1064 let s = self.take_str(lexer)?;
1065 return Err(ParlexError {
1066 message: format!("error on lexeme {:?}", s),
1067 span: Some(lexer.span()),
1068 });
1069 }
1070 Rule::End => {
1071 if lexer.mode() == Mode::Expr {
1072 yield_id(lexer, TokenID::End);
1073 } else {
1074 return Err(ParlexError {
1075 message: format!("unexpected end of stream"),
1076 span: Some(lexer.span()),
1077 });
1078 }
1079 }
1080 }
1081
1082 log::trace!(
1083 "ACTION end: mode {:?}, rule {:?}, buf {:?}, buf2 {:?}, label {:?}, accum {}",
1084 lexer.mode(),
1085 rule,
1086 std::string::String::from_utf8_lossy(&lexer.buffer),
1087 std::string::String::from_utf8_lossy(&self.buffer2),
1088 std::string::String::from_utf8_lossy(&self.bin_label),
1089 lexer.accum_flag,
1090 );
1091
1092 Ok(())
1093 }
1094}
1095
1096pub struct TermLexer<I>
1146where
1147 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
1148{
1149 pub(crate) lexer: Lexer<I, TermLexerDriver<I>, Arena>,
1152}
1153
1154impl<I> TermLexer<I>
1155where
1156 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
1157{
1158 pub fn try_new(input: I, encoding: Encoding) -> Result<Self, ParlexError> {
1192 let driver = TermLexerDriver {
1193 _marker: PhantomData,
1194 encoding,
1195 nest_count: 0,
1196 comment_nest_count: 0,
1197 curly_nest_count: 0,
1198 script_curly_nest_count: 0,
1199 bin_count: 0,
1200 bin_label: Vec::new(),
1201 date_format: String::new(),
1202 buffer2: Vec::new(),
1203 span2: Span::default(),
1204 };
1205 let lexer = Lexer::try_new(input, driver)?;
1206 Ok(Self { lexer })
1207 }
1208}
1209
1210impl<I> TryNextWithContext<Arena, LexerStats> for TermLexer<I>
1211where
1212 I: TryNextWithContext<Arena, Item = u8, Error: std::fmt::Display + 'static>,
1213{
1214 type Item = TermToken;
1216
1217 type Error = ParlexError;
1219
1220 fn try_next_with_context(
1243 &mut self,
1244 context: &mut Arena,
1245 ) -> Result<Option<TermToken>, ParlexError> {
1246 self.lexer.try_next_with_context(context)
1247 }
1248
1249 fn stats(&self) -> LexerStats {
1250 self.lexer.stats()
1251 }
1252}
1253
1254#[cfg(test)]
1256mod tests {
1257 use arena_terms::View;
1258 use parlex::Token;
1259 use try_next::IterInput;
1260
1261 use super::*;
1262
1263 fn lex(arena: &mut Arena, s: &str) -> Vec<TermToken> {
1264 let input = IterInput::from(s.bytes());
1265 let mut lexer = TermLexer::try_new(input, Encoding::Utf8).expect("cannot create lexer");
1266 lexer.try_collect_with_context(arena).expect("lexer error")
1267 }
1268
1269 #[test]
1270 fn test_dates() {
1271 let _ = env_logger::builder().is_test(true).try_init();
1272 let mut arena = Arena::new();
1273 const DATES: &[(&str, u8)] = &[
1274 ("date{-5381856000000}", 0),
1275 ("date{-5381830320000}", 1),
1276 ("date{-5381830311000}", 2),
1277 ("date{-5381830310999}", 3),
1278 ("date{1799-06-16}", 0),
1279 ("date{1799-06-16Z}", 0),
1280 ("date{1799-06-16 Z}", 0),
1281 ("date{1799-06-16-00:00}", 0),
1282 ("date{1799-06-16 -00:00}", 0),
1283 ("date{1799-06-16T07:08}", 1),
1284 ("date{1799-06-16T07:08:09}", 2),
1285 ("date{1799-06-16T07:08:09Z}", 2),
1286 ("date{1799-06-16T07:08:09.001Z}", 3),
1287 ("date{1799-06-16T07:08:09 Z}", 2),
1288 ("date{1799-06-16T07:08:09.001 Z}", 3),
1289 ("date{1799-06-16T07:08:09+00:00}", 2),
1290 ("date{1799-06-16T07:08:09.001+00:00}", 3),
1291 ("date{1799-06-16T07:08:09 +00:00}", 2),
1292 ("date{1799-06-16T07:08:09.001 +00:00}", 3),
1293 ("date{1799-06-16T07:08:09Z}", 2),
1294 ("date{1799-06-16T07:08:09.001Z}", 3),
1295 ("date{1799-06-16 07:08:09 Z}", 2),
1296 ("date{1799-06-16T07:08:09.001 Z}", 3),
1297 ("date{1799-06-16 07:08:09+00:00}", 2),
1298 ("date{1799-06-16T07:08:09.001+00:00}", 3),
1299 ("date{1799-06-16 07:08:09 +00:00}", 2),
1300 ("date{1799-06-16 07:08:09.001 +00:00}", 3),
1301 ("date{1799-06-16T07:08Z}", 1),
1302 ("date{1799-06-16T07:08 Z }", 1),
1303 ("date{ 1799-06-16T07:08+00:00}", 1),
1304 ("date{ 1799-06-16T07:08 +00:00 }", 1),
1305 ("date{06/16/1799Z}", 0),
1306 ("date{06/16/1799 Z}", 0),
1307 ("date{06/16/1799+00:00}", 0),
1308 ("date{06/16/1799 +00:00}", 0),
1309 ("date{06/16/1799 07:08Z}", 1),
1310 ("date{06/16/1799 07:08:09Z}", 2),
1311 ("date{06/16/1799 07:08:09.001Z}", 3),
1312 ("date{06/16/1799 07:08 Z}", 1),
1313 ("date{06/16/1799 07:08:09 Z}", 2),
1314 ("date{06/16/1799 07:08:09.001 Z}", 3),
1315 ("date{06/16/1799 07:08+00:00}", 1),
1316 ("date{06/16/1799 07:08:09+00:00}", 2),
1317 ("date{06/16/1799 07:08:09.001+00:00}", 3),
1318 ("date{06/16/1799 07:08 +00:00}", 1),
1319 ("date{06/16/1799 07:08:09 +00:00}", 2),
1320 ("date{06/16/1799 07:08:09.001 +00:00}", 3),
1321 ("date{16-Jun-1799Z}", 0),
1322 ("date{16-jun-1799 Z}", 0),
1323 ("date{16-JUN-1799+00:00}", 0),
1324 ("date{16-Jun-1799 +00:00}", 0),
1325 ("date{16-Jun-1799 07:08Z}", 1),
1326 ("date{16-JUN-1799 07:08:09Z}", 2),
1327 ("date{16-Jun-1799 07:08:09.001Z}", 3),
1328 ("date{16-Jun-1799 07:08 Z}", 1),
1329 ("date{16-jun-1799 07:08:09 Z}", 2),
1330 ("date{16-Jun-1799 07:08:09.001 Z}", 3),
1331 ("date{16-Jun-1799 07:08+00:00}", 1),
1332 ("date{16-Jun-1799 07:08:09+00:00}", 2),
1333 ("date{16-Jun-1799 07:08:09.001+00:00}", 3),
1334 ("date{16-Jun-1799 07:08 +00:00}", 1),
1335 ("date{16-Jun-1799 07:08:09 +00:00}", 2),
1336 ("date{16-Jun-1799 07:08:09.001 +00:00}", 3),
1337 ];
1338 for (s, k) in DATES {
1339 let mut ts = lex(&mut arena, s);
1340 let tok = ts.remove(0);
1341 assert_eq!(tok.token_id, TokenID::Date);
1342 let term = Term::try_from(tok.value).unwrap();
1343 let d = term.unpack_date(&arena).unwrap();
1344 assert_eq!(
1345 d,
1346 match k {
1347 0 => -5381856000000,
1348 1 => -5381830320000,
1349 2 => -5381830311000,
1350 3 => -5381830310999,
1351 _ => unreachable!(),
1352 }
1353 );
1354 }
1355 }
1356
1357 #[test]
1358 fn test_atoms() {
1359 let mut arena = Arena::new();
1360 let ts = lex(&mut arena, "\na+foo-x '^&%^&%^&%''abc' 'AAA'");
1361 dbg!(&ts);
1362 assert!(ts.len() == 9);
1363 assert!(ts.iter().take(ts.len() - 1).all(|t| {
1364 t.span().unwrap().start.line == 1
1365 && matches!(
1366 Term::try_from(t.value.clone())
1367 .unwrap()
1368 .view(&arena)
1369 .unwrap(),
1370 View::Atom(_)
1371 )
1372 }));
1373 }
1374
1375 #[test]
1376 fn test_bin() {
1377 let mut arena = Arena::new();
1378 let ts = lex(
1379 &mut arena,
1380 "% single line comment\nbin{3:\x00\x01\x02 eob:\x00\x01:aaa\x02:eob eob\n\x00\neob eob\r\n\x00\r\neob\r\n}\r\nhex{ 0203 0405 FE }",
1381 );
1382 dbg!(&ts);
1383 assert!(ts.len() == 3);
1384 assert!(matches!(
1385 Term::try_from(ts[0].value.clone())
1386 .unwrap()
1387 .view(&arena)
1388 .unwrap(),
1389 View::Bin(_)
1390 ));
1391 match Term::try_from(ts[0].value.clone())
1392 .unwrap()
1393 .view(&arena)
1394 .unwrap()
1395 {
1396 View::Bin(bytes) => assert!(bytes == &[0, 1, 2, 0, 1, 58, 97, 97, 97, 2, 0, 0,]),
1397 _ => unreachable!(),
1398 }
1399 }
1400
1401 #[test]
1402 fn test_text() {
1403 let mut arena = Arena::new();
1404 let ts = lex(
1405 &mut arena,
1406 "/* single /* line */ comment */\ntext{3:abc eob:de:aaa:eob eob\n0\neob eob\r\n1\r\neob\r\n}\r\n",
1407 );
1408 dbg!(&ts);
1409 assert!(ts.len() == 2);
1410 assert!(matches!(
1411 Term::try_from(ts[0].value.clone())
1412 .unwrap()
1413 .view(&arena)
1414 .unwrap(),
1415 View::Str(_)
1416 ));
1417 match Term::try_from(ts[0].value.clone())
1418 .unwrap()
1419 .view(&arena)
1420 .unwrap()
1421 {
1422 View::Str(s) => assert!(s == "abcde:aaa01"),
1423 _ => unreachable!(),
1424 }
1425 }
1426
1427 #[test]
1428 fn test_texts() {
1429 let mut arena = Arena::new();
1430 let ts = lex(
1431 &mut arena,
1432 "/* single [ ( { /* line */ comment */\n\"hello\" {hello} text{5:hello} text{e:hello:e} text{e:h:e e:e:e 2:ll e:o:e} text{\ne\nhello\ne}",
1433 );
1434 dbg!(&ts);
1435 assert!(ts.len() == 9);
1438 let strs: Vec<&TermToken> = ts
1440 .iter()
1441 .filter(|t| {
1442 matches!(t.token_id, TokenID::Str)
1443 })
1444 .collect();
1445 assert_eq!(strs.len(), 6);
1446 assert!(strs.iter().all(|t| {
1447 match Term::try_from(t.value.clone())
1448 .unwrap()
1449 .view(&arena)
1450 .unwrap()
1451 {
1452 View::Str(s) => s == "hello",
1453 _ => false,
1454 }
1455 }));
1456 }
1457
1458 #[test]
1459 fn test_integers() {
1460 let mut arena = Arena::new();
1461 let ts = lex(&mut arena, "[2'01010001111, 10'123, 36'AZ]");
1462 assert!(ts.len() == 8);
1463 assert!(matches!(ts[1].token_id, TokenID::Int));
1464 }
1465
1466 #[test]
1467 fn lex_string_subs() {
1468 let _ = env_logger::builder().is_test(true).try_init();
1469 let arena = &mut Arena::new();
1470 let ts = lex(arena, "\"aaa{1 + 2}bbb{3 * 4}ccc\"");
1471 assert_eq!(ts.len(), 20);
1473 assert_eq!(ts[0].token_id, TokenID::LeftParen);
1474 assert_eq!(ts[18].token_id, TokenID::RightParen);
1475 let t0: Term = ts[1].value.clone().try_into().unwrap();
1476 let t1: Term = ts[9].value.clone().try_into().unwrap();
1477 let t2: Term = ts[17].value.clone().try_into().unwrap();
1478 assert_eq!(t0.unpack_str(arena).unwrap(), "aaa");
1479 assert_eq!(t1.unpack_str(arena).unwrap(), "bbb");
1480 assert_eq!(t2.unpack_str(arena).unwrap(), "ccc");
1481 }
1482
1483 #[test]
1485 fn string_preserves_lf() {
1486 let mut arena = Arena::new();
1487 let ts = lex(&mut arena, "\"hello\nworld\"");
1488 assert_eq!(ts.len(), 4);
1490 let t: Term = ts[1].value.clone().try_into().unwrap();
1491 assert_eq!(t.unpack_str(&arena).unwrap(), "hello\nworld");
1492 }
1493
1494 #[test]
1496 fn string_normalizes_crlf_to_lf() {
1497 let mut arena = Arena::new();
1498 let ts = lex(&mut arena, "\"hello\r\nworld\"");
1499 assert_eq!(ts.len(), 4);
1500 let t: Term = ts[1].value.clone().try_into().unwrap();
1501 assert_eq!(t.unpack_str(&arena).unwrap(), "hello\nworld");
1502 }
1503
1504 #[test]
1506 fn string_preserves_bare_cr() {
1507 let mut arena = Arena::new();
1508 let ts = lex(&mut arena, "\"hello\rworld\"");
1509 assert_eq!(ts.len(), 4);
1510 let t: Term = ts[1].value.clone().try_into().unwrap();
1511 assert_eq!(t.unpack_str(&arena).unwrap(), "hello\rworld");
1512 }
1513
1514 #[test]
1516 fn atom_preserves_lf() {
1517 let mut arena = Arena::new();
1518 let ts = lex(&mut arena, "'hello\nworld'");
1519 assert_eq!(ts.len(), 2);
1520 let t: Term = ts[0].value.clone().try_into().unwrap();
1521 assert_eq!(t.unpack_atom(&arena, &[]).unwrap(), "hello\nworld");
1522 }
1523
1524 #[test]
1526 fn atom_normalizes_crlf_to_lf() {
1527 let mut arena = Arena::new();
1528 let ts = lex(&mut arena, "'hello\r\nworld'");
1529 assert_eq!(ts.len(), 2);
1530 let t: Term = ts[0].value.clone().try_into().unwrap();
1531 assert_eq!(t.unpack_atom(&arena, &[]).unwrap(), "hello\nworld");
1532 }
1533
1534 #[test]
1536 fn atom_preserves_bare_cr() {
1537 let mut arena = Arena::new();
1538 let ts = lex(&mut arena, "'hello\rworld'");
1539 assert_eq!(ts.len(), 2);
1540 let t: Term = ts[0].value.clone().try_into().unwrap();
1541 assert_eq!(t.unpack_atom(&arena, &[]).unwrap(), "hello\rworld");
1542 }
1543
1544 #[test]
1546 fn string_preserves_cr_at_start() {
1547 let mut arena = Arena::new();
1548 let ts = lex(&mut arena, "\"\rhello\"");
1549 assert_eq!(ts.len(), 4);
1550 let t: Term = ts[1].value.clone().try_into().unwrap();
1551 assert_eq!(t.unpack_str(&arena).unwrap(), "\rhello");
1552 }
1553
1554 #[test]
1556 fn string_normalizes_crlf_at_start() {
1557 let mut arena = Arena::new();
1558 let ts = lex(&mut arena, "\"\r\nhello\"");
1559 assert_eq!(ts.len(), 4);
1560 let t: Term = ts[1].value.clone().try_into().unwrap();
1561 assert_eq!(t.unpack_str(&arena).unwrap(), "\nhello");
1562 }
1563
1564 #[test]
1566 fn script_block_normalizes_crlf() {
1567 let mut arena = Arena::new();
1568 let ts = lex(&mut arena, "{foo\r\nbar}");
1569 assert_eq!(ts.len(), 2);
1570 let t: Term = ts[0].value.clone().try_into().unwrap();
1571 assert_eq!(t.unpack_str(&arena).unwrap(), "foo\nbar");
1572 }
1573
1574 #[test]
1576 fn script_block_preserves_lf() {
1577 let mut arena = Arena::new();
1578 let ts = lex(&mut arena, "{foo\nbar}");
1579 assert_eq!(ts.len(), 2);
1580 let t: Term = ts[0].value.clone().try_into().unwrap();
1581 assert_eq!(t.unpack_str(&arena).unwrap(), "foo\nbar");
1582 }
1583
1584 #[test]
1587 fn bin_counted_preserves_leading_crlf() {
1588 let mut arena = Arena::new();
1589 let ts = lex(&mut arena, "bin{2:\r\n}");
1590 assert_eq!(ts.len(), 2);
1591 let t: Term = ts[0].value.clone().try_into().unwrap();
1592 match t.view(&arena).unwrap() {
1593 View::Bin(bytes) => assert_eq!(bytes, &[0x0D, 0x0A]),
1594 v => panic!("expected Bin, got {:?}", v),
1595 }
1596 }
1597
1598 #[test]
1600 fn bin_counted_preserves_nonleading_crlf() {
1601 let mut arena = Arena::new();
1602 let ts = lex(&mut arena, "bin{3:A\r\n}");
1603 assert_eq!(ts.len(), 2);
1604 let t: Term = ts[0].value.clone().try_into().unwrap();
1605 match t.view(&arena).unwrap() {
1606 View::Bin(bytes) => assert_eq!(bytes, &[0x41, 0x0D, 0x0A]),
1607 v => panic!("expected Bin, got {:?}", v),
1608 }
1609 }
1610
1611 #[test]
1615 fn text_counted_normalizes_leading_crlf() {
1616 let mut arena = Arena::new();
1617 let ts = lex(&mut arena, "text{1:\r\n}");
1618 assert_eq!(ts.len(), 2);
1619 let t: Term = ts[0].value.clone().try_into().unwrap();
1620 assert_eq!(t.unpack_str(&arena).unwrap(), "\n");
1621 }
1622
1623 #[test]
1626 fn text_counted_normalizes_nonleading_crlf() {
1627 let mut arena = Arena::new();
1628 let ts = lex(&mut arena, "text{2:A\r\n}");
1629 assert_eq!(ts.len(), 2);
1630 let t: Term = ts[0].value.clone().try_into().unwrap();
1631 assert_eq!(t.unpack_str(&arena).unwrap(), "A\n");
1632 }
1633
1634 #[test]
1636 fn string_normalizes_multiple_crlf() {
1637 let mut arena = Arena::new();
1638 let ts = lex(&mut arena, "\"a\r\nb\r\nc\"");
1639 assert_eq!(ts.len(), 4);
1640 let t: Term = ts[1].value.clone().try_into().unwrap();
1641 assert_eq!(t.unpack_str(&arena).unwrap(), "a\nb\nc");
1642 }
1643}