From e8da28436538647eb428ba04143798a24a00f66f Mon Sep 17 00:00:00 2001 From: stupidcomputer Date: Sun, 16 Jun 2024 20:12:08 -0500 Subject: [PATCH] add a proper command line interface --- README.md | 15 +++---- cli/cli.py | 99 ++++++++++++++++++++++++++++++++++--------- cli/lib/clientside.py | 12 ++++-- cli/lib/server.py | 15 +++++-- 4 files changed, 104 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 0810b2f..6f9c679 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,14 @@ # desmos-computer ## What is this? -- a client-server architecture for synchronizing a file containing Desmos expressions to a graph, -- a test suite for evaluating the 'correctness' of Desmos expressions, -- an instruction set architecture for Turing machines whose cells contain IEEE 754 compliant integers in each cell, -- an assembler for that instruction set architecture, -- and other utilities. +- a client-server architecture for synchronizing a file containing Desmos expressions to a graph, (`cli/lib/server.py` and `cli/lib/clientside.py`) +- an instruction set architecture for Turing machines whose cells contain IEEE 754 compliant integers in each cell, (`cli/data/computer.py`) +- an assembler for that instruction set architecture, (not yet!) +- and other utilities. (disassembler, etc.) ## How does the ISA work? The 'CPU', implemented in Desmos, takes in a list (aka an array, Turing tape, etc.) and starts execution at cell 1 (lists have 1-based indexes in Desmos). -The list also serves as the memory, as well. (Think like Befunge's `p` command. +The list also serves as the memory, as well. (Think like Befunge's `p` command.) *Todo: disconnect opcode definitions and opcodes from the actual CPU implementation. Because of this, don't rely on this table! Check the implementation in `data/computer.desmos`.* @@ -43,10 +42,10 @@ Things we're optimizing for: In general: *embed the intelligence into the machine code, **not** the CPU/ISA!* ## Things to do -- [ ] Write a test suite for evaluating arbitrary Desmos expressions and getting their expected outputs. +- [x] Write a test suite for the various instruction of the ISA executing *in Desmos* - [ ] Write an assembler to compile a custom Assembly language to native Desmos list format. - [ ] Simplify all this into a command line tool. -- [ ] Simplify the synchronization stack. +- [x] Simplify the synchronization stack. - [ ] Write documentation for all of this. ## License diff --git a/cli/cli.py b/cli/cli.py index 0cf6204..3d80397 100644 --- a/cli/cli.py +++ b/cli/cli.py @@ -2,29 +2,86 @@ from .lib.server import DesmosGraphServer from .lib.graphparser import DesmosGraph, DesmosGraphOverride from .lib.clientside import payload as JSGraphPayload -from .tests.isa import test_entry_point +from .data.computer import payload as ComputerPayload +from .data.testing import payload as TestingPayload + +import pyperclip + +import argparse + +def handle_sync(parser): + if parser.copy_userscript: + pyperclip.copy(JSGraphPayload) + print("copied userscript to clipboard") + + if parser.filename: + graph = DesmosGraph.from_file(parser.filename) + + if parser.override: + override = DesmosGraphOverride.from_file(parser.override) + graph.include_override(override) + + server = DesmosGraphServer() + server.instructions_to_run = [] + server.append_inst({ + "type": "insert_graph", + "graph": graph, + }) + server.start(no_stop=True) + +def handle_data(parser): + if parser.dataname: + if parser.dataname == "computer.desmos": + print(ComputerPayload) + elif parser.dataname == "testing.desmos": + print(TestingPayload) + return + + if parser.list: + parsers = ["computer.desmos", "testing.desmos"] + print('\n'.join(parsers)) def main(): -# graph = DesmosGraph.from_file("data/computer.desmos") -# override = DesmosGraphOverride.from_file("test.override") -# -# graph.include_override(override) -# server = DesmosGraphServer() -# server.append_inst({ -# "type": "insert_graph", -# "graph": graph, -# }) -# server.append_inst({ -# "type": "test_graph", -# "graph": graph, -# "name": "test and assert addition", -# "expectedOutput": [1, 4, 6, 0, 0, 4], -# "expression": "B", -# }) -# server.start() -# print(server.outputs) -# - test_entry_point() + parser = argparse.ArgumentParser( + prog="desmosisa", + description="a smörgåsbord of utilities for desmos, including some implementations of an desmos-based isa", + ) + subparsers = parser.add_subparsers(dest="subparser_name") + sync_parser = subparsers.add_parser("sync", help="desmos calculator synchronization utilities") + sync_parser.add_argument( + 'filename', + nargs='?', + help="filename of DesmosExpressions to synchronize with client" + ) + sync_parser.add_argument( + '-o', '--override', + help="filename of DesmosOverride file, to override certain expressions in the DesmosExpression file", + action="store" + ) + sync_parser.add_argument( + '-c', '--copy-userscript', + help="copy the userscript to the clipboard, to be pasted into the JS console within the calculator.", + action="store_true" + ) + + data_parser = subparsers.add_parser("data", help="access various prebuilt files") + data_parser.add_argument( + 'dataname', + nargs='?', + help='name of the datafile requested' + ) + data_parser.add_argument( + '-l', '--list', + help='list available datafiles', + action='store_true' + ) + + args = parser.parse_args() + + if args.subparser_name == "sync": + handle_sync(args) + if args.subparser_name == "data": + handle_data(args) if __name__ == "__main__": main() diff --git a/cli/lib/clientside.py b/cli/lib/clientside.py index be51379..827bc24 100644 --- a/cli/lib/clientside.py +++ b/cli/lib/clientside.py @@ -11,6 +11,8 @@ function arraysEqual(a, b) { return true; } +var refresh = true; + function main() { let socket = new WebSocket("ws://localhost:8764"); var toCompare = ""; @@ -21,9 +23,11 @@ function main() { } socket.onclose = function(e) { - setTimeout(function() { - main(); - }, 1000); + if (refresh) { + setTimeout(function() { + main(); + }, 1000); + } } socket.onmessage = function(e) { @@ -83,5 +87,5 @@ function main() { console.log(`[LOG] couldn't parse message ${e.data}`) } } -} main(); +} """ diff --git a/cli/lib/server.py b/cli/lib/server.py index 304e03f..e85f261 100644 --- a/cli/lib/server.py +++ b/cli/lib/server.py @@ -89,18 +89,25 @@ class DesmosGraphServer: } ) - self.stop.set_result("sotp please!!!!") + if self.stop: + self.stop.set_result("sotp please!!!!") async def main(self, stop): async with serve(self.ws_main, "localhost", 8764): self.stop = stop - await stop + if not stop: + await asyncio.Future() + else: + await stop - def start(self): + def start(self, no_stop=False): loop = asyncio.get_event_loop() stop = loop.create_future() - loop.run_until_complete(self.main(stop)) + if no_stop: + loop.run_until_complete(self.main(stop=None)) + else: + loop.run_until_complete(self.main(stop=stop)) def append_inst(self, inst): self.instructions_to_run.append(inst)