@@ -154,8 +154,11 @@ tok_continuation_line(struct tok_state *tok) {
154154
155155
156156int
157- _PyLexer_get_normal_mode (struct tok_state * tok , tokenizer_mode * current_tok , struct token * token )
157+ _PyLexer_get_normal (struct tok_state * tok , ftstring_state * current , struct token * token )
158158{
159+ assert (current == NULL ||
160+ (current -> mode == FTSTRING_MODE_EXPRESSION &&
161+ current -> replacement_depth > 0 ));
159162 int c ;
160163 int blankline , nonascii ;
161164
@@ -317,13 +320,13 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
317320 c = tok_nextc (tok );
318321 }
319322
320- if (INSIDE_FSTRING ( tok ) && INSIDE_FSTRING_EXPR ( current_tok ) ) {
323+ if (current != NULL ) {
321324 const char * comment_end = tok -> cur ;
322325 if (c == '\n' || c == '\r' ) {
323326 comment_end -- ;
324327 }
325328 if (_PyLexer_record_ftstring_comment (
326- tok , tok -> start , comment_end ) < 0 ) {
329+ tok , current , tok -> start , comment_end ) < 0 ) {
327330 tok -> done = E_NOMEM ;
328331 return MAKE_TOKEN (ERRORTOKEN );
329332 }
@@ -547,34 +550,25 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
547550 }
548551
549552 /* Punctuation character */
550- int is_punctuation = (c == ':' || c == '}' || c == '!' || c == '{' );
551- if (is_punctuation && INSIDE_FSTRING (tok ) && INSIDE_FSTRING_EXPR (current_tok )) {
552- /* This code block gets executed before the curly_bracket_depth is incremented
553- * by the `{` case, so for ensuring that we are on the 0th level, we need
554- * to adjust it manually */
555- int cursor = current_tok -> curly_bracket_depth - (c != '{' );
556- int in_format_spec = current_tok -> in_format_spec ;
557- int cursor_in_format_with_debug =
558- cursor == 1 && (current_tok -> in_debug || in_format_spec );
559- int cursor_valid = cursor == 0 || cursor_in_format_with_debug ;
560- if (cursor_valid && c == '!' ) {
553+ int is_punctuation = (c == ':' || c == '}' || c == '!' );
554+ if (is_punctuation && current != NULL ) {
555+ int bracket_depth = _PyLexer_FTStringBracketDepth (tok , current );
556+ int at_expression_boundary =
557+ bracket_depth == current -> replacement_depth ;
558+ if (at_expression_boundary && c == '!' ) {
561559 int c2 = tok_nextc (tok );
562560 if (c2 == '=' ) {
563- cursor_valid = 0 ;
561+ at_expression_boundary = 0 ;
564562 }
565563 tok_backup (tok , c2 );
566564 }
567- if (cursor_valid ) {
568- _PyLexer_update_ftstring_expr (tok , c );
569- }
570- if (cursor_valid && c != '{' &&
571- _PyLexer_set_ftstring_expr_metadata (tok , token )) {
565+ if (at_expression_boundary &&
566+ _PyLexer_finish_ftstring_expr (tok , current , token )) {
572567 return MAKE_TOKEN (ERRORTOKEN );
573568 }
574569
575- if (c == ':' && cursor == current_tok -> curly_bracket_expr_start_depth ) {
576- current_tok -> kind = TOK_FSTRING_MODE ;
577- current_tok -> in_format_spec = 1 ;
570+ if (c == ':' && at_expression_boundary ) {
571+ current -> mode = FTSTRING_MODE_FORMAT_SPEC ;
578572 p_start = tok -> start ;
579573 p_end = tok -> cur ;
580574 return MAKE_TOKEN (_PyToken_OneChar (c ));
@@ -613,16 +607,20 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
613607 tok -> parenlinenostack [tok -> level ] = tok -> lineno ;
614608 tok -> parencolstack [tok -> level ] = (int )(tok -> start - tok -> line_start );
615609 tok -> level ++ ;
616- if (INSIDE_FSTRING (tok )) {
617- current_tok -> curly_bracket_depth ++ ;
618- }
619610 break ;
620611 case ')' :
621612 case ']' :
622613 case '}' :
623- if (INSIDE_FSTRING (tok ) && !current_tok -> curly_bracket_depth && c == '}' ) {
624- return MAKE_TOKEN (_PyTokenizer_syntaxerror (tok ,
625- "%c-string: single '}' is not allowed" , TOK_GET_STRING_PREFIX (tok )));
614+ if (current != NULL &&
615+ _PyLexer_FTStringBracketDepth (tok , current ) == 0 ) {
616+ if (c == '}' ) {
617+ return MAKE_TOKEN (_PyTokenizer_syntaxerror (tok ,
618+ "%c-string: single '}' is not allowed" ,
619+ _PyLexer_StringPrefix (current -> kind )));
620+ }
621+ return MAKE_TOKEN (_PyTokenizer_syntaxerror (
622+ tok , "%c-string: unmatched '%c'" ,
623+ _PyLexer_StringPrefix (current -> kind ), c ));
626624 }
627625 if (!tok -> tok_extra_tokens && !tok -> level ) {
628626 return MAKE_TOKEN (_PyTokenizer_syntaxerror (tok , "unmatched '%c'" , c ));
@@ -633,17 +631,15 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
633631 if (!tok -> tok_extra_tokens && !((opening == '(' && c == ')' ) ||
634632 (opening == '[' && c == ']' ) ||
635633 (opening == '{' && c == '}' ))) {
636- /* If the opening bracket belongs to an f-string's expression
637- part (e.g. f"{)}") and the closing bracket is an arbitrary
638- nested expression, then instead of matching a different
639- syntactical construct with it; we'll throw an unmatched
640- parentheses error. */
641- if (INSIDE_FSTRING (tok ) && opening == '{' ) {
642- assert (current_tok -> curly_bracket_depth >= 0 );
643- int previous_bracket = current_tok -> curly_bracket_depth - 1 ;
644- if (previous_bracket == current_tok -> curly_bracket_expr_start_depth ) {
634+ /* Do not match a closer against the brace that opened the
635+ * current replacement field. */
636+ if (current != NULL && opening == '{' ) {
637+ int bracket_depth =
638+ _PyLexer_FTStringBracketDepth (tok , current );
639+ if (bracket_depth == current -> replacement_depth - 1 ) {
645640 return MAKE_TOKEN (_PyTokenizer_syntaxerror (tok ,
646- "%c-string: unmatched '%c'" , TOK_GET_STRING_PREFIX (tok ), c ));
641+ "%c-string: unmatched '%c'" ,
642+ _PyLexer_StringPrefix (current -> kind ), c ));
647643 }
648644 }
649645 if (tok -> parenlinenostack [tok -> level ] != tok -> lineno ) {
@@ -661,17 +657,16 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
661657 }
662658 }
663659
664- if (INSIDE_FSTRING ( tok ) ) {
665- current_tok -> curly_bracket_depth -- ;
666- if (current_tok -> curly_bracket_depth < 0 ) {
660+ if (current != NULL ) {
661+ int bracket_depth = _PyLexer_FTStringBracketDepth ( tok , current ) ;
662+ if (bracket_depth < 0 ) {
667663 return MAKE_TOKEN (_PyTokenizer_syntaxerror (tok , "%c-string: unmatched '%c'" ,
668- TOK_GET_STRING_PREFIX ( tok ), c ));
664+ _PyLexer_StringPrefix ( current -> kind ), c ));
669665 }
670- if (c == '}' && current_tok -> curly_bracket_depth == current_tok -> curly_bracket_expr_start_depth ) {
671- current_tok -> curly_bracket_expr_start_depth -- ;
672- current_tok -> kind = TOK_FSTRING_MODE ;
673- current_tok -> in_format_spec = 0 ;
674- current_tok -> in_debug = 0 ;
666+ if (c == '}' && bracket_depth == current -> replacement_depth - 1 ) {
667+ current -> replacement_depth -- ;
668+ current -> mode = FTSTRING_MODE_MIDDLE ;
669+ current -> debug_expr = 0 ;
675670 }
676671 }
677672 break ;
@@ -683,8 +678,9 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
683678 return MAKE_TOKEN (_PyTokenizer_syntaxerror (tok , "invalid non-printable character U+%04X" , c ));
684679 }
685680
686- if ( c == '=' && INSIDE_FSTRING_EXPR_AT_TOP (current_tok )) {
687- current_tok -> in_debug = 1 ;
681+ if (c == '=' && current != NULL &&
682+ _PyLexer_FTStringBracketDepth (tok , current ) == current -> replacement_depth ) {
683+ current -> debug_expr = 1 ;
688684 }
689685
690686 /* Punctuation character */
@@ -694,21 +690,13 @@ _PyLexer_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, str
694690}
695691
696692
697- static int
698- tok_get (struct tok_state * tok , struct token * token )
699- {
700- tokenizer_mode * current_tok = TOK_GET_MODE (tok );
701- if (current_tok -> kind == TOK_REGULAR_MODE ) {
702- return _PyLexer_get_normal_mode (tok , current_tok , token );
703- } else {
704- return _PyLexer_get_fstring_mode (tok , current_tok , token );
705- }
706- }
707-
708693int
709694_PyTokenizer_Get (struct tok_state * tok , struct token * token )
710695{
711- int result = tok_get (tok , token );
696+ ftstring_state * current = _PyLexer_CurrentFTString (tok );
697+ int result = current == NULL || current -> mode == FTSTRING_MODE_EXPRESSION
698+ ? _PyLexer_get_normal (tok , current , token )
699+ : _PyLexer_get_ftstring (tok , current , token );
712700 if (tok_failed (tok )) {
713701 result = ERRORTOKEN ;
714702 }
0 commit comments