1
0
mirror of synced 2024-11-28 07:50:51 +01:00

Pass indentation context into expression rendering for upcoming function definition support.

This commit is contained in:
Jennifer Taylor 2021-04-26 01:21:42 +00:00
parent 351e7060b8
commit 3a9b3a7b3c
2 changed files with 112 additions and 98 deletions

View File

@ -110,27 +110,31 @@ class Statement(ConvertedAction):
raise NotImplementedError(f"{self.__class__.__name__} does not implement render()!") raise NotImplementedError(f"{self.__class__.__name__} does not implement render()!")
def object_ref(obj: Any) -> str: def object_ref(obj: Any, parent_prefix: str) -> str:
if isinstance(obj, (GenericObject, Variable, Member, MethodCall, FunctionCall)): if isinstance(obj, (GenericObject, Variable, Member, MethodCall, FunctionCall, Register)):
return obj.render(nested=True) return obj.render(parent_prefix, nested=True)
else: else:
raise Exception(f"Unsupported objectref {obj} ({type(obj)})") raise Exception(f"Unsupported objectref {obj} ({type(obj)})")
def value_ref(param: Any, parens: bool = False) -> str: def value_ref(param: Any, parent_prefix: str, parens: bool = False) -> str:
if isinstance(param, Expression): if isinstance(param, StringConstant):
return param.render(nested=parens) # Treat this as a string constant.
return repr(param.render(parent_prefix))
elif isinstance(param, Expression):
return param.render(parent_prefix, nested=parens)
elif isinstance(param, (str, int, float)): elif isinstance(param, (str, int, float)):
return repr(param) return repr(param)
else: else:
raise Exception(f"Unsupported valueref {param} ({type(param)})") raise Exception(f"Unsupported valueref {param} ({type(param)})")
def name_ref(param: Any) -> str: def name_ref(param: Any, parent_prefix: str) -> str:
# Reference a name, so strings should not be quoted.
if isinstance(param, str): if isinstance(param, str):
return param return param
elif isinstance(param, StringConstant): elif isinstance(param, StringConstant):
return param.render() return param.render(parent_prefix)
else: else:
raise Exception(f"Unsupported nameref {param} ({type(param)})") raise Exception(f"Unsupported nameref {param} ({type(param)})")
@ -202,10 +206,10 @@ class ExpressionStatement(Statement):
self.expr = expr self.expr = expr
def __repr__(self) -> str: def __repr__(self) -> str:
return f"{self.expr.render()}" return f"{self.expr.render('')}"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
return [f"{prefix}{self.expr.render()};"] return [f"{prefix}{self.expr.render(prefix)};"]
class StopMovieStatement(Statement): class StopMovieStatement(Statement):
@ -232,11 +236,11 @@ class DebugTraceStatement(Statement):
self.trace = trace self.trace = trace
def __repr__(self) -> str: def __repr__(self) -> str:
trace = value_ref(self.trace) trace = value_ref(self.trace, "")
return f"builtin_DebugTrace({trace})" return f"builtin_DebugTrace({trace})"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
trace = value_ref(self.trace) trace = value_ref(self.trace, prefix)
return [f"{prefix}builtin_DebugTrace({trace});"] return [f"{prefix}builtin_DebugTrace({trace});"]
@ -246,11 +250,11 @@ class GotoFrameStatement(Statement):
self.frame = frame self.frame = frame
def __repr__(self) -> str: def __repr__(self) -> str:
frame = value_ref(self.frame) frame = value_ref(self.frame, "")
return f"builtin_GotoFrame({frame})" return f"builtin_GotoFrame({frame})"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
frame = value_ref(self.frame) frame = value_ref(self.frame, prefix)
return [f"{prefix}builtin_GotoFrame({frame});"] return [f"{prefix}builtin_GotoFrame({frame});"]
@ -262,15 +266,15 @@ class CloneSpriteStatement(Statement):
self.depth = depth self.depth = depth
def __repr__(self) -> str: def __repr__(self) -> str:
obj = object_ref(self.obj_to_clone) obj = object_ref(self.obj_to_clone, "")
name = value_ref(self.name) name = value_ref(self.name, "")
depth = value_ref(self.depth) depth = value_ref(self.depth, "")
return f"builtin_CloneSprite({obj}, {name}, {depth})" return f"builtin_CloneSprite({obj}, {name}, {depth})"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
obj = object_ref(self.obj_to_clone) obj = object_ref(self.obj_to_clone, prefix)
name = value_ref(self.name) name = value_ref(self.name, prefix)
depth = value_ref(self.depth) depth = value_ref(self.depth, prefix)
return [f"{prefix}builtin_CloneSprite({obj}, {name}, {depth});"] return [f"{prefix}builtin_CloneSprite({obj}, {name}, {depth});"]
@ -281,13 +285,13 @@ class ArithmeticExpression(Expression):
self.right = right self.right = right
def __repr__(self) -> str: def __repr__(self) -> str:
left = value_ref(self.left, parens=True) left = value_ref(self.left, "", parens=True)
right = value_ref(self.right, parens=True) right = value_ref(self.right, "", parens=True)
return f"{left} {self.op} {right}" return f"{left} {self.op} {right}"
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
left = value_ref(self.left, parens=True) left = value_ref(self.left, parent_prefix, parens=True)
right = value_ref(self.right, parens=True) right = value_ref(self.right, parent_prefix, parens=True)
if nested and self.op == '-': if nested and self.op == '-':
return f"({left} {self.op} {right})" return f"({left} {self.op} {right})"
@ -301,10 +305,10 @@ class Array(Expression):
self.params = params self.params = params
def __repr__(self) -> str: def __repr__(self) -> str:
return self.render() return self.render("")
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
params = [value_ref(param) for param in self.params] params = [value_ref(param, parent_prefix) for param in self.params]
return f"[{', '.join(params)}]" return f"[{', '.join(params)}]"
@ -315,29 +319,35 @@ class FunctionCall(Expression):
self.params = params self.params = params
def __repr__(self) -> str: def __repr__(self) -> str:
return self.render() return self.render("")
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
name = name_ref(self.name) name = name_ref(self.name, parent_prefix)
params = [value_ref(param) for param in self.params] params = [value_ref(param, parent_prefix) for param in self.params]
return f"{name}({', '.join(params)})" return f"{name}({', '.join(params)})"
class MethodCall(Expression): class MethodCall(Expression):
# Call a method on an object. # Call a method on an object.
def __init__(self, objectref: Any, name: Union[str, StringConstant], params: List[Any]) -> None: def __init__(self, objectref: Any, name: Union[str, int, Expression], params: List[Any]) -> None:
self.objectref = objectref self.objectref = objectref
self.name = name self.name = name
self.params = params self.params = params
def __repr__(self) -> str: def __repr__(self) -> str:
return self.render() return self.render("")
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
obj = object_ref(self.objectref) try:
name = name_ref(self.name) obj = object_ref(self.objectref, parent_prefix)
params = [value_ref(param) for param in self.params] name = name_ref(self.name, parent_prefix)
return f"{obj}.{name}({', '.join(params)})" params = [value_ref(param, parent_prefix) for param in self.params]
return f"{obj}.{name}({', '.join(params)})"
except Exception:
obj = object_ref(self.objectref, parent_prefix)
name = value_ref(self.name, parent_prefix)
params = [value_ref(param, parent_prefix) for param in self.params]
return f"{obj}[{name}]({', '.join(params)})"
class NewFunction(Expression): class NewFunction(Expression):
@ -348,9 +358,9 @@ class NewFunction(Expression):
self.body = body self.body = body
def __repr__(self) -> str: def __repr__(self) -> str:
return self.render() return self.render("")
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
val = f"new function({repr(self.funcname) or '<anonymous function>'}, {hex(self.flags)}, 'TODO: ByteCode')" val = f"new function({repr(self.funcname) or '<anonymous function>'}, {hex(self.flags)}, 'TODO: ByteCode')"
if nested: if nested:
return f"({val})" return f"({val})"
@ -365,11 +375,11 @@ class NewObject(Expression):
self.params = params self.params = params
def __repr__(self) -> str: def __repr__(self) -> str:
return self.render() return self.render('')
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
objname = name_ref(self.objname) objname = name_ref(self.objname, parent_prefix)
params = [value_ref(param) for param in self.params] params = [value_ref(param, parent_prefix) for param in self.params]
val = f"new {objname}({', '.join(params)})" val = f"new {objname}({', '.join(params)})"
if nested: if nested:
return f"({val})" return f"({val})"
@ -386,28 +396,28 @@ class SetMemberStatement(Statement):
def __repr__(self) -> str: def __repr__(self) -> str:
try: try:
ref = object_ref(self.objectref) ref = object_ref(self.objectref, "")
name = name_ref(self.name) name = name_ref(self.name, "")
val = value_ref(self.valueref) val = value_ref(self.valueref, "")
return f"{ref}.{name} = {val}" return f"{ref}.{name} = {val}"
except Exception: except Exception:
# This is not a simple string object reference. # This is not a simple string object reference.
ref = object_ref(self.objectref) ref = object_ref(self.objectref, "")
name = value_ref(self.name) name = value_ref(self.name, "")
val = value_ref(self.valueref) val = value_ref(self.valueref, "")
return f"{ref}[{name}] = {val}" return f"{ref}[{name}] = {val}"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
try: try:
ref = object_ref(self.objectref) ref = object_ref(self.objectref, prefix)
name = name_ref(self.name) name = name_ref(self.name, prefix)
val = value_ref(self.valueref) val = value_ref(self.valueref, prefix)
return [f"{prefix}{ref}.{name} = {val};"] return [f"{prefix}{ref}.{name} = {val};"]
except Exception: except Exception:
# This is not a simple string object reference. # This is not a simple string object reference.
ref = object_ref(self.objectref) ref = object_ref(self.objectref, prefix)
name = value_ref(self.name) name = value_ref(self.name, prefix)
val = value_ref(self.valueref) val = value_ref(self.valueref, prefix)
return [f"{prefix}{ref}[{name}] = {val};"] return [f"{prefix}{ref}[{name}] = {val};"]
@ -417,11 +427,11 @@ class DeleteVariableStatement(Statement):
self.name = name self.name = name
def __repr__(self) -> str: def __repr__(self) -> str:
name = name_ref(self.name) name = name_ref(self.name, "")
return f"del {name}" return f"del {name}"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
name = name_ref(self.name) name = name_ref(self.name, prefix)
return [f"{prefix}del {name};"] return [f"{prefix}del {name};"]
@ -432,12 +442,12 @@ class StoreRegisterStatement(Statement):
self.valueref = valueref self.valueref = valueref
def __repr__(self) -> str: def __repr__(self) -> str:
val = value_ref(self.valueref) val = value_ref(self.valueref, "")
return f"{self.register.render()} = {val}" return f"{self.register.render('')} = {val}"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
val = value_ref(self.valueref) val = value_ref(self.valueref, prefix)
return [f"{prefix}{self.register.render()} = {val};"] return [f"{prefix}{self.register.render(prefix)} = {val};"]
class SetVariableStatement(Statement): class SetVariableStatement(Statement):
@ -447,13 +457,13 @@ class SetVariableStatement(Statement):
self.valueref = valueref self.valueref = valueref
def __repr__(self) -> str: def __repr__(self) -> str:
name = name_ref(self.name) name = name_ref(self.name, "")
val = value_ref(self.valueref) val = value_ref(self.valueref, "")
return f"{name} = {val}" return f"{name} = {val}"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
name = name_ref(self.name) name = name_ref(self.name, prefix)
val = value_ref(self.valueref) val = value_ref(self.valueref, prefix)
return [f"{prefix}{name} = {val};"] return [f"{prefix}{name} = {val};"]
@ -464,13 +474,13 @@ class SetLocalStatement(Statement):
self.valueref = valueref self.valueref = valueref
def __repr__(self) -> str: def __repr__(self) -> str:
name = name_ref(self.name) name = name_ref(self.name, "")
val = value_ref(self.valueref) val = value_ref(self.valueref, "")
return f"local {name} = {val}" return f"local {name} = {val}"
def render(self, prefix: str) -> List[str]: def render(self, prefix: str) -> List[str]:
name = name_ref(self.name) name = name_ref(self.name, prefix)
val = value_ref(self.valueref) val = value_ref(self.valueref, prefix)
return [f"{prefix}local {name} = {val};"] return [f"{prefix}local {name} = {val};"]
@ -485,7 +495,7 @@ class IsUndefinedIf(IfExpr):
self.negate = negate self.negate = negate
def __repr__(self) -> str: def __repr__(self) -> str:
val = value_ref(self.conditional, parens=True) val = value_ref(self.conditional, "", parens=True)
if self.negate: if self.negate:
return f"if ({val} is not UNDEFINED)" return f"if ({val} is not UNDEFINED)"
else: else:
@ -498,7 +508,7 @@ class IsBooleanIf(IfExpr):
self.negate = negate self.negate = negate
def __repr__(self) -> str: def __repr__(self) -> str:
val = value_ref(self.conditional, parens=True) val = value_ref(self.conditional, "", parens=True)
if self.negate: if self.negate:
return f"if ({val} is False)" return f"if ({val} is False)"
else: else:
@ -512,8 +522,8 @@ class IsEqualIf(IfExpr):
self.negate = negate self.negate = negate
def __repr__(self) -> str: def __repr__(self) -> str:
val1 = value_ref(self.conditional1, parens=True) val1 = value_ref(self.conditional1, "", parens=True)
val2 = value_ref(self.conditional2, parens=True) val2 = value_ref(self.conditional2, "", parens=True)
return f"if ({val1} {'!=' if self.negate else '=='} {val2})" return f"if ({val1} {'!=' if self.negate else '=='} {val2})"
@ -524,8 +534,8 @@ class IsStrictEqualIf(IfExpr):
self.negate = negate self.negate = negate
def __repr__(self) -> str: def __repr__(self) -> str:
val1 = value_ref(self.conditional1, parens=True) val1 = value_ref(self.conditional1, "", parens=True)
val2 = value_ref(self.conditional2, parens=True) val2 = value_ref(self.conditional2, "", parens=True)
return f"if ({val1} {'!==' if self.negate else '==='} {val2})" return f"if ({val1} {'!==' if self.negate else '==='} {val2})"
@ -536,8 +546,8 @@ class MagnitudeIf(IfExpr):
self.negate = negate self.negate = negate
def __repr__(self) -> str: def __repr__(self) -> str:
val1 = value_ref(self.conditional1, parens=True) val1 = value_ref(self.conditional1, "", parens=True)
val2 = value_ref(self.conditional2, parens=True) val2 = value_ref(self.conditional2, "", parens=True)
return f"if ({val1} {'<' if self.negate else '>'} {val2})" return f"if ({val1} {'<' if self.negate else '>'} {val2})"
@ -548,8 +558,8 @@ class MagnitudeEqualIf(IfExpr):
self.negate = negate self.negate = negate
def __repr__(self) -> str: def __repr__(self) -> str:
val1 = value_ref(self.conditional1, parens=True) val1 = value_ref(self.conditional1, "", parens=True)
val2 = value_ref(self.conditional2, parens=True) val2 = value_ref(self.conditional2, "", parens=True)
return f"if ({val1} {'<=' if self.negate else '>='} {val2})" return f"if ({val1} {'<=' if self.negate else '>='} {val2})"
@ -780,10 +790,10 @@ class Variable(Expression):
self.name = name self.name = name
def __repr__(self) -> str: def __repr__(self) -> str:
return f"Variable({name_ref(self.name)})" return f"Variable({name_ref(self.name, '')})"
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
return name_ref(self.name) return name_ref(self.name, parent_prefix)
class Member(Expression): class Member(Expression):
@ -794,17 +804,17 @@ class Member(Expression):
self.member = member self.member = member
def __repr__(self) -> str: def __repr__(self) -> str:
return self.render() return self.render("")
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
try: try:
member = name_ref(self.member) member = name_ref(self.member, parent_prefix)
ref = object_ref(self.objectref) ref = object_ref(self.objectref, parent_prefix)
return f"{ref}.{member}" return f"{ref}.{member}"
except Exception: except Exception:
# This is not a simple string object reference. # This is not a simple string object reference.
member = value_ref(self.member) member = value_ref(self.member, parent_prefix)
ref = object_ref(self.objectref) ref = object_ref(self.objectref, parent_prefix)
return f"{ref}[{member}]" return f"{ref}[{member}]"
@ -1854,7 +1864,7 @@ class ByteCodeDecompiler(VerboseOutput):
if action.opcode == AP2Action.CALL_METHOD: if action.opcode == AP2Action.CALL_METHOD:
method_name = stack.pop() method_name = stack.pop()
if not isinstance(method_name, (str, StringConstant)): if not isinstance(method_name, (str, int, Expression)):
raise Exception("Logic error!") raise Exception("Logic error!")
object_reference = stack.pop() object_reference = stack.pop()
num_params = stack.pop() num_params = stack.pop()
@ -1977,8 +1987,8 @@ class ByteCodeDecompiler(VerboseOutput):
continue continue
if action.opcode == AP2Action.ADD2: if action.opcode == AP2Action.ADD2:
expr1 = stack.pop()
expr2 = stack.pop() expr2 = stack.pop()
expr1 = stack.pop()
stack.append(ArithmeticExpression(expr1, "+", expr2)) stack.append(ArithmeticExpression(expr1, "+", expr2))
chunk.actions[i] = NopStatement() chunk.actions[i] = NopStatement()
@ -1998,6 +2008,7 @@ class ByteCodeDecompiler(VerboseOutput):
stack.append(ArithmeticExpression(expr1, "*", expr2)) stack.append(ArithmeticExpression(expr1, "*", expr2))
chunk.actions[i] = NopStatement() chunk.actions[i] = NopStatement()
continue
if action.opcode == AP2Action.DIVIDE: if action.opcode == AP2Action.DIVIDE:
expr2 = stack.pop() expr2 = stack.pop()
@ -2006,7 +2017,6 @@ class ByteCodeDecompiler(VerboseOutput):
chunk.actions[i] = NopStatement() chunk.actions[i] = NopStatement()
continue continue
continue
if action.opcode == AP2Action.MODULO: if action.opcode == AP2Action.MODULO:
expr2 = stack.pop() expr2 = stack.pop()
@ -2069,6 +2079,10 @@ class ByteCodeDecompiler(VerboseOutput):
self.vprint(stack) self.vprint(stack)
raise Exception(f"TODO: {action}") raise Exception(f"TODO: {action}")
# Make sure we consumed the stack.
if stack:
raise Exception(f"Stack not empty, contains {stack}!")
# Now, clean up code generation. # Now, clean up code generation.
new_actions: List[ConvertedAction] = [] new_actions: List[ConvertedAction] = []
for action in chunk.actions: for action in chunk.actions:

View File

@ -417,7 +417,7 @@ class AP2Action:
# Similar to STORE_REGISTER but does not preserve the value on the stack afterwards. # Similar to STORE_REGISTER but does not preserve the value on the stack afterwards.
STORE_REGISTER2 = 74 STORE_REGISTER2 = 74
# Take one opcode parameter for the number of registers to in it, and then one opcode parameter # Take one opcode parameter for the number of registers to init, and then one opcode parameter
# per the number of registers param as the register number to init, initializing that register # per the number of registers param as the register number to init, initializing that register
# as an "Undefined" object. # as an "Undefined" object.
INIT_REGISTER = 75 INIT_REGISTER = 75
@ -618,7 +618,7 @@ class DefineFunction2Action(AP2Action):
class Expression: class Expression:
# Any thing that can be evaluated for a result, such as a variable # Any thing that can be evaluated for a result, such as a variable
# reference, function call, or mathematical operation. # reference, function call, or mathematical operation.
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
raise NotImplementedError(f"{self.__class__.__name__} does not implement render()!") raise NotImplementedError(f"{self.__class__.__name__} does not implement render()!")
@ -630,7 +630,7 @@ class GenericObject(Expression):
def __repr__(self) -> str: def __repr__(self) -> str:
return self.name return self.name
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
return self.name return self.name
@ -650,7 +650,7 @@ class Register(Expression):
def __repr__(self) -> str: def __repr__(self) -> str:
return f"Register({self.no})" return f"Register({self.no})"
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
return f"registers[{self.no}]" return f"registers[{self.no}]"
@ -2600,7 +2600,7 @@ class StringConstant(Expression):
else: else:
return f"StringConstant({hex(self.const)}: {StringConstant.property_to_name(self.const)})" return f"StringConstant({hex(self.const)}: {StringConstant.property_to_name(self.const)})"
def render(self, nested: bool = False) -> str: def render(self, parent_prefix: str, nested: bool = False) -> str:
if self.alias: if self.alias:
return self.alias return self.alias
else: else: