#![cfg(debug_assertions)]
use hermes_ast::context::Context;
use hermes_parser::js::JSParserImpl;
use hermes_parser::lexer::{GrammarContext, JSLexer};
use hermes_support::diag::CollectingHandler;
use hermes_support::manager::SourceErrorManager;
use hermes_support::render::render_diagnostic;
fn paren_ladder(n: usize) -> String {
let mut s = String::new();
for _ in 0..n {
s.push_str("(\n");
}
s.push_str("1\n");
for _ in 0..n {
s.push_str(")\n");
}
s
}
fn typeof_ladder(n: usize) -> String {
"typeof\n".repeat(n) + "xyzzy;\n"
}
fn parse(src: &str) -> (bool, String) {
let mut sm = SourceErrorManager::new();
let opts = sm.output_options();
sm.set_handler(Box::new(CollectingHandler::new()));
let buf_id = sm.add_buffer("nested-parens.js", src);
let mut ctx = Context::new();
let gc = ctx.lock();
let ok = {
let atoms = &gc.ctx().atom_table;
let lexer =
JSLexer::new(buf_id, &mut sm, atoms, GrammarContext::AllowRegExp);
let mut parser = JSParserImpl::new(&gc, lexer);
parser.parse().is_some()
};
let rendered: String = sm
.handler_as::<CollectingHandler>()
.expect("CollectingHandler installed above")
.messages()
.iter()
.map(|d| render_diagnostic(d, &opts))
.collect();
(ok, rendered)
}
fn on_a_big_stack(f: fn()) {
std::thread::Builder::new()
.stack_size(32 * 1024 * 1024)
.spawn(f)
.expect("failed to spawn the deep-recursion test thread")
.join()
.expect("the deep-recursion test thread panicked");
}
#[test]
fn one_below_the_limit_parses_cleanly() {
on_a_big_stack(one_below_the_limit_parses_cleanly_impl);
}
fn one_below_the_limit_parses_cleanly_impl() {
let (ok, rendered) = parse(&paren_ladder(125));
assert!(ok, "125 nested parens must parse");
assert_eq!(rendered, "", "125 nested parens must emit no diagnostic");
}
#[test]
fn at_the_limit_reports_the_recursion_error() {
on_a_big_stack(at_the_limit_reports_the_recursion_error_impl);
}
fn at_the_limit_reports_the_recursion_error_impl() {
let (ok, rendered) = parse(&paren_ladder(126));
assert!(!ok, "126 nested parens must fail to parse");
assert_eq!(
rendered,
"nested-parens.js:127:1: error: Too many nested expressions/\
statements/declarations\n\
1\n\
^\n"
);
}
#[test]
fn at_the_limit_renders_a_bare_caret_on_a_wide_token() {
on_a_big_stack(at_the_limit_renders_a_bare_caret_on_a_wide_token_impl);
}
fn at_the_limit_renders_a_bare_caret_on_a_wide_token_impl() {
let (ok, rendered) = parse(&typeof_ladder(125));
assert!(ok, "125 nested `typeof` must parse");
assert_eq!(rendered, "", "125 nested `typeof` must emit no diagnostic");
let (ok, rendered) = parse(&typeof_ladder(126));
assert!(!ok, "126 nested `typeof` must fail to parse");
assert_eq!(
rendered,
"nested-parens.js:127:1: error: Too many nested expressions/\
statements/declarations\n\
xyzzy;\n\
^\n"
);
}