use hermes_atom_table::AtomBytes;
use hermes_support::diag::Subsystem;
use hermes_support::location::{SMLoc, SMRange};
use crate::token_kinds::TokenKind;
use crate::utf8::{
is_utf8_start, match_unicode_line_terminator_offset1,
UTF8_LINE_TERMINATOR_CHAR0,
};
use hermes_unicode::is_unicode_only_space;
use super::JSLexer;
impl<'a> JSLexer<'a> {
pub fn set_prev_token_end_loc(&mut self, loc: SMLoc) {
self.prev_token_end = loc;
}
pub(crate) fn unsafe_set_punctuator(
&mut self,
kind: TokenKind,
loc: SMLoc,
range: SMRange,
) {
debug_assert!(kind.is_punctuator(), "must set a punctuator");
self.token.set_punctuator(kind);
self.token.set_range(range);
self.seek(loc);
}
pub(crate) fn unsafe_set_identifier(
&mut self,
ident: AtomBytes,
loc: SMLoc,
range: SMRange,
) {
self.token.set_identifier(ident);
self.token.set_range(range);
self.seek(loc);
}
pub(crate) fn unsafe_set_reserved_word(
&mut self,
kind: TokenKind,
loc: SMLoc,
range: SMRange,
) {
let ident = self.res_word_ident(kind);
self.token.set_res_word(kind, ident);
self.token.set_range(range);
self.seek(loc);
}
pub fn save_point(&self) -> SavePoint {
let kind = self.token.kind();
debug_assert!(
kind.is_punctuator()
|| kind == TokenKind::identifier
|| kind == TokenKind::rw_extends,
"SavePoint can only be used for punctuators, identifier or `extends` keyword"
);
SavePoint {
kind,
ident: if kind == TokenKind::identifier {
Some(self.token.get_identifier())
} else {
None
},
loc: self.cur_loc(),
range: self.token.source_range(),
prev_token_end: self.prev_token_end,
comment_storage_size: self.get_stored_comments().len(),
token_storage_size: self.get_stored_tokens().len(),
}
}
pub fn is_current_token_a_directive(&mut self) -> bool {
if self.token.kind() != TokenKind::string_literal {
return false;
}
let saved_offset = self.cursor.offset();
let saved_newline = self.new_line_before_current_token;
let buffer = self.cursor.buffer().clone();
let raw = buffer.raw();
let mut ptr = saved_offset as usize;
let result = loop {
debug_assert!(
ptr < raw.len(),
"lexing past end of input"
);
match raw[ptr] {
0 => {
if ptr == raw.len() - 1 {
break true;
}
break false;
}
b';' | b'}' => break true,
b'\r' | b'\n' => break true,
UTF8_LINE_TERMINATOR_CHAR0 => {
if match_unicode_line_terminator_offset1(&raw[ptr..]) {
break true;
}
break false;
}
0x0b | 0x0c => {
ptr += 1;
continue;
}
b'\t' | b' ' => {
loop {
ptr += 1;
if raw[ptr] != b'\t' && raw[ptr] != b' ' {
break;
}
}
continue;
}
0xc2 => {
if raw[ptr + 1] == 0xa0 {
ptr += 2;
continue;
} else {
if let Some(next) = directive_unicode_space(raw, ptr) {
ptr = next;
continue;
}
break false;
}
}
0xef => {
if raw[ptr + 1] == 0xbb && raw[ptr + 2] == 0xbf {
ptr += 3;
continue;
} else {
if let Some(next) = directive_unicode_space(raw, ptr) {
ptr = next;
continue;
}
break false;
}
}
b'/' => {
if raw[ptr + 1] == b'/' {
break true;
} else if raw[ptr + 1] == b'*' {
let saved_comment_len = self.comment_storage.len();
let saved_suppressed = self.sm.suppressed_messages();
self.sm
.set_suppressed_messages(Some(Subsystem::Unspecified));
self.cursor.seek(ptr as u32);
self.skip_block_comment();
ptr = self.cursor.offset() as usize;
self.sm.set_suppressed_messages(saved_suppressed);
if self.store_comments {
self.comment_storage.truncate(saved_comment_len);
}
continue;
} else {
break false;
}
}
_ => {
if let Some(next) = directive_unicode_space(raw, ptr) {
ptr = next;
continue;
}
break false;
}
}
};
self.cursor.seek(saved_offset);
self.new_line_before_current_token = saved_newline;
result
}
pub fn rescan_rbrace_in_template_literal(&mut self) -> &crate::token::Token {
debug_assert!(
self.token.kind() == TokenKind::r_brace,
"need }} to rescan"
);
let back = self.cursor.offset() - 1;
self.cursor.seek(back);
if self.store_tokens {
self.token_storage.pop();
}
debug_assert!(
self.cursor.peek() == b'}',
"non-}} was scanned as r_brace"
);
let start = self.cur_loc();
self.token.set_start(start);
self.scan_template_literal();
self.finish_token();
&self.token
}
}
pub struct SavePoint {
kind: TokenKind,
ident: Option<AtomBytes>,
loc: SMLoc,
range: SMRange,
prev_token_end: SMLoc,
comment_storage_size: usize,
token_storage_size: usize,
}
impl SavePoint {
pub fn restore(self, lexer: &mut JSLexer) {
if self.kind == TokenKind::identifier {
lexer.unsafe_set_identifier(self.ident.unwrap(), self.loc, self.range);
} else if self.kind == TokenKind::rw_extends {
lexer.unsafe_set_reserved_word(self.kind, self.loc, self.range);
} else {
lexer.unsafe_set_punctuator(self.kind, self.loc, self.range);
}
lexer.prev_token_end = self.prev_token_end;
if lexer.store_comments
&& self.comment_storage_size < lexer.comment_storage.len()
{
lexer.comment_storage.truncate(self.comment_storage_size);
}
if lexer.get_store_tokens() {
lexer.token_storage.truncate(self.token_storage_size);
}
}
}
fn directive_unicode_space(raw: &[u8], ptr: usize) -> Option<usize> {
if is_utf8_start(raw[ptr]) {
let mut i = ptr;
let cp = crate::utf8::decode_utf8::<false>(raw, &mut i, |_| {});
if is_unicode_only_space(cp) {
return Some(i);
}
}
None
}