Skip to content
This repository was archived by the owner on Apr 25, 2024. It is now read-only.

Commit 974a64c

Browse files
committed
split off arbitrary eval parts of #= and flip default for *read-eval* to false. N.B. this does not disable #=, only arbitrary eval using #=.
1 parent cdc037d commit 974a64c

File tree

4 files changed

+82
-46
lines changed

4 files changed

+82
-46
lines changed

src/clj/clojure/core.clj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5871,11 +5871,12 @@
58715871
{:added "1.0"})
58725872

58735873
(add-doc-and-meta *read-eval*
5874-
"When set to logical false, the EvalReader (#=(...)) is disabled in the
5875-
read/load in the thread-local binding.
5876-
Example: (binding [*read-eval* false] (read-string \"#=(eval (def x 3))\"))
5874+
"When set to logical true in the thread-local binding, the eval
5875+
reader (#=(...)) for arbitrary expressions is enabled in read/load.
5876+
Example:
5877+
(binding [*read-eval* true] (read-string \"#=(* 2 21)\"))
58775878
5878-
Defaults to true"
5879+
Defaults to false"
58795880
{:added "1.0"})
58805881

58815882
(defn future?

src/clj/clojure/core_print.clj

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -309,31 +309,23 @@
309309
(defmethod print-dup clojure.lang.LazilyPersistentVector [o w] (print-method o w))
310310

311311
(def primitives-classnames
312-
{Float/TYPE "Float/TYPE"
313-
Integer/TYPE "Integer/TYPE"
314-
Long/TYPE "Long/TYPE"
315-
Boolean/TYPE "Boolean/TYPE"
316-
Character/TYPE "Character/TYPE"
317-
Double/TYPE "Double/TYPE"
318-
Byte/TYPE "Byte/TYPE"
319-
Short/TYPE "Short/TYPE"})
312+
{Float/TYPE "float"
313+
Integer/TYPE "int"
314+
Long/TYPE "long"
315+
Boolean/TYPE "boolean"
316+
Character/TYPE "char"
317+
Double/TYPE "double"
318+
Byte/TYPE "byte"
319+
Short/TYPE "short"})
320320

321321
(defmethod print-method Class [^Class c, ^Writer w]
322322
(.write w (.getName c)))
323323

324324
(defmethod print-dup Class [^Class c, ^Writer w]
325-
(cond
326-
(.isPrimitive c) (do
327-
(.write w "#=(identity ")
328-
(.write w ^String (primitives-classnames c))
329-
(.write w ")"))
330-
(.isArray c) (do
331-
(.write w "#=(java.lang.Class/forName \"")
332-
(.write w (.getName c))
333-
(.write w "\")"))
334-
:else (do
335-
(.write w "#=")
336-
(.write w (.getName c)))))
325+
(let [^String cs (or (primitives-classnames c) (.getName c))]
326+
(.write w "#=\"")
327+
(.write w cs)
328+
(.write w "\"")))
337329

338330
(defmethod print-method java.math.BigDecimal [b, ^Writer w]
339331
(.write w (str b))
@@ -368,7 +360,7 @@
368360
(defmethod print-dup java.util.regex.Pattern [p ^Writer w] (print-method p w))
369361

370362
(defmethod print-dup clojure.lang.Namespace [^clojure.lang.Namespace n ^Writer w]
371-
(.write w "#=(find-ns ")
363+
(.write w "#=(clojure.lang.Namespace/find ")
372364
(print-dup (.name n) w)
373365
(.write w ")"))
374366

@@ -380,7 +372,8 @@
380372
(agent-error o))
381373
" FAILED"
382374
""))
383-
pr-on, "", ">", (list (if (and (instance? clojure.lang.IPending o) (not (.isRealized o)))
375+
pr-on, "", ">", (list (if (and (instance? clojure.lang.IPending o)
376+
(not (.isRealized ^clojure.lang.IPending o)))
384377
:pending
385378
@o)), w))
386379

src/jvm/clojure/lang/LispReader.java

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
import java.lang.reflect.Constructor;
3131
import java.math.BigDecimal;
3232
import java.math.BigInteger;
33-
import java.util.ArrayList;
34-
import java.util.List;
35-
import java.util.Map;
33+
import java.util.*;
3634
import java.util.regex.Matcher;
3735
import java.util.regex.Pattern;
3836

@@ -1023,18 +1021,40 @@ else if(s.ns != null) //static method
10231021
}
10241022
*/
10251023

1024+
static IPersistentMap primclasses = RT.map("int", int.class,
1025+
"long", long.class,
1026+
"float", float.class,
1027+
"double", double.class,
1028+
"char", char.class,
1029+
"boolean", boolean.class,
1030+
"short", short.class,
1031+
"byte", byte.class,
1032+
"void", void.class);
1033+
1034+
static boolean onWhiteList(Class c){
1035+
Collection<Class> whitelist = (Collection<Class>) RT.READWHITELIST.deref();
1036+
1037+
for(Class wc : whitelist)
1038+
{
1039+
if(wc.isAssignableFrom(c))
1040+
return true;
1041+
}
1042+
return false;
1043+
}
1044+
10261045
public static class EvalReader extends AFn{
10271046
public Object invoke(Object reader, Object eq) {
1028-
if (!RT.booleanCast(RT.READEVAL.deref()))
1029-
{
1030-
throw Util.runtimeException("EvalReader not allowed when *read-eval* is false.");
1031-
}
1032-
1047+
boolean readeval = RT.booleanCast(RT.READEVAL.deref());
1048+
10331049
PushbackReader r = (PushbackReader) reader;
10341050
Object o = read(r, true, null, true);
1035-
if(o instanceof Symbol)
1051+
if(o instanceof Symbol || o instanceof String)
10361052
{
1037-
return RT.classForName(o.toString());
1053+
String s = o.toString();
1054+
Class c = (Class) primclasses.valAt(s);
1055+
if(c != null)
1056+
return c;
1057+
return RT.classForName(s);
10381058
}
10391059
else if(o instanceof IPersistentList)
10401060
{
@@ -1046,20 +1066,35 @@ else if(o instanceof IPersistentList)
10461066
}
10471067
if(fs.name.endsWith("."))
10481068
{
1049-
Object[] args = RT.toArray(RT.next(o));
1050-
return Reflector.invokeConstructor(RT.classForName(fs.name.substring(0, fs.name.length() - 1)), args);
1069+
Class c = RT.classForName(fs.name.substring(0, fs.name.length() - 1));
1070+
if(readeval || onWhiteList(c))
1071+
{
1072+
Object[] args = RT.toArray(RT.next(o));
1073+
return Reflector.invokeConstructor(c, args);
1074+
}
1075+
throw Util.runtimeException("eval reading not allowed when *read-eval* is false.");
10511076
}
10521077
if(Compiler.namesStaticMember(fs))
10531078
{
1054-
Object[] args = RT.toArray(RT.next(o));
1055-
return Reflector.invokeStaticMethod(fs.ns, fs.name, args);
1079+
Class c = RT.classForName(fs.ns);
1080+
1081+
if(readeval || onWhiteList(c))
1082+
{
1083+
Object[] args = RT.toArray(RT.next(o));
1084+
return Reflector.invokeStaticMethod(c, fs.name, args);
1085+
}
1086+
throw Util.runtimeException("eval reading not allowed when *read-eval* is false.");
10561087
}
1057-
Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs);
1058-
if(v instanceof Var)
1088+
if(readeval)
10591089
{
1060-
return ((IFn) v).applyTo(RT.next(o));
1090+
Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs);
1091+
if(v instanceof Var)
1092+
{
1093+
return ((IFn) v).applyTo(RT.next(o));
1094+
}
1095+
throw Util.runtimeException("Can't resolve " + fs);
10611096
}
1062-
throw Util.runtimeException("Can't resolve " + fs);
1097+
throw Util.runtimeException("eval reading not allowed when *read-eval* is false.");
10631098
}
10641099
else
10651100
throw new IllegalArgumentException("Unsupported #= form");

src/jvm/clojure/lang/RT.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,13 @@ public class RT{
181181
final static Keyword TAG_KEY = Keyword.intern(null, "tag");
182182
final static Keyword CONST_KEY = Keyword.intern(null, "const");
183183
final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.intern("*agent*"), null).setDynamic();
184-
final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.intern("*read-eval*"), T).setDynamic();
184+
final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.intern("*read-eval*"), F).setDynamic();
185+
final static public Var READWHITELIST = Var.intern(CLOJURE_NS, Symbol.intern("*read-whitelist*"),
186+
RT.vector(java.lang.Number.class,
187+
java.util.Collection.class,
188+
java.util.Map.class,
189+
clojure.lang.Namespace.class,
190+
clojure.lang.Fn.class)).setDynamic();
185191
final static public Var DATA_READERS = Var.intern(CLOJURE_NS, Symbol.intern("*data-readers*"), RT.map()).setDynamic();
186192
final static public Var DEFAULT_DATA_READER_FN = Var.intern(CLOJURE_NS, Symbol.intern("*default-data-reader-fn*"), RT.map()).setDynamic();
187193
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) {
18611867
}
18621868
}
18631869
else if(x instanceof Class) {
1864-
w.write("#=");
1870+
w.write("#=\"");
18651871
w.write(((Class) x).getName());
1872+
w.write('"');
18661873
}
18671874
else if(x instanceof BigDecimal && readably) {
18681875
w.write(x.toString());

0 commit comments

Comments
 (0)