From 5366ab48889743eee672dfc148b83bfabd0ed696 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Fri, 2 Dec 2011 18:28:51 -0500 Subject: [PATCH] CLJ-890: Tagged reader literals like #foo/bar --- src/clj/clojure/main.clj | 1 + src/jvm/clojure/lang/Compiler.java | 3 +- src/jvm/clojure/lang/LispReader.java | 44 +++++++++++++++++++++++++++++++++- src/jvm/clojure/lang/RT.java | 3 ++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/main.clj b/src/clj/clojure/main.clj index 8efff8d..487d0fd 100644 --- a/src/clj/clojure/main.clj +++ b/src/clj/clojure/main.clj @@ -94,6 +94,7 @@ *print-meta* *print-meta* *print-length* *print-length* *print-level* *print-level* + *data-readers* *data-readers* *compile-path* (System/getProperty "clojure.compile.path" "classes") *command-line-args* *command-line-args* *unchecked-math* *unchecked-math* diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index cbcf58d..853e331 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -6894,7 +6894,8 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) { LINE_AFTER, pushbackReader.getLineNumber() ,RT.UNCHECKED_MATH, RT.UNCHECKED_MATH.deref() ,RT.WARN_ON_REFLECTION, RT.WARN_ON_REFLECTION.deref() - )); + ,RT.DATA_READERS, RT.DATA_READERS.deref() + )); try { diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index dbb59a6..857d839 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -1145,8 +1145,50 @@ public static List readDelimitedList(char delim, PushbackReader r, boolean isRec public static class CtorReader extends AFn{ public Object invoke(Object reader, Object firstChar){ PushbackReader r = (PushbackReader) reader; + Object name = read(r, true, null, false); + if (!(name instanceof Symbol)) + throw new RuntimeException("Reader tag must be a symbol"); + Symbol sym = (Symbol)name; + if (sym.getNamespace() != null || RT.BUILTIN_DATA_TAGS.contains(sym)) + return readTagged(r, sym); + else + return readRecord(r, sym); + } + + private Object readTagged(PushbackReader reader, Symbol tag){ + Object o = read(reader, true, null, true); + + ILookup data_readers = (ILookup)RT.DATA_READERS.deref(); + IFn data = (IFn)RT.get(data_readers, tag); + if(data != null) + return data.invoke(o); + + // No data reader, just add :data metadata + Object meta = RT.map(RT.DATA_KEY, tag); + int line = -1; + if(reader instanceof LineNumberingPushbackReader) + line = ((LineNumberingPushbackReader) reader).getLineNumber(); + if(o instanceof IMeta) + { + if(line != -1 && o instanceof ISeq) + meta = ((IPersistentMap) meta).assoc(RT.LINE_KEY, line); + if(o instanceof IReference) + { + ((IReference)o).resetMeta((IPersistentMap) meta); + return o; + } + Object ometa = RT.meta(o); + for(ISeq s = RT.seq(meta); s != null; s = s.next()) { + IMapEntry kv = (IMapEntry) s.first(); + ometa = RT.assoc(ometa, kv.getKey(), kv.getValue()); + } + return ((IObj) o).withMeta((IPersistentMap) ometa); + } + else + return o; + } - Object recordName = read(r, true, null, false); + private Object readRecord(PushbackReader r, Symbol recordName){ Class recordClass = RT.classForName(recordName.toString()); char endch; boolean shortForm = true; diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 1d0fba8..9d5f386 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -180,8 +180,11 @@ final static public Var ERR = new PrintWriter(new OutputStreamWriter(System.err), true)).setDynamic(); final static Keyword TAG_KEY = Keyword.intern(null, "tag"); final static Keyword CONST_KEY = Keyword.intern(null, "const"); +final static Keyword DATA_KEY = Keyword.intern(null, "data"); final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.intern("*agent*"), null).setDynamic(); final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.intern("*read-eval*"), T).setDynamic(); +final static public Var DATA_READERS = Var.intern(CLOJURE_NS, Symbol.intern("*data-readers*"), RT.map()).setDynamic(); +final static public IPersistentSet BUILTIN_DATA_TAGS = RT.set(); final static public Var ASSERT = Var.intern(CLOJURE_NS, Symbol.intern("*assert*"), T).setDynamic(); final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.intern("*math-context*"), null).setDynamic(); static Keyword LINE_KEY = Keyword.intern(null, "line"); -- 1.7.4.1