Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Parse the string as f-string
  • Loading branch information
gvanrossum committed May 3, 2022
commit 73f3c34429e6d5838d8c61081768942407bb32fe
4 changes: 2 additions & 2 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ slice[expr_ty]:
| a=named_expression { a }

atom[expr_ty]:
| a=NAME b=STRING { _PyPegen_tag_string(p, a, b) }
| a=NAME b=STRING { _PyPegen_tag_string(p, a, (Token *)b) }
| NAME
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
Expand Down Expand Up @@ -871,7 +871,7 @@ lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) }
# LITERALS
# ========

strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) }
strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a, 0) }

list[expr_ty]:
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
Expand Down
18 changes: 11 additions & 7 deletions Parser/action_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,14 +870,18 @@ _PyPegen_seq_delete_starred_exprs(Parser *p, asdl_seq *kwargs)
}

expr_ty
_PyPegen_tag_string(Parser *p, expr_ty tag, Token *t)
_PyPegen_tag_string(Parser *p, expr_ty tag, Token *tok)
{
// No prefixes (f, r, b, u)
// Parse like fstring
// Create a node similar to f-string AST
expr_ty str = _PyAST_Constant(t->bytes, NULL, t->lineno,
t->col_offset, t->end_lineno,
t->end_col_offset, p->arena);
asdl_generic_seq *tokens = _Py_asdl_generic_seq_new(1, p->arena);
if (tokens == NULL)
return NULL;
asdl_seq_SET(tokens, 0, tok);
expr_ty str = _PyPegen_concatenate_strings(p, (asdl_seq *)tokens, 1);
if (str == NULL)
return NULL;
return _PyAST_TagString(tag, str,
tag->lineno, tag->col_offset, str->end_lineno, str->end_col_offset,
p->arena);
Expand All @@ -886,7 +890,7 @@ _PyPegen_tag_string(Parser *p, expr_ty tag, Token *t)


expr_ty
_PyPegen_concatenate_strings(Parser *p, asdl_seq *strings)
_PyPegen_concatenate_strings(Parser *p, asdl_seq *strings, int tagged)
{
Py_ssize_t len = asdl_seq_LEN(strings);
assert(len > 0);
Expand All @@ -898,7 +902,7 @@ _PyPegen_concatenate_strings(Parser *p, asdl_seq *strings)
PyObject *bytes_str = NULL;

FstringParser state;
_PyPegen_FstringParser_Init(&state);
_PyPegen_FstringParser_Init(&state, tagged);

for (Py_ssize_t i = 0; i < len; i++) {
Token *t = asdl_seq_GET_UNTYPED(strings, i);
Expand All @@ -909,7 +913,7 @@ _PyPegen_concatenate_strings(Parser *p, asdl_seq *strings)
const char *fstr;
Py_ssize_t fstrlen = -1;

if (_PyPegen_parsestr(p, &this_bytesmode, &this_rawmode, &s, &fstr, &fstrlen, t) != 0) {
if (_PyPegen_parsestr(p, &this_bytesmode, &this_rawmode, &s, &fstr, &fstrlen, t, tagged) != 0) {
goto error;
}

Expand Down
4 changes: 2 additions & 2 deletions Parser/parser.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Parser/pegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ asdl_keyword_seq *_PyPegen_seq_delete_starred_exprs(Parser *, asdl_seq *);
expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_expr_seq *, asdl_seq *,
int lineno, int col_offset, int end_lineno,
int end_col_offset, PyArena *arena);
expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_seq *);
expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_seq *, int);
expr_ty _PyPegen_tag_string(Parser *p, expr_ty, Token *);
expr_ty _PyPegen_ensure_imaginary(Parser *p, expr_ty);
expr_ty _PyPegen_ensure_real(Parser *p, expr_ty);
Expand Down
16 changes: 10 additions & 6 deletions Parser/string_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
string object. Return 0 if no errors occurred. */
int
_PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
const char **fstr, Py_ssize_t *fstrlen, Token *t)
const char **fstr, Py_ssize_t *fstrlen, Token *t, int tagged)
{
const char *s = PyBytes_AsString(t->bytes);
if (s == NULL) {
Expand All @@ -175,12 +175,16 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,

size_t len;
int quote = Py_CHARMASK(*s);
int fmode = 0;
int fmode = tagged;
*bytesmode = 0;
*rawmode = 0;
*rawmode = tagged;
*result = NULL;
*fstr = NULL;
if (Py_ISALPHA(quote)) {
if (tagged) {
RAISE_SYNTAX_ERROR("Cannot combine tag and letter prefix");
return -1;
}
while (!*bytesmode || !*rawmode) {
if (quote == 'b' || quote == 'B') {
quote =(unsigned char)*++s;
Expand Down Expand Up @@ -1030,10 +1034,10 @@ FstringParser_check_invariants(FstringParser *state)
#endif

void
_PyPegen_FstringParser_Init(FstringParser *state)
_PyPegen_FstringParser_Init(FstringParser *state, int fmode)
{
state->last_str = NULL;
state->fmode = 0;
state->fmode = fmode;
ExprList_Init(&state->expr_list);
FstringParser_check_invariants(state);
}
Expand Down Expand Up @@ -1245,7 +1249,7 @@ fstring_parse(Parser *p, const char **str, const char *end, int raw,
{
FstringParser state;

_PyPegen_FstringParser_Init(&state);
_PyPegen_FstringParser_Init(&state, 0);
if (_PyPegen_FstringParser_ConcatFstring(p, &state, str, end, raw, recurse_lvl,
first_token, t, last_token) < 0) {
_PyPegen_FstringParser_Dealloc(&state);
Expand Down
4 changes: 2 additions & 2 deletions Parser/string_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ typedef struct {
int fmode;
} FstringParser;

void _PyPegen_FstringParser_Init(FstringParser *);
void _PyPegen_FstringParser_Init(FstringParser *, int);
int _PyPegen_parsestr(Parser *, int *, int *, PyObject **,
const char **, Py_ssize_t *, Token *);
const char **, Py_ssize_t *, Token *, int);
int _PyPegen_FstringParser_ConcatFstring(Parser *, FstringParser *, const char **,
const char *, int, int, Token *, Token *,
Token *);
Expand Down
32 changes: 14 additions & 18 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -4915,24 +4915,20 @@ compiler_tag_string(struct compiler *c, expr_ty e)
expr_ty tag = e->v.TagString.tag;
expr_ty str = e->v.TagString.str;
if (tag->kind == Name_kind) {
if (str->kind == Constant_kind) {
PyObject *value = str->v.Constant.value;
PyObject *kind = str->v.Constant.kind;
if (kind == NULL && PyBytes_CheckExact(value)) {
// Generate code for tag(value)
asdl_expr_seq *args =
_Py_asdl_expr_seq_new(1, c->c_arena);
if (args == NULL)
return 0;
asdl_seq_SET(args, 0, str);
asdl_keyword_seq *keywords =
_Py_asdl_keyword_seq_new(0, c->c_arena);
if (keywords == NULL)
return 0;
ADDOP(c, PUSH_NULL);
VISIT(c, expr, tag);
return compiler_call_helper(c, 0, args, keywords);
}
if (str->kind == JoinedStr_kind) {
// Generate code for tag(str)
asdl_expr_seq *args =
_Py_asdl_expr_seq_new(1, c->c_arena);
if (args == NULL)
return 0;
asdl_seq_SET(args, 0, str);
asdl_keyword_seq *keywords =
_Py_asdl_keyword_seq_new(0, c->c_arena);
if (keywords == NULL)
return 0;
ADDOP(c, PUSH_NULL);
VISIT(c, expr, tag);
return compiler_call_helper(c, 0, args, keywords);
}
}
}
Expand Down