Skip to content

Commit

Permalink
Support class scoped variable lookup in interpolation lambdas (take 2) (
Browse files Browse the repository at this point in the history
python#45)

Co-authored-by: Lysandros Nikolaou <[email protected]>
  • Loading branch information
davepeck and lysnikolaou authored Jul 15, 2024
1 parent 62c9e0a commit 03af022
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 48 deletions.
4 changes: 2 additions & 2 deletions Include/internal/pycore_ast.h

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

1 change: 0 additions & 1 deletion Include/internal/pycore_ast_state.h

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

2 changes: 2 additions & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

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

2 changes: 2 additions & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct _Py_global_strings {
struct {
STRUCT_FOR_STR(anon_dictcomp, "<dictcomp>")
STRUCT_FOR_STR(anon_genexpr, "<genexpr>")
STRUCT_FOR_STR(anon_interpolation, "<interpolation>")
STRUCT_FOR_STR(anon_lambda, "<lambda>")
STRUCT_FOR_STR(anon_listcomp, "<listcomp>")
STRUCT_FOR_STR(anon_module, "<module>")
Expand Down Expand Up @@ -493,6 +494,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(insert_pis)
STRUCT_FOR_ID(instructions)
STRUCT_FOR_ID(intern)
STRUCT_FOR_ID(interpolation)
STRUCT_FOR_ID(intersection)
STRUCT_FOR_ID(interval)
STRUCT_FOR_ID(is_running)
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_runtime_init_generated.h

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

8 changes: 8 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

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

2 changes: 1 addition & 1 deletion Objects/decodedobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ DecodedConcrete_repr(PyObject *s)
{
PyObject *left = NULL, *repr = NULL, *right = NULL, *leftrepr = NULL;
PyObject *final = NULL;

left = PyUnicode_FromString("DecodedConcrete(");
if (left == NULL) {
goto exit;
Expand Down
2 changes: 1 addition & 1 deletion Parser/Python.asdl
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ module Python
| FormattedValue(expr value, int conversion, expr? format_spec)
| JoinedStr(expr* values)
| TagString(expr tag, expr str)
| Interpolation(expr lambda, expr str, expr? conversion, expr? format_spec)
| Interpolation(expr body, expr str, expr? conversion, expr? format_spec)
| Decoded(constant value, string? kind)
| Constant(constant value, string? kind)

Expand Down
18 changes: 1 addition & 17 deletions Parser/action_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,17 +1412,6 @@ _PyPegen_name_from_f_string_start(Parser *p, Token* t)
t->end_col_offset, p->arena);
}

static expr_ty
lambdafy(Parser *p, expr_ty arg)
{
arguments_ty args = _PyPegen_empty_arguments(p);
if (args == NULL)
return NULL;
return _PyAST_Lambda(args, arg,
arg->lineno, arg->col_offset, arg->end_lineno, arg->end_col_offset,
p->arena);
}

expr_ty
_PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) {
expr_ty tag = _PyPegen_name_from_f_string_start(p, a);
Expand All @@ -1441,10 +1430,6 @@ _PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) {
if (value->kind == FormattedValue_kind) {

expr_ty expr = value->v.FormattedValue.value;
expr_ty lambda = lambdafy(p, expr);
if (lambda == NULL) {
return NULL;
}

constant rawstr = _PyAST_ExprAsUnicode(expr);
if (rawstr == NULL) {
Expand Down Expand Up @@ -1475,7 +1460,7 @@ _PyPegen_tag_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) {
}

expr_ty spec = value->v.FormattedValue.format_spec;
expr_ty interpolation = _PyAST_Interpolation(lambda,
expr_ty interpolation = _PyAST_Interpolation(expr,
raw, conv, spec,
value->lineno, value->col_offset,
value->end_lineno, value->end_col_offset,
Expand Down Expand Up @@ -1604,7 +1589,6 @@ expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, in
debug_metadata = closing_brace->metadata;
}


expr_ty debug_text;
if (debug_as_decoded_ast) {
debug_text = _PyAST_Decoded(debug_metadata, NULL, lineno, col_offset + 1, debug_end_line,
Expand Down
38 changes: 18 additions & 20 deletions Python/Python-ast.c

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

2 changes: 1 addition & 1 deletion Python/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx)
ret = validate_exprs(state, exp->v.Tuple.elts, ctx, 0);
break;
case Interpolation_kind:
ret = validate_expr(state, exp->v.Interpolation.lambda, Load) &&
ret = validate_expr(state, exp->v.Interpolation.body, Load) &&
validate_expr(state, exp->v.Interpolation.str, Load) &&
(exp->v.Interpolation.conversion == NULL ||
validate_expr(state, exp->v.Interpolation.conversion, Load)) &&
Expand Down
2 changes: 1 addition & 1 deletion Python/ast_opt.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state)
CALL(fold_tuple, expr_ty, node_);
break;
case Interpolation_kind:
CALL(astfold_expr, expr_ty, node_->v.Interpolation.lambda);
CALL(astfold_expr, expr_ty, node_->v.Interpolation.body);
CALL(astfold_expr, expr_ty, node_->v.Interpolation.str);
CALL_OPT(astfold_expr, expr_ty, node_->v.Interpolation.conversion);
CALL_OPT(astfold_expr, expr_ty, node_->v.Interpolation.format_spec);
Expand Down
40 changes: 38 additions & 2 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ enum {
COMPILER_SCOPE_FUNCTION,
COMPILER_SCOPE_ASYNC_FUNCTION,
COMPILER_SCOPE_LAMBDA,
COMPILER_SCOPE_INTERPOLATION,
COMPILER_SCOPE_COMPREHENSION,
COMPILER_SCOPE_ANNOTATIONS,
};
Expand Down Expand Up @@ -629,7 +630,8 @@ compiler_set_qualname(struct compiler *c)
if (!force_global) {
if (parent->u_scope_type == COMPILER_SCOPE_FUNCTION
|| parent->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION
|| parent->u_scope_type == COMPILER_SCOPE_LAMBDA)
|| parent->u_scope_type == COMPILER_SCOPE_LAMBDA
|| parent->u_scope_type == COMPILER_SCOPE_INTERPOLATION)
{
_Py_DECLARE_STR(dot_locals, ".<locals>");
base = PyUnicode_Concat(parent->u_metadata.u_qualname,
Expand Down Expand Up @@ -5009,9 +5011,43 @@ compiler_joined_str(struct compiler *c, expr_ty e)
static int
compiler_interpolation(struct compiler *c, expr_ty e)
{
PyCodeObject *co;
location loc = LOC(e);

_Py_DECLARE_STR(anon_interpolation, "<interpolation>");
RETURN_IF_ERROR(
compiler_enter_scope(c, &_Py_STR(anon_interpolation), COMPILER_SCOPE_INTERPOLATION,
(void *)e, e->lineno));

/* Make None the first constant, so the interpolation can't have a
docstring. */
RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None));

c->u->u_metadata.u_argcount = 0;
c->u->u_metadata.u_posonlyargcount = 0;
c->u->u_metadata.u_kwonlyargcount = 0;

VISIT_IN_SCOPE(c, expr, e->v.Interpolation.body);
if (c->u->u_ste->ste_generator) {
co = optimize_and_assemble(c, 0);
}
else {
location loc = LOC(e->v.Interpolation.body);
ADDOP_IN_SCOPE(c, loc, RETURN_VALUE);
co = optimize_and_assemble(c, 1);
}
compiler_exit_scope(c);
if (co == NULL) {
return ERROR;
}

if (compiler_make_closure(c, loc, co, 0) < 0) {
Py_DECREF(co);
return ERROR;
}
Py_DECREF(co);

int oparg = 2;
VISIT(c, expr, e->v.Interpolation.lambda);
VISIT(c, expr, e->v.Interpolation.str);
if (e->v.Interpolation.conversion) {
VISIT(c, expr, e->v.Interpolation.conversion);
Expand Down
Loading

0 comments on commit 03af022

Please sign in to comment.