use super::*;
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn parse_function_literal(&mut self) -> Result<Expression<'ast>> {
let location = self.current_location();
self.parse_function_literal_with_debug_name(ParsedAttributes::default(), location, None)
}
pub(in crate::parser) fn parse_function_literal_with_attributes(
&mut self,
attributes: ParsedAttributes<'ast>,
location: Location,
) -> Result<Expression<'ast>> {
self.parse_function_literal_with_debug_name(attributes, location, None)
}
pub(in crate::parser) fn parse_function_literal_with_debug_name(
&mut self,
attributes: ParsedAttributes<'ast>,
location: Location,
debug_name: Option<AstName<'ast>>,
) -> Result<Expression<'ast>> {
let function_keyword = self.current_position();
self.advance();
let parsed = self.parse_function_after_name(FunctionParseContext {
attributes,
location,
match_location: location,
function_keyword,
self_parameter: None,
debug_name,
})?;
Ok(self
.arena
.alloc_expression_function_literal_direct(parsed.function.location, parsed.function))
}
pub(in crate::parser) fn parse_function_after_name(
&mut self,
context: FunctionParseContext<'ast>,
) -> Result<ParsedFunction<'ast>> {
self.parse_function_after_name_inner(context, |_| ())
.map(|parsed| ParsedFunction {
function: parsed.function,
})
}
pub(in crate::parser) fn parse_local_function_after_name(
&mut self,
context: FunctionParseContext<'ast>,
local: FunctionLocalBinding<'ast>,
) -> Result<ParsedLocalFunction<'ast>> {
self.parse_function_after_name_inner(context, |parser| {
parser.declare_local(
local.name,
local.location,
None,
local.is_const,
local.is_exported,
)
})
.map(|parsed| ParsedLocalFunction {
function: parsed.function,
local: parsed.local,
})
}
fn parse_function_after_name_inner<L>(
&mut self,
context: FunctionParseContext<'ast>,
declare_local: impl FnOnce(&mut Self) -> L,
) -> Result<ParsedFunctionWithLocal<'ast, L>> {
let FunctionParseContext {
attributes,
location,
match_location,
function_keyword,
self_parameter,
debug_name,
} = context;
self.with_match_recovery_stop(MatchRecoveryStop::ReservedEnd, |parser| {
let generics = parser.parse_optional_generic_parameters(false)?;
let paren_location = parser.current_location();
let paren = parser.current;
parser.expect_function_left_paren()?;
let mut bindings = parser.temp_bindings();
let mut argument_commas = parser.temp_positions();
let parameters =
parser.with_match_recovery_stop(MatchRecoveryStop::RightParen, |parser| {
let parameters = if parser.current.kind() != TokenKind::RightParen {
parser.parse_binding_list_into(
&mut bindings,
true,
&mut argument_commas,
false,
)?
} else {
ParsedBindingList {
variadic: false,
vararg_location: Location::zero(),
vararg_annotation: None,
vararg_annotation_colon: Position::missing(),
}
};
let arg_location = (paren.kind() == TokenKind::LeftParen
&& parser.current.kind() == TokenKind::RightParen)
.then(|| {
Location::new(paren_location.begin, parser.current_token_location().end)
});
if parser.current.kind() != TokenKind::RightParen {
let error = parser.matched_token_error(")", "(", paren_location);
parser.report_parse_error(error);
parser.recover_match_on_line(Token::RightParen);
} else {
parser.advance();
}
Ok((parameters, arg_location))
})?;
let (parameters, arg_location) = parameters;
let (return_annotation, return_specifier) =
parser.parse_optional_return_annotation_with_colon()?;
let body_begin = parser.previous_token_end_position();
let local = declare_local(parser);
let locals_begin = parser.locals.stack.len();
parser.contexts.functions.push(FunctionContext {
loop_depth: 0,
vararg: parameters.variadic,
});
let self_parameter = if let Some(location) = self_parameter {
let name = parser.name_self;
Some(parser.declare_local(name, location, None, false, false))
} else {
None
};
let mut args = parser.temp_locals();
for binding in bindings.iter() {
args.push_back(parser.declare_local(
binding.name,
binding.name_location,
binding.annotation,
binding.is_const,
false,
));
}
let body =
parser.parse_block_until_from(&["end"], "function", match_location, body_begin);
parser.contexts.functions.pop();
parser.restore_locals(locals_begin);
let function_depth = parser.contexts.functions.len() + 1;
let end_location = parser.current_token_location();
let mut body = body?;
body.has_end = parser.expect_match_end_with_lookahead("function", match_location);
let body = parser.arena.alloc_block(body);
let attr_lists = attributes.attr_lists;
let attribute_values = attributes.attributes;
let cst = parser.cst.enabled().then(|| CstExprFunction {
attr_lists,
function_keyword,
open_generics: generics.open,
generics_commas: parser.arena.alloc_slice_copy(&generics.commas),
close_generics: generics.close,
argument_annotation_colons: {
let mut argument_annotation_colons = argument_commas.nested();
for binding in bindings.iter() {
argument_annotation_colons.push_back(binding.colon_position);
}
parser
.arena
.alloc_slice_copy(argument_annotation_colons.as_slice())
},
argument_commas: parser.arena.alloc_slice_copy(argument_commas.as_slice()),
vararg_annotation_colon: parameters.vararg_annotation_colon,
return_specifier: return_specifier.unwrap_or(Position::missing()),
});
let vararg_annotation = parameters.vararg_annotation;
let attributes = parser.arena.alloc_slice_copy(&attribute_values);
let function = parser.alloc_function_with_cst(
Function {
location: Location::new(location.begin, end_location.end),
attributes,
generics: parser.arena.alloc_slice_copy(&generics.types),
generic_packs: parser.arena.alloc_slice_copy(&generics.type_packs),
self_parameter,
args: parser.arena.alloc_slice_copy(args.as_slice()),
vararg: parameters.variadic,
vararg_location: parameters.vararg_location,
body,
function_depth,
debug_name,
return_annotation,
vararg_annotation,
arg_location,
},
cst.map(CstNode::ExprFunction),
);
Ok(ParsedFunctionWithLocal { function, local })
})
}
}
pub(super) struct ParsedFunction<'ast> {
pub(super) function: &'ast mut Function<'ast>,
}
pub(super) struct ParsedLocalFunction<'ast> {
pub(super) function: &'ast mut Function<'ast>,
pub(super) local: &'ast Local<'ast>,
}
struct ParsedFunctionWithLocal<'ast, L> {
function: &'ast mut Function<'ast>,
local: L,
}
pub(in crate::parser) struct FunctionParseContext<'ast> {
pub(super) attributes: ParsedAttributes<'ast>,
pub(super) location: Location,
pub(super) match_location: Location,
pub(super) function_keyword: Position,
pub(super) self_parameter: Option<Location>,
pub(super) debug_name: Option<AstName<'ast>>,
}
pub(in crate::parser) struct FunctionLocalBinding<'ast> {
pub(super) name: AstName<'ast>,
pub(super) location: Location,
pub(super) is_const: bool,
pub(super) is_exported: bool,
}