use super::*;
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn parse_call_arguments(
&mut self,
explicit_types: Option<CstTypeInstantiation>,
callee_line: usize,
) -> Result<ParsedCallArguments<'ast>> {
let parsed = self.parse_call_list(callee_line)?;
Ok(ParsedCallArguments {
arguments: parsed.arguments,
location: parsed.location,
end: parsed.end,
cst: self.cst.enabled().then_some(CstExprCall {
explicit_types,
..parsed.cst
}),
})
}
pub(in crate::parser) fn parse_call_list(
&mut self,
callee_line: usize,
) -> Result<ParsedCallList<'ast>> {
match self.current {
Token::LeftParen => {
if self.current_line() > callee_line {
self.report_ambiguous_call_error();
}
let open_parens = self.current_position();
let arg_start = self.current_token_location().end;
self.advance();
let (arguments, comma_positions) = self.parse_arguments()?;
let arg_end = self.current_token_location().end;
let end = self.current_token_location().end;
let closing_parens_found = self.expect_match_token(
Token::RightParen,
")",
"(",
Location::new(open_parens, open_parens),
false,
);
let close_parens =
closing_parens_found.then(|| self.previous_token_location().begin);
Ok(ParsedCallList {
arguments,
location: Location::new(arg_start, arg_end),
end,
cst: CstExprCall {
open_parens: Some(open_parens),
close_parens,
comma_positions,
explicit_types: None,
},
})
}
Token::QuotedString { value, quote_style } => {
let ast_quote_style = StringQuoteStyle::from(quote_style);
let location = self.current_token_location();
let cst = self.cst_node(|| {
CstNode::ExprConstantString(CstExprConstantString {
source_string: self.current_source_string(),
quote_style: CstStringQuoteStyle::from(quote_style),
block_depth: 0,
})
});
self.advance();
let value = self.parse_quoted_string(value, location, ast_quote_style);
let value = self.attach_expression_cst(value, cst);
Ok(ParsedCallList {
arguments: self.arena.alloc_slice_copy(&[value]),
location,
end: location.end,
cst: CstExprCall {
open_parens: None,
close_parens: None,
comma_positions: Vec::new(),
explicit_types: None,
},
})
}
Token::RawString { value, block_depth } => {
let location = self.current_token_location();
let cst = self.cst_node(|| {
CstNode::ExprConstantString(CstExprConstantString {
source_string: self.current_source_string(),
quote_style: CstStringQuoteStyle::QuotedRaw,
block_depth: block_depth as u32,
})
});
self.advance();
let value = self.arena.alloc_expression_string_direct(
location,
self.ast_string(&multiline_string_bytes(value)),
StringQuoteStyle::QuotedRaw,
);
let value = self.attach_expression_cst(value, cst);
Ok(ParsedCallList {
arguments: self.arena.alloc_slice_copy(&[value]),
location,
end: location.end,
cst: CstExprCall {
open_parens: None,
close_parens: None,
comma_positions: Vec::new(),
explicit_types: None,
},
})
}
Token::LeftBrace => {
let location = self.current_location();
self.advance();
let table = self.parse_table_constructor(location)?;
let end = table.location.end;
Ok(ParsedCallList {
arguments: self.arena.alloc_slice_copy(&[table]),
location: Location::new(location.end, end),
end,
cst: CstExprCall {
open_parens: None,
close_parens: None,
comma_positions: Vec::new(),
explicit_types: None,
},
})
}
_ => Err(self.unexpected("(")),
}
}
pub(in crate::parser) fn parse_arguments(
&mut self,
) -> Result<(&'ast [Expression<'ast>], Vec<Position>)> {
let mut args = self.temp_expressions();
let mut comma_positions = self.temp_positions();
if self.current.kind() == TokenKind::RightParen {
return Ok((self.empty_expression_slice(), Vec::new()));
}
self.parse_expression_list_into(&mut args, &mut comma_positions)?;
Ok((
self.arena.alloc_slice_copy(args.as_slice()),
comma_positions.as_slice().to_vec(),
))
}
pub(in crate::parser) fn parse_primary_expression_statement(
&mut self,
) -> Result<Expression<'ast>> {
self.parse_primary_expression(true)
}
pub(in crate::parser) fn parse_primary_expression_after_prefix(
&mut self,
mut expression: Expression<'ast>,
mut expression_line: usize,
as_statement: bool,
) -> Result<Expression<'ast>> {
let old_recursion_counter = self.contexts.recursion_counter;
loop {
let double_less =
self.current.kind() == TokenKind::Less && self.peek().kind() == TokenKind::Less;
match self.current {
Token::LeftParen if expression.accepts_call() => {
if !as_statement && self.current_line() > expression_line {
self.report_ambiguous_call_error();
self.contexts.recursion_counter = old_recursion_counter;
return Ok(expression);
}
let begin = expression.location().begin;
let ParsedCallArguments {
arguments,
location,
end,
cst,
} = self.parse_call_arguments(None, expression_line)?;
expression = self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(begin, end),
ExpressionKind::Call {
func: expression,
type_args: self.arena.alloc_slice_copy(&[]),
args: self.arena.alloc_slice_copy(arguments),
self_call: false,
arg_location: location,
},
),
cst.map(CstNode::ExprCall),
);
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
Token::QuotedString { .. } | Token::RawString { .. } | Token::LeftBrace
if expression.accepts_call() =>
{
let begin = expression.location().begin;
let ParsedCallArguments {
arguments,
location,
end,
cst,
} = self.parse_call_arguments(None, expression_line)?;
expression = self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(begin, end),
ExpressionKind::Call {
func: expression,
type_args: self.arena.alloc_slice_copy(&[]),
args: self.arena.alloc_slice_copy(arguments),
self_call: false,
arg_location: location,
},
),
cst.map(CstNode::ExprCall),
);
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
Token::Less if double_less => {
let begin = expression.location().begin;
let instantiation = self.parse_explicit_type_instantiation()?;
let args = self.arena.alloc_slice_copy(&instantiation.arguments);
expression = self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(begin, instantiation.end_location.end),
ExpressionKind::Instantiate {
expr: expression,
type_args: args,
},
),
instantiation.cst.map(|instantiation| {
CstNode::ExprExplicitTypeInstantiation(
CstExprExplicitTypeInstantiation { instantiation },
)
}),
);
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
Token::LeftBracket => {
let begin = expression.location().begin;
let open_bracket = self.current_position();
self.advance();
let index = self.parse_expression()?;
let close_bracket = self.current_position();
let end = self.current_token_location().end;
let closing_bracket_found = self.expect_match_token(
Token::RightBracket,
"]",
"[",
Location::new(open_bracket, open_bracket),
false,
);
expression = self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(begin, end),
ExpressionKind::IndexExpr {
expr: expression,
index,
},
),
self.cst_node(|| {
CstNode::ExprIndexExpr(CstExprIndexExpr {
open_bracket,
close_bracket: if closing_bracket_found {
close_bracket
} else {
Position::missing()
},
})
}),
);
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
Token::Dot => {
let begin = expression.location().begin;
let op_position = self.current_position();
self.advance();
let field = self.parse_index_name(None, op_position)?;
let field_name = field.name;
expression = self.alloc_expression(ExpressionInit::new(
Location::new(begin, field.location.end),
ExpressionKind::IndexName {
expr: expression,
index: field_name,
index_location: field.location,
op_position,
op: IndexNameOp::Dot,
},
));
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
Token::Colon => {
let op = self.current_position();
self.advance();
let callee_begin = expression.location().begin;
let method = self.parse_index_name(Some("method name"), op)?;
let method_line = method.location.begin.line as usize + 1;
let (explicit_type_arguments, explicit_types) = if self.current.kind()
== TokenKind::Less
&& self.peek().kind() == TokenKind::Less
{
let instantiation = self.parse_explicit_type_instantiation()?;
(instantiation.arguments, instantiation.cst)
} else {
(
Vec::new(),
self.cst.enabled().then(CstTypeInstantiation::default),
)
};
if !matches!(
self.current,
Token::LeftParen
| Token::QuotedString { .. }
| Token::RawString { .. }
| Token::LeftBrace
) {
let method_name = method.name;
let indexed = self.alloc_expression(ExpressionInit::new(
Location::new(callee_begin, method.location.end),
ExpressionKind::IndexName {
expr: expression,
index: method_name,
index_location: method.location,
op_position: op,
op: IndexNameOp::Colon,
},
));
let error = self.method_call_arguments_error(
indexed.location,
indexed.location.end.line as usize + 1,
);
let error_location = error.location;
let message_index = self.report_parse_error(error);
expression = self.alloc_expression(ExpressionInit::new(
error_location,
ExpressionKind::Error {
expressions: self.arena.alloc_slice_fill_iter([indexed]),
message_index,
},
));
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
continue;
}
let ParsedCallArguments {
arguments,
location,
end,
cst,
} = self.parse_call_arguments(explicit_types, method_line)?;
let method_name = method.name;
let func = self.alloc_expression(ExpressionInit::new(
Location::new(callee_begin, method.location.end),
ExpressionKind::IndexName {
expr: expression,
index: method_name,
index_location: method.location,
op_position: op,
op: IndexNameOp::Colon,
},
));
expression = self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(callee_begin, end),
ExpressionKind::Call {
func,
type_args: self
.arena
.alloc_slice_fill_iter(explicit_type_arguments),
args: self.arena.alloc_slice_copy(arguments),
self_call: true,
arg_location: location,
},
),
cst.map(CstNode::ExprCall),
);
expression_line = expression.location().end.line as usize + 1;
if let Err(error) = self.enter_recursion("expression") {
self.contexts.recursion_counter = old_recursion_counter;
return Err(error);
}
}
_ => {
self.contexts.recursion_counter = old_recursion_counter;
return Ok(expression);
}
}
}
}
pub(in crate::parser) fn report_ambiguous_call_error(&mut self) {
self.report_parse_error(self.located("Ambiguous syntax: this looks like an argument list for a function call, but could also be a start of new statement; use ';' to separate statements"));
}
}