From 223dade62b6bd64d240dd43027e7de329b93c688 Mon Sep 17 00:00:00 2001
From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com>
Date: Sat, 16 May 2020 16:22:33 -0400
Subject: [PATCH] Emit proper error for escape sequence overflow

Before this commit, escape sequences above std::char::MAX ('\u{10ffff}')
would overflow and cause a panic. This commit replaces an `unwrap` with
`ok_or` and a clearer error message. This message will likely change
in the future in order to better conform to the `dart-sass` implementation
which currently also fails to cleanly handle this overflow.

See https://github.com/kaj/rsass/pull/73
---
 src/utils/strings.rs | 10 +++++++---
 tests/str-escape.rs  |  4 ++++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/utils/strings.rs b/src/utils/strings.rs
index cd1399d..fae92c6 100644
--- a/src/utils/strings.rs
+++ b/src/utils/strings.rs
@@ -121,8 +121,9 @@ fn escape<I: Iterator<Item = Token>>(
         Some(t) => t,
         None => return Ok(String::new()),
     };
+    let mut span = first.pos();
     if first.kind == '\n' {
-        return Err(("Expected escape sequence.", first.pos()).into());
+        return Err(("Expected escape sequence.", span).into());
     } else if first.kind.is_ascii_hexdigit() {
         for _ in 0..6 {
             let next = match toks.peek() {
@@ -133,16 +134,19 @@ fn escape<I: Iterator<Item = Token>>(
                 break;
             }
             value *= 16;
+            span = span.merge(next.pos());
             value += as_hex(toks.next().unwrap().kind)
         }
         if toks.peek().is_some() && toks.peek().unwrap().kind.is_whitespace() {
             toks.next();
         }
     } else {
-        value = toks.next().unwrap().kind as u32;
+        let next = toks.next().unwrap();
+        span = span.merge(next.pos());
+        value = next.kind as u32;
     }
 
-    let c = std::char::from_u32(value).unwrap();
+    let c = std::char::from_u32(value).ok_or(("Invalid escape sequence.", span))?;
     if (identifier_start && is_name_start(c) && !c.is_digit(10))
         || (!identifier_start && is_name(c))
     {
diff --git a/tests/str-escape.rs b/tests/str-escape.rs
index 5875cf2..c0ba921 100644
--- a/tests/str-escape.rs
+++ b/tests/str-escape.rs
@@ -168,3 +168,7 @@ test!(
     "a {\n  color: \\9;\n}\n",
     "a {\n  color: \\9 ;\n}\n"
 );
+error!(
+    escape_sequence_does_not_fit_inside_char,
+    "a {\n  color: \\110000;\n}\n", "Error: Invalid escape sequence."
+);