use super::*;
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn parse_function_declaration(
&mut self,
location: Location,
attributes: ParsedAttributes<'ast>,
) -> Result<ParsedStatement<'ast>> {
let function_keyword = self.current_position();
self.advance();
let attr_lists = attributes.attr_lists.clone();
let name = self.parse_function_name()?;
let self_parameter = name.has_self.then_some(location);
let parsed = match self.parse_function_after_name(FunctionParseContext {
attributes,
location,
match_location: location,
function_keyword,
self_parameter,
debug_name: Some(name.debug_name),
}) {
Ok(function) => function,
Err(error) => {
let error_location = error.location;
return Ok(self.report_statement_error(error_location, error));
}
};
let statement_location = Location::new(location.begin, parsed.function.location.end);
let name_expression = self.check_assignable_expression(name.expression);
let statement = self
.arena
.alloc_statement_node(StatementFunctionDeclaration::new(
statement_location,
false,
name_expression,
parsed.function,
));
Ok(self.parsed_statement_from_node(
statement,
if self.cst.enabled() {
Some(CstNode::StatFunction(CstStatFunction {
attr_lists,
function_keyword,
}))
} else {
None
},
))
}
pub(in crate::parser) fn parse_function_name(&mut self) -> Result<ParsedFunctionName<'ast>> {
let (mut debug_name, mut expression) = if let Token::Ident(name) = self.current {
let name_location = self.current_token_location();
let debug_name = name;
self.advance();
let expression = if let Some(local) = self.visible_local(debug_name) {
if self.local_is_type_function_capture(local) {
let error_location = self.current_location();
let message_index = self.report_parse_error(self.error_at(
error_location,
self.name_message(
b"Type function cannot reference outer local '",
local.name,
b"'",
),
));
self.arena.alloc_expression_error_direct(
error_location,
self.empty_expression_slice(),
message_index,
)
} else {
self.arena.alloc_expression_local_direct(
name_location,
local,
local.function_depth != self.contexts.functions.len(),
)
}
} else {
self.arena
.alloc_expression_global_direct(name_location, debug_name)
};
(debug_name, expression)
} else {
let name_location = self.current_token_location();
let message_index =
self.report_parse_error(self.identifier_error(Some("function name")));
let debug_name = self.name_error;
(
debug_name,
self.arena.alloc_expression_error_direct(
name_location,
self.empty_expression_slice(),
message_index,
),
)
};
let mut has_self = false;
let old_recursion_counter = self.contexts.recursion_counter;
loop {
match self.current {
Token::Dot => {
let op_position = self.current_position();
self.advance();
let field = self.parse_name("field name");
debug_name = field.name;
expression = self.arena.alloc_expression_index_name_direct(
Location::new(expression.location().begin, field.location.end),
expression,
debug_name,
field.location,
op_position,
IndexNameOp::Dot,
);
if let Err(error) = self.enter_recursion("function name") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
Token::Colon => {
let op_position = self.current_position();
self.advance();
has_self = true;
let field = self.parse_name("method name");
debug_name = field.name;
expression = self.arena.alloc_expression_index_name_direct(
Location::new(expression.location().begin, field.location.end),
expression,
debug_name,
field.location,
op_position,
IndexNameOp::Colon,
);
break;
}
_ => break,
}
}
self.contexts.recursion_counter = old_recursion_counter;
let expression = self.check_assignable_expression(expression);
Ok(ParsedFunctionName {
expression,
has_self,
debug_name,
})
}
}