summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jvm/clojure/lang/Compiler.java80
1 files changed, 74 insertions, 6 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 46aecc5d..b5071f32 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -177,7 +177,7 @@ private static Expr analyzeFn(C context, ISeq form) throws Exception {
for(ISeq s = RT.rest(form);s != null;s = RT.rest(s))
{
FnMethod f = analyzeMethod(fn,(ISeq) RT.first(s));
- if(f.restParm != null || f.keyParms != null)
+ if(f.isVariadic())
{
if(variadicMethod == null)
variadicMethod = f;
@@ -277,9 +277,65 @@ static class FnExpr extends AnExpr{
else
{
format("static public Object ~A(~{~A ~A~^, ~}",
-s getName(),
+ getName(),
closesDecls);
}
+
+ for(ISeq methods = RT.seq(this.methods);methods != null;methods = methods.rest())
+ {
+ FnMethod m = (FnMethod) methods.first();
+ if(!willBeStaticMethod())
+ format("public Object ~A(", m.isVariadic()?"doInvoke":"invoke");
+ for(ISeq reqs = RT.seq(m.reqParms);reqs != null;reqs = reqs.rest())
+ {
+ LocalBindingExpr be = (LocalBindingExpr) reqs.first();
+ format("Object ~A", be.b.getName());
+ if(be.b.needsBox())
+ format("__arg");
+ if(reqs.rest() != null)
+ format(",");
+ }
+ if(m.isVariadic())
+ {
+ if(m.reqParms.count() > 0)
+ format(",");
+ format("ISeq ");
+ if(m.restParm != null)
+ {
+ format("~A", m.restParm.b.getName());
+ if(m.restParm.b.needsBox())
+ format("__arg");
+ }
+ else
+ format("__keys");
+ }
+ format(") throws Exception{~%");
+
+ //emit declarations for any boxed args
+ for(ISeq reqs = RT.seq(m.reqParms);reqs != null;reqs = reqs.rest())
+ {
+ LocalBindingExpr be = (LocalBindingExpr) reqs.first();
+ if(be.b.needsBox())
+ be.b.emitDeclaration(be.b.getName() + "__arg");
+ }
+ //emit declaration for any boxed rest arg
+ if(m.restParm != null && m.restParm.b.needsBox())
+ m.restParm.b.emitDeclaration(m.restParm.b.getName() + "__arg");
+ //keys are locals, plucked out of rest arg
+ if(m.keyParms != null)
+ {
+ format("ISeq __valseq = null;~%");
+ for (ISeq keys = RT.seq(m.keyParms); keys != null; keys = keys.rest())
+ {
+ KeyParam key = (KeyParam) keys.first();
+ KeywordExpr kw = registerKeyword((Keyword) Symbol.intern(":" + key.bindingExpression.b.sym.name));
+ format("__valseq = RT.findKey(~A,__keys);", kw.emitExpressionString());
+ key.bindingExpression.b.emitDeclaration(
+ (String) RT.format(null, "(__valseq!=null)?clojure.lang.RT.first(__valseq):~A"
+ , key.init.emitExpressionString()));
+ }
+ }
+ }
}
boolean willBeStaticMethod() {
@@ -309,6 +365,10 @@ static class FnMethod {
this.parent = parent;
this.fn = fn;
}
+
+ boolean isVariadic(){
+ return keyParms != null || restParm != null;
+ }
}
enum PSTATE{REQ,REST,KEY,DONE}
@@ -532,16 +592,16 @@ static String resolveHostClassname(String classname) throws Exception {
static class KeyParam{
public KeyParam(LocalBindingExpr b, Expr init) {
- this.b = b;
+ this.bindingExpression = b;
this.init = init;
}
public KeyParam(LocalBindingExpr b) {
- this.b = b;
+ this.bindingExpression = b;
this.init = NIL_EXPR;
}
- LocalBindingExpr b;
+ LocalBindingExpr bindingExpression;
Expr init;
}
@@ -631,7 +691,7 @@ static class LocalBinding{
}
public String getName(){
- return munge(sym.name) + "__" + id;
+ return munge(sym.name) + (isParam?"":("__" + id));
}
boolean needsBox(){
@@ -643,6 +703,14 @@ static class LocalBinding{
return "clojure.lang.Box";
return "Object";
}
+
+ void emitDeclaration(String init) throws Exception {
+ format("~A ~A = ", typeDeclaration(), getName());
+ if(needsBox())
+ format("new clojure.lang.Box(~A);~%", init);
+ else
+ format("~A;~%", init);
+ }
}
static class LocalBindingExpr extends AnExpr{