<< Back to previous view

[CLJ-890] Tagged literals in reader Created: 02/Dec/11  Updated: 01/Mar/13  Resolved: 03/Feb/12

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Stuart Sierra Assignee: Stuart Sierra
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJ-890-001.patch     Text File CLJ-890-002.patch    
Patch: Code
Approval: Vetted

 Description   

See http://dev.clojure.org/display/design/Tagged+Literals



 Comments   
Comment by Stuart Sierra [ 02/Dec/11 5:32 PM ]

Rough draft in CLJ-890-001.patch:

This adds reader tags like #user/foo. If the symbol following the # is namespace-qualified, or if it is one of a predefined set of built-in tags (currently empty) it is interpreted as a tag. Otherwise, it is interpreted as a class name, as in defrecord literals.

The dynamic Var *data-readers* is a map from tags (symbols) to reader functions/Vars. Each invocation of Compiler.load creates a new thread-local binding, as does the REPL. At the top of a source file, use (set! *data-readers* ...) to define the tags just for that file. For runtime invocations of the reader, use binding.

When reading a tagged literal, if the tag is not defined in *data-readers* it is added as :data metadata on the following form. If the following form does not support metadata, the tag is ignored. This causes a problem when an undefined tag is used in source code, because the compiler tries to evaluate it:

user=> #foo.bar/bar {:a 1}
CompilerException java.lang.RuntimeException: No such var: foo.bar/bar, compiling:(NO_SOURCE_PATH:0) 
user=> (quote #foo.bar/bar {:a 1})
{:a 1}
user=> (meta *1)
{:data foo.bar/bar}
Comment by Stuart Sierra [ 09/Dec/11 3:08 PM ]

New file CLJ-890-002.patch:

  • tag definitions loaded from /data_readers.clj files on classpath
  • read as a series of symbol-symbol pairs
  • "target" symbol interpreted as a Var
  • creates namespaces and interns Vars as necessary
  • may be more than one file
  • throws exception on conflict
  • sets root binding of *data-readers*
Comment by Stuart Sierra [ 13/Jan/12 8:28 AM ]

Patch CLJ-890-002.patch applied following discussion with Rich. Will be included in release 1.4.0-alpha4

Comment by Brandon Bloom [ 16/Aug/12 9:48 PM ]

It would be a small extension to allow overriding of readers for untagged forms as well.

For example, MapReader currently calls RT.map(a) when it could call RT.get(data_readers, MAP_TAG).invoke(a)

This would allow consumers of the reader to supply their own implementations for any basic data structure. Not that anyone is likely to have a better map/set/etc, but I could see it being useful for using a different RegExp engine or something like that. The primary use case I have in mind, however, is the ClojureScript compiler. The compiler needs to know the order of the key-value-pairs in a map or the elements in a set. See CLJS-288

Generated at Sat Jul 26 10:16:02 CDT 2014 using JIRA 4.4#649-r158309.