Clean up codes
This commit is contained in:
@@ -1,14 +1,22 @@
|
|||||||
from typing import Dict, Optional, Tuple, List, Any
|
from typing import Dict, Optional, Tuple, List, Any
|
||||||
|
|
||||||
class MaMa:
|
class MaMa:
|
||||||
def __init__(self, prog: Dict[int, str] | List[str],
|
def __init__(self, prog: Dict[int, str] | List[str], stack: Dict[int, int] | List[int] | None = None) -> None:
|
||||||
stack: Dict[int, int] | List[int] | None = None) -> None:
|
self.step_counter = 0
|
||||||
self.steps = 0
|
|
||||||
self.prog = {i: instr for i, instr in enumerate(prog)} if isinstance(prog, list) else prog
|
|
||||||
self.p_prog = 0
|
|
||||||
self.stack: Dict[int, int] = {}
|
|
||||||
self.p_stack = -1
|
|
||||||
self.halted = False
|
self.halted = False
|
||||||
|
|
||||||
|
# Init prog from list or dict
|
||||||
|
self.p_prog = 0
|
||||||
|
if isinstance(prog, list):
|
||||||
|
self.prog = {i: micro for i, micro in enumerate(prog)}
|
||||||
|
else:
|
||||||
|
self.prog = prog
|
||||||
|
|
||||||
|
# Default stack
|
||||||
|
self.p_stack = -1
|
||||||
|
self.stack: Dict[int, int] = {}
|
||||||
|
|
||||||
|
# Init custom stack from list or dict
|
||||||
if stack is not None:
|
if stack is not None:
|
||||||
if isinstance(stack, list):
|
if isinstance(stack, list):
|
||||||
self.stack = {i: v for i, v in enumerate(stack)}
|
self.stack = {i: v for i, v in enumerate(stack)}
|
||||||
@@ -17,8 +25,7 @@ class MaMa:
|
|||||||
self.p_stack = max(self.stack.keys(), default=-1)
|
self.p_stack = max(self.stack.keys(), default=-1)
|
||||||
self.initial_stack = dict(self.stack)
|
self.initial_stack = dict(self.stack)
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# Runs the machine and returns execution journal
|
||||||
|
|
||||||
def run(self, max_steps: int = 1000) -> List[Dict[str, int | str | dict | list]]:
|
def run(self, max_steps: int = 1000) -> List[Dict[str, int | str | dict | list]]:
|
||||||
steps = 0
|
steps = 0
|
||||||
# always insert init configuration as step 0
|
# always insert init configuration as step 0
|
||||||
@@ -28,48 +35,48 @@ class MaMa:
|
|||||||
steps += 1
|
steps += 1
|
||||||
return journal
|
return journal
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# Returns the full program
|
||||||
|
|
||||||
def structure(self) -> Dict[int, Dict[str, Any]]:
|
def structure(self) -> Dict[int, Dict[str, Any]]:
|
||||||
return {i: {"call": call, "macros": []} for i, call in sorted(self.prog.items())}
|
return {i: {"micro": micro, "macros": []} for i, micro in sorted(self.prog.items())}
|
||||||
|
|
||||||
|
# Decodes string MaMa instructions to function callables
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def decode(call: str) -> Tuple[str, Optional[List[int]]]:
|
def decode(micro: str) -> Tuple[str, Optional[List[int]]]:
|
||||||
if "(" in call:
|
if "(" in micro:
|
||||||
name, rest = call.split("(", 1)
|
name, rest = micro.split("(", 1)
|
||||||
args_str = rest[:-1]
|
args_str = rest[:-1]
|
||||||
if args_str.strip() == "":
|
if args_str.strip() == "":
|
||||||
return name, []
|
return name, []
|
||||||
args = [int(a.strip()) for a in args_str.split(",")]
|
args = [int(a.strip()) for a in args_str.split(",")]
|
||||||
return name, args
|
return name, args
|
||||||
return call, None
|
return micro, None
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# Generates journal entry for a step
|
||||||
|
def config(self, micro: str) -> Dict[str, int | str | dict | list]:
|
||||||
def config(self, call: str) -> Dict[str, int | str | dict | list]:
|
|
||||||
return {
|
return {
|
||||||
"step": self.steps,
|
"step": self.step_counter,
|
||||||
"call": call,
|
"micro": micro,
|
||||||
"p_prog": self.p_prog,
|
"p_prog": self.p_prog,
|
||||||
"p_stack": self.p_stack,
|
"p_stack": self.p_stack,
|
||||||
"stack": dict(self.stack),
|
"stack": dict(self.stack),
|
||||||
}
|
}
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# Executes one step of the machine
|
||||||
|
|
||||||
def __step(self) -> Dict[str, int | str | dict | list]:
|
def __step(self) -> Dict[str, int | str | dict | list]:
|
||||||
if self.halted or self.p_prog not in self.prog:
|
if self.halted or self.p_prog not in self.prog:
|
||||||
self.halted = True
|
self.halted = True
|
||||||
return self.config("halted")
|
return self.config("halted")
|
||||||
|
|
||||||
call = self.prog[self.p_prog]
|
micro = self.prog[self.p_prog]
|
||||||
name, args = MaMa.decode(call)
|
name, args = MaMa.decode(micro)
|
||||||
method = getattr(self, f"_{name}", None)
|
method = getattr(self, f"_{name}", None)
|
||||||
if method is None:
|
if method is None:
|
||||||
raise ValueError(f"Unknown instruction: {call}")
|
raise ValueError(f"Unknown instruction: {micro}")
|
||||||
method(args)
|
method(args)
|
||||||
self.steps += 1
|
self.step_counter += 1
|
||||||
return self.config(call)
|
return self.config(micro)
|
||||||
|
|
||||||
|
# DEFINE MaMa Micros
|
||||||
|
|
||||||
# Stop execution
|
# Stop execution
|
||||||
def _stop(self, _: Optional[int]) -> None:
|
def _stop(self, _: Optional[int]) -> None:
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class MaMaGUI:
|
|||||||
state = self.journal[self.journal_index]
|
state = self.journal[self.journal_index]
|
||||||
stack = dict(state["stack"])
|
stack = dict(state["stack"])
|
||||||
p_prog, p_stack = int(state["p_prog"]), int(state["p_stack"])
|
p_prog, p_stack = int(state["p_prog"]), int(state["p_stack"])
|
||||||
step, call = int(state["step"]), str(state["call"])
|
step, micro = int(state["step"]), str(state["micro"])
|
||||||
|
|
||||||
# Load code structure
|
# Load code structure
|
||||||
structure = self.machine.structure()
|
structure = self.machine.structure()
|
||||||
@@ -96,7 +96,7 @@ class MaMaGUI:
|
|||||||
|
|
||||||
instr_indent = " " * depth
|
instr_indent = " " * depth
|
||||||
prefix = ">> " if addr == p_prog else " "
|
prefix = ">> " if addr == p_prog else " "
|
||||||
line = f"{prefix}{instr_indent}{addr:>3}: {info['call']}"
|
line = f"{prefix}{instr_indent}{addr:>3}: {info['micro']}"
|
||||||
self.prog_list.insert(tk.END, line)
|
self.prog_list.insert(tk.END, line)
|
||||||
opened_macros = macros
|
opened_macros = macros
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ class MaMaGUI:
|
|||||||
|
|
||||||
# Update configuration and global stack
|
# Update configuration and global stack
|
||||||
self.conf_label.config(text=f"({p_stack}, {p_prog}, {list(stack.values())})")
|
self.conf_label.config(text=f"({p_stack}, {p_prog}, {list(stack.values())})")
|
||||||
self.status.config(text=f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Call: {call}")
|
self.status.config(text=f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Micro: {micro}")
|
||||||
|
|
||||||
# Configure auto step speed
|
# Configure auto step speed
|
||||||
def __update_speed(self, value: str) -> None:
|
def __update_speed(self, value: str) -> None:
|
||||||
|
|||||||
@@ -1,42 +1,49 @@
|
|||||||
from typing import Dict, Optional, List, Any, Tuple
|
from typing import Dict, Optional, List, Any, Tuple, override
|
||||||
from MaMa import MaMa
|
from MaMa import MaMa
|
||||||
|
|
||||||
class MaMaMa(MaMa):
|
class MaMaMa(MaMa):
|
||||||
def __init__(self, prog, stack=None) -> None:
|
def __init__(self, prog, stack=None) -> None:
|
||||||
|
# Store macros
|
||||||
self.macros: Dict[str, Dict[str, Any]] = {}
|
self.macros: Dict[str, Dict[str, Any]] = {}
|
||||||
self.initial_macros: Dict[str, Dict[str, Any]] = {}
|
self.initial_macros: Dict[str, Dict[str, Any]] = {}
|
||||||
|
|
||||||
|
# Trace nested macros
|
||||||
self._macro_trace: Dict[int, List[str]] = {}
|
self._macro_trace: Dict[int, List[str]] = {}
|
||||||
super().__init__(prog, stack)
|
super().__init__(prog, stack)
|
||||||
|
|
||||||
|
# Register a new macro, which is a name and a sequence of micros
|
||||||
def add_macro(self, name: str, prog: List[str] | Dict[int, str], args: List[str] = None) -> None:
|
def add_macro(self, name: str, prog: List[str] | Dict[int, str], args: List[str] = None) -> None:
|
||||||
if isinstance(prog, list):
|
if isinstance(prog, list):
|
||||||
prog = {i: instr for i, instr in enumerate(prog)}
|
prog = {i: instr for i, instr in enumerate(prog)}
|
||||||
self.macros[name] = {"prog": prog, "args": args}
|
self.macros[name] = {"prog": prog, "args": args}
|
||||||
self.initial_macros[name] = dict(self.macros[name])
|
self.initial_macros[name] = dict(self.macros[name])
|
||||||
|
|
||||||
|
# Automatically flatten macros and then execute
|
||||||
|
@override
|
||||||
def run(self, max_steps: int = 1000):
|
def run(self, max_steps: int = 1000):
|
||||||
# automatically flatten macros before execution
|
self.__flatten_macro()
|
||||||
self._expand_macros_into_prog()
|
|
||||||
return super().run(max_steps)
|
return super().run(max_steps)
|
||||||
|
|
||||||
# --- flatten macros recursively before execution ---
|
# Flatten macros recursively
|
||||||
def _expand_macros_into_prog(self) -> None:
|
def __flatten_macro(self) -> None:
|
||||||
def expand(prog: Dict[int, str], stack: List[str]) -> List[Tuple[str, List[str]]]:
|
def expand(prog: Dict[int, str], stack: List[str]) -> List[Tuple[str, List[str]]]:
|
||||||
out: List[Tuple[str, List[str]]] = []
|
out: List[Tuple[str, List[str]]] = []
|
||||||
for _, call in sorted(prog.items()):
|
for _, micro in sorted(prog.items()):
|
||||||
name, args = self.decode(call)
|
name, args = self.decode(micro)
|
||||||
if name in self.macros:
|
if name in self.macros:
|
||||||
out.extend(expand(self.macros[name]["prog"], stack + [name]))
|
out.extend(expand(self.macros[name]["prog"], stack + [name]))
|
||||||
else:
|
else:
|
||||||
out.append((call, list(stack)))
|
out.append((micro, list(stack)))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
expanded = expand(self.prog, [])
|
expanded = expand(self.prog, [])
|
||||||
self.prog = {i: call for i, (call, _) in enumerate(expanded)}
|
self.prog = {i: call for i, (call, _) in enumerate(expanded)}
|
||||||
self._macro_trace = {i: macros for i, (_, macros) in enumerate(expanded)}
|
self._macro_trace = {i: macros for i, (_, macros) in enumerate(expanded)}
|
||||||
|
|
||||||
|
# Add macros to structure
|
||||||
|
@override
|
||||||
def structure(self) -> Dict[int, Dict[str, Any]]:
|
def structure(self) -> Dict[int, Dict[str, Any]]:
|
||||||
return {
|
return {
|
||||||
i: {"call": call, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog}
|
i: {"micro": micro, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog}
|
||||||
for i, call in sorted(self.prog.items())
|
for i, micro in sorted(self.prog.items())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user