def replace_dict(self, replacements, variable_set=None, leaf_operation=None):
if variable_set is None:<EOL><INDENT>variable_set = set()<EOL><DEDENT>if leaf_operation is None:<EOL><INDENT>leaf_operation = lambda x: x<EOL><DEDENT>arg_queue = [iter([self])]<EOL>rep_queue = []<EOL>ast_queue = []<EOL>while arg_queue:<EOL><INDENT>try:<EOL><INDENT>ast = next(arg_queue[-<NUM_LIT:1>])<EOL>repl = ast<EOL>if not isinstance(ast, Base):<EOL><INDENT>rep_queue.append(repl)<EOL>continue<EOL><DEDENT>elif ast.cache_key in replacements:<EOL><INDENT>repl = replacements[ast.cache_key]<EOL><DEDENT>elif ast.variables >= variable_set:<EOL><INDENT>if ast.op in operations.leaf_operations:<EOL><INDENT>repl = leaf_operation(ast)<EOL>if repl is not ast:<EOL><INDENT>replacements[ast.cache_key] = repl<EOL><DEDENT><DEDENT>elif ast.depth > <NUM_LIT:1>:<EOL><INDENT>arg_queue.append(iter(ast.args))<EOL>ast_queue.append(ast)<EOL>continue<EOL><DEDENT><DEDENT>rep_queue.append(repl)<EOL>continue<EOL><DEDENT>except StopIteration:<EOL><INDENT>arg_queue.pop()<EOL>if ast_queue:<EOL><INDENT>ast = ast_queue.pop()<EOL>repl = ast<EOL>args = rep_queue[-len(ast.args):]<EOL>del rep_queue[-len(ast.args):]<EOL>if any((a is not b for a, b in zip(ast.args, args))):<EOL><INDENT>repl = ast.make_like(ast.op, tuple(args))<EOL>replacements[ast.cache_key] = repl<EOL><DEDENT>rep_queue.append(repl)<EOL><DEDENT><DEDENT><DEDENT>assert len(arg_queue) == <NUM_LIT:0>, "<STR_LIT>"<EOL>assert len(ast_queue) == <NUM_LIT:0>, "<STR_LIT>"<EOL>assert len(rep_queue) == <NUM_LIT:1>, ("<STR_LIT>", len(rep_queue))<EOL>return rep_queue.pop()<EOL>
Returns this AST with subexpressions replaced by those that can be found in `replacements` dict.

:param variable_set:    For optimization, ast's without these variables are not checked for replacing.
:param replacements:    A dictionary of hashes to their replacements.
:param leaf_operation:  An operation that should be applied to the leaf nodes.
:return:                An AST with all instances of ast's in replacements.