|
7 | 7 |
|
8 | 8 | #define MAKE_TOKEN(token_type) _PyLexer_token_setup(tok, token, token_type, p_start, p_end) |
9 | 9 |
|
10 | | -static void |
11 | | -rewind_to_string_start(struct tok_state *tok, const char *start, |
12 | | - _PyTok_Loc location) |
| 10 | +static int |
| 11 | +string_error_token(struct tok_state *tok, struct token *token, |
| 12 | + const char *start, _PyTok_Loc location) |
13 | 13 | { |
14 | | - tok->cur = (char *)start + 1; |
15 | | - tok->line_start = start - location.byte_col; |
16 | | - tok->lineno = location.lineno; |
| 14 | + tok->diagnostic = (_PyTokenizer_Diagnostic){ |
| 15 | + .location = {location.lineno, location.byte_col + 1}, |
| 16 | + .text_span = _PyLexer_BufferSpan(tok, start - location.byte_col, tok->inp), |
| 17 | + }; |
| 18 | + int type = _PyLexer_token_setup(tok, token, ERRORTOKEN, NULL, NULL); |
| 19 | + token->start_loc = location; |
| 20 | + token->end_loc = (_PyTok_Loc){location.lineno, -1}; |
| 21 | + return type; |
17 | 22 | } |
18 | 23 |
|
19 | 24 | int |
@@ -351,44 +356,51 @@ _PyLexer_scan_string(struct tok_state *tok, struct token *token, int c) |
351 | 356 | } |
352 | 357 | if (c == EOF || (quote_size == 1 && c == '\n')) { |
353 | 358 | int end_lineno = tok->lineno; |
354 | | - rewind_to_string_start(tok, tok->start, tok->start_loc); |
| 359 | + _PyTok_Loc location = tok->start_loc; |
| 360 | + const char *line = tok->start - location.byte_col; |
| 361 | + Py_ssize_t cursor_offset = (Py_ssize_t)location.byte_col + 1; |
355 | 362 |
|
356 | 363 | const ftstring_state *state = _PyLexer_CurrentFTString(tok); |
357 | 364 | if (state != NULL) { |
358 | 365 | /* A matching quote belongs to the surrounding formatted |
359 | 366 | * string, so the expression is missing its closing brace. */ |
360 | 367 | if (state->quote == quote && state->quote_size == quote_size) { |
361 | | - return MAKE_TOKEN(_PyTokenizer_syntaxerror(tok, |
| 368 | + _PyTokenizer_syntaxerror_at( |
| 369 | + tok, line, cursor_offset, location.lineno, -1, -1, |
362 | 370 | "%c-string: expecting '}'", |
363 | | - _PyLexer_StringPrefix(state->kind))); |
| 371 | + _PyLexer_StringPrefix(state->kind)); |
| 372 | + return string_error_token(tok, token, tok->start, location); |
364 | 373 | } |
365 | 374 | } |
366 | 375 |
|
367 | 376 | if (quote_size == 3) { |
368 | | - _PyTokenizer_syntaxerror(tok, "unterminated triple-quoted string literal" |
369 | | - " (detected at line %d)", end_lineno); |
| 377 | + _PyTokenizer_syntaxerror_at( |
| 378 | + tok, line, cursor_offset, location.lineno, -1, -1, |
| 379 | + "unterminated triple-quoted string literal" |
| 380 | + " (detected at line %d)", end_lineno); |
370 | 381 | if (c != '\n') { |
371 | 382 | tok->done = E_EOFS; |
372 | 383 | } |
373 | | - return MAKE_TOKEN(ERRORTOKEN); |
| 384 | + return string_error_token(tok, token, tok->start, location); |
374 | 385 | } |
375 | 386 | else { |
376 | 387 | if (has_escaped_quote) { |
377 | | - _PyTokenizer_syntaxerror( |
378 | | - tok, |
| 388 | + _PyTokenizer_syntaxerror_at( |
| 389 | + tok, line, cursor_offset, location.lineno, -1, -1, |
379 | 390 | "unterminated string literal (detected at line %d); " |
380 | 391 | "perhaps you escaped the end quote?", |
381 | 392 | end_lineno |
382 | 393 | ); |
383 | 394 | } else { |
384 | | - _PyTokenizer_syntaxerror( |
385 | | - tok, "unterminated string literal (detected at line %d)", end_lineno |
| 395 | + _PyTokenizer_syntaxerror_at( |
| 396 | + tok, line, cursor_offset, location.lineno, -1, -1, |
| 397 | + "unterminated string literal (detected at line %d)", end_lineno |
386 | 398 | ); |
387 | 399 | } |
388 | 400 | if (c != '\n') { |
389 | 401 | tok->done = E_EOLS; |
390 | 402 | } |
391 | | - return MAKE_TOKEN(ERRORTOKEN); |
| 403 | + return string_error_token(tok, token, tok->start, location); |
392 | 404 | } |
393 | 405 | } |
394 | 406 | if (c == quote) { |
@@ -451,25 +463,29 @@ _PyLexer_get_ftstring(struct tok_state *tok, ftstring_state *current, struct tok |
451 | 463 | } |
452 | 464 |
|
453 | 465 | int end_lineno = tok->lineno; |
454 | | - rewind_to_string_start(tok, |
455 | | - _PyLexer_BufferPointer(tok, current->start), |
456 | | - current->start_loc); |
| 466 | + _PyTok_Loc location = current->start_loc; |
| 467 | + const char *line = _PyLexer_BufferPointer(tok, current->start) - location.byte_col; |
| 468 | + Py_ssize_t cursor_offset = (Py_ssize_t)location.byte_col + 1; |
457 | 469 |
|
458 | 470 | if (quote_size == 3) { |
459 | | - _PyTokenizer_syntaxerror(tok, |
460 | | - "unterminated triple-quoted %c-string literal" |
461 | | - " (detected at line %d)", |
462 | | - _PyLexer_StringPrefix(current->kind), end_lineno); |
| 471 | + _PyTokenizer_syntaxerror_at( |
| 472 | + tok, line, cursor_offset, location.lineno, -1, -1, |
| 473 | + "unterminated triple-quoted %c-string literal" |
| 474 | + " (detected at line %d)", |
| 475 | + _PyLexer_StringPrefix(current->kind), end_lineno); |
463 | 476 | if (c != '\n') { |
464 | 477 | tok->done = E_EOFS; |
465 | 478 | } |
466 | | - return MAKE_TOKEN(ERRORTOKEN); |
| 479 | + return string_error_token(tok, token, |
| 480 | + _PyLexer_BufferPointer(tok, current->start), location); |
467 | 481 | } |
468 | 482 | else { |
469 | | - return MAKE_TOKEN(_PyTokenizer_syntaxerror(tok, |
470 | | - "unterminated %c-string literal (detected at" |
471 | | - " line %d)", |
472 | | - _PyLexer_StringPrefix(current->kind), end_lineno)); |
| 483 | + _PyTokenizer_syntaxerror_at( |
| 484 | + tok, line, cursor_offset, location.lineno, -1, -1, |
| 485 | + "unterminated %c-string literal (detected at line %d)", |
| 486 | + _PyLexer_StringPrefix(current->kind), end_lineno); |
| 487 | + return string_error_token(tok, token, |
| 488 | + _PyLexer_BufferPointer(tok, current->start), location); |
473 | 489 | } |
474 | 490 | } |
475 | 491 |
|
|
0 commit comments