diff options
author | Rich Hickey <richhickey@gmail.com> | 2006-10-02 19:51:10 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2006-10-02 19:51:10 +0000 |
commit | 3302b103d19483ab301c98f381f03eb3a2ed0107 (patch) | |
tree | 662330eb6638ae26bd8037d206d48cb7abe2fa6a | |
parent | bc5dc23be88ad294d86d8d2b09583c41eafdd9b9 (diff) |
interim checkin
-rw-r--r-- | src/cli/runtime/PersistentArrayMap.cs | 2 | ||||
-rw-r--r-- | src/cli/runtime/RT.cs | 5 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 265 | ||||
-rw-r--r-- | src/jvm/clojure/lang/PersistentArrayMap.java | 2 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 6 |
5 files changed, 250 insertions, 30 deletions
diff --git a/src/cli/runtime/PersistentArrayMap.cs b/src/cli/runtime/PersistentArrayMap.cs index 8ffaca76..68d4b2c1 100644 --- a/src/cli/runtime/PersistentArrayMap.cs +++ b/src/cli/runtime/PersistentArrayMap.cs @@ -34,7 +34,7 @@ internal readonly Object[] array; internal const int HASHTABLE_THRESHOLD = 42;
protected PersistentArrayMap(){
- this.array = RT.EMPTY_ARRAY;
+ this.array = new object[]{};
}
virtual internal PersistentArrayMap create(params Object[] init){
diff --git a/src/cli/runtime/RT.cs b/src/cli/runtime/RT.cs index 5cf4187f..8f7141d9 100644 --- a/src/cli/runtime/RT.cs +++ b/src/cli/runtime/RT.cs @@ -21,8 +21,9 @@ namespace clojure.lang public class RT
{
- public static Symbol T = Symbol.intern("t");
+ public static Symbol T = Symbol.intern(":t");
static public Var OUT = Module.intern("clojure", "^out");
+ static public Var _CT_MODULE = Module.intern("clojure", "^module");
public static Object[] EMPTY_ARRAY = new Object[0];
@@ -38,6 +39,8 @@ public class RT chars = new Object[256];
for(int i=0;i<chars.Length;i++)
chars[i] = (char)i;
+ OUT.bind(Console.Out);
+ _CT_MODULE.bind((Module.findOrCreate("clj-user")));
}
static public bool equal(Object k1,Object k2){
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 7a323dc1..3f4cd050 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -13,16 +13,23 @@ package clojure.lang; import java.io.StringWriter; +import java.io.InputStreamReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; public class Compiler{ ///* static Symbol DEF = Symbol.intern("def"); static Symbol FN = Symbol.intern("fn"); static Symbol DO = Symbol.intern("do"); +static Symbol IMPORT = Symbol.intern("import"); +static Symbol USE = Symbol.intern("use"); 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 public Var _CT_OUT = RT.OUT; +static public Var _CT_MODULE = RT._CT_MODULE; + static NilExpr NIL_EXPR = new NilExpr(); //short-name-string->full-name-string @@ -67,6 +74,123 @@ static public IPersistentMap CHAR_MAP = private static final int MAX_POSITIONAL_ARITY = 20; + +static String compile(String ns, String className, LineNumberingPushbackReader... files) throws Exception { + StringWriter w = new StringWriter(); + try + { + _CT_OUT.pushThreadBinding(w); + KEYWORDS.pushThreadBinding(null); + VARS.pushThreadBinding(null); + METHOD.pushThreadBinding(null); + LOCAL_ENV.pushThreadBinding(null); + FNS.pushThreadBinding(new PersistentArrayList(4)); + + format("/* Generated by Clojure */~%~%"); + format("package ~A;~%", ns); + format("public class ~A{~%", className); + + PersistentArrayList forms = new PersistentArrayList(20); + for(LineNumberingPushbackReader reader : files) + { + try + { + IMPORTS.pushThreadBinding(null); + USES.pushThreadBinding(null); + + Object eof = new Object(); + Object form = null; + + while((form = LispReader.read(reader,false,eof,false)) != eof) + { + form = macroexpand(form); + if(!(form instanceof ISeq)) + throw new Exception("No atoms allowed at top level"); + Object op = RT.first(form); + + //enact import and use at compile-time + if(op == IMPORT) + { + //todo implement import + } + else if(op == USE) + { + //todo implement use + } + else + forms = forms.cons(analyze(C.STATEMENT, form)); + } + } + finally + { + IMPORTS.popThreadBinding(); + USES.popThreadBinding(); + } + } + //declare static members for keywords, vars + for(ISeq keys = RT.seq(KEYWORDS.getValue());keys != null;keys = keys.rest()) + { + KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val(); + format("static Keyword ~A;~%", k.emitExpressionString()); + } + for(ISeq vars = RT.seq(VARS.getValue());vars != null;vars = vars.rest()) + { + Var v = (Var) ((IMapEntry) vars.first()).val(); + format("static Var ~A;~%", munge(v.toString())); + } + + //todo declare static members for syms, quoted aggregates + + //emit nested static class/method declarations for nested fns + PersistentArrayList fns = (PersistentArrayList)FNS.getValue(); + for(int f =0;f<fns.count();f++) + { + FnExpr fn = (FnExpr) fns.nth(f); + fn.emitDeclaration(); + } + + //define the load function + format("public void load() throws Exception{~%"); + //init the keywords and vars + for(ISeq keys = RT.seq(KEYWORDS.getValue());keys != null;keys = keys.rest()) + { + KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val(); + format("~A = (Keyword)Symbol.intern(~S);~%", k.emitExpressionString(), k.sym.name); + } + for(ISeq vars = RT.seq(VARS.getValue());vars != null;vars = vars.rest()) + { + Var v = (Var) ((IMapEntry) vars.first()).val(); + format("~A = Module.intern(~S,~S);~%", munge(v.toString()), v.module.name,v.name.name); + } + //todo init syms and quoted aggregates + //emit the top level forms + for(int i = 0;i<forms.count();i++) + { + Expr e = (Expr) forms.nth(i); + e.emitStatement(); + } + //close load function + format("}~%"); + + //close class def + format("}~%"); + } + catch(Exception e) + { + e.printStackTrace(); + } + finally + { + _CT_OUT.popThreadBinding(); + KEYWORDS.popThreadBinding(); + VARS.popThreadBinding(); + METHOD.popThreadBinding(); + LOCAL_ENV.popThreadBinding(); + FNS.popThreadBinding(); + } + return w.toString(); +} + static String munge(String name){ StringBuilder sb = new StringBuilder(); for(char c : name.toCharArray()) @@ -117,12 +241,12 @@ static class AnExpr implements Expr{ public String emitExpressionString() throws Exception { StringWriter w = new StringWriter(); try{ - OUT.pushThreadBinding(w); + _CT_OUT.pushThreadBinding(w); emitExpression(); return w.toString(); } finally{ - OUT.popThreadBinding(); + _CT_OUT.popThreadBinding(); } } } @@ -159,17 +283,74 @@ private static Expr analyzeSeq(C context, ISeq form) throws Exception { Object op = RT.first(form); if(op == DEF) return analyzeDef(context, form); - if(op == FN) + else if(op == FN) return analyzeFn(context, form); + else if(op == DO) + return analyzeDo(context, form); else throw new UnsupportedOperationException(); } +private static Expr analyzeDo(C context, ISeq form) throws Exception { + //(do ...) + //(do) == null + if(RT.rest(form) == null) + return NIL_EXPR; + else if(RT.rest(RT.rest(form)) == null) //(do x) == x + return analyze(context, macroexpand(RT.second(form))); + else if(context == C.EXPRESSION) + return analyzeFn(context, RT.cons(FN, RT.cons(null, RT.rest(form)))); + else + return analyzeBody(context, RT.rest(form)); + +} + +private static Expr analyzeBody(C context, ISeq forms) throws Exception { + PersistentArrayList exprs = new PersistentArrayList(4); + for(;forms != null;forms = forms.rest()) + { + Expr e = (context == C.STATEMENT || RT.rest(forms) != null) ? + analyze(C.STATEMENT, macroexpand(forms.first())) + : + analyze(C.RETURN, macroexpand(forms.first())); + exprs = exprs.cons(e); + } + return new BodyExpr(exprs); +} + +static class BodyExpr extends AnExpr{ + PersistentArrayList exprs; + + public BodyExpr(PersistentArrayList exprs){ + this.exprs = exprs; + } + + public void emitStatement() throws Exception{ + for(int i=0;i<exprs.count();i++) + ((Expr)exprs.nth(i)).emitStatement(); + } + public void emitReturn() throws Exception{ + if(exprs.count() == 0) + NIL_EXPR.emitReturn(); + else + { + for(int i=0;i<exprs.count();i++) + { + if(i < exprs.count()-1) + ((Expr)exprs.nth(i)).emitStatement(); + else + ((Expr)exprs.nth(i)).emitReturn(); + } + } + } +} + 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)) - return analyzeFn(context, RT.list(FN, RT.rest(form))); + if(RT.second(form) == null || + !(RT.first(RT.second(form)) == null || RT.first(RT.second(form)) instanceof ISeq)) + form = RT.list(FN, RT.rest(form)); FnMethod[] methodArray = new FnMethod[MAX_POSITIONAL_ARITY+1]; FnMethod variadicMethod = null; @@ -222,7 +403,7 @@ static class FnExpr extends AnExpr{ if(name == null) { if(binding != null) - name = "FN__" + binding.sym.name + "__" + RT.nextID(); + name = "FN__" + munge(binding.sym.name) + "__" + RT.nextID(); else name = "FN__" + RT.nextID(); } @@ -233,7 +414,7 @@ static class FnExpr extends AnExpr{ format("(new ~A(", getName()); for(ISeq s = RT.seq(closes);s!=null;s=s.rest()) { - LocalBinding b = (LocalBinding) ((MapEntry) s.first()).key(); + LocalBinding b = (LocalBinding) ((IMapEntry) s.first()).key(); format("~A", b.getName()); if (s.rest() != null) format(","); @@ -248,7 +429,7 @@ static class FnExpr extends AnExpr{ closesDecls = new PersistentArrayList(closes.count() * 2); for (ISeq s = RT.seq(closes); s != null; s = s.rest()) { - LocalBinding b = (LocalBinding) ((MapEntry) s.first()).key(); + LocalBinding b = (LocalBinding) ((IMapEntry) s.first()).key(); closesDecls.cons(b.typeDeclaration()); closesDecls.cons(b.getName()); } @@ -266,7 +447,7 @@ static class FnExpr extends AnExpr{ format("public ~A (~{~A ~A~^, ~}){~%", getName(), closesDecls); for (ISeq s = RT.seq(closes); s != null; s = s.rest()) { - LocalBinding b = (LocalBinding) ((MapEntry) s.first()).key(); + LocalBinding b = (LocalBinding) ((IMapEntry) s.first()).key(); format("this.~A = ~A;~%", b.getName(), b.getName()); if (s.rest() != null) format(","); @@ -330,7 +511,7 @@ static class FnExpr extends AnExpr{ { KeyParam key = (KeyParam) keys.first(); KeywordExpr kw = registerKeyword((Keyword) Symbol.intern(":" + key.bindingExpression.b.sym.name)); - format("__valseq = RT.findKey(~A,__keys);", kw.emitExpressionString()); + 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())); @@ -340,7 +521,7 @@ static class FnExpr extends AnExpr{ //local variables for (ISeq locals = RT.seq(m.locals); locals != null; locals = locals.rest()) { - LocalBinding b = (LocalBinding) ((MapEntry) locals.first()).key(); + LocalBinding b = (LocalBinding) ((IMapEntry) locals.first()).key(); if(!b.isParam) b.emitDeclaration("null"); } @@ -435,7 +616,7 @@ private static FnMethod analyzeMethod(FnExpr fn,ISeq form) throws Exception { if(p instanceof ISeq) method.keyParms = method.keyParms.cons( new KeyParam(createParamBinding((Symbol) RT.first(p)), - analyze(C.EXPRESSION, RT.second(p)))); + analyze(C.EXPRESSION, RT.second(p)))); else method.keyParms = method.keyParms.cons( new KeyParam(createParamBinding((Symbol) p))); @@ -471,12 +652,17 @@ static LocalBindingExpr createParamBinding(Symbol p) { private static Expr analyzeDef(C context, ISeq form) throws Exception { //(def x) or (def x initexpr) + if(form.count() > 3) + throw new Exception("Too many arguments to def"); Symbol sym = (Symbol) RT.second(form); - Module module = (Module) MODULE.getValue(); + Module module = (Module) _CT_MODULE.getValue(); Var var = module.intern(baseSymbol(sym)); registerVar(var); VarExpr ve = new VarExpr(var, typeHint(sym)); Expr init = analyze(C.EXPRESSION, macroexpand(RT.third(form))); + if(init instanceof FnExpr) + ((FnExpr)init).name = "FN__" + munge(var.name.toString()) + "__" + RT.nextID(); + return new DefExpr(ve, init); } @@ -523,13 +709,13 @@ private static Expr analyzeSymbol(Symbol sym) throws Exception { } static Var lookupVar(Symbol sym){ - Module module = (Module) MODULE.getValue(); + Module module = (Module) _CT_MODULE.getValue(); Var v = module.find(sym); if(v != null) return v; for(ISeq seq = RT.seq(USES.getValue());seq != null;seq = RT.rest(seq)) { - module = (Module) ((MapEntry)RT.first(seq)).key(); + module = (Module) ((IMapEntry)RT.first(seq)).key(); v = module.find(sym); if(v != null && !v.hidden) return v; @@ -556,7 +742,7 @@ private static void registerVar(Var var) { } private static void registerFn(FnExpr fn) { - FNS.setValue(RT.cons(fn, (ISeq)FNS.getValue())); + FNS.setValue(RT.cons(fn, (IPersistentCollection) FNS.getValue())); } static void closeOver(LocalBinding b,FnMethod method){ @@ -611,15 +797,16 @@ static class KeyParam{ public KeyParam(LocalBindingExpr b, Expr init) { this.bindingExpression = b; this.init = init; + kw = registerKeyword((Keyword) Symbol.intern(":" + bindingExpression.b.sym.name)); } public KeyParam(LocalBindingExpr b) { - this.bindingExpression = b; - this.init = NIL_EXPR; + this(b,NIL_EXPR); } LocalBindingExpr bindingExpression; Expr init; + KeywordExpr kw; } @@ -663,7 +850,7 @@ static class HostExpr extends AnExpr{ public void emitExpression() throws Exception{ if(sym instanceof ClassSymbol) - format("%A.class", resolveHostClassname(((ClassSymbol) sym).className)); + format("~A.class", resolveHostClassname(((ClassSymbol) sym).className)); } } /* @@ -677,7 +864,7 @@ static class SymExpr extends AnExpr{ } public void emitExpression() throws Exception{ - format("%A", munge(sym.name)); + format("~A", munge(sym.name)); } } */ @@ -689,7 +876,7 @@ static class KeywordExpr extends AnExpr{ } public void emitExpression() throws Exception { - format("%A", munge(sym.name)); + format("~A", munge(sym.name)); } } @@ -740,7 +927,7 @@ static class LocalBindingExpr extends AnExpr{ } public void emitExpression() throws Exception{ - format("%A", b.getName()); + format("~A", b.getName()); } } @@ -754,7 +941,7 @@ static class VarExpr extends AnExpr{ } public void emitExpression() throws Exception{ - format("%A", munge(var.toString())); + format("~A", munge(var.toString())); } } @@ -768,10 +955,36 @@ static class DefExpr extends AnExpr{ } public void emitExpression() throws Exception{ - format("%A.bind(%A)", var.emitExpressionString(),init.emitExpressionString()); + format("~A.bind(~A)", var.emitExpressionString(),init.emitExpressionString()); } } +public static void main(String[] args) throws Exception { + if(!(args.length >= 3 )) + System.err.println("Usage: clojure.lang.Compiler package class file1 [file2 ...]"); + String pkg = args[0]; + String classname = args[1]; + LineNumberingPushbackReader[] rs = new LineNumberingPushbackReader[args.length - 2]; + String ret; + try + { + for(int i=0;i<rs.length;i++) + { + rs[i] = new LineNumberingPushbackReader(new InputStreamReader(new FileInputStream(args[i + 2]))); + } + ret = compile(pkg, classname, rs); + System.out.print(ret); + } + finally + { + for (LineNumberingPushbackReader r : rs) + { + if(r != null) + r.close(); + } + } +} + } //*/ diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index 620a6520..acfacab5 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -31,7 +31,7 @@ static final int HASHTABLE_THRESHOLD = 42; public static PersistentArrayMap EMPTY = new PersistentArrayMap();
protected PersistentArrayMap(){
- this.array = RT.EMPTY_ARRAY;
+ this.array = new Object[]{};
}
PersistentArrayMap create(Object... init){
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index f00101c0..ea4f6041 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -18,8 +18,9 @@ import java.io.*; public class RT{ - static public Symbol T = Symbol.intern("t"); + static public Symbol T = Symbol.intern(":t"); static public Var OUT = Module.intern("clojure","^out"); + static public Var _CT_MODULE = Module.intern("clojure", "^module"); static public final Object[] EMPTY_ARRAY = new Object[]{}; static public final Character[] chars; static AtomicInteger id = new AtomicInteger(1); @@ -28,6 +29,9 @@ public class RT{ chars = new Character[256]; for(int i=0;i<chars.length;i++) chars[i] = new Character((char)i); + + OUT.bind(new OutputStreamWriter(System.out)); + _CT_MODULE.bind((Module.findOrCreate("clj-user"))); } static public int nextID(){ |