Commit d8813f05 authored by Stefan Behnel's avatar Stefan Behnel

manual merge of Haoyu's nonlocal implementation

parent 7d1a5f54
...@@ -3434,6 +3434,24 @@ class GlobalNode(StatNode): ...@@ -3434,6 +3434,24 @@ class GlobalNode(StatNode):
pass pass
class NonlocalNode(StatNode):
# Nonlocal variable declaration via the 'nonlocal' keyword.
#
# names [string]
child_attrs = []
def analyse_declarations(self, env):
for name in self.names:
env.declare_nonlocal(name, self.pos)
def analyse_expressions(self, env):
pass
def generate_execution_code(self, code):
pass
class ExprStatNode(StatNode): class ExprStatNode(StatNode):
# Expression used as a statement. # Expression used as a statement.
# #
......
...@@ -84,6 +84,7 @@ cdef p_genexp(PyrexScanner s, expr) ...@@ -84,6 +84,7 @@ cdef p_genexp(PyrexScanner s, expr)
#------------------------------------------------------- #-------------------------------------------------------
cdef p_global_statement(PyrexScanner s) cdef p_global_statement(PyrexScanner s)
cdef p_nonlocal_statement(PyrexScanner s)
cdef p_expression_or_assignment(PyrexScanner s) cdef p_expression_or_assignment(PyrexScanner s)
cdef p_print_statement(PyrexScanner s) cdef p_print_statement(PyrexScanner s)
cdef p_exec_statement(PyrexScanner s) cdef p_exec_statement(PyrexScanner s)
......
...@@ -1047,6 +1047,12 @@ def p_global_statement(s): ...@@ -1047,6 +1047,12 @@ def p_global_statement(s):
names = p_ident_list(s) names = p_ident_list(s)
return Nodes.GlobalNode(pos, names = names) return Nodes.GlobalNode(pos, names = names)
def p_nonlocal_statement(s):
pos = s.position()
s.next()
names = p_ident_list(s)
return Nodes.NonlocalNode(pos, names = names)
def p_expression_or_assignment(s): def p_expression_or_assignment(s):
expr_list = [p_testlist_star_expr(s)] expr_list = [p_testlist_star_expr(s)]
while s.sy == '=': while s.sy == '=':
...@@ -1600,6 +1606,8 @@ def p_simple_statement(s, first_statement = 0): ...@@ -1600,6 +1606,8 @@ def p_simple_statement(s, first_statement = 0):
#print "p_simple_statement:", s.sy, s.systring ### #print "p_simple_statement:", s.sy, s.systring ###
if s.sy == 'global': if s.sy == 'global':
node = p_global_statement(s) node = p_global_statement(s)
elif s.sy == 'nonlocal':
node = p_nonlocal_statement(s)
elif s.sy == 'print': elif s.sy == 'print':
node = p_print_statement(s) node = p_print_statement(s)
elif s.sy == 'exec': elif s.sy == 'exec':
......
...@@ -36,7 +36,7 @@ def get_lexicon(): ...@@ -36,7 +36,7 @@ def get_lexicon():
#------------------------------------------------------------------ #------------------------------------------------------------------
py_reserved_words = [ py_reserved_words = [
"global", "def", "class", "print", "del", "pass", "break", "global", "nonlocal", "def", "class", "print", "del", "pass", "break",
"continue", "return", "raise", "import", "exec", "try", "continue", "return", "raise", "import", "exec", "try",
"except", "finally", "while", "if", "elif", "else", "for", "except", "finally", "while", "if", "elif", "else", "for",
"in", "assert", "and", "or", "not", "is", "in", "lambda", "in", "assert", "and", "or", "not", "is", "in", "lambda",
......
...@@ -1272,6 +1272,15 @@ class LocalScope(Scope): ...@@ -1272,6 +1272,15 @@ class LocalScope(Scope):
entry = self.global_scope().lookup_target(name) entry = self.global_scope().lookup_target(name)
self.entries[name] = entry self.entries[name] = entry
def declare_nonlocal(self, name, pos):
# Pull entry from outer scope into local scope
if self.lookup_here(name):
warning(pos, "'%s' redeclared" % name, 0)
else:
entry = self.lookup(name)
if entry is None or not entry.from_closure:
error(pos, "no binding for nonlocal '%s' found" % name)
def lookup(self, name): def lookup(self, name):
# Look up name in this scope or an enclosing one. # Look up name in this scope or an enclosing one.
# Return None if not found. # Return None if not found.
......
...@@ -215,7 +215,8 @@ class SimpleAssignmentTypeInferer(object): ...@@ -215,7 +215,8 @@ class SimpleAssignmentTypeInferer(object):
# TODO: Implement a real type inference algorithm. # TODO: Implement a real type inference algorithm.
# (Something more powerful than just extending this one...) # (Something more powerful than just extending this one...)
def infer_types(self, scope): def infer_types(self, scope):
enabled = not scope.is_closure_scope and scope.directives['infer_types'] closure_or_inner = scope.is_closure_scope or (scope.outer_scope and scope.outer_scope.is_closure_scope)
enabled = not closure_or_inner and scope.directives['infer_types']
verbose = scope.directives['infer_types.verbose'] verbose = scope.directives['infer_types.verbose']
if enabled == True: if enabled == True:
spanning_type = aggressive_spanning_type spanning_type = aggressive_spanning_type
......
def simple():
"""
>>> simple()
1
2
"""
x = 1
y = 2
def f():
nonlocal x
nonlocal x, y
print(x)
print(y)
f()
def assign():
"""
>>> assign()
1
"""
xx = 0
def ff():
nonlocal xx
xx += 1
print(xx)
ff()
def nested():
"""
>>> nested()
1
"""
x = 0
def fx():
def gx():
nonlocal x
x=1
print(x)
return gx
fx()()
def arg(x):
"""
>>> arg('x')
xyy
"""
def appendy():
nonlocal x
x += 'y'
x+='y'
appendy()
print x
return
def argtype(int n):
"""
>>> argtype(0)
1
"""
def inc():
nonlocal n
n += 1
inc()
print n
return
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment