summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2007-09-01 19:19:49 +0000
committerRich Hickey <richhickey@gmail.com>2007-09-01 19:19:49 +0000
commitf96102812da70214ef45e4f7bb68707258d3a41c (patch)
tree6b9df87d78cf4fd6d2360e2bdc18a4ef4b514065 /src
parente49402f71c6751b77c68631d5ebb44de72a44a93 (diff)
interim checkin
Diffstat (limited to 'src')
-rw-r--r--src/jvm/clojure/lang/BytecodeCompiler.java201
-rw-r--r--src/jvm/clojure/lang/Compiler.java10
2 files changed, 116 insertions, 95 deletions
diff --git a/src/jvm/clojure/lang/BytecodeCompiler.java b/src/jvm/clojure/lang/BytecodeCompiler.java
index cb80d992..0063c0f1 100644
--- a/src/jvm/clojure/lang/BytecodeCompiler.java
+++ b/src/jvm/clojure/lang/BytecodeCompiler.java
@@ -45,6 +45,9 @@ static Symbol _AMP_ = Symbol.create("&");
private static final int MAX_POSITIONAL_ARITY = 20;
private static Type OBJECT_TYPE;
+private static Type KEYWORD_TYPE = Type.getType(Keyword.class);
+private static Type VAR_TYPE = Type.getType(DynamicVar.class);
+
private static Type[][] ARG_TYPES;
static
@@ -62,7 +65,7 @@ static
//symbol->localbinding
-static public DynamicVar LOCAL_ENV = DynamicVar.create();
+static public DynamicVar LOCAL_ENV = DynamicVar.create(null);
//vector<localbinding>
static public DynamicVar LOOP_LOCALS = DynamicVar.create();
@@ -74,13 +77,13 @@ static public DynamicVar KEYWORDS = DynamicVar.create();
static public DynamicVar VARS = DynamicVar.create();
//FnFrame
-static public DynamicVar METHOD = DynamicVar.create();
+static public DynamicVar METHOD = DynamicVar.create(null);
//String
-static public DynamicVar SOURCE = DynamicVar.create();
+static public DynamicVar SOURCE = DynamicVar.create(null);
//Integer
-static public DynamicVar NEXT_LOCAL_NUM = DynamicVar.create();
+static public DynamicVar NEXT_LOCAL_NUM = DynamicVar.create(0);
//DynamicClassLoader
static public DynamicVar LOADER = DynamicVar.create();
@@ -234,7 +237,7 @@ static class IfExpr implements Expr{
}
static public IPersistentMap CHAR_MAP =
- PersistentHashMap.create('-', "_DASH_",
+ PersistentHashMap.create('-', "_",
'.', "_DOT_",
':', "_COLON_",
'+', "_PLUS_",
@@ -275,12 +278,13 @@ static class FnExpr implements Expr{
IPersistentCollection methods;
//if there is a variadic overload (there can only be one) it is stored here
FnMethod variadicMethod = null;
- String name = null;
+ String name;
String internalName;
//localbinding->itself
- IPersistentMap closes = null;
- IPersistentMap keywords = null;
- IPersistentMap vars = null;
+ IPersistentMap closes = PersistentHashMap.EMPTY;
+ //KeywordExpr->iteself
+ IPersistentMap keywords = PersistentHashMap.EMPTY;
+ IPersistentMap vars = PersistentHashMap.EMPTY;
Class compiledClass;
static Expr parse(C context, ISeq form, String name) throws Exception{
@@ -308,7 +312,7 @@ static class FnExpr implements Expr{
FnMethod variadicMethod = null;
for(ISeq s = RT.rest(form); s != null; s = RT.rest(s))
{
- FnMethod f = analyzeMethod(fn, (ISeq) RT.first(s));
+ FnMethod f = FnMethod.parse(fn, (ISeq) RT.first(s));
if(f.isVariadic())
{
if(variadicMethod == null)
@@ -360,11 +364,17 @@ static class FnExpr implements Expr{
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
//ClassVisitor cv = cw;
ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));
- cv.visit(V1_5, ACC_PUBLIC, name, null, isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFn", null);
+ cv.visit(V1_5, ACC_PUBLIC, internalName, null, isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFn", null);
String source = (String) SOURCE.get();
if(source != null)
cv.visitSource(source, null);
//todo static fields for keywords and vars
+ for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
+ {
+ KeywordExpr k = (KeywordExpr) s.first();
+ cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, munge(k.k.sym.toString()),
+ OBJECT_TYPE.getDescriptor(), null, null);
+ }
//todo static init for keywords and vars
//instance fields for closed-overs
for(ISeq s = RT.keys(closes); s != null; s = s.rest())
@@ -410,68 +420,6 @@ enum PSTATE{
REQ, REST, DONE
}
-private static FnMethod analyzeMethod(FnExpr fn, ISeq form) throws Exception{
- //([args] body...)
- ISeq parms = (ISeq) RT.first(form);
- ISeq body = RT.rest(form);
- try
- {
- FnMethod method = new FnMethod(fn, (FnMethod) METHOD.get());
- //register as the current method and set up a new env frame
- DynamicVar.pushThreadBindings(
- RT.map(
- METHOD, method,
- LOCAL_ENV, LOCAL_ENV.get(),
- LOOP_LOCALS, null,
- NEXT_LOCAL_NUM, 0));
-
- //register 'this' as local 0
- registerLocal(THISFN, null);
-
- PSTATE state = PSTATE.REQ;
- PersistentVector loopLocals = PersistentVector.EMPTY;
- for(ISeq ps = parms; ps != null; ps = ps.rest())
- {
- Symbol p = (Symbol) ps.first();
- if(p.equals(_AMP_))
- {
- if(state == PSTATE.REQ)
- state = PSTATE.REST;
- else
- throw new Exception("Invalid parameter list");
- }
-
- else
- {
- LocalBinding lb = registerLocal(p, tagOf(p));
- loopLocals = loopLocals.cons(lb);
- switch(state)
- {
- case REQ:
- method.reqParms = method.reqParms.cons(lb);
- break;
- case REST:
- method.restParm = lb;
- state = PSTATE.DONE;
- break;
-
- default:
- throw new Exception("Unexpected parameter");
- }
- }
- }
- if(method.reqParms.count() > MAX_POSITIONAL_ARITY)
- throw new Exception("Can't specify more than " + MAX_POSITIONAL_ARITY + " params");
- LOOP_LOCALS.set(loopLocals);
- method.body = BodyExpr.parse(C.RETURN, body);
- return method;
- }
- finally
- {
- DynamicVar.popThreadBindings();
- }
-}
-
static class FnMethod{
//when closures are defined inside other closures,
@@ -481,7 +429,6 @@ static class FnMethod{
IPersistentMap locals = null;
//localbinding->localbinding
PersistentVector reqParms = PersistentVector.EMPTY;
- PersistentVector keyParms = null;
LocalBinding restParm = null;
Expr body = null;
FnExpr fn;
@@ -492,7 +439,75 @@ static class FnMethod{
}
boolean isVariadic(){
- return keyParms != null || restParm != null;
+ return restParm != null;
+ }
+
+ int numParams(){
+ return reqParms.count() + (isVariadic() ? 1 : 0);
+ }
+
+ private static FnMethod parse(FnExpr fn, ISeq form) throws Exception{
+ //([args] body...)
+ IPersistentArray parms = (IPersistentArray) RT.first(form);
+ ISeq body = RT.rest(form);
+ try
+ {
+ FnMethod method = new FnMethod(fn, (FnMethod) METHOD.get());
+ //register as the current method and set up a new env frame
+ DynamicVar.pushThreadBindings(
+ RT.map(
+ METHOD, method,
+ LOCAL_ENV, LOCAL_ENV.get(),
+ LOOP_LOCALS, null,
+ NEXT_LOCAL_NUM, 0));
+
+ //register 'this' as local 0
+ registerLocal(THISFN, null);
+
+ PSTATE state = PSTATE.REQ;
+ PersistentVector loopLocals = PersistentVector.EMPTY;
+ for(int i = 0; i < parms.count(); i++)
+ {
+ if(!(parms.nth(i) instanceof Symbol))
+ throw new IllegalArgumentException("fn params must be Symbols");
+ Symbol p = (Symbol) parms.nth(i);
+ if(p.equals(_AMP_))
+ {
+ if(state == PSTATE.REQ)
+ state = PSTATE.REST;
+ else
+ throw new Exception("Invalid parameter list");
+ }
+
+ else
+ {
+ LocalBinding lb = registerLocal(p, tagOf(p));
+ loopLocals = loopLocals.cons(lb);
+ switch(state)
+ {
+ case REQ:
+ method.reqParms = method.reqParms.cons(lb);
+ break;
+ case REST:
+ method.restParm = lb;
+ state = PSTATE.DONE;
+ break;
+
+ default:
+ throw new Exception("Unexpected parameter");
+ }
+ }
+ }
+ if(method.reqParms.count() > MAX_POSITIONAL_ARITY)
+ throw new Exception("Can't specify more than " + MAX_POSITIONAL_ARITY + " params");
+ LOOP_LOCALS.set(loopLocals);
+ method.body = BodyExpr.parse(C.RETURN, body);
+ return method;
+ }
+ finally
+ {
+ DynamicVar.popThreadBindings();
+ }
}
}
@@ -578,7 +593,12 @@ static class LetExpr implements Expr{
static Expr parse(C context, ISeq form, boolean isLoop) throws Exception{
//(let [var val var2 val2 ...] body...)
- ISeq bindings = (ISeq) RT.second(form);
+ if(!(RT.second(form) instanceof IPersistentArray))
+ throw new IllegalArgumentException("Bad binding form, expected vector");
+
+ IPersistentArray bindings = (IPersistentArray) RT.second(form);
+ if((bindings.count() % 2) != 0)
+ throw new IllegalArgumentException("Bad binding form, expected matched symbol expression pairs");
ISeq body = RT.rest(RT.rest(form));
@@ -596,15 +616,13 @@ static class LetExpr implements Expr{
PersistentVector bindingInits = PersistentVector.EMPTY;
PersistentVector loopLocals = PersistentVector.EMPTY;
- for(ISeq bs = bindings; bs != null; bs = RT.rest(RT.rest(bs)))
+ for(int i = 0; i < bindings.count(); i += 2)
{
- if(!(RT.first(bs) instanceof Symbol))
- throw new IllegalArgumentException("Bad binding form, expected symbol, got: " + RT.first(bs));
- Symbol sym = (Symbol) RT.first(bs);
- if(bs.rest() == null)
- throw new IllegalArgumentException("Bad binding form, expected expression following: " + sym);
+ if(!(bindings.nth(i) instanceof Symbol))
+ throw new IllegalArgumentException("Bad binding form, expected symbol, got: " + bindings.nth(i));
+ Symbol sym = (Symbol) bindings.nth(i);
- Expr init = analyze(C.EXPRESSION, RT.second(bs), sym.name);
+ Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name);
//sequential enhancement of env (like Lisp let*)
LocalBinding lb = registerLocal(sym, tagOf(sym));
BindingInit bi = new BindingInit(lb, init);
@@ -624,7 +642,7 @@ static class LetExpr implements Expr{
}
public Object eval() throws Exception{
- throw new UnsupportedOperationException("Can't eval let");
+ throw new UnsupportedOperationException("Can't eval let/loop");
}
}
@@ -633,7 +651,7 @@ private static LocalBinding registerLocal(Symbol sym, Symbol tag) throws Excepti
LocalBinding b = new LocalBinding(num, sym, tag);
NEXT_LOCAL_NUM.set(num + 1);
IPersistentMap localsMap = (IPersistentMap) LOCAL_ENV.get();
- LOCAL_ENV.set(RT.assoc(b.sym, b, localsMap));
+ LOCAL_ENV.set(RT.assoc(localsMap, b.sym, b));
FnMethod method = (FnMethod) METHOD.get();
method.locals = (IPersistentMap) RT.assoc(method.locals, b, b);
return b;
@@ -693,9 +711,9 @@ private static KeywordExpr registerKeyword(Keyword keyword){
return new KeywordExpr(keyword);
IPersistentMap keywordsMap = (IPersistentMap) KEYWORDS.get();
- KeywordExpr ke = (KeywordExpr) RT.get(keyword, keywordsMap);
+ KeywordExpr ke = (KeywordExpr) RT.get(keywordsMap, keyword);
if(ke == null)
- KEYWORDS.set(RT.assoc(keyword, ke = new KeywordExpr(keyword), keywordsMap));
+ KEYWORDS.set(RT.assoc(keywordsMap, keyword, ke = new KeywordExpr(keyword)));
return ke;
}
@@ -743,7 +761,7 @@ private static void registerVar(DynamicVar var) throws Exception{
if(!VARS.isBound())
return;
IPersistentMap varsMap = (IPersistentMap) VARS.get();
- if(varsMap != null && RT.get(var, varsMap) == null)
+ if(varsMap != null && RT.get(varsMap, var) == null)
VARS.set(RT.assoc(varsMap, var, var));
}
@@ -752,7 +770,7 @@ private static String currentNS(){
}
static void closeOver(LocalBinding b, FnMethod method){
- if(b != null && method != null && RT.get(b, method.locals) == null)
+ if(b != null && method != null && RT.get(method.locals, b) == null)
{
method.fn.closes = (IPersistentMap) RT.assoc(method.fn.closes, b, b);
closeOver(b, method.parent);
@@ -763,7 +781,7 @@ static void closeOver(LocalBinding b, FnMethod method){
static LocalBinding referenceLocal(Symbol sym) throws Exception{
if(!LOCAL_ENV.isBound())
return null;
- LocalBinding b = (LocalBinding) RT.get(sym, LOCAL_ENV.get());
+ LocalBinding b = (LocalBinding) RT.get(LOCAL_ENV.get(), sym);
if(b != null)
{
closeOver(b, (FnMethod) METHOD.get());
@@ -787,6 +805,8 @@ public static void main(String[] args){
{
try
{
+ DynamicVar.pushThreadBindings(
+ RT.map(LOADER, new DynamicClassLoader()));
Object r = LispReader.read(rdr, false, EOF, false);
if(r == EOF)
break;
@@ -797,6 +817,7 @@ public static void main(String[] args){
}
catch(Exception e)
{
+ DynamicVar.popThreadBindings();
e.printStackTrace();
}
}
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index bba2c96b..85f2347e 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -1568,7 +1568,7 @@ static Object macroexpand(Object x){
private static KeywordExpr registerKeyword(Keyword keyword) throws Exception{
IPersistentMap keywordsMap = (IPersistentMap) KEYWORDS.get();
- KeywordExpr ke = (KeywordExpr) RT.get(keyword, keywordsMap);
+ KeywordExpr ke = (KeywordExpr) RT.get(keywordsMap, keyword);
//! if(ke == null)
//! KEYWORDS.set(RT.assoc(keyword, ke = new KeywordExpr(keyword), keywordsMap));
return ke;
@@ -1576,7 +1576,7 @@ private static KeywordExpr registerKeyword(Keyword keyword) throws Exception{
private static void registerVar(DynamicVar var) throws Exception{
IPersistentMap varsMap = (IPersistentMap) VARS.get();
- if(RT.get(var, varsMap) == null)
+ if(RT.get(varsMap, var) == null)
VARS.set(RT.assoc(varsMap, var, var));
}
@@ -1585,7 +1585,7 @@ private static void registerFn(FnExpr fn) throws Exception{
}
static void closeOver(LocalBinding b, FnMethod method){
- if(b != null && method != null && RT.get(b, method.locals) == null)
+ if(b != null && method != null && RT.get(method.locals, b) == null)
{
b.isClosed = true;
method.fn.closes = (IPersistentMap) RT.assoc(method.fn.closes, b, b);
@@ -1594,7 +1594,7 @@ static void closeOver(LocalBinding b, FnMethod method){
}
static LocalBinding referenceLocal(Symbol sym) throws Exception{
- LocalBinding b = (LocalBinding) RT.get(sym, LOCAL_ENV.get());
+ LocalBinding b = (LocalBinding) RT.get(LOCAL_ENV.get(), sym);
if(b != null)
{
closeOver(b, (FnMethod) METHOD.get());
@@ -1629,7 +1629,7 @@ static String resolveHostClassname(String classname) throws Exception{
if(isPrimitive(classname))
return classname;
IPersistentMap importMap = (IPersistentMap) IMPORTS.get();
- String fullyQualifiedName = (String) RT.get(classname, importMap);
+ String fullyQualifiedName = (String) RT.get(importMap, classname);
if(fullyQualifiedName == null)
throw new Exception("Can't resolve type name: " + classname);
return fullyQualifiedName;