mirror of
https://github.com/python/cpython.git
synced 2025-07-19 01:05:26 +00:00
create NameConstant AST class for None, True, and False literals (closes #16619)
This commit is contained in:
parent
4b237e3b11
commit
442f20996d
15 changed files with 152 additions and 72 deletions
|
@ -271,6 +271,10 @@ static PyTypeObject *Bytes_type;
|
|||
static char *Bytes_fields[]={
|
||||
"s",
|
||||
};
|
||||
static PyTypeObject *NameConstant_type;
|
||||
static char *NameConstant_fields[]={
|
||||
"value",
|
||||
};
|
||||
static PyTypeObject *Ellipsis_type;
|
||||
static PyTypeObject *Attribute_type;
|
||||
_Py_IDENTIFIER(attr);
|
||||
|
@ -673,6 +677,7 @@ static PyObject* ast2obj_object(void *o)
|
|||
Py_INCREF((PyObject*)o);
|
||||
return (PyObject*)o;
|
||||
}
|
||||
#define ast2obj_singleton ast2obj_object
|
||||
#define ast2obj_identifier ast2obj_object
|
||||
#define ast2obj_string ast2obj_object
|
||||
#define ast2obj_bytes ast2obj_object
|
||||
|
@ -684,6 +689,17 @@ static PyObject* ast2obj_int(long b)
|
|||
|
||||
/* Conversion Python -> AST */
|
||||
|
||||
static int obj2ast_singleton(PyObject *obj, PyObject** out, PyArena* arena)
|
||||
{
|
||||
if (obj != Py_None && obj != Py_True && obj != Py_False) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"AST singleton must be True, False, or None");
|
||||
return 1;
|
||||
}
|
||||
*out = obj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int obj2ast_object(PyObject* obj, PyObject** out, PyArena* arena)
|
||||
{
|
||||
if (obj == Py_None)
|
||||
|
@ -860,6 +876,9 @@ static int init_types(void)
|
|||
if (!Str_type) return 0;
|
||||
Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1);
|
||||
if (!Bytes_type) return 0;
|
||||
NameConstant_type = make_type("NameConstant", expr_type,
|
||||
NameConstant_fields, 1);
|
||||
if (!NameConstant_type) return 0;
|
||||
Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0);
|
||||
if (!Ellipsis_type) return 0;
|
||||
Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3);
|
||||
|
@ -1920,6 +1939,25 @@ Bytes(bytes s, int lineno, int col_offset, PyArena *arena)
|
|||
return p;
|
||||
}
|
||||
|
||||
expr_ty
|
||||
NameConstant(singleton value, int lineno, int col_offset, PyArena *arena)
|
||||
{
|
||||
expr_ty p;
|
||||
if (!value) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field value is required for NameConstant");
|
||||
return NULL;
|
||||
}
|
||||
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->kind = NameConstant_kind;
|
||||
p->v.NameConstant.value = value;
|
||||
p->lineno = lineno;
|
||||
p->col_offset = col_offset;
|
||||
return p;
|
||||
}
|
||||
|
||||
expr_ty
|
||||
Ellipsis(int lineno, int col_offset, PyArena *arena)
|
||||
{
|
||||
|
@ -2028,6 +2066,7 @@ Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, PyArena
|
|||
*arena)
|
||||
{
|
||||
expr_ty p;
|
||||
assert(PyUnicode_CompareWithASCIIString(id, "True") && PyUnicode_CompareWithASCIIString(id, "False") && PyUnicode_CompareWithASCIIString(id, "None"));
|
||||
if (!id) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"field id is required for Name");
|
||||
|
@ -2948,6 +2987,15 @@ ast2obj_expr(void* _o)
|
|||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case NameConstant_kind:
|
||||
result = PyType_GenericNew(NameConstant_type, NULL, NULL);
|
||||
if (!result) goto failed;
|
||||
value = ast2obj_singleton(o->v.NameConstant.value);
|
||||
if (!value) goto failed;
|
||||
if (_PyObject_SetAttrId(result, &PyId_value, value) == -1)
|
||||
goto failed;
|
||||
Py_DECREF(value);
|
||||
break;
|
||||
case Ellipsis_kind:
|
||||
result = PyType_GenericNew(Ellipsis_type, NULL, NULL);
|
||||
if (!result) goto failed;
|
||||
|
@ -5688,6 +5736,29 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
|
|||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
isinstance = PyObject_IsInstance(obj, (PyObject*)NameConstant_type);
|
||||
if (isinstance == -1) {
|
||||
return 1;
|
||||
}
|
||||
if (isinstance) {
|
||||
singleton value;
|
||||
|
||||
if (_PyObject_HasAttrId(obj, &PyId_value)) {
|
||||
int res;
|
||||
tmp = _PyObject_GetAttrId(obj, &PyId_value);
|
||||
if (tmp == NULL) goto failed;
|
||||
res = obj2ast_singleton(tmp, &value, arena);
|
||||
if (res != 0) goto failed;
|
||||
Py_XDECREF(tmp);
|
||||
tmp = NULL;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NameConstant");
|
||||
return 1;
|
||||
}
|
||||
*out = NameConstant(value, lineno, col_offset, arena);
|
||||
if (*out == NULL) goto failed;
|
||||
return 0;
|
||||
}
|
||||
isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type);
|
||||
if (isinstance == -1) {
|
||||
return 1;
|
||||
|
@ -7008,6 +7079,8 @@ PyInit__ast(void)
|
|||
NULL;
|
||||
if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return
|
||||
NULL;
|
||||
if (PyDict_SetItemString(d, "NameConstant",
|
||||
(PyObject*)NameConstant_type) < 0) return NULL;
|
||||
if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0)
|
||||
return NULL;
|
||||
if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) <
|
||||
|
|
22
Python/ast.c
22
Python/ast.c
|
@ -282,6 +282,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
|
|||
return validate_exprs(exp->v.Tuple.elts, ctx, 0);
|
||||
/* These last cases don't have any checking. */
|
||||
case Name_kind:
|
||||
case NameConstant_kind:
|
||||
case Ellipsis_kind:
|
||||
return 1;
|
||||
default:
|
||||
|
@ -903,7 +904,7 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
|
|||
break;
|
||||
case Name_kind:
|
||||
if (ctx == Store) {
|
||||
if (forbidden_name(c, e->v.Name.id, n, 1))
|
||||
if (forbidden_name(c, e->v.Name.id, n, 0))
|
||||
return 0; /* forbidden_name() calls ast_error() */
|
||||
}
|
||||
e->v.Name.ctx = ctx;
|
||||
|
@ -955,6 +956,9 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
|
|||
case Bytes_kind:
|
||||
expr_name = "literal";
|
||||
break;
|
||||
case NameConstant_kind:
|
||||
expr_name = "keyword";
|
||||
break;
|
||||
case Ellipsis_kind:
|
||||
expr_name = "Ellipsis";
|
||||
break;
|
||||
|
@ -1819,11 +1823,21 @@ ast_for_atom(struct compiling *c, const node *n)
|
|||
|
||||
switch (TYPE(ch)) {
|
||||
case NAME: {
|
||||
/* All names start in Load context, but may later be
|
||||
changed. */
|
||||
PyObject *name = NEW_IDENTIFIER(ch);
|
||||
PyObject *name;
|
||||
const char *s = STR(ch);
|
||||
size_t len = strlen(s);
|
||||
if (len >= 4 && len <= 5) {
|
||||
if (!strcmp(s, "None"))
|
||||
return NameConstant(Py_None, LINENO(n), n->n_col_offset, c->c_arena);
|
||||
if (!strcmp(s, "True"))
|
||||
return NameConstant(Py_True, LINENO(n), n->n_col_offset, c->c_arena);
|
||||
if (!strcmp(s, "False"))
|
||||
return NameConstant(Py_False, LINENO(n), n->n_col_offset, c->c_arena);
|
||||
}
|
||||
name = new_identifier(s, c);
|
||||
if (!name)
|
||||
return NULL;
|
||||
/* All names start in Load context, but may later be changed. */
|
||||
return Name(name, Load, LINENO(n), n->n_col_offset, c->c_arena);
|
||||
}
|
||||
case STRING: {
|
||||
|
|
|
@ -3194,12 +3194,18 @@ expr_constant(struct compiler *c, expr_ty e)
|
|||
case Name_kind:
|
||||
/* optimize away names that can't be reassigned */
|
||||
id = PyUnicode_AsUTF8(e->v.Name.id);
|
||||
if (strcmp(id, "True") == 0) return 1;
|
||||
if (strcmp(id, "False") == 0) return 0;
|
||||
if (strcmp(id, "None") == 0) return 0;
|
||||
if (strcmp(id, "__debug__") == 0)
|
||||
return ! c->c_optimize;
|
||||
/* fall through */
|
||||
if (id && strcmp(id, "__debug__") == 0)
|
||||
return !c->c_optimize;
|
||||
return -1;
|
||||
case NameConstant_kind: {
|
||||
PyObject *o = e->v.NameConstant.value;
|
||||
if (o == Py_None)
|
||||
return 0;
|
||||
else if (o == Py_True)
|
||||
return 1;
|
||||
else if (o == Py_False)
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -3375,6 +3381,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
|
|||
case Ellipsis_kind:
|
||||
ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts);
|
||||
break;
|
||||
case NameConstant_kind:
|
||||
ADDOP_O(c, LOAD_CONST, e->v.NameConstant.value, consts);
|
||||
break;
|
||||
/* The following exprs can be assignment targets. */
|
||||
case Attribute_kind:
|
||||
if (e->v.Attribute.ctx != AugStore)
|
||||
|
|
|
@ -327,37 +327,6 @@ markblocks(unsigned char *code, Py_ssize_t len)
|
|||
return blocks;
|
||||
}
|
||||
|
||||
/* Helper to replace LOAD_NAME None/True/False with LOAD_CONST
|
||||
Returns: 0 if no change, 1 if change, -1 if error */
|
||||
static int
|
||||
load_global(unsigned char *codestr, Py_ssize_t i, char *name, PyObject *consts)
|
||||
{
|
||||
Py_ssize_t j;
|
||||
PyObject *obj;
|
||||
if (name == NULL)
|
||||
return 0;
|
||||
if (strcmp(name, "None") == 0)
|
||||
obj = Py_None;
|
||||
else if (strcmp(name, "True") == 0)
|
||||
obj = Py_True;
|
||||
else if (strcmp(name, "False") == 0)
|
||||
obj = Py_False;
|
||||
else
|
||||
return 0;
|
||||
for (j = 0; j < PyList_GET_SIZE(consts); j++) {
|
||||
if (PyList_GET_ITEM(consts, j) == obj)
|
||||
break;
|
||||
}
|
||||
if (j == PyList_GET_SIZE(consts)) {
|
||||
if (PyList_Append(consts, obj) < 0)
|
||||
return -1;
|
||||
}
|
||||
assert(PyList_GET_ITEM(consts, j) == obj);
|
||||
codestr[i] = LOAD_CONST;
|
||||
SETARG(codestr, i, j);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform basic peephole optimizations to components of a code object.
|
||||
The consts object should still be in list form to allow new constants
|
||||
to be appended.
|
||||
|
@ -392,7 +361,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
|
|||
Py_ssize_t const_stack_size = 0;
|
||||
int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
|
||||
unsigned int *blocks = NULL;
|
||||
char *name;
|
||||
|
||||
/* Bail out if an exception is set */
|
||||
if (PyErr_Occurred())
|
||||
|
@ -475,20 +443,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
|
|||
codestr[i+3] = NOP;
|
||||
break;
|
||||
|
||||
/* Replace LOAD_GLOBAL/LOAD_NAME None/True/False
|
||||
with LOAD_CONST None/True/False */
|
||||
case LOAD_NAME:
|
||||
case LOAD_GLOBAL:
|
||||
j = GETARG(codestr, i);
|
||||
name = _PyUnicode_AsString(PyTuple_GET_ITEM(names, j));
|
||||
h = load_global(codestr, i, name, consts);
|
||||
if (h < 0)
|
||||
goto exitError;
|
||||
else if (h == 0)
|
||||
continue;
|
||||
CONST_STACK_PUSH_OP(i);
|
||||
break;
|
||||
|
||||
/* Skip over LOAD_CONST trueconst
|
||||
POP_JUMP_IF_FALSE xx. This improves
|
||||
"while 1" performance. */
|
||||
|
|
|
@ -1437,6 +1437,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
|
|||
case Str_kind:
|
||||
case Bytes_kind:
|
||||
case Ellipsis_kind:
|
||||
case NameConstant_kind:
|
||||
/* Nothing to do here. */
|
||||
break;
|
||||
/* The following exprs can be assignment targets. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue