use std::str;
use super::*;
use swc_common::{BytePos, SpanData};
use swc_ecma_parser::{token::{Token, TokenAndSpan}};
pub struct TokenFinder<'a> {
tokens: &'a Vec<TokenAndSpan>,
file_bytes: &'a Vec<u8>,
token_index: usize,
}
impl<'a> TokenFinder<'a> {
pub fn new(tokens: &'a Vec<TokenAndSpan>, file_bytes: &'a Vec<u8>) -> TokenFinder<'a> {
TokenFinder {
tokens,
file_bytes,
token_index: 0,
}
}
pub fn get_char_at(&self, pos: &BytePos) -> char {
self.file_bytes[pos.0 as usize] as char
}
pub fn get_previous_token_if_open_paren(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_previous_token_if(node, |token| token.token == Token::LParen)
}
pub fn get_next_token_if_close_paren(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_next_token_if(node, |token| token.token == Token::RParen)
}
pub fn get_previous_token_if_open_brace(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_previous_token_if(node, |token| token.token == Token::LBrace)
}
pub fn get_previous_token_if_open_bracket(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_previous_token_if(node, |token| token.token == Token::LBracket)
}
pub fn get_previous_token_if_close_brace(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_previous_token_if(node, |token| token.token == Token::RBrace)
}
pub fn get_previous_token_if_from_keyword(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
let file_bytes = self.file_bytes;
self.get_previous_token_if(node, |token| get_text(file_bytes, &token.span) == "from")
}
pub fn get_previous_token_if_colon(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_previous_token_if(node, |token| token.token == Token::Colon)
}
pub fn get_previous_token_if_operator(&mut self, node: &dyn Ranged, operator_text: &str) -> Option<&'a TokenAndSpan> {
let file_bytes = self.file_bytes;
self.get_previous_token_if(node, |token| get_text(file_bytes, &token.span) == operator_text)
}
fn get_previous_token_if<F>(&mut self, node: &dyn Ranged, is_match: F) -> Option<&'a TokenAndSpan> where F : FnOnce(&TokenAndSpan) -> bool {
let previous_token = self.get_previous_token(node)?;
return if is_match(&previous_token) { Some(previous_token) } else { None };
}
pub fn get_previous_token(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_before(node, |_| true)
}
pub fn get_next_token_if_comma(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_next_token_if(node, |token| token.token == Token::Comma)
}
pub fn get_next_token_if_close_bracket(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_next_token_if(node, |token| token.token == Token::RBracket)
}
fn get_next_token_if<F>(&mut self, node: &dyn Ranged, is_match: F) -> Option<&'a TokenAndSpan> where F : FnOnce(&TokenAndSpan) -> bool {
let next_token = self.get_next_token(node)?;
return if is_match(&next_token) { Some(next_token) } else { None };
}
fn get_next_token(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_after(node, |_| true)
}
pub fn get_first_open_brace_token_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_within(node, |token| token.token == Token::LBrace)
}
pub fn get_last_close_brace_token_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_last_token_within(node, |token| token.token == Token::RBrace)
}
pub fn get_first_open_bracket_token_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_within(node, |token| token.token == Token::LBracket)
}
pub fn get_first_comma_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_within(node, |token| token.token == Token::Comma)
}
pub fn get_first_semi_colon_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_within(node, |token| token.token == Token::Semi)
}
pub fn get_first_colon_token_after(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_after(node, |token| token.token == Token::Colon)
}
pub fn get_first_colon_token_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_within(node, |token| token.token == Token::Colon)
}
pub fn get_first_operator_after(&mut self, node: &dyn Ranged, operator_text: &str) -> Option<&'a TokenAndSpan> {
self.get_first_token_after_with_text(node, operator_text)
}
pub fn get_first_keyword_after(&mut self, node: &dyn Ranged, keyword_text: &str) -> Option<&'a TokenAndSpan> {
self.get_first_token_after_with_text(node, keyword_text)
}
fn get_first_token_after_with_text(&mut self, node: &dyn Ranged, text: &str) -> Option<&'a TokenAndSpan> {
let file_bytes = self.file_bytes;
self.get_first_token_after(node, |token| get_text(file_bytes, &token.span) == text)
}
pub fn get_first_else_keyword_within(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
let file_bytes = self.file_bytes;
self.get_first_token_within(node, |token| get_text(file_bytes, &token.span) == "else")
}
pub fn get_first_open_brace_token_before(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_before(node, |token| token.token == Token::LBrace)
}
pub fn get_first_open_paren_before(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_before(node, |token| token.token == Token::LParen)
}
pub fn get_first_close_paren_before(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_before(node, |token| token.token == Token::RParen)
}
pub fn get_first_close_paren_after(&mut self, node: &dyn Ranged) -> Option<&'a TokenAndSpan> {
self.get_first_token_after(node, |token| token.token == Token::RParen)
}
pub fn get_previous_token_end_before(&mut self, node: &dyn Ranged) -> BytePos {
let previous_token = self.get_previous_token(node);
if let Some(token) = previous_token {
token.span.hi()
} else {
BytePos(0)
}
}
pub fn get_next_token_pos_after(&mut self, node: &dyn Ranged) -> BytePos {
let next_token = self.get_next_token(node);
if let Some(token) = next_token {
token.span.lo()
} else {
BytePos(self.file_bytes.len() as u32)
}
}
fn get_first_token_before<F>(&mut self, node: &dyn Ranged, is_match: F) -> Option<&'a TokenAndSpan> where F : Fn(&TokenAndSpan) -> bool{
let pos = node.lo();
if self.tokens.is_empty() { return None; }
self.move_to_node_pos(pos);
if self.tokens[self.token_index].lo() < pos {
let current_token = &self.tokens[self.token_index];
if is_match(current_token) {
return Some(current_token);
}
}
while self.try_decrement_index() {
let current_token = &self.tokens[self.token_index];
if is_match(current_token) {
return Some(current_token);
}
}
return None;
}
fn get_first_token_after<F>(&mut self, node: &dyn Ranged, is_match: F) -> Option<&'a TokenAndSpan> where F : Fn(&'a TokenAndSpan) -> bool {
let end = node.hi();
if self.tokens.is_empty() { return None; }
self.move_to_node_end(end);
while self.try_increment_index() {
let current_token = &self.tokens[self.token_index];
if is_match(current_token) {
return Some(current_token);
}
}
return None;
}
fn get_first_token_within<F>(&mut self, node: &dyn Ranged, is_match: F) -> Option<&'a TokenAndSpan> where F : Fn(&'a TokenAndSpan) -> bool {
let node_span_data = node.span_data();
let pos = node_span_data.lo;
let end = node_span_data.hi;
if self.tokens.is_empty() { return None; }
self.move_to_node_pos(pos);
loop {
let current_token = &self.tokens[self.token_index];
let token_pos = current_token.span.lo;
if token_pos >= end {
break;
} else if is_match(current_token) {
return Some(current_token);
}
if !self.try_increment_index() {
break;
}
}
None
}
fn get_last_token_within<F>(&mut self, node: &dyn Ranged, is_match: F) -> Option<&'a TokenAndSpan> where F : Fn(&'a TokenAndSpan) -> bool {
let node_span_data = node.span_data();
let end = node_span_data.hi;
if self.tokens.is_empty() { return None; }
self.move_to_node_end(end);
loop {
let current_token = &self.tokens[self.token_index];
let token_pos = current_token.span_data().lo;
if token_pos >= end {
break;
} else if is_match(current_token) {
return Some(current_token);
}
if !self.try_decrement_index() {
break;
}
}
None
}
fn move_to_node_pos(&mut self, pos: BytePos) {
while self.tokens[self.token_index].lo() < pos {
if !self.try_increment_index() {
break;
}
}
while self.tokens[self.token_index].lo() > pos {
if !self.try_decrement_index() {
break;
}
}
}
fn move_to_node_end(&mut self, end: BytePos) {
while self.tokens[self.token_index].hi() < end {
if !self.try_increment_index() {
break;
}
}
while self.tokens[self.token_index].hi() > end {
if !self.try_decrement_index() {
break;
}
}
}
fn try_increment_index(&mut self) -> bool {
if self.token_index == self.tokens.len() - 1 {
false
} else {
self.token_index += 1;
true
}
}
fn try_decrement_index(&mut self) -> bool {
if self.token_index == 0 {
false
} else {
self.token_index -= 1;
true
}
}
}
fn get_text<'a>(file_bytes: &'a Vec<u8>, span_data: &SpanData) -> &'a str {
let bytes = &file_bytes[(span_data.lo.0 as usize)..(span_data.hi.0 as usize)];
str::from_utf8(&bytes).unwrap()
}