Commit 442f2099 authored by Benjamin Peterson's avatar Benjamin Peterson

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

parent 4b237e3b
...@@ -182,8 +182,9 @@ enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, ...@@ -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 { ...@@ -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); ...@@ -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)
......
...@@ -5,6 +5,7 @@ typedef PyObject * identifier; ...@@ -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
......
...@@ -42,7 +42,6 @@ def literal_eval(node_or_string): ...@@ -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): ...@@ -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)):
......
...@@ -928,6 +928,9 @@ class ASTValidatorTests(unittest.TestCase): ...@@ -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(): ...@@ -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 = [ ...@@ -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',))])])),
......
...@@ -33,7 +33,7 @@ SyntaxError: invalid syntax ...@@ -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): ...@@ -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
......
...@@ -10,6 +10,10 @@ What's New in Python 3.4.0 Alpha 1? ...@@ -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
......
-- 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 ...@@ -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)
......
...@@ -222,7 +222,7 @@ class ASDLParser(spark.GenericParser, object): ...@@ -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
......
...@@ -820,6 +820,7 @@ static PyObject* ast2obj_object(void *o) ...@@ -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) ...@@ -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)
......
...@@ -271,6 +271,10 @@ static PyTypeObject *Bytes_type; ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) <
......
...@@ -282,6 +282,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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: {
......
...@@ -3194,12 +3194,18 @@ expr_constant(struct compiler *c, expr_ty e) ...@@ -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) ...@@ -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)
......
...@@ -327,37 +327,6 @@ markblocks(unsigned char *code, Py_ssize_t len) ...@@ -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, ...@@ -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, ...@@ -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. */
......
...@@ -1437,6 +1437,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) ...@@ -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. */
......
...@@ -307,6 +307,9 @@ class Unparser: ...@@ -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))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment