Skip to content

Instantly share code, notes, and snippets.

@xsc
Last active October 29, 2016 12:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xsc/a2baff46d43324b640adca5a5ec55198 to your computer and use it in GitHub Desktop.
Save xsc/a2baff46d43324b640adca5a5ec55198 to your computer and use it in GitHub Desktop.
Useless Language AST (clojure.spec)
;; The AST consists of declarations and calls.
(s/def :lang/ast
(s/keys :req [:lang/declarations :lang/calls]))
;; Throughout, we'll use variables/calls identified by their name.
(s/def :lang/name
(s/and string? #(re-matches #"[a-z]+" %)))
(s/def :lang/variable-name
:lang/name)
(s/def :lang/call-name
:lang/name)
;; Declarations are maps containing a single variable name.
(s/def :lang/declarations
(s/coll-of :lang/declaration))
(s/def :lang/declaration
(s/keys :req [:lang/variable-name]))
;; Calls are maps containing the name of the call and the variables to
;; be used as parameters.
(s/def :lang/calls
(s/coll-of :lang/call))
(s/def :lang/call
(s/keys :req [:lang/call-name :lang/call-parameters]))
(s/def :lang/call-parameters
(s/coll-of :lang/variable-name))
(def ^:dynamic *variable-names* nil)
(defn variable-name-declared-before-use?
[n]
(or (not *variable-names*)
(contains? *variable-names* n)))
(s/def :lang/variable-name
(s/and :lang/name variable-name-declared-before-use?))
(defn verify-ast
[{:keys [lang/declarations] :as ast}]
(let [variable-names (set (map :lang/variable-name declarations))]
(binding [*variable-names* variable-names]
(s/explain-data :lang/ast ast))))
(defn variable-names-declared-before-use?
[{:keys [lang/declarations lang/calls]}]
(let [valid-variable-name? (set (map :lang/variable-name declarations))
used-variable-names (mapcat :lang/call-parameters calls)]
(every? valid-variable-name? used-variable-names)))
(s/def :lang/ast-with-predicates
(s/and :lang/ast
variable-names-declared-before-use?))
(s/def :lang/valid-ast
(s/with-specialisation
:lang/ast
(fn [ast]
{:lang/variable-name (variable-name-declared? ast)
:lang/declarations variable-names-unique?})))
;; or as constant specialisation:
(defn valid-ast-spec
[ast]
(s/specialised
:lang/ast
{:lang/variable-name (variable-name-declared? ast)
:lang/declarations variable-names-unique?}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment