diff -r 4006c4ca0c1f Include/Python-ast.h --- a/Include/Python-ast.h Tue Dec 04 21:10:55 2012 +0200 +++ b/Include/Python-ast.h Wed Dec 05 19:42:01 2012 -0500 @@ -177,18 +177,19 @@ struct _stmt { int col_offset; }; enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, IfExp_kind=5, Dict_kind=6, Set_kind=7, ListComp_kind=8, SetComp_kind=9, DictComp_kind=10, GeneratorExp_kind=11, Yield_kind=12, YieldFrom_kind=13, Compare_kind=14, Call_kind=15, Num_kind=16, Str_kind=17, Bytes_kind=18, - Ellipsis_kind=19, Attribute_kind=20, Subscript_kind=21, - Starred_kind=22, Name_kind=23, List_kind=24, Tuple_kind=25}; + NameConstant_kind=19, Ellipsis_kind=20, Attribute_kind=21, + Subscript_kind=22, Starred_kind=23, Name_kind=24, + List_kind=25, Tuple_kind=26}; struct _expr { enum _expr_kind kind; union { struct { boolop_ty op; asdl_seq *values; } BoolOp; @@ -274,16 +275,20 @@ struct _expr { string s; } Str; struct { bytes s; } Bytes; struct { + singleton value; + } NameConstant; + + struct { expr_ty value; identifier attr; expr_context_ty ctx; } Attribute; struct { expr_ty value; slice_ty slice; @@ -504,16 +509,19 @@ expr_ty _Py_Call(expr_ty func, asdl_seq starargs, expr_ty kwargs, int lineno, int col_offset, PyArena *arena); #define Num(a0, a1, a2, a3) _Py_Num(a0, a1, a2, a3) expr_ty _Py_Num(object n, int lineno, int col_offset, PyArena *arena); #define Str(a0, a1, a2, a3) _Py_Str(a0, a1, a2, a3) 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) 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) 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) expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena); #define Subscript(a0, a1, a2, a3, a4, a5) _Py_Subscript(a0, a1, a2, a3, a4, a5) expr_ty _Py_Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena); diff -r 4006c4ca0c1f Include/asdl.h --- a/Include/asdl.h Tue Dec 04 21:10:55 2012 +0200 +++ b/Include/asdl.h Wed Dec 05 19:42:01 2012 -0500 @@ -1,15 +1,16 @@ #ifndef Py_ASDL_H #define Py_ASDL_H typedef PyObject * identifier; typedef PyObject * string; typedef PyObject * bytes; typedef PyObject * object; +typedef PyObject * singleton; /* 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 at this stage. So, for example, I'll represent identifiers as interned Python strings. */ /* XXX A sequence should be typed so that its use can be typechecked. */ diff -r 4006c4ca0c1f Lib/ast.py --- a/Lib/ast.py Tue Dec 04 21:10:55 2012 +0200 +++ b/Lib/ast.py Wed Dec 05 19:42:01 2012 -0500 @@ -37,17 +37,16 @@ def parse(source, filename='', def literal_eval(node_or_string): """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. """ - _safe_names = {'None': None, 'True': True, 'False': False} if isinstance(node_or_string, str): node_or_string = parse(node_or_string, mode='eval') if isinstance(node_or_string, Expression): node_or_string = node_or_string.body def _convert(node): if isinstance(node, (Str, Bytes)): return node.s elif isinstance(node, Num): @@ -56,19 +55,18 @@ def literal_eval(node_or_string): return tuple(map(_convert, node.elts)) elif isinstance(node, List): return list(map(_convert, node.elts)) elif isinstance(node, Set): return set(map(_convert, node.elts)) elif isinstance(node, Dict): return dict((_convert(k), _convert(v)) for k, v in zip(node.keys, node.values)) - elif isinstance(node, Name): - if node.id in _safe_names: - return _safe_names[node.id] + elif isinstance(node, NameConstant): + return node.value elif isinstance(node, UnaryOp) and \ isinstance(node.op, (UAdd, USub)) and \ isinstance(node.operand, (Num, UnaryOp, BinOp)): operand = _convert(node.operand) if isinstance(node.op, UAdd): return + operand else: return - operand diff -r 4006c4ca0c1f Lib/test/test_ast.py --- a/Lib/test/test_ast.py Tue Dec 04 21:10:55 2012 +0200 +++ b/Lib/test/test_ast.py Wed Dec 05 19:42:01 2012 -0500 @@ -923,16 +923,19 @@ class ASTValidatorTests(unittest.TestCas "must have Load context") def test_list(self): self._sequence(ast.List) def test_tuple(self): 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): stdlib = os.path.dirname(ast.__file__) tests = [fn for fn in os.listdir(stdlib) if fn.endswith(".py")] tests.extend(["test/test_grammar.py", "test/test_unpack_ex.py"]) for module in tests: fn = os.path.join(stdlib, module) with open(fn, "r", encoding="utf-8") as fp: source = fp.read() @@ -954,23 +957,23 @@ def main(): print(repr(to_tuple(compile(s, "?", kind, 0x400)))+",") print("]") print("main()") raise SystemExit test_main() #### EVERYTHING BELOW IS GENERATED ##### 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', [('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', [], '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', [('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', [('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', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])]), ('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Num', (1, 4), 1))]), ('Module', [('AugAssign', (1, 0), ('Name', (1, 0), 'v', ('Store',)), ('Add',), ('Num', (1, 5), 1))]), ('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Pass', (1, 11))], [])]), ('Module', [('While', (1, 0), ('Name', (1, 6), 'v', ('Load',)), [('Pass', (1, 8))], [])]), @@ -997,24 +1000,24 @@ exec_results = [ ('Module', [('Expr', (1, 0), ('DictComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [])]))]), ('Module', [('Expr', (1, 0), ('SetComp', (1, 1), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 12), 'x', ('Load',)), [('Name', (1, 17), 'g', ('Load',))])]))]), ('Module', [('Expr', (1, 0), ('SetComp', (1, 1), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7), [('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 9), 'm', ('Store',))], ('Store',)), ('Name', (1, 14), 'x', ('Load',)), [])]))]), ] single_results = [ ('Interactive', [('Expr', (1, 0), ('BinOp', (1, 0), ('Num', (1, 0), 1), ('Add',), ('Num', (1, 2), 2)))]), ] 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', ('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', ('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), [], [])), -('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', ('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', ('Compare', (1, 0), ('Num', (1, 0), 1), [('Lt',), ('Lt',)], [('Num', (1, 4), 2), ('Num', (1, 8), 3)])), ('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))), ('Expression', ('Num', (1, 0), 10)), ('Expression', ('Str', (1, 0), 'string')), ('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), diff -r 4006c4ca0c1f Lib/test/test_syntax.py --- a/Lib/test/test_syntax.py Tue Dec 04 21:10:55 2012 +0200 +++ b/Lib/test/test_syntax.py Wed Dec 05 19:42:01 2012 -0500 @@ -28,17 +28,17 @@ In ast.c, syntax errors are raised by ca Errors from set_context(): >>> obj.None = 1 Traceback (most recent call last): SyntaxError: invalid syntax >>> None = 1 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 error to assign to the empty list? It will always raise some error at runtime. >>> () = 1 Traceback (most recent call last): SyntaxError: can't assign to () @@ -228,17 +228,17 @@ SyntaxError: keyword can't be an express More set_context(): >>> (x for x in x) += 1 Traceback (most recent call last): SyntaxError: can't assign to generator expression >>> None += 1 Traceback (most recent call last): -SyntaxError: assignment to keyword +SyntaxError: can't assign to keyword >>> f() += 1 Traceback (most recent call last): SyntaxError: can't assign to function call Test continue in finally in weird combinations. continue in for loop under finally should be ok. diff -r 4006c4ca0c1f Parser/Python.asdl --- a/Parser/Python.asdl Tue Dec 04 21:10:55 2012 +0200 +++ b/Parser/Python.asdl Wed Dec 05 19:42:01 2012 -0500 @@ -1,9 +1,9 @@ --- 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 { mod = Module(stmt* body) | Interactive(stmt* body) | Expression(expr body) -- not really an actual node but useful in Jython's typesystem. @@ -64,18 +64,18 @@ module Python -- need sequences for compare to distinguish between -- x < 4 < 3 and (x < 4) < 3 | Compare(expr left, cmpop* ops, expr* comparators) | Call(expr func, expr* args, keyword* keywords, expr? starargs, expr? kwargs) | Num(object n) -- a number as a PyObject. | Str(string s) -- need to specify raw, unicode, etc? | Bytes(bytes s) + | NameConstant(singleton value) | Ellipsis - -- other literals? bools? -- the following expression can appear in assignment context | Attribute(expr value, identifier attr, expr_context ctx) | Subscript(expr value, slice slice, expr_context ctx) | Starred(expr value, expr_context ctx) | Name(identifier id, expr_context ctx) | List(expr* elts, expr_context ctx) | Tuple(expr* elts, expr_context ctx) diff -r 4006c4ca0c1f Parser/asdl.py --- a/Parser/asdl.py Tue Dec 04 21:10:55 2012 +0200 +++ b/Parser/asdl.py Wed Dec 05 19:42:01 2012 -0500 @@ -217,17 +217,17 @@ class ASDLParser(spark.GenericParser, ob def p_field_4(self, type_): " field ::= Id * " return Field(type_[0], seq=True) def p_field_5(self, type_): " field ::= Id ? " 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 :-) # not sure if any of the methods are useful yet, but I'm adding them # piecemeal as they seem helpful class AST(object): pass # a marker class diff -r 4006c4ca0c1f Parser/asdl_c.py --- a/Parser/asdl_c.py Tue Dec 04 21:10:55 2012 +0200 +++ b/Parser/asdl_c.py Wed Dec 05 19:42:01 2012 -0500 @@ -815,27 +815,39 @@ static PyObject* ast2obj_list(asdl_seq * static PyObject* ast2obj_object(void *o) { if (!o) o = Py_None; 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 static PyObject* ast2obj_int(long b) { return PyLong_FromLong(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) obj = NULL; if (obj) PyArena_AddPyObject(arena, obj); Py_XINCREF(obj); *out = obj; diff -r 4006c4ca0c1f Python/Python-ast.c --- a/Python/Python-ast.c Tue Dec 04 21:10:55 2012 +0200 +++ b/Python/Python-ast.c Wed Dec 05 19:42:01 2012 -0500 @@ -266,16 +266,20 @@ static PyTypeObject *Str_type; _Py_IDENTIFIER(s); static char *Str_fields[]={ "s", }; 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); _Py_IDENTIFIER(ctx); static char *Attribute_fields[]={ "value", "attr", "ctx", @@ -668,27 +672,39 @@ static PyObject* ast2obj_list(asdl_seq * static PyObject* ast2obj_object(void *o) { if (!o) o = Py_None; 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 static PyObject* ast2obj_int(long b) { return PyLong_FromLong(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) obj = NULL; if (obj) PyArena_AddPyObject(arena, obj); Py_XINCREF(obj); *out = obj; @@ -855,16 +871,19 @@ static int init_types(void) Call_type = make_type("Call", expr_type, Call_fields, 5); if (!Call_type) return 0; Num_type = make_type("Num", expr_type, Num_fields, 1); if (!Num_type) return 0; Str_type = make_type("Str", expr_type, Str_fields, 1); 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); if (!Attribute_type) return 0; Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); if (!Subscript_type) return 0; Starred_type = make_type("Starred", expr_type, Starred_fields, 2); if (!Starred_type) return 0; @@ -1916,16 +1935,35 @@ Bytes(bytes s, int lineno, int col_offse p->kind = Bytes_kind; p->v.Bytes.s = s; p->lineno = lineno; p->col_offset = col_offset; 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) { expr_ty p; p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Ellipsis_kind; p->lineno = lineno; @@ -2023,16 +2061,17 @@ Starred(expr_ty value, expr_context_ty c return p; } expr_ty 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"); return NULL; } if (!ctx) { PyErr_SetString(PyExc_ValueError, "field ctx is required for Name"); @@ -2943,16 +2982,25 @@ ast2obj_expr(void* _o) result = PyType_GenericNew(Bytes_type, NULL, NULL); if (!result) goto failed; value = ast2obj_bytes(o->v.Bytes.s); if (!value) goto failed; if (_PyObject_SetAttrId(result, &PyId_s, value) == -1) 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; break; case Attribute_kind: result = PyType_GenericNew(Attribute_type, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(o->v.Attribute.value); @@ -5683,16 +5731,39 @@ obj2ast_expr(PyObject* obj, expr_ty* out } else { PyErr_SetString(PyExc_TypeError, "required field \"s\" missing from Bytes"); return 1; } *out = Bytes(s, lineno, col_offset, 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; } if (isinstance) { *out = Ellipsis(lineno, col_offset, arena); if (*out == NULL) goto failed; @@ -7003,16 +7074,18 @@ PyInit__ast(void) if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return NULL; if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return NULL; if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return 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) < 0) return NULL; if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < 0) return NULL; if (PyDict_SetItemString(d, "Starred", (PyObject*)Starred_type) < 0) return NULL; diff -r 4006c4ca0c1f Python/ast.c --- a/Python/ast.c Tue Dec 04 21:10:55 2012 +0200 +++ b/Python/ast.c Wed Dec 05 19:42:01 2012 -0500 @@ -277,16 +277,17 @@ validate_expr(expr_ty exp, expr_context_ case Starred_kind: return validate_expr(exp->v.Starred.value, ctx); case List_kind: return validate_exprs(exp->v.List.elts, ctx, 0); case Tuple_kind: 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: PyErr_SetString(PyExc_SystemError, "unexpected expression"); return 0; } } @@ -898,17 +899,17 @@ set_context(struct compiling *c, expr_ty break; case Starred_kind: e->v.Starred.ctx = ctx; if (!set_context(c, e->v.Starred.value, ctx, n)) return 0; 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; break; case List_kind: e->v.List.ctx = ctx; s = e->v.List.elts; break; @@ -950,16 +951,19 @@ set_context(struct compiling *c, expr_ty break; case Dict_kind: case Set_kind: case Num_kind: case Str_kind: case Bytes_kind: expr_name = "literal"; break; + case NameConstant_kind: + expr_name = "keyword"; + break; case Ellipsis_kind: expr_name = "Ellipsis"; break; case Compare_kind: expr_name = "comparison"; break; case IfExp_kind: expr_name = "conditional expression"; @@ -1814,21 +1818,31 @@ ast_for_atom(struct compiling *c, const | '{' [dictmaker|testlist_comp] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' */ node *ch = CHILD(n, 0); int bytesmode = 0; 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: { PyObject *str = parsestrplus(c, n, &bytesmode); if (!str) { if (PyErr_ExceptionMatches(PyExc_UnicodeError)) { PyObject *type, *value, *tback, *errstr; PyErr_Fetch(&type, &value, &tback); diff -r 4006c4ca0c1f Python/compile.c --- a/Python/compile.c Tue Dec 04 21:10:55 2012 +0200 +++ b/Python/compile.c Wed Dec 05 19:42:01 2012 -0500 @@ -3189,22 +3189,28 @@ expr_constant(struct compiler *c, expr_t return 1; case Num_kind: return PyObject_IsTrue(e->v.Num.n); case Str_kind: return PyObject_IsTrue(e->v.Str.s); 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; } } /* Implements the with statement from PEP 343. @@ -3370,16 +3376,19 @@ compiler_visit_expr(struct compiler *c, ADDOP_O(c, LOAD_CONST, e->v.Str.s, consts); break; case Bytes_kind: ADDOP_O(c, LOAD_CONST, e->v.Bytes.s, consts); break; 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) VISIT(c, expr, e->v.Attribute.value); switch (e->v.Attribute.ctx) { case AugLoad: ADDOP(c, DUP_TOP); /* Fall through to load */ diff -r 4006c4ca0c1f Python/peephole.c --- a/Python/peephole.c Tue Dec 04 21:10:55 2012 +0200 +++ b/Python/peephole.c Wed Dec 05 19:42:01 2012 -0500 @@ -322,47 +322,16 @@ markblocks(unsigned char *code, Py_ssize /* Build block numbers in the second pass */ for (i=0 ; i= 255. EXTENDED_ARG can @@ -387,17 +356,16 @@ PyCode_Optimize(PyObject *code, PyObject int *addrmap = NULL; int new_line, cum_orig_line, last_line, tabsiz; PyObject **const_stack = NULL; Py_ssize_t *load_const_stack = NULL; Py_ssize_t const_stack_top = -1; 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()) goto exitError; /* Bypass optimization when the lineno table is too complex */ assert(PyBytes_Check(lineno_obj)); lineno = (unsigned char*)PyBytes_AS_STRING(lineno_obj); @@ -470,30 +438,16 @@ PyCode_Optimize(PyObject *code, PyObject if (j < 6 || j > 9 || codestr[i+3] != UNARY_NOT || !ISBASICBLOCK(blocks,i,4)) continue; SETARG(codestr, i, (j^1)); 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. */ case LOAD_CONST: CONST_STACK_PUSH_OP(i); j = GETARG(codestr, i); if (codestr[i+3] != POP_JUMP_IF_FALSE || !ISBASICBLOCK(blocks,i,6) || diff -r 4006c4ca0c1f Python/symtable.c --- a/Python/symtable.c Tue Dec 04 21:10:55 2012 +0200 +++ b/Python/symtable.c Wed Dec 05 19:42:01 2012 -0500 @@ -1432,16 +1432,17 @@ symtable_visit_expr(struct symtable *st, VISIT(st, expr, e->v.Call.starargs); if (e->v.Call.kwargs) VISIT(st, expr, e->v.Call.kwargs); break; case Num_kind: case Str_kind: case Bytes_kind: case Ellipsis_kind: + case NameConstant_kind: /* Nothing to do here. */ break; /* The following exprs can be assignment targets. */ case Attribute_kind: VISIT(st, expr, e->v.Attribute.value); break; case Subscript_kind: VISIT(st, expr, e->v.Subscript.value); diff -r 4006c4ca0c1f Tools/parser/unparse.py --- a/Tools/parser/unparse.py Tue Dec 04 21:10:55 2012 +0200 +++ b/Tools/parser/unparse.py Wed Dec 05 19:42:01 2012 -0500 @@ -302,16 +302,19 @@ class Unparser: self.write(repr(t.s)) def _Str(self, tree): self.write(repr(tree.s)) def _Name(self, t): self.write(t.id) + def _NameConstant(self, t): + self.write(repr(t.value)) + def _Num(self, t): # Substitute overflowing decimal literal for AST infinities. self.write(repr(t.n).replace("inf", INFSTR)) def _List(self, t): self.write("[") interleave(lambda: self.write(", "), self.dispatch, t.elts) self.write("]")