示例#1
0
static int
analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
              PyObject *global)
{
    PyObject *name, *v, *local = NULL, *scope = NULL;
    PyObject *newbound = NULL, *newglobal = NULL;
    PyObject *newfree = NULL, *allfree = NULL;
    int i, success = 0;
    Py_ssize_t pos = 0;

    local = PyDict_New();  /* collect new names bound in block */
    if (!local)
        goto error;
    scope = PyDict_New(); /* collect scopes defined for each name */
    if (!scope)
        goto error;

    /* Allocate new global and bound variable dictionaries.  These
       dictionaries hold the names visible in nested blocks.  For
       ClassBlocks, the bound and global names are initialized
       before analyzing names, because class bindings aren't
       visible in methods.  For other blocks, they are initialized
       after names are analyzed.
     */

    /* TODO(jhylton): Package these dicts in a struct so that we
       can write reasonable helper functions?
    */
    newglobal = PyDict_New();
    if (!newglobal)
        goto error;
    newbound = PyDict_New();
    if (!newbound)
        goto error;
    newfree = PyDict_New();
    if (!newfree)
        goto error;

    if (ste->ste_type == ClassBlock) {
        if (PyDict_Update(newglobal, global) < 0)
            goto error;
        if (bound)
            if (PyDict_Update(newbound, bound) < 0)
                goto error;
    }

    while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
        long flags = PyInt_AS_LONG(v);
        if (!analyze_name(ste, scope, name, flags,
                          bound, local, free, global))
            goto error;
    }

    if (ste->ste_type != ClassBlock) {
        if (ste->ste_type == FunctionBlock) {
            if (PyDict_Update(newbound, local) < 0)
                goto error;
        }
        if (bound) {
            if (PyDict_Update(newbound, bound) < 0)
                goto error;
        }
        if (PyDict_Update(newglobal, global) < 0)
            goto error;
    }

    /* Recursively call analyze_block() on each child block.

       newbound, newglobal now contain the names visible in
       nested blocks.  The free variables in the children will
       be collected in allfree.
    */
    allfree = PyDict_New();
    if (!allfree)
        goto error;
    for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
        PyObject *c = PyList_GET_ITEM(ste->ste_children, i);
        PySTEntryObject* entry;
        assert(c && PySTEntry_Check(c));
        entry = (PySTEntryObject*)c;
        if (!analyze_child_block(entry, newbound, newfree, newglobal,
                                 allfree))
            goto error;
        if (entry->ste_free || entry->ste_child_free)
            ste->ste_child_free = 1;
    }

    if (PyDict_Update(newfree, allfree) < 0)
        goto error;
    if (ste->ste_type == FunctionBlock && !analyze_cells(scope, newfree))
        goto error;
    if (!update_symbols(ste->ste_symbols, scope, bound, newfree,
                        ste->ste_type == ClassBlock))
        goto error;
    if (!check_unoptimized(ste))
        goto error;

    if (PyDict_Update(free, newfree) < 0)
        goto error;
    success = 1;
 error:
    Py_XDECREF(local);
    Py_XDECREF(scope);
    Py_XDECREF(newbound);
    Py_XDECREF(newglobal);
    Py_XDECREF(newfree);
    Py_XDECREF(allfree);
    if (!success)
        assert(PyErr_Occurred());
    return success;
}
示例#2
0
static int
analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, 
	      PyObject *global)
{
	PyObject *name, *v, *local = NULL, *scope = NULL, *newbound = NULL;
	PyObject *newglobal = NULL, *newfree = NULL;
	int i, success = 0;
	Py_ssize_t pos = 0;

	local = PyDict_New();
	if (!local)
		goto error;
	scope = PyDict_New();
	if (!scope)
		goto error;
	newglobal = PyDict_New();
	if (!newglobal)
		goto error;
	newfree = PyDict_New();
	if (!newfree)
		goto error;
	newbound = PyDict_New();
	if (!newbound)
		goto error;

	if (ste->ste_type == ClassBlock) {
		/* make a copy of globals before calling analyze_name(),
		   because global statements in the class have no effect
		   on nested functions.
		*/
		if (PyDict_Update(newglobal, global) < 0)
			goto error;
		if (bound)
			if (PyDict_Update(newbound, bound) < 0)
				goto error;
	}

	assert(PySTEntry_Check(ste));
	assert(PyDict_Check(ste->ste_symbols));
	while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) {
		long flags = PyInt_AS_LONG(v);
		if (!analyze_name(ste, scope, name, flags, bound, local, free,
				  global))
			goto error;
	}

	if (ste->ste_type != ClassBlock) {
		if (ste->ste_type == FunctionBlock) {
			if (PyDict_Update(newbound, local) < 0)
				goto error;
		}
		if (bound) {
			if (PyDict_Update(newbound, bound) < 0)
				goto error;
		}
		if (PyDict_Update(newglobal, global) < 0)
			goto error;
	}

	/* Recursively call analyze_block() on each child block */
	for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
		PyObject *c = PyList_GET_ITEM(ste->ste_children, i);
		PySTEntryObject* entry;
		assert(c && PySTEntry_Check(c));
		entry = (PySTEntryObject*)c;
		if (!analyze_block(entry, newbound, newfree, newglobal))
			goto error;
		if (entry->ste_free || entry->ste_child_free)
			ste->ste_child_free = 1;
	}

	if (ste->ste_type == FunctionBlock && !analyze_cells(scope, newfree))
		goto error;
	if (!update_symbols(ste->ste_symbols, scope, bound, newfree,
			    ste->ste_type == ClassBlock))
		goto error;
	if (!check_unoptimized(ste))
		goto error;

	if (PyDict_Update(free, newfree) < 0)
		goto error;
	success = 1;
 error:
	Py_XDECREF(local);
	Py_XDECREF(scope);
	Py_XDECREF(newbound);
	Py_XDECREF(newglobal);
	Py_XDECREF(newfree);
	if (!success)
		assert(PyErr_Occurred());
	return success;
}