diff --git a/load/simple-state-machines.el b/load/simple-state-machines.el index b7f213b..d73eb60 100644 --- a/load/simple-state-machines.el +++ b/load/simple-state-machines.el @@ -61,7 +61,31 @@ ;; 'test-step' -- Calls the handler for the current state. ;; 'test-set-state' -- Tries to set the current state to the provided one, and ;; signals an error if the transition is invalid. - +;; +;; Here is the recreation of the counter example from +;; https://www.emacswiki.org/emacs/StateMachine +;; +;; (ssm-defstate-machine counter +;; :states (start count end) +;; :transitions ((start . count) +;; (count . end) +;; (count . count)) +;; :handlers ((start . (lambda (name) +;; (princ "Starting...") +;; (terpri) +;; (ssm-update-state name 'count 0))) +;; (count . (lambda (name) +;; (cond ((<= (ssm-get-state-data name) 10) +;; (princ (ssm-get-state-data name)) +;; (ssm-update-state +;; name +;; 'count +;; (1+ (ssm-get-state-data name)))) +;; (t (terpri) (ssm-update-state name 'end nil))))))) +;; +;; (ssm-run-until-state 'counter 'end) +;; +;; As you can see, ssm-update-state definitely needs some love. It is unwieldy. ;;; Code: (require 'cl-lib) @@ -142,7 +166,7 @@ Each entry of this alist has the form (FROM . TO).")) (let ((,handler (alist-get ,current-state ,handlers-table)) (,prev-state ,current-state)) (cl-assert ,handler nil "There is no handler for the current state") - (funcall ,handler ,machine-name) + (funcall ,handler ',name) (cl-assert (cl-find (cons ,prev-state ,current-state) @@ -165,12 +189,31 @@ Each entry of this alist has the form (FROM . TO).")) (setq ,current-state state ,state-data new-data)))))))) -(defun ssm-update-state (machine new-state &optional new-data) +(defun ssm-update-state (machine new-state new-data) "Updates the state of the state machine MACHINE. Signals an error if the state transition is invalid." (let ((state-fn - (intern-soft (concat machine "-set-state")))) + (intern-soft (concat (symbol-name machine) "-set-state")))) (funcall state-fn new-state new-data))) +(defun ssm-get-state (machine) + "Returns the state of the specified machine." + (let ((state + (intern-soft (concat (symbol-name machine) "-current-state")))) + (symbol-value state))) + +(defun ssm-get-state-data (machine) + "Returns the state data of the specified machine." + (let ((state-data + (intern-soft (concat (symbol-name machine) "-state-data")))) + (symbol-value state-data))) + +(defun ssm-run-until-state (machine state) + "Steps the specified MACHINE until it enters state STATE." + (let ((step-fn + (intern-soft (concat (symbol-name machine) "-step")))) + (while (not (equal (ssm-get-state machine) state)) + (funcall step-fn)))) + (provide 'simple-state-machines) ;;; simple-state-machines.el ends here diff --git a/load/simple-state-machines.elc b/load/simple-state-machines.elc index 905a51f..1c44207 100644 Binary files a/load/simple-state-machines.elc and b/load/simple-state-machines.elc differ