Introduce a context manager for compiler.returnable

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2013-04-21 00:17:30 +02:00
parent adecd32897
commit 7066d53b02
3 changed files with 82 additions and 60 deletions

View File

@ -33,7 +33,7 @@ from hy.models.list import HyList
from hy.models.dict import HyDict from hy.models.dict import HyDict
from hy.models.keyword import HyKeyword from hy.models.keyword import HyKeyword
from hy.util import flatten_literal_list, str_type from hy.util import flatten_literal_list, str_type, temporary_attribute_value
from collections import defaultdict from collections import defaultdict
import codecs import codecs
@ -129,6 +129,9 @@ class HyASTCompiler(object):
self.anon_fn_count = 0 self.anon_fn_count = 0
self.imports = defaultdict(list) self.imports = defaultdict(list)
def being_returnable(self, v):
return temporary_attribute_value(self, "returnable", v)
def compile(self, tree): def compile(self, tree):
try: try:
for _type in _compile_table: for _type in _compile_table:
@ -951,9 +954,7 @@ class HyASTCompiler(object):
@builds("foreach") @builds("foreach")
@checkargs(min=1) @checkargs(min=1)
def compile_for_expression(self, expression): def compile_for_expression(self, expression):
ret_status = self.returnable with self.being_returnable(False):
self.returnable = False
expression.pop(0) # for expression.pop(0) # for
name, iterable = expression.pop(0) name, iterable = expression.pop(0)
target = self._storeize(self.compile_symbol(name)) target = self._storeize(self.compile_symbol(name))
@ -963,7 +964,8 @@ class HyASTCompiler(object):
if expression and expression[-1][0] == HySymbol("else"): if expression and expression[-1][0] == HySymbol("else"):
else_expr = expression.pop() else_expr = expression.pop()
if len(else_expr) > 2: if len(else_expr) > 2:
raise HyTypeError(else_expr, raise HyTypeError(
else_expr,
"`else' statement in `foreach' is too long") "`else' statement in `foreach' is too long")
elif len(else_expr) == 2: elif len(else_expr) == 2:
orelse = self._code_branch( orelse = self._code_branch(
@ -981,7 +983,6 @@ class HyASTCompiler(object):
expression.start_column), expression.start_column),
orelse=orelse) orelse=orelse)
self.returnable = ret_status
return ret return ret
@builds("while") @builds("while")
@ -1012,22 +1013,20 @@ class HyASTCompiler(object):
def compile_fn_expression(self, expression): def compile_fn_expression(self, expression):
expression.pop(0) # fn expression.pop(0) # fn
ret_status = self.returnable
self.anon_fn_count += 1 self.anon_fn_count += 1
name = "_hy_anon_fn_%d" % (self.anon_fn_count) name = "_hy_anon_fn_%d" % (self.anon_fn_count)
sig = expression.pop(0) sig = expression.pop(0)
body = [] body = []
if expression != []: if expression != []:
self.returnable = True with self.being_returnable(True):
tailop = self.compile(expression.pop(-1)) tailop = self.compile(expression.pop(-1))
self.returnable = False with self.being_returnable(False):
for el in expression: for el in expression:
body.append(self.compile(el)) body.append(self.compile(el))
body.append(tailop) body.append(tailop)
self.returnable = True with self.being_returnable(True):
body = self._code_branch(body, body = self._code_branch(body,
expression.start_line, expression.start_line,
expression.start_column) expression.start_column)
@ -1052,7 +1051,6 @@ class HyASTCompiler(object):
body=body, body=body,
decorator_list=[]) decorator_list=[])
self.returnable = ret_status
return ret return ret
@builds(HyInteger) @builds(HyInteger)

View File

@ -1,4 +1,5 @@
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org> # Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
# Copyright (c) 2013 Julien Danjou <julien@danjou.info>
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"), # copy of this software and associated documentation files (the "Software"),
@ -18,6 +19,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
import contextlib
import sys import sys
@ -27,6 +29,15 @@ else:
str_type = unicode str_type = unicode
@contextlib.contextmanager
def temporary_attribute_value(obj, attribute, value):
"""Temporarily switch an object attribute value to another value."""
original_value = getattr(obj, attribute)
setattr(obj, attribute, value)
yield
setattr(obj, attribute, original_value)
def flatten_literal_list(entry): def flatten_literal_list(entry):
for e in entry: for e in entry:
if type(e) == list: if type(e) == list:

13
tests/test_util.py Normal file
View File

@ -0,0 +1,13 @@
from hy import util
def test_temporary_attribute_value():
class O(object):
def __init__(self):
self.foobar = 0
o = O()
with util.temporary_attribute_value(o, "foobar", 42):
assert o.foobar == 42
assert o.foobar == 0