summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli/runtime/PersistentArrayMap.cs2
-rw-r--r--src/cli/runtime/RT.cs5
-rw-r--r--src/jvm/clojure/lang/Compiler.java265
-rw-r--r--src/jvm/clojure/lang/PersistentArrayMap.java2
-rw-r--r--src/jvm/clojure/lang/RT.java6
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(){