Skip to content

Commit b7e6918

Browse files
committed
Fix parsing and printing of escape sequences in strings and bytes.
1 parent b4bbb7d commit b7e6918

File tree

5 files changed

+26
-10
lines changed

5 files changed

+26
-10
lines changed

src/bytes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ named!(escapedchar<StrSpan, Option<u8>>,
2727
}
2828
| preceded!(char!('x'), tuple!(one_of!("0123456789abcdefABCDEF"), one_of!("0123456789abcdefABCDEF"))) => { |(c1, c2): (char, char)|
2929
match (c1.to_digit(16), c2.to_digit(16)) {
30-
(Some(d1), Some(d2)) => Some(((d1 << 8) + d2) as u8),
30+
(Some(d1), Some(d2)) => Some(((d1 << 4) + d2) as u8),
3131
_ => unreachable!(),
3232
}
3333
}

src/expressions.rs

+4
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ mod tests {
642642
assert_parse_eq(atom(make_strspan(r#"r'fo \' o' "#)), Ok((make_strspan(" "),
643643
Box::new(Expression::String(vec![PyString { prefix: "r".to_string(), content: "fo \\' o".to_string() }])))
644644
));
645+
646+
assert_parse_eq(atom(make_strspan(r#"'\x8a'"#)), Ok((make_strspan(""),
647+
Box::new(Expression::String(vec![new_pystring("\u{8a}")])))
648+
));
645649
}
646650

647651
#[test]

src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn main() {
1515
let mut content = String::new();
1616
file.read_to_string(&mut content).expect("Could not read file");
1717
let (rest, ast) = file_input(make_strspan(&content)).unwrap();
18+
//println!("{:?}", ast);
1819
let output = format_module(&ast);
1920
if rest.fragment.0.len() > 0 {
2021
println!("\nUnparsed: {:?}\n\n", rest.fragment.0)

src/strings.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ named!(escapedchar<StrSpan, Option<char>>,
2626
}
2727
| preceded!(char!('x'), tuple!(one_of!("0123456789abcdefABCDEF"), one_of!("0123456789abcdefABCDEF"))) => { |(c1, c2): (char, char)|
2828
match (c1.to_digit(16), c2.to_digit(16)) {
29-
(Some(d1), Some(d2)) => ::std::char::from_u32((d1 << 8) + d2),
29+
(Some(d1), Some(d2)) => ::std::char::from_u32((d1 << 4) + d2),
3030
_ => unreachable!(),
3131
}
3232
}
@@ -37,15 +37,15 @@ named!(escapedchar<StrSpan, Option<char>>,
3737
| preceded!(char!('u'), count!(one_of!("0123456789abcdefABCDEF"), 4)) => { |v: Vec<char>| {
3838
let it: Vec<u32> = v.iter().map(|c| c.to_digit(16).unwrap()).collect();
3939
if let [d1, d2, d3, d4] = &it[..] {
40-
::std::char::from_u32((d1 << 24) + (d2 << 16) + (d3 << 8) + d4)
40+
::std::char::from_u32((d1 << 12) + (d2 << 8) + (d3 << 4) + d4)
4141
}
4242
else { unreachable!() }
4343
}}
4444
| preceded!(char!('U'), count!(one_of!("0123456789abcdefABCDEF"), 8)) => { |v: Vec<char>| {
4545
let it: Vec<u32> = v.iter().map(|c| c.to_digit(16).unwrap()).collect();
4646
if let [d1, d2, d3, d4, d5, d6, d7, d8] = &it[..] {
47-
::std::char::from_u32((d1 << 56) + (d2 << 48) + (d3 << 40) + (d4 << 32) +
48-
(d5 << 24) + (d6 << 16) + (d7 << 8) + d8)
47+
::std::char::from_u32((d1 << 28) + (d2 << 24) + (d3 << 20) + (d4 << 16) +
48+
(d5 << 12) + (d6 << 8) + (d7 << 4) + d8)
4949
}
5050
else { unreachable!() }
5151
}}

src/visitors/printer.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -499,14 +499,25 @@ fn format_expr(e: &Expression) -> String {
499499
'\t' => "\\t".to_string(),
500500
'\\' => "\\\\".to_string(),
501501
'"' => "\\\"".to_string(),
502-
c if c.is_ascii() => c.to_string(),
503-
c if (c as u32) <= 0xffff => format!("\\u{:04}", c as u32),
504-
c => format!("\\U{:08}", c as u32),
502+
'\x20'...'\x7e' => c.to_string(),
503+
'\x00'...'\x1f' | '\x7f' | '\u{80}'...'\u{ff}' => format!("\\x{:02x}", c as u8),
504+
'\u{100}'...'\u{ffff}' => format!("\\u{:04x}", c as u16),
505+
'\u{10000}'...'\u{10ffff}' => format!("\\U{:08x}", c as u32),
506+
_ => unreachable!(),
505507
}).collect::<Vec<_>>()[..].concat())
506508
))
507509
},
508-
Expression::Bytes(ref b) => {
509-
format!("bytes({:?})", b) // FIXME: that's cheating
510+
Expression::Bytes(ref content) => {
511+
format!("b\"{}\"", content.iter().map(|b| match b {
512+
b'\r' => "\\r".to_string(),
513+
b'\n' => "\\n".to_string(),
514+
b'\t' => "\\t".to_string(),
515+
b'\\' => "\\\\".to_string(),
516+
b'"' => "\\\"".to_string(),
517+
0x20...0x7e => (*b as char).to_string(),
518+
0x00...0x1f | 0x7f | 0x80...0xff => format!("\\x{:02x}", b),
519+
_ => unreachable!(), // waiting for https://github.com/rust-lang/rust/pull/50912
520+
}).collect::<Vec<_>>()[..].concat())
510521
},
511522

512523
Expression::DictLiteral(ref v) =>

0 commit comments

Comments
 (0)