Skip to content

Commit

Permalink
fix: early inverse binding for else condition
Browse files Browse the repository at this point in the history
(closes #150)
  • Loading branch information
vberlier committed Nov 28, 2023
1 parent 4e1b257 commit 44a6dbf
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 72 deletions.
37 changes: 30 additions & 7 deletions bolt/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ class Accumulator:
header: Dict[str, str] = field(default_factory=dict)
root_scope: bool = True

last_condition: str = "_bolt_error_last_condition"
current_siblings: Tuple[AstNode, ...] = ()
current_sibling_index: int = 0
condition_inverse: Optional[str] = None

def get_source(self) -> str:
"""Return the source code."""
Expand Down Expand Up @@ -240,22 +242,22 @@ def function(self, name: str, *args: str, return_type: str = ""):
self.root_scope = previous_root

@contextmanager
def if_statement(self, condition: str):
def if_statement(self, condition: str, inverse: Optional[str] = None):
"""Emit if statement."""
branch = self.helper("branch", condition)
self.statement(f"with {branch} as _bolt_condition:")
with self.block():
self.statement(f"if _bolt_condition:")
with self.block():
yield
self.last_condition = condition
self.condition_inverse = inverse

@contextmanager
def else_statement(self):
"""Emit else statement."""
negated_value = self.helper("operator_not", self.last_condition)
self.statement(f"{self.last_condition} = {negated_value}")
with self.if_statement(self.last_condition):
if not self.condition_inverse:
raise ValueError("Condition inverse unavailable.")
with self.if_statement(self.condition_inverse):
yield

def enclose(self, code: str, from_index: int):
Expand Down Expand Up @@ -362,7 +364,13 @@ def visit_multiple(
collector: Optional[ChildrenCollector] = None
index = len(acc.lines)

previous_siblings = acc.current_siblings
previous_sibling_index = acc.current_sibling_index
acc.current_siblings = children

for i, child in enumerate(children):
acc.current_sibling_index = i

result = yield child
if result is None:
continue
Expand All @@ -378,6 +386,9 @@ def visit_multiple(
current_count = i + 1
index = len(acc.lines)

acc.current_siblings = previous_siblings
acc.current_sibling_index = previous_sibling_index

if collector:
collector.add_static(*children[current_count:])
return collector.flush()
Expand Down Expand Up @@ -838,7 +849,19 @@ def if_statement(
acc: Accumulator,
) -> Generator[AstNode, Optional[List[str]], Optional[List[str]]]:
condition = yield from visit_single(node.arguments[0], required=True)
with acc.if_statement(condition):
inverse = None

else_index = acc.current_sibling_index + 1
if (
else_index < len(acc.current_siblings)
and isinstance(else_node := acc.current_siblings[else_index], AstCommand)
and else_node.identifier == "else:body"
):
inverse = f"{condition}_inverse"
value = acc.helper("operator_not", condition)
acc.statement(f"{inverse} = {value}", lineno=node.arguments[0])

with acc.if_statement(condition, inverse):
yield from visit_body(cast(AstRoot, node.arguments[1]), acc)
return []

Expand Down
8 changes: 4 additions & 4 deletions tests/snapshots/bolt__parse_130__1.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
_bolt_lineno = [1], [1]
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_lineno = [1, 13], [1, 2]
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
with _bolt_runtime.scope() as _bolt_var2:
Expand All @@ -10,11 +10,11 @@ with _bolt_runtime.scope() as _bolt_var2:
with _bolt_runtime.push_nesting('execute:commands'):
with _bolt_runtime.scope() as _bolt_var1:
_bolt_var0 = True
_bolt_var0_inverse = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[0].commands)
_bolt_var0 = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
with _bolt_helper_branch(_bolt_var0_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[1].commands)
_bolt_runtime.commands.append(_bolt_helper_replace(_bolt_refs[10], arguments=_bolt_helper_children([_bolt_helper_replace(_bolt_refs[9], arguments=_bolt_helper_children([*_bolt_refs[6:9], _bolt_helper_replace(_bolt_refs[5], arguments=_bolt_helper_children([*_bolt_refs[4:5], _bolt_helper_replace(_bolt_refs[3], arguments=_bolt_helper_children([_bolt_helper_replace(_bolt_refs[2], commands=_bolt_helper_children(_bolt_var1))]))]))]))])))
Expand Down
16 changes: 8 additions & 8 deletions tests/snapshots/bolt__parse_132__1.txt
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
_bolt_lineno = [1], [1]
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_lineno = [1, 15, 22], [1, 3, 5]
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
with _bolt_runtime.scope() as _bolt_var4:
_bolt_var0 = 1
_bolt_var0_inverse = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[0].commands)
_bolt_var0 = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
with _bolt_helper_branch(_bolt_var0_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var1 = 2
_bolt_var1_inverse = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[1].commands)
_bolt_var1 = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
with _bolt_helper_branch(_bolt_var1_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var2 = 3
_bolt_var2_inverse = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[2].commands)
_bolt_var2 = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
with _bolt_helper_branch(_bolt_var2_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var3 = 4
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
Expand Down
16 changes: 8 additions & 8 deletions tests/snapshots/bolt__parse_133__1.txt
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
_bolt_lineno = [1], [1]
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_lineno = [1, 15, 22], [1, 3, 5]
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
with _bolt_runtime.scope() as _bolt_var4:
_bolt_var0 = 1
_bolt_var0_inverse = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[0].commands)
_bolt_var0 = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
with _bolt_helper_branch(_bolt_var0_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var1 = 2
_bolt_var1_inverse = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[1].commands)
_bolt_var1 = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
with _bolt_helper_branch(_bolt_var1_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var2 = 3
_bolt_var2_inverse = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[2].commands)
_bolt_var2 = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
with _bolt_helper_branch(_bolt_var2_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var3 = 4
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
Expand Down
20 changes: 10 additions & 10 deletions tests/snapshots/bolt__parse_134__1.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
_bolt_lineno = [1], [1]
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_lineno = [1, 15, 22, 29], [1, 3, 5, 7]
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
with _bolt_runtime.scope() as _bolt_var4:
_bolt_var0 = 1
_bolt_var0_inverse = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[0].commands)
_bolt_var0 = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
with _bolt_helper_branch(_bolt_var0_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var1 = 2
_bolt_var1_inverse = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[1].commands)
_bolt_var1 = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
with _bolt_helper_branch(_bolt_var1_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var2 = 3
_bolt_var2_inverse = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[2].commands)
_bolt_var2 = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
with _bolt_helper_branch(_bolt_var2_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var3 = 4
_bolt_var3_inverse = _bolt_helper_operator_not(_bolt_var3)
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[3].commands)
_bolt_var3 = _bolt_helper_operator_not(_bolt_var3)
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
with _bolt_helper_branch(_bolt_var3_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[4].commands)
_bolt_var5 = _bolt_helper_replace(_bolt_refs[5], commands=_bolt_helper_children(_bolt_var4))
Expand Down
20 changes: 10 additions & 10 deletions tests/snapshots/bolt__parse_135__1.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
_bolt_lineno = [1], [1]
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_lineno = [1, 15, 22, 29], [1, 3, 5, 7]
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
with _bolt_runtime.scope() as _bolt_var4:
_bolt_var0 = 1
_bolt_var0_inverse = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[0].commands)
_bolt_var0 = _bolt_helper_operator_not(_bolt_var0)
with _bolt_helper_branch(_bolt_var0) as _bolt_condition:
with _bolt_helper_branch(_bolt_var0_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var1 = 2
_bolt_var1_inverse = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[1].commands)
_bolt_var1 = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
with _bolt_helper_branch(_bolt_var1_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var2 = 3
_bolt_var2_inverse = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[2].commands)
_bolt_var2 = _bolt_helper_operator_not(_bolt_var2)
with _bolt_helper_branch(_bolt_var2) as _bolt_condition:
with _bolt_helper_branch(_bolt_var2_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_var3 = 4
_bolt_var3_inverse = _bolt_helper_operator_not(_bolt_var3)
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[3].commands)
_bolt_var3 = _bolt_helper_operator_not(_bolt_var3)
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
with _bolt_helper_branch(_bolt_var3_inverse) as _bolt_condition:
if _bolt_condition:
_bolt_runtime.commands.extend(_bolt_refs[4].commands)
_bolt_runtime.commands.append(_bolt_refs[5])
Expand Down
8 changes: 4 additions & 4 deletions tests/snapshots/bolt__parse_138__1.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
_bolt_lineno = [1], [1]
_bolt_lineno = [1, 12], [1, 2]
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
with _bolt_runtime.scope() as _bolt_var2:
while True:
_bolt_var0 = True
if not _bolt_var0:
break
_bolt_var1 = 'hello'
_bolt_var1_inverse = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
if _bolt_condition:
pass
_bolt_var1 = _bolt_helper_operator_not(_bolt_var1)
with _bolt_helper_branch(_bolt_var1) as _bolt_condition:
with _bolt_helper_branch(_bolt_var1_inverse) as _bolt_condition:
if _bolt_condition:
break
_bolt_var3 = _bolt_helper_replace(_bolt_refs[0], commands=_bolt_helper_children(_bolt_var2))
Expand Down
8 changes: 4 additions & 4 deletions tests/snapshots/bolt__parse_139__1.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
_bolt_lineno = [1, 15, 20, 27, 40], [1, 2, 3, 4, 6]
_bolt_lineno = [1, 15, 20, 28, 40], [1, 2, 3, 4, 6]
_bolt_helper_get_attribute = _bolt_runtime.helpers['get_attribute']
_bolt_helper_interpolate_resource_location = _bolt_runtime.helpers['interpolate_resource_location']
_bolt_helper_children = _bolt_runtime.helpers['children']
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_branch = _bolt_runtime.helpers['branch']
_bolt_helper_interpolate_range = _bolt_runtime.helpers['interpolate_range']
_bolt_helper_replace = _bolt_runtime.helpers['replace']
_bolt_helper_operator_not = _bolt_runtime.helpers['operator_not']
_bolt_helper_interpolate_message = _bolt_runtime.helpers['interpolate_message']
with _bolt_runtime.scope() as _bolt_var10:
_bolt_var0 = generate_tree
Expand All @@ -21,6 +21,7 @@ with _bolt_runtime.scope() as _bolt_var10:
_bolt_var3 = _bolt_helper_get_attribute(_bolt_var3, 'partition')
_bolt_var4 = 5
_bolt_var3 = _bolt_var3(_bolt_var4)
_bolt_var3_inverse = _bolt_helper_operator_not(_bolt_var3)
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
if _bolt_condition:
with _bolt_runtime.push_nesting('execute:subcommand'):
Expand All @@ -33,8 +34,7 @@ with _bolt_runtime.scope() as _bolt_var10:
_bolt_var6 = _bolt_helper_get_attribute(_bolt_var6, 'children')
_bolt_var6 = _bolt_helper_interpolate_resource_location(_bolt_var6, _bolt_refs[4])
_bolt_runtime.commands.append(_bolt_helper_replace(_bolt_refs[8], arguments=_bolt_helper_children([_bolt_helper_replace(_bolt_refs[7], arguments=_bolt_helper_children([*_bolt_helper_children([_bolt_refs[2], _bolt_refs[3], _bolt_var5]), _bolt_helper_replace(_bolt_refs[6], arguments=_bolt_helper_children([_bolt_helper_replace(_bolt_refs[5], arguments=_bolt_helper_children([_bolt_var6]))]))]))])))
_bolt_var3 = _bolt_helper_operator_not(_bolt_var3)
with _bolt_helper_branch(_bolt_var3) as _bolt_condition:
with _bolt_helper_branch(_bolt_var3_inverse) as _bolt_condition:
if _bolt_condition:
with _bolt_runtime.push_nesting('execute:subcommand'):
_bolt_var7 = node
Expand Down
Loading

0 comments on commit 44a6dbf

Please sign in to comment.