diff options
author | Rich Hickey <richhickey@gmail.com> | 2007-09-03 22:31:49 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2007-09-03 22:31:49 +0000 |
commit | c0b1333eb25fea97a04de528d5c8f612bd098e89 (patch) | |
tree | 7d71596545f0a3e6f983b1f27eaa1b6eb6347d72 /src | |
parent | a51a104cfff59b7b27628dcc66885d712510879f (diff) |
added assign, support rebinding of Var via set
Diffstat (limited to 'src')
-rw-r--r-- | src/jvm/clojure/lang/BytecodeCompiler.java | 38 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Var.java | 7 |
2 files changed, 40 insertions, 5 deletions
diff --git a/src/jvm/clojure/lang/BytecodeCompiler.java b/src/jvm/clojure/lang/BytecodeCompiler.java index 1dd51e80..3412fbb8 100644 --- a/src/jvm/clojure/lang/BytecodeCompiler.java +++ b/src/jvm/clojure/lang/BytecodeCompiler.java @@ -152,6 +152,34 @@ static class DefExpr implements Expr{ } } +static class AssignExpr implements Expr{ + final AssignableExpr target; + final Expr val; + + + public AssignExpr(AssignableExpr target, Expr val){ + this.target = target; + this.val = val; + } + + public Object eval() throws Exception{ + return target.evalAssign(val); + } + + public void emit(C context, FnExpr fn, GeneratorAdapter gen){ + target.emitAssign(context, fn, gen, val); + } + + public static Expr parse(C context, ISeq form) throws Exception{ + if(RT.length(form) != 3) + throw new IllegalArgumentException("Malformed assignment, expecting (= target val)"); + Expr target = analyze(C.EXPRESSION, RT.second(form)); + if(!(target instanceof AssignableExpr)) + throw new IllegalArgumentException("Invalid assignment target"); + return new AssignExpr((AssignableExpr) target, analyze(C.EXPRESSION, RT.third(form))); + } +} + static class VarExpr implements Expr, AssignableExpr{ final Var var; final Symbol tag; @@ -180,7 +208,7 @@ static class VarExpr implements Expr, AssignableExpr{ } public void emitAssign(C context, FnExpr fn, GeneratorAdapter gen, - Expr val) throws Exception{ + Expr val){ fn.emitVar(gen, var); val.emit(C.EXPRESSION, fn, gen); gen.invokeVirtual(VAR_TYPE, setMethod); @@ -243,7 +271,7 @@ static abstract class LiteralExpr implements Expr{ static interface AssignableExpr{ Object evalAssign(Expr val) throws Exception; - void emitAssign(C context, FnExpr fn, GeneratorAdapter gen, Expr val) throws Exception; + void emitAssign(C context, FnExpr fn, GeneratorAdapter gen, Expr val); } static abstract class HostExpr implements Expr{ @@ -330,7 +358,7 @@ static class InstanceFieldExpr extends FieldExpr implements AssignableExpr{ } public void emitAssign(C context, FnExpr fn, GeneratorAdapter gen, - Expr val) throws Exception{ + Expr val){ target.emit(C.EXPRESSION, fn, gen); gen.push(fieldName); val.emit(C.EXPRESSION, fn, gen); @@ -367,7 +395,7 @@ static class StaticFieldExpr extends FieldExpr implements AssignableExpr{ } public void emitAssign(C context, FnExpr fn, GeneratorAdapter gen, - Expr val) throws Exception{ + Expr val){ gen.push(className); gen.push(fieldName); val.emit(C.EXPRESSION, fn, gen); @@ -1372,6 +1400,8 @@ private static Expr analyzeSeq(C context, ISeq form, String name) throws Excepti return HostExpr.parse(context, form); else if(op.equals(THE_VAR)) return TheVarExpr.parse(context, form); + else if(op.equals(ASSIGN)) + return AssignExpr.parse(context, form); else return InvokeExpr.parse(context, form); } diff --git a/src/jvm/clojure/lang/Var.java b/src/jvm/clojure/lang/Var.java index 42ecde91..267bc7ee 100644 --- a/src/jvm/clojure/lang/Var.java +++ b/src/jvm/clojure/lang/Var.java @@ -124,7 +124,12 @@ public Object set(Object val){ Box b = getThreadBinding(); if(b != null) return (b.val = val); - throw new IllegalStateException(String.format("Can't change root binding of: %s with set", sym)); + if(hasRoot()) + { + bindRoot(val); + return val; + } + throw new IllegalStateException(String.format("Can't establish root binding of: %s with set", sym)); } public Object getRoot(){ |