Implementation of the UM-32 "Universal Machine" as described by the Cult of the Bound Variable

move `unescape_str` into `parse` module

tjh 3ed9dee0 16c843c7

Changed files
+45 -62
src
+45 -2
src/asm/parse.rs
··· 1 1 use super::Token; 2 2 use crate::Register; 3 3 use logos::{Logos, Source}; 4 - use std::{borrow::Cow, collections::HashMap, iter::Peekable, ops::Range}; 4 + use std::{borrow::Cow, collections::HashMap, iter::Peekable, ops::Range, str::CharIndices}; 5 5 6 6 pub fn parse(_unit: impl std::fmt::Display, source: &str) -> Result<ParsedProgram, Error> { 7 7 Parser::new(source).parse() ··· 680 680 { 681 681 match tokens.next() { 682 682 Some((Token::String(value), span)) => { 683 - let unescaped = crate::str::unescape_str(value).map_err(|_| Error::eof())?; 683 + let unescaped = unescape_str(value).map_err(|_| Error::eof())?; 684 684 Ok((unescaped, span)) 685 685 } 686 686 Some((token, span)) => Err(Error::new( ··· 694 694 fn merge_spans(start: &Range<usize>, end: &Range<usize>) -> Range<usize> { 695 695 start.start..end.end 696 696 } 697 + 698 + #[derive(Debug)] 699 + #[allow(unused)] 700 + pub struct InvalidCharacterEscape(pub char, pub usize); 701 + 702 + pub fn unescape_str(s: &str) -> Result<Cow<str>, InvalidCharacterEscape> { 703 + fn escape_inner(c: &str, i: &mut CharIndices<'_>) -> Result<String, InvalidCharacterEscape> { 704 + let mut buffer = c.to_owned(); 705 + let mut in_escape = true; 706 + 707 + for (index, c) in i { 708 + match (in_escape, c) { 709 + (false, '\\') => { 710 + in_escape = true; 711 + continue; 712 + } 713 + (false, c) => buffer.push(c), 714 + (true, '\\') => buffer.push('\\'), 715 + (true, 'n') => buffer.push('\n'), 716 + (true, '0') => buffer.push('\0'), 717 + (true, '"') => buffer.push('"'), 718 + (true, '\'') => buffer.push('\''), 719 + (true, 'r') => buffer.push('\r'), 720 + (true, 't') => buffer.push('\t'), 721 + (true, c) => Err(InvalidCharacterEscape(c, index))?, 722 + } 723 + 724 + in_escape = false; 725 + } 726 + 727 + Ok(buffer) 728 + } 729 + 730 + let mut char_indicies = s.char_indices(); 731 + for (index, c) in &mut char_indicies { 732 + let scanned = &s[..index]; 733 + if c == '\\' { 734 + return Ok(Cow::Owned(escape_inner(scanned, &mut char_indicies)?)); 735 + } 736 + } 737 + 738 + Ok(Cow::Borrowed(s)) 739 + }
-1
src/lib.rs
··· 4 4 pub mod asm; 5 5 pub mod ops; 6 6 pub mod reg; 7 - pub mod str; 8 7 9 8 use ops::Operation; 10 9 use reg::Register;
-59
src/str.rs
··· 1 - use std::{borrow::Cow, str::CharIndices}; 2 - 3 - #[derive(Debug)] 4 - pub struct InvalidCharacterEscape(pub char, pub usize); 5 - 6 - pub fn unescape_str(s: &str) -> Result<Cow<str>, InvalidCharacterEscape> { 7 - fn escape_inner(c: &str, i: &mut CharIndices<'_>) -> Result<String, InvalidCharacterEscape> { 8 - let mut buffer = c.to_owned(); 9 - let mut in_escape = true; 10 - 11 - for (index, c) in i { 12 - match (in_escape, c) { 13 - (false, '\\') => { 14 - in_escape = true; 15 - continue; 16 - } 17 - (false, c) => buffer.push(c), 18 - (true, '\\') => buffer.push('\\'), 19 - (true, 'n') => buffer.push('\n'), 20 - (true, '0') => buffer.push('\0'), 21 - (true, '"') => buffer.push('"'), 22 - (true, '\'') => buffer.push('\''), 23 - (true, 'r') => buffer.push('\r'), 24 - (true, 't') => buffer.push('\t'), 25 - (true, c) => Err(InvalidCharacterEscape(c, index))?, 26 - } 27 - 28 - in_escape = false; 29 - } 30 - 31 - Ok(buffer) 32 - } 33 - 34 - let mut char_indicies = s.char_indices(); 35 - for (index, c) in &mut char_indicies { 36 - let scanned = &s[..index]; 37 - if c == '\\' { 38 - return Ok(Cow::Owned(escape_inner(scanned, &mut char_indicies)?)); 39 - } 40 - } 41 - 42 - Ok(Cow::Borrowed(s)) 43 - } 44 - 45 - #[cfg(test)] 46 - mod tests { 47 - use std::borrow::Cow; 48 - 49 - use super::unescape_str; 50 - 51 - #[test] 52 - fn no_unescapes() { 53 - let s = "Hello, this string should have no characters that need unescaping."; 54 - let u = unescape_str(s).unwrap(); 55 - 56 - assert!(matches!(u, Cow::Borrowed(_))); 57 - assert_eq!(s, u); 58 - } 59 - }