This is to answer the question: How to solve the scoping problem using a simple transform? (This might not be the proper solution, just investigating. I know too little about why the current variable scoping is broken.)
(Btw there's some rationale for doing this: It would closely emulate how the Python parser works when interpreting the module scope -- almost simulate running the module-level code (though with an eye only for the namespace handling). This kind of stuff (emulating the simple Python parser) is imnsho much easier to do with a visitor than in a recursive process.)
What one does: Transform every variable assignment, and reference, but the last one, to a temporary. I.e:
#!python import math f = 3 f = 34 + math.sin(f) class f: x = f x = 2*f x = f() def f(y): return x(y) def x(z): return 4
By a single pass (keeping track of names assigned to in AssignmentNodes and references to them in NameNode in dicts and lists) one can without much pain (= ~50 lines of "interesting but not really challenging code") transform this to (where each tmpx variable is a TempNode that doesn't name-clash with variables named tmpx, of course. Also the tmpx variables does not enter the module dict):
#!python tmp1 = 3 tmp2 = 34 + math.sin(tmp1) class tmp3: tmp4 = tmp2 x = tmp4 tmp5 = tmp3() def f(y): return x(y) # Python semantics is to keep x here now, and not tmp4 which is x at definition time? Transform can work either way. def tmp6(z): return 4
This will in turn cause static linking in the correct way everywhere.
In addition, some fudging of the function names stored etc. is needed (add an "should_appear_as" attribute to TempNode and use it in code generation of a function), but that appears to be it?
The same transform could easily raise an error when a global name is used before it is defined too.