Skip to content

Commit

Permalink
Some initial work
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed May 20, 2024
1 parent 3c28510 commit 462657e
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@ struct PyCodeObject _PyCode_DEF(1);
#define CO_FUTURE_BARRY_AS_BDFL 0x400000
#define CO_FUTURE_GENERATOR_STOP 0x800000
#define CO_FUTURE_ANNOTATIONS 0x1000000
#define CO_FUTURE_LARRY_AS_FLUFL 0x2000000

#define CO_NO_MONITORING_EVENTS 0x2000000
#define CO_NO_MONITORING_EVENTS 0x4000000

/* This should be defined if a future statement modifies the syntax.
For example, when a keyword is added.
Expand Down
1 change: 1 addition & 0 deletions Include/cpython/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef struct {
#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"
#define FUTURE_GENERATOR_STOP "generator_stop"
#define FUTURE_ANNOTATIONS "annotations"
#define FUTURE_LARRY_AS_FLUFL "larry_as_FLUFL"

#define PY_INVALID_STACK_EFFECT INT_MAX
PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg);
Expand Down
1 change: 1 addition & 0 deletions Include/cpython/funcobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ typedef struct {
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
PyObject *func_annotations; /* Annotations, a dict or NULL */
PyObject *func_annotate; /* The __annotate__ function */
PyObject *func_typeparams; /* Tuple of active type variables or NULL */
vectorcallfunc vectorcall;
/* Version number for use by specializer.
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_symtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ typedef struct _symtable_entry {
int ste_end_col_offset; /* end offset of first line of block */
int ste_opt_lineno; /* lineno of last exec or import * */
int ste_opt_col_offset; /* offset of last exec or import * */
struct _symtable_entry *ste_annotation_block; /* symbol table entry for this entry's annotations */
struct symtable *ste_table;
} PySTEntryObject;

Expand Down
6 changes: 6 additions & 0 deletions Lib/__future__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"barry_as_FLUFL",
"generator_stop",
"annotations",
"larry_as_FLUFL",
]

__all__ = ["all_feature_names"] + all_feature_names
Expand All @@ -76,6 +77,7 @@
CO_FUTURE_BARRY_AS_BDFL = 0x400000
CO_FUTURE_GENERATOR_STOP = 0x800000 # StopIteration becomes RuntimeError in generators
CO_FUTURE_ANNOTATIONS = 0x1000000 # annotations become strings at runtime
CO_FUTURE_LARRY_AS_FLUFL = 0x2000000 # Deferred evaluation of annotations


class _Feature:
Expand Down Expand Up @@ -145,3 +147,7 @@ def __repr__(self):
annotations = _Feature((3, 7, 0, "beta", 1),
None,
CO_FUTURE_ANNOTATIONS)

larry_as_FLUFL = _Feature((3, 14, 0, "alpha", 1),
(3, 16, 0, "alpha", 1),
CO_FUTURE_LARRY_AS_FLUFL)
10 changes: 9 additions & 1 deletion Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr)
op->func_weakreflist = NULL;
op->func_module = module;
op->func_annotations = NULL;
op->func_annotate = NULL;
op->func_typeparams = NULL;
op->vectorcall = _PyFunction_Vectorcall;
op->func_version = 0;
Expand Down Expand Up @@ -202,6 +203,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
op->func_weakreflist = NULL;
op->func_module = module;
op->func_annotations = NULL;
op->func_annotate = NULL;
op->func_typeparams = NULL;
op->vectorcall = _PyFunction_Vectorcall;
op->func_version = 0;
Expand Down Expand Up @@ -512,7 +514,11 @@ static PyObject *
func_get_annotation_dict(PyFunctionObject *op)
{
if (op->func_annotations == NULL) {
return NULL;
if (op->func_annotate == NULL) {
return NULL;
}
PyObject *one = _PyLong_GetOne();
PyObject *ann_dict = _PyObject_CallOneArg(op->func_annotate, one);
}
if (PyTuple_CheckExact(op->func_annotations)) {
PyObject *ann_tuple = op->func_annotations;
Expand Down Expand Up @@ -972,6 +978,7 @@ func_clear(PyFunctionObject *op)
Py_CLEAR(op->func_dict);
Py_CLEAR(op->func_closure);
Py_CLEAR(op->func_annotations);
Py_CLEAR(op->func_annotate);
Py_CLEAR(op->func_typeparams);
// Don't Py_CLEAR(op->func_code), since code is always required
// to be non-NULL. Similarly, name and qualname shouldn't be NULL.
Expand Down Expand Up @@ -1028,6 +1035,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
Py_VISIT(f->func_dict);
Py_VISIT(f->func_closure);
Py_VISIT(f->func_annotations);
Py_VISIT(f->func_annotate);
Py_VISIT(f->func_typeparams);
Py_VISIT(f->func_qualname);
return 0;
Expand Down
2 changes: 2 additions & 0 deletions Python/future.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ future_check_features(_PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
continue;
} else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
} else if (strcmp(feature, FUTURE_LARRY_AS_FLUFL) == 0) {
ff->ff_features |= CO_FUTURE_LARRY_AS_FLUFL;
} else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
continue;
} else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
Expand Down
54 changes: 53 additions & 1 deletion Python/symtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
ste->ste_can_see_class_scope = 0;
ste->ste_comp_iter_expr = 0;
ste->ste_needs_classdict = 0;
ste->ste_annotation_block = NULL;

ste->ste_symbols = PyDict_New();
ste->ste_varnames = PyList_New(0);
Expand Down Expand Up @@ -166,6 +167,7 @@ ste_dealloc(PySTEntryObject *ste)
Py_XDECREF(ste->ste_varnames);
Py_XDECREF(ste->ste_children);
Py_XDECREF(ste->ste_directives);
Py_XDECREF(ste->ste_annotation_block);
PyObject_Free(ste);
}

Expand Down Expand Up @@ -1360,6 +1362,35 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
return 1;
}

static int
symtable_reenter_block(struct symtable *st, PySTEntryObject* ste)
{
PySTEntryObject *prev = NULL;

if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) {
Py_DECREF(ste);
return 0;
}
prev = st->st_cur;
/* bpo-37757: For now, disallow *all* assignment expressions in the
* outermost iterator expression of a comprehension, even those inside
* a nested comprehension or a lambda expression.
*/
if (prev) {
ste->ste_comp_iter_expr = prev->ste_comp_iter_expr;
}
/* The entry is owned by the stack. Borrow it for st_cur. */
Py_DECREF(ste);
st->st_cur = ste;

if (prev) {
if (PyList_Append(prev->ste_children, (PyObject *)ste) < 0) {
return 0;
}
}
return 1;
}

static long
symtable_lookup_entry(struct symtable *st, PySTEntryObject *ste, PyObject *name)
{
Expand Down Expand Up @@ -1666,6 +1697,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
Py_CLEAR(st->st_cur->ste_annotation_block);
break;
case ClassDef_kind: {
PyObject *tmp;
Expand Down Expand Up @@ -1981,6 +2013,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
if (!symtable_exit_block(st))
VISIT_QUIT(st, 0);
}
Py_CLEAR(st->st_cur->ste_annotation_block);
break;
case AsyncWith_kind:
VISIT_SEQ(st, withitem, s->v.AsyncWith.items);
Expand Down Expand Up @@ -2435,8 +2468,27 @@ symtable_visit_annotation(struct symtable *st, expr_ty annotation)
annotation->end_col_offset)) {
VISIT_QUIT(st, 0);
}
int deferred_annotations = st->st_future->ff_features & CO_FUTURE_LARRY_AS_FLUFL;
if (deferred_annotations) {
if (st->st_cur->ste_annotation_block == NULL) {
struct _symtable_entry *st_parent = st->st_cur;
if (!symtable_enter_block(st, &_Py_ID(_annotation), AnnotationBlock,
(void *)annotation, annotation->lineno,
annotation->col_offset, annotation->end_lineno,
annotation->end_col_offset)) {
VISIT_QUIT(st, 0);
}
st_parent->ste_annotation_block =
(struct _symtable_entry *)Py_NewRef(st->st_cur);
}
else {
if (!symtable_reenter_block(st, st->st_cur->ste_annotation_block)) {
VISIT_QUIT(st, 0);
}
}
}
VISIT(st, expr, annotation);
if (future_annotations && !symtable_exit_block(st)) {
if ((future_annotations || deferred_annotations) && !symtable_exit_block(st)) {
VISIT_QUIT(st, 0);
}
return 1;
Expand Down

0 comments on commit 462657e

Please sign in to comment.