mirror of
https://github.com/DragonMinded/bemaniutils.git
synced 2026-08-25 11:54:38 -05:00
Massive type refactor for decompiler.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -6,17 +6,6 @@ from .ap2 import (
|
||||
AP2Pointer,
|
||||
AP2Trigger,
|
||||
DefineFunction2Action,
|
||||
Expression,
|
||||
GenericObject,
|
||||
NULL,
|
||||
UNDEFINED,
|
||||
THIS,
|
||||
ROOT,
|
||||
PARENT,
|
||||
CLIP,
|
||||
GLOBAL,
|
||||
Register,
|
||||
StringConstant,
|
||||
PushAction,
|
||||
InitRegisterAction,
|
||||
StoreRegisterAction,
|
||||
@@ -29,6 +18,71 @@ from .ap2 import (
|
||||
GetURL2Action,
|
||||
StartDragAction,
|
||||
)
|
||||
from .expression import (
|
||||
Expression,
|
||||
GenericObject,
|
||||
NULL,
|
||||
UNDEFINED,
|
||||
THIS,
|
||||
ROOT,
|
||||
PARENT,
|
||||
CLIP,
|
||||
GLOBAL,
|
||||
Register,
|
||||
StringConstant,
|
||||
ArithmeticExpression,
|
||||
MethodCall,
|
||||
FunctionCall,
|
||||
GetTimeFunctionCall,
|
||||
GetPathFunctionCall,
|
||||
Variable,
|
||||
Member,
|
||||
NewFunction,
|
||||
NewObject,
|
||||
Array,
|
||||
Object,
|
||||
NotExpression,
|
||||
name_ref,
|
||||
value_ref,
|
||||
object_ref,
|
||||
)
|
||||
from .statement import (
|
||||
ConvertedAction,
|
||||
Statement,
|
||||
StopMovieStatement,
|
||||
PlayMovieStatement,
|
||||
GotoFrameStatement,
|
||||
GetURL2Statement,
|
||||
NextFrameStatement,
|
||||
PreviousFrameStatement,
|
||||
StopSoundStatement,
|
||||
CloneSpriteStatement,
|
||||
RemoveSpriteStatement,
|
||||
DebugTraceStatement,
|
||||
NopStatement,
|
||||
IfStatement,
|
||||
DoWhileStatement,
|
||||
WhileStatement,
|
||||
ForStatement,
|
||||
BreakStatement,
|
||||
ContinueStatement,
|
||||
ReturnStatement,
|
||||
NullReturnStatement,
|
||||
ThrowStatement,
|
||||
GotoStatement,
|
||||
DefineLabelStatement,
|
||||
SetVariableStatement,
|
||||
DeleteVariableStatement,
|
||||
SetMemberStatement,
|
||||
DeleteMemberStatement,
|
||||
SetLocalStatement,
|
||||
StoreRegisterStatement,
|
||||
ExpressionStatement,
|
||||
IfExpr,
|
||||
IsUndefinedIf,
|
||||
IsBooleanIf,
|
||||
TwoParameterIf,
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
@@ -41,7 +95,6 @@ __all__ = [
|
||||
'AP2Object',
|
||||
'AP2Pointer',
|
||||
'AP2Trigger',
|
||||
'DefineFunction2Action',
|
||||
'Expression',
|
||||
'GenericObject',
|
||||
'NULL',
|
||||
@@ -53,6 +106,56 @@ __all__ = [
|
||||
'GLOBAL',
|
||||
'Register',
|
||||
'StringConstant',
|
||||
'ArithmeticExpression',
|
||||
'MethodCall',
|
||||
'FunctionCall',
|
||||
'GetTimeFunctionCall',
|
||||
'GetPathFunctionCall',
|
||||
'Variable',
|
||||
'Member',
|
||||
'NewFunction',
|
||||
'NewObject',
|
||||
'Array',
|
||||
'Object',
|
||||
'NotExpression',
|
||||
'name_ref',
|
||||
'value_ref',
|
||||
'object_ref',
|
||||
'ConvertedAction',
|
||||
'Statement',
|
||||
'StopMovieStatement',
|
||||
'PlayMovieStatement',
|
||||
'GotoFrameStatement',
|
||||
'GetURL2Statement',
|
||||
'NextFrameStatement',
|
||||
'PreviousFrameStatement',
|
||||
'StopSoundStatement',
|
||||
'CloneSpriteStatement',
|
||||
'RemoveSpriteStatement',
|
||||
'DebugTraceStatement',
|
||||
'NopStatement',
|
||||
'IfStatement',
|
||||
'DoWhileStatement',
|
||||
'WhileStatement',
|
||||
'ForStatement',
|
||||
'BreakStatement',
|
||||
'ContinueStatement',
|
||||
'ReturnStatement',
|
||||
'NullReturnStatement',
|
||||
'ThrowStatement',
|
||||
'GotoStatement',
|
||||
'DefineLabelStatement',
|
||||
'SetVariableStatement',
|
||||
'DeleteVariableStatement',
|
||||
'SetMemberStatement',
|
||||
'DeleteMemberStatement',
|
||||
'SetLocalStatement',
|
||||
'StoreRegisterStatement',
|
||||
'ExpressionStatement',
|
||||
'IfExpr',
|
||||
'IsUndefinedIf',
|
||||
'IsBooleanIf',
|
||||
'TwoParameterIf',
|
||||
'PushAction',
|
||||
'InitRegisterAction',
|
||||
'StoreRegisterAction',
|
||||
@@ -64,4 +167,5 @@ __all__ = [
|
||||
'AddNumRegisterAction',
|
||||
'GetURL2Action',
|
||||
'StartDragAction',
|
||||
'DefineFunction2Action',
|
||||
]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2219
bemani/format/afp/types/expression.py
Normal file
2219
bemani/format/afp/types/expression.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,9 @@ from typing import Any, Dict, Tuple
|
||||
|
||||
|
||||
class Color:
|
||||
# An RGBA color, represented as a series of floats between 0.0 and 1.0.
|
||||
# These can be multiplied or added against other colors to perform various
|
||||
# blending operations.
|
||||
def __init__(self, r: float, g: float, b: float, a: float) -> None:
|
||||
self.r = r
|
||||
self.g = g
|
||||
@@ -45,6 +48,7 @@ class Color:
|
||||
|
||||
|
||||
class Point:
|
||||
# A simple 2D point.
|
||||
def __init__(self, x: float, y: float) -> None:
|
||||
self.x = x
|
||||
self.y = y
|
||||
@@ -77,6 +81,7 @@ class Point:
|
||||
|
||||
|
||||
class Rectangle:
|
||||
# A 2D rectangle, represented by its left/right/top/bottom bounds.
|
||||
def __init__(self, left: float, top: float, bottom: float, right: float) -> None:
|
||||
self.left = left
|
||||
self.top = top
|
||||
@@ -108,6 +113,17 @@ class Rectangle:
|
||||
|
||||
|
||||
class Matrix:
|
||||
# The classic SWF matrix. Technically it is missing the third column, but that
|
||||
# column never changes and thus can be omitted. Includes operations for multiplying
|
||||
# 2D points as well as other matrixes and inverting itself. This is how SWF (and
|
||||
# as a result, AFP) performs its affine transformations on objects that are placed.
|
||||
#
|
||||
# The matrix, if laid out, looks as follows:
|
||||
#
|
||||
# | a b 0 |
|
||||
# | c d 0 |
|
||||
# | tx ty 1 |
|
||||
|
||||
def __init__(self, a: float, b: float, c: float, d: float, tx: float, ty: float) -> None:
|
||||
self.a = a
|
||||
self.b = b
|
||||
@@ -118,7 +134,7 @@ class Matrix:
|
||||
|
||||
@staticmethod
|
||||
def identity() -> "Matrix":
|
||||
return Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
|
||||
return Matrix(a=1.0, b=0.0, c=0.0, d=1.0, tx=0.0, ty=0.0)
|
||||
|
||||
def as_dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
||||
return {
|
||||
@@ -172,6 +188,7 @@ class Matrix:
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
# This happens if one of the scaling factors is zero.
|
||||
raise ZeroDivisionError(f"Matrix({self}) cannot be inverted!")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
||||
686
bemani/format/afp/types/statement.py
Normal file
686
bemani/format/afp/types/statement.py
Normal file
@@ -0,0 +1,686 @@
|
||||
import os
|
||||
from typing import Any, List, Sequence, Union
|
||||
|
||||
from .expression import (
|
||||
Expression,
|
||||
StringConstant,
|
||||
Register,
|
||||
value_ref,
|
||||
name_ref,
|
||||
object_ref,
|
||||
)
|
||||
|
||||
|
||||
class ConvertedAction:
|
||||
# An action that has been analyzed and converted to an intermediate representation.
|
||||
# This is only here because a Statement is a ConvertedAction and I don't want to
|
||||
# introduce a circular dependency.
|
||||
pass
|
||||
|
||||
|
||||
class Statement(ConvertedAction):
|
||||
# This is just a type class for finished statements.
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
raise NotImplementedError(f"{self.__class__.__name__} does not implement render()!")
|
||||
|
||||
|
||||
class DefineLabelStatement(Statement):
|
||||
def __init__(self, location: int) -> None:
|
||||
self.location = location
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"label_{self.location}:"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"label_{self.location}:"]
|
||||
|
||||
|
||||
class BreakStatement(Statement):
|
||||
# A break from a loop (forces execution to the next line after the loop).
|
||||
def __repr__(self) -> str:
|
||||
return "break"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}break;"]
|
||||
|
||||
|
||||
class ContinueStatement(Statement):
|
||||
# A continue in a loop (forces execution to the top of the loop).
|
||||
def __repr__(self) -> str:
|
||||
return "continue"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}continue;"]
|
||||
|
||||
|
||||
class GotoStatement(Statement):
|
||||
# A goto, including the ID of the chunk we want to jump to.
|
||||
def __init__(self, location: int) -> None:
|
||||
if location < 0:
|
||||
raise Exception(f"Logic error, attempting to go to artificially inserted location {location}!")
|
||||
|
||||
self.location = location
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"goto label_{self.location}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}goto label_{self.location};"]
|
||||
|
||||
|
||||
class NullReturnStatement(Statement):
|
||||
# A statement which directs the control flow to the end of the code, but
|
||||
# does not pop the stack to return
|
||||
def __repr__(self) -> str:
|
||||
return "return"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}return;"]
|
||||
|
||||
|
||||
class ReturnStatement(Statement):
|
||||
# A statement which directs the control flow to the end of the code,
|
||||
# returning the top of the stack.
|
||||
def __init__(self, ret: Any) -> None:
|
||||
self.ret = ret
|
||||
|
||||
def __repr__(self) -> str:
|
||||
ret = value_ref(self.ret, "")
|
||||
return f"return {ret}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
ret = value_ref(self.ret, prefix, verbose=verbose)
|
||||
return [f"{prefix}return {ret};"]
|
||||
|
||||
|
||||
class ThrowStatement(Statement):
|
||||
# A statement which raises an exception. It appears that there is no
|
||||
# 'catch' in this version of bytecode so it must be used only as an
|
||||
# assert.
|
||||
def __init__(self, exc: Any) -> None:
|
||||
self.exc = exc
|
||||
|
||||
def __repr__(self) -> str:
|
||||
exc = value_ref(self.exc, "")
|
||||
return f"throw {exc}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
exc = value_ref(self.exc, prefix, verbose=verbose)
|
||||
return [f"{prefix}throw {exc};"]
|
||||
|
||||
|
||||
class NopStatement(Statement):
|
||||
# A literal no-op. We will get rid of these in an optimizing pass.
|
||||
def __repr__(self) -> str:
|
||||
return "nop"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
# We should never render this!
|
||||
raise Exception("Logic error, a NopStatement should never make it to the render stage!")
|
||||
|
||||
|
||||
class ExpressionStatement(Statement):
|
||||
# A statement which is an expression that discards its return.
|
||||
def __init__(self, expr: Expression) -> None:
|
||||
self.expr = expr
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.expr.render('')}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}{self.expr.render(prefix, verbose=verbose)};"]
|
||||
|
||||
|
||||
class StopSoundStatement(Statement):
|
||||
# Stop all sounds, this is an actionscript-specific opcode.
|
||||
def __repr__(self) -> str:
|
||||
return "builtin_StopAllSounds()"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}builtin_StopAllSounds();"]
|
||||
|
||||
|
||||
class StopMovieStatement(Statement):
|
||||
# Stop the movie, this is an actionscript-specific opcode.
|
||||
def __repr__(self) -> str:
|
||||
return "builtin_StopPlaying()"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}builtin_StopPlaying();"]
|
||||
|
||||
|
||||
class PlayMovieStatement(Statement):
|
||||
# Play the movie, this is an actionscript-specific opcode.
|
||||
def __repr__(self) -> str:
|
||||
return "builtin_StartPlaying()"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}builtin_StartPlaying();"]
|
||||
|
||||
|
||||
class NextFrameStatement(Statement):
|
||||
# Advance to the next frame, this is an actionscript-specific opcode.
|
||||
def __repr__(self) -> str:
|
||||
return "builtin_GotoNextFrame()"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}builtin_GotoNextFrame();"]
|
||||
|
||||
|
||||
class PreviousFrameStatement(Statement):
|
||||
# Advance to the previous frame, this is an actionscript-specific opcode.
|
||||
def __repr__(self) -> str:
|
||||
return "builtin_GotoPreviousFrame()"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
return [f"{prefix}builtin_GotoPreviousFrame();"]
|
||||
|
||||
|
||||
class DebugTraceStatement(Statement):
|
||||
# Print a debug trace if supported.
|
||||
def __init__(self, trace: Any) -> None:
|
||||
self.trace = trace
|
||||
|
||||
def __repr__(self) -> str:
|
||||
trace = value_ref(self.trace, "")
|
||||
return f"builtin_DebugTrace({trace})"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
trace = value_ref(self.trace, prefix, verbose=verbose)
|
||||
return [f"{prefix}builtin_DebugTrace({trace});"]
|
||||
|
||||
|
||||
class GotoFrameStatement(Statement):
|
||||
# Go to a specified frame in the animation.
|
||||
def __init__(self, frame: Any) -> None:
|
||||
self.frame = frame
|
||||
|
||||
def __repr__(self) -> str:
|
||||
frame = value_ref(self.frame, "")
|
||||
return f"builtin_GotoFrame({frame})"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
frame = value_ref(self.frame, prefix, verbose=verbose)
|
||||
return [f"{prefix}builtin_GotoFrame({frame});"]
|
||||
|
||||
|
||||
class CloneSpriteStatement(Statement):
|
||||
# Clone a sprite.
|
||||
def __init__(self, obj_to_clone: Any, name: Union[str, Expression], depth: Union[int, Expression]) -> None:
|
||||
self.obj_to_clone = obj_to_clone
|
||||
self.name = name
|
||||
self.depth = depth
|
||||
|
||||
def __repr__(self) -> str:
|
||||
obj = object_ref(self.obj_to_clone, "")
|
||||
name = value_ref(self.name, "")
|
||||
depth = value_ref(self.depth, "")
|
||||
return f"builtin_CloneSprite({obj}, {name}, {depth})"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
obj = object_ref(self.obj_to_clone, prefix, verbose=verbose)
|
||||
name = value_ref(self.name, prefix, verbose=verbose)
|
||||
depth = value_ref(self.depth, prefix, verbose=verbose)
|
||||
return [f"{prefix}builtin_CloneSprite({obj}, {name}, {depth});"]
|
||||
|
||||
|
||||
class RemoveSpriteStatement(Statement):
|
||||
# Clone a sprite.
|
||||
def __init__(self, obj_to_remove: Any) -> None:
|
||||
self.obj_to_remove = obj_to_remove
|
||||
|
||||
def __repr__(self) -> str:
|
||||
obj = object_ref(self.obj_to_remove, "")
|
||||
return f"builtin_RemoveSprite({obj})"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
obj = object_ref(self.obj_to_remove, prefix, verbose=verbose)
|
||||
return [f"{prefix}builtin_RemoveSprite({obj});"]
|
||||
|
||||
|
||||
class GetURL2Statement(Statement):
|
||||
# Load the URL given in the parameters, with any possible target.
|
||||
def __init__(self, action: int, url: Any, target: Any) -> None:
|
||||
self.action = action
|
||||
self.url = url
|
||||
self.target = target
|
||||
|
||||
def __repr__(self) -> str:
|
||||
url = value_ref(self.url, "")
|
||||
target = value_ref(self.target, "")
|
||||
return f"builtin_GetURL2({self.action}, {url}, {target})"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
url = value_ref(self.url, prefix, verbose=verbose)
|
||||
target = value_ref(self.target, prefix, verbose=verbose)
|
||||
return [f"{prefix}builtin_GetURL2({self.action}, {url}, {target});"]
|
||||
|
||||
|
||||
class SetMemberStatement(Statement):
|
||||
# Call a method on an object.
|
||||
def __init__(self, objectref: Any, name: Union[str, int, Expression], valueref: Any) -> None:
|
||||
self.objectref = objectref
|
||||
self.name = name
|
||||
self.valueref = valueref
|
||||
|
||||
def code_equiv(self) -> str:
|
||||
try:
|
||||
ref = object_ref(self.objectref, "")
|
||||
name = name_ref(self.name, "")
|
||||
return f"{ref}.{name}"
|
||||
except Exception:
|
||||
# This is not a simple string object reference.
|
||||
ref = object_ref(self.objectref, "")
|
||||
name = value_ref(self.name, "")
|
||||
return f"{ref}[{name}]"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
try:
|
||||
ref = object_ref(self.objectref, "")
|
||||
name = name_ref(self.name, "")
|
||||
val = value_ref(self.valueref, "")
|
||||
return f"{ref}.{name} = {val}"
|
||||
except Exception:
|
||||
# This is not a simple string object reference.
|
||||
ref = object_ref(self.objectref, "")
|
||||
name = value_ref(self.name, "")
|
||||
val = value_ref(self.valueref, "")
|
||||
return f"{ref}[{name}] = {val}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
try:
|
||||
ref = object_ref(self.objectref, prefix, verbose=verbose)
|
||||
name = name_ref(self.name, prefix, verbose=verbose)
|
||||
val = value_ref(self.valueref, prefix, verbose=verbose)
|
||||
return [f"{prefix}{ref}.{name} = {val};"]
|
||||
except Exception:
|
||||
# This is not a simple string object reference.
|
||||
ref = object_ref(self.objectref, prefix, verbose=verbose)
|
||||
name = value_ref(self.name, prefix, verbose=verbose)
|
||||
val = value_ref(self.valueref, prefix, verbose=verbose)
|
||||
return [f"{prefix}{ref}[{name}] = {val};"]
|
||||
|
||||
|
||||
class DeleteVariableStatement(Statement):
|
||||
# Call a method on an object.
|
||||
def __init__(self, name: Union[str, StringConstant]) -> None:
|
||||
self.name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
name = name_ref(self.name, "")
|
||||
return f"del {name}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
name = name_ref(self.name, prefix, verbose=verbose)
|
||||
return [f"{prefix}del {name};"]
|
||||
|
||||
|
||||
class DeleteMemberStatement(Statement):
|
||||
# Call a method on an object.
|
||||
def __init__(self, objectref: Any, name: Union[str, int, Expression]) -> None:
|
||||
self.objectref = objectref
|
||||
self.name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
try:
|
||||
ref = object_ref(self.objectref, "")
|
||||
name = name_ref(self.name, "")
|
||||
return f"del {ref}.{name}"
|
||||
except Exception:
|
||||
# This is not a simple string object reference.
|
||||
ref = object_ref(self.objectref, "")
|
||||
name = value_ref(self.name, "")
|
||||
return f"del {ref}[{name}]"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
try:
|
||||
ref = object_ref(self.objectref, prefix, verbose=verbose)
|
||||
name = name_ref(self.name, prefix, verbose=verbose)
|
||||
return [f"{prefix}del {ref}.{name};"]
|
||||
except Exception:
|
||||
# This is not a simple string object reference.
|
||||
ref = object_ref(self.objectref, prefix, verbose=verbose)
|
||||
name = value_ref(self.name, prefix, verbose=verbose)
|
||||
return [f"{prefix}del {ref}[{name}];"]
|
||||
|
||||
|
||||
class StoreRegisterStatement(Statement):
|
||||
# Set a variable to a value.
|
||||
def __init__(self, register: Register, valueref: Any) -> None:
|
||||
self.register = register
|
||||
self.valueref = valueref
|
||||
|
||||
def code_equiv(self) -> str:
|
||||
return self.register.render('')
|
||||
|
||||
def __repr__(self) -> str:
|
||||
val = value_ref(self.valueref, "")
|
||||
return f"{self.register.render('')} = {val}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
val = value_ref(self.valueref, prefix, verbose=verbose)
|
||||
return [f"{prefix}{self.register.render(prefix, verbose=verbose)} = {val};"]
|
||||
|
||||
|
||||
class SetVariableStatement(Statement):
|
||||
# Set a variable to a value.
|
||||
def __init__(self, name: Union[str, StringConstant], valueref: Any) -> None:
|
||||
self.name = name
|
||||
self.valueref = valueref
|
||||
|
||||
def code_equiv(self) -> str:
|
||||
return name_ref(self.name, "")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
name = name_ref(self.name, "")
|
||||
val = value_ref(self.valueref, "")
|
||||
return f"{name} = {val}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
name = name_ref(self.name, prefix, verbose=verbose)
|
||||
val = value_ref(self.valueref, prefix, verbose=verbose)
|
||||
return [f"{prefix}{name} = {val};"]
|
||||
|
||||
|
||||
class SetLocalStatement(Statement):
|
||||
# Define a local variable with a value.
|
||||
def __init__(self, name: Union[str, StringConstant], valueref: Any) -> None:
|
||||
self.name = name
|
||||
self.valueref = valueref
|
||||
|
||||
def code_equiv(self) -> str:
|
||||
return name_ref(self.name, "")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
name = name_ref(self.name, "")
|
||||
val = value_ref(self.valueref, "")
|
||||
return f"local {name} = {val}"
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
name = name_ref(self.name, prefix, verbose=verbose)
|
||||
val = value_ref(self.valueref, prefix, verbose=verbose)
|
||||
return [f"{prefix}local {name} = {val};"]
|
||||
|
||||
|
||||
class IfExpr(ConvertedAction):
|
||||
# This is just for typing.
|
||||
def invert(self) -> "IfExpr":
|
||||
raise NotImplementedError("Not implemented!")
|
||||
|
||||
def swap(self) -> "IfExpr":
|
||||
raise NotImplementedError("Not implemented!")
|
||||
|
||||
|
||||
class IsUndefinedIf(IfExpr):
|
||||
def __init__(self, conditional: Any, negate: bool) -> None:
|
||||
self.conditional = conditional
|
||||
self.negate = negate
|
||||
|
||||
def invert(self) -> "IsUndefinedIf":
|
||||
return IsUndefinedIf(self.conditional, not self.negate)
|
||||
|
||||
def swap(self) -> "IsUndefinedIf":
|
||||
return IsUndefinedIf(self.conditional, self.negate)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
val = value_ref(self.conditional, "", parens=True)
|
||||
if self.negate:
|
||||
return f"{val} is not UNDEFINED"
|
||||
else:
|
||||
return f"{val} is UNDEFINED"
|
||||
|
||||
|
||||
class IsBooleanIf(IfExpr):
|
||||
def __init__(self, conditional: Any, negate: bool) -> None:
|
||||
self.conditional = conditional
|
||||
self.negate = negate
|
||||
|
||||
def invert(self) -> "IsBooleanIf":
|
||||
return IsBooleanIf(self.conditional, not self.negate)
|
||||
|
||||
def swap(self) -> "IsBooleanIf":
|
||||
return IsBooleanIf(self.conditional, self.negate)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
val = value_ref(self.conditional, "", parens=True)
|
||||
if self.negate:
|
||||
return f"not {val}"
|
||||
else:
|
||||
return f"{val}"
|
||||
|
||||
|
||||
class TwoParameterIf(IfExpr):
|
||||
EQUALS = "=="
|
||||
NOT_EQUALS = "!="
|
||||
LT = "<"
|
||||
GT = ">"
|
||||
LT_EQUALS = "<="
|
||||
GT_EQUALS = ">="
|
||||
STRICT_EQUALS = "==="
|
||||
STRICT_NOT_EQUALS = "!=="
|
||||
|
||||
def __init__(self, conditional1: Any, comp: str, conditional2: Any) -> None:
|
||||
if comp not in {
|
||||
self.EQUALS,
|
||||
self.NOT_EQUALS,
|
||||
self.LT,
|
||||
self.GT,
|
||||
self.LT_EQUALS,
|
||||
self.GT_EQUALS,
|
||||
self.STRICT_EQUALS,
|
||||
self.STRICT_NOT_EQUALS,
|
||||
}:
|
||||
raise Exception(f"Invalid comparision {comp}!")
|
||||
|
||||
self.conditional1 = conditional1
|
||||
self.comp = comp
|
||||
self.conditional2 = conditional2
|
||||
|
||||
def invert(self) -> "TwoParameterIf":
|
||||
if self.comp == self.EQUALS:
|
||||
return TwoParameterIf(self.conditional1, self.NOT_EQUALS, self.conditional2)
|
||||
if self.comp == self.NOT_EQUALS:
|
||||
return TwoParameterIf(self.conditional1, self.EQUALS, self.conditional2)
|
||||
if self.comp == self.LT:
|
||||
return TwoParameterIf(self.conditional1, self.GT_EQUALS, self.conditional2)
|
||||
if self.comp == self.GT:
|
||||
return TwoParameterIf(self.conditional1, self.LT_EQUALS, self.conditional2)
|
||||
if self.comp == self.LT_EQUALS:
|
||||
return TwoParameterIf(self.conditional1, self.GT, self.conditional2)
|
||||
if self.comp == self.GT_EQUALS:
|
||||
return TwoParameterIf(self.conditional1, self.LT, self.conditional2)
|
||||
if self.comp == self.STRICT_EQUALS:
|
||||
return TwoParameterIf(self.conditional1, self.STRICT_NOT_EQUALS, self.conditional2)
|
||||
if self.comp == self.STRICT_NOT_EQUALS:
|
||||
return TwoParameterIf(self.conditional1, self.STRICT_EQUALS, self.conditional2)
|
||||
raise Exception(f"Cannot invert {self.comp}!")
|
||||
|
||||
def swap(self) -> "TwoParameterIf":
|
||||
if self.comp == self.EQUALS:
|
||||
return TwoParameterIf(self.conditional2, self.EQUALS, self.conditional1)
|
||||
if self.comp == self.NOT_EQUALS:
|
||||
return TwoParameterIf(self.conditional2, self.NOT_EQUALS, self.conditional1)
|
||||
if self.comp == self.LT:
|
||||
return TwoParameterIf(self.conditional2, self.GT, self.conditional1)
|
||||
if self.comp == self.GT:
|
||||
return TwoParameterIf(self.conditional2, self.LT, self.conditional1)
|
||||
if self.comp == self.LT_EQUALS:
|
||||
return TwoParameterIf(self.conditional2, self.GT_EQUALS, self.conditional1)
|
||||
if self.comp == self.GT_EQUALS:
|
||||
return TwoParameterIf(self.conditional2, self.LT_EQUALS, self.conditional1)
|
||||
if self.comp == self.STRICT_EQUALS:
|
||||
return TwoParameterIf(self.conditional2, self.STRICT_EQUALS, self.conditional1)
|
||||
if self.comp == self.STRICT_NOT_EQUALS:
|
||||
return TwoParameterIf(self.conditional2, self.STRICT_NOT_EQUALS, self.conditional1)
|
||||
raise Exception(f"Cannot swap {self.comp}!")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
val1 = value_ref(self.conditional1, "", parens=True)
|
||||
val2 = value_ref(self.conditional2, "", parens=True)
|
||||
return f"{val1} {self.comp} {val2}"
|
||||
|
||||
|
||||
class IfStatement(Statement):
|
||||
def __init__(self, cond: IfExpr, true_statements: Sequence[Statement], false_statements: Sequence[Statement]) -> None:
|
||||
self.cond = cond
|
||||
self.true_statements = list(true_statements)
|
||||
self.false_statements = list(false_statements)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
true_entries: List[str] = []
|
||||
for statement in self.true_statements:
|
||||
true_entries.extend([f" {s}" for s in str(statement).split(os.linesep)])
|
||||
|
||||
false_entries: List[str] = []
|
||||
for statement in self.false_statements:
|
||||
false_entries.extend([f" {s}" for s in str(statement).split(os.linesep)])
|
||||
|
||||
if false_entries:
|
||||
return os.linesep.join([
|
||||
f"if ({self.cond}) {{",
|
||||
os.linesep.join(true_entries),
|
||||
"} else {",
|
||||
os.linesep.join(false_entries),
|
||||
"}"
|
||||
])
|
||||
else:
|
||||
return os.linesep.join([
|
||||
f"if ({self.cond}) {{",
|
||||
os.linesep.join(true_entries),
|
||||
"}"
|
||||
])
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
true_entries: List[str] = []
|
||||
for statement in self.true_statements:
|
||||
true_entries.extend(statement.render(prefix=prefix + " ", verbose=verbose))
|
||||
|
||||
false_entries: List[str] = []
|
||||
for statement in self.false_statements:
|
||||
false_entries.extend(statement.render(prefix=prefix + " ", verbose=verbose))
|
||||
|
||||
if false_entries:
|
||||
return [
|
||||
f"{prefix}if ({self.cond})",
|
||||
f"{prefix}{{",
|
||||
*true_entries,
|
||||
f"{prefix}}}",
|
||||
f"{prefix}else",
|
||||
f"{prefix}{{",
|
||||
*false_entries,
|
||||
f"{prefix}}}"
|
||||
]
|
||||
else:
|
||||
return [
|
||||
f"{prefix}if ({self.cond})",
|
||||
f"{prefix}{{",
|
||||
*true_entries,
|
||||
f"{prefix}}}"
|
||||
]
|
||||
|
||||
|
||||
class DoWhileStatement(Statement):
|
||||
def __init__(self, body: Sequence[Statement]) -> None:
|
||||
self.body = list(body)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
entries: List[str] = []
|
||||
for statement in self.body:
|
||||
entries.extend([f" {s}" for s in str(statement).split(os.linesep)])
|
||||
|
||||
return os.linesep.join([
|
||||
"do {",
|
||||
os.linesep.join(entries),
|
||||
"} while (True)"
|
||||
])
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
entries: List[str] = []
|
||||
for statement in self.body:
|
||||
entries.extend(statement.render(prefix=prefix + " ", verbose=verbose))
|
||||
|
||||
return [
|
||||
f"{prefix}do",
|
||||
f"{prefix}{{",
|
||||
*entries,
|
||||
f"{prefix}}}",
|
||||
f"{prefix}while (True);",
|
||||
]
|
||||
|
||||
|
||||
class ForStatement(DoWhileStatement):
|
||||
# Special case of a DoWhileStatement that tracks its own exit condition and increment.
|
||||
def __init__(self, inc_variable: str, inc_init: Any, cond: IfExpr, inc_assign: Any, body: Sequence[Statement], local: bool = False) -> None:
|
||||
super().__init__(body)
|
||||
self.inc_variable = inc_variable
|
||||
self.inc_init = inc_init
|
||||
self.cond = cond
|
||||
self.inc_assign = inc_assign
|
||||
self.local = local
|
||||
|
||||
def __repr__(self) -> str:
|
||||
entries: List[str] = []
|
||||
for statement in self.body:
|
||||
entries.extend([f" {s}" for s in str(statement).split(os.linesep)])
|
||||
|
||||
inc_init = value_ref(self.inc_init, "")
|
||||
inc_assign = value_ref(self.inc_assign, "")
|
||||
if self.local:
|
||||
local = "local "
|
||||
else:
|
||||
local = ""
|
||||
|
||||
return os.linesep.join([
|
||||
f"for ({local}{self.inc_variable} = {inc_init}; {self.cond}; {self.inc_variable} = {inc_assign}) {{",
|
||||
os.linesep.join(entries),
|
||||
"}"
|
||||
])
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
entries: List[str] = []
|
||||
for statement in self.body:
|
||||
entries.extend(statement.render(prefix=prefix + " ", verbose=verbose))
|
||||
|
||||
inc_init = value_ref(self.inc_init, prefix, verbose=verbose)
|
||||
inc_assign = value_ref(self.inc_assign, prefix, verbose=verbose)
|
||||
if self.local:
|
||||
local = "local "
|
||||
else:
|
||||
local = ""
|
||||
|
||||
return [
|
||||
f"{prefix}for ({local}{self.inc_variable} = {inc_init}; {self.cond}; {self.inc_variable} = {inc_assign}) {{",
|
||||
f"{prefix}{{",
|
||||
*entries,
|
||||
f"{prefix}}}",
|
||||
]
|
||||
|
||||
|
||||
class WhileStatement(DoWhileStatement):
|
||||
# Special case of a DoWhileStatement that tracks its own exit condition.
|
||||
def __init__(self, cond: IfExpr, body: Sequence[Statement]) -> None:
|
||||
super().__init__(body)
|
||||
self.cond = cond
|
||||
|
||||
def __repr__(self) -> str:
|
||||
entries: List[str] = []
|
||||
for statement in self.body:
|
||||
entries.extend([f" {s}" for s in str(statement).split(os.linesep)])
|
||||
|
||||
return os.linesep.join([
|
||||
f"while ({self.cond}) {{",
|
||||
os.linesep.join(entries),
|
||||
"}"
|
||||
])
|
||||
|
||||
def render(self, prefix: str, verbose: bool = False) -> List[str]:
|
||||
entries: List[str] = []
|
||||
for statement in self.body:
|
||||
entries.extend(statement.render(prefix=prefix + " ", verbose=verbose))
|
||||
|
||||
return [
|
||||
f"{prefix}while ({self.cond}) {{",
|
||||
f"{prefix}{{",
|
||||
*entries,
|
||||
f"{prefix}}}",
|
||||
]
|
||||
Reference in New Issue
Block a user