| #include "Python.h" |
| #include "compile.h" |
| #include "symtable.h" |
| #include "graminit.h" |
| #include "structmember.h" |
| |
| /* The compiler uses this function to load a PySymtableEntry object |
| for a code block. Each block is loaded twice, once during the |
| symbol table pass and once during the code gen pass. Entries |
| created during the first pass are cached for the second pass, using |
| the st_symbols dictionary. |
| |
| The cache is keyed by st_nscopes. Each code block node in a |
| module's parse tree can be assigned a unique id based on the order |
| in which the nodes are visited by the compiler. This strategy |
| works so long as the symbol table and codegen passes visit the same |
| nodes in the same order. |
| */ |
| |
| |
| PyObject * |
| PySymtableEntry_New(struct symtable *st, char *name, int type, int lineno) |
| { |
| PySymtableEntryObject *ste = NULL; |
| PyObject *k, *v; |
| |
| k = PyInt_FromLong(st->st_nscopes++); |
| if (k == NULL) |
| goto fail; |
| v = PyDict_GetItem(st->st_symbols, k); |
| if (v) { |
| Py_DECREF(k); |
| Py_INCREF(v); |
| return v; |
| } |
| |
| ste = (PySymtableEntryObject *)PyObject_New(PySymtableEntryObject, |
| &PySymtableEntry_Type); |
| ste->ste_table = st; |
| ste->ste_id = k; |
| |
| v = PyString_FromString(name); |
| if (v == NULL) |
| goto fail; |
| ste->ste_name = v; |
| |
| v = PyDict_New(); |
| if (v == NULL) |
| goto fail; |
| ste->ste_symbols = v; |
| |
| v = PyList_New(0); |
| if (v == NULL) |
| goto fail; |
| ste->ste_varnames = v; |
| |
| v = PyList_New(0); |
| if (v == NULL) |
| goto fail; |
| ste->ste_children = v; |
| |
| ste->ste_optimized = 0; |
| ste->ste_opt_lineno = 0; |
| ste->ste_tmpname = 0; |
| ste->ste_lineno = lineno; |
| switch (type) { |
| case funcdef: |
| case lambdef: |
| ste->ste_type = TYPE_FUNCTION; |
| break; |
| case classdef: |
| ste->ste_type = TYPE_CLASS; |
| break; |
| case single_input: |
| case eval_input: |
| case file_input: |
| ste->ste_type = TYPE_MODULE; |
| break; |
| } |
| |
| if (st->st_cur == NULL) |
| ste->ste_nested = 0; |
| else if (st->st_cur->ste_nested |
| || st->st_cur->ste_type == TYPE_FUNCTION) |
| ste->ste_nested = 1; |
| else |
| ste->ste_nested = 0; |
| ste->ste_child_free = 0; |
| ste->ste_generator = 0; |
| |
| if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) |
| goto fail; |
| |
| return (PyObject *)ste; |
| fail: |
| Py_XDECREF(ste); |
| return NULL; |
| } |
| |
| static PyObject * |
| ste_repr(PySymtableEntryObject *ste) |
| { |
| char buf[256]; |
| |
| PyOS_snprintf(buf, sizeof(buf), |
| "<symtable entry %.100s(%ld), line %d>", |
| PyString_AS_STRING(ste->ste_name), |
| PyInt_AS_LONG(ste->ste_id), |
| ste->ste_lineno); |
| return PyString_FromString(buf); |
| } |
| |
| static void |
| ste_dealloc(PySymtableEntryObject *ste) |
| { |
| ste->ste_table = NULL; |
| Py_XDECREF(ste->ste_id); |
| Py_XDECREF(ste->ste_name); |
| Py_XDECREF(ste->ste_symbols); |
| Py_XDECREF(ste->ste_varnames); |
| Py_XDECREF(ste->ste_children); |
| PyObject_Del(ste); |
| } |
| |
| #define OFF(x) offsetof(PySymtableEntryObject, x) |
| |
| static PyMemberDef ste_memberlist[] = { |
| {"id", T_OBJECT, OFF(ste_id), READONLY}, |
| {"name", T_OBJECT, OFF(ste_name), READONLY}, |
| {"symbols", T_OBJECT, OFF(ste_symbols), READONLY}, |
| {"varnames", T_OBJECT, OFF(ste_varnames), READONLY}, |
| {"children", T_OBJECT, OFF(ste_children), READONLY}, |
| {"type", T_INT, OFF(ste_type), READONLY}, |
| {"lineno", T_INT, OFF(ste_lineno), READONLY}, |
| {"optimized",T_INT, OFF(ste_optimized), READONLY}, |
| {"nested", T_INT, OFF(ste_nested), READONLY}, |
| {NULL} |
| }; |
| |
| PyTypeObject PySymtableEntry_Type = { |
| PyObject_HEAD_INIT(&PyType_Type) |
| 0, |
| "symtable entry", |
| sizeof(PySymtableEntryObject), |
| 0, |
| (destructor)ste_dealloc, /* tp_dealloc */ |
| 0, /* tp_print */ |
| 0, /* tp_getattr */ |
| 0, /* tp_setattr */ |
| 0, /* tp_compare */ |
| (reprfunc)ste_repr, /* tp_repr */ |
| 0, /* tp_as_number */ |
| 0, /* tp_as_sequence */ |
| 0, /* tp_as_mapping */ |
| 0, /* tp_hash */ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| PyObject_GenericGetAttr, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| 0, /* tp_methods */ |
| ste_memberlist, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| 0, /* tp_init */ |
| 0, /* tp_alloc */ |
| 0, /* tp_new */ |
| }; |