Skip to content

Commit

Permalink
Refactor out a method having common code for sequence unpacking.
Browse files Browse the repository at this point in the history
  • Loading branch information
stephan-hof committed Nov 29, 2016
1 parent ee1d514 commit 292601d
Showing 1 changed file with 65 additions and 44 deletions.
109 changes: 65 additions & 44 deletions src/RestrictedPython/transformer.py
Expand Up @@ -373,6 +373,63 @@ def protect_unpack_sequence(self, target, value):
args=[value, spec, ast.Name('_getiter_', ast.Load())],
keywords=[])

def gen_unpack_wrapper(self, node, target, ctx='store'):
"""Helper function to protect tuple unpacks.
node: used to copy the locations for the new nodes.
target: is the tuple which must be protected.
ctx: Defines the context of the returned temporary node.
It returns a tuple with two element.
Element 1: Is a temporary name node which must be used to
replace the target.
The context (store, param) is defined
by the 'ctx' parameter..
Element 2: Is a try .. finally where the body performs the
protected tuple unpack of the temporary variable
into the original target.
"""

# Generate a tmp name to replace the tuple with.
tmp_name = self.gen_tmp_name()

# Generates an expressions which protects the unpack.
# converter looks like 'wrapper(tmp_name)'.
# 'wrapper' takes care to protect sequence unpacking with _getiter_.
converter = self.protect_unpack_sequence(
target,
ast.Name(tmp_name, ast.Load()))

# Assign the expression to the original names.
# Cleanup the temporary variable.
# Generates:
# try:
# # converter is 'wrapper(tmp_name)'
# arg = converter
# finally:
# del tmp_arg
cleanup = ast.TryFinally(
body=[ast.Assign(targets=[target], value=converter)],
finalbody=[self.gen_del_stmt(tmp_name)]
)

if ctx == 'store':
ctx = ast.Store()
elif ctx == 'param':
ctx = ast.Param()
else:
raise Exception('Unsupported context type.')

# This node is used to catch the tuple in a tmp variable.
tmp_target = ast.Name(tmp_name, ctx)

copy_locations(tmp_target, node)
copy_locations(cleanup, node)

return (tmp_target, cleanup)

def gen_none_node(self):
if version >= (3, 4):
return ast.NameConstant(value=None)
Expand Down Expand Up @@ -1313,28 +1370,13 @@ def visit_ExceptHandler(self, node):
if not isinstance(node.name, ast.Tuple):
return node

# Generate a tmp name to replace the tuple with.
tmp_name = self.gen_tmp_name()

# Generates an expressions which protects the unpack.
converter = self.protect_unpack_sequence(
node.name,
ast.Name(tmp_name, ast.Load()))

# Assign the expression to the original names.
# Cleanup the temporary variable.
cleanup = ast.TryFinally(
body=[ast.Assign(targets=[node.name], value=converter)],
finalbody=[self.gen_del_stmt(tmp_name)]

)
tmp_target, unpack = self.gen_unpack_wrapper(node, node.name)

# Repalce the tuple with the temporary variable.
node.name = ast.Name(tmp_name, ast.Store())
# Replace the tuple with the temporary variable.
node.name = tmp_target

copy_locations(cleanup, node)
copy_locations(node.name, node)
node.body.insert(0, cleanup)
# Insert the unpack code within the body of the except clause.
node.body.insert(0, unpack)

return node

Expand Down Expand Up @@ -1373,32 +1415,11 @@ def visit_FunctionDef(self, node):
unpacks = []
for index, arg in enumerate(list(node.args.args)):
if isinstance(arg, ast.Tuple):
tmp_name = self.gen_tmp_name()

# converter looks like wrapper(tmp_name).
# Wrapper takes care to protect
# sequence unpacking with _getiter_
converter = self.protect_unpack_sequence(
arg,
ast.Name(tmp_name, ast.Load()))

# Generates:
# try:
# # converter is 'wrapper(tmp_name)'
# arg = converter
# finally:
# del tmp_arg
cleanup = ast.TryFinally(
body=[ast.Assign(targets=[arg], value=converter)],
finalbody=[self.gen_del_stmt(tmp_name)]
)
tmp_target, unpack = self.gen_unpack_wrapper(node, arg, 'param')

# Replace the tuple with a single (temporary) parameter.
node.args.args[index] = ast.Name(tmp_name, ast.Param())

copy_locations(node.args.args[index], node)
copy_locations(cleanup, node)
unpacks.append(cleanup)
node.args.args[index] = tmp_target
unpacks.append(unpack)

# Add the unpacks at the front of the body.
# Keep the order, so that tuple one is unpacked first.
Expand Down

0 comments on commit 292601d

Please sign in to comment.