create NameConstant AST class for None, True, and False literals (closes #16619)
This commit is contained in:
parent
4b237e3b11
commit
442f20996d
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
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)):
|
||||||
|
|
|
@ -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',))])])),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
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)
|
||||||
|
|
|
@ -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) <
|
||||||
|
|
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);
|
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: {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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:
|
||||||
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))
|
||||||
|
|
Loading…
Reference in New Issue