summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2006-09-29 16:58:49 +0000
committerRich Hickey <richhickey@gmail.com>2006-09-29 16:58:49 +0000
commit63f878b1103d32483c44ef6416a6c74c4b7b969b (patch)
tree776d24d4f7698f4aa5c8c6025696d4efa76bc113
parentc62973eb7d0af525fe5e9e6d1e9d8a8971aab8b2 (diff)
interim checkin
-rw-r--r--src/jvm/clojure/lang/Compiler.java193
1 files changed, 159 insertions, 34 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 246b6fc2..b755185f 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -18,8 +18,9 @@ public class Compiler{
///*
static Symbol DEF = Symbol.intern("def");
static Symbol FN = Symbol.intern("fn");
-static Symbol AMP_KEY = Symbol.intern("&key");
-static Symbol AMP_REST = Symbol.intern("&rest");
+static Symbol DO = Symbol.intern("do");
+static Symbol _AM_KEY = Symbol.intern("&key");
+static Symbol _AM_REST = Symbol.intern("&rest");
static public Var OUT = Module.intern("clojure", "^out");
static public Var MODULE = Module.intern("clojure", "^module");
static NilExpr NIL_EXPR = new NilExpr();
@@ -33,9 +34,11 @@ static public Var VARS = Module.intern("clojure", "^compiler-vars");
//symbol->localbinding
static public Var LOCAL_ENV = Module.intern("clojure", "^compiler-local-env");
//FnFrame
-static public Var FRAME = Module.intern("clojure", "^compiler-frame");
+static public Var METHOD = Module.intern("clojure", "^compiler-method");
//module->module
static public Var USES = Module.intern("clojure", "^compiler-uses");
+//ISeq FnExprs
+static public Var FNS = Module.intern("clojure", "^compiler-fns");
static public IPersistentMap CHAR_MAP =
new PersistentArrayMap('-', "_HY_",
@@ -62,6 +65,8 @@ static public IPersistentMap CHAR_MAP =
'\\',"_BS_",
'?', "_QM_");
+private static final int MAX_POSITIONAL_ARITY = 20;
+
static String munge(String name){
StringBuilder sb = new StringBuilder();
for(char c : name.toCharArray())
@@ -163,56 +168,162 @@ private static Expr analyzeSeq(C context, ISeq form) throws Exception {
private static Expr analyzeFn(C context, ISeq form) throws Exception {
//(fn (args) body) or (fn ((args) body) ((args2) body2) ...)
//turn former into latter
- if(RT.first(RT.second(form)) instanceof ISeq)
+ if(!(RT.first(RT.second(form)) instanceof ISeq))
return analyzeFn(context, RT.list(FN, RT.rest(form)));
- IPersistentCollection methods = null;
+ FnMethod[] methodArray = new FnMethod[MAX_POSITIONAL_ARITY+1];
+ FnMethod variadicMethod = null;
+ FnExpr fn = new FnExpr();
for(ISeq s = RT.rest(form);s != null;s = RT.rest(s))
- methods = RT.cons(analyzeMethod((ISeq) RT.first(s)),methods);
+ {
+ FnMethod f = analyzeMethod(fn,(ISeq) RT.first(s));
+ if(f.restParm != null || f.keyParms != null)
+ {
+ if(variadicMethod == null)
+ variadicMethod = f;
+ else
+ throw new Exception("Can't have more than 1 variadic overload");
+ }
+ else if(methodArray[f.reqParms.count()] == null)
+ methodArray[f.reqParms.count()] = f;
+ else
+ throw new Exception("Can't have 2 overloads with same arity");
+ }
+ if(variadicMethod != null)
+ {
+ for(int i = variadicMethod.reqParms.count() + 1;i<=MAX_POSITIONAL_ARITY;i++)
+ if(methodArray[i] != null)
+ throw new Exception("Can't have fixed arity function with more params than variadic function");
+ }
+
+ IPersistentCollection methods = null;
+ for(int i = 0;i<methodArray.length;i++)
+ if(methodArray[i] != null)
+ methods = RT.cons(methodArray[i], methods);
+ if(variadicMethod != null)
+ methods = RT.cons(variadicMethod, methods);
+
+ fn.methods = methods;
+ fn.isVariadic = variadicMethod != null;
+ registerFn(fn);
+ return fn;
+}
+
+static class FnExpr extends AnExpr{
+ IPersistentCollection methods;
+ boolean isVariadic;
+ LocalBinding b;
+ private String className = null;
+ boolean isCalledDirectly = false;
+ //localbinding->itself
+ IPersistentMap closes = null;
+
+ String getClassName(){
+ if(className == null)
+ {
+ if(b != null)
+ className = "FN__" + b.sym.name + "__" + RT.nextID();
+ else
+ className = "FN__" + RT.nextID();
+ }
+ return className;
+ }
+
+ public void emitExpression() throws Exception{
+ format("(new ~A(", getClassName());
+ for(ISeq s = RT.seq(closes);s!=null;s=s.rest())
+ {
+ LocalBinding b = (LocalBinding) ((MapEntry) s.first()).key();
+ format("~A", b.getName());
+ if (s.rest() != null)
+ format(",");
+ }
+ format("))");
+ }
+} s
+
+static class FnMethod {
+ FnMethod parent = null;
+ //localbinding->localbinding
+ IPersistentMap locals = null;
+ //localbinding->localbinding
+ PersistentArrayList reqParms = new PersistentArrayList(4);
+ PersistentArrayList keyParms = null;
+ LocalBindingExpr restParm = null;
+ Expr body = null;
+ FnExpr fn;
+
+ public FnMethod(FnExpr fn,FnMethod parent) {
+ this.parent = parent;
+ this.fn = fn;
+ }
}
enum PSTATE{REQ,REST,KEY,DONE}
-private static FnFrame analyzeMethod(ISeq form) throws Exception {
+private static FnMethod analyzeMethod(FnExpr fn,ISeq form) throws Exception {
+ //((args) body)
ISeq parms = (ISeq) RT.first(form);
ISeq body = RT.rest(form);
try
{
- FnFrame frame = new FnFrame((FnFrame) FRAME.getValue());
- FRAME.pushThreadBinding(frame);
+ FnMethod method = new FnMethod(fn,(FnMethod) METHOD.getValue());
+ METHOD.pushThreadBinding(method);
LOCAL_ENV.pushThreadBinding(LOCAL_ENV.getValue());
PSTATE state = PSTATE.REQ;
- for (ISeq ps = RT.rest(form); ps != null; ps = ps.rest())
+ for (ISeq ps = parms; ps != null; ps = ps.rest())
{
- Symbol p = (Symbol) ps.first();
- if (p == AMP_REST)
+ Object p = ps.first();
+ if (p == _AM_REST)
{
if (state == PSTATE.REQ)
state = PSTATE.REST;
else
- throw new Exception("Invalid argument list");
+ throw new Exception("Invalid parameter list");
}
- else if (p == AMP_KEY)
+ else if (p == _AM_KEY)
{
if (state == PSTATE.REQ)
+ {
state = PSTATE.KEY;
+ method.keyParms = new PersistentArrayList(4);
+ }
else
- throw new Exception("Invalid argument list");
+ throw new Exception("Invalid parameter list");
}
else
{
switch (state)
{
case REQ:
+ method.reqParms = method.reqParms.cons(createParamBinding((Symbol) p));
+ break;
+ case REST:
+ method.restParm = createParamBinding((Symbol) p);
+ state = PSTATE.DONE;
break;
+ case KEY:
+ if(p instanceof ISeq)
+ method.keyParms = method.keyParms.cons(
+ new KeyParam(createParamBinding((Symbol) RT.first(p)),
+ analyze(C.EXPRESSION, RT.second(p))));
+ else
+ method.keyParms = method.keyParms.cons(
+ new KeyParam(createParamBinding((Symbol) p)));
+
+ break;
+ default:
+ throw new Exception("Unexpected parameter");
}
}
}
-
- return (FnFrame) FRAME.getValue();
+ if(method.reqParms.count() > MAX_POSITIONAL_ARITY)
+ throw new Exception("Sorry, can't specify more than " + MAX_POSITIONAL_ARITY + " params");
+ method.body = analyze(C.RETURN, RT.cons(DO, body));
+ return method;
}
finally{
- FRAME.popThreadBinding();
+ METHOD.popThreadBinding();
LOCAL_ENV.popThreadBinding();
}
}
@@ -313,26 +424,30 @@ private static void registerVar(Var var) {
VARS.setValue(RT.assoc(var, var, varsMap));
}
-static void closeOver(LocalBinding b,FnFrame frame){
- if(b != null && frame != null && RT.get(b,frame.locals) == null)
+private static void registerFn(FnExpr fn) {
+ FNS.setValue(RT.cons(fn, (ISeq)FNS.getValue()));
+}
+
+static void closeOver(LocalBinding b,FnMethod method){
+ if(b != null && method != null && RT.get(b,method.locals) == null)
{
b.isClosed = true;
- frame.closes = (IPersistentMap)RT.assoc(b, b, frame.closes);
- closeOver(b,frame.parent);
+ method.fn.closes = (IPersistentMap)RT.assoc(b, b, method.fn.closes);
+ closeOver(b,method.parent);
}
}
static LocalBinding referenceLocal(Symbol sym) {
LocalBinding b = (LocalBinding) RT.get(sym, LOCAL_ENV.getValue());
- closeOver(b,(FnFrame) FRAME.getValue());
+ closeOver(b,(FnMethod) METHOD.getValue());
return b;
}
private static void registerLocal(LocalBinding b) {
IPersistentMap localsMap = (IPersistentMap) LOCAL_ENV.getValue();
LOCAL_ENV.setValue(RT.assoc(b.sym, b, localsMap));
- FnFrame frame = (FnFrame) FRAME.getValue();
- frame.locals = (IPersistentMap) RT.assoc(b, b, frame.locals);
+ FnMethod method = (FnMethod) METHOD.getValue();
+ method.locals = (IPersistentMap) RT.assoc(b, b, method.locals);
}
/*
(defun reference-var (sym)
@@ -359,18 +474,24 @@ static String resolveHostClassname(String classname) throws Exception {
return fullyQualifiedName;
}
-static class FnFrame{
- FnFrame parent = null;
- //localbinding->localbinding
- IPersistentMap locals = null;
- //localbinding->localbinding
- IPersistentMap closes = null;
- public FnFrame(FnFrame parent) {
- this.parent = parent;
+
+static class KeyParam{
+ public KeyParam(LocalBindingExpr b, Expr init) {
+ this.b = b;
+ this.init = init;
}
+
+ public KeyParam(LocalBindingExpr b) {
+ this.b = b;
+ this.init = NIL_EXPR;
+ }
+
+ LocalBindingExpr b;
+ Expr init;
}
+
static class NilExpr extends AnExpr{
public void emitExpression() throws Exception{
format("null");
@@ -451,6 +572,10 @@ static class LocalBinding{
public LocalBinding(Symbol sym) {
this.sym = sym;
}
+
+ public String getName(){
+ return munge(sym.name) + "__" + id;
+ }
}
static class LocalBindingExpr extends AnExpr{
@@ -463,7 +588,7 @@ static class LocalBindingExpr extends AnExpr{
}
public void emitExpression() throws Exception{
- format("%A", munge(b.sym.name));
+ format("%A", b.getName());
}
}