Skip to content
Snippets Groups Projects

Docstring refactor of core

Merged Johannes Kung requested to merge docstring_refactor into main
All threads resolved!
20 files
+ 993
509
Compare changes
  • Side-by-side
  • Inline
Files
20
+ 103
81
@@ -6,16 +6,16 @@ from os.path import exists, isdir
from simudator.core.processor import Processor
HELP_TEXT = """Here is a list of possible commands:
CLI control:
CLI control:
- h, help : Shows this message.
- q, quit : Closes the program. Nothing will be saved.
Simulation control:
Simulation control:
- n [x], next [x]: Simulates x ticks.
If no x is given, simulates one tick.
- rc, run_continuously:
- rc, run_continuously:
Continuously simulate ticks until a HALT is signalled
or a breakpoint is reached.
@@ -30,72 +30,78 @@ State information:
- p, print: Prints all states of all modules.
- pl, printlist [add/remove] [module name] ...:
Add or remove the given modules to a list of modules to print. If no
Add or remove the given modules to a list of modules to print. If no
arguments are given, i.e. "pl" or "printlist" on their own, all the modules
in the list will be printed.
- pp, pretty print: Prints relevant processor state information in a
- pp, pretty print: Prints relevant processor state information in a
readable and compact format.
- ppv, pretty print verbose: Prints all processor state information in a
- ppv, pretty print verbose: Prints all processor state information in a
readable and compact format.
Breakpoints:
Breakpoints:
- p br, print breaks: Prints all breakpoints.
- p br lam, print break lambdas:
Prints all available lambdas of this processor to use for lambda
breakpoints.
- p br lam, print break lambdas:
Prints all available lambdas of this processor to use for lambda
breakpoints.
- br state, break state [module name] [state name] [value]:
Add a breakpoint for the module with the given name. The breakpoint brakes
Add a breakpoint for the module with the given name. The breakpoint brakes
when the specified state of the module has the specified value.
- br mem, break memory [module name] [adress] [value]:
Add a breakpoint for a memory module with the given name. The breakpoint
breaks when the specified adress of the memory has the specified value.
- br mem, break memory [module name] [address] [value]:
Add a breakpoint for a memory module with the given name. The breakpoint
breaks when the specified address of the memory has the specified value.
- br lam, break lambda [lambda_name] [keyword argument] ...:
Add a breakpoint that uses the referenced lambda to evaluate when to
break. Any module names in the keyword arguments will be substituted with
Add a breakpoint that uses the referenced lambda to evaluate when to
break. Any module names in the keyword arguments will be substituted with
the actual module. Strings must be enclosed with quotation marks.
- rm br [id], remove break [id]:
Remove the breakpoint with the given ID.
File I/O:
File I/O:
- l, load [path]:
Loads a processors state from a given file path.
- sf, save to file [path]:
Saves the processor state to the specified file.
Saves the processor state to the specified file.
"""
class CLI:
"""
Terminal based program for controlling a processor.
Mostly used for testing and debugging.
Parameters
----------
processor : Processor
"""
def __init__(self, processor: Processor):
self.running = True
self.processor = processor
self.print_list = []
self._running = True
self._processor = processor
self._print_list = []
def run(self) -> None:
"""
Runs the CLI.
Will put the user in an input loop where they can send commands to the program
"""Run the CLI.
Put the user in an input loop where they can send commands to the
program.
"""
print("Welcome to simuDAtor!")
while self.running:
while self._running:
# Get user commands here
user_input = input("> ")
# Note: Keep the order of the cases consistent with the help text
# Note: Keep the order of the cases consistent with the help text
# for convenience
match user_input.split():
# CLI control -------------------------------------------------
@@ -106,7 +112,7 @@ class CLI:
case ["q"] | ["quit"]:
# Ends the loop
print("Goodbye")
self.running = False
self._running = False
# Simulation control ------------------------------------------
case ["n"] | ["next"]:
@@ -114,7 +120,7 @@ class CLI:
# this could take time for larger simulations,
# could be good to add loading icon and stop user input
self.processor.do_tick()
self._processor.do_tick()
case ["n", _] | ["next", _]:
# runs a given number of ticks
@@ -123,32 +129,32 @@ class CLI:
try:
for _ in range(int(user_input.split()[1])):
self.processor.do_tick()
if self.processor.is_stopped:
self._processor.do_tick()
if self._processor.is_stopped:
break
if self.processor.breakpoint_reached:
bp = self.processor.last_breakpoint
if self._processor.breakpoint_reached:
bp = self._processor.last_breakpoint
print(f"Reached breakpoint: {bp}")
if self.processor.should_halt():
if self._processor.should_halt():
print("The processor halted")
except ValueError:
print("Invalid value")
case ["rc"] | ["run_continuously"]:
self.processor.run_continuously()
if self.processor.breakpoint_reached:
bp = self.processor.last_breakpoint
self._processor.run_continuously()
if self._processor.breakpoint_reached:
bp = self._processor.last_breakpoint
print(f"Reached breakpoint: {bp}")
if self.processor.should_halt():
if self._processor.should_halt():
print("The processor halted")
case ["u"] | ["undo"]:
# undo one clock cycles
current_cycle = self.processor.get_clock()
current_cycle = self._processor.get_clock()
try:
self.processor.load_cycle(max(current_cycle - 1, 0))
self._processor.load_cycle(max(current_cycle - 1, 0))
except IndexError:
print("Index out of range")
@@ -162,46 +168,46 @@ class CLI:
print("Invalid value")
continue
current_cycle = self.processor.get_clock()
current_cycle = self._processor.get_clock()
try:
self.processor.load_cycle(max(current_cycle - number, 0))
self._processor.load_cycle(max(current_cycle - number, 0))
except IndexError:
print("Index out of range")
case ["r"] | ["resets"]:
# self.processor.load_cycle(0)
self.processor.reset()
self._processor.reset()
# State information -------------------------------------------
case ["c"] | ["clock"]:
# shows current clockcycle
print("Clock is at: ", str(self.processor.get_clock()))
print("Clock is at: ", str(self._processor.get_clock()))
case ["p"] | ["print"]:
print("\n")
# prints all module states, is most prbably hard to read
for module in self.processor.get_modules():
for module in self._processor.get_modules():
module.print_module()
print("\n")
case ["pl", *_] | ["printlist", *_]:
self.print_list_command(user_input.split())
self._print_list_command(user_input.split())
case ["pp"] | ["pretty print"]:
# pretty print the modules of the processor
self.processor.pretty_print()
self._processor.pretty_print()
case ["ppv"] | ["pretty print verbose"]:
# pretty print the modules of the processor
# with all available information
self.processor.pretty_print_verbose()
self._processor.pretty_print_verbose()
# Breakpoints -------------------------------------------------
case ["p", "br"] | ["print", "breaks"]:
self.processor.print_breakpoints()
self._processor.print_breakpoints()
case ["p", "br", "lam"] | ["print", "break", "lambdas"]:
lambdas = self.processor.get_breakpoint_lambdas()
lambdas = self._processor.get_breakpoint_lambdas()
if not lambdas:
print("There are no lambdas for this processor.")
else:
@@ -212,7 +218,7 @@ class CLI:
state_name = user_input.split()[3]
val = ast.literal_eval(user_input.split()[4])
try:
self.processor.add_state_breakpoint(
self._processor.add_state_breakpoint(
module_name, state_name, val
)
except ValueError as e:
@@ -221,9 +227,11 @@ class CLI:
case ["br", "mem", _, _, _] | ["break", "memory", _, _, _]:
module_name = user_input.split()[2]
try:
adress = ast.literal_eval(user_input.split()[3])
address = ast.literal_eval(user_input.split()[3])
value = ast.literal_eval(user_input.split()[4])
self.processor.add_memory_breakpoint(module_name, adress, value)
self._processor.add_memory_breakpoint(
module_name, address, value
)
except ValueError as e:
print(e)
@@ -235,14 +243,14 @@ class CLI:
key, value = kwarg.split('=')
kwargs[key] = ast.literal_eval(value)
try:
self.processor.add_lambda_breakpoint(lambda_name, **kwargs)
self._processor.add_lambda_breakpoint(lambda_name, **kwargs)
except ValueError as e:
print(e)
case ["rm", "br", _] | ["remove", "break", _]:
try:
bp_id = int(user_input.split()[2])
if not self.processor.remove_breakpoint(bp_id):
if not self._processor.remove_breakpoint(bp_id):
print(f"No breakpoint with ID {bp_id}")
except ValueError:
print("Breakpoint ID must be an integer")
@@ -251,36 +259,38 @@ class CLI:
case ["l", _] | ["load", _]:
# load processor state from file
try:
self.processor.reset()
self.processor.load_state_from_file(user_input.split()[1])
self._processor.reset()
self._processor.load_state_from_file(user_input.split()[1])
except FileNotFoundError:
print("No file called ", user_input.split()[1], " was found")
case ["sf"] | ["save to file"]:
file_path = "cpu_save_file"
self.processor.save_state_to_file(file_path)
self._processor.save_state_to_file(file_path)
case ["sf", _] | ["save to file", _]:
file_path = user_input.split()[1]
self.check_file_path(file_path)
self._save_to_file(file_path)
# -------------------------------------------------------------
case _:
# message for unknown command
print("Unknown command. Write \"help\" for assistance.")
def check_file_path(self, file_path) -> None:
"""
Checks the file path user gave as input. If it is a directory
this funciton will simply return and not write anything. If it
is a file that already exists it will demand a 'yes' or 'no' from
user to decide if it should write over the existing file.
If the given file does not exist it will simply create the file.
def _save_to_file(self, file_path: str) -> None:
"""Save the processor state to the given file path.
No save is made if the file path is a directory. If the file already
exists, the user is given the choice to overwrite the file.
Parameters
----------
file_path : str
"""
# Given file does not exist, save_state_to_file will create it
if not exists(file_path):
self.processor.save_state_to_file(file_path)
self._processor.save_state_to_file(file_path)
else:
# We dont touch directories
@@ -299,17 +309,27 @@ class CLI:
print("Please give an input of 'yes' or 'no'!")
if overwrite == "yes":
self.processor.save_state_to_file(file_path)
return
else:
return
def print_list_command(self, user_input):
self._processor.save_state_to_file(file_path)
def _print_list_command(self, user_input: list[str]) -> None:
"""Add/remove modules to internal list or print all modules in the
internal list.
Parameters
----------
user_input : list[str]
A print list command split by spaces. Should be on the format
``["printlist", "add", MODULE_NAME, ...]`` or
``["printlist", "remove", MODULE_NAME, ...]`` to add or remove
modules, where MODULE_NAME is the name of a module as a string,
or ``["printlist"]`` to print all added modules.
(``"printlist"`` can be substituted with ``"pl"``)
"""
# no additional commands so only print
if len(user_input) == 1:
print("\n")
for name in self.print_list:
self.processor.get_module(name).print_module()
for name in self._print_list:
self._processor.get_module(name).print_module()
print("\n")
return
@@ -319,17 +339,19 @@ class CLI:
for name in names:
# check if name exists
try:
self.processor.get_module(name)
if name not in self.print_list:
self.print_list.append(name)
self._processor.get_module(name)
if name not in self._print_list:
self._print_list.append(name)
except KeyError:
print("No module named", name,)
print(
"No module named",
name,
)
elif user_input[1] == "remove":
for name in names:
if name in self.print_list:
self.print_list.remove(name)
if name in self._print_list:
self._print_list.remove(name)
else:
print(name, "not in print list")
else:
Loading