summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2007-12-13 16:43:15 +0000
committerRich Hickey <richhickey@gmail.com>2007-12-13 16:43:15 +0000
commit7be0a43dd5c83333de8e10c010f4d04f9ce4087e (patch)
treec36fa7e81c66e718a5bd13cf177dee2cac44b8f5 /src
parent1c3bf71000b2a531995557110e04cd5ff8c22535 (diff)
added try
Diffstat (limited to 'src')
-rw-r--r--src/jvm/clojure/lang/Compiler.java156
1 files changed, 151 insertions, 5 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index c051d1c2..5db862b2 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -12,13 +12,14 @@
package clojure.lang;
-//*
+/*
import clojure.asm.*;
import clojure.asm.commons.Method;
import clojure.asm.commons.GeneratorAdapter;
-//*/
-/*
+/*/
+//*
+
import org.objectweb.asm.*;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.commons.GeneratorAdapter;
@@ -46,6 +47,7 @@ static final Symbol THE_VAR = Symbol.create("the-var");
static final Symbol DOT = Symbol.create(".");
static final Symbol ASSIGN = Symbol.create("set!");
static final Symbol TRY_FINALLY = Symbol.create("try-finally");
+static final Symbol TRY = Symbol.create("try");
static final Symbol THROW = Symbol.create("throw");
static final Symbol MONITOR_ENTER = Symbol.create("monitor-enter");
static final Symbol MONITOR_EXIT = Symbol.create("monitor-exit");
@@ -81,6 +83,7 @@ static IPersistentMap specials = RT.map(
DOT, new HostExpr.Parser(),
ASSIGN, new AssignExpr.Parser(),
TRY_FINALLY, new TryFinallyExpr.Parser(),
+ TRY, new TryExpr.Parser(),
THROW, new ThrowExpr.Parser(),
MONITOR_ENTER, new MonitorEnterExpr.Parser(),
MONITOR_EXIT, new MonitorExitExpr.Parser(),
@@ -1203,6 +1206,149 @@ static class MonitorExitExpr extends UntypedExpr{
}
+static class TryExpr implements Expr{
+ final Expr tryExpr;
+ final Expr finallyExpr;
+ final PersistentVector catchExprs;
+
+ static class CatchClause{
+ final String className;
+ final LocalBinding lb;
+ final Expr handler;
+ Label label;
+ Label endLabel;
+
+
+ public CatchClause(String className, LocalBinding lb, Expr handler){
+ this.className = className;
+ this.lb = lb;
+ this.handler = handler;
+ }
+ }
+
+ public TryExpr(Expr tryExpr, PersistentVector catchExprs, Expr finallyExpr){
+ this.tryExpr = tryExpr;
+ this.catchExprs = catchExprs;
+ this.finallyExpr = finallyExpr;
+ }
+
+ public Object eval() throws Exception{
+ throw new UnsupportedOperationException("Can't eval try");
+ }
+
+ public void emit(C context, FnExpr fn, GeneratorAdapter gen){
+ Label startTry = gen.newLabel();
+ Label endTry = gen.newLabel();
+ Label end = gen.newLabel();
+ Label finallyLabel = gen.newLabel();
+ for(int i = 0; i < catchExprs.count(); i++)
+ {
+ CatchClause clause = (CatchClause) catchExprs.nth(i);
+ clause.label = gen.newLabel();
+ clause.endLabel = gen.newLabel();
+ gen.visitTryCatchBlock(startTry, endTry, clause.label, clause.className.replace('.', '/'));
+ }
+ if(finallyExpr != null)
+ gen.visitTryCatchBlock(startTry, endTry, finallyLabel, null);
+
+ gen.mark(startTry);
+ tryExpr.emit(context, fn, gen);
+ gen.mark(endTry);
+ if(finallyExpr != null)
+ finallyExpr.emit(C.STATEMENT, fn, gen);
+ gen.goTo(end);
+
+ for(int i = 0; i < catchExprs.count(); i++)
+ {
+ CatchClause clause = (CatchClause) catchExprs.nth(i);
+ gen.mark(clause.label);
+ //exception should be on stack
+ //put in clause local
+ gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), clause.lb.idx);
+ clause.handler.emit(context, fn, gen);
+ gen.mark(clause.endLabel);
+
+ if(finallyExpr != null)
+ finallyExpr.emit(C.STATEMENT, fn, gen);
+ gen.goTo(end);
+ }
+ if(finallyExpr != null)
+ {
+ gen.mark(finallyLabel);
+ //exception should be on stack
+ finallyExpr.emit(C.STATEMENT, fn, gen);
+ gen.throwException();
+ }
+ gen.mark(end);
+ for(int i = 0; i < catchExprs.count(); i++)
+ {
+ CatchClause clause = (CatchClause) catchExprs.nth(i);
+ gen.visitLocalVariable(clause.lb.name, "Ljava/lang/Object;", null, clause.label, clause.endLabel,
+ clause.lb.idx);
+ }
+ }
+
+ public boolean hasJavaClass() throws Exception{
+ return tryExpr.hasJavaClass();
+ }
+
+ public Class getJavaClass() throws Exception{
+ return tryExpr.getJavaClass();
+ }
+
+ static class Parser implements IParser{
+
+ public Expr parse(C context, Object frm) throws Exception{
+ ISeq form = (ISeq) frm;
+ if(context == C.EVAL || context == C.EXPRESSION)
+ return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
+
+ //(try try-expr catch-block finally-expr)
+ //catch-block: [class sym expr class2 sym2 expr2 ...]
+ if(form.count() != 3 && form.count() != 4)
+ throw new IllegalArgumentException(
+ "Wrong number of arguments, expecting: (try try-expr catch-block finally-expr?) ");
+
+ IPersistentVector catchBlock = (IPersistentVector) RT.third(form);
+ if((catchBlock.count() % 3) != 0)
+ throw new IllegalArgumentException("Bad catch block, expected matched class symbol expression triples");
+
+ PersistentVector catches = PersistentVector.EMPTY;
+
+ for(int i = 0; i < catchBlock.count(); i += 3)
+ {
+ String className = HostExpr.maybeClassName(catchBlock.nth(i));
+ if(className == null)
+ throw new IllegalArgumentException("Unable to resolve classname: " + catchBlock.nth(i));
+ if(!(catchBlock.nth(i + 1) instanceof Symbol))
+ throw new IllegalArgumentException(
+ "Bad binding form, expected symbol, got: " + catchBlock.nth(i + 1));
+ Symbol sym = (Symbol) catchBlock.nth(i + 1);
+ if(sym.getNamespace() != null)
+ throw new Exception("Can't bind qualified name");
+
+ IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.get(),
+ NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.get());
+ try
+ {
+ Var.pushThreadBindings(dynamicBindings);
+ LocalBinding lb = registerLocal(sym, null, null);
+ Expr handler = analyze(context, catchBlock.nth(i + 2));
+ catches = catches.cons(new CatchClause(className, lb, handler));
+ }
+ finally
+ {
+ Var.popThreadBindings();
+ }
+ }
+
+ return new TryExpr(analyze(context, RT.second(form)),
+ catches,
+ RT.fourth(form) != null ? analyze(C.STATEMENT, RT.fourth(form)) : null);
+ }
+ }
+}
+
static class TryFinallyExpr implements Expr{
final Expr tryExpr;
final Expr finallyExpr;
@@ -1952,8 +2098,8 @@ static class FnExpr implements Expr{
//derived from AFn/RestFn
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// ClassWriter cw = new ClassWriter(0);
- ClassVisitor cv = cw;
- //ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out));
+ //ClassVisitor cv = cw;
+ ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out));
//ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));
cv.visit(V1_5, ACC_PUBLIC, internalName, null, isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFn", null);
String source = (String) SOURCE.get();