use hermes_atom_table::AtomTable;
use hermes_parser::lexer::{GrammarContext, JSLexer};
use hermes_parser::token_kinds::TokenKind;
use hermes_support::diag::{CollectingHandler, DiagKind};
use hermes_support::manager::SourceErrorManager;
struct Diag {
last_err: u32,
last_warn: u32,
}
impl Diag {
fn new() -> Diag {
Diag {
last_err: 0,
last_warn: 0,
}
}
fn err_clear(&mut self, lex: &JSLexer) -> u32 {
let cur = lex.get_source_mgr().error_count();
let d = cur - self.last_err;
self.last_err = cur;
d
}
fn warn_clear(&mut self, lex: &JSLexer) -> u32 {
let cur = lex.get_source_mgr().warning_count();
let d = cur - self.last_warn;
self.last_warn = cur;
d
}
}
fn mk(src: &str) -> (SourceErrorManager, hermes_support::location::SourceId) {
let mut sm = SourceErrorManager::new();
let id = sm.add_buffer("t", src);
(sm, id)
}
fn mk_bytes(src: &[u8]) -> (SourceErrorManager, hermes_support::location::SourceId) {
let mut sm = SourceErrorManager::new();
let id = sm.add_buffer_bytes("t", src);
(sm, id)
}
fn punctuators() -> Vec<(TokenKind, &'static str)> {
use TokenKind::*;
vec![
(l_brace, "{"),
(r_brace, "}"),
(l_paren, "("),
(r_paren, ")"),
(l_square, "["),
(r_square, "]"),
(period, "."),
(questiondot, "?."),
(dotdotdot, "..."),
(semi, ";"),
(comma, ","),
(plusplus, "++"),
(minusminus, "--"),
(starstar, "**"),
(star, "*"),
(percent, "%"),
(slash, "/"),
(plus, "+"),
(minus, "-"),
(lessless, "<<"),
(greatergreater, ">>"),
(greatergreatergreater, ">>>"),
(less, "<"),
(greater, ">"),
(lessequal, "<="),
(greaterequal, ">="),
(equalequal, "=="),
(exclaimequal, "!="),
(equalequalequal, "==="),
(exclaimequalequal, "!=="),
(amp, "&"),
(caret, "^"),
(pipe, "|"),
(ampamp, "&&"),
(pipepipe, "||"),
(questionquestion, "??"),
(exclaim, "!"),
(tilde, "~"),
(question, "?"),
(colon, ":"),
(equal, "="),
(plusequal, "+="),
(minusequal, "-="),
(starequal, "*="),
(starstarequal, "**="),
(percentequal, "%="),
(slashequal, "/="),
(lesslessequal, "<<="),
(greatergreaterequal, ">>="),
(greatergreatergreaterequal, ">>>="),
(ampequal, "&="),
(pipeequal, "|="),
(ampampequal, "&&="),
(pipepipeequal, "||="),
(questionquestionequal, "??="),
(caretequal, "^="),
(equalgreater, "=>"),
(at, "@"),
]
}
#[test]
fn punctuator_test() {
let puncts = punctuators();
let mut src = String::new();
for (_, s) in &puncts {
src.push_str(s);
src.push(' ');
}
let (mut sm, id) = mk(&src);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
for (kind, _) in &puncts {
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), *kind);
}
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
for (kind, _) in &puncts {
assert!(kind.is_punctuator());
}
}
#[test]
fn punctuator_div_test() {
let (mut sm, id) = mk("a / b /= c");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::slash);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::slashequal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn white_space_test() {
let (mut sm, id) = mk("{ ; \n} \n \n ;");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::l_brace);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::r_brace);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert!(!lex.is_new_line_before_current_token());
}
#[test]
fn unicode_white_space_test() {
let (mut sm, id) = mk_bytes(b"{\xe2\x80\x80;\xe2\x80\x8a \n} \xe2\x81\x9f\n \n ;");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::l_brace);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::r_brace);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(diag.err_clear(&lex), 0);
}
#[test]
fn comment_test() {
let (mut sm, id) = mk(
"; /* foo */ { /* bar \n\
\x20 ***** */ } // hello\n\
\x20/* comment */ ;\n\
\x20/* not closed",
);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::l_brace);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::r_brace);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(diag.err_clear(&lex), 1); assert!(lex.is_new_line_before_current_token());
}
#[test]
fn hashbang_test() {
let (mut sm, id) = mk(
"#! hashbang comment\n\
;\n\
#! // not a hashbang comment\n",
);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::exclaim);
assert_eq!(diag.err_clear(&lex), 1);
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert!(lex.is_new_line_before_current_token());
}
fn number_cases() -> Vec<(&'static str, f64)> {
vec![
("1235", 1235.0),
("1234567890123", 1234567890123.0),
("0", 0.0),
("0x10", 16.0),
("1.2", 1.2),
("055", 45.0), (".1", 0.1),
("1.", 1.0),
("1e2", 1e2),
("5e+3", 5e3),
("4e-3", 4e-3),
(".1e-3", 0.1e-3),
("12.34e+5", 12.34e5),
]
}
#[test]
fn number_test() {
let mut src = String::new();
for (s, _) in number_cases() {
src.push(' ');
src.push_str(s);
}
let (mut sm, id) = mk(&src);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
lex.set_strict_mode(false);
for (s, expected) in number_cases() {
let tok = lex.advance(GrammarContext::AllowDiv);
assert_eq!(tok.kind(), TokenKind::numeric_literal, "src={s:?}");
assert_eq!(
tok.get_numeric_literal().to_bits(),
expected.to_bits(),
"value mismatch for {s:?}"
);
}
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::eof);
}
#[test]
fn numeric_separator_test() {
let (mut sm, id) = mk(
" 1_2 12\
\x20 0x1_2 0x12\
\x20 0xdead_beef 0xdeadbeef\
\x20 0b1_1 0b11\
\x20 0o1_1 0o11\
\x20 123_456_789 123456789\
\x20 12_345e1_2 12345e12\
\x20 1_1.1_2 1_1.12",
);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
loop {
let tok = lex.advance(GrammarContext::AllowDiv);
if tok.kind() == TokenKind::eof {
break;
}
assert_eq!(tok.kind(), TokenKind::numeric_literal);
let with_sep = tok.get_numeric_literal();
let tok = lex.advance(GrammarContext::AllowDiv);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
let no_sep = tok.get_numeric_literal();
assert_eq!(with_sep, no_sep);
}
}
#[test]
fn bigint_test() {
{
let (mut sm, id) = mk(
" 0n 1n 1000n 12_34n 1928371289378129381212398n 0xdeadbeefn 0b10101100101n",
);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
let expect = |lex: &mut JSLexer, tab: &AtomTable, s: &[u8]| {
assert_eq!(
lex.advance(GrammarContext::AllowDiv).kind(),
TokenKind::bigint_literal
);
assert_eq!(tab.bytes(lex.token().get_bigint_literal()), s);
};
expect(&mut lex, &tab, b"0");
expect(&mut lex, &tab, b"1");
expect(&mut lex, &tab, b"1000");
expect(&mut lex, &tab, b"1234");
expect(&mut lex, &tab, b"1928371289378129381212398");
expect(&mut lex, &tab, b"0xdeadbeef");
expect(&mut lex, &tab, b"0b10101100101");
}
for src in ["09n", "1.1n", "1e2n"] {
let (mut sm, id) = mk(src);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
lex.advance(GrammarContext::AllowDiv);
assert_eq!(diag.err_clear(&lex), 1, "src={src:?}");
}
}
#[test]
fn biginteger_test() {
let (mut sm, id) = mk(" 0xFFFFFFFFFFFFFFFF 99999999999999999999");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
let tok = lex.advance(GrammarContext::AllowDiv);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 18446744073709551616.0_f64);
let tok = lex.advance(GrammarContext::AllowDiv);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 100000000000000000000.0_f64);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::eof);
}
#[test]
fn bad_numbers_test() {
let (mut sm, id) =
mk("123hhhh; 123e ; .4.5 ; 0_7 1__23 0b_11 123_ 1._2 12e_3");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowDiv);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::semi);
lex.set_strict_mode(false);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 2);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowDiv).kind(), TokenKind::eof);
}
#[test]
fn zero_radix_test() {
let (mut sm, id) = mk(" 0x");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn octal_literal_test() {
{
let (mut sm, id) = mk("01 010 09 019 0o11 0O11");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 1.0);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 8.0);
assert_eq!(diag.warn_clear(&lex), 0);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 9.0);
assert_eq!(diag.warn_clear(&lex), 1);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 19.0);
assert_eq!(diag.warn_clear(&lex), 1);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 9.0);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 9.0);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
{
let (mut sm, id) = mk("08.1_1 07.11 07.9 08.9");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_strict_mode(false);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 8.11);
assert_eq!(diag.warn_clear(&lex), 1);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 8.9);
assert_eq!(diag.warn_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
{
let (mut sm, id) = mk("08.1_1 07.11 07.9 08.9");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_strict_mode(true);
for _ in 0..4 {
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
}
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
}
#[test]
fn flow_octal_literal_test() {
let (mut sm, id) = mk("01");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::Type);
let tok = lex.advance(GrammarContext::Type);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 1.0);
assert_eq!(diag.err_clear(&lex), 1);
}
#[test]
fn binary_literal_test() {
let (mut sm, id) = mk("0b1 0B1 0b101");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 1.0);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 1.0);
let tok = lex.advance(GrammarContext::AllowRegExp);
assert_eq!(tok.kind(), TokenKind::numeric_literal);
assert_eq!(tok.get_numeric_literal(), 5.0);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn simple_identifier_test() {
let (mut sm, id) = mk("true foo bar foo");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"foo");
let foo = lex.token().get_identifier();
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"bar");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"foo");
assert_eq!(foo, lex.token().get_identifier());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn identifier_test() {
let (mut sm, id) = mk(" _foo$123 $123 a\\u0061 \\u0061\\u0061 \\u0061a");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"_foo$123");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"$123");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"aa");
let aa = lex.token().get_identifier();
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"aa");
assert_eq!(aa, lex.token().get_identifier());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"aa");
assert_eq!(aa, lex.token().get_identifier());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn private_identifier_test() {
let (mut sm, id) = mk(" #foo # foo #64");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::private_identifier);
assert_eq!(tab.bytes(lex.token().get_private_identifier()), b"foo");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"foo");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.token().get_numeric_literal(), 64.0);
}
#[test]
fn string_test1() {
let (mut sm, id) = mk_bytes(b"'aa' \"bb\" 'open1\n\"open2");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"aa");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"bb");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"open1");
assert!(!lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"open2");
assert!(lex.is_new_line_before_current_token());
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert!(!lex.is_new_line_before_current_token());
}
#[test]
fn string_line_para_sep_test() {
let (mut sm, id) = mk_bytes(
b"'\xe2\x80\xa8' '\xe2\x80\xa9' '\\\xe2\x80\xa8' '\\\xe2\x80\xa9' ",
);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"\xe2\x80\xa8");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"\xe2\x80\xa9");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn string_test2() {
let (mut sm, id) = mk_bytes(
b"'a\\u0061\x62\x63' '\\w\\'\\\"\\b\\f\\n\\r\\t\\v\\\na' '\\x1g' '\\u123g'",
);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"aabc");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(
tab.bytes(lex.token().get_string_literal()),
b"w'\"\x08\x0c\n\r\t\x0ba"
);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn string_octal_test() {
{
let (mut sm, id) = mk("'\\0' '\\000' '\\05'");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_strict_mode(false);
for _ in 0..3 {
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
}
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
{
let (mut sm, id) = mk("'\\0' '\\000' '\\05'");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_strict_mode(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
}
#[test]
fn unicode_escape_test() {
{
let (mut sm, id) = mk("'\\u0f3b' '\\u{0f3b}' '\\u{0062}'");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"\xe0\xbc\xbb");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"\xe0\xbc\xbb");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 0);
assert_eq!(tab.bytes(lex.token().get_string_literal()), b"\x62");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(diag.err_clear(&lex), 0);
}
{
let (mut sm, id) = mk("'\\u{ffffffff}'");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
}
{
let (mut sm, id) = mk("'\\u{}'");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
}
}
#[test]
fn regexp_smoke() {
let (mut sm, id) = mk("; /aa/bc");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::regexp_literal);
let re = lex.token().get_regexp_literal();
assert_eq!(tab.bytes(re.body()), b"aa");
assert_eq!(tab.bytes(re.flags()), b"bc");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn regexp_smoke2() {
let (mut sm, id) = mk("; /(\\w+)\\s(\\w+)/g");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::regexp_literal);
let re = lex.token().get_regexp_literal();
assert_eq!(tab.bytes(re.body()), b"(\\w+)\\s(\\w+)");
assert_eq!(tab.bytes(re.flags()), b"g");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn class_in_regexp() {
let (mut sm, id) = mk("/[a/]/");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::regexp_literal);
assert_eq!(tab.bytes(lex.token().get_regexp_literal().body()), b"[a/]");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(diag.err_clear(&lex), 0);
}
#[test]
fn utf16_bad_surrogate_pairs() {
let (mut sm, id) = mk("' \\udc01 \\ud805 '");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(
tab.bytes(lex.token().get_string_literal()),
b"\x20\xed\xb0\x81\x20\xed\xa0\x85\x20"
);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(diag.err_clear(&lex), 0);
}
#[test]
fn normalize_utf8() {
let (mut sm, id) = mk_bytes(b"'\xf0\x90\x80\x81'");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(
tab.bytes(lex.token().get_string_literal()),
b"\xed\xa0\x80\xed\xb0\x81"
);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn template_literals() {
{
let (mut sm, id) = mk_bytes(b"`abc` `\\x41` `\\u0041` `\\\xe2\x80\xa8`");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::no_substitution_template);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"abc");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"abc");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::no_substitution_template);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"\x41");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"\\x41");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::no_substitution_template);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"\x41");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"\\u0041");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::no_substitution_template);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"\\\xe2\x80\xa8");
}
{
let (mut sm, id) = mk("`abc${x}def${y}ghi`");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::template_head);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"abc");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"abc");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"x");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::r_brace);
lex.rescan_rbrace_in_template_literal();
assert_eq!(lex.token().kind(), TokenKind::template_middle);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"def");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"def");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(tab.bytes(lex.token().get_identifier()), b"y");
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::r_brace);
lex.rescan_rbrace_in_template_literal();
assert_eq!(lex.token().kind(), TokenKind::template_tail);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"ghi");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"ghi");
}
{
let (mut sm, id) = mk("`\\0`");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::no_substitution_template);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"\0");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"\\0");
}
{
let (mut sm, id) = mk_bytes(b"`\r\n \n \r`");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::no_substitution_template);
assert_eq!(tab.bytes(lex.token().get_template_value().unwrap()), b"\n \n \n");
assert_eq!(tab.bytes(lex.token().get_template_raw_value()), b"\n \n \n");
}
}
#[test]
fn reserved_tokens() {
let src = "implements private public interface package protected static yield";
{
let (mut sm, id) = mk(src);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_strict_mode(true);
for k in [
TokenKind::rw_implements,
TokenKind::rw_private,
TokenKind::rw_public,
TokenKind::rw_interface,
TokenKind::rw_package,
TokenKind::rw_protected,
TokenKind::rw_static,
TokenKind::rw_yield,
] {
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), k);
}
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(diag.err_clear(&lex), 0);
}
{
let (mut sm, id) = mk(src);
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_strict_mode(false);
for _ in 0..8 {
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
}
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(diag.err_clear(&lex), 0);
}
}
#[test]
fn source_mapping_url() {
{
let (mut sm, id) = mk(
"var x = 1;//# sourceMappingURL=localhost:8000/this_is_the_url.map",
);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_var);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::equal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
lex.advance(GrammarContext::AllowRegExp);
assert_eq!(
lex.get_source_mapping_url(),
Some("localhost:8000/this_is_the_url.map")
);
}
{
let (mut sm, id) = mk(
"var x = 1;\n//# sourceMappingURL=second-map.map\nvar y = 2;",
);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_var);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::equal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
lex.advance(GrammarContext::AllowRegExp);
assert_eq!(lex.get_source_mapping_url(), Some("second-map.map"));
}
{
let (mut sm, id) = mk(
"var x = 1;\n\
// sourceMappingURL=localhost:8000/this_is_the_url.map\n\
//# sourceMappingURL =localhost:8000/this_is_the_url.map\n\
//#sourceMappingURL=localhost:8000/this_is_the_url.map\n\
//# sourceMappingURL=\nlocalhost:8000/this_is_the_url.map\n",
);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_var);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::equal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
lex.advance(GrammarContext::AllowRegExp);
lex.advance(GrammarContext::AllowRegExp);
lex.advance(GrammarContext::AllowRegExp);
lex.advance(GrammarContext::AllowRegExp);
let url = lex.get_source_mapping_url();
assert!(url.is_none() || url == Some(""), "url={url:?}");
let mgr_url = lex.get_source_mgr().source_mapping_url(id);
assert!(
mgr_url.is_none() || mgr_url == Some(""),
"mgr_url={mgr_url:?}"
);
}
{
let (mut sm, id) = mk(
"var x = 1;\n//# sourceMappingURL=url1\n//# sourceMappingURL=url2\n",
);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_var);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::equal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
lex.advance(GrammarContext::AllowRegExp);
lex.advance(GrammarContext::AllowRegExp);
assert_eq!(lex.get_source_mapping_url(), Some("url2"));
}
}
#[test]
fn lookahead_newline_test() {
let (mut sm, id) = mk("function\n(");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_function);
let opt_next = lex.lookahead1::<true>(None);
assert_eq!(opt_next, None);
assert_eq!(lex.token().kind(), TokenKind::rw_function);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::l_paren);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn lookahead_test() {
let (mut sm, id) = mk("function( foo,");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_function);
let opt_next = lex.lookahead1::<true>(None);
assert_eq!(opt_next, Some(TokenKind::l_paren));
assert_eq!(lex.token().kind(), TokenKind::rw_function);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::l_paren);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
let opt_next = lex.lookahead1::<true>(Some(TokenKind::plus));
assert_eq!(opt_next, Some(TokenKind::comma));
assert_eq!(lex.token().kind(), TokenKind::identifier);
let opt_next = lex.lookahead1::<true>(Some(TokenKind::comma));
assert_eq!(opt_next, Some(TokenKind::comma));
assert_eq!(lex.token().kind(), TokenKind::comma);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn regress_consume_bad_hex_test() {
let (mut sm, id) = mk_bytes(b"'\\x\x15\x15'");
let tab = AtomTable::new();
let mut diag = Diag::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(diag.err_clear(&lex), 1);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert!(!lex.is_new_line_before_current_token());
assert_eq!(diag.err_clear(&lex), 0);
}
#[test]
fn consume_bad_braced_code_point() {
let (mut sm, id) = mk("'\\u{12XXXXXXXXXXX'");
sm.set_error_limit(1);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::string_literal);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
}
#[test]
fn at_sign_test() {
for limit in [10u32, 1u32] {
let (mut sm, id) = mk("`${{}@");
sm.set_error_limit(limit);
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::template_head);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::l_brace);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::r_brace);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::at);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
assert_eq!(lex.get_source_mgr().error_count(), 0, "limit={limit}");
}
}
#[test]
fn jsx_test() {
let (mut sm, id) = mk("abc def{xyz<qwerty");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance_in_jsx_child().kind(), TokenKind::jsx_text);
assert_eq!(tab.bytes(lex.token().get_jsx_text_raw()), b"abc def");
assert_eq!(lex.advance_in_jsx_child().kind(), TokenKind::l_brace);
assert_eq!(lex.advance_in_jsx_child().kind(), TokenKind::jsx_text);
assert_eq!(tab.bytes(lex.token().get_jsx_text_raw()), b"xyz");
assert_eq!(lex.advance_in_jsx_child().kind(), TokenKind::less);
assert_eq!(lex.advance_in_jsx_child().kind(), TokenKind::jsx_text);
assert_eq!(tab.bytes(lex.token().get_jsx_text_raw()), b"qwerty");
}
#[test]
fn store_comments_test() {
use hermes_parser::token::CommentKind;
{
let (mut sm, id) = mk("// hello\n;\n// world");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_store_comments(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 2);
assert_eq!(cs[0].kind(), CommentKind::Line);
assert_eq!(cs[0].get_string(raw), b" hello");
assert_eq!(cs[1].kind(), CommentKind::Line);
assert_eq!(cs[1].get_string(raw), b" world");
}
{
let (mut sm, id) = mk("/* hello */;/*world*/");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_store_comments(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 2);
assert_eq!(cs[0].kind(), CommentKind::Block);
assert_eq!(cs[0].get_string(raw), b" hello ");
assert_eq!(cs[1].kind(), CommentKind::Block);
assert_eq!(cs[1].get_string(raw), b"world");
}
{
let (mut sm, id) = mk("#! hello world\n;");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_store_comments(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 1);
assert_eq!(cs[0].kind(), CommentKind::Hashbang);
assert_eq!(cs[0].get_string(raw), b" hello world");
}
{
let (mut sm, id) = mk("/**/;//\n");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_store_comments(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::semi);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 2);
assert_eq!(cs[0].kind(), CommentKind::Block);
assert_eq!(cs[0].get_string(raw), b"");
assert_eq!(cs[1].kind(), CommentKind::Line);
assert_eq!(cs[1].get_string(raw), b"");
}
{
let (mut sm, id) = mk("/*one*/ < /*two*/ >");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_store_comments(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::less);
let save_point = lex.save_point();
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::greater);
{
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 2);
assert_eq!(cs[0].kind(), CommentKind::Block);
assert_eq!(cs[0].get_string(raw), b"one");
assert_eq!(cs[1].kind(), CommentKind::Block);
assert_eq!(cs[1].get_string(raw), b"two");
}
save_point.restore(&mut lex);
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 1);
assert_eq!(cs[0].kind(), CommentKind::Block);
assert_eq!(cs[0].get_string(raw), b"one");
}
{
let (mut sm, id) = mk("/*one*/ A /*two*/ >");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
lex.set_store_comments(true);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
{
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 1);
assert_eq!(cs[0].get_string(raw), b"one");
}
lex.lookahead1::<true>(Some(TokenKind::semi));
{
let buf = lex.get_source_mgr().source_buffer(id);
let raw = buf.raw();
let cs = lex.get_stored_comments();
assert_eq!(cs.len(), 1);
assert_eq!(cs[0].get_string(raw), b"one");
}
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::greater);
assert_eq!(lex.get_stored_comments().len(), 2);
}
}
#[test]
fn prev_token_end_loc_test() {
let (mut sm, id) = mk("var x = 1");
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::rw_var);
let var_end_loc = lex.token().end_loc();
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::identifier);
assert_eq!(lex.prev_token_end(), var_end_loc);
let id_end_loc = lex.token().end_loc();
let save_point = lex.save_point();
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::equal);
assert_eq!(lex.prev_token_end(), id_end_loc);
let equal_end_loc = lex.token().end_loc();
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::numeric_literal);
assert_eq!(lex.prev_token_end(), equal_end_loc);
save_point.restore(&mut lex);
assert_eq!(lex.prev_token_end(), var_end_loc);
}
#[test]
fn comment_error_message_text() {
let (mut sm, id) = mk("/* not closed");
sm.set_handler(Box::new(CollectingHandler::new()));
let tab = AtomTable::new();
let mut lex = JSLexer::new(id, &mut sm, &tab, GrammarContext::AllowRegExp);
assert_eq!(lex.advance(GrammarContext::AllowRegExp).kind(), TokenKind::eof);
let h = lex
.get_source_mgr()
.handler_as::<CollectingHandler>()
.unwrap();
let errs: Vec<_> = h
.messages()
.iter()
.filter(|m| m.kind == DiagKind::Error)
.collect();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].message, "non-terminated block comment");
let notes: Vec<_> = h
.messages()
.iter()
.filter(|m| m.kind == DiagKind::Note)
.collect();
assert_eq!(notes.len(), 1);
assert_eq!(notes[0].message, "comment started here");
}