diff --git a/pylingual/control_flow_reconstruction/cfg.py b/pylingual/control_flow_reconstruction/cfg.py index 41091f5..a7b368e 100644 --- a/pylingual/control_flow_reconstruction/cfg.py +++ b/pylingual/control_flow_reconstruction/cfg.py @@ -93,11 +93,7 @@ class CFG(DiGraph_CFT): if depth_limit is None: depth_limit = len(self) - get_children = ( - self.neighbors - if sort_neighbors is None - else lambda n: iter(sort_neighbors(self.neighbors(n))) - ) + get_children = self.neighbors if sort_neighbors is None else lambda n: iter(sort_neighbors(self.neighbors(n))) visited = set() for start in nodes: diff --git a/pylingual/control_flow_reconstruction/templates/Loop.py b/pylingual/control_flow_reconstruction/templates/Loop.py index 0745c94..817aa7a 100644 --- a/pylingual/control_flow_reconstruction/templates/Loop.py +++ b/pylingual/control_flow_reconstruction/templates/Loop.py @@ -11,12 +11,13 @@ from ..utils import ( defer_source_to, starting_instructions, to_indented_source, - make_try_match, + make_try_match, ) if TYPE_CHECKING: from pylingual.control_flow_reconstruction.cfg import CFG + @register_template(0, 1) class ForLoop(ControlFlowTemplate): template = T( @@ -48,17 +49,16 @@ class SelfLoop(ControlFlowTemplate): {loop_body} """ + @register_template(0, 2) class TrueSelfLoop(ControlFlowTemplate): - template = T( - loop_body=~N("tail.", "loop_body"), - tail=N.tail()) + template = T(loop_body=~N("tail.", "loop_body"), tail=N.tail()) try_match = make_try_match( { EdgeKind.Fall: "tail", - }, - "loop_body" + }, + "loop_body", ) @to_indented_source @@ -67,6 +67,7 @@ class TrueSelfLoop(ControlFlowTemplate): {loop_body} """ + @register_template(0, 3) class InlinedComprehensionTemplate(ControlFlowTemplate): template = T( @@ -85,15 +86,17 @@ class InlinedComprehensionTemplate(ControlFlowTemplate): to_indented_source = defer_source_to("comp") + class BreakTemplate(ControlFlowTemplate): @classmethod def try_match(cls, cfg, node): if isinstance(node, BreakTemplate) or has_no_lines(cfg, node) or with_instructions("RAISE_VARARGS")(cfg, node): return None - return condense_mapping(cls, cfg, {'child': node}, 'child') + return condense_mapping(cls, cfg, {"child": node}, "child") def to_indented_source(self, source): - return self.child.to_indented_source(source) + self.line('break') + return self.child.to_indented_source(source) + self.line("break") + class ContinueTemplate(ControlFlowTemplate): @classmethod @@ -102,11 +105,12 @@ class ContinueTemplate(ControlFlowTemplate): return None instruction = node.get_instructions()[-1].opname if instruction in {"JUMP_ABSOLUTE", "JUMP_BACKWARD", "CONTINUE_LOOP"} and (node.get_instructions()[-1].starts_line is not None or node.get_instructions()[-2].starts_line is not None): - return condense_mapping(cls, cfg, {'child': node}, 'child') + return condense_mapping(cls, cfg, {"child": node}, "child") return None def to_indented_source(self, source): - return self.child.to_indented_source(source) + self.line('continue') + return self.child.to_indented_source(source) + self.line("continue") + @register_template(0, 0) class FixLoop(ControlFlowTemplate): @@ -125,14 +129,13 @@ class FixLoop(ControlFlowTemplate): # a back-edge is an edge from any node that is dominated by this node back_edges = [] for predecessor in cfg.predecessors(node): - # A back edge exists if the predecessor is reachable from the node (node dominates predecessor) if cfg.dominates(node, predecessor): back_edges.append(predecessor) if not back_edges: return None - + # Get all nodes encompassed by the loop excluding source node and initial false jump loopnode = None for succ in cfg.successors(node): @@ -142,9 +145,9 @@ class FixLoop(ControlFlowTemplate): dfs_edges = cfg.dfs_labeled_edges_no_loop(source=loopnode) encompassed_nodes = [v for u, v, d in dfs_edges if d == "forward"] - + edges_to_remove = [] - + # Find the candidate end that break connects to candidate_end = None for succ in cfg.successors(node): @@ -152,13 +155,12 @@ class FixLoop(ControlFlowTemplate): candidate_end = succ # Candidate end is a buffer node - if cfg.in_degree(candidate_end) == 1 and any(exact_instructions(*op)(cfg, candidate_end) for op in [ - ("POP_BLOCK",), ("END_FOR",), ("END_FOR", "POP_TOP"), ("LOAD_CONST", "RETURN_VALUE")]): + if cfg.in_degree(candidate_end) == 1 and any(exact_instructions(*op)(cfg, candidate_end) for op in [("POP_BLOCK",), ("END_FOR",), ("END_FOR", "POP_TOP"), ("LOAD_CONST", "RETURN_VALUE")]): for ss in cfg.successors(candidate_end): if cfg.out_degree(ss) <= 1: candidate_end = ss break - + if encompassed_nodes is not None: for succ in encompassed_nodes: if cfg.get_edge_data(succ, candidate_end) != None: @@ -175,4 +177,4 @@ class FixLoop(ControlFlowTemplate): cfg.remove_edge(cont_node, node) cfg.iterate() - return \ No newline at end of file + return diff --git a/test/Exception.py b/test/Exception.py index 7a88433..24224b1 100644 --- a/test/Exception.py +++ b/test/Exception.py @@ -4,6 +4,7 @@ def a0_bare_try_except(): except: print(2) + def a1_bare_try_except_fallthrough(): try: print(1) @@ -11,6 +12,7 @@ def a1_bare_try_except_fallthrough(): print(2) print(3) + # 3.11/3.12/3.13 Duplicate blocks causing blocks to not match def b0_nested_try_except(): try: @@ -22,6 +24,7 @@ def b0_nested_try_except(): except: print(4) + def b1_nested_try_except_fallthrough(): try: print(1) @@ -33,7 +36,8 @@ def b1_nested_try_except_fallthrough(): print(4) print(5) -# 3.13 Duplicate blocks + +# 3.13 Duplicate blocks def b2_nested_try_except_early_fallthrough(): try: print(1) @@ -45,6 +49,7 @@ def b2_nested_try_except_early_fallthrough(): print(4) print(5) + def b3_nested_try_except_double_fallthrough(): try: print(1) @@ -57,6 +62,7 @@ def b3_nested_try_except_double_fallthrough(): print(5) print(6) + # 3.11/3.12/3.13 Duplicate blocks causing blocks to not match def c0_multi_except_nested(): try: @@ -74,6 +80,7 @@ def c0_multi_except_nested(): except: print(7) + # 3.11/3.12/3.13 Duplicate blocks causing blocks to not match def c1_multi_except_nested_fallthrough(): try: @@ -92,6 +99,7 @@ def c1_multi_except_nested_fallthrough(): except: print(8) + def c2_multi_except_nested_fallthrough2(): try: print(1) @@ -110,7 +118,8 @@ def c2_multi_except_nested_fallthrough2(): print(8) print(9) -# 3.13 Duplicate blocks + +# 3.13 Duplicate blocks def c3_multi_except_nested_early_fallthrough(): try: print(1) @@ -128,6 +137,7 @@ def c3_multi_except_nested_early_fallthrough(): print(7) print(8) + def c4_multi_except_nested_all_fallthrough(): try: print(1) @@ -147,6 +157,7 @@ def c4_multi_except_nested_all_fallthrough(): print(9) print(10) + # 3.10/3.11/3.12/3.13 Duplicate blocks causing templates to not match # Discussed in issue 41 def d0_named_except_nested(): @@ -159,6 +170,7 @@ def d0_named_except_nested(): except: print(4) + def d1_named_except_nested_fallthrough(): try: print(1) @@ -170,7 +182,8 @@ def d1_named_except_nested_fallthrough(): print(4) print(5) -# 3.13 Duplicate blocks + +# 3.13 Duplicate blocks def d2_named_except_nested_early_fallthrough(): try: print(1) @@ -182,6 +195,7 @@ def d2_named_except_nested_early_fallthrough(): print(4) print(5) + def d3_named_except_nested_double_fallthrough(): try: print(1) @@ -194,6 +208,7 @@ def d3_named_except_nested_double_fallthrough(): print(5) print(6) + def e0_try_except_else(): try: print(1) @@ -203,6 +218,7 @@ def e0_try_except_else(): print(3) print(4) + def f0_try_except_else_finally(): try: print(1) @@ -214,6 +230,7 @@ def f0_try_except_else_finally(): print(4) print(5) + def g0_multi_except_with_else(): try: print(1) @@ -225,6 +242,7 @@ def g0_multi_except_with_else(): print(4) print(5) + def h0_multi_except_fallback_with_else(): try: print(1) @@ -238,6 +256,7 @@ def h0_multi_except_fallback_with_else(): print(5) print(6) + def i0_mixed_named_unnamed_except_with_else(): try: print(1) @@ -251,6 +270,7 @@ def i0_mixed_named_unnamed_except_with_else(): print(5) print(6) + def j0_named_except_with_else(): try: print(1) @@ -262,6 +282,7 @@ def j0_named_except_with_else(): print(4) print(5) + def k0_try_except_finally(): try: print(1) @@ -271,6 +292,7 @@ def k0_try_except_finally(): print(3) print(4) + def l0_specific_except_finally(): try: print(1) @@ -280,6 +302,7 @@ def l0_specific_except_finally(): print(3) print(4) + def m0_multi_except(): try: print(1) @@ -291,6 +314,7 @@ def m0_multi_except(): print(4) print(5) + def n0_multi_except_with_fallback(): try: print(1) @@ -302,6 +326,7 @@ def n0_multi_except_with_fallback(): print(4) print(5) + def o0_multi_except_fallback_finally(): try: print(1) @@ -313,6 +338,7 @@ def o0_multi_except_fallback_finally(): print(4) print(5) + def p0_multi_named_except(): try: print(1) @@ -324,6 +350,7 @@ def p0_multi_named_except(): print(4) print(5) + def q0_mixed_named_unnamed_except(): try: print(1) @@ -335,6 +362,7 @@ def q0_mixed_named_unnamed_except(): print(4) print(5) + def r0_mixed_named_unnamed_except_finally(): try: print(1) @@ -348,6 +376,7 @@ def r0_mixed_named_unnamed_except_finally(): print(5) print(6) + def s0_named_except_fallback(): try: print(1) @@ -357,6 +386,7 @@ def s0_named_except_fallback(): print(3) print(4) + def t0_named_except_fallback_finally(): try: print(1) @@ -368,6 +398,7 @@ def t0_named_except_fallback_finally(): print(4) print(5) + def u0_multi_named_except_finally(): try: print(1) @@ -379,6 +410,7 @@ def u0_multi_named_except_finally(): print(4) print(5) + def v0_multi_except_finally(): try: print(1) @@ -390,6 +422,7 @@ def v0_multi_except_finally(): print(4) print(5) + def w0_try_except_raise(): try: print(1) @@ -397,6 +430,7 @@ def w0_try_except_raise(): print(2) raise Exc + def x0_multi_except_raise(): try: print(1) @@ -407,6 +441,7 @@ def x0_multi_except_raise(): print(3) raise Exc + def y0_named_except_raise(): try: print(1) @@ -414,6 +449,7 @@ def y0_named_except_raise(): print(2) raise Exc + # 3.11 Try return getting left outside of TryExcept def z0_try_except_return(): try: @@ -422,6 +458,7 @@ def z0_try_except_return(): except: print(2) + # 3.11 Try return getting left outside of TryExcept def z1_try_except_return_both(): try: @@ -431,6 +468,7 @@ def z1_try_except_return_both(): print(2) return 3 + # 3.11 Try return getting left outside of TryExcept def aa0_multi_except_return(): try: @@ -441,7 +479,8 @@ def aa0_multi_except_return(): except b: print(3) -# 3.6/3.7/3.8 ExceptExc abandons tail node. + +# 3.6/3.7/3.8 ExceptExc abandons tail node. # Could be fixed (?) but breaks other test cases # 3.11 Try return getting left outside of TryExcept def aa1_multi_except_return_both(): @@ -454,6 +493,7 @@ def aa1_multi_except_return_both(): except b: print(3) + # 3.11 Try return getting left outside of TryExcept def ab0_named_except_raise_return(): try: @@ -466,6 +506,7 @@ def ab0_named_except_raise_return(): print(3) raise Exc + # 3.8 Double natural edge graph error (?) # 3.11 Try return getting left outside of TryExcept def ab1_named_except_return(): @@ -476,12 +517,14 @@ def ab1_named_except_return(): print(2) return 3 + def ab2_named_except_return(): try: return a except Exception as a: return b + # 3.11/3.12/3.13 No template match def ac0_empty_try_finally(): try: @@ -489,6 +532,7 @@ def ac0_empty_try_finally(): finally: print(1) + def ad0_multiple_try_blocks(): try: print(1) @@ -500,6 +544,7 @@ def ad0_multiple_try_blocks(): except: print(4) + def ae0_try_except_else_nested_try(): try: print(1) @@ -511,6 +556,7 @@ def ae0_try_except_else_nested_try(): except: print(4) + # 3.9 Duplicate blocks (?) # 3.11/3.12/3.13 Matching priority TryElse TryFinally (?) def af0_try_finally_nested_except(): @@ -522,12 +568,14 @@ def af0_try_finally_nested_except(): except: print(3) + def ag0_try_except_tuple(): try: print(1) except (A, B): print(2) + # 3.9 Difficult template ambiguity between Try/TryFinally # 3.11/3.12/3.13 Matching priority TryElse TryFinally (?) def ah0_try_finally_return(): @@ -536,6 +584,7 @@ def ah0_try_finally_return(): finally: return 2 + # 3.11/3.12/3.13 No template match (?) def ai0_try_return_finally(): try: @@ -543,6 +592,7 @@ def ai0_try_return_finally(): finally: print(2) + # 3.9/3.10 Difficult template ambiguity between Try/TryFinally # 3.11/3.12/3.13 No template match (?) def aj0_try_return_finally_return(): @@ -551,6 +601,7 @@ def aj0_try_return_finally_return(): finally: return 2 + def ak0_try_except_raise_return(): try: print(1) @@ -558,6 +609,7 @@ def ak0_try_except_raise_return(): except: raise Exception() + # 3.8/3.9/3.10 No template match def al0_try_except_return_finally(): try: @@ -568,6 +620,7 @@ def al0_try_except_return_finally(): finally: print(3) + # 3.8/3.9/3.10 No template match # 3.11/3.12/3.13 Matching priority TryElse TryFinally (?) def am0_try_finally_raise(): @@ -577,6 +630,7 @@ def am0_try_finally_raise(): finally: raise Exception() + def an0_try_finally_fallthrough(): try: print(1) @@ -584,8 +638,9 @@ def an0_try_finally_fallthrough(): print(2) print(3) + def ao0_try_finally_simple(): try: print(1) finally: - print(2) \ No newline at end of file + print(2) diff --git a/test/Loop.py b/test/Loop.py index 8c730bf..20117a9 100644 --- a/test/Loop.py +++ b/test/Loop.py @@ -2,20 +2,24 @@ def a0_for_over_list(): for x in [1, 2, 3]: print("for over list") + def a1_for_over_list_nofallthru(): for x in [1, 2, 3]: print("for over list") print("end") + def b0_for_over_tuples(): for a, b in [(1, 2), (3, 4)]: print("tuples") + def b1_for_over_tuples_nofallthru(): for a, b in [(1, 2), (3, 4)]: print("tuples") print("end") + # 3.6/3.7 No else template def c0_for_else(): for i in range(3): @@ -23,6 +27,7 @@ def c0_for_else(): else: print("for else") + # 3.6/3.7 No else template def c1_for_else_nofallthru(): for i in range(3): @@ -31,6 +36,7 @@ def c1_for_else_nofallthru(): print("for else") print("end") + # 3.6/3.7 Naive break detection, an unexpected buffer POP_BLOCK to end # 3.9 Naive break detection, an unexpected buffer block to end def d0_for_with_break(): @@ -39,6 +45,7 @@ def d0_for_with_break(): print("breaking") break + # 3.6/3.7 Naive break detection, an unexpected buffer POP_BLOCK to end def d1_for_with_break_nofallthru(): for x in range(10): @@ -47,6 +54,7 @@ def d1_for_with_break_nofallthru(): break print("end") + # Help to implement break def d2_for_without_break(): for x in range(10): @@ -54,6 +62,7 @@ def d2_for_without_break(): print("not breaking") print("end") + # Help to implement break def d3_for_return(): for x in range(10): @@ -62,6 +71,7 @@ def d3_for_return(): return print("end") + def e0_for_with_continue(): for x in range(5): if x % 2 == 0: @@ -69,6 +79,7 @@ def e0_for_with_continue(): continue print("after continue") + def e1_for_with_continue_nofallthru(): for x in range(5): if x % 2 == 0: @@ -77,17 +88,20 @@ def e1_for_with_continue_nofallthru(): print("after continue") print("end") + def f0_nested_for_loops(): for i in range(2): for j in range(3): print(f"nested {i},{j}") + def f1_nested_for_loops_nofallthru(): for i in range(2): for j in range(3): print(f"nested {i},{j}") print("end") + def g0_for_with_try_except(): for x in range(2): try: @@ -95,6 +109,7 @@ def g0_for_with_try_except(): except Exception: print("except block") + def g1_for_with_try_except_nofallthru(): for x in range(2): try: @@ -103,17 +118,20 @@ def g1_for_with_try_except_nofallthru(): print("except block") print("end") + def h0_for_with_with_statement(): for _ in range(1): with a: print("inside with") + def h1_for_with_with_statement_nofallthru(): for _ in range(1): with a: print("inside with") print("end") + def i0_for_with_function_call_iterable(): def get_items(): return [1, 2, 3] @@ -121,6 +139,7 @@ def i0_for_with_function_call_iterable(): for item in get_items(): print(f"item: {item}") + def i1_for_with_function_call_iterable_nofallthru(): def get_items(): return [1, 2, 3] @@ -129,15 +148,18 @@ def i1_for_with_function_call_iterable_nofallthru(): print(f"item: {item}") print("end") + def j0_for_with_empty_body_ellipsis(): for _ in range(3): ... + def j1_for_with_empty_body_ellipsis_nofallthru(): for _ in range(3): ... print("end") + # 3.6/3.7 Naive break detection, no back edge # 3.9/3.11 No while loop detection, self false_jump edge & naive break detection def k0_while_true_with_break(): @@ -148,6 +170,7 @@ def k0_while_true_with_break(): if x >= 1: break + # 3.6/3.7 Naive break detection, no back edge # 3.9/3.11 No while loop detection, self false_jump edge & naive break detection def k1_while_true_with_break_nofallthru(): @@ -159,6 +182,7 @@ def k1_while_true_with_break_nofallthru(): break print("end") + # 3.6/3.7 No else template # 3.11 No while loop detection, self false_jump edge def l0_while_with_else(): @@ -169,6 +193,7 @@ def l0_while_with_else(): else: print("while else") + # 3.6/3.7 No else template # 3.11 No while loop detection, self false_jump edge def l1_while_with_else_nofallthru(): @@ -180,6 +205,7 @@ def l1_while_with_else_nofallthru(): print("while else") print("end") + # 3.11 No continue def m0_while_with_continue(): i = 0 @@ -190,6 +216,7 @@ def m0_while_with_continue(): continue print("after continue") + # 3.11 No continue def m1_while_with_continue_nofallthru(): i = 0 @@ -201,6 +228,7 @@ def m1_while_with_continue_nofallthru(): print("after continue") print("end") + # 3.6/3.7 Naive break detection, no back edge def n0_while_with_break(): i = 0 @@ -208,6 +236,7 @@ def n0_while_with_break(): print("break in while") break + # 3.6/3.7 Naive break detection, no back edge def n1_while_with_break_nofallthru(): i = 0 @@ -216,6 +245,7 @@ def n1_while_with_break_nofallthru(): break print("end") + # 3.11 While template broke def o0_nested_while_loops(): i = 0 @@ -226,6 +256,7 @@ def o0_nested_while_loops(): j += 1 i += 1 + # 3.11 While template broke def o1_nested_while_loops_nofallthru(): i = 0 @@ -237,8 +268,9 @@ def o1_nested_while_loops_nofallthru(): i += 1 print("end") + # 3.6/3.7 While template broke (?) -# 3.9 Disconnected with MetaTemplate[end] (?) +# 3.9 Disconnected with MetaTemplate[end] (?) def p0_while_with_try_except(): while True: try: @@ -246,8 +278,9 @@ def p0_while_with_try_except(): except: print("except in while") + # 3.6/3.7 While template broke (?) -# 3.9 Disconnected with MetaTemplate[end] (?) +# 3.9 Disconnected with MetaTemplate[end] (?) def p1_while_with_try_except_nofallthru(): while True: try: @@ -256,12 +289,14 @@ def p1_while_with_try_except_nofallthru(): print("except in while") print("end") + # 3.6/3.7 While template broke (?) abandoning nodes def q0_while_with_with_statement(): while True: with a: print("inside while with") + # 3.6/3.7 While template broke (?) abandoning nodes def q1_while_with_with_statement_nofallthru(): while True: @@ -269,12 +304,14 @@ def q1_while_with_with_statement_nofallthru(): print("inside while with") print("end") + # 3.6/3.7 While template broke def r0_for_inside_while(): while True: for x in [1, 2]: print("for in while") + # 3.6/3.7 While template broke def r1_for_inside_while_nofallthru(): while True: @@ -282,6 +319,7 @@ def r1_for_inside_while_nofallthru(): print("for in while") print("end") + # 3.6/3.7 While template broke def s0_while_inside_for(): for _ in range(1): @@ -289,6 +327,7 @@ def s0_while_inside_for(): print("while in for") break + # 3.6/3.7 While template broke def s1_while_inside_for_nofallthru(): for _ in range(1): @@ -297,17 +336,20 @@ def s1_while_inside_for_nofallthru(): break print("end") + # 3.6/3.7 While template broke def t0_while_with_empty_body_ellipsis(): while True: ... + # 3.6/3.7 While template broke def t1_while_with_empty_body_ellipsis_nofallthru(): while True: ... print("end") + def u0_break_in_nested_for(): for i in range(3): for j in range(3): @@ -316,6 +358,7 @@ def u0_break_in_nested_for(): break print(f"i={i}, j={j}") + def u1_break_in_nested_for_nofallthru(): for i in range(3): for j in range(3): @@ -325,6 +368,7 @@ def u1_break_in_nested_for_nofallthru(): print(f"i={i}, j={j}") print("end") + def v0_continue_in_nested_for(): for i in range(3): for j in range(3): @@ -332,6 +376,7 @@ def v0_continue_in_nested_for(): continue print(f"Processing i={i}, j={j}") + def v1_continue_in_nested_for_nofallthru(): for i in range(3): for j in range(3): @@ -340,6 +385,7 @@ def v1_continue_in_nested_for_nofallthru(): print(f"Processing i={i}, j={j}") print("end") + # 3.13 if statement putting code in the else block def w0_break_with_else(): for i in range(5): @@ -349,6 +395,7 @@ def w0_break_with_else(): else: print("This won't execute due to break") + # 3.13 if statement putting code in the else block def w1_break_with_else_nofallthru(): for i in range(5): @@ -359,6 +406,7 @@ def w1_break_with_else_nofallthru(): print("This won't execute due to break") print("end") + # 3.6/3.7 No continue detection def x0_continue_with_else(): for i in range(3): @@ -368,6 +416,7 @@ def x0_continue_with_else(): else: print("Else clause still executes after continue") + # 3.6/3.7 No continue detection def x1_continue_with_else_nofallthru(): for i in range(3): @@ -378,6 +427,7 @@ def x1_continue_with_else_nofallthru(): print("Else clause still executes after continue") print("end") + # 3.9/3.11 Naive break detection, break statement is further up def y0_break_in_try_except(): for i in range(5): @@ -388,6 +438,7 @@ def y0_break_in_try_except(): except: print("Exception occurred") + # 3.9 Naive break detection, break statement is further up def y1_break_in_try_except_nofallthru(): for i in range(5): @@ -399,6 +450,7 @@ def y1_break_in_try_except_nofallthru(): print("Exception occurred") print("end") + # 3.9 Naive break detection, break statement is further up def y2_return_in_try_except_nofallthru(): for i in range(5): @@ -411,6 +463,7 @@ def y2_return_in_try_except_nofallthru(): print("Exception occurred") print("end") + # 3.6/3.9 No continue detection def z0_continue_in_try_except(): for i in range(5): @@ -421,6 +474,7 @@ def z0_continue_in_try_except(): except: print("Exception occurred") + # 3.6/3.9/3.11 No continue detection def z1_continue_in_try_except_nofallthru(): for i in range(5): @@ -430,4 +484,4 @@ def z1_continue_in_try_except_nofallthru(): print(f"Value: {i}") except: print("Exception occurred") - print("end") \ No newline at end of file + print("end") diff --git a/test/With.py b/test/With.py index d4b4fc0..6e3c603 100644 --- a/test/With.py +++ b/test/With.py @@ -2,65 +2,79 @@ def a0_bare_with(): with a: print(1) + def a1_bare_with_fallthrough(): with a: print(1) print(2) + def b0_multi_with(): with a, b: print(1) + def b1_multi_with_fallthrough(): with a, b: print(1) print(2) + def c0_with_as(): with a as c: print(1) + def c1_with_as_fallthrough(): with a as c: print(1) print(2) + def d0_multi_with_as(): with a, b as c: print(1) + def d1_multi_with_as_fallthrough(): with a, b as c: print(1) print(2) + def e0_with_multi_as(): with a as b, c: print(1) + def e1_with_multi_as_fallthrough(): with a as b, c: print(1) print(2) + def f0_multi_with_multi_as(): with a as b, c as d: print(1) + def f1_multi_with_multi_as_fallthrough(): with a as b, c as d: print(1) print(2) + def g0_multi_with_multi_as_alt(): with a, b as c, d: print(1) + def g1_multi_with_multi_as_fallthrough_alt(): with a, b as c, d: print(1) print(2) + def h0_try_with_except(): try: with a: @@ -69,75 +83,91 @@ def h0_try_with_except(): print(2) print(3) + def i0_with_return(): with a: return 1 print(1) + def j0_with_raise(): with a: raise Exc print(1) + async def k0_bare_async_with(): async with a: print(1) + async def k1_bare_async_with_fallthrough(): async with a: print(1) print(2) + async def l0_multi_async_with(): async with a, b: print(1) + async def l1_multi_async_with_fallthrough(): async with a, b: print(1) print(2) + async def m0_async_with_as(): async with a as c: print(1) + async def m1_async_with_as_fallthrough(): async with a as c: print(1) print(2) + async def n0_multi_async_with_as(): async with a, b as c: print(1) + async def n1_multi_async_with_as_fallthrough(): async with a, b as c: print(1) print(2) + async def o0_async_with_multi_as(): async with a as b, c: print(1) + async def o1_async_with_multi_as_fallthrough(): async with a as b, c: print(1) print(2) + async def p0_multi_async_with_multi_as(): async with a as b, c as d: print(1) + async def p1_multi_async_with_multi_as_fallthrough(): async with a as b, c as d: print(1) print(2) + async def q0_multi_async_with_multi_as_alt(): async with a, b as c, d: print(1) + async def q1_multi_async_with_multi_as_fallthrough_alt(): async with a, b as c, d: print(1) - print(2) \ No newline at end of file + print(2)