mirror of
https://github.com/python/cpython.git
synced 2026-07-26 11:52:27 -04:00
9d231cbc93
The builtin compile() accepts an AST object since Python 2.6, but symtable.symtable() only accepted str and bytes, although the implementation builds the symbol table from an AST anyway. Accept an AST object as well: convert it for the requested compile type, validate it, honor future statements found in the tree, and build the symbol table the same way the compiler does. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
181 lines
5.6 KiB
C
181 lines
5.6 KiB
C
#include "Python.h"
|
|
#include "pycore_ast.h" // PyAST_Check()
|
|
#include "pycore_pyarena.h" // _PyArena_New()
|
|
#include "pycore_pythonrun.h" // _Py_SourceAsString()
|
|
#include "pycore_symtable.h" // struct symtable
|
|
|
|
#include "clinic/symtablemodule.c.h"
|
|
/*[clinic input]
|
|
module _symtable
|
|
[clinic start generated code]*/
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f4685845a7100605]*/
|
|
|
|
|
|
static struct symtable *
|
|
symtable_from_ast(PyObject *source, PyObject *filename, int compile_mode)
|
|
{
|
|
PyArena *arena = _PyArena_New();
|
|
if (arena == NULL) {
|
|
return NULL;
|
|
}
|
|
struct symtable *st = NULL;
|
|
mod_ty mod = PyAST_obj2mod(source, arena, compile_mode);
|
|
if (mod == NULL || !_PyAST_Validate(mod)) {
|
|
goto finally;
|
|
}
|
|
_PyFutureFeatures future;
|
|
if (!_PyFuture_FromAST(mod, filename, &future)) {
|
|
goto finally;
|
|
}
|
|
st = _PySymtable_Build(mod, filename, &future);
|
|
finally:
|
|
_PyArena_Free(arena);
|
|
return st;
|
|
}
|
|
|
|
|
|
/*[clinic input]
|
|
_symtable.symtable
|
|
|
|
source: object
|
|
filename: unicode_fs_decoded
|
|
startstr: str
|
|
/
|
|
*
|
|
module as modname: object = None
|
|
|
|
Return symbol and scope dictionaries used internally by compiler.
|
|
|
|
The source can be a string, a bytes object, or an AST object.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
_symtable_symtable_impl(PyObject *module, PyObject *source,
|
|
PyObject *filename, const char *startstr,
|
|
PyObject *modname)
|
|
/*[clinic end generated code: output=235ec5a87a9ce178 input=6cadac0485f576a7]*/
|
|
{
|
|
struct symtable *st;
|
|
PyObject *t;
|
|
int compile_mode;
|
|
|
|
if (strcmp(startstr, "exec") == 0)
|
|
compile_mode = 0;
|
|
else if (strcmp(startstr, "eval") == 0)
|
|
compile_mode = 1;
|
|
else if (strcmp(startstr, "single") == 0)
|
|
compile_mode = 2;
|
|
else {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"symtable() arg 3 must be 'exec' or 'eval' or 'single'");
|
|
return NULL;
|
|
}
|
|
if (modname == Py_None) {
|
|
modname = NULL;
|
|
}
|
|
else if (!PyUnicode_Check(modname)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"symtable() argument 'module' must be str or None, not %T",
|
|
modname);
|
|
return NULL;
|
|
}
|
|
|
|
if (PyAST_Check(source)) {
|
|
st = symtable_from_ast(source, filename, compile_mode);
|
|
}
|
|
else {
|
|
static const int starts[] = {
|
|
Py_file_input, Py_eval_input, Py_single_input};
|
|
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
|
PyObject *source_copy = NULL;
|
|
|
|
cf.cf_flags = PyCF_SOURCE_IS_UTF8;
|
|
const char *str = _Py_SourceAsString(source, "symtable",
|
|
"string, bytes or AST",
|
|
&cf, &source_copy);
|
|
if (str == NULL) {
|
|
return NULL;
|
|
}
|
|
st = _Py_SymtableStringObjectFlags(str, filename,
|
|
starts[compile_mode], &cf,
|
|
modname);
|
|
Py_XDECREF(source_copy);
|
|
}
|
|
if (st == NULL) {
|
|
return NULL;
|
|
}
|
|
t = Py_NewRef(st->st_top);
|
|
_PySymtable_Free(st);
|
|
return t;
|
|
}
|
|
|
|
static PyMethodDef symtable_methods[] = {
|
|
_SYMTABLE_SYMTABLE_METHODDEF
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static int
|
|
symtable_init_constants(PyObject *m)
|
|
{
|
|
if (PyModule_AddIntMacro(m, USE) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_GLOBAL) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_NONLOCAL) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_LOCAL) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_PARAM) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_TYPE_PARAM) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_FREE_CLASS) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_IMPORT) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_BOUND) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_ANNOT) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_COMP_ITER) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, DEF_COMP_CELL) < 0) return -1;
|
|
|
|
if (PyModule_AddIntConstant(m, "TYPE_FUNCTION", FunctionBlock) < 0)
|
|
return -1;
|
|
if (PyModule_AddIntConstant(m, "TYPE_CLASS", ClassBlock) < 0)
|
|
return -1;
|
|
if (PyModule_AddIntConstant(m, "TYPE_MODULE", ModuleBlock) < 0)
|
|
return -1;
|
|
if (PyModule_AddIntConstant(m, "TYPE_ANNOTATION", AnnotationBlock) < 0)
|
|
return -1;
|
|
if (PyModule_AddIntConstant(m, "TYPE_TYPE_ALIAS", TypeAliasBlock) < 0)
|
|
return -1;
|
|
if (PyModule_AddIntConstant(m, "TYPE_TYPE_PARAMETERS", TypeParametersBlock) < 0)
|
|
return -1;
|
|
if (PyModule_AddIntConstant(m, "TYPE_TYPE_VARIABLE", TypeVariableBlock) < 0)
|
|
return -1;
|
|
|
|
if (PyModule_AddIntMacro(m, LOCAL) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, GLOBAL_EXPLICIT) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, GLOBAL_IMPLICIT) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, FREE) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, CELL) < 0) return -1;
|
|
|
|
if (PyModule_AddIntConstant(m, "SCOPE_OFF", SCOPE_OFFSET) < 0) return -1;
|
|
if (PyModule_AddIntMacro(m, SCOPE_MASK) < 0) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PyModuleDef_Slot symtable_slots[] = {
|
|
_Py_ABI_SLOT,
|
|
{Py_mod_exec, symtable_init_constants},
|
|
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
|
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
|
{0, NULL}
|
|
};
|
|
|
|
static struct PyModuleDef symtablemodule = {
|
|
PyModuleDef_HEAD_INIT,
|
|
.m_name = "_symtable",
|
|
.m_size = 0,
|
|
.m_methods = symtable_methods,
|
|
.m_slots = symtable_slots,
|
|
};
|
|
|
|
PyMODINIT_FUNC
|
|
PyInit__symtable(void)
|
|
{
|
|
return PyModuleDef_Init(&symtablemodule);
|
|
}
|