Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/parser/arrow_function_definitions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,15 @@ impl ArrowParameters {

pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
// Finds the FunctionBody, ConciseBody, or AsyncConciseBody that contains location most closely.
if self.location().contains(location) {
match self {
ArrowParameters::Identifier(_) => None,
ArrowParameters::Formals(arrow_formal_parameters) => {
match self {
ArrowParameters::Identifier(_) => None,
ArrowParameters::Formals(arrow_formal_parameters) => {
if self.location().contains(location) {
arrow_formal_parameters.body_containing_location(location)
} else {
None
}
}
} else {
None
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/parser/arrow_function_definitions/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,15 @@ mod arrow_parameters {
fn contains_expression(src: &str) -> bool {
Maker::new(src).arrow_parameters().contains_expression()
}

#[test_case("x" => None; "binding identifier")]
#[test_case("(x, y=call())" => None ; "location in params, but not in a body itself")]
#[test_case("(x=function(){call();}, y)" => ssome("call ( ) ;"); "location in params")]
#[test_case("(x, y)" => None; "location not in production")]
fn body_containing_location(src: &str) -> Option<String> {
let location = find_call(src);
Maker::new(src).arrow_parameters().body_containing_location(&location).map(|node| node.to_string())
}
}

// CONCISE BODY
Expand Down Expand Up @@ -619,4 +628,12 @@ mod arrow_formal_parameters {
fn display(src: &str) -> String {
format!("{}", Maker::new(src).arrow_formal_parameters())
}

#[test_case("()" => None; "location not in parse node")]
#[test_case("(x = call())" => None; "there, but not in body")]
#[test_case("(x = function(){call();})" => ssome("call ( ) ;"); "found a function body")]
fn body_containing_location(src: &str) -> Option<String> {
let location = find_call(src);
Maker::new(src).arrow_formal_parameters().body_containing_location(&location).map(|node| node.to_string())
}
}
17 changes: 11 additions & 6 deletions src/parser/async_function_definitions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,14 @@ impl AsyncFunctionExpression {
pub(crate) fn is_named_function(&self) -> bool {
self.ident.is_some()
}
#[expect(unused_variables)]

pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
todo!()
// Finds the FunctionBody, ConciseBody, or AsyncConciseBody that contains location most closely.
if self.location().contains(location) {
self.params.body_containing_location(location).or_else(|| self.body.body_containing_location(location))
} else {
None
}
}
}

Expand Down Expand Up @@ -756,10 +761,10 @@ impl AsyncFunctionBody {
self.0.lexically_scoped_declarations()
}

//#[expect(unused_variables)]
//pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
// todo!()
//}
pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
// Finds the FunctionBody, ConciseBody, or AsyncConciseBody that contains location most closely
self.0.body_containing_location(location)
}
}

// AwaitExpression[Yield] :
Expand Down
18 changes: 12 additions & 6 deletions src/parser/async_generator_function_definitions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,9 +525,14 @@ impl AsyncGeneratorExpression {
pub(crate) fn is_named_function(&self) -> bool {
self.ident.is_some()
}
#[expect(unused_variables)]

pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
todo!()
// Finds the FunctionBody, ConciseBody, or AsyncConciseBody that contains location most closely
if self.location().contains(location) {
self.params.body_containing_location(location).or_else(|| self.body.body_containing_location(location))
} else {
None
}
}
}

Expand Down Expand Up @@ -633,10 +638,11 @@ impl AsyncGeneratorBody {
pub(crate) fn function_body_contains_use_strict(&self) -> bool {
self.0.function_body_contains_use_strict()
}
//#[expect(unused_variables)]
//pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
// todo!()
//}

pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
// Finds the FunctionBody, ConciseBody, or AsyncConciseBody that contains location most closely
self.0.body_containing_location(location)
}
}

#[cfg(test)]
Expand Down
13 changes: 9 additions & 4 deletions src/parser/generator_function_definitions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,9 +489,14 @@ impl GeneratorExpression {
pub(crate) fn is_named_function(&self) -> bool {
self.ident.is_some()
}
#[expect(unused_variables)]

pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
todo!()
// Finds the FunctionBody, ConciseBody, or AsyncConciseBody that contains location most closely.
if self.location().contains(location) {
self.params.body_containing_location(location).or_else(|| self.body.body_containing_location(location))
} else {
None
}
}
}

Expand Down Expand Up @@ -601,9 +606,9 @@ impl GeneratorBody {
pub(crate) fn lexically_scoped_declarations(&self) -> Vec<DeclPart> {
self.0.lexically_scoped_declarations()
}
#[expect(unused_variables)]

pub(crate) fn body_containing_location(&self, location: &Location) -> Option<ContainingBody> {
todo!()
self.0.body_containing_location(location)
}
}

Expand Down
46 changes: 46 additions & 0 deletions src/parser/primary_expressions/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,52 @@ mod primary_expression {
fn location(src: &str) -> Location {
Maker::new(src).primary_expression().location()
}

#[test_case("this" => None; "this expression")]
#[test_case("blue" => None; "identifier expression")]
#[test_case("[ function () { return call(); } ]" => ssome("return call ( ) ;"); "array literal; present")]
#[test_case("[ 19 ]" => None; "array literal; missing")]
#[test_case("{ a: function () { return call(); } }" => ssome("return call ( ) ;"); "object literal; present")]
#[test_case("{ a: 10 }" => None; "object literal; missing")]
#[test_case("(function () { return call(); })" => ssome("return call ( ) ;"); "paren expr; present")]
#[test_case("(10)" => None; "paren; missing")]
#[test_case("`${function () { return call(); }}`" => ssome("return call ( ) ;"); "template; present")]
#[test_case("`${1}`" => None; "template; missing")]
#[test_case("class a { item () { return call(); } }" => ssome("return call ( ) ;"); "class; present")]
#[test_case("class a { item () { return 5; } }" => None; "class; missing")]
#[test_case("function *() { return call(); }" => ssome("return call ( ) ;"); "generator; present")]
#[test_case("function *() { return undefined; }" => None; "generator; missing")]
#[test_case("async function () { return call(); }" => ssome("return call ( ) ;"); "async function; present")]
#[test_case("async function () { return undefined; }" => None; "async function; missing")]
#[test_case("async function *() { return call(); }" => ssome("return call ( ) ;"); "async generator; present")]
#[test_case("async function *() { return undefined; }" => None; "async generator; missing")]
fn body_containing_location(src: &str) -> Option<String> {
let location = find_call(src);
Maker::new(src)
.return_ok(true)
.primary_expression()
.body_containing_location(&location)
.map(|node| node.to_string())
}

#[test_case("this" => false; "this expression")]
#[test_case("a" => false; "identifier")]
#[test_case("18" => false; "literal")]
#[test_case("[]" => false; "array literal")]
#[test_case("{ a: 10 }" => false; "object literal")]
#[test_case("``" => false; "template literal")]
#[test_case("function () { return 1; }" => false; "function expression")]
#[test_case("class { a() {} }" => false; "class expression")]
#[test_case("function *(){}" => false; "generator expression")]
#[test_case("async function(){}" => false; "async function expression")]
#[test_case("async function * () {}" => false; "async generator expression")]
#[test_case("/regex/" => false; "regular expression")]
#[test_case("(10)" => false; "paren expression; missing")]
#[test_case("(call())" => true; "paren expression; present")]
fn has_call_in_tail_position(src: &str) -> bool {
let location = find_call(src);
Maker::new(src).primary_expression().has_call_in_tail_position(&location)
}
}

// LITERAL
Expand Down
Loading