use super::*;
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn parse_interpolated_string(
&mut self,
first: &'source [u8],
) -> Result<Expression<'ast>> {
let start_location = self.current_token_location();
let mut end_location = start_location;
let mut recovery_error = None;
let mut strings = self.temp_strings();
let mut args = self.temp_expressions();
let mut interp_cst = self
.cst
.enabled()
.then(|| (self.temp_source_strings(), self.temp_positions()));
if let Some((source_strings, string_positions)) = &mut interp_cst {
source_strings.push_back(self.current_source_string());
string_positions.push_back(self.current_position());
}
let first_string = match self.parse_interpolated_literal(first) {
Ok(value) => value,
Err(error) => {
self.advance();
let message_index = self.report_parse_error(ParseError::new(
Location::new(start_location.begin, end_location.end),
error.message,
));
return Ok(self.alloc_expression(ExpressionInit::new(
Location::new(start_location.begin, end_location.end),
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)));
}
};
strings.push_back(first_string);
self.advance();
loop {
if matches!(
self.current,
Token::InterpStringMid(_) | Token::InterpStringEnd(_)
) {
let message_index =
self.report_parse_error(self.interpolated_missing_expression_error());
self.advance();
let expressions = self.empty_expression_slice();
args.push_back(self.alloc_expression(ExpressionInit::new(
end_location,
ExpressionKind::Error {
expressions,
message_index,
},
)));
break;
}
if matches!(self.current, Token::BrokenString) {
self.advance();
let message_index = self.report_parse_error(self.error_at(
end_location,
"Malformed interpolated string; did you forget to add a '`'?",
));
let expressions = self.empty_expression_slice();
args.push_back(self.alloc_expression(ExpressionInit::new(
end_location,
ExpressionKind::Error {
expressions,
message_index,
},
)));
break;
}
let expression = self.parse_expression()?;
args.push_back(expression);
match self.current {
Token::InterpStringMid(value) => {
let location = self.current_token_location();
end_location = location;
if let Some((source_strings, string_positions)) = &mut interp_cst {
source_strings.push_back(self.current_source_string());
string_positions.push_back(self.current_position());
}
let string = match self.parse_interpolated_literal(value) {
Ok(value) => value,
Err(error) => {
self.advance();
let location = Location::new(start_location.begin, end_location.end);
let message_index =
self.report_parse_error(ParseError::new(location, error.message));
return Ok(self.alloc_expression(ExpressionInit::new(
location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)));
}
};
strings.push_back(string);
self.advance();
}
Token::InterpStringEnd(value) => {
let location = self.current_token_location();
end_location = location;
if let Some((source_strings, string_positions)) = &mut interp_cst {
source_strings.push_back(self.current_source_string());
string_positions.push_back(self.current_position());
}
let string = match self.parse_interpolated_literal(value) {
Ok(value) => value,
Err(error) => {
self.advance();
let location = Location::new(start_location.begin, end_location.end);
let message_index =
self.report_parse_error(ParseError::new(location, error.message));
return Ok(self.alloc_expression(ExpressionInit::new(
location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)));
}
};
strings.push_back(string);
self.advance();
break;
}
Token::BrokenInterpDoubleBrace(_) => {
self.advance();
let message_index = self.report_parse_error(self.error_at(
end_location,
"Double braces are not permitted within interpolated strings; did you mean '\\{'?"
,
));
return Ok(self.alloc_expression(ExpressionInit::new(
end_location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)));
}
Token::BrokenString => {
self.advance();
recovery_error = Some(if self.lexer.interpolation_brace_is_open() {
"Malformed interpolated string; did you forget to add a '}'?"
} else {
"Malformed interpolated string; did you forget to add a '`'?"
});
break;
}
Token::Eof => {
recovery_error = Some(if self.lexer.interpolation_brace_is_open() {
"Malformed interpolated string; did you forget to add a '}'?"
} else {
"Malformed interpolated string; did you forget to add a '`'?"
});
break;
}
_ => {
let message_index = self.report_parse_error(self.error_at(
end_location,
format!("Malformed interpolated string, got {}", self.current),
));
return Ok(self.alloc_expression(ExpressionInit::new(
end_location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)));
}
}
}
let end = if recovery_error.is_some() {
self.previous_token_location().end
} else {
end_location.end
};
let location = Location::new(start_location.begin, end);
let expression = self.alloc_expression_with_cst(
ExpressionInit::new(
location,
ExpressionKind::InterpString {
strings: self.arena.alloc_slice_copy(strings.as_slice()),
expressions: self.arena.alloc_slice_copy(args.as_slice()),
},
),
interp_cst.map(|(source_strings, string_positions)| {
CstNode::ExprInterpString(CstExprInterpString {
source_strings: source_strings.as_slice().to_vec(),
string_positions: string_positions.as_slice().to_vec(),
})
}),
);
if let Some(message) = recovery_error {
self.report_parse_error(self.error_at(self.previous_token_location(), message));
}
Ok(expression)
}
pub(in crate::parser) fn parse_quoted_string(
&mut self,
value: &[u8],
location: Location,
quote_style: StringQuoteStyle,
) -> Expression<'ast> {
let Some(value) = fixup_string_bytes(value) else {
let message_index = self.report_parse_error(self.error_at(
location,
"String literal contains malformed escape sequence",
));
return self.arena.alloc_expression_error_direct(
location,
self.empty_expression_slice(),
message_index,
);
};
self.arena
.alloc_expression_string_direct(location, self.ast_string(&value), quote_style)
}
}