@@ -377,8 +377,9 @@ PyST_GetScope(PySTEntryObject *ste, PyObject *name)
377377
378378/* Decide on scope of name, given flags.
379379
380- The dicts passed in as arguments are modified as necessary.
381- ste is passed so that flags can be updated.
380+ The namespace dictionaries may be modified to record information
381+ about the new name. For example, a new global will add an entry to
382+ global. A name that was global can be changed to local.
382383*/
383384
384385static int
@@ -454,7 +455,7 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
454455 explicit? It could also be global implicit.
455456 */
456457 if (global && PySet_Contains (global , name )) {
457- SET_SCOPE (scopes , name , GLOBAL_EXPLICIT );
458+ SET_SCOPE (scopes , name , GLOBAL_IMPLICIT );
458459 return 1 ;
459460 }
460461 if (ste -> ste_nested )
@@ -628,28 +629,56 @@ update_symbols(PyObject *symbols, PyObject *scopes,
628629}
629630
630631/* Make final symbol table decisions for block of ste.
632+
631633 Arguments:
632634 ste -- current symtable entry (input/output)
633- bound -- set of variables bound in enclosing scopes (input)
635+ bound -- set of variables bound in enclosing scopes (input). bound
636+ is NULL for module blocks.
634637 free -- set of free variables in enclosed scopes (output)
635638 globals -- set of declared global variables in enclosing scopes (input)
639+
640+ The implementation uses two mutually recursive functions,
641+ analyze_block() and analyze_child_block(). analyze_block() is
642+ responsible for analyzing the individual names defined in a block.
643+ analyze_child_block() prepares temporary namespace dictionaries
644+ used to evaluated nested blocks.
645+
646+ The two functions exist because a child block should see the name
647+ bindings of its enclosing blocks, but those bindings should not
648+ propagate back to a parent block.
636649*/
637650
651+ static int
652+ analyze_child_block (PySTEntryObject * entry , PyObject * bound , PyObject * free ,
653+ PyObject * global , PyObject * child_free );
654+
638655static int
639656analyze_block (PySTEntryObject * ste , PyObject * bound , PyObject * free ,
640657 PyObject * global )
641658{
642659 PyObject * name , * v , * local = NULL , * scopes = NULL , * newbound = NULL ;
643- PyObject * newglobal = NULL , * newfree = NULL ;
660+ PyObject * newglobal = NULL , * newfree = NULL , * allfree = NULL ;
644661 int i , success = 0 ;
645662 Py_ssize_t pos = 0 ;
646663
647- scopes = PyDict_New ();
648- if (!scopes )
649- goto error ;
650- local = PySet_New (NULL );
664+ local = PySet_New (NULL ); /* collect new names bound in block */
651665 if (!local )
652666 goto error ;
667+ scopes = PyDict_New (); /* collect scopes defined for each name */
668+ if (!scopes )
669+ goto error ;
670+
671+ /* Allocate new global and bound variable dictionaries. These
672+ dictionaries hold the names visible in nested blocks. For
673+ ClassBlocks, the bound and global names are initialized
674+ before analyzing names, because class bindings aren't
675+ visible in methods. For other blocks, they are initialized
676+ after names are analyzed.
677+ */
678+
679+ /* TODO(jhylton): Package these dicts in a struct so that we
680+ can write reasonable helper functions?
681+ */
653682 newglobal = PySet_New (NULL );
654683 if (!newglobal )
655684 goto error ;
@@ -666,25 +695,22 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
666695 this one.
667696 */
668697 if (ste -> ste_type == ClassBlock ) {
698+ /* Pass down known globals */
699+ if (!PyNumber_InPlaceOr (newglobal , global ))
700+ goto error ;
701+ Py_DECREF (newglobal );
669702 /* Pass down previously bound symbols */
670703 if (bound ) {
671704 if (!PyNumber_InPlaceOr (newbound , bound ))
672705 goto error ;
673706 Py_DECREF (newbound );
674707 }
675- /* Pass down known globals */
676- if (!PyNumber_InPlaceOr (newglobal , global ))
677- goto error ;
678- Py_DECREF (newglobal );
679708 }
680709
681- /* Analyze symbols in current scope */
682- assert (PySTEntry_Check (ste ));
683- assert (PyDict_Check (ste -> ste_symbols ));
684710 while (PyDict_Next (ste -> ste_symbols , & pos , & name , & v )) {
685711 long flags = PyLong_AS_LONG (v );
686- if (!analyze_name (ste , scopes , name , flags , bound , local , free ,
687- global ))
712+ if (!analyze_name (ste , scopes , name , flags ,
713+ bound , local , free , global ))
688714 goto error ;
689715 }
690716
@@ -716,19 +742,31 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
716742 goto error ;
717743 }
718744
719- /* Recursively call analyze_block() on each child block */
745+ /* Recursively call analyze_block() on each child block.
746+
747+ newbound, newglobal now contain the names visible in
748+ nested blocks. The free variables in the children will
749+ be collected in allfree.
750+ */
751+ allfree = PySet_New (NULL );
752+ if (!allfree )
753+ goto error ;
720754 for (i = 0 ; i < PyList_GET_SIZE (ste -> ste_children ); ++ i ) {
721755 PyObject * c = PyList_GET_ITEM (ste -> ste_children , i );
722756 PySTEntryObject * entry ;
723757 assert (c && PySTEntry_Check (c ));
724758 entry = (PySTEntryObject * )c ;
725- if (!analyze_block (entry , newbound , newfree , newglobal ))
759+ if (!analyze_child_block (entry , newbound , newfree , newglobal ,
760+ allfree ))
726761 goto error ;
727762 /* Check if any children have free variables */
728763 if (entry -> ste_free || entry -> ste_child_free )
729764 ste -> ste_child_free = 1 ;
730765 }
731766
767+ if (PyNumber_InPlaceOr (newfree , allfree ) < 0 )
768+ goto error ;
769+
732770 /* Check if any local variables must be converted to cell variables */
733771 if (ste -> ste_type == FunctionBlock && !analyze_cells (scopes , newfree ,
734772 NULL ))
@@ -753,11 +791,47 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
753791 Py_XDECREF (newbound );
754792 Py_XDECREF (newglobal );
755793 Py_XDECREF (newfree );
794+ Py_XDECREF (allfree );
756795 if (!success )
757796 assert (PyErr_Occurred ());
758797 return success ;
759798}
760799
800+ static int
801+ analyze_child_block (PySTEntryObject * entry , PyObject * bound , PyObject * free ,
802+ PyObject * global , PyObject * child_free )
803+ {
804+ PyObject * temp_bound = NULL , * temp_global = NULL , * temp_free = NULL ;
805+ int success = 0 ;
806+
807+ /* Copy the bound and global dictionaries.
808+
809+ These dictionary are used by all blocks enclosed by the
810+ current block. The analyze_block() call modifies these
811+ dictionaries.
812+
813+ */
814+ temp_bound = PySet_New (bound );
815+ if (!temp_bound )
816+ goto error ;
817+ temp_free = PySet_New (free );
818+ if (!temp_free )
819+ goto error ;
820+ temp_global = PySet_New (global );
821+ if (!temp_global )
822+ goto error ;
823+
824+ if (!analyze_block (entry , temp_bound , temp_free , temp_global ))
825+ goto error ;
826+ success = PyNumber_InPlaceOr (child_free , temp_free ) >= 0 ;
827+ success = 1 ;
828+ error :
829+ Py_XDECREF (temp_bound );
830+ Py_XDECREF (temp_free );
831+ Py_XDECREF (temp_global );
832+ return success ;
833+ }
834+
761835static int
762836symtable_analyze (struct symtable * st )
763837{
0 commit comments