cpython: 27e5437f442c (original) (raw)

Mercurial > cpython

changeset 100065:27e5437f442c

Add ast.Constant Issue #26146: Add a new kind of AST node: ast.Constant. It can be used by external AST optimizers, but the compiler does not emit directly such node. An optimizer can replace the following AST nodes with ast.Constant: * ast.NameConstant: None, False, True * ast.Num: int, float, complex * ast.Str: str * ast.Bytes: bytes * ast.Tuple if items are constants too: tuple * frozenset Update code to accept ast.Constant instead of ast.Num and/or ast.Str: * compiler * docstrings * ast.literal_eval() * Tools/parser/unparse.py [#26146]

Victor Stinner victor.stinner@gmail.com
date Tue, 26 Jan 2016 00:40:57 +0100
parents 4cb3c2d0aff2
children cbd4a6a2657e
files Include/Python-ast.h Include/asdl.h Lib/ast.py Lib/test/test_ast.py Misc/NEWS Parser/Python.asdl Parser/asdl.py Parser/asdl_c.py Python/Python-ast.c Python/ast.c Python/compile.c Python/future.c Python/symtable.c Tools/parser/unparse.py
diffstat 14 files changed, 401 insertions(+), 44 deletions(-)[+] [-] Include/Python-ast.h 13 Include/asdl.h 1 Lib/ast.py 52 Lib/test/test_ast.py 120 Misc/NEWS 4 Parser/Python.asdl 7 Parser/asdl.py 3 Parser/asdl_c.py 21 Python/Python-ast.c 79 Python/ast.c 50 Python/compile.c 60 Python/future.c 5 Python/symtable.c 1 Tools/parser/unparse.py 29

line wrap: on

line diff

--- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -202,9 +202,9 @@ enum _expr_kind {BoolOp_kind=1, BinOp_ki Await_kind=12, Yield_kind=13, YieldFrom_kind=14, Compare_kind=15, Call_kind=16, Num_kind=17, Str_kind=18, FormattedValue_kind=19, JoinedStr_kind=20, Bytes_kind=21,

struct _expr { enum _expr_kind kind; union { @@ -316,6 +316,10 @@ struct _expr { } NameConstant; struct {

@@ -567,6 +571,9 @@ expr_ty _Py_NameConstant(singleton value *arena); #define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2) expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena); +#define Constant(a0, a1, a2, a3) _Py_Constant(a0, a1, a2, a3) +expr_ty _Py_Constant(constant value, int lineno, int col_offset, PyArena

#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);

--- a/Include/asdl.h +++ b/Include/asdl.h @@ -6,6 +6,7 @@ typedef PyObject * string; typedef PyObject * bytes; typedef PyObject * object; typedef PyObject * singleton; +typedef PyObject * constant; /* 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

--- a/Lib/ast.py +++ b/Lib/ast.py @@ -35,6 +35,8 @@ def parse(source, filename='', return compile(source, filename, mode, PyCF_ONLY_AST) +_NUM_TYPES = (int, float, complex) + def literal_eval(node_or_string): """ Safely evaluate an expression node or a string containing a Python @@ -47,7 +49,9 @@ def literal_eval(node_or_string): if isinstance(node_or_string, Expression): node_or_string = node_or_string.body def _convert(node):

@@ -62,24 +66,21 @@ def literal_eval(node_or_string): in zip(node.keys, node.values)) elif isinstance(node, NameConstant): return node.value

def walk(node):

--- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,7 +1,8 @@ +import ast +import dis import os import sys import unittest -import ast import weakref from test import support @@ -933,6 +934,123 @@ class ASTValidatorTests(unittest.TestCas compile(mod, fn, "exec") +class ConstantTests(unittest.TestCase):

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ + def main(): if name != 'main': return

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Release date: tba Core and Builtins ----------------- +- Issue #26146: Add a new kind of AST node: ast.Constant. It can be used

--- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -1,4 +1,8 @@ --- ASDL's six builtin types are identifier, int, string, bytes, object, singleton +-- ASDL's 7 builtin types are: +-- identifier, int, string, bytes, object, singleton, constant +-- +-- singleton: None, True or False +-- constant can be None, whereas None means "no value" for object. module Python { @@ -76,6 +80,7 @@ module Python | Bytes(bytes s) | NameConstant(singleton value) | Ellipsis

-- the following expression can appear in assignment context | Attribute(expr value, identifier attr, expr_context ctx)

--- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -33,7 +33,8 @@ import re

See the EBNF at the top of the file to understand the logical connection

between the various node types.

-builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton'} +builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton',

class AST: def repr(self):

--- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -834,6 +834,7 @@ static PyObject* ast2obj_object(void o) return (PyObject)o; } #define ast2obj_singleton ast2obj_object +#define ast2obj_constant ast2obj_object #define ast2obj_identifier ast2obj_object #define ast2obj_string ast2obj_object #define ast2obj_bytes ast2obj_object @@ -871,6 +872,26 @@ static int obj2ast_object(PyObject* obj, return 0; } +static int obj2ast_constant(PyObject* obj, PyObject** out, PyArena* arena) +{

+

+} + static int obj2ast_identifier(PyObject* obj, PyObject** out, PyArena* arena) { if (!PyUnicode_CheckExact(obj) && obj != Py_None) {

--- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -306,6 +306,10 @@ static char *NameConstant_fields[]={ "value", }; static PyTypeObject *Ellipsis_type; +static PyTypeObject *Constant_type; +static char *Constant_fields[]={

+}; static PyTypeObject Attribute_type; _Py_IDENTIFIER(attr); _Py_IDENTIFIER(ctx); @@ -709,6 +713,7 @@ static PyObject ast2obj_object(void o) return (PyObject)o; } #define ast2obj_singleton ast2obj_object +#define ast2obj_constant ast2obj_object #define ast2obj_identifier ast2obj_object #define ast2obj_string ast2obj_object #define ast2obj_bytes ast2obj_object @@ -746,6 +751,26 @@ static int obj2ast_object(PyObject* obj, return 0; } +static int obj2ast_constant(PyObject* obj, PyObject** out, PyArena* arena) +{

+

+} + static int obj2ast_identifier(PyObject* obj, PyObject** out, PyArena* arena) { if (!PyUnicode_CheckExact(obj) && obj != Py_None) { @@ -941,6 +966,8 @@ static int init_types(void) if (!NameConstant_type) return 0; Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0); if (!Ellipsis_type) return 0;

expr_ty +Constant(constant value, int lineno, int col_offset, PyArena *arena) +{

+} + +expr_ty Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, PyArena arena) { @@ -3267,6 +3313,15 @@ ast2obj_expr(void _o) result = PyType_GenericNew(Ellipsis_type, NULL, NULL); if (!result) goto failed; break;

@@ -6240,6 +6295,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out if (*out == NULL) goto failed; return 0; }

+

@@ -7517,6 +7594,8 @@ PyInit__ast(void) 0) return NULL; if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) return NULL;

--- a/Python/ast.c +++ b/Python/ast.c @@ -132,6 +132,50 @@ validate_arguments(arguments_ty args) } static int +validate_constant(PyObject *value) +{

+

+

+

+

+

+

+

+} + +static int validate_expr(expr_ty exp, expr_context_ty ctx) { int check_ctx = 1; @@ -240,6 +284,12 @@ validate_expr(expr_ty exp, expr_context_ return validate_expr(exp->v.Call.func, Load) && validate_exprs(exp->v.Call.args, Load, 0) && validate_keywords(exp->v.Call.keywords);

--- a/Python/compile.c +++ b/Python/compile.c @@ -1314,7 +1314,11 @@ compiler_isdocstring(stmt_ty s) { if (s->kind != Expr_kind) return 0;

} /* Compile a sequence of statements, checking for a docstring. */ @@ -1688,8 +1692,12 @@ compiler_function(struct compiler *c, st st = (stmt_ty)asdl_seq_GET(body, 0); docstring = compiler_isdocstring(st);

@@ -2600,6 +2608,36 @@ compiler_assert(struct compiler *c, stmt } static int +compiler_visit_stmt_expr(struct compiler *c, expr_ty value) +{

+

+

+

+} + +static int compiler_visit_stmt(struct compiler *c, stmt_ty s) { Py_ssize_t i, n; @@ -2669,16 +2707,7 @@ compiler_visit_stmt(struct compiler *c, case Nonlocal_kind: break; case Expr_kind:

--- a/Python/future.c +++ b/Python/future.c @@ -79,7 +79,10 @@ future_parse(PyFutureFeatures *ff, mod_t i = 0; first = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);

--- a/Python/symtable.c +++ b/Python/symtable.c @@ -1455,6 +1455,7 @@ symtable_visit_expr(struct symtable *st, case JoinedStr_kind: VISIT_SEQ(st, expr, e->v.JoinedStr.values); break;

--- a/Tools/parser/unparse.py +++ b/Tools/parser/unparse.py @@ -343,6 +343,11 @@ class Unparser: value = t.s.replace("{", "{{").replace("}", "}}") write(value)

+ def _fstring_FormattedValue(self, t, write): write("{") expr = io.StringIO() @@ -364,6 +369,25 @@ class Unparser: def _Name(self, t): self.write(t.id)

+

+ def _NameConstant(self, t): self.write(repr(t.value)) @@ -443,7 +467,7 @@ class Unparser: def _Tuple(self, t): self.write("(") if len(t.elts) == 1:

@@ -490,7 +514,8 @@ class Unparser: # Special case: 3.abs() is a syntax error, so if t.value # is an integer literal then we need to either parenthesize # it or add an extra space to get 3 .abs().