| 220 | } |
| 221 | |
| 222 | fn interpolation<'a, I>() -> impl Parser<'a, I, ExprKind, ParserError<'a>> + Clone |
| 223 | where |
| 224 | I: Input<'a, Token = lr::Token, Span = Span> + BorrowInput<'a>, |
| 225 | { |
| 226 | select_ref! { |
| 227 | lr::Token { kind: TokenKind::Interpolation('s', string), .. } => (ExprKind::SString as fn(_) -> _, string.clone()), |
| 228 | lr::Token { kind: TokenKind::Interpolation('f', string), .. } => (ExprKind::FString as fn(_) -> _, string.clone()), |
| 229 | } |
| 230 | .validate(|(finish, string), extra, emit| { |
| 231 | let span = extra.span(); |
| 232 | match interpolation::parse(string, span + 2) { |
| 233 | Ok(items) => finish(items), |
| 234 | Err(errors) => { |
| 235 | for err in errors { |
| 236 | // Convert Error to Rich for emission |
| 237 | let err_span = err.span.unwrap_or(span); |
| 238 | // Use the reason's Display impl, not Error's Debug |
| 239 | let message = err.reason.to_string(); |
| 240 | emit.emit(Rich::custom(err_span, message)); |
| 241 | } |
| 242 | finish(vec![]) |
| 243 | } |
| 244 | } |
| 245 | }) |
| 246 | .labelled("interpolated string") |
| 247 | } |
| 248 | |
| 249 | fn case<'a, I>( |
| 250 | expr: impl Parser<'a, I, Expr, ParserError<'a>> + Clone + 'a, |