From d498ae8d6a4e84b13ccabe320fa5e35eba9218b1 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 19 Sep 2024 17:13:13 -0400 Subject: [PATCH] Now a working demo of FSM and DBC for the blog post. --- .gitignore | 1 + python/dbc.py | 23 +++++++++++++++++++ python/dbc_test.py | 26 ++++++++++++++++++++++ python/fsm.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++ python/fsm_test.py | 8 +++++++ status.txt | 3 +++ 6 files changed, 116 insertions(+) create mode 100644 python/dbc.py create mode 100644 python/dbc_test.py create mode 100644 python/fsm.py create mode 100644 python/fsm_test.py create mode 100644 status.txt diff --git a/.gitignore b/.gitignore index bafeaa5..40d2c65 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ subprojects *.dll *~ [0-9]* +__pycache__ diff --git a/python/dbc.py b/python/dbc.py new file mode 100644 index 0000000..e28051b --- /dev/null +++ b/python/dbc.py @@ -0,0 +1,23 @@ +import traceback + +class DBCError(Exception): pass +class CheckError(DBCError): pass +class PreError(DBCError): pass +class PostError(DBCError): pass +class SentinelError(DBCError): pass + +def check(test, msg, cls=CheckError): + print(">>> ", msg) + traceback.print_stack(limit=-1) + if not test: + raise cls(msg) + +def pre(test, msg): + check(test, msg, PreError) + +def post(test, msg): + check(test, msg, PostError) + +def sentinel(): + traceback.print_stack(limit=-1) + raise SentinelError() diff --git a/python/dbc_test.py b/python/dbc_test.py new file mode 100644 index 0000000..0e971a4 --- /dev/null +++ b/python/dbc_test.py @@ -0,0 +1,26 @@ +import dbc +import traceback + +print("---- CHECK ---") +try: + dbc.check(1 == 2, "Check Failed!") +except dbc.CheckError as e: + print("Check failure:", e) + +print("---- SENTINEL ---") +try: + dbc.sentinel() +except dbc.SentinelError as e: + print("Sentinel failure:", e) + +print("---- PRECOND ---") +try: + dbc.pre(1 == 2, "Pre Failed!") +except dbc.PreError as e: + print("Pre condition failure: ", e) + +print("---- POSTCOND ---") +try: + dbc.post(1 == 2, "Post Failed!") +except dbc.PostError as e: + print("Post condition failure:", e) diff --git a/python/fsm.py b/python/fsm.py new file mode 100644 index 0000000..9f468c3 --- /dev/null +++ b/python/fsm.py @@ -0,0 +1,55 @@ + +def START(): + return LISTENING + +def LISTENING(event): + if event == "connect": + return CONNECTED + elif event == "error": + return LISTENING + else: + return ERROR + +def CONNECTED(event): + if event == "accept": + return ACCEPTED + elif event == "close": + return CLOSED + else: + return ERROR + +def ACCEPTED(event): + if event == "close": + return CLOSED + elif event == "read": + return READING(event) + elif event == "write": + return WRITING(event) + else: + return ERROR + +def READING(event): + if event == "read": + return READING + elif event == "write": + return WRITING(event) + elif event == "close": + return CLOSED + else: + return ERROR + +def WRITING(event): + if event == "read": + return READING(event) + elif event == "write": + return WRITING + elif event == "close": + return CLOSED + else: + return ERROR + +def CLOSED(event): + return LISTENING(event) + +def ERROR(event): + return ERROR diff --git a/python/fsm_test.py b/python/fsm_test.py new file mode 100644 index 0000000..0b076d1 --- /dev/null +++ b/python/fsm_test.py @@ -0,0 +1,8 @@ +import fsm + +state = fsm.START() +script = ["connect", "accept", "read", "read", "write", "close", "connect"] + +for event in script: + print(event, ">>>", state) + state = state(event) diff --git a/status.txt b/status.txt new file mode 100644 index 0000000..e2c0508 --- /dev/null +++ b/status.txt @@ -0,0 +1,3 @@ +Welcome! + +Working on a blog post about Finite State Machines and Design-by-Contract. Feel free to ask for advice about anything programming or art related.