Last active
April 16, 2017 04:34
-
-
Save madstap/e9ecaa37db3637f9ac8132d58ce0e191 to your computer and use it in GitHub Desktop.
Code golfer as a macro
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns golf.code-golfer) | |
(def ^:private safe-neighbors | |
"The characters that indicate neighboring spaces are safe to remove." | |
(set "(){}[]\"")) | |
(defn- whitespace? [x] | |
{:pre [(char? x)]} | |
(Character/isWhitespace x)) | |
(def ^:private safe-or-nil? | |
(some-fn safe-neighbors nil?)) | |
(defn one? [x] (== 1 x)) | |
(defn- split-into-neighbors [s] | |
(if (one? (count s)) | |
[[nil (first s) nil]] | |
(let [[[a b c] :as xs] (butlast (partition-all 3 1 s))] | |
(conj xs [nil a b])))) | |
(defn- minimize-fn [code-str] | |
(first | |
(reduce (fn [[acc inside-str?] [a x b]] | |
(cond | |
inside-str? (if (= \" x) | |
[(str acc x) false] | |
[(str acc x) inside-str?]) | |
(= \" x) | |
[(str acc x) true] | |
(and x (Character/isWhitespace x) (or (safe-or-nil? a) | |
(safe-or-nil? b))) | |
[acc inside-str?] | |
:else [(str acc x) inside-str?])) | |
["" false] | |
(split-into-neighbors code-str)))) | |
(defmacro golf [& body] | |
(->> body (map pr-str) (interpose " ") (apply str) minimize-fn)) | |
(comment | |
(= "" (golf)) | |
(= "1" (golf 1)) | |
(= "foo bar" (golf foo bar)) | |
(= "foo[1 2[baz]]3" (golf foo [1 2 [baz]] 3)) | |
(= "foo\"[] []\"" (golf foo "[] []")) | |
(= "(defn f[x](inc x))" | |
(golf (defn f [x] | |
;; Increments x | |
(inc x)))) | |
(= "(foo)" (golf (foo #_bar))) | |
;; TODO: Ideally this would return "'(1 2 3)" | |
(= "(quote(1 2 3))" (golf '(1 2 3))) | |
;; Quotes inside strings will trip it up | |
(= "[\"\\\"\"[]]" (golf ["\"" []])) ;=> false | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment