|
|
|
#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 */
|
|
|
|
};
|