mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
Merged revisions 62004 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r62004 | georg.brandl | 2008-03-28 13:11:56 +0100 (Fr, 28 Mär 2008) | 4 lines Patch #1810 by Thomas Lee, reviewed by myself: allow compiling Python AST objects into code objects in compile(). ........
This commit is contained in:
parent
d3372793d6
commit
618dc5e064
8 changed files with 3476 additions and 53 deletions
|
@ -10,16 +10,16 @@ Abstract Syntax Trees
|
||||||
|
|
||||||
|
|
||||||
The ``_ast`` module helps Python applications to process trees of the Python
|
The ``_ast`` module helps Python applications to process trees of the Python
|
||||||
abstract syntax grammar. The Python compiler currently provides read-only access
|
abstract syntax grammar. The abstract syntax itself might change with each
|
||||||
to such trees, meaning that applications can only create a tree for a given
|
Python release; this module helps to find out programmatically what the current
|
||||||
piece of Python source code; generating :term:`bytecode` from a (potentially modified)
|
grammar looks like.
|
||||||
tree is not supported. The abstract syntax itself might change with each Python
|
|
||||||
release; this module helps to find out programmatically what the current grammar
|
|
||||||
looks like.
|
|
||||||
|
|
||||||
An abstract syntax tree can be generated by passing ``_ast.PyCF_ONLY_AST`` as a
|
An abstract syntax tree can be generated by passing :data:`_ast.PyCF_ONLY_AST`
|
||||||
flag to the :func:`compile` builtin function. The result will be a tree of
|
as a flag to the :func:`compile` builtin function. The result will be a tree of
|
||||||
objects whose classes all inherit from ``_ast.AST``.
|
objects whose classes all inherit from :class:`_ast.AST`.
|
||||||
|
|
||||||
|
A modified abstract syntax tree can be compiled into a Python code object using
|
||||||
|
the built-in :func:`compile` function.
|
||||||
|
|
||||||
The actual classes are derived from the ``Parser/Python.asdl`` file, which is
|
The actual classes are derived from the ``Parser/Python.asdl`` file, which is
|
||||||
reproduced below. There is one class defined for each left-hand side symbol in
|
reproduced below. There is one class defined for each left-hand side symbol in
|
||||||
|
@ -39,12 +39,15 @@ attribute ``left`` of type ``_ast.expr``. Instances of ``_ast.expr`` and
|
||||||
``_ast.stmt`` subclasses also have lineno and col_offset attributes. The lineno
|
``_ast.stmt`` subclasses also have lineno and col_offset attributes. The lineno
|
||||||
is the line number of source text (1 indexed so the first line is line 1) and
|
is the line number of source text (1 indexed so the first line is line 1) and
|
||||||
the col_offset is the utf8 byte offset of the first token that generated the
|
the col_offset is the utf8 byte offset of the first token that generated the
|
||||||
node. The utf8 offset is recorded because the parser uses utf8 internally.
|
node. The utf8 offset is recorded because the parser uses utf8 internally.
|
||||||
|
|
||||||
If these attributes are marked as optional in the grammar (using a question
|
If these attributes are marked as optional in the grammar (using a question
|
||||||
mark), the value might be ``None``. If the attributes can have zero-or-more
|
mark), the value might be ``None``. If the attributes can have zero-or-more
|
||||||
values (marked with an asterisk), the values are represented as Python lists.
|
values (marked with an asterisk), the values are represented as Python lists.
|
||||||
|
|
||||||
|
The constructors of all ``_ast`` classes don't take arguments; instead, if you
|
||||||
|
create instances, you must assign the required attributes separately.
|
||||||
|
|
||||||
|
|
||||||
Abstract Grammar
|
Abstract Grammar
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -193,21 +193,21 @@ available. They are listed here in alphabetical order.
|
||||||
|
|
||||||
.. function:: compile(source, filename, mode[, flags[, dont_inherit]])
|
.. function:: compile(source, filename, mode[, flags[, dont_inherit]])
|
||||||
|
|
||||||
Compile the *source* into a code object. Code objects can be executed by a call
|
Compile the *source* into a code object. Code objects can be
|
||||||
to :func:`exec` or evaluated by a call to :func:`eval`. The *filename* argument
|
executed by a call to :func:`exec` or evaluated by a call to
|
||||||
should give the file from which the code was read; pass some recognizable value
|
:func:`eval`. *source* can either be a string or an AST object.
|
||||||
if it wasn't read from a file (``'<string>'`` is commonly used). The *mode*
|
Refer to the :mod:`_ast` module documentation for information on
|
||||||
argument specifies what kind of code must be compiled; it can be ``'exec'`` if
|
how to compile into and from AST objects.
|
||||||
*source* consists of a sequence of statements, ``'eval'`` if it consists of a
|
|
||||||
single expression, or ``'single'`` if it consists of a single interactive
|
|
||||||
statement (in the latter case, expression statements that evaluate to something
|
|
||||||
else than ``None`` will be printed).
|
|
||||||
|
|
||||||
When compiling multi-line statements, two caveats apply: line endings must be
|
The *filename* argument should give the file from
|
||||||
represented by a single newline character (``'\n'``), and the input must be
|
which the code was read; pass some recognizable value if it wasn't
|
||||||
terminated by at least one newline character. If line endings are represented
|
read from a file (``'<string>'`` is commonly used). The *mode*
|
||||||
by ``'\r\n'``, use the string :meth:`replace` method to change them into
|
argument specifies what kind of code must be compiled; it can be
|
||||||
``'\n'``.
|
``'exec'`` if *source* consists of a sequence of statements,
|
||||||
|
``'eval'`` if it consists of a single expression, or ``'single'``
|
||||||
|
if it consists of a single interactive statement (in the latter
|
||||||
|
case, expression statements that evaluate to something else than
|
||||||
|
``None`` will be printed).
|
||||||
|
|
||||||
The optional arguments *flags* and *dont_inherit* (which are new in Python 2.2)
|
The optional arguments *flags* and *dont_inherit* (which are new in Python 2.2)
|
||||||
control which future statements (see :pep:`236`) affect the compilation of
|
control which future statements (see :pep:`236`) affect the compilation of
|
||||||
|
@ -227,6 +227,9 @@ available. They are listed here in alphabetical order.
|
||||||
This function raises :exc:`SyntaxError` if the compiled source is invalid,
|
This function raises :exc:`SyntaxError` if the compiled source is invalid,
|
||||||
and :exc:`TypeError` if the source contains null bytes.
|
and :exc:`TypeError` if the source contains null bytes.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
Support for compiling AST objects.
|
||||||
|
|
||||||
|
|
||||||
.. function:: complex([real[, imag]])
|
.. function:: complex([real[, imag]])
|
||||||
|
|
||||||
|
|
|
@ -542,3 +542,5 @@ keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena);
|
||||||
alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena);
|
alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena);
|
||||||
|
|
||||||
PyObject* PyAST_mod2obj(mod_ty t);
|
PyObject* PyAST_mod2obj(mod_ty t);
|
||||||
|
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena);
|
||||||
|
int PyAST_Check(PyObject* obj);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import unittest
|
import unittest
|
||||||
import sys
|
import sys
|
||||||
|
import _ast
|
||||||
from test import test_support
|
from test import test_support
|
||||||
|
|
||||||
class TestSpecifics(unittest.TestCase):
|
class TestSpecifics(unittest.TestCase):
|
||||||
|
@ -406,6 +407,28 @@ if 1:
|
||||||
self.assert_("_A__mangled_mod" in A.f.__code__.co_varnames)
|
self.assert_("_A__mangled_mod" in A.f.__code__.co_varnames)
|
||||||
self.assert_("__package__" in A.f.__code__.co_varnames)
|
self.assert_("__package__" in A.f.__code__.co_varnames)
|
||||||
|
|
||||||
|
def test_compile_ast(self):
|
||||||
|
fname = __file__
|
||||||
|
if fname.lower().endswith(('pyc', 'pyo')):
|
||||||
|
fname = fname[:-1]
|
||||||
|
with open(fname, 'r') as f:
|
||||||
|
fcontents = f.read()
|
||||||
|
sample_code = [
|
||||||
|
['<assign>', 'x = 5'],
|
||||||
|
['<ifblock>', """if True:\n pass\n"""],
|
||||||
|
['<forblock>', """for n in [1, 2, 3]:\n print(n)\n"""],
|
||||||
|
['<deffunc>', """def foo():\n pass\nfoo()\n"""],
|
||||||
|
[fname, fcontents],
|
||||||
|
]
|
||||||
|
|
||||||
|
for fname, code in sample_code:
|
||||||
|
co1 = compile(code, '%s1' % fname, 'exec')
|
||||||
|
ast = compile(code, '%s2' % fname, 'exec', _ast.PyCF_ONLY_AST)
|
||||||
|
self.assert_(type(ast) == _ast.Module)
|
||||||
|
co2 = compile(ast, '%s3' % fname, 'exec')
|
||||||
|
self.assertEqual(co1, co2)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test_support.run_unittest(TestSpecifics)
|
test_support.run_unittest(TestSpecifics)
|
||||||
|
|
||||||
|
|
255
Parser/asdl_c.py
255
Parser/asdl_c.py
|
@ -73,12 +73,12 @@ def is_simple(sum):
|
||||||
A sum is simple if its types have no fields, e.g.
|
A sum is simple if its types have no fields, e.g.
|
||||||
unaryop = Invert | Not | UAdd | USub
|
unaryop = Invert | Not | UAdd | USub
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for t in sum.types:
|
for t in sum.types:
|
||||||
if t.fields:
|
if t.fields:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class EmitVisitor(asdl.VisitorBase):
|
class EmitVisitor(asdl.VisitorBase):
|
||||||
"""Visit that emits lines"""
|
"""Visit that emits lines"""
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ class EmitVisitor(asdl.VisitorBase):
|
||||||
line = (" " * TABSIZE * depth) + line + "\n"
|
line = (" " * TABSIZE * depth) + line + "\n"
|
||||||
self.file.write(line)
|
self.file.write(line)
|
||||||
|
|
||||||
|
|
||||||
class TypeDefVisitor(EmitVisitor):
|
class TypeDefVisitor(EmitVisitor):
|
||||||
def visitModule(self, mod):
|
def visitModule(self, mod):
|
||||||
for dfn in mod.dfns:
|
for dfn in mod.dfns:
|
||||||
|
@ -133,6 +134,7 @@ class TypeDefVisitor(EmitVisitor):
|
||||||
self.emit(s, depth)
|
self.emit(s, depth)
|
||||||
self.emit("", depth)
|
self.emit("", depth)
|
||||||
|
|
||||||
|
|
||||||
class StructVisitor(EmitVisitor):
|
class StructVisitor(EmitVisitor):
|
||||||
"""Visitor to generate typdefs for AST."""
|
"""Visitor to generate typdefs for AST."""
|
||||||
|
|
||||||
|
@ -202,6 +204,7 @@ class StructVisitor(EmitVisitor):
|
||||||
self.emit("};", depth)
|
self.emit("};", depth)
|
||||||
self.emit("", depth)
|
self.emit("", depth)
|
||||||
|
|
||||||
|
|
||||||
class PrototypeVisitor(EmitVisitor):
|
class PrototypeVisitor(EmitVisitor):
|
||||||
"""Generate function prototypes for the .h file"""
|
"""Generate function prototypes for the .h file"""
|
||||||
|
|
||||||
|
@ -271,6 +274,7 @@ class PrototypeVisitor(EmitVisitor):
|
||||||
self.emit_function(name, get_c_type(name),
|
self.emit_function(name, get_c_type(name),
|
||||||
self.get_args(prod.fields), [], union=0)
|
self.get_args(prod.fields), [], union=0)
|
||||||
|
|
||||||
|
|
||||||
class FunctionVisitor(PrototypeVisitor):
|
class FunctionVisitor(PrototypeVisitor):
|
||||||
"""Visitor to generate constructor functions for AST."""
|
"""Visitor to generate constructor functions for AST."""
|
||||||
|
|
||||||
|
@ -324,6 +328,7 @@ class FunctionVisitor(PrototypeVisitor):
|
||||||
emit("p->%s = %s;" % (argname, argname), 1)
|
emit("p->%s = %s;" % (argname, argname), 1)
|
||||||
assert not attrs
|
assert not attrs
|
||||||
|
|
||||||
|
|
||||||
class PickleVisitor(EmitVisitor):
|
class PickleVisitor(EmitVisitor):
|
||||||
|
|
||||||
def visitModule(self, mod):
|
def visitModule(self, mod):
|
||||||
|
@ -345,6 +350,181 @@ class PickleVisitor(EmitVisitor):
|
||||||
def visitField(self, sum):
|
def visitField(self, sum):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Obj2ModPrototypeVisitor(PickleVisitor):
|
||||||
|
def visitProduct(self, prod, name):
|
||||||
|
code = "static int obj2ast_%s(PyObject* obj, %s* out, PyArena* arena);"
|
||||||
|
self.emit(code % (name, get_c_type(name)), 0)
|
||||||
|
|
||||||
|
visitSum = visitProduct
|
||||||
|
|
||||||
|
|
||||||
|
class Obj2ModVisitor(PickleVisitor):
|
||||||
|
def funcHeader(self, name):
|
||||||
|
ctype = get_c_type(name)
|
||||||
|
self.emit("int", 0)
|
||||||
|
self.emit("obj2ast_%s(PyObject* obj, %s* out, PyArena* arena)" % (name, ctype), 0)
|
||||||
|
self.emit("{", 0)
|
||||||
|
self.emit("PyObject* tmp = NULL;", 1)
|
||||||
|
self.emit("", 0)
|
||||||
|
|
||||||
|
def sumTrailer(self, name):
|
||||||
|
self.emit("", 0)
|
||||||
|
self.emit("tmp = PyObject_Repr(obj);", 1)
|
||||||
|
# there's really nothing more we can do if this fails ...
|
||||||
|
self.emit("if (tmp == NULL) goto failed;", 1)
|
||||||
|
error = "expected some sort of %s, but got %%.400s" % name
|
||||||
|
format = "PyErr_Format(PyExc_TypeError, \"%s\", PyString_AS_STRING(tmp));"
|
||||||
|
self.emit(format % error, 1, reflow=False)
|
||||||
|
self.emit("failed:", 0)
|
||||||
|
self.emit("Py_XDECREF(tmp);", 1)
|
||||||
|
self.emit("return 1;", 1)
|
||||||
|
self.emit("}", 0)
|
||||||
|
self.emit("", 0)
|
||||||
|
|
||||||
|
def simpleSum(self, sum, name):
|
||||||
|
self.funcHeader(name)
|
||||||
|
for t in sum.types:
|
||||||
|
self.emit("if (PyObject_IsInstance(obj, (PyObject*)%s_type)) {" % t.name, 1)
|
||||||
|
self.emit("*out = %s;" % t.name, 2)
|
||||||
|
self.emit("return 0;", 2)
|
||||||
|
self.emit("}", 1)
|
||||||
|
self.sumTrailer(name)
|
||||||
|
|
||||||
|
def buildArgs(self, fields):
|
||||||
|
return ", ".join(fields + ["arena"])
|
||||||
|
|
||||||
|
def complexSum(self, sum, name):
|
||||||
|
self.funcHeader(name)
|
||||||
|
for a in sum.attributes:
|
||||||
|
self.visitAttributeDeclaration(a, name, sum=sum)
|
||||||
|
self.emit("", 0)
|
||||||
|
# XXX: should we only do this for 'expr'?
|
||||||
|
self.emit("if (obj == Py_None) {", 1)
|
||||||
|
self.emit("*out = NULL;", 2)
|
||||||
|
self.emit("return 0;", 2)
|
||||||
|
self.emit("}", 1)
|
||||||
|
for a in sum.attributes:
|
||||||
|
self.visitField(a, name, sum=sum, depth=1)
|
||||||
|
for t in sum.types:
|
||||||
|
self.emit("if (PyObject_IsInstance(obj, (PyObject*)%s_type)) {" % t.name, 1)
|
||||||
|
for f in t.fields:
|
||||||
|
self.visitFieldDeclaration(f, t.name, sum=sum, depth=2)
|
||||||
|
self.emit("", 0)
|
||||||
|
for f in t.fields:
|
||||||
|
self.visitField(f, t.name, sum=sum, depth=2)
|
||||||
|
args = [f.name.value for f in t.fields] + [a.name.value for a in sum.attributes]
|
||||||
|
self.emit("*out = %s(%s);" % (t.name, self.buildArgs(args)), 2)
|
||||||
|
self.emit("if (*out == NULL) goto failed;", 2)
|
||||||
|
self.emit("return 0;", 2)
|
||||||
|
self.emit("}", 1)
|
||||||
|
self.sumTrailer(name)
|
||||||
|
|
||||||
|
def visitAttributeDeclaration(self, a, name, sum=sum):
|
||||||
|
ctype = get_c_type(a.type)
|
||||||
|
self.emit("%s %s;" % (ctype, a.name), 1)
|
||||||
|
|
||||||
|
def visitSum(self, sum, name):
|
||||||
|
if is_simple(sum):
|
||||||
|
self.simpleSum(sum, name)
|
||||||
|
else:
|
||||||
|
self.complexSum(sum, name)
|
||||||
|
|
||||||
|
def visitProduct(self, prod, name):
|
||||||
|
ctype = get_c_type(name)
|
||||||
|
self.emit("int", 0)
|
||||||
|
self.emit("obj2ast_%s(PyObject* obj, %s* out, PyArena* arena)" % (name, ctype), 0)
|
||||||
|
self.emit("{", 0)
|
||||||
|
self.emit("PyObject* tmp = NULL;", 1)
|
||||||
|
for f in prod.fields:
|
||||||
|
self.visitFieldDeclaration(f, name, prod=prod, depth=1)
|
||||||
|
self.emit("", 0)
|
||||||
|
for f in prod.fields:
|
||||||
|
self.visitField(f, name, prod=prod, depth=1)
|
||||||
|
args = [f.name.value for f in prod.fields]
|
||||||
|
self.emit("*out = %s(%s);" % (name, self.buildArgs(args)), 1)
|
||||||
|
self.emit("return 0;", 1)
|
||||||
|
self.emit("failed:", 0)
|
||||||
|
self.emit("Py_XDECREF(tmp);", 1)
|
||||||
|
self.emit("return 1;", 1)
|
||||||
|
self.emit("}", 0)
|
||||||
|
self.emit("", 0)
|
||||||
|
|
||||||
|
def visitFieldDeclaration(self, field, name, sum=None, prod=None, depth=0):
|
||||||
|
ctype = get_c_type(field.type)
|
||||||
|
if field.seq:
|
||||||
|
if self.isSimpleType(field):
|
||||||
|
self.emit("asdl_int_seq* %s;" % field.name, depth)
|
||||||
|
else:
|
||||||
|
self.emit("asdl_seq* %s;" % field.name, depth)
|
||||||
|
else:
|
||||||
|
ctype = get_c_type(field.type)
|
||||||
|
self.emit("%s %s;" % (ctype, field.name), depth)
|
||||||
|
|
||||||
|
def isSimpleSum(self, field):
|
||||||
|
# XXX can the members of this list be determined automatically?
|
||||||
|
return field.type.value in ('expr_context', 'boolop', 'operator',
|
||||||
|
'unaryop', 'cmpop')
|
||||||
|
|
||||||
|
def isNumeric(self, field):
|
||||||
|
return get_c_type(field.type) in ("int", "bool")
|
||||||
|
|
||||||
|
def isSimpleType(self, field):
|
||||||
|
return self.isSimpleSum(field) or self.isNumeric(field)
|
||||||
|
|
||||||
|
def visitField(self, field, name, sum=None, prod=None, depth=0):
|
||||||
|
ctype = get_c_type(field.type)
|
||||||
|
self.emit("if (PyObject_HasAttrString(obj, \"%s\")) {" % field.name, depth)
|
||||||
|
self.emit("int res;", depth+1)
|
||||||
|
if field.seq:
|
||||||
|
self.emit("Py_ssize_t len;", depth+1)
|
||||||
|
self.emit("Py_ssize_t i;", depth+1)
|
||||||
|
self.emit("tmp = PyObject_GetAttrString(obj, \"%s\");" % field.name, depth+1)
|
||||||
|
self.emit("if (tmp == NULL) goto failed;", depth+1)
|
||||||
|
if field.seq:
|
||||||
|
self.emit("if (!PyList_Check(tmp)) {", depth+1)
|
||||||
|
self.emit("PyErr_Format(PyExc_TypeError, \"%s field \\\"%s\\\" must "
|
||||||
|
"be a list, not a %%.200s\", tmp->ob_type->tp_name);" %
|
||||||
|
(name, field.name),
|
||||||
|
depth+2, reflow=False)
|
||||||
|
self.emit("goto failed;", depth+2)
|
||||||
|
self.emit("}", depth+1)
|
||||||
|
self.emit("len = PyList_GET_SIZE(tmp);", depth+1)
|
||||||
|
if self.isSimpleType(field):
|
||||||
|
self.emit("%s = asdl_int_seq_new(len, arena);" % field.name, depth+1)
|
||||||
|
else:
|
||||||
|
self.emit("%s = asdl_seq_new(len, arena);" % field.name, depth+1)
|
||||||
|
self.emit("if (%s == NULL) goto failed;" % field.name, depth+1)
|
||||||
|
self.emit("for (i = 0; i < len; i++) {", depth+1)
|
||||||
|
self.emit("%s value;" % ctype, depth+2)
|
||||||
|
self.emit("res = obj2ast_%s(PyList_GET_ITEM(tmp, i), &value, arena);" %
|
||||||
|
field.type, depth+2, reflow=False)
|
||||||
|
self.emit("if (res != 0) goto failed;", depth+2)
|
||||||
|
self.emit("asdl_seq_SET(%s, i, value);" % field.name, depth+2)
|
||||||
|
self.emit("}", depth+1)
|
||||||
|
else:
|
||||||
|
self.emit("res = obj2ast_%s(tmp, &%s, arena);" %
|
||||||
|
(field.type, field.name), depth+1)
|
||||||
|
self.emit("if (res != 0) goto failed;", depth+1)
|
||||||
|
|
||||||
|
self.emit("Py_XDECREF(tmp);", depth+1)
|
||||||
|
self.emit("tmp = NULL;", depth+1)
|
||||||
|
self.emit("} else {", depth)
|
||||||
|
if not field.opt:
|
||||||
|
message = "required field \\\"%s\\\" missing from %s" % (field.name, name)
|
||||||
|
format = "PyErr_SetString(PyExc_TypeError, \"%s\");"
|
||||||
|
self.emit(format % message, depth+1, reflow=False)
|
||||||
|
self.emit("return 1;", depth+1)
|
||||||
|
else:
|
||||||
|
if self.isNumeric(field):
|
||||||
|
self.emit("%s = 0;" % field.name, depth+1)
|
||||||
|
elif not self.isSimpleType(field):
|
||||||
|
self.emit("%s = NULL;" % field.name, depth+1)
|
||||||
|
else:
|
||||||
|
raise TypeError("could not determine the default value for %s" % field.name)
|
||||||
|
self.emit("}", depth)
|
||||||
|
|
||||||
|
|
||||||
class MarshalPrototypeVisitor(PickleVisitor):
|
class MarshalPrototypeVisitor(PickleVisitor):
|
||||||
|
|
||||||
def prototype(self, sum, name):
|
def prototype(self, sum, name):
|
||||||
|
@ -354,6 +534,7 @@ class MarshalPrototypeVisitor(PickleVisitor):
|
||||||
|
|
||||||
visitProduct = visitSum = prototype
|
visitProduct = visitSum = prototype
|
||||||
|
|
||||||
|
|
||||||
class PyTypesDeclareVisitor(PickleVisitor):
|
class PyTypesDeclareVisitor(PickleVisitor):
|
||||||
|
|
||||||
def visitProduct(self, prod, name):
|
def visitProduct(self, prod, name):
|
||||||
|
@ -439,6 +620,8 @@ static int add_attributes(PyTypeObject* type, char**attrs, int num_fields)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Conversion AST -> Python */
|
||||||
|
|
||||||
static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*))
|
static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*))
|
||||||
{
|
{
|
||||||
int i, n = asdl_seq_LEN(seq);
|
int i, n = asdl_seq_LEN(seq);
|
||||||
|
@ -471,6 +654,42 @@ static PyObject* ast2obj_int(long b)
|
||||||
{
|
{
|
||||||
return PyLong_FromLong(b);
|
return PyLong_FromLong(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Conversion Python -> AST */
|
||||||
|
|
||||||
|
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;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define obj2ast_identifier obj2ast_object
|
||||||
|
#define obj2ast_string obj2ast_object
|
||||||
|
|
||||||
|
static int obj2ast_int(PyObject* obj, int* out, PyArena* arena)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!PyLong_Check(obj)) {
|
||||||
|
PyObject *s = PyObject_Repr(obj);
|
||||||
|
if (s == NULL) return 1;
|
||||||
|
PyErr_Format(PyExc_ValueError, "invalid integer value: %.400s",
|
||||||
|
PyString_AS_STRING(s));
|
||||||
|
Py_DECREF(s);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (int)PyLong_AsLong(obj);
|
||||||
|
if (i == -1 && PyErr_Occurred())
|
||||||
|
return 1;
|
||||||
|
*out = i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
""", 0, reflow=False)
|
""", 0, reflow=False)
|
||||||
|
|
||||||
self.emit("static int init_types(void)",0)
|
self.emit("static int init_types(void)",0)
|
||||||
|
@ -518,6 +737,7 @@ static PyObject* ast2obj_int(long b)
|
||||||
(cons.name, cons.name), 1)
|
(cons.name, cons.name), 1)
|
||||||
self.emit("if (!%s_singleton) return 0;" % cons.name, 1)
|
self.emit("if (!%s_singleton) return 0;" % cons.name, 1)
|
||||||
|
|
||||||
|
|
||||||
def parse_version(mod):
|
def parse_version(mod):
|
||||||
return mod.version.value[12:-3]
|
return mod.version.value[12:-3]
|
||||||
|
|
||||||
|
@ -557,6 +777,7 @@ class ASTModuleVisitor(PickleVisitor):
|
||||||
def addObj(self, name):
|
def addObj(self, name):
|
||||||
self.emit('if (PyDict_SetItemString(d, "%s", (PyObject*)%s_type) < 0) return;' % (name, name), 1)
|
self.emit('if (PyDict_SetItemString(d, "%s", (PyObject*)%s_type) < 0) return;' % (name, name), 1)
|
||||||
|
|
||||||
|
|
||||||
_SPECIALIZED_SEQUENCES = ('stmt', 'expr')
|
_SPECIALIZED_SEQUENCES = ('stmt', 'expr')
|
||||||
|
|
||||||
def find_sequence(fields, doing_specialization):
|
def find_sequence(fields, doing_specialization):
|
||||||
|
@ -582,6 +803,7 @@ class StaticVisitor(PickleVisitor):
|
||||||
def visit(self, object):
|
def visit(self, object):
|
||||||
self.emit(self.CODE, 0, reflow=False)
|
self.emit(self.CODE, 0, reflow=False)
|
||||||
|
|
||||||
|
|
||||||
class ObjVisitor(PickleVisitor):
|
class ObjVisitor(PickleVisitor):
|
||||||
|
|
||||||
def func_begin(self, name):
|
def func_begin(self, name):
|
||||||
|
@ -632,8 +854,12 @@ class ObjVisitor(PickleVisitor):
|
||||||
self.emit("case %s:" % t.name, 2)
|
self.emit("case %s:" % t.name, 2)
|
||||||
self.emit("Py_INCREF(%s_singleton);" % t.name, 3)
|
self.emit("Py_INCREF(%s_singleton);" % t.name, 3)
|
||||||
self.emit("return %s_singleton;" % t.name, 3)
|
self.emit("return %s_singleton;" % t.name, 3)
|
||||||
|
self.emit("default:" % name, 2)
|
||||||
|
self.emit('/* should never happen, but just in case ... */', 3)
|
||||||
|
code = "PyErr_Format(PyExc_SystemError, \"unknown %s found\");" % name
|
||||||
|
self.emit(code, 3, reflow=False)
|
||||||
|
self.emit("return NULL;", 3)
|
||||||
self.emit("}", 1)
|
self.emit("}", 1)
|
||||||
self.emit("return NULL; /* cannot happen */", 1)
|
|
||||||
self.emit("}", 0)
|
self.emit("}", 0)
|
||||||
|
|
||||||
def visitProduct(self, prod, name):
|
def visitProduct(self, prod, name):
|
||||||
|
@ -707,6 +933,27 @@ PyObject* PyAST_mod2obj(mod_ty t)
|
||||||
init_types();
|
init_types();
|
||||||
return ast2obj_mod(t);
|
return ast2obj_mod(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena)
|
||||||
|
{
|
||||||
|
mod_ty res;
|
||||||
|
init_types();
|
||||||
|
if (!PyObject_IsInstance(ast, mod_type)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "expected either Module, Interactive "
|
||||||
|
"or Expression node");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (obj2ast_mod(ast, &res, arena) != 0)
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PyAST_Check(PyObject* obj)
|
||||||
|
{
|
||||||
|
init_types();
|
||||||
|
return PyObject_IsInstance(obj, (PyObject*)AST_type);
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class ChainOfVisitors:
|
class ChainOfVisitors:
|
||||||
|
@ -750,6 +997,8 @@ def main(srcfile):
|
||||||
)
|
)
|
||||||
c.visit(mod)
|
c.visit(mod)
|
||||||
f.write("PyObject* PyAST_mod2obj(mod_ty t);\n")
|
f.write("PyObject* PyAST_mod2obj(mod_ty t);\n")
|
||||||
|
print >>f, "mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena);"
|
||||||
|
print >>f, "int PyAST_Check(PyObject* obj);"
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if SRC_DIR:
|
if SRC_DIR:
|
||||||
|
@ -764,8 +1013,10 @@ def main(srcfile):
|
||||||
v = ChainOfVisitors(
|
v = ChainOfVisitors(
|
||||||
PyTypesDeclareVisitor(f),
|
PyTypesDeclareVisitor(f),
|
||||||
PyTypesVisitor(f),
|
PyTypesVisitor(f),
|
||||||
|
Obj2ModPrototypeVisitor(f),
|
||||||
FunctionVisitor(f),
|
FunctionVisitor(f),
|
||||||
ObjVisitor(f),
|
ObjVisitor(f),
|
||||||
|
Obj2ModVisitor(f),
|
||||||
ASTModuleVisitor(f),
|
ASTModuleVisitor(f),
|
||||||
PartingShots(f),
|
PartingShots(f),
|
||||||
)
|
)
|
||||||
|
|
3116
Python/Python-ast.c
3116
Python/Python-ast.c
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
||||||
/* Built-in functions */
|
/* Built-in functions */
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "Python-ast.h"
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "code.h"
|
#include "code.h"
|
||||||
|
@ -527,22 +528,6 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
cf.cf_flags = supplied_flags | PyCF_SOURCE_IS_UTF8;
|
cf.cf_flags = supplied_flags | PyCF_SOURCE_IS_UTF8;
|
||||||
|
|
||||||
str = source_as_string(cmd);
|
|
||||||
if (str == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (strcmp(startstr, "exec") == 0)
|
|
||||||
start = Py_file_input;
|
|
||||||
else if (strcmp(startstr, "eval") == 0)
|
|
||||||
start = Py_eval_input;
|
|
||||||
else if (strcmp(startstr, "single") == 0)
|
|
||||||
start = Py_single_input;
|
|
||||||
else {
|
|
||||||
PyErr_SetString(PyExc_ValueError,
|
|
||||||
"compile() arg 3 must be 'exec' or 'eval' or 'single'");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supplied_flags &
|
if (supplied_flags &
|
||||||
~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_DONT_IMPLY_DEDENT | PyCF_ONLY_AST))
|
~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_DONT_IMPLY_DEDENT | PyCF_ONLY_AST))
|
||||||
{
|
{
|
||||||
|
@ -555,6 +540,48 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
if (!dont_inherit) {
|
if (!dont_inherit) {
|
||||||
PyEval_MergeCompilerFlags(&cf);
|
PyEval_MergeCompilerFlags(&cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PyAST_Check(cmd)) {
|
||||||
|
PyObject *result;
|
||||||
|
if (supplied_flags & PyCF_ONLY_AST) {
|
||||||
|
Py_INCREF(cmd);
|
||||||
|
result = cmd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyArena *arena;
|
||||||
|
mod_ty mod;
|
||||||
|
|
||||||
|
arena = PyArena_New();
|
||||||
|
mod = PyAST_obj2mod(cmd, arena);
|
||||||
|
if (mod == NULL) {
|
||||||
|
PyArena_Free(arena);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result = (PyObject*)PyAST_Compile(mod, filename,
|
||||||
|
&cf, arena);
|
||||||
|
PyArena_Free(arena);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: is it possible to pass start to the PyAST_ branch? */
|
||||||
|
if (strcmp(startstr, "exec") == 0)
|
||||||
|
start = Py_file_input;
|
||||||
|
else if (strcmp(startstr, "eval") == 0)
|
||||||
|
start = Py_eval_input;
|
||||||
|
else if (strcmp(startstr, "single") == 0)
|
||||||
|
start = Py_single_input;
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"compile() arg 3 must be 'exec'"
|
||||||
|
"or 'eval' or 'single'");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = source_as_string(cmd);
|
||||||
|
if (str == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return Py_CompileStringFlags(str, filename, start, &cf);
|
return Py_CompileStringFlags(str, filename, start, &cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2356,8 +2356,11 @@ unaryop(unaryop_ty op)
|
||||||
return UNARY_POSITIVE;
|
return UNARY_POSITIVE;
|
||||||
case USub:
|
case USub:
|
||||||
return UNARY_NEGATIVE;
|
return UNARY_NEGATIVE;
|
||||||
|
default:
|
||||||
|
PyErr_Format(PyExc_SystemError,
|
||||||
|
"unary op %d should not be possible", op);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2388,8 +2391,11 @@ binop(struct compiler *c, operator_ty op)
|
||||||
return BINARY_AND;
|
return BINARY_AND;
|
||||||
case FloorDiv:
|
case FloorDiv:
|
||||||
return BINARY_FLOOR_DIVIDE;
|
return BINARY_FLOOR_DIVIDE;
|
||||||
|
default:
|
||||||
|
PyErr_Format(PyExc_SystemError,
|
||||||
|
"binary op %d should not be possible", op);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2416,8 +2422,9 @@ cmpop(cmpop_ty op)
|
||||||
return PyCmp_IN;
|
return PyCmp_IN;
|
||||||
case NotIn:
|
case NotIn:
|
||||||
return PyCmp_NOT_IN;
|
return PyCmp_NOT_IN;
|
||||||
|
default:
|
||||||
|
return PyCmp_BAD;
|
||||||
}
|
}
|
||||||
return PyCmp_BAD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2448,10 +2455,11 @@ inplace_binop(struct compiler *c, operator_ty op)
|
||||||
return INPLACE_AND;
|
return INPLACE_AND;
|
||||||
case FloorDiv:
|
case FloorDiv:
|
||||||
return INPLACE_FLOOR_DIVIDE;
|
return INPLACE_FLOOR_DIVIDE;
|
||||||
|
default:
|
||||||
|
PyErr_Format(PyExc_SystemError,
|
||||||
|
"inplace binary op %d should not be possible", op);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
PyErr_Format(PyExc_SystemError,
|
|
||||||
"inplace binary op %d should not be possible", op);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue