further refactor parsing of hex colors

This commit is contained in:
ConnorSkees 2020-06-17 06:25:38 -04:00
parent 00bd9f3847
commit 042935f362
2 changed files with 31 additions and 19 deletions

View File

@ -526,41 +526,38 @@ impl<'a> Parser<'a> {
} }
fn parse_hex(&mut self) -> SassResult<Spanned<Value>> { fn parse_hex(&mut self) -> SassResult<Spanned<Value>> {
let mut s = String::with_capacity(8); let mut s = String::with_capacity(7);
s.push('#');
if self if self
.toks .toks
.peek() .peek()
.ok_or(("Expected identifier.", self.span_before))? .ok_or(("Expected identifier.", self.span_before))?
.kind .kind
.is_ascii_digit() .is_ascii_hexdigit()
{ {
while let Some(c) = self.toks.peek() { while let Some(c) = self.toks.peek() {
if !c.kind.is_ascii_hexdigit() || s.len() == 8 { if !c.kind.is_ascii_hexdigit() {
break; break;
} }
let tok = self.toks.next().unwrap(); let tok = self.toks.next().unwrap();
self.span_before = self.span_before.merge(tok.pos()); self.span_before = self.span_before.merge(tok.pos());
s.push(tok.kind); s.push(tok.kind);
} }
// this branch exists so that we can emit `#` combined with
// identifiers. e.g. `#ooobar` should be emitted exactly as written;
// that is, `#ooobar`.
} else { } else {
let i = self.parse_identifier()?; let ident = self.parse_identifier()?;
if i.node.chars().all(|c| c.is_ascii_hexdigit()) {
s = i.node;
self.span_before = self.span_before.merge(i.span);
} else {
return Ok(Spanned { return Ok(Spanned {
node: Value::String(format!("#{}", i.node), QuoteKind::None), node: Value::String(format!("#{}", ident.node), QuoteKind::None),
span: i.span, span: ident.span,
}); });
} }
} let v = match u32::from_str_radix(&s[1..], 16) {
let v = match u32::from_str_radix(&s, 16) {
Ok(a) => a, Ok(a) => a,
Err(_) => { Err(_) => return Ok(Value::String(s, QuoteKind::None).span(self.span_before)),
return Ok(Value::String(format!("#{}", s), QuoteKind::None).span(self.span_before))
}
}; };
let (red, green, blue, alpha) = match s.len() { let (red, green, blue, alpha) = match s.len().saturating_sub(1) {
3 => ( 3 => (
(((v & 0x0f00) >> 8) * 0x11) as u8, (((v & 0x0f00) >> 8) * 0x11) as u8,
(((v & 0x00f0) >> 4) * 0x11) as u8, (((v & 0x00f0) >> 4) * 0x11) as u8,
@ -587,7 +584,7 @@ impl<'a> Parser<'a> {
), ),
_ => return Err(("Expected hex digit.", self.span_before).into()), _ => return Err(("Expected hex digit.", self.span_before).into()),
}; };
let color = Color::new(red, green, blue, alpha, format!("#{}", s)); let color = Color::new(red, green, blue, alpha, s);
Ok(Value::Color(Box::new(color)).span(self.span_before)) Ok(Value::Color(Box::new(color)).span(self.span_before))
} }

View File

@ -582,3 +582,18 @@ test!(
"a {\n color: hsl(-1 -1 -1);\n}\n", "a {\n color: hsl(-1 -1 -1);\n}\n",
"a {\n color: black;\n}\n" "a {\n color: black;\n}\n"
); );
test!(
interpolation_after_hash_containing_only_hex_chars,
"a {\n color: ##{123};\n color: type-of(##{123});\n}\n",
"a {\n color: #123;\n color: string;\n}\n"
);
test!(
non_hex_chars_after_hash_are_still_touching_hash,
"a {\n color: #ooobar;\n}\n",
"a {\n color: #ooobar;\n}\n"
);
test!(
more_than_8_hex_chars_after_hash,
"a {\n color: #ffffffffff;\n}\n",
"a {\n color: #ffffffffff;\n}\n"
);