use super::Lexer;
use radixdb_core::SmartString;
const MAX_LITERAL_BYTES: usize = 8 * 1024 * 1024;
impl Lexer {
pub(super) fn read_number(&mut self) -> SmartString {
let mut result = SmartString::new("");
result.push(self.ch);
self.read_char();
while self.ch.is_ascii_digit() {
result.push(self.ch);
self.read_char();
}
if self.ch == '.' && self.peek_char().is_ascii_digit() {
result.push(self.ch);
self.read_char();
while self.ch.is_ascii_digit() {
result.push(self.ch);
self.read_char();
}
}
if self.ch == 'e' || self.ch == 'E' {
result.push(self.ch);
self.read_char();
if self.ch == '+' || self.ch == '-' {
result.push(self.ch);
self.read_char();
}
if !self.ch.is_ascii_digit() {
self.last_error = Some("invalid number format: exponent has no digits".to_string());
return result;
}
while self.ch.is_ascii_digit() {
result.push(self.ch);
self.read_char();
}
}
result
}
pub(super) fn read_string_literal(&mut self) -> SmartString {
let quote = self.ch;
let quote_byte = quote as u8;
let start_pos = self.position;
let mut scan_pos = self.read_position; let input_len = self.input.len();
let mut found_escape = false;
while scan_pos < input_len {
let b = self.input[scan_pos];
if b == quote_byte {
if scan_pos + 1 < input_len && self.input[scan_pos + 1] == quote_byte {
found_escape = true;
break;
}
let end_pos = scan_pos + 1;
self.pos.column += 1;
let contents = unsafe {
std::str::from_utf8_unchecked(&self.input[self.read_position..scan_pos])
};
for ch in contents.chars() {
if ch == '\n' {
self.pos.line += 1;
self.pos.column = 1;
} else {
self.pos.column += 1;
}
}
self.pos.column += 1;
self.position = scan_pos;
self.read_position = end_pos;
self.pos.offset = self.position;
if self.read_position >= input_len {
self.ch = '\0';
self.position = self.read_position;
self.eof = true;
} else {
let (ch, len) = self.decode_char_at(self.read_position);
self.ch = ch;
self.position = self.read_position;
self.read_position += len;
self.eof = false;
}
self.pos.offset = self.position;
if end_pos.saturating_sub(start_pos) > MAX_LITERAL_BYTES {
self.last_error = Some(format!(
"string literal exceeds limit of {MAX_LITERAL_BYTES} bytes"
));
return SmartString::new("");
}
let slice =
unsafe { std::str::from_utf8_unchecked(&self.input[start_pos..end_pos]) };
return SmartString::new(slice);
} else if b == b'\\' || b == 0 {
found_escape = true;
break;
}
scan_pos += 1;
}
if !found_escape && scan_pos >= input_len {
}
let estimated_len = if scan_pos > self.read_position {
scan_pos - start_pos + 2
} else {
32
};
let mut result = String::with_capacity(estimated_len);
let mut oversized = false;
result.push(quote);
self.read_char();
loop {
if self.ch == '\0' {
if self.eof {
self.last_error = Some("unterminated string literal".to_string());
} else {
self.last_error =
Some("NULL byte (0x00) is not allowed in string literals".to_string());
}
if !oversized {
result.push(quote);
}
break;
} else if self.ch == quote {
if self.peek_char() == quote {
if !oversized {
result.push(self.ch);
}
self.read_char();
self.read_char();
} else {
if !oversized {
result.push(quote);
}
self.read_char();
break;
}
} else if self.ch == '\\' {
if !oversized {
result.push(self.ch);
}
self.read_char();
if self.ch != '\0' {
if !oversized {
result.push(self.ch);
}
self.read_char();
}
} else {
if !oversized {
result.push(self.ch);
}
self.read_char();
}
if !oversized && result.len() > MAX_LITERAL_BYTES {
oversized = true;
result.clear();
}
}
if oversized {
self.last_error = Some(format!(
"string literal exceeds limit of {MAX_LITERAL_BYTES} bytes"
));
}
SmartString::from_string(result)
}
}