Search code examples
clojureclojurescript

Clojurescript how to read-string map with numeric keywords?


Trying to read a hash map from string but if keys are "keyword" type values I got an error from cljs.reader/read-string. What is the correct way to read a hash-map from string?

This version without keywords work:

(cljs.reader/read-string (pr-str {1 "a", 1481876814936 "sdafa", 1481876816039 "afdas", 1481876817344 "asdfa", 2 "b"}))
=> {1 "a", 1481876814936 "sdafa", 1481876816039 "afdas", 1481876817344 "asdfa", 2 "b"}

But this version with keywords throws an error:

(cljs.reader/read-string (pr-str {:1 "a", :1481876814936 "sdafa", :1481876816039 "afdas", :1481876817344 "asdfa", :2 "b"}))
 cljs.user=> #object[TypeError TypeError: Cannot read property '0' of null]
TypeError: Cannot read property '0' of null
    at cljs$reader$read_keyword (file:///test/resources/public/js/ui-out/cljs/reader.js:681:19)
    at cljs$reader$read_delimited_list (file:///test/resources/public/js/ui-out/cljs/reader.js:397:20)
    at cljs$reader$read_map (file:///test/resources/public/js/ui-out/cljs/reader.js:466:41)
    at cljs$reader$read (file:///test/resources/public/js/ui-out/cljs/reader.js:879:34)
    at cljs$reader$read_string (file:///test/resources/public/js/ui-out/cljs/reader.js:911:25)
    at eval (eval at figwheel$client$utils$eval_helper (file:///test/resources/public/js/ui-out/figwheel/client/utils.js:143:8), <anonymous>:1:114)
    at eval (eval at figwheel$client$utils$eval_helper (file:///test/resources/public/js/ui-out/figwheel/client/utils.js:143:8), <anonymous>:9:3)
    at eval (eval at figwheel$client$utils$eval_helper (file:///test/resources/public/js/ui-out/figwheel/client/utils.js:143:8), <anonymous>:14:4)
    at figwheel$client$utils$eval_helper (file:///test/resources/public/js/ui-out/figwheel/client/utils.js:143:8)
nil

Same code works on clojure:

user=> (read-string (pr-str {:1 "a", :1481876814936 "sdafa", :1481876816039 "afdas", :1481876817344 "asdfa", :2 "b"}))
{:1 "a", :1481876814936 "sdafa", :1481876816039 "afdas", :1481876817344 "asdfa", :2 "b"}

Solution

  • cljs.reader doesn't support keywords starting with a numeric character, probably because symbols, and by extension, keywords, must start with a non-numeric character, though the formulation in the official documentation is open to multiple interpretations. See http://clojure.org/reference/reader#_symbols and http://clojure.org/reference/reader#_literals

    The clojure reader (the jvm implementation) always has supported keywords like :1234 and that's probably not going to change now.

    Shorter example of failure:

    (require 'cljs.reader)
    (cljs.reader/read-string ":1")
    

    Addendum: it's always been possible to construct other kinds of unreadable keywords in clojure using the keyword function and problems resulting from using those keywords fall under "undefined behaviour" - in other words: you're on your own if you do things like (keyword " ")

    Addendum 1: JIRA ticket about the issue in cljs.reader is at http://dev.clojure.org/jira/browse/CLJS-677