Clojure

Tagged literals in reader

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Patch:
    Code
  • Approval:
    Vetted
  1. CLJ-890-001.patch
    02/Dec/11 5:32 PM
    5 kB
    Stuart Sierra
  2. CLJ-890-002.patch
    09/Dec/11 3:08 PM
    6 kB
    Stuart Sierra

Activity

Hide
Brandon Bloom added a comment -

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

Show
Brandon Bloom added a comment - 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
Hide
Stuart Sierra added a comment - - edited

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

Show
Stuart Sierra added a comment - - edited Patch CLJ-890-002.patch applied following discussion with Rich. Will be included in release 1.4.0-alpha4
Hide
Stuart Sierra added a comment -

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*
Show
Stuart Sierra added a comment - 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*
Hide
Stuart Sierra added a comment -

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}
Show
Stuart Sierra added a comment - 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}

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: