def forward_transfer(gen_sym, in_env, statement): if isinstance(statement, ast.Assign): target = statement.targets[0].id result, gen_sym = peval_expression(statement.value, gen_sym, in_env.known_values()) new_values=dict(in_env.values) for name in result.mutated_bindings: new_values[name] = Value(undefined=True) if result.fully_evaluated: new_value = Value(value=result.value) else: new_value = Value(undefined=True) new_values[target] = new_value out_env = Environment(values=new_values) new_exprs = [CachedExpression(path=['value'], node=result.node)] return gen_sym, out_env, new_exprs, result.temp_bindings elif isinstance(statement, (ast.Expr, ast.Return)): result, gen_sym = peval_expression(statement.value, gen_sym, in_env.known_values()) new_values=dict(in_env.values) for name in result.mutated_bindings: new_values[name] = Value(undefined=True) new_exprs = [CachedExpression(path=['value'], node=result.node)] out_env = Environment(values=new_values) return gen_sym, out_env, new_exprs, result.temp_bindings elif isinstance(statement, ast.If): result, gen_sym = peval_expression(statement.test, gen_sym, in_env.known_values()) new_values=dict(in_env.values) for name in result.mutated_bindings: new_values[name] = Value(undefined=True) out_env = Environment(values=new_values) new_exprs = [CachedExpression(path=['test'], node=result.node)] return gen_sym, out_env, new_exprs, result.temp_bindings else: return gen_sym, in_env, [], {}
def check_peval_expression(source, bindings, expected_source, fully_evaluated=False, expected_value=None, expected_temp_bindings=None): source_tree = expression_ast(source) # In some cases we need to enforce the expected node, # because it cannot be obtained by parsing # (e.g. "-5" is parsed as "UnaryOp(op=USub(), Num(n=5))", not as "Num(n=-5)"). # But we expect the latter from a fully evaluated expression. if isinstance(expected_source, str): expected_tree = expression_ast(expected_source) else: expected_tree = expected_source gen_sym = GenSym() result, gen_sym = peval_expression(source_tree, gen_sym, bindings) assert_ast_equal(result.node, expected_tree) assert result.fully_evaluated == fully_evaluated if fully_evaluated: assert result.value == expected_value if expected_temp_bindings is not None: for key, val in expected_temp_bindings.items(): assert key in result.temp_bindings assert result.temp_bindings[key] == expected_temp_bindings[key]
def test_generator_exp(): # Need to do this manually, since we can't compare generator expressions # without changing their state. source_tree = expression_ast("(x + 1 for x in range(a))") expected_tree = expression_ast("__peval_temp_2") bindings = dict(a=10, range=range) gen_sym = GenSym() result, gen_sym = peval_expression(source_tree, gen_sym, bindings) assert_ast_equal(result.node, expected_tree) assert result.fully_evaluated expected_genexp = (x + 1 for x in range(10)) assert type(result.value) == type(expected_genexp) assert list(result.value) == list(expected_genexp) # Since the binding contained the reference to the same genexp, # and we destroyed it, we need to do the evaluation again # in order to check the binding as well gen_sym = GenSym() result, gen_sym = peval_expression(source_tree, gen_sym, bindings) expected_genexp = (x + 1 for x in range(10)) assert '__peval_temp_2' in result.temp_bindings binding = result.temp_bindings['__peval_temp_2'] assert type(binding) == type(expected_genexp) assert list(binding) == list(expected_genexp) check_peval_expression( '(x + 1 for x in range(a))', dict(a=10), '(x + 1 for x in range(10))')