Advertisement
Guest User

Untitled

a guest
Feb 20th, 2017
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.31 KB | None | 0 0
  1. (require '[clojure.string :as str])
  2.  
  3. (defn parse [s]
  4. (->> s
  5. str/split-lines
  6. (map (fn [line]
  7. (let [[action source destination alternative]
  8. (str/split (str/trim line) #" +")]
  9. [action
  10. {:source source
  11. :destination destination
  12. :alternative alternative}])))
  13. (into {})))
  14.  
  15. (defmacro session [protocol-filename [initial-state final-state] & actions]
  16. (let [protocol (parse (slurp (io/resource protocol-filename)))
  17. valid-actions (set (keys protocol))
  18. valid-states (set (mapcat (juxt :source :destination) (vals protocol)))]
  19. (cond
  20. (not (valid-states initial-state))
  21. (throw (ex-info (str "Invalid initial state " initial-state)
  22. {:valid-states valid-states}))
  23. (not (valid-states final-state))
  24. (throw (ex-info (str "Invalid final state " final-state)
  25. {:valid-states valid-states}))
  26.  
  27. :else
  28. (loop [state initial-state
  29. [action & nxt] actions]
  30. (if-not (valid-actions action)
  31. (throw (ex-info (str "Invalid action " action)
  32. {:valid-actions valid-actions}))
  33. (let [{:keys [source destination]} (get protocol action)]
  34. (cond
  35. (not= source state)
  36. (throw (ex-info (str "Action " action " is not valid in state " state) {}))
  37.  
  38. (seq nxt)
  39. (recur destination nxt)
  40.  
  41. (not (= destination final-state))
  42. (throw (ex-info (str "Expected final state " final-state ", got " destination) {}))
  43.  
  44. :else ; we're done! program is correct
  45. (into [] actions))))))))
  46.  
  47. ;; At macro-expansion time, this session will be verified against the protocol
  48. ;; described in "vending-machine.txt", starting in state "waiting" and proving
  49. ;; that the session always ends in state "vended".
  50. (session "vending-machine.txt" ["waiting" "vended"]
  51. ;; "hack" -> Won't compile as it's not a legal action described in vending-machine.txt
  52. "pay"
  53. "return"
  54. ;; "vend" -> Won't compile as it's not a legal action *in this state*.
  55. "pay"
  56. "select"
  57. "vend") ;; if you forgot "vend", it wouldn't compile either, as the final state of this session *must* be "vended"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement