Store hex digits in a stack-allocated buffer
This commit is contained in:
parent
c56db92d1f
commit
fdb9f06880
2 changed files with 45 additions and 5 deletions
|
@ -1,5 +1,7 @@
|
||||||
use crate::{File, SyntaxKind, SyntaxNodeRef, WalkEvent};
|
use crate::{File, SyntaxKind, SyntaxNodeRef, WalkEvent};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
/// Parse a file and create a string representation of the resulting parse tree.
|
/// Parse a file and create a string representation of the resulting parse tree.
|
||||||
pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
|
pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
|
||||||
|
@ -78,3 +80,38 @@ pub(crate) fn validate_block_structure(root: SyntaxNodeRef) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MutAsciiString<'a> {
|
||||||
|
buf: &'a mut [u8],
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MutAsciiString<'a> {
|
||||||
|
pub fn new(buf: &'a mut [u8]) -> MutAsciiString<'a> {
|
||||||
|
MutAsciiString { buf, len: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
str::from_utf8(&self.buf[..self.len]).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, c: char) {
|
||||||
|
assert!(self.len() < self.buf.len());
|
||||||
|
assert!(c.is_ascii());
|
||||||
|
|
||||||
|
self.buf[self.len] = c as u8;
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for MutAsciiString<'a> {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &str {
|
||||||
|
self.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
File,
|
File,
|
||||||
string_lexing::{self, CharComponentKind},
|
string_lexing::{self, CharComponentKind},
|
||||||
|
utils::MutAsciiString,
|
||||||
yellow::{
|
yellow::{
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
SyntaxErrorKind::*,
|
SyntaxErrorKind::*,
|
||||||
|
@ -73,12 +74,18 @@ fn validate_char(node: ast::Char, errors: &mut Vec<SyntaxError>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut code = String::new();
|
let mut buf = &mut [0; 6];
|
||||||
|
let mut code = MutAsciiString::new(buf);
|
||||||
let mut closed = false;
|
let mut closed = false;
|
||||||
for c in text[3..].chars() {
|
for c in text[3..].chars() {
|
||||||
assert!(!closed, "no characters after escape is closed");
|
assert!(!closed, "no characters after escape is closed");
|
||||||
|
|
||||||
if c.is_digit(16) {
|
if c.is_digit(16) {
|
||||||
|
if code.len() == 6 {
|
||||||
|
errors.push(SyntaxError::new(OverlongUnicodeEscape, range));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
code.push(c);
|
code.push(c);
|
||||||
} else if c == '_' {
|
} else if c == '_' {
|
||||||
// Reject leading _
|
// Reject leading _
|
||||||
|
@ -103,10 +110,6 @@ fn validate_char(node: ast::Char, errors: &mut Vec<SyntaxError>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if code.len() > 6 {
|
|
||||||
errors.push(SyntaxError::new(OverlongUnicodeEscape, range));
|
|
||||||
}
|
|
||||||
|
|
||||||
match u32::from_str_radix(&code, 16) {
|
match u32::from_str_radix(&code, 16) {
|
||||||
Ok(code_u32) if code_u32 > 0x10FFFF => {
|
Ok(code_u32) if code_u32 > 0x10FFFF => {
|
||||||
errors.push(SyntaxError::new(UnicodeEscapeOutOfRange, range));
|
errors.push(SyntaxError::new(UnicodeEscapeOutOfRange, range));
|
||||||
|
|
Loading…
Reference in a new issue