Fix one last case where we can get surprise gotos.
This commit is contained in:
parent
203fdd3a10
commit
b81d2aeaae
@ -1220,7 +1220,7 @@ class BitVector:
|
|||||||
|
|
||||||
|
|
||||||
class ByteCodeDecompiler(VerboseOutput):
|
class ByteCodeDecompiler(VerboseOutput):
|
||||||
def __init__(self, bytecode: ByteCode, optimize: bool = True) -> None:
|
def __init__(self, bytecode: ByteCode, optimize: bool = False) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.bytecode = bytecode
|
self.bytecode = bytecode
|
||||||
@ -2105,7 +2105,11 @@ class ByteCodeDecompiler(VerboseOutput):
|
|||||||
|
|
||||||
next_id = chunks_by_id[cur_id].next_chunks[0]
|
next_id = chunks_by_id[cur_id].next_chunks[0]
|
||||||
if next_id not in chunks_by_id:
|
if next_id not in chunks_by_id:
|
||||||
raise Exception(f"Logic error, we can't jump to chunk {next_id} for chunk {cur_id} as it is outside of our scope!")
|
# We need to go to the next chunk, but we don't own it. Convert it to a goto.
|
||||||
|
self.vprint(f"Chunk ID {cur_id} needs a goto after empty if.")
|
||||||
|
cur_chunk.actions.append(GotoStatement(next_id))
|
||||||
|
chunks_by_id[cur_id].next_chunks = []
|
||||||
|
break
|
||||||
|
|
||||||
cur_id = next_id
|
cur_id = next_id
|
||||||
continue
|
continue
|
||||||
@ -3184,10 +3188,10 @@ class ByteCodeDecompiler(VerboseOutput):
|
|||||||
if isinstance(last_new_statement, GotoStatement):
|
if isinstance(last_new_statement, GotoStatement):
|
||||||
# Replace the next IDs with just the goto.
|
# Replace the next IDs with just the goto.
|
||||||
new_next_ids = {last_new_statement.location}
|
new_next_ids = {last_new_statement.location}
|
||||||
if isinstance(last_new_statement, (ThrowStatement, NullReturnStatement, ReturnStatement)):
|
elif isinstance(last_new_statement, (ThrowStatement, NullReturnStatement, ReturnStatement)):
|
||||||
# We don't have a next ID, we're returning.
|
# We don't have a next ID, we're returning.
|
||||||
new_next_ids = set()
|
new_next_ids = set()
|
||||||
if isinstance(last_new_statement, IntermediateIf):
|
elif isinstance(last_new_statement, IntermediateIf):
|
||||||
# We have potentially more than one next ID, given what statements exist
|
# We have potentially more than one next ID, given what statements exist
|
||||||
# inside the true/false chunks.
|
# inside the true/false chunks.
|
||||||
intermediates: List[Statement] = []
|
intermediates: List[Statement] = []
|
||||||
@ -3221,25 +3225,15 @@ class ByteCodeDecompiler(VerboseOutput):
|
|||||||
|
|
||||||
# Insert a sentinel for where temporary variables can be added if we
|
# Insert a sentinel for where temporary variables can be added if we
|
||||||
# need to in the future.
|
# need to in the future.
|
||||||
sentinels: List[Statement] = [InsertionLocation(chunk.id)]
|
sentinels: List[Union[Statement, IntermediateIf]] = [InsertionLocation(chunk.id)]
|
||||||
|
|
||||||
# If we have a goto, we need to insert the tempvar assignment before it.
|
# If we have a goto or intermediate if, we need to insert the tempvar assignment before it.
|
||||||
if new_statements and isinstance(new_statements[-1], GotoStatement):
|
# This is because in both cases we will redirect control flow, so we need to make sure
|
||||||
|
# tempvar assignment happens before that redirection for the code to make sense.
|
||||||
|
if new_statements and isinstance(new_statements[-1], (GotoStatement, IntermediateIf)):
|
||||||
sentinels.append(new_statements[-1])
|
sentinels.append(new_statements[-1])
|
||||||
new_statements = new_statements[:-1]
|
new_statements = new_statements[:-1]
|
||||||
|
|
||||||
# If we have an intermediate If, we need to insert the tempvar before it
|
|
||||||
# and also render it out to a real if statement.
|
|
||||||
if new_statements and isinstance(new_statements[-1], IntermediateIf):
|
|
||||||
sentinels.append(
|
|
||||||
IfStatement(
|
|
||||||
cast(IfExpr, new_statements[-1].parent_action),
|
|
||||||
new_statements[-1].true_statements,
|
|
||||||
new_statements[-1].false_statements,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
new_statements = new_statements[:-1]
|
|
||||||
|
|
||||||
# Add our new statements to the end of the statement list.
|
# Add our new statements to the end of the statement list.
|
||||||
new_statements.extend(sentinels)
|
new_statements.extend(sentinels)
|
||||||
else:
|
else:
|
||||||
@ -3250,10 +3244,28 @@ class ByteCodeDecompiler(VerboseOutput):
|
|||||||
|
|
||||||
# Verify that we converted all the statements properly.
|
# Verify that we converted all the statements properly.
|
||||||
for statement in new_statements:
|
for statement in new_statements:
|
||||||
if not isinstance(statement, Statement):
|
if isinstance(statement, IntermediateIf):
|
||||||
|
# Intermediate if conditional (such as a break/return/goto inside
|
||||||
|
# a loop.
|
||||||
|
if not isinstance(statement.parent_action, IfExpr):
|
||||||
|
raise Exception(f"Logic error, found unconverted IntermediateIf {statement}!")
|
||||||
|
|
||||||
|
if not statement.true_statements and not statement.false_statements:
|
||||||
|
self.vprint(f"Skipping adding if statement {statement} because it is an empty sentinel!")
|
||||||
|
else:
|
||||||
|
statements.append(
|
||||||
|
IfStatement(
|
||||||
|
statement.parent_action,
|
||||||
|
statement.true_statements,
|
||||||
|
statement.false_statements,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif isinstance(statement, Statement):
|
||||||
|
# Regular statement.
|
||||||
|
statements.append(statement)
|
||||||
|
else:
|
||||||
# We didn't convert a statement properly.
|
# We didn't convert a statement properly.
|
||||||
raise Exception(f"Logic error, {statement} is not converted!")
|
raise Exception(f"Logic error, {statement} is not converted!")
|
||||||
statements.append(statement)
|
|
||||||
|
|
||||||
# Go to the next chunk
|
# Go to the next chunk
|
||||||
if not chunk.next_chunks:
|
if not chunk.next_chunks:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user