Last active
November 3, 2017 17:21
-
-
Save blasut/b4ae4d594db0c9434207c002ca463bd3 to your computer and use it in GitHub Desktop.
This file contains 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 playingwithsyntax.core) | |
;; We can define our own 'reader', which says that <> are waaay coler than Sexps. | |
;; We "bottom" out to clojure, so we parse the <>-exp and return a sexp that clojure understands. | |
;; To support list literals we can return a quoted list from read. | |
(comment | |
;; This is useful for stepping through the my-read function | |
(def string-to-read "(+ 1 1)") | |
(def string-to-read "<+ 1 1>")) | |
(defn my-read [string-to-read] | |
(cond | |
(= \( (first string-to-read)) (read-string (str "'" string-to-read)) | |
(= \< (first string-to-read)) (-> string-to-read | |
(clojure.string/replace "<" "(") | |
(clojure.string/replace ">" ")") | |
(read-string)) | |
:else (read-string string-to-read))) | |
(my-read "<+ 1 1>") ;; => (+ 1 1) | |
(my-read "(+ 1 1)") ;; => (quote (+ 1 1)) | |
;; So now we dont have sexps anymore (for an very small example ofc, only works with a single form) | |
(eval (my-read "<+ 1 1>")) | |
;; => 2 | |
(eval (my-read "(+ 1 1)")) | |
;; => (+ 1 1) | |
;; the rest of clojure works as normal | |
(eval (my-read "{:a 3}")) | |
;; => {:a 3} | |
;; This is because macroexpansion works by receiving forms that are READ, macros operate on clojure data not on strings. | |
;; We don't have access to adding new syntax to the read-table in clojure. | |
;; And we can't extend the tagged literals because those are read AFTER clojure read. | |
;; Or, we could add a tagged literal that is the <>-sexp. But that is the same thing as here, but nicer. | |
;; It still has to read a stream, it doesn't change the clojure-built in read-table. | |
;; So we could use EDN tagged literals to build our new syntax, call it "clo<ure>" and read it in with tagged literals. | |
;; But this is fundamentally different to changing the read-table. | |
;; And the syntax would be a bit different because of how the reader works I think... Should try that though | |
;; So one would have to use our reader and READ from some stream BEFORE the clojure reader does anything. | |
;; this can be achieved by overwriting which reader clojure is using, like rebinding it when starting a new repl. | |
;; We can't just use a the new "syntax" with a macro without putting the <> forms into a string when passing it into the macro. | |
;; so the macro has to take a string or a normal clojure form, which is lol. doesn't work | |
(defmacro my-syntax [forms] | |
(if (string? forms) | |
`(my-read ~forms) | |
`(my-read ,(prn-str '~forms)))) | |
(macroexpand '(my-syntax (+ 1 1))) | |
(macroexpand '(my-syntax "<+ 5 5>")) | |
(my-syntax (+ 1 1)) | |
(my-syntax 5) | |
;; this works | |
(my-syntax "<+ 5 5>") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment