Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

split off arbitrary eval parts of #= and flip default for *read-eval*…

… to false. N.B. this does not disable #=, only arbitrary eval using #=.
  • Loading branch information...
commit 974a64c06917861b7557fd73154254195b2de548 1 parent cdc037d
@richhickey richhickey authored
View
9 src/clj/clojure/core.clj
@@ -5871,11 +5871,12 @@
{:added "1.0"})
(add-doc-and-meta *read-eval*
- "When set to logical false, the EvalReader (#=(...)) is disabled in the
- read/load in the thread-local binding.
- Example: (binding [*read-eval* false] (read-string \"#=(eval (def x 3))\"))
+ "When set to logical true in the thread-local binding, the eval
+ reader (#=(...)) for arbitrary expressions is enabled in read/load.
+ Example:
+ (binding [*read-eval* true] (read-string \"#=(* 2 21)\"))
- Defaults to true"
+ Defaults to false"
{:added "1.0"})
(defn future?
View
37 src/clj/clojure/core_print.clj
@@ -309,31 +309,23 @@
(defmethod print-dup clojure.lang.LazilyPersistentVector [o w] (print-method o w))
(def primitives-classnames
- {Float/TYPE "Float/TYPE"
- Integer/TYPE "Integer/TYPE"
- Long/TYPE "Long/TYPE"
- Boolean/TYPE "Boolean/TYPE"
- Character/TYPE "Character/TYPE"
- Double/TYPE "Double/TYPE"
- Byte/TYPE "Byte/TYPE"
- Short/TYPE "Short/TYPE"})
+ {Float/TYPE "float"
+ Integer/TYPE "int"
+ Long/TYPE "long"
+ Boolean/TYPE "boolean"
+ Character/TYPE "char"
+ Double/TYPE "double"
+ Byte/TYPE "byte"
+ Short/TYPE "short"})
(defmethod print-method Class [^Class c, ^Writer w]
(.write w (.getName c)))
(defmethod print-dup Class [^Class c, ^Writer w]
- (cond
- (.isPrimitive c) (do
- (.write w "#=(identity ")
- (.write w ^String (primitives-classnames c))
- (.write w ")"))
- (.isArray c) (do
- (.write w "#=(java.lang.Class/forName \"")
- (.write w (.getName c))
- (.write w "\")"))
- :else (do
- (.write w "#=")
- (.write w (.getName c)))))
+ (let [^String cs (or (primitives-classnames c) (.getName c))]
+ (.write w "#=\"")
+ (.write w cs)
+ (.write w "\"")))
(defmethod print-method java.math.BigDecimal [b, ^Writer w]
(.write w (str b))
@@ -368,7 +360,7 @@
(defmethod print-dup java.util.regex.Pattern [p ^Writer w] (print-method p w))
(defmethod print-dup clojure.lang.Namespace [^clojure.lang.Namespace n ^Writer w]
- (.write w "#=(find-ns ")
+ (.write w "#=(clojure.lang.Namespace/find ")
(print-dup (.name n) w)
(.write w ")"))
@@ -380,7 +372,8 @@
(agent-error o))
" FAILED"
""))
- pr-on, "", ">", (list (if (and (instance? clojure.lang.IPending o) (not (.isRealized o)))
+ pr-on, "", ">", (list (if (and (instance? clojure.lang.IPending o)
+ (not (.isRealized ^clojure.lang.IPending o)))
:pending
@o)), w))
View
71 src/jvm/clojure/lang/LispReader.java
@@ -30,9 +30,7 @@
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -1023,18 +1021,40 @@ else if(s.ns != null) //static method
}
*/
+static IPersistentMap primclasses = RT.map("int", int.class,
+ "long", long.class,
+ "float", float.class,
+ "double", double.class,
+ "char", char.class,
+ "boolean", boolean.class,
+ "short", short.class,
+ "byte", byte.class,
+ "void", void.class);
+
+static boolean onWhiteList(Class c){
+ Collection<Class> whitelist = (Collection<Class>) RT.READWHITELIST.deref();
+
+ for(Class wc : whitelist)
+ {
+ if(wc.isAssignableFrom(c))
+ return true;
+ }
+ return false;
+}
+
public static class EvalReader extends AFn{
public Object invoke(Object reader, Object eq) {
- if (!RT.booleanCast(RT.READEVAL.deref()))
- {
- throw Util.runtimeException("EvalReader not allowed when *read-eval* is false.");
- }
-
+ boolean readeval = RT.booleanCast(RT.READEVAL.deref());
+
PushbackReader r = (PushbackReader) reader;
Object o = read(r, true, null, true);
- if(o instanceof Symbol)
+ if(o instanceof Symbol || o instanceof String)
{
- return RT.classForName(o.toString());
+ String s = o.toString();
+ Class c = (Class) primclasses.valAt(s);
+ if(c != null)
+ return c;
+ return RT.classForName(s);
}
else if(o instanceof IPersistentList)
{
@@ -1046,20 +1066,35 @@ else if(o instanceof IPersistentList)
}
if(fs.name.endsWith("."))
{
- Object[] args = RT.toArray(RT.next(o));
- return Reflector.invokeConstructor(RT.classForName(fs.name.substring(0, fs.name.length() - 1)), args);
+ Class c = RT.classForName(fs.name.substring(0, fs.name.length() - 1));
+ if(readeval || onWhiteList(c))
+ {
+ Object[] args = RT.toArray(RT.next(o));
+ return Reflector.invokeConstructor(c, args);
+ }
+ throw Util.runtimeException("eval reading not allowed when *read-eval* is false.");
}
if(Compiler.namesStaticMember(fs))
{
- Object[] args = RT.toArray(RT.next(o));
- return Reflector.invokeStaticMethod(fs.ns, fs.name, args);
+ Class c = RT.classForName(fs.ns);
+
+ if(readeval || onWhiteList(c))
+ {
+ Object[] args = RT.toArray(RT.next(o));
+ return Reflector.invokeStaticMethod(c, fs.name, args);
+ }
+ throw Util.runtimeException("eval reading not allowed when *read-eval* is false.");
}
- Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs);
- if(v instanceof Var)
+ if(readeval)
{
- return ((IFn) v).applyTo(RT.next(o));
+ Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs);
+ if(v instanceof Var)
+ {
+ return ((IFn) v).applyTo(RT.next(o));
+ }
+ throw Util.runtimeException("Can't resolve " + fs);
}
- throw Util.runtimeException("Can't resolve " + fs);
+ throw Util.runtimeException("eval reading not allowed when *read-eval* is false.");
}
else
throw new IllegalArgumentException("Unsupported #= form");
View
11 src/jvm/clojure/lang/RT.java
@@ -181,7 +181,13 @@
final static Keyword TAG_KEY = Keyword.intern(null, "tag");
final static Keyword CONST_KEY = Keyword.intern(null, "const");
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 READEVAL = Var.intern(CLOJURE_NS, Symbol.intern("*read-eval*"), F).setDynamic();
+final static public Var READWHITELIST = Var.intern(CLOJURE_NS, Symbol.intern("*read-whitelist*"),
+ RT.vector(java.lang.Number.class,
+ java.util.Collection.class,
+ java.util.Map.class,
+ clojure.lang.Namespace.class,
+ clojure.lang.Fn.class)).setDynamic();
final static public Var DATA_READERS = Var.intern(CLOJURE_NS, Symbol.intern("*data-readers*"), RT.map()).setDynamic();
final static public Var DEFAULT_DATA_READER_FN = Var.intern(CLOJURE_NS, Symbol.intern("*default-data-reader-fn*"), RT.map()).setDynamic();
final static public Var DEFAULT_DATA_READERS = Var.intern(CLOJURE_NS, Symbol.intern("default-data-readers"), RT.map());
@@ -1861,8 +1867,9 @@ else if(x instanceof Character) {
}
}
else if(x instanceof Class) {
- w.write("#=");
+ w.write("#=\"");
w.write(((Class) x).getName());
+ w.write('"');
}
else if(x instanceof BigDecimal && readably) {
w.write(x.toString());
Please sign in to comment.
Something went wrong with that request. Please try again.