use super::super::*;
use super::is_type_follow;
pub(in crate::parser) struct ParsedFunctionParameterTypes<'ast> {
pub(super) result: Vec<Type<'ast>>,
pub(super) result_names: Vec<Option<ArgumentName<'ast>>>,
pub(super) comma_positions: Vec<Position>,
pub(super) name_colon_positions: Vec<Option<Position>>,
pub(super) vararg_annotation: Option<TypePack<'ast>>,
}
impl ParsedFunctionParameterTypes<'_> {
pub(super) fn has_named_parameters(&self) -> bool {
!self.result_names.is_empty()
}
}
pub(in crate::parser) struct ParsedParenthesizedFunctionParameterTypes<'ast> {
pub(super) parameters: ParsedFunctionParameterTypes<'ast>,
pub(super) open: Position,
pub(super) close: Position,
pub(super) close_location: Location,
}
pub(in crate::parser) struct TypeParameters<'ast> {
pub(super) arguments: Vec<TypeOrPack<'ast>>,
pub(super) open: Position,
pub(super) commas: Vec<Position>,
pub(super) close: Position,
}
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn alloc_explicit_type_pack(
&mut self,
location: Location,
types: Vec<Type<'ast>>,
tail: Option<TypePack<'ast>>,
parentheses: Option<CstTypePackParentheses>,
comma_positions: Vec<Position>,
) -> TypePack<'ast> {
let types = self.alloc_type_slice(types);
let kind = TypePackKind::Explicit {
type_list: TypeList {
types,
tail_type: tail,
},
};
let cst = self.cst.enabled().then_some({
CstNode::TypePackExplicit(CstTypePackExplicit {
parentheses,
comma_positions,
})
});
self.alloc_type_pack_with_cst(location, kind, cst)
}
pub(in crate::parser) fn alloc_explicit_type_pack_from_parameters(
&mut self,
location: Location,
parameters: ParsedFunctionParameterTypes<'ast>,
parentheses: Option<CstTypePackParentheses>,
) -> TypePack<'ast> {
self.alloc_explicit_type_pack(
location,
parameters.result,
parameters.vararg_annotation,
parentheses,
parameters.comma_positions,
)
}
pub(in crate::parser) fn alloc_generic_type_pack(
&mut self,
location: Location,
generic_name: AstName<'ast>,
ellipsis: Position,
) -> TypePack<'ast> {
let cst = self
.cst
.enabled()
.then_some(CstNode::TypePackGeneric(CstTypePackGeneric { ellipsis }));
self.alloc_type_pack_with_cst(location, TypePackKind::Generic { generic_name }, cst)
}
pub(in crate::parser) fn parse_return_type_pack(&mut self) -> Result<TypePack<'ast>> {
let old_recursion_counter = self.enter_recursion("type annotation")?;
let ident_starts_type_pack =
matches!(self.current, Token::Ident(_)) && self.peek().kind() == TokenKind::Ellipsis;
let result = match self.current {
Token::LeftParen => self.parse_function_return_type_pack(),
Token::Ellipsis => self.parse_type_pack(),
Token::Ident(_) if ident_starts_type_pack => self.parse_type_pack(),
_ => {
let annotation = self.parse_type_annotation()?;
Ok(self.alloc_explicit_type_pack(
annotation.location,
vec![annotation],
None,
None,
Vec::new(),
))
}
};
self.contexts.recursion_counter = old_recursion_counter;
result
}
pub(in crate::parser) fn parse_function_return_type_pack(&mut self) -> Result<TypePack<'ast>> {
let arg_types = self.parse_function_type_parameter_pack()?;
let result = if self.current.kind() == TokenKind::SkinnyArrow
|| self.current.kind() == TokenKind::Colon
{
let return_arrow = self.current_position();
if self.current.kind() == TokenKind::Colon {
self.report_parse_error(self.function_type_colon_return_error());
self.advance();
} else {
self.advance();
}
let return_types = self.parse_return_type_pack()?;
let ParsedFunctionParameterTypes {
result,
result_names,
comma_positions,
name_colon_positions,
vararg_annotation,
} = arg_types.parameters;
let cst = self.cst.enabled().then(|| {
CstNode::TypeFunction(CstTypeFunction {
open_generics: Position::missing(),
generics_commas: Vec::new(),
close_generics: Position::missing(),
open_arguments: arg_types.open,
argument_name_colons: name_colon_positions,
argument_commas: comma_positions,
close_arguments: arg_types.close,
return_arrow,
})
});
let function_returns = return_types;
let attributes = self.arena.alloc_slice_fill_iter(std::iter::empty());
let generics = self.arena.alloc_slice_fill_iter(std::iter::empty());
let generic_packs = self.arena.alloc_slice_fill_iter(std::iter::empty());
let function_parameters = TypeList {
types: self.alloc_type_slice(result),
tail_type: vararg_annotation,
};
let arg_names = self.arena.alloc_slice_fill_iter(result_names);
let function = self.alloc_type_with_cst(
Location::new(arg_types.open, function_returns.location.end),
TypeKind::Function {
attributes,
generics,
generic_packs,
arg_types: function_parameters,
arg_names,
return_types: function_returns,
},
cst,
);
self.alloc_explicit_type_pack(function.location, vec![function], None, None, Vec::new())
} else if arg_types.parameters.has_named_parameters() {
let function = self.parse_function_type_tail(
Location::from_length(arg_types.open, 1),
Vec::new(),
ParsedGenericParameters::default(),
arg_types,
)?;
self.alloc_explicit_type_pack(function.location, vec![function], None, None, Vec::new())
} else {
let location = Location::new(arg_types.open, arg_types.close_location.end);
if arg_types.parameters.result.len() == 1 {
let inner = arg_types.parameters.result[0];
let annotation = if arg_types.parameters.vararg_annotation.is_none() {
let cst = self.cst_node(|| {
CstNode::TypeGroup(CstTypeGroup {
close_position: arg_types.close,
})
});
self.alloc_type_with_cst(location, TypeKind::Group { ty: inner }, cst)
} else {
inner
};
let annotation = self.parse_type_suffix(Some(annotation), location)?;
let end = if arg_types.parameters.result.len() == 1 {
location.end
} else {
annotation.location.end
};
self.alloc_explicit_type_pack(
Location::new(location.begin, end),
vec![annotation],
arg_types.parameters.vararg_annotation,
None,
Vec::new(),
)
} else {
self.alloc_explicit_type_pack_from_parameters(
location,
arg_types.parameters,
Some(CstTypePackParentheses {
open: arg_types.open,
close: arg_types.close,
}),
)
}
};
Ok(result)
}
pub(in crate::parser) fn parse_type_parameters_with_cst(
&mut self,
) -> Result<TypeParameters<'ast>> {
let open = self.current_position();
let less_location = self.current_token_location();
if self.current.kind() != TokenKind::Less {
return Ok(TypeParameters {
arguments: Vec::new(),
open: Position::missing(),
commas: Vec::new(),
close: Position::missing(),
});
}
self.advance();
let mut arguments = self.temp_type_or_pack();
let mut commas = self.temp_positions();
if self.current.kind() == TokenKind::Greater {
let close = self.current_position();
self.advance();
return Ok(TypeParameters {
arguments: arguments.as_slice().to_vec(),
open,
commas: commas.as_slice().to_vec(),
close,
});
}
loop {
arguments.push_back(self.parse_type_argument()?);
match self.current {
Token::Comma => {
commas.push_back(self.current_position());
self.advance();
}
Token::Greater => {
let close = self.current_position();
self.advance();
return Ok(TypeParameters {
arguments: arguments.as_slice().to_vec(),
open,
commas: commas.as_slice().to_vec(),
close,
});
}
_ => break,
}
}
let close = if self.expect_match_token(Token::Greater, ">", "<", less_location, false) {
self.previous_token_location().begin
} else {
Position::missing()
};
Ok(TypeParameters {
arguments: arguments.as_slice().to_vec(),
open,
commas: commas.as_slice().to_vec(),
close,
})
}
pub(in crate::parser) fn parse_type_argument(&mut self) -> Result<TypeOrPack<'ast>> {
let ident_starts_type_pack =
matches!(self.current, Token::Ident(_)) && self.peek().kind() == TokenKind::Ellipsis;
match self.current {
Token::Ellipsis => {
let annotation = self.parse_type_pack()?;
Ok(TypeOrPack::Pack(annotation))
}
Token::Ident(_) if ident_starts_type_pack => {
let annotation = self.parse_type_pack()?;
Ok(TypeOrPack::Pack(annotation))
}
Token::LeftParen => {
let begin = self.current_location();
match self.parse_simple_type_or_pack_inner(true, false)? {
TypeOrPack::Pack(pack) => {
if let TypePackKind::Explicit { type_list } = pack.kind()
&& type_list.tail_type.is_none()
&& type_list.types.len() == 1
&& is_type_follow(&self.current)
{
let parenthesized = type_list.types[0];
let close_position = self
.cst
.get(pack)
.and_then(|node| match node {
CstNode::TypePackExplicit(cst) => {
cst.parentheses.map(|parentheses| parentheses.close)
}
_ => None,
})
.unwrap_or(Position::missing());
let cst = self
.cst_node(|| CstNode::TypeGroup(CstTypeGroup { close_position }));
let annotation = self.alloc_type_with_cst(
parenthesized.location,
TypeKind::Group { ty: parenthesized },
cst,
);
let annotation = self.parse_type_suffix(Some(annotation), begin)?;
return Ok(TypeOrPack::Type(annotation));
}
Ok(TypeOrPack::Pack(pack))
}
TypeOrPack::Type(annotation) => {
let annotation = self.parse_type_suffix(Some(annotation), begin)?;
Ok(TypeOrPack::Type(annotation))
}
}
}
_ => self.parse_type_annotation().map(TypeOrPack::Type),
}
}
pub(in crate::parser) fn parse_function_type_parameter_pack(
&mut self,
) -> Result<ParsedParenthesizedFunctionParameterTypes<'ast>> {
self.with_match_recovery_stop(MatchRecoveryStop::SkinnyArrow, |parser| {
parser.parse_parenthesized_type_pack_with_names()
})
}
pub(in crate::parser) fn parse_parenthesized_type_pack_with_names(
&mut self,
) -> Result<ParsedParenthesizedFunctionParameterTypes<'ast>> {
let paren_location = self.current_location();
let open = if self.current.kind() == TokenKind::LeftParen {
self.current_position()
} else {
Position::missing()
};
self.expect_and_consume(Token::LeftParen, "function parameters");
let mut result = self.temp_types();
let mut result_names = self.temp_optional_argument_names();
let mut comma_positions = self.temp_positions();
let mut name_colon_positions = self.temp_optional_positions();
let mut vararg_annotation = None;
if self.current.kind() == TokenKind::RightParen {
let close_location = self.current_token_location();
let close = close_location.begin;
self.advance();
return Ok(ParsedParenthesizedFunctionParameterTypes {
parameters: ParsedFunctionParameterTypes {
result: result.as_slice().to_vec(),
result_names: result_names.as_slice().to_vec(),
comma_positions: comma_positions.as_slice().to_vec(),
name_colon_positions: name_colon_positions.as_slice().to_vec(),
vararg_annotation,
},
open,
close,
close_location,
});
}
loop {
if self.current.kind() == TokenKind::Ellipsis
|| matches!(self.current, Token::Ident(_))
&& self.peek().kind() == TokenKind::Ellipsis
{
vararg_annotation = Some(self.parse_type_pack()?);
let (close_location, close) =
self.parse_parenthesized_type_pack_close(paren_location)?;
return Ok(ParsedParenthesizedFunctionParameterTypes {
parameters: ParsedFunctionParameterTypes {
result: result.as_slice().to_vec(),
result_names: result_names.as_slice().to_vec(),
comma_positions: comma_positions.as_slice().to_vec(),
name_colon_positions: name_colon_positions.as_slice().to_vec(),
vararg_annotation,
},
open,
close,
close_location,
});
}
if let Token::Ident(name) = self.current
&& self.peek().kind() == TokenKind::Colon
{
while result_names.len() < result.len() {
result_names.push_back(None);
}
while name_colon_positions.len() < result.len() {
name_colon_positions.push_back(None);
}
result_names.push_back(Some(ArgumentName {
name,
location: self.current_token_location(),
}));
self.advance();
name_colon_positions.push_back(Some(self.current_position()));
self.advance();
} else if result_names.len() != 0 {
result_names.push_back(None);
name_colon_positions.push_back(None);
}
let annotation = self.parse_type_annotation()?;
if self.current.kind() == TokenKind::Ellipsis {
let TypeKind::Reference {
prefix: None,
name,
parameters,
..
} = annotation.kind()
else {
return Err(self.unexpected("generic type pack"));
};
if !parameters.is_empty() {
return Err(self.unexpected("generic type pack"));
}
let ellipsis = self.current_position();
self.advance();
let name = self.intern_name_bytes(name.bytes());
vararg_annotation = Some(self.alloc_generic_type_pack(
Location::new(
annotation.location.begin,
self.previous_token_end_position(),
),
name,
ellipsis,
));
let (close_location, close) =
self.parse_parenthesized_type_pack_close(paren_location)?;
return Ok(ParsedParenthesizedFunctionParameterTypes {
parameters: ParsedFunctionParameterTypes {
result: result.as_slice().to_vec(),
result_names: result_names.as_slice().to_vec(),
comma_positions: comma_positions.as_slice().to_vec(),
name_colon_positions: name_colon_positions.as_slice().to_vec(),
vararg_annotation,
},
open,
close,
close_location,
});
}
result.push_back(annotation);
match self.current {
Token::Comma => {
comma_positions.push_back(self.current_position());
self.advance();
if self.current.kind() == TokenKind::RightParen {
self.report_parse_error(
self.located("Expected type after ',' but got ')' instead"),
);
let close_location = self.current_token_location();
let close = close_location.begin;
self.advance();
return Ok(ParsedParenthesizedFunctionParameterTypes {
parameters: ParsedFunctionParameterTypes {
result: result.as_slice().to_vec(),
result_names: result_names.as_slice().to_vec(),
comma_positions: comma_positions.as_slice().to_vec(),
name_colon_positions: name_colon_positions.as_slice().to_vec(),
vararg_annotation,
},
open,
close,
close_location,
});
}
}
Token::RightParen => {
let close_location = self.current_token_location();
let close = close_location.begin;
self.advance();
return Ok(ParsedParenthesizedFunctionParameterTypes {
parameters: ParsedFunctionParameterTypes {
result: result.as_slice().to_vec(),
result_names: result_names.as_slice().to_vec(),
comma_positions: comma_positions.as_slice().to_vec(),
name_colon_positions: name_colon_positions.as_slice().to_vec(),
vararg_annotation,
},
open,
close,
close_location,
});
}
_ => {
let (close_location, close) =
self.parse_parenthesized_type_pack_close(paren_location)?;
return Ok(ParsedParenthesizedFunctionParameterTypes {
parameters: ParsedFunctionParameterTypes {
result: result.as_slice().to_vec(),
result_names: result_names.as_slice().to_vec(),
comma_positions: comma_positions.as_slice().to_vec(),
name_colon_positions: name_colon_positions.as_slice().to_vec(),
vararg_annotation,
},
open,
close,
close_location,
});
}
}
}
}
pub(in crate::parser) fn parse_parenthesized_type_pack_close(
&mut self,
paren_location: Location,
) -> Result<(Location, Position)> {
let close_location = self.current_token_location();
if self.current.kind() == TokenKind::RightParen {
self.advance();
return Ok((close_location, close_location.begin));
}
let close = if self.expect_match_token(Token::RightParen, ")", "(", paren_location, true) {
self.previous_token_location().begin
} else {
Position::missing()
};
Ok((close_location, close))
}
pub(in crate::parser) fn parse_type_pack(&mut self) -> Result<TypePack<'ast>> {
let current = self.current;
match current {
Token::Ellipsis => {
let start = self.current_token_location();
self.advance();
let annotation = self.parse_type_annotation()?;
Ok(self.alloc_type_pack(
Location::new(start.begin, annotation.location.end),
TypePackKind::Variadic {
variadic_type: annotation,
},
))
}
Token::Ident(name) if self.peek().kind() == TokenKind::Ellipsis => {
let start = self.current_token_location();
self.advance();
let ellipsis = self.current_position();
let ellipsis_location = self.current_token_location();
self.advance();
Ok(self.alloc_generic_type_pack(
Location::new(start.begin, ellipsis_location.end),
name,
ellipsis,
))
}
_ => Err(self.unexpected("type pack")),
}
}
pub(in crate::parser) fn parse_variadic_argument_type_pack(
&mut self,
) -> Result<TypePack<'ast>> {
let current = self.current;
if let Token::Ident(name) = current
&& self.peek().kind() == TokenKind::Ellipsis
{
let start = self.current_token_location();
self.advance();
let ellipsis = self.current_position();
let ellipsis_location = self.current_token_location();
self.advance();
return Ok(self.alloc_generic_type_pack(
Location::new(start.begin, ellipsis_location.end),
name,
ellipsis,
));
}
let annotation = self.parse_type_annotation()?;
Ok(self.alloc_type_pack(
annotation.location,
TypePackKind::Variadic {
variadic_type: annotation,
},
))
}
}