create NameConstant AST class for None, True, and False literals (closes #16619)

This commit is contained in:
Benjamin Peterson 2012-12-06 17:41:04 -05:00
parent 4b237e3b11
commit 442f20996d
15 changed files with 152 additions and 72 deletions

View File

@ -182,8 +182,9 @@ enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4,
SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11, SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11,
Yield_kind=12, YieldFrom_kind=13, Compare_kind=14, Yield_kind=12, YieldFrom_kind=13, Compare_kind=14,
Call_kind=15, Num_kind=16, Str_kind=17, Bytes_kind=18, Call_kind=15, Num_kind=16, Str_kind=17, Bytes_kind=18,
Ellipsis_kind=19, Attribute_kind=20, Subscript_kind=21, NameConstant_kind=19, Ellipsis_kind=20, Attribute_kind=21,
Starred_kind=22, Name_kind=23, List_kind=24, Tuple_kind=25}; Subscript_kind=22, Starred_kind=23, Name_kind=24,
List_kind=25, Tuple_kind=26};
struct _expr { struct _expr {
enum _expr_kind kind; enum _expr_kind kind;
union { union {
@ -278,6 +279,10 @@ struct _expr {
bytes s; bytes s;
} Bytes; } Bytes;
struct {
singleton value;
} NameConstant;
struct { struct {
expr_ty value; expr_ty value;
identifier attr; identifier attr;
@ -509,6 +514,9 @@ expr_ty _Py_Num(object n, int lineno, int col_offset, PyArena *arena);
expr_ty _Py_Str(string s, int lineno, int col_offset, PyArena *arena); expr_ty _Py_Str(string s, int lineno, int col_offset, PyArena *arena);
#define Bytes(a0, a1, a2, a3) _Py_Bytes(a0, a1, a2, a3) #define Bytes(a0, a1, a2, a3) _Py_Bytes(a0, a1, a2, a3)
expr_ty _Py_Bytes(bytes s, int lineno, int col_offset, PyArena *arena); expr_ty _Py_Bytes(bytes s, int lineno, int col_offset, PyArena *arena);
#define NameConstant(a0, a1, a2, a3) _Py_NameConstant(a0, a1, a2, a3)
expr_ty _Py_NameConstant(singleton value, int lineno, int col_offset, PyArena
*arena);
#define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2) #define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2)
expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena); expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena);
#define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5) #define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5)

View File

@ -5,6 +5,7 @@ typedef PyObject * identifier;
typedef PyObject * string; typedef PyObject * string;
typedef PyObject * bytes; typedef PyObject * bytes;
typedef PyObject * object; typedef PyObject * object;
typedef PyObject * singleton;
/* It would be nice if the code generated by asdl_c.py was completely /* It would be nice if the code generated by asdl_c.py was completely
independent of Python, but it is a goal the requires too much work independent of Python, but it is a goal the requires too much work

View File

@ -42,7 +42,6 @@ def literal_eval(node_or_string):
Python literal structures: strings, bytes, numbers, tuples, lists, dicts, Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
sets, booleans, and None. sets, booleans, and None.
""" """
_safe_names = {'None': None, 'True': True, 'False': False}
if isinstance(node_or_string, str): if isinstance(node_or_string, str):
node_or_string = parse(node_or_string, mode='eval') node_or_string = parse(node_or_string, mode='eval')
if isinstance(node_or_string, Expression): if isinstance(node_or_string, Expression):
@ -61,9 +60,8 @@ def literal_eval(node_or_string):
elif isinstance(node, Dict): elif isinstance(node, Dict):
return dict((_convert(k), _convert(v)) for k, v return dict((_convert(k), _convert(v)) for k, v
in zip(node.keys, node.values)) in zip(node.keys, node.values))
elif isinstance(node, Name): elif isinstance(node, NameConstant):
if node.id in _safe_names: return node.value
return _safe_names[node.id]
elif isinstance(node, UnaryOp) and \ elif isinstance(node, UnaryOp) and \
isinstance(node.op, (UAdd, USub)) and \ isinstance(node.op, (UAdd, USub)) and \
isinstance(node.operand, (Num, UnaryOp, BinOp)): isinstance(node.operand, (Num, UnaryOp, BinOp)):

View File

@ -928,6 +928,9 @@ class ASTValidatorTests(unittest.TestCase):
def test_tuple(self): def test_tuple(self):
self._sequence(ast.Tuple) self._sequence(ast.Tuple)
def test_nameconstant(self):
self.expr(ast.NameConstant(4), "singleton must be True, False, or None")
def test_stdlib_validates(self): def test_stdlib_validates(self):
stdlib = os.path.dirname(ast.__file__) stdlib = os.path.dirname(ast.__file__)
tests = [fn for fn in os.listdir(stdlib) if fn.endswith(".py")] tests = [fn for fn in os.listdir(stdlib) if fn.endswith(".py")]
@ -959,13 +962,13 @@ def main():
#### EVERYTHING BELOW IS GENERATED ##### #### EVERYTHING BELOW IS GENERATED #####
exec_results = [ exec_results = [
('Module', [('Expr', (1, 0), ('Name', (1, 0), 'None', ('Load',)))]), ('Module', [('Expr', (1, 0), ('NameConstant', (1, 0), None))]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Pass', (1, 9))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Pass', (1, 9))], [], None)]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', 'a', None)], None, None, [], None, None, [], []), [('Pass', (1, 10))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', 'a', None)], None, None, [], None, None, [], []), [('Pass', (1, 10))], [], None)]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', 'a', None)], None, None, [], None, None, [('Num', (1, 8), 0)], []), [('Pass', (1, 12))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', 'a', None)], None, None, [], None, None, [('Num', (1, 8), 0)], []), [('Pass', (1, 12))], [], None)]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], 'args', None, [], None, None, [], []), [('Pass', (1, 14))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], 'args', None, [], None, None, [], []), [('Pass', (1, 14))], [], None)]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], 'kwargs', None, [], []), [('Pass', (1, 17))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], 'kwargs', None, [], []), [('Pass', (1, 17))], [], None)]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', 'a', None), ('arg', 'b', None), ('arg', 'c', None), ('arg', 'd', None), ('arg', 'e', None)], 'args', None, [], 'kwargs', None, [('Num', (1, 11), 1), ('Name', (1, 16), 'None', ('Load',)), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])], []), [('Pass', (1, 52))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', 'a', None), ('arg', 'b', None), ('arg', 'c', None), ('arg', 'd', None), ('arg', 'e', None)], 'args', None, [], 'kwargs', None, [('Num', (1, 11), 1), ('NameConstant', (1, 16), None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])], []), [('Pass', (1, 52))], [], None)]),
('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))], [])]), ('Module', [('ClassDef', (1, 0), 'C', [], [], None, None, [('Pass', (1, 8))], [])]),
('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], None, None, [('Pass', (1, 17))], [])]), ('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], None, None, [('Pass', (1, 17))], [])]),
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]),
@ -1002,14 +1005,14 @@ single_results = [
('Interactive', [('Expr', (1, 0), ('BinOp', (1, 0), ('Num', (1, 0), 1), ('Add',), ('Num', (1, 2), 2)))]), ('Interactive', [('Expr', (1, 0), ('BinOp', (1, 0), ('Num', (1, 0), 1), ('Add',), ('Num', (1, 2), 2)))]),
] ]
eval_results = [ eval_results = [
('Expression', ('Name', (1, 0), 'None', ('Load',))), ('Expression', ('NameConstant', (1, 0), None)),
('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])), ('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])),
('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))), ('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))),
('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))), ('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))),
('Expression', ('Lambda', (1, 0), ('arguments', [], None, None, [], None, None, [], []), ('Name', (1, 7), 'None', ('Load',)))), ('Expression', ('Lambda', (1, 0), ('arguments', [], None, None, [], None, None, [], []), ('NameConstant', (1, 7), None))),
('Expression', ('Dict', (1, 0), [('Num', (1, 2), 1)], [('Num', (1, 4), 2)])), ('Expression', ('Dict', (1, 0), [('Num', (1, 2), 1)], [('Num', (1, 4), 2)])),
('Expression', ('Dict', (1, 0), [], [])), ('Expression', ('Dict', (1, 0), [], [])),
('Expression', ('Set', (1, 0), [('Name', (1, 1), 'None', ('Load',))])), ('Expression', ('Set', (1, 0), [('NameConstant', (1, 1), None)])),
('Expression', ('Dict', (1, 0), [('Num', (2, 6), 1)], [('Num', (4, 10), 2)])), ('Expression', ('Dict', (1, 0), [('Num', (2, 6), 1)], [('Num', (4, 10), 2)])),
('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])),
('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])), ('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])),

View File

@ -33,7 +33,7 @@ SyntaxError: invalid syntax
>>> None = 1 >>> None = 1
Traceback (most recent call last): Traceback (most recent call last):
SyntaxError: assignment to keyword SyntaxError: can't assign to keyword
It's a syntax error to assign to the empty tuple. Why isn't it an It's a syntax error to assign to the empty tuple. Why isn't it an
error to assign to the empty list? It will always raise some error at error to assign to the empty list? It will always raise some error at
@ -233,7 +233,7 @@ Traceback (most recent call last):
SyntaxError: can't assign to generator expression SyntaxError: can't assign to generator expression
>>> None += 1 >>> None += 1
Traceback (most recent call last): Traceback (most recent call last):
SyntaxError: assignment to keyword SyntaxError: can't assign to keyword
>>> f() += 1 >>> f() += 1
Traceback (most recent call last): Traceback (most recent call last):
SyntaxError: can't assign to function call SyntaxError: can't assign to function call

View File

@ -10,6 +10,10 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #16619: Create NameConstant AST class to represent None, True, and False
literals. As a result, these constants are never loaded at runtime from
builtins.
- Issue #16455: On FreeBSD and Solaris, if the locale is C, the - Issue #16455: On FreeBSD and Solaris, if the locale is C, the
ASCII/surrogateescape codec is now used, instead of the locale encoding, to ASCII/surrogateescape codec is now used, instead of the locale encoding, to
decode the command line arguments. This change fixes inconsistencies with decode the command line arguments. This change fixes inconsistencies with

View File

@ -1,4 +1,4 @@
-- ASDL's five builtin types are identifier, int, string, bytes, object -- ASDL's six builtin types are identifier, int, string, bytes, object, singleton
module Python module Python
{ {
@ -69,8 +69,8 @@ module Python
| Num(object n) -- a number as a PyObject. | Num(object n) -- a number as a PyObject.
| Str(string s) -- need to specify raw, unicode, etc? | Str(string s) -- need to specify raw, unicode, etc?
| Bytes(bytes s) | Bytes(bytes s)
| NameConstant(singleton value)
| Ellipsis | Ellipsis
-- other literals? bools?
-- the following expression can appear in assignment context -- the following expression can appear in assignment context
| Attribute(expr value, identifier attr, expr_context ctx) | Attribute(expr value, identifier attr, expr_context ctx)

View File

@ -222,7 +222,7 @@ class ASDLParser(spark.GenericParser, object):
" field ::= Id ? " " field ::= Id ? "
return Field(type[0], opt=True) return Field(type[0], opt=True)
builtin_types = ("identifier", "string", "bytes", "int", "object") builtin_types = ("identifier", "string", "bytes", "int", "object", "singleton")
# below is a collection of classes to capture the AST of an AST :-) # below is a collection of classes to capture the AST of an AST :-)
# not sure if any of the methods are useful yet, but I'm adding them # not sure if any of the methods are useful yet, but I'm adding them

View File

@ -820,6 +820,7 @@ static PyObject* ast2obj_object(void *o)
Py_INCREF((PyObject*)o); Py_INCREF((PyObject*)o);
return (PyObject*)o; return (PyObject*)o;
} }
#define ast2obj_singleton ast2obj_object
#define ast2obj_identifier ast2obj_object #define ast2obj_identifier ast2obj_object
#define ast2obj_string ast2obj_object #define ast2obj_string ast2obj_object
#define ast2obj_bytes ast2obj_object #define ast2obj_bytes ast2obj_object
@ -831,6 +832,17 @@ static PyObject* ast2obj_int(long b)
/* Conversion Python -> AST */ /* 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) static int obj2ast_object(PyObject* obj, PyObject** out, PyArena* arena)
{ {
if (obj == Py_None) if (obj == Py_None)

View File

@ -271,6 +271,10 @@ static PyTypeObject *Bytes_type;
static char *Bytes_fields[]={ static char *Bytes_fields[]={
"s", "s",
}; };
static PyTypeObject *NameConstant_type;
static char *NameConstant_fields[]={
"value",
};
static PyTypeObject *Ellipsis_type; static PyTypeObject *Ellipsis_type;
static PyTypeObject *Attribute_type; static PyTypeObject *Attribute_type;
_Py_IDENTIFIER(attr); _Py_IDENTIFIER(attr);
@ -673,6 +677,7 @@ static PyObject* ast2obj_object(void *o)
Py_INCREF((PyObject*)o); Py_INCREF((PyObject*)o);
return (PyObject*)o; return (PyObject*)o;
} }
#define ast2obj_singleton ast2obj_object
#define ast2obj_identifier ast2obj_object #define ast2obj_identifier ast2obj_object
#define ast2obj_string ast2obj_object #define ast2obj_string ast2obj_object
#define ast2obj_bytes ast2obj_object #define ast2obj_bytes ast2obj_object
@ -684,6 +689,17 @@ static PyObject* ast2obj_int(long b)
/* Conversion Python -> AST */ /* 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) static int obj2ast_object(PyObject* obj, PyObject** out, PyArena* arena)
{ {
if (obj == Py_None) if (obj == Py_None)
@ -860,6 +876,9 @@ static int init_types(void)
if (!Str_type) return 0; if (!Str_type) return 0;
Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1); Bytes_type = make_type("Bytes", expr_type, Bytes_fields, 1);
if (!Bytes_type) return 0; 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); Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0);
if (!Ellipsis_type) return 0; if (!Ellipsis_type) return 0;
Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); 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; 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 expr_ty
Ellipsis(int lineno, int col_offset, PyArena *arena) 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) *arena)
{ {
expr_ty p; expr_ty p;
assert(PyUnicode_CompareWithASCIIString(id, "True") && PyUnicode_CompareWithASCIIString(id, "False") && PyUnicode_CompareWithASCIIString(id, "None"));
if (!id) { if (!id) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"field id is required for Name"); "field id is required for Name");
@ -2948,6 +2987,15 @@ ast2obj_expr(void* _o)
goto failed; goto failed;
Py_DECREF(value); Py_DECREF(value);
break; 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: case Ellipsis_kind:
result = PyType_GenericNew(Ellipsis_type, NULL, NULL); result = PyType_GenericNew(Ellipsis_type, NULL, NULL);
if (!result) goto failed; if (!result) goto failed;
@ -5688,6 +5736,29 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
if (*out == NULL) goto failed; if (*out == NULL) goto failed;
return 0; 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); isinstance = PyObject_IsInstance(obj, (PyObject*)Ellipsis_type);
if (isinstance == -1) { if (isinstance == -1) {
return 1; return 1;
@ -7008,6 +7079,8 @@ PyInit__ast(void)
NULL; NULL;
if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return if (PyDict_SetItemString(d, "Bytes", (PyObject*)Bytes_type) < 0) return
NULL; NULL;
if (PyDict_SetItemString(d, "NameConstant",
(PyObject*)NameConstant_type) < 0) return NULL;
if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0)
return NULL; return NULL;
if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) <

View File

@ -282,6 +282,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
return validate_exprs(exp->v.Tuple.elts, ctx, 0); return validate_exprs(exp->v.Tuple.elts, ctx, 0);
/* These last cases don't have any checking. */ /* These last cases don't have any checking. */
case Name_kind: case Name_kind:
case NameConstant_kind:
case Ellipsis_kind: case Ellipsis_kind:
return 1; return 1;
default: default:
@ -903,7 +904,7 @@ set_context(struct compiling *c, expr_ty e, expr_context_ty ctx, const node *n)
break; break;
case Name_kind: case Name_kind:
if (ctx == Store) { 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() */ return 0; /* forbidden_name() calls ast_error() */
} }
e->v.Name.ctx = ctx; 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: case Bytes_kind:
expr_name = "literal"; expr_name = "literal";
break; break;
case NameConstant_kind:
expr_name = "keyword";
break;
case Ellipsis_kind: case Ellipsis_kind:
expr_name = "Ellipsis"; expr_name = "Ellipsis";
break; break;
@ -1819,11 +1823,21 @@ ast_for_atom(struct compiling *c, const node *n)
switch (TYPE(ch)) { switch (TYPE(ch)) {
case NAME: { case NAME: {
/* All names start in Load context, but may later be PyObject *name;
changed. */ const char *s = STR(ch);
PyObject *name = NEW_IDENTIFIER(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) if (!name)
return NULL; 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); return Name(name, Load, LINENO(n), n->n_col_offset, c->c_arena);
} }
case STRING: { case STRING: {

View File

@ -3194,12 +3194,18 @@ expr_constant(struct compiler *c, expr_ty e)
case Name_kind: case Name_kind:
/* optimize away names that can't be reassigned */ /* optimize away names that can't be reassigned */
id = PyUnicode_AsUTF8(e->v.Name.id); id = PyUnicode_AsUTF8(e->v.Name.id);
if (strcmp(id, "True") == 0) return 1; if (id && strcmp(id, "__debug__") == 0)
if (strcmp(id, "False") == 0) return 0; return !c->c_optimize;
if (strcmp(id, "None") == 0) return 0; return -1;
if (strcmp(id, "__debug__") == 0) case NameConstant_kind: {
return ! c->c_optimize; PyObject *o = e->v.NameConstant.value;
/* fall through */ if (o == Py_None)
return 0;
else if (o == Py_True)
return 1;
else if (o == Py_False)
return 0;
}
default: default:
return -1; return -1;
} }
@ -3375,6 +3381,9 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
case Ellipsis_kind: case Ellipsis_kind:
ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts); ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts);
break; break;
case NameConstant_kind:
ADDOP_O(c, LOAD_CONST, e->v.NameConstant.value, consts);
break;
/* The following exprs can be assignment targets. */ /* The following exprs can be assignment targets. */
case Attribute_kind: case Attribute_kind:
if (e->v.Attribute.ctx != AugStore) if (e->v.Attribute.ctx != AugStore)

View File

@ -327,37 +327,6 @@ markblocks(unsigned char *code, Py_ssize_t len)
return blocks; 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. /* Perform basic peephole optimizations to components of a code object.
The consts object should still be in list form to allow new constants The consts object should still be in list form to allow new constants
to be appended. to be appended.
@ -392,7 +361,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
Py_ssize_t const_stack_size = 0; Py_ssize_t const_stack_size = 0;
int in_consts = 0; /* whether we are in a LOAD_CONST sequence */ int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
unsigned int *blocks = NULL; unsigned int *blocks = NULL;
char *name;
/* Bail out if an exception is set */ /* Bail out if an exception is set */
if (PyErr_Occurred()) if (PyErr_Occurred())
@ -475,20 +443,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
codestr[i+3] = NOP; codestr[i+3] = NOP;
break; 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 /* Skip over LOAD_CONST trueconst
POP_JUMP_IF_FALSE xx. This improves POP_JUMP_IF_FALSE xx. This improves
"while 1" performance. */ "while 1" performance. */

View File

@ -1437,6 +1437,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
case Str_kind: case Str_kind:
case Bytes_kind: case Bytes_kind:
case Ellipsis_kind: case Ellipsis_kind:
case NameConstant_kind:
/* Nothing to do here. */ /* Nothing to do here. */
break; break;
/* The following exprs can be assignment targets. */ /* The following exprs can be assignment targets. */

View File

@ -307,6 +307,9 @@ class Unparser:
def _Name(self, t): def _Name(self, t):
self.write(t.id) self.write(t.id)
def _NameConstant(self, t):
self.write(repr(t.value))
def _Num(self, t): def _Num(self, t):
# Substitute overflowing decimal literal for AST infinities. # Substitute overflowing decimal literal for AST infinities.
self.write(repr(t.n).replace("inf", INFSTR)) self.write(repr(t.n).replace("inf", INFSTR))