diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-10-11 01:02:30 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-10-11 01:02:30 +0000 |
commit | 2faa08e4d42feac84230d52272de6f10b0caa434 (patch) | |
tree | c7d483d174889fc61d4c3041aedb90bc1913b001 /src | |
parent | 53ec9af4fd879482a6b8e04cff029d5db9634870 (diff) |
refined ## to #=, now takes either
#=classname
#=(classname. ctor-args*)
#=(classname/staticMethod args*)
#=(varname args*)
and calls with _unevaluated_ args
Diffstat (limited to 'src')
-rw-r--r-- | src/clj/clojure/boot.clj | 39 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 194 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 73 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Repl.java | 20 |
4 files changed, 236 insertions, 90 deletions
diff --git a/src/clj/clojure/boot.clj b/src/clj/clojure/boot.clj index 7fd1a22c..f721ec33 100644 --- a/src/clj/clojure/boot.clj +++ b/src/clj/clojure/boot.clj @@ -3438,13 +3438,16 @@ (prefer-method print-method clojure.lang.IPersistentList clojure.lang.ISeq) -(defmethod print-method java.util.List [o, #^Writer w] - (.write w "##(") +(defn print-ctor [o print-args #^Writer w] + (.write w "#=(") (.write w (.getName (class o))) (.write w ". ") - (print-sequential "[" print-method " " "]" o w) + (print-args o w) (.write w ")")) +(defmethod print-method java.util.List [o, #^Writer w] + (print-ctor o #(print-sequential "[" print-method " " "]" %1 %2) w)) + (prefer-method print-method clojure.lang.IPersistentList java.util.List) (prefer-method print-method clojure.lang.IPersistentVector java.util.List) @@ -3476,7 +3479,7 @@ (dotimes n (count v) (print-method (nth v n) w) (when (< n (dec (count v))) - (.append w \ ))) + (.append w \space))) (.append w \]) nil) @@ -3485,23 +3488,21 @@ (print-sequential "{" (fn [e #^Writer w] - (do (print-method (key e) w) (.append w \ ) (print-method (val e) w))) + (do (print-method (key e) w) (.append w \space) (print-method (val e) w))) ", " "}" (seq m) w)) (defmethod print-method java.util.Map [m, #^Writer w] - (.write w "##(") - (.write w (.getName (class m))) - (.write w ". ") - (print-sequential - "{" - (fn [e #^Writer w] - (do (print-method (key e) w) (.append w \ ) (print-method (val e) w))) - ", " - "}" - (seq m) w) - (.write w ")")) + (print-ctor m + #(print-sequential + "{" + (fn [e #^Writer w] + (do (print-method (key e) w) (.append w \space) (print-method (val e) w))) + ", " + "}" + (seq %1) %2) + w)) (prefer-method print-method clojure.lang.IPersistentMap java.util.Map) @@ -3528,7 +3529,7 @@ nil) (defmethod print-method Class [#^Class c, #^Writer w] - (.write w "##") + (.write w "#=") (.write w (.getName c))) (defmethod print-method java.math.BigDecimal [b, #^Writer w] @@ -3539,3 +3540,7 @@ (.append w \#) (print-method (str p) w)) +(defmacro declare + "defs the supplied var names with no bindings, useful for making forward declarations." + [& names] `(do ~@(map #(list 'def %) names))) + diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 06da69ae..2dd92a25 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -268,7 +268,7 @@ static class DefExpr implements Expr{ final static Method setMetaMethod = Method.getMethod("void setMeta(clojure.lang.IPersistentMap)"); final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String, String)"); - public DefExpr(String source,int line,Var var, Expr init, Expr meta, boolean initProvided){ + public DefExpr(String source, int line, Var var, Expr init, Expr meta, boolean initProvided){ this.source = source; this.line = line; this.var = var; @@ -354,7 +354,7 @@ static class DefExpr implements Expr{ IPersistentMap mm = sym.meta(); mm = (IPersistentMap) RT.assoc(mm, RT.LINE_KEY, LINE.get()).assoc(RT.FILE_KEY, SOURCE.get()); Expr meta = analyze(context == C.EVAL ? context : C.EXPRESSION, mm); - return new DefExpr((String) SOURCE.get(),(Integer) LINE.get(), + return new DefExpr((String) SOURCE.get(), (Integer) LINE.get(), v, analyze(context == C.EVAL ? context : C.EXPRESSION, RT.third(form), v.sym.name), meta, RT.count(form) == 3); } @@ -846,8 +846,9 @@ static class InstanceFieldExpr extends FieldExpr implements AssignableExpr{ this.line = line; if(field == null && RT.booleanCast(RT.WARN_ON_REFLECTION.get())) { - ((PrintWriter)RT.ERR.get()).format("Reflection warning, line: %d - reference to field %s can't be resolved.\n", line, - fieldName); + ((PrintWriter) RT.ERR.get()) + .format("Reflection warning, line: %d - reference to field %s can't be resolved.\n", line, + fieldName); } } @@ -1045,7 +1046,8 @@ static abstract class MethodExpr extends HostExpr{ } catch(Exception e1) { - e1.printStackTrace((PrintWriter)RT.ERR.get()); //To change body of catch statement use File | Settings | File Templates. + e1.printStackTrace((PrintWriter) RT.ERR + .get()); //To change body of catch statement use File | Settings | File Templates. } } @@ -1102,7 +1104,8 @@ static class InstanceMethodExpr extends MethodExpr{ if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.get())) { - ((PrintWriter)RT.ERR.get()).format("Reflection warning, line: %d - call to %s can't be resolved.\n", line, methodName); + ((PrintWriter) RT.ERR.get()) + .format("Reflection warning, line: %d - call to %s can't be resolved.\n", line, methodName); } } @@ -1237,7 +1240,8 @@ static class StaticMethodExpr extends MethodExpr{ method = (java.lang.reflect.Method) (methodidx >= 0 ? methods.get(methodidx) : null); if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.get())) { - ((PrintWriter)RT.ERR.get()).format("Reflection warning, line: %d - call to %s can't be resolved.\n", line, methodName); + ((PrintWriter) RT.ERR.get()) + .format("Reflection warning, line: %d - call to %s can't be resolved.\n", line, methodName); } } @@ -1328,7 +1332,7 @@ static class StaticMethodExpr extends MethodExpr{ static class UnresolvedVarExpr implements Expr{ public final Symbol symbol; - public UnresolvedVarExpr(Symbol symbol) { + public UnresolvedVarExpr(Symbol symbol){ this.symbol = symbol; } @@ -2060,7 +2064,8 @@ public static class NewExpr implements Expr{ this.ctor = ctoridx >= 0 ? (Constructor) ctors.get(ctoridx) : null; if(ctor == null && RT.booleanCast(RT.WARN_ON_REFLECTION.get())) { - ((PrintWriter)RT.ERR.get()).format("Reflection warning, line: %d - call to %s ctor can't be resolved.\n", line, c.getName()); + ((PrintWriter) RT.ERR.get()) + .format("Reflection warning, line: %d - call to %s ctor can't be resolved.\n", line, c.getName()); } } @@ -2717,7 +2722,7 @@ static class InvokeExpr implements Expr{ // throw new IllegalArgumentException( // String.format("No more than %d args supported", MAX_POSITIONAL_ARITY)); - return new InvokeExpr((String) SOURCE.get(),(Integer) LINE.get(), tagOf(form), fexpr, args); + return new InvokeExpr((String) SOURCE.get(), (Integer) LINE.get(), tagOf(form), fexpr, args); } } @@ -2751,8 +2756,8 @@ static class FnLoaderThunk extends RestFn{ synchronized private IFn loadFn() throws Exception{ if(f == null) { - Class fc = fx.getCompiledClass(); - f = (IFn)fc.newInstance(); + Class fc = fx.getCompiledClass(); + f = (IFn) fc.newInstance(); v.swapRoot(f); } return f; @@ -2779,20 +2784,62 @@ static public class FnExpr implements Expr{ int line; PersistentVector constants; int constantsID; - public final IPersistentCollection methods() { return methods;} - public final FnMethod variadicMethod() { return variadicMethod;} - public final String name() { return name;} - public final String simpleName() { return simpleName;} - public final String internalName() { return internalName;} - public final String thisName() { return thisName;} - public final Type fntype() { return fntype;} - public final IPersistentMap closes() { return closes;} - public final IPersistentMap keywords() { return keywords;} - public final IPersistentMap vars() { return vars;} - public final Class compiledClass() { return compiledClass;} - public final int line() { return line;} - public final PersistentVector constants() { return constants;} - public final int constantsID() { return constantsID;} + + public final IPersistentCollection methods(){ + return methods; + } + + public final FnMethod variadicMethod(){ + return variadicMethod; + } + + public final String name(){ + return name; + } + + public final String simpleName(){ + return simpleName; + } + + public final String internalName(){ + return internalName; + } + + public final String thisName(){ + return thisName; + } + + public final Type fntype(){ + return fntype; + } + + public final IPersistentMap closes(){ + return closes; + } + + public final IPersistentMap keywords(){ + return keywords; + } + + public final IPersistentMap vars(){ + return vars; + } + + public final Class compiledClass(){ + return compiledClass; + } + + public final int line(){ + return line; + } + + public final PersistentVector constants(){ + return constants; + } + + public final int constantsID(){ + return constantsID; + } final static Method kwintern = Method.getMethod("clojure.lang.Keyword intern(String, String)"); final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String)"); @@ -3106,7 +3153,7 @@ static public class FnExpr implements Expr{ cv.visitEnd(); loader = (DynamicClassLoader) LOADER.get(); - bytecode = cw.toByteArray(); + bytecode = cw.toByteArray(); } synchronized Class getCompiledClass(){ @@ -3244,14 +3291,38 @@ public static class FnMethod{ int maxLocal = 0; int line; PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY; - public final IPersistentMap locals() { return locals;} - public final PersistentVector reqParms() { return reqParms;} - public final LocalBinding restParm() { return restParm;} - public final Expr body() { return body;} - public final FnExpr fn() { return fn;} - public final PersistentVector argLocals() { return argLocals;} - public final int maxLocal() { return maxLocal;} - public final int line() { return line;} + + public final IPersistentMap locals(){ + return locals; + } + + public final PersistentVector reqParms(){ + return reqParms; + } + + public final LocalBinding restParm(){ + return restParm; + } + + public final Expr body(){ + return body; + } + + public final FnExpr fn(){ + return fn; + } + + public final PersistentVector argLocals(){ + return argLocals; + } + + public final int maxLocal(){ + return maxLocal; + } + + public final int line(){ + return line; + } public FnMethod(FnExpr fn, FnMethod parent){ this.parent = parent; @@ -3466,7 +3537,10 @@ public static class LocalBindingExpr implements Expr, MaybePrimitiveExpr{ public static class BodyExpr implements Expr{ PersistentVector exprs; - public final PersistentVector exprs() { return exprs;} + + public final PersistentVector exprs(){ + return exprs; + } public BodyExpr(PersistentVector exprs){ this.exprs = exprs; @@ -3529,8 +3603,14 @@ public static class BodyExpr implements Expr{ public static class BindingInit{ LocalBinding binding; Expr init; - public final LocalBinding binding() { return binding;} - public final Expr init() { return init;} + + public final LocalBinding binding(){ + return binding; + } + + public final Expr init(){ + return init; + } public BindingInit(LocalBinding binding, Expr init){ this.binding = binding; @@ -3820,8 +3900,9 @@ private static Expr analyze(C context, Object form, String name) throws Exceptio static public class CompilerException extends Exception{ public CompilerException(String source, int line, Throwable cause){ - super(errorMsg(source,line,cause.toString()), cause); + super(errorMsg(source, line, cause.toString()), cause); } + public String toString(){ return getMessage(); } @@ -3867,6 +3948,10 @@ static public IFn isInline(Object op, int arity) throws Exception{ return null; } +public static boolean namesStaticMember(Symbol sym){ + return sym.ns != null && namespaceFor(sym) == null; +} + public static Object macroexpand1(Object x) throws Exception{ if(x instanceof ISeq) { @@ -3903,17 +3988,14 @@ public static Object macroexpand1(Object x) throws Exception{ Symbol meth = Symbol.intern(sname.substring(1)); return RT.listStar(DOT, RT.second(form), meth, form.rest().rest()); } - else if(sym.ns != null) + else if(namesStaticMember(sym)) { - if(namespaceFor(sym) == null) + Symbol target = Symbol.intern(sym.ns); + Class c = HostExpr.maybeClass(target, false); + if(c != null) { - Symbol target = Symbol.intern(sym.ns); - Class c = HostExpr.maybeClass(target, false); - if(c != null) - { - Symbol meth = Symbol.intern(sym.name); - return RT.listStar(DOT, target, meth, form.rest()); - } + Symbol meth = Symbol.intern(sym.name); + return RT.listStar(DOT, target, meth, form.rest()); } } else @@ -4005,7 +4087,7 @@ public static Object eval(Object form) throws Exception{ catch(Throwable e) { if(!(e instanceof CompilerException)) - throw new CompilerException((String)SOURCE.get(), (Integer) LINE.get(),e); + throw new CompilerException((String) SOURCE.get(), (Integer) LINE.get(), e); else throw (CompilerException) e; } @@ -4088,10 +4170,10 @@ static Object resolve(Symbol sym) throws Exception{ } static private Namespace namespaceFor(Symbol sym){ - return namespaceFor(currentNS(),sym); + return namespaceFor(currentNS(), sym); } -static private Namespace namespaceFor(Namespace inns,Symbol sym){ +static private Namespace namespaceFor(Namespace inns, Symbol sym){ //note, presumes non-nil sym.ns // first check against currentNS' aliases... Symbol nsSym = Symbol.create(sym.ns); @@ -4108,7 +4190,7 @@ static public Object resolveIn(Namespace n, Symbol sym) throws Exception{ //note - ns-qualified vars must already exist if(sym.ns != null) { - Namespace ns = namespaceFor(n,sym); + Namespace ns = namespaceFor(n, sym); if(ns == null) throw new Exception("No such namespace: " + sym.ns); @@ -4132,7 +4214,7 @@ static public Object resolveIn(Namespace n, Symbol sym) throws Exception{ Object o = n.getMapping(sym); if(o == null) { - if( RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.get())) + if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.get())) { return sym; } @@ -4191,7 +4273,7 @@ static Var lookupVar(Symbol sym, boolean internNew) throws Exception{ var = ns.findInternedVar(name); } else if(sym.equals(NS)) - var = RT.NS_VAR; + var = RT.NS_VAR; else if(sym.equals(IN_NS)) var = RT.IN_NS_VAR; else @@ -4284,7 +4366,7 @@ public static Object loadFile(String file) throws Exception{ FileInputStream f = new FileInputStream(file); try { - return load(new InputStreamReader(f,RT.UTF8), new File(file).getAbsolutePath(), (new File(file)).getName()); + return load(new InputStreamReader(f, RT.UTF8), new File(file).getAbsolutePath(), (new File(file)).getName()); } finally { @@ -4323,7 +4405,7 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) thro } catch(LispReader.ReaderException e) { - throw new CompilerException(sourceName,e.line,e.getCause()); + throw new CompilerException(sourceName, e.line, e.getCause()); } finally { diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index d4d03f89..c0cd63ec 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -86,7 +86,7 @@ static dispatchMacros['"'] = new RegexReader();
dispatchMacros['('] = new FnReader();
dispatchMacros['{'] = new SetReader();
- dispatchMacros['#'] = new EvalReader();
+ dispatchMacros['='] = new EvalReader();
}
static boolean isWhitespace(int ch){
@@ -459,9 +459,12 @@ static class VarReader extends AFn{ public Object invoke(Object reader, Object quote) throws Exception{
PushbackReader r = (PushbackReader) reader;
Object o = read(r, true, null, true);
- Object v = Compiler.maybeResolveIn(Compiler.currentNS(), (Symbol) o);
- if(v instanceof Var)
- return v;
+ if(o instanceof Symbol)
+ {
+ Object v = Compiler.maybeResolveIn(Compiler.currentNS(), (Symbol) o);
+ if(v instanceof Var)
+ return v;
+ }
return RT.list(THE_VAR, o);
}
}
@@ -816,14 +819,68 @@ static class ListReader extends AFn{ }
+static class CtorReader extends AFn{
+ static final Symbol cls = Symbol.create("class");
+
+ public Object invoke(Object reader, Object leftangle) throws Exception{
+ PushbackReader r = (PushbackReader) reader;
+ // #<class classname>
+ // #<classname args*>
+ // #<classname/staticMethod args*>
+ List list = readDelimitedList('>', r, true);
+ if(list.isEmpty())
+ throw new Exception("Must supply 'class', classname or classname/staticMethod");
+ Symbol s = (Symbol) list.get(0);
+ Object[] args = list.subList(1, list.size()).toArray();
+ if(s.equals(cls))
+ {
+ return RT.classForName(args[0].toString());
+ }
+ else if(s.ns != null) //static method
+ {
+ String classname = s.ns;
+ String method = s.name;
+ return Reflector.invokeStaticMethod(classname, method, args);
+ }
+ else
+ {
+ return Reflector.invokeConstructor(RT.classForName(s.name), args);
+ }
+ }
+
+}
+
static class EvalReader extends AFn{
public Object invoke(Object reader, Object eq) throws Exception{
PushbackReader r = (PushbackReader) reader;
-
- Compiler.Expr expr = Compiler.analyze(Compiler.C.EVAL, read(r, true, null, true));
- return expr.eval();
+ Object o = read(r, true, null, true);
+ if(o instanceof Symbol)
+ {
+ return RT.classForName(o.toString());
+ }
+ else if(o instanceof IPersistentList)
+ {
+ Symbol fs = (Symbol) RT.first(o);
+ if(fs.name.endsWith("."))
+ {
+ Object[] args = RT.toArray(RT.rest(o));
+ return Reflector.invokeConstructor(RT.classForName(fs.name.substring(0, fs.name.length() - 1)), args);
+ }
+ if(Compiler.namesStaticMember(fs))
+ {
+ Object[] args = RT.toArray(RT.rest(o));
+ return Reflector.invokeStaticMethod(fs.ns, fs.name, args);
+ }
+ Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs);
+ if(v instanceof Var)
+ {
+ return ((IFn) v).applyTo(RT.rest(o));
+ }
+ throw new Exception("Can't resolve " + v);
+ }
+ else
+ throw new IllegalArgumentException("Unsupported #= form");
}
-
}
//static class ArgVectorReader extends AFn{
diff --git a/src/jvm/clojure/lang/Repl.java b/src/jvm/clojure/lang/Repl.java index 1c065dd2..b2549b3c 100644 --- a/src/jvm/clojure/lang/Repl.java +++ b/src/jvm/clojure/lang/Repl.java @@ -24,6 +24,7 @@ static final Var in_ns = RT.var("clojure", "in-ns"); static final Var refer = RT.var("clojure", "refer"); static final Var ns = RT.var("clojure", "*ns*"); static final Var warn_on_reflection = RT.var("clojure", "*warn-on-reflection*"); +static final Var print_meta = RT.var("clojure", "*print-meta*"); static final Var star1 = RT.var("clojure", "*1"); static final Var star2 = RT.var("clojure", "*2"); static final Var star3 = RT.var("clojure", "*3"); @@ -41,11 +42,12 @@ public static void main(String[] args) throws Exception{ //must have corresponding popThreadBindings in finally clause Var.pushThreadBindings( RT.map(ns, ns.get(), - warn_on_reflection, warn_on_reflection.get(), - star1, null, - star2, null, - star3, null, - stare, null)); + warn_on_reflection, warn_on_reflection.get(), + print_meta, print_meta.get(), + star1, null, + star2, null, + star3, null, + stare, null)); //create and move into the user namespace in_ns.invoke(USER); @@ -59,11 +61,11 @@ public static void main(String[] args) throws Exception{ } catch(Exception e) { - e.printStackTrace((PrintWriter)RT.ERR.get()); + e.printStackTrace((PrintWriter) RT.ERR.get()); } //repl IO support - LineNumberingPushbackReader rdr = new LineNumberingPushbackReader(new InputStreamReader(System.in,RT.UTF8)); + LineNumberingPushbackReader rdr = new LineNumberingPushbackReader(new InputStreamReader(System.in, RT.UTF8)); OutputStreamWriter w = (OutputStreamWriter) RT.OUT.get();//new OutputStreamWriter(System.out); Object EOF = new Object(); @@ -95,14 +97,14 @@ public static void main(String[] args) throws Exception{ Throwable c = e; while(c.getCause() != null) c = c.getCause(); - ((PrintWriter)RT.ERR.get()).println(e instanceof Compiler.CompilerException ? e : c); + ((PrintWriter) RT.ERR.get()).println(e instanceof Compiler.CompilerException ? e : c); stare.set(e); } } } catch(Exception e) { - e.printStackTrace((PrintWriter)RT.ERR.get()); + e.printStackTrace((PrintWriter) RT.ERR.get()); } finally { |