Mercurial > lasercutter
diff src/clojure/lang/Compiler.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/lang/Compiler.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,6897 @@ 1.4 +/** 1.5 + * Copyright (c) Rich Hickey. All rights reserved. 1.6 + * The use and distribution terms for this software are covered by the 1.7 + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.8 + * which can be found in the file epl-v10.html at the root of this distribution. 1.9 + * By using this software in any fashion, you are agreeing to be bound by 1.10 + * the terms of this license. 1.11 + * You must not remove this notice, or any other, from this software. 1.12 + **/ 1.13 + 1.14 +/* rich Aug 21, 2007 */ 1.15 + 1.16 +package clojure.lang; 1.17 + 1.18 +//* 1.19 + 1.20 +import clojure.asm.*; 1.21 +import clojure.asm.commons.Method; 1.22 +import clojure.asm.commons.GeneratorAdapter; 1.23 +//*/ 1.24 +/* 1.25 + 1.26 +import org.objectweb.asm.*; 1.27 +import org.objectweb.asm.commons.Method; 1.28 +import org.objectweb.asm.commons.GeneratorAdapter; 1.29 +import org.objectweb.asm.util.TraceClassVisitor; 1.30 +import org.objectweb.asm.util.CheckClassAdapter; 1.31 +//*/ 1.32 + 1.33 +import java.io.*; 1.34 +import java.util.*; 1.35 +import java.lang.reflect.Constructor; 1.36 +import java.lang.reflect.Modifier; 1.37 + 1.38 +public class Compiler implements Opcodes{ 1.39 + 1.40 +static final Symbol DEF = Symbol.create("def"); 1.41 +static final Symbol LOOP = Symbol.create("loop*"); 1.42 +static final Symbol RECUR = Symbol.create("recur"); 1.43 +static final Symbol IF = Symbol.create("if"); 1.44 +static final Symbol LET = Symbol.create("let*"); 1.45 +static final Symbol LETFN = Symbol.create("letfn*"); 1.46 +static final Symbol DO = Symbol.create("do"); 1.47 +static final Symbol FN = Symbol.create("fn*"); 1.48 +static final Symbol QUOTE = Symbol.create("quote"); 1.49 +static final Symbol THE_VAR = Symbol.create("var"); 1.50 +static final Symbol DOT = Symbol.create("."); 1.51 +static final Symbol ASSIGN = Symbol.create("set!"); 1.52 +//static final Symbol TRY_FINALLY = Symbol.create("try-finally"); 1.53 +static final Symbol TRY = Symbol.create("try"); 1.54 +static final Symbol CATCH = Symbol.create("catch"); 1.55 +static final Symbol FINALLY = Symbol.create("finally"); 1.56 +static final Symbol THROW = Symbol.create("throw"); 1.57 +static final Symbol MONITOR_ENTER = Symbol.create("monitor-enter"); 1.58 +static final Symbol MONITOR_EXIT = Symbol.create("monitor-exit"); 1.59 +static final Symbol IMPORT = Symbol.create("clojure.core", "import*"); 1.60 +//static final Symbol INSTANCE = Symbol.create("instance?"); 1.61 +static final Symbol DEFTYPE = Symbol.create("deftype*"); 1.62 +static final Symbol CASE = Symbol.create("case*"); 1.63 + 1.64 +//static final Symbol THISFN = Symbol.create("thisfn"); 1.65 +static final Symbol CLASS = Symbol.create("Class"); 1.66 +static final Symbol NEW = Symbol.create("new"); 1.67 +static final Symbol THIS = Symbol.create("this"); 1.68 +static final Symbol REIFY = Symbol.create("reify*"); 1.69 +//static final Symbol UNQUOTE = Symbol.create("unquote"); 1.70 +//static final Symbol UNQUOTE_SPLICING = Symbol.create("unquote-splicing"); 1.71 +//static final Symbol SYNTAX_QUOTE = Symbol.create("clojure.core", "syntax-quote"); 1.72 +static final Symbol LIST = Symbol.create("clojure.core", "list"); 1.73 +static final Symbol HASHMAP = Symbol.create("clojure.core", "hash-map"); 1.74 +static final Symbol VECTOR = Symbol.create("clojure.core", "vector"); 1.75 +static final Symbol IDENTITY = Symbol.create("clojure.core", "identity"); 1.76 + 1.77 +static final Symbol _AMP_ = Symbol.create("&"); 1.78 +static final Symbol ISEQ = Symbol.create("clojure.lang.ISeq"); 1.79 + 1.80 +static final Keyword inlineKey = Keyword.intern(null, "inline"); 1.81 +static final Keyword inlineAritiesKey = Keyword.intern(null, "inline-arities"); 1.82 + 1.83 +static final Keyword volatileKey = Keyword.intern(null, "volatile"); 1.84 +static final Keyword implementsKey = Keyword.intern(null, "implements"); 1.85 +static final String COMPILE_STUB_PREFIX = "compile__stub"; 1.86 + 1.87 +static final Keyword protocolKey = Keyword.intern(null, "protocol"); 1.88 +static final Keyword onKey = Keyword.intern(null, "on"); 1.89 + 1.90 +static final Symbol NS = Symbol.create("ns"); 1.91 +static final Symbol IN_NS = Symbol.create("in-ns"); 1.92 + 1.93 +//static final Symbol IMPORT = Symbol.create("import"); 1.94 +//static final Symbol USE = Symbol.create("use"); 1.95 + 1.96 +//static final Symbol IFN = Symbol.create("clojure.lang", "IFn"); 1.97 + 1.98 +static final public IPersistentMap specials = PersistentHashMap.create( 1.99 + DEF, new DefExpr.Parser(), 1.100 + LOOP, new LetExpr.Parser(), 1.101 + RECUR, new RecurExpr.Parser(), 1.102 + IF, new IfExpr.Parser(), 1.103 + CASE, new CaseExpr.Parser(), 1.104 + LET, new LetExpr.Parser(), 1.105 + LETFN, new LetFnExpr.Parser(), 1.106 + DO, new BodyExpr.Parser(), 1.107 + FN, null, 1.108 + QUOTE, new ConstantExpr.Parser(), 1.109 + THE_VAR, new TheVarExpr.Parser(), 1.110 + IMPORT, new ImportExpr.Parser(), 1.111 + DOT, new HostExpr.Parser(), 1.112 + ASSIGN, new AssignExpr.Parser(), 1.113 + DEFTYPE, new NewInstanceExpr.DeftypeParser(), 1.114 + REIFY, new NewInstanceExpr.ReifyParser(), 1.115 +// TRY_FINALLY, new TryFinallyExpr.Parser(), 1.116 +TRY, new TryExpr.Parser(), 1.117 +THROW, new ThrowExpr.Parser(), 1.118 +MONITOR_ENTER, new MonitorEnterExpr.Parser(), 1.119 +MONITOR_EXIT, new MonitorExitExpr.Parser(), 1.120 +// INSTANCE, new InstanceExpr.Parser(), 1.121 +// IDENTICAL, new IdenticalExpr.Parser(), 1.122 +//THISFN, null, 1.123 +CATCH, null, 1.124 +FINALLY, null, 1.125 +// CLASS, new ClassExpr.Parser(), 1.126 +NEW, new NewExpr.Parser(), 1.127 +// UNQUOTE, null, 1.128 +// UNQUOTE_SPLICING, null, 1.129 +// SYNTAX_QUOTE, null, 1.130 +_AMP_, null 1.131 +); 1.132 + 1.133 +private static final int MAX_POSITIONAL_ARITY = 20; 1.134 +private static final Type OBJECT_TYPE; 1.135 +private static final Type KEYWORD_TYPE = Type.getType(Keyword.class); 1.136 +private static final Type VAR_TYPE = Type.getType(Var.class); 1.137 +private static final Type SYMBOL_TYPE = Type.getType(Symbol.class); 1.138 +//private static final Type NUM_TYPE = Type.getType(Num.class); 1.139 +private static final Type IFN_TYPE = Type.getType(IFn.class); 1.140 +private static final Type AFUNCTION_TYPE = Type.getType(AFunction.class); 1.141 +private static final Type RT_TYPE = Type.getType(RT.class); 1.142 +final static Type CLASS_TYPE = Type.getType(Class.class); 1.143 +final static Type NS_TYPE = Type.getType(Namespace.class); 1.144 +final static Type UTIL_TYPE = Type.getType(Util.class); 1.145 +final static Type REFLECTOR_TYPE = Type.getType(Reflector.class); 1.146 +final static Type THROWABLE_TYPE = Type.getType(Throwable.class); 1.147 +final static Type BOOLEAN_OBJECT_TYPE = Type.getType(Boolean.class); 1.148 +final static Type IPERSISTENTMAP_TYPE = Type.getType(IPersistentMap.class); 1.149 +final static Type IOBJ_TYPE = Type.getType(IObj.class); 1.150 + 1.151 +private static final Type[][] ARG_TYPES; 1.152 +private static final Type[] EXCEPTION_TYPES = {Type.getType(Exception.class)}; 1.153 + 1.154 +static 1.155 + { 1.156 + OBJECT_TYPE = Type.getType(Object.class); 1.157 + ARG_TYPES = new Type[MAX_POSITIONAL_ARITY + 2][]; 1.158 + for(int i = 0; i <= MAX_POSITIONAL_ARITY; ++i) 1.159 + { 1.160 + Type[] a = new Type[i]; 1.161 + for(int j = 0; j < i; j++) 1.162 + a[j] = OBJECT_TYPE; 1.163 + ARG_TYPES[i] = a; 1.164 + } 1.165 + Type[] a = new Type[MAX_POSITIONAL_ARITY + 1]; 1.166 + for(int j = 0; j < MAX_POSITIONAL_ARITY; j++) 1.167 + a[j] = OBJECT_TYPE; 1.168 + a[MAX_POSITIONAL_ARITY] = Type.getType("[Ljava/lang/Object;"); 1.169 + ARG_TYPES[MAX_POSITIONAL_ARITY + 1] = a; 1.170 + 1.171 + 1.172 + } 1.173 + 1.174 + 1.175 +//symbol->localbinding 1.176 +static final public Var LOCAL_ENV = Var.create(null); 1.177 + 1.178 +//vector<localbinding> 1.179 +static final public Var LOOP_LOCALS = Var.create(); 1.180 + 1.181 +//Label 1.182 +static final public Var LOOP_LABEL = Var.create(); 1.183 + 1.184 +//vector<object> 1.185 +static final public Var CONSTANTS = Var.create(); 1.186 + 1.187 +//IdentityHashMap 1.188 +static final public Var CONSTANT_IDS = Var.create(); 1.189 + 1.190 +//vector<keyword> 1.191 +static final public Var KEYWORD_CALLSITES = Var.create(); 1.192 + 1.193 +//vector<var> 1.194 +static final public Var PROTOCOL_CALLSITES = Var.create(); 1.195 + 1.196 +//vector<var> 1.197 +static final public Var VAR_CALLSITES = Var.create(); 1.198 + 1.199 +//keyword->constid 1.200 +static final public Var KEYWORDS = Var.create(); 1.201 + 1.202 +//var->constid 1.203 +static final public Var VARS = Var.create(); 1.204 + 1.205 +//FnFrame 1.206 +static final public Var METHOD = Var.create(null); 1.207 + 1.208 +//null or not 1.209 +static final public Var IN_CATCH_FINALLY = Var.create(null); 1.210 + 1.211 +//DynamicClassLoader 1.212 +static final public Var LOADER = Var.create(); 1.213 + 1.214 +//String 1.215 +static final public Var SOURCE = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), 1.216 + Symbol.create("*source-path*"), "NO_SOURCE_FILE"); 1.217 + 1.218 +//String 1.219 +static final public Var SOURCE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), 1.220 + Symbol.create("*file*"), "NO_SOURCE_PATH"); 1.221 + 1.222 +//String 1.223 +static final public Var COMPILE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), 1.224 + Symbol.create("*compile-path*"), null); 1.225 +//boolean 1.226 +static final public Var COMPILE_FILES = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), 1.227 + Symbol.create("*compile-files*"), Boolean.FALSE); 1.228 + 1.229 +static final public Var INSTANCE = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), 1.230 + Symbol.create("instance?")); 1.231 + 1.232 +static final public Var ADD_ANNOTATIONS = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), 1.233 + Symbol.create("add-annotations")); 1.234 + 1.235 +//Integer 1.236 +static final public Var LINE = Var.create(0); 1.237 + 1.238 +//Integer 1.239 +static final public Var LINE_BEFORE = Var.create(0); 1.240 +static final public Var LINE_AFTER = Var.create(0); 1.241 + 1.242 +//Integer 1.243 +static final public Var NEXT_LOCAL_NUM = Var.create(0); 1.244 + 1.245 +//Integer 1.246 +static final public Var RET_LOCAL_NUM = Var.create(); 1.247 + 1.248 + 1.249 +static final public Var COMPILE_STUB_SYM = Var.create(null); 1.250 +static final public Var COMPILE_STUB_CLASS = Var.create(null); 1.251 + 1.252 + 1.253 +//PathNode chain 1.254 +static final public Var CLEAR_PATH = Var.create(null); 1.255 + 1.256 +//tail of PathNode chain 1.257 +static final public Var CLEAR_ROOT = Var.create(null); 1.258 + 1.259 +//LocalBinding -> Set<LocalBindingExpr> 1.260 +static final public Var CLEAR_SITES = Var.create(null); 1.261 + 1.262 + public enum C{ 1.263 + STATEMENT, //value ignored 1.264 + EXPRESSION, //value required 1.265 + RETURN, //tail position relative to enclosing recur frame 1.266 + EVAL 1.267 +} 1.268 + 1.269 +interface Expr{ 1.270 + Object eval() throws Exception; 1.271 + 1.272 + void emit(C context, ObjExpr objx, GeneratorAdapter gen); 1.273 + 1.274 + boolean hasJavaClass() throws Exception; 1.275 + 1.276 + Class getJavaClass() throws Exception; 1.277 +} 1.278 + 1.279 +public static abstract class UntypedExpr implements Expr{ 1.280 + 1.281 + public Class getJavaClass(){ 1.282 + throw new IllegalArgumentException("Has no Java class"); 1.283 + } 1.284 + 1.285 + public boolean hasJavaClass(){ 1.286 + return false; 1.287 + } 1.288 +} 1.289 + 1.290 +interface IParser{ 1.291 + Expr parse(C context, Object form) throws Exception; 1.292 +} 1.293 + 1.294 +static boolean isSpecial(Object sym){ 1.295 + return specials.containsKey(sym); 1.296 +} 1.297 + 1.298 +static Symbol resolveSymbol(Symbol sym){ 1.299 + //already qualified or classname? 1.300 + if(sym.name.indexOf('.') > 0) 1.301 + return sym; 1.302 + if(sym.ns != null) 1.303 + { 1.304 + Namespace ns = namespaceFor(sym); 1.305 + if(ns == null || ns.name.name == sym.ns) 1.306 + return sym; 1.307 + return Symbol.create(ns.name.name, sym.name); 1.308 + } 1.309 + Object o = currentNS().getMapping(sym); 1.310 + if(o == null) 1.311 + return Symbol.intern(currentNS().name.name, sym.name); 1.312 + else if(o instanceof Class) 1.313 + return Symbol.intern(null, ((Class) o).getName()); 1.314 + else if(o instanceof Var) 1.315 + { 1.316 + Var v = (Var) o; 1.317 + return Symbol.create(v.ns.name.name, v.sym.name); 1.318 + } 1.319 + return null; 1.320 + 1.321 +} 1.322 + 1.323 +static class DefExpr implements Expr{ 1.324 + public final Var var; 1.325 + public final Expr init; 1.326 + public final Expr meta; 1.327 + public final boolean initProvided; 1.328 + public final String source; 1.329 + public final int line; 1.330 + final static Method bindRootMethod = Method.getMethod("void bindRoot(Object)"); 1.331 + final static Method setTagMethod = Method.getMethod("void setTag(clojure.lang.Symbol)"); 1.332 + final static Method setMetaMethod = Method.getMethod("void setMeta(clojure.lang.IPersistentMap)"); 1.333 + final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String, String)"); 1.334 + 1.335 + public DefExpr(String source, int line, Var var, Expr init, Expr meta, boolean initProvided){ 1.336 + this.source = source; 1.337 + this.line = line; 1.338 + this.var = var; 1.339 + this.init = init; 1.340 + this.meta = meta; 1.341 + this.initProvided = initProvided; 1.342 + } 1.343 + 1.344 + private boolean includesExplicitMetadata(MapExpr expr) { 1.345 + for(int i=0; i < expr.keyvals.count(); i += 2) 1.346 + { 1.347 + Keyword k = ((KeywordExpr) expr.keyvals.nth(i)).k; 1.348 + if ((k != RT.FILE_KEY) && 1.349 + (k != RT.DECLARED_KEY) && 1.350 + (k != RT.LINE_KEY)) 1.351 + return true; 1.352 + } 1.353 + return false; 1.354 + } 1.355 + 1.356 + public Object eval() throws Exception{ 1.357 + try 1.358 + { 1.359 + if(initProvided) 1.360 + { 1.361 +// if(init instanceof FnExpr && ((FnExpr) init).closes.count()==0) 1.362 +// var.bindRoot(new FnLoaderThunk((FnExpr) init,var)); 1.363 +// else 1.364 + var.bindRoot(init.eval()); 1.365 + } 1.366 + if(meta != null) 1.367 + { 1.368 + IPersistentMap metaMap = (IPersistentMap) meta.eval(); 1.369 + if (initProvided || includesExplicitMetadata((MapExpr) meta)) 1.370 + var.setMeta((IPersistentMap) meta.eval()); 1.371 + } 1.372 + return var; 1.373 + } 1.374 + catch(Throwable e) 1.375 + { 1.376 + if(!(e instanceof CompilerException)) 1.377 + throw new CompilerException(source, line, e); 1.378 + else 1.379 + throw (CompilerException) e; 1.380 + } 1.381 + } 1.382 + 1.383 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.384 + objx.emitVar(gen, var); 1.385 + if(meta != null) 1.386 + { 1.387 + if (initProvided || includesExplicitMetadata((MapExpr) meta)) 1.388 + { 1.389 + gen.dup(); 1.390 + meta.emit(C.EXPRESSION, objx, gen); 1.391 + gen.checkCast(IPERSISTENTMAP_TYPE); 1.392 + gen.invokeVirtual(VAR_TYPE, setMetaMethod); 1.393 + } 1.394 + } 1.395 + if(initProvided) 1.396 + { 1.397 + gen.dup(); 1.398 + init.emit(C.EXPRESSION, objx, gen); 1.399 + gen.invokeVirtual(VAR_TYPE, bindRootMethod); 1.400 + } 1.401 + 1.402 + if(context == C.STATEMENT) 1.403 + gen.pop(); 1.404 + } 1.405 + 1.406 + public boolean hasJavaClass(){ 1.407 + return true; 1.408 + } 1.409 + 1.410 + public Class getJavaClass(){ 1.411 + return Var.class; 1.412 + } 1.413 + 1.414 + static class Parser implements IParser{ 1.415 + public Expr parse(C context, Object form) throws Exception{ 1.416 + //(def x) or (def x initexpr) 1.417 + if(RT.count(form) > 3) 1.418 + throw new Exception("Too many arguments to def"); 1.419 + else if(RT.count(form) < 2) 1.420 + throw new Exception("Too few arguments to def"); 1.421 + else if(!(RT.second(form) instanceof Symbol)) 1.422 + throw new Exception("First argument to def must be a Symbol"); 1.423 + Symbol sym = (Symbol) RT.second(form); 1.424 + Var v = lookupVar(sym, true); 1.425 + if(v == null) 1.426 + throw new Exception("Can't refer to qualified var that doesn't exist"); 1.427 + if(!v.ns.equals(currentNS())) 1.428 + { 1.429 + if(sym.ns == null) 1.430 + v = currentNS().intern(sym); 1.431 +// throw new Exception("Name conflict, can't def " + sym + " because namespace: " + currentNS().name + 1.432 +// " refers to:" + v); 1.433 + else 1.434 + throw new Exception("Can't create defs outside of current ns"); 1.435 + } 1.436 + IPersistentMap mm = sym.meta(); 1.437 + Object source_path = SOURCE_PATH.get(); 1.438 + source_path = source_path == null ? "NO_SOURCE_FILE" : source_path; 1.439 + mm = (IPersistentMap) RT.assoc(mm, RT.LINE_KEY, LINE.get()).assoc(RT.FILE_KEY, source_path); 1.440 + Expr meta = analyze(context == C.EVAL ? context : C.EXPRESSION, mm); 1.441 + return new DefExpr((String) SOURCE.deref(), (Integer) LINE.deref(), 1.442 + v, analyze(context == C.EVAL ? context : C.EXPRESSION, RT.third(form), v.sym.name), 1.443 + meta, RT.count(form) == 3); 1.444 + } 1.445 + } 1.446 +} 1.447 + 1.448 +public static class AssignExpr implements Expr{ 1.449 + public final AssignableExpr target; 1.450 + public final Expr val; 1.451 + 1.452 + public AssignExpr(AssignableExpr target, Expr val){ 1.453 + this.target = target; 1.454 + this.val = val; 1.455 + } 1.456 + 1.457 + public Object eval() throws Exception{ 1.458 + return target.evalAssign(val); 1.459 + } 1.460 + 1.461 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.462 + target.emitAssign(context, objx, gen, val); 1.463 + } 1.464 + 1.465 + public boolean hasJavaClass() throws Exception{ 1.466 + return val.hasJavaClass(); 1.467 + } 1.468 + 1.469 + public Class getJavaClass() throws Exception{ 1.470 + return val.getJavaClass(); 1.471 + } 1.472 + 1.473 + static class Parser implements IParser{ 1.474 + public Expr parse(C context, Object frm) throws Exception{ 1.475 + ISeq form = (ISeq) frm; 1.476 + if(RT.length(form) != 3) 1.477 + throw new IllegalArgumentException("Malformed assignment, expecting (set! target val)"); 1.478 + Expr target = analyze(C.EXPRESSION, RT.second(form)); 1.479 + if(!(target instanceof AssignableExpr)) 1.480 + throw new IllegalArgumentException("Invalid assignment target"); 1.481 + return new AssignExpr((AssignableExpr) target, analyze(C.EXPRESSION, RT.third(form))); 1.482 + } 1.483 + } 1.484 +} 1.485 + 1.486 +public static class VarExpr implements Expr, AssignableExpr{ 1.487 + public final Var var; 1.488 + public final Object tag; 1.489 + final static Method getMethod = Method.getMethod("Object get()"); 1.490 + final static Method setMethod = Method.getMethod("Object set(Object)"); 1.491 + 1.492 + public VarExpr(Var var, Symbol tag){ 1.493 + this.var = var; 1.494 + this.tag = tag != null ? tag : var.getTag(); 1.495 + } 1.496 + 1.497 + public Object eval() throws Exception{ 1.498 + return var.deref(); 1.499 + } 1.500 + 1.501 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.502 + objx.emitVar(gen, var); 1.503 + gen.invokeVirtual(VAR_TYPE, getMethod); 1.504 + if(context == C.STATEMENT) 1.505 + { 1.506 + gen.pop(); 1.507 + } 1.508 + } 1.509 + 1.510 + public boolean hasJavaClass(){ 1.511 + return tag != null; 1.512 + } 1.513 + 1.514 + public Class getJavaClass() throws Exception{ 1.515 + return HostExpr.tagToClass(tag); 1.516 + } 1.517 + 1.518 + public Object evalAssign(Expr val) throws Exception{ 1.519 + return var.set(val.eval()); 1.520 + } 1.521 + 1.522 + public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, 1.523 + Expr val){ 1.524 + objx.emitVar(gen, var); 1.525 + val.emit(C.EXPRESSION, objx, gen); 1.526 + gen.invokeVirtual(VAR_TYPE, setMethod); 1.527 + if(context == C.STATEMENT) 1.528 + gen.pop(); 1.529 + } 1.530 +} 1.531 + 1.532 +public static class TheVarExpr implements Expr{ 1.533 + public final Var var; 1.534 + 1.535 + public TheVarExpr(Var var){ 1.536 + this.var = var; 1.537 + } 1.538 + 1.539 + public Object eval() throws Exception{ 1.540 + return var; 1.541 + } 1.542 + 1.543 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.544 + objx.emitVar(gen, var); 1.545 + if(context == C.STATEMENT) 1.546 + gen.pop(); 1.547 + } 1.548 + 1.549 + public boolean hasJavaClass(){ 1.550 + return true; 1.551 + } 1.552 + 1.553 + public Class getJavaClass() throws ClassNotFoundException{ 1.554 + return Var.class; 1.555 + } 1.556 + 1.557 + static class Parser implements IParser{ 1.558 + public Expr parse(C context, Object form) throws Exception{ 1.559 + Symbol sym = (Symbol) RT.second(form); 1.560 + Var v = lookupVar(sym, false); 1.561 + if(v != null) 1.562 + return new TheVarExpr(v); 1.563 + throw new Exception("Unable to resolve var: " + sym + " in this context"); 1.564 + } 1.565 + } 1.566 +} 1.567 + 1.568 +public static class KeywordExpr implements Expr{ 1.569 + public final Keyword k; 1.570 + 1.571 + public KeywordExpr(Keyword k){ 1.572 + this.k = k; 1.573 + } 1.574 + 1.575 + public Object eval() throws Exception{ 1.576 + return k; 1.577 + } 1.578 + 1.579 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.580 + objx.emitKeyword(gen, k); 1.581 + if(context == C.STATEMENT) 1.582 + gen.pop(); 1.583 + 1.584 + } 1.585 + 1.586 + public boolean hasJavaClass(){ 1.587 + return true; 1.588 + } 1.589 + 1.590 + public Class getJavaClass() throws ClassNotFoundException{ 1.591 + return Keyword.class; 1.592 + } 1.593 +} 1.594 + 1.595 +public static class ImportExpr implements Expr{ 1.596 + public final String c; 1.597 + final static Method forNameMethod = Method.getMethod("Class forName(String)"); 1.598 + final static Method importClassMethod = Method.getMethod("Class importClass(Class)"); 1.599 + final static Method derefMethod = Method.getMethod("Object deref()"); 1.600 + 1.601 + public ImportExpr(String c){ 1.602 + this.c = c; 1.603 + } 1.604 + 1.605 + public Object eval() throws Exception{ 1.606 + Namespace ns = (Namespace) RT.CURRENT_NS.deref(); 1.607 + ns.importClass(RT.classForName(c)); 1.608 + return null; 1.609 + } 1.610 + 1.611 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.612 + gen.getStatic(RT_TYPE,"CURRENT_NS",VAR_TYPE); 1.613 + gen.invokeVirtual(VAR_TYPE, derefMethod); 1.614 + gen.checkCast(NS_TYPE); 1.615 + gen.push(c); 1.616 + gen.invokeStatic(CLASS_TYPE, forNameMethod); 1.617 + gen.invokeVirtual(NS_TYPE, importClassMethod); 1.618 + if(context == C.STATEMENT) 1.619 + gen.pop(); 1.620 + } 1.621 + 1.622 + public boolean hasJavaClass(){ 1.623 + return false; 1.624 + } 1.625 + 1.626 + public Class getJavaClass() throws ClassNotFoundException{ 1.627 + throw new IllegalArgumentException("ImportExpr has no Java class"); 1.628 + } 1.629 + 1.630 + static class Parser implements IParser{ 1.631 + public Expr parse(C context, Object form) throws Exception{ 1.632 + return new ImportExpr((String) RT.second(form)); 1.633 + } 1.634 + } 1.635 +} 1.636 + 1.637 +public static abstract class LiteralExpr implements Expr{ 1.638 + abstract Object val(); 1.639 + 1.640 + public Object eval(){ 1.641 + return val(); 1.642 + } 1.643 +} 1.644 + 1.645 +static interface AssignableExpr{ 1.646 + Object evalAssign(Expr val) throws Exception; 1.647 + 1.648 + void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, Expr val); 1.649 +} 1.650 + 1.651 +static public interface MaybePrimitiveExpr extends Expr{ 1.652 + public boolean canEmitPrimitive(); 1.653 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen); 1.654 +} 1.655 + 1.656 +static public abstract class HostExpr implements Expr, MaybePrimitiveExpr{ 1.657 + final static Type BOOLEAN_TYPE = Type.getType(Boolean.class); 1.658 + final static Type CHAR_TYPE = Type.getType(Character.class); 1.659 + final static Type INTEGER_TYPE = Type.getType(Integer.class); 1.660 + final static Type LONG_TYPE = Type.getType(Long.class); 1.661 + final static Type FLOAT_TYPE = Type.getType(Float.class); 1.662 + final static Type DOUBLE_TYPE = Type.getType(Double.class); 1.663 + final static Type SHORT_TYPE = Type.getType(Short.class); 1.664 + final static Type BYTE_TYPE = Type.getType(Byte.class); 1.665 + final static Type NUMBER_TYPE = Type.getType(Number.class); 1.666 + 1.667 + final static Method charValueMethod = Method.getMethod("char charValue()"); 1.668 + final static Method booleanValueMethod = Method.getMethod("boolean booleanValue()"); 1.669 + 1.670 + final static Method charValueOfMethod = Method.getMethod("Character valueOf(char)"); 1.671 + final static Method intValueOfMethod = Method.getMethod("Integer valueOf(int)"); 1.672 + final static Method longValueOfMethod = Method.getMethod("Long valueOf(long)"); 1.673 + final static Method floatValueOfMethod = Method.getMethod("Float valueOf(float)"); 1.674 + final static Method doubleValueOfMethod = Method.getMethod("Double valueOf(double)"); 1.675 + final static Method shortValueOfMethod = Method.getMethod("Short valueOf(short)"); 1.676 + final static Method byteValueOfMethod = Method.getMethod("Byte valueOf(byte)"); 1.677 + 1.678 + final static Method intValueMethod = Method.getMethod("int intValue()"); 1.679 + final static Method longValueMethod = Method.getMethod("long longValue()"); 1.680 + final static Method floatValueMethod = Method.getMethod("float floatValue()"); 1.681 + final static Method doubleValueMethod = Method.getMethod("double doubleValue()"); 1.682 + final static Method byteValueMethod = Method.getMethod("byte byteValue()"); 1.683 + final static Method shortValueMethod = Method.getMethod("short shortValue()"); 1.684 + 1.685 + final static Method fromIntMethod = Method.getMethod("clojure.lang.Num from(int)"); 1.686 + final static Method fromLongMethod = Method.getMethod("clojure.lang.Num from(long)"); 1.687 + final static Method fromDoubleMethod = Method.getMethod("clojure.lang.Num from(double)"); 1.688 + 1.689 + 1.690 + //* 1.691 + public static void emitBoxReturn(ObjExpr objx, GeneratorAdapter gen, Class returnType){ 1.692 + if(returnType.isPrimitive()) 1.693 + { 1.694 + if(returnType == boolean.class) 1.695 + { 1.696 + Label falseLabel = gen.newLabel(); 1.697 + Label endLabel = gen.newLabel(); 1.698 + gen.ifZCmp(GeneratorAdapter.EQ, falseLabel); 1.699 + gen.getStatic(BOOLEAN_OBJECT_TYPE, "TRUE", BOOLEAN_OBJECT_TYPE); 1.700 + gen.goTo(endLabel); 1.701 + gen.mark(falseLabel); 1.702 + gen.getStatic(BOOLEAN_OBJECT_TYPE, "FALSE", BOOLEAN_OBJECT_TYPE); 1.703 +// NIL_EXPR.emit(C.EXPRESSION, fn, gen); 1.704 + gen.mark(endLabel); 1.705 + } 1.706 + else if(returnType == void.class) 1.707 + { 1.708 + NIL_EXPR.emit(C.EXPRESSION, objx, gen); 1.709 + } 1.710 + else if(returnType == char.class) 1.711 + { 1.712 + gen.invokeStatic(CHAR_TYPE, charValueOfMethod); 1.713 + } 1.714 + else 1.715 + { 1.716 + if(returnType == int.class) 1.717 + //gen.invokeStatic(NUM_TYPE, fromIntMethod); 1.718 + gen.invokeStatic(INTEGER_TYPE, intValueOfMethod); 1.719 + else if(returnType == float.class) 1.720 + { 1.721 + //gen.visitInsn(F2D); 1.722 + gen.invokeStatic(FLOAT_TYPE, floatValueOfMethod); 1.723 + //m = floatValueOfMethod; 1.724 + } 1.725 + else if(returnType == double.class) 1.726 + gen.invokeStatic(DOUBLE_TYPE, doubleValueOfMethod); 1.727 + else if(returnType == long.class) 1.728 + gen.invokeStatic(LONG_TYPE, longValueOfMethod); 1.729 + else if(returnType == byte.class) 1.730 + gen.invokeStatic(BYTE_TYPE, byteValueOfMethod); 1.731 + else if(returnType == short.class) 1.732 + gen.invokeStatic(SHORT_TYPE, shortValueOfMethod); 1.733 + } 1.734 + } 1.735 + } 1.736 + 1.737 + //*/ 1.738 + public static void emitUnboxArg(ObjExpr objx, GeneratorAdapter gen, Class paramType){ 1.739 + if(paramType.isPrimitive()) 1.740 + { 1.741 + if(paramType == boolean.class) 1.742 + { 1.743 + gen.checkCast(BOOLEAN_TYPE); 1.744 + gen.invokeVirtual(BOOLEAN_TYPE, booleanValueMethod); 1.745 +// Label falseLabel = gen.newLabel(); 1.746 +// Label endLabel = gen.newLabel(); 1.747 +// gen.ifNull(falseLabel); 1.748 +// gen.push(1); 1.749 +// gen.goTo(endLabel); 1.750 +// gen.mark(falseLabel); 1.751 +// gen.push(0); 1.752 +// gen.mark(endLabel); 1.753 + } 1.754 + else if(paramType == char.class) 1.755 + { 1.756 + gen.checkCast(CHAR_TYPE); 1.757 + gen.invokeVirtual(CHAR_TYPE, charValueMethod); 1.758 + } 1.759 + else 1.760 + { 1.761 + Method m = intValueMethod; 1.762 + gen.checkCast(NUMBER_TYPE); 1.763 + if(paramType == int.class) 1.764 + m = intValueMethod; 1.765 + else if(paramType == float.class) 1.766 + m = floatValueMethod; 1.767 + else if(paramType == double.class) 1.768 + m = doubleValueMethod; 1.769 + else if(paramType == long.class) 1.770 + m = longValueMethod; 1.771 + else if(paramType == byte.class) 1.772 + m = byteValueMethod; 1.773 + else if(paramType == short.class) 1.774 + m = shortValueMethod; 1.775 + gen.invokeVirtual(NUMBER_TYPE, m); 1.776 + } 1.777 + } 1.778 + else 1.779 + { 1.780 + gen.checkCast(Type.getType(paramType)); 1.781 + } 1.782 + } 1.783 + 1.784 + static class Parser implements IParser{ 1.785 + public Expr parse(C context, Object frm) throws Exception{ 1.786 + ISeq form = (ISeq) frm; 1.787 + //(. x fieldname-sym) or 1.788 + //(. x 0-ary-method) 1.789 + // (. x methodname-sym args+) 1.790 + // (. x (methodname-sym args?)) 1.791 + if(RT.length(form) < 3) 1.792 + throw new IllegalArgumentException("Malformed member expression, expecting (. target member ...)"); 1.793 + //determine static or instance 1.794 + //static target must be symbol, either fully.qualified.Classname or Classname that has been imported 1.795 + int line = (Integer) LINE.deref(); 1.796 + String source = (String) SOURCE.deref(); 1.797 + Class c = maybeClass(RT.second(form), false); 1.798 + //at this point c will be non-null if static 1.799 + Expr instance = null; 1.800 + if(c == null) 1.801 + instance = analyze(context == C.EVAL ? context : C.EXPRESSION, RT.second(form)); 1.802 + boolean maybeField = RT.length(form) == 3 && 1.803 + (RT.third(form) instanceof Symbol 1.804 + || RT.third(form) instanceof Keyword); 1.805 + if(maybeField && !(RT.third(form) instanceof Keyword)) 1.806 + { 1.807 + Symbol sym = (Symbol) RT.third(form); 1.808 + if(c != null) 1.809 + maybeField = Reflector.getMethods(c, 0, munge(sym.name), true).size() == 0; 1.810 + else if(instance != null && instance.hasJavaClass() && instance.getJavaClass() != null) 1.811 + maybeField = Reflector.getMethods(instance.getJavaClass(), 0, munge(sym.name), false).size() == 0; 1.812 + } 1.813 + if(maybeField) //field 1.814 + { 1.815 + Symbol sym = (RT.third(form) instanceof Keyword)? 1.816 + ((Keyword)RT.third(form)).sym 1.817 + :(Symbol) RT.third(form); 1.818 + Symbol tag = tagOf(form); 1.819 + if(c != null) { 1.820 + return new StaticFieldExpr(line, c, munge(sym.name), tag); 1.821 + } else 1.822 + return new InstanceFieldExpr(line, instance, munge(sym.name), tag); 1.823 + } 1.824 + else 1.825 + { 1.826 + ISeq call = (ISeq) ((RT.third(form) instanceof ISeq) ? RT.third(form) : RT.next(RT.next(form))); 1.827 + if(!(RT.first(call) instanceof Symbol)) 1.828 + throw new IllegalArgumentException("Malformed member expression"); 1.829 + Symbol sym = (Symbol) RT.first(call); 1.830 + Symbol tag = tagOf(form); 1.831 + PersistentVector args = PersistentVector.EMPTY; 1.832 + for(ISeq s = RT.next(call); s != null; s = s.next()) 1.833 + args = args.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, s.first())); 1.834 + if(c != null) 1.835 + return new StaticMethodExpr(source, line, tag, c, munge(sym.name), args); 1.836 + else 1.837 + return new InstanceMethodExpr(source, line, tag, instance, munge(sym.name), args); 1.838 + } 1.839 + } 1.840 + } 1.841 + 1.842 + private static Class maybeClass(Object form, boolean stringOk) throws Exception{ 1.843 + if(form instanceof Class) 1.844 + return (Class) form; 1.845 + Class c = null; 1.846 + if(form instanceof Symbol) 1.847 + { 1.848 + Symbol sym = (Symbol) form; 1.849 + if(sym.ns == null) //if ns-qualified can't be classname 1.850 + { 1.851 + if(Util.equals(sym,COMPILE_STUB_SYM.get())) 1.852 + return (Class) COMPILE_STUB_CLASS.get(); 1.853 + if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') 1.854 + c = RT.classForName(sym.name); 1.855 + else 1.856 + { 1.857 + Object o = currentNS().getMapping(sym); 1.858 + if(o instanceof Class) 1.859 + c = (Class) o; 1.860 + } 1.861 + } 1.862 + } 1.863 + else if(stringOk && form instanceof String) 1.864 + c = RT.classForName((String) form); 1.865 + return c; 1.866 + } 1.867 + 1.868 + /* 1.869 + private static String maybeClassName(Object form, boolean stringOk){ 1.870 + String className = null; 1.871 + if(form instanceof Symbol) 1.872 + { 1.873 + Symbol sym = (Symbol) form; 1.874 + if(sym.ns == null) //if ns-qualified can't be classname 1.875 + { 1.876 + if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') 1.877 + className = sym.name; 1.878 + else 1.879 + { 1.880 + IPersistentMap imports = (IPersistentMap) ((Var) RT.NS_IMPORTS.get()).get(); 1.881 + className = (String) imports.valAt(sym); 1.882 + } 1.883 + } 1.884 + } 1.885 + else if(stringOk && form instanceof String) 1.886 + className = (String) form; 1.887 + return className; 1.888 + } 1.889 + */ 1.890 + static Class tagToClass(Object tag) throws Exception{ 1.891 + Class c = maybeClass(tag, true); 1.892 + if(tag instanceof Symbol) 1.893 + { 1.894 + Symbol sym = (Symbol) tag; 1.895 + if(sym.ns == null) //if ns-qualified can't be classname 1.896 + { 1.897 + if(sym.name.equals("objects")) 1.898 + c = Object[].class; 1.899 + else if(sym.name.equals("ints")) 1.900 + c = int[].class; 1.901 + else if(sym.name.equals("longs")) 1.902 + c = long[].class; 1.903 + else if(sym.name.equals("floats")) 1.904 + c = float[].class; 1.905 + else if(sym.name.equals("doubles")) 1.906 + c = double[].class; 1.907 + else if(sym.name.equals("chars")) 1.908 + c = char[].class; 1.909 + else if(sym.name.equals("shorts")) 1.910 + c = short[].class; 1.911 + else if(sym.name.equals("bytes")) 1.912 + c = byte[].class; 1.913 + else if(sym.name.equals("booleans")) 1.914 + c = boolean[].class; 1.915 + } 1.916 + } 1.917 + if(c != null) 1.918 + return c; 1.919 + throw new IllegalArgumentException("Unable to resolve classname: " + tag); 1.920 + } 1.921 +} 1.922 + 1.923 +static abstract class FieldExpr extends HostExpr{ 1.924 +} 1.925 + 1.926 +static class InstanceFieldExpr extends FieldExpr implements AssignableExpr{ 1.927 + public final Expr target; 1.928 + public final Class targetClass; 1.929 + public final java.lang.reflect.Field field; 1.930 + public final String fieldName; 1.931 + public final int line; 1.932 + public final Symbol tag; 1.933 + final static Method invokeNoArgInstanceMember = Method.getMethod("Object invokeNoArgInstanceMember(Object,String)"); 1.934 + final static Method setInstanceFieldMethod = Method.getMethod("Object setInstanceField(Object,String,Object)"); 1.935 + 1.936 + 1.937 + public InstanceFieldExpr(int line, Expr target, String fieldName, Symbol tag) throws Exception{ 1.938 + this.target = target; 1.939 + this.targetClass = target.hasJavaClass() ? target.getJavaClass() : null; 1.940 + this.field = targetClass != null ? Reflector.getField(targetClass, fieldName, false) : null; 1.941 + this.fieldName = fieldName; 1.942 + this.line = line; 1.943 + this.tag = tag; 1.944 + if(field == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) 1.945 + { 1.946 + RT.errPrintWriter() 1.947 + .format("Reflection warning, %s:%d - reference to field %s can't be resolved.\n", 1.948 + SOURCE_PATH.deref(), line, fieldName); 1.949 + } 1.950 + } 1.951 + 1.952 + public Object eval() throws Exception{ 1.953 + return Reflector.invokeNoArgInstanceMember(target.eval(), fieldName); 1.954 + } 1.955 + 1.956 + public boolean canEmitPrimitive(){ 1.957 + return targetClass != null && field != null && 1.958 + Util.isPrimitive(field.getType()); 1.959 + } 1.960 + 1.961 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.962 + gen.visitLineNumber(line, gen.mark()); 1.963 + if(targetClass != null && field != null) 1.964 + { 1.965 + target.emit(C.EXPRESSION, objx, gen); 1.966 + gen.checkCast(getType(targetClass)); 1.967 + gen.getField(getType(targetClass), fieldName, Type.getType(field.getType())); 1.968 + } 1.969 + else 1.970 + throw new UnsupportedOperationException("Unboxed emit of unknown member"); 1.971 + } 1.972 + 1.973 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.974 + gen.visitLineNumber(line, gen.mark()); 1.975 + if(targetClass != null && field != null) 1.976 + { 1.977 + target.emit(C.EXPRESSION, objx, gen); 1.978 + gen.checkCast(getType(targetClass)); 1.979 + gen.getField(getType(targetClass), fieldName, Type.getType(field.getType())); 1.980 + //if(context != C.STATEMENT) 1.981 + HostExpr.emitBoxReturn(objx, gen, field.getType()); 1.982 + if(context == C.STATEMENT) 1.983 + { 1.984 + gen.pop(); 1.985 + } 1.986 + } 1.987 + else 1.988 + { 1.989 + target.emit(C.EXPRESSION, objx, gen); 1.990 + gen.push(fieldName); 1.991 + gen.invokeStatic(REFLECTOR_TYPE, invokeNoArgInstanceMember); 1.992 + if(context == C.STATEMENT) 1.993 + gen.pop(); 1.994 + } 1.995 + } 1.996 + 1.997 + public boolean hasJavaClass() throws Exception{ 1.998 + return field != null || tag != null; 1.999 + } 1.1000 + 1.1001 + public Class getJavaClass() throws Exception{ 1.1002 + return tag != null ? HostExpr.tagToClass(tag) : field.getType(); 1.1003 + } 1.1004 + 1.1005 + public Object evalAssign(Expr val) throws Exception{ 1.1006 + return Reflector.setInstanceField(target.eval(), fieldName, val.eval()); 1.1007 + } 1.1008 + 1.1009 + public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, 1.1010 + Expr val){ 1.1011 + gen.visitLineNumber(line, gen.mark()); 1.1012 + if(targetClass != null && field != null) 1.1013 + { 1.1014 + target.emit(C.EXPRESSION, objx, gen); 1.1015 + gen.checkCast(Type.getType(targetClass)); 1.1016 + val.emit(C.EXPRESSION, objx, gen); 1.1017 + gen.dupX1(); 1.1018 + HostExpr.emitUnboxArg(objx, gen, field.getType()); 1.1019 + gen.putField(Type.getType(targetClass), fieldName, Type.getType(field.getType())); 1.1020 + } 1.1021 + else 1.1022 + { 1.1023 + target.emit(C.EXPRESSION, objx, gen); 1.1024 + gen.push(fieldName); 1.1025 + val.emit(C.EXPRESSION, objx, gen); 1.1026 + gen.invokeStatic(REFLECTOR_TYPE, setInstanceFieldMethod); 1.1027 + } 1.1028 + if(context == C.STATEMENT) 1.1029 + gen.pop(); 1.1030 + } 1.1031 +} 1.1032 + 1.1033 +static class StaticFieldExpr extends FieldExpr implements AssignableExpr{ 1.1034 + //final String className; 1.1035 + public final String fieldName; 1.1036 + public final Class c; 1.1037 + public final java.lang.reflect.Field field; 1.1038 + public final Symbol tag; 1.1039 +// final static Method getStaticFieldMethod = Method.getMethod("Object getStaticField(String,String)"); 1.1040 +// final static Method setStaticFieldMethod = Method.getMethod("Object setStaticField(String,String,Object)"); 1.1041 + final int line; 1.1042 + 1.1043 + public StaticFieldExpr(int line, Class c, String fieldName, Symbol tag) throws Exception{ 1.1044 + //this.className = className; 1.1045 + this.fieldName = fieldName; 1.1046 + this.line = line; 1.1047 + //c = Class.forName(className); 1.1048 + this.c = c; 1.1049 + field = c.getField(fieldName); 1.1050 + this.tag = tag; 1.1051 + } 1.1052 + 1.1053 + public Object eval() throws Exception{ 1.1054 + return Reflector.getStaticField(c, fieldName); 1.1055 + } 1.1056 + 1.1057 + public boolean canEmitPrimitive(){ 1.1058 + return Util.isPrimitive(field.getType()); 1.1059 + } 1.1060 + 1.1061 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1062 + gen.visitLineNumber(line, gen.mark()); 1.1063 + gen.getStatic(Type.getType(c), fieldName, Type.getType(field.getType())); 1.1064 + } 1.1065 + 1.1066 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1067 + gen.visitLineNumber(line, gen.mark()); 1.1068 + 1.1069 + gen.getStatic(Type.getType(c), fieldName, Type.getType(field.getType())); 1.1070 + //if(context != C.STATEMENT) 1.1071 + HostExpr.emitBoxReturn(objx, gen, field.getType()); 1.1072 + if(context == C.STATEMENT) 1.1073 + { 1.1074 + gen.pop(); 1.1075 + } 1.1076 +// gen.push(className); 1.1077 +// gen.push(fieldName); 1.1078 +// gen.invokeStatic(REFLECTOR_TYPE, getStaticFieldMethod); 1.1079 + } 1.1080 + 1.1081 + public boolean hasJavaClass(){ 1.1082 + return true; 1.1083 + } 1.1084 + 1.1085 + public Class getJavaClass() throws Exception{ 1.1086 + //Class c = Class.forName(className); 1.1087 + //java.lang.reflect.Field field = c.getField(fieldName); 1.1088 + return tag != null ? HostExpr.tagToClass(tag) : field.getType(); 1.1089 + } 1.1090 + 1.1091 + public Object evalAssign(Expr val) throws Exception{ 1.1092 + return Reflector.setStaticField(c, fieldName, val.eval()); 1.1093 + } 1.1094 + 1.1095 + public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, 1.1096 + Expr val){ 1.1097 + gen.visitLineNumber(line, gen.mark()); 1.1098 + val.emit(C.EXPRESSION, objx, gen); 1.1099 + gen.dup(); 1.1100 + HostExpr.emitUnboxArg(objx, gen, field.getType()); 1.1101 + gen.putStatic(Type.getType(c), fieldName, Type.getType(field.getType())); 1.1102 + if(context == C.STATEMENT) 1.1103 + gen.pop(); 1.1104 + } 1.1105 + 1.1106 + 1.1107 +} 1.1108 + 1.1109 +static Class maybePrimitiveType(Expr e){ 1.1110 + try 1.1111 + { 1.1112 + if(e instanceof MaybePrimitiveExpr && e.hasJavaClass() && ((MaybePrimitiveExpr)e).canEmitPrimitive()) 1.1113 + { 1.1114 + Class c = e.getJavaClass(); 1.1115 + if(Util.isPrimitive(c)) 1.1116 + return c; 1.1117 + } 1.1118 + } 1.1119 + catch(Exception ex) 1.1120 + { 1.1121 + throw new RuntimeException(ex); 1.1122 + } 1.1123 + return null; 1.1124 +} 1.1125 + 1.1126 +static abstract class MethodExpr extends HostExpr{ 1.1127 + static void emitArgsAsArray(IPersistentVector args, ObjExpr objx, GeneratorAdapter gen){ 1.1128 + gen.push(args.count()); 1.1129 + gen.newArray(OBJECT_TYPE); 1.1130 + for(int i = 0; i < args.count(); i++) 1.1131 + { 1.1132 + gen.dup(); 1.1133 + gen.push(i); 1.1134 + ((Expr) args.nth(i)).emit(C.EXPRESSION, objx, gen); 1.1135 + gen.arrayStore(OBJECT_TYPE); 1.1136 + } 1.1137 + } 1.1138 + 1.1139 + public static void emitTypedArgs(ObjExpr objx, GeneratorAdapter gen, Class[] parameterTypes, IPersistentVector args){ 1.1140 + for(int i = 0; i < parameterTypes.length; i++) 1.1141 + { 1.1142 + Expr e = (Expr) args.nth(i); 1.1143 + try 1.1144 + { 1.1145 + if(maybePrimitiveType(e) == parameterTypes[i]) 1.1146 + { 1.1147 + ((MaybePrimitiveExpr) e).emitUnboxed(C.EXPRESSION, objx, gen); 1.1148 + } 1.1149 + else 1.1150 + { 1.1151 + e.emit(C.EXPRESSION, objx, gen); 1.1152 + HostExpr.emitUnboxArg(objx, gen, parameterTypes[i]); 1.1153 + } 1.1154 + } 1.1155 + catch(Exception e1) 1.1156 + { 1.1157 + e1.printStackTrace(RT.errPrintWriter()); 1.1158 + } 1.1159 + 1.1160 + } 1.1161 + } 1.1162 +} 1.1163 + 1.1164 +static class InstanceMethodExpr extends MethodExpr{ 1.1165 + public final Expr target; 1.1166 + public final String methodName; 1.1167 + public final IPersistentVector args; 1.1168 + public final String source; 1.1169 + public final int line; 1.1170 + public final Symbol tag; 1.1171 + public final java.lang.reflect.Method method; 1.1172 + 1.1173 + final static Method invokeInstanceMethodMethod = 1.1174 + Method.getMethod("Object invokeInstanceMethod(Object,String,Object[])"); 1.1175 + 1.1176 + 1.1177 + public InstanceMethodExpr(String source, int line, Symbol tag, Expr target, String methodName, IPersistentVector args) 1.1178 + throws Exception{ 1.1179 + this.source = source; 1.1180 + this.line = line; 1.1181 + this.args = args; 1.1182 + this.methodName = methodName; 1.1183 + this.target = target; 1.1184 + this.tag = tag; 1.1185 + if(target.hasJavaClass() && target.getJavaClass() != null) 1.1186 + { 1.1187 + List methods = Reflector.getMethods(target.getJavaClass(), args.count(), methodName, false); 1.1188 + if(methods.isEmpty()) 1.1189 + method = null; 1.1190 + //throw new IllegalArgumentException("No matching method found"); 1.1191 + else 1.1192 + { 1.1193 + int methodidx = 0; 1.1194 + if(methods.size() > 1) 1.1195 + { 1.1196 + ArrayList<Class[]> params = new ArrayList(); 1.1197 + ArrayList<Class> rets = new ArrayList(); 1.1198 + for(int i = 0; i < methods.size(); i++) 1.1199 + { 1.1200 + java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i); 1.1201 + params.add(m.getParameterTypes()); 1.1202 + rets.add(m.getReturnType()); 1.1203 + } 1.1204 + methodidx = getMatchingParams(methodName, params, args, rets); 1.1205 + } 1.1206 + java.lang.reflect.Method m = 1.1207 + (java.lang.reflect.Method) (methodidx >= 0 ? methods.get(methodidx) : null); 1.1208 + if(m != null && !Modifier.isPublic(m.getDeclaringClass().getModifiers())) 1.1209 + { 1.1210 + //public method of non-public class, try to find it in hierarchy 1.1211 + m = Reflector.getAsMethodOfPublicBase(m.getDeclaringClass(), m); 1.1212 + } 1.1213 + method = m; 1.1214 + } 1.1215 + } 1.1216 + else 1.1217 + method = null; 1.1218 + 1.1219 + if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) 1.1220 + { 1.1221 + RT.errPrintWriter() 1.1222 + .format("Reflection warning, %s:%d - call to %s can't be resolved.\n", 1.1223 + SOURCE_PATH.deref(), line, methodName); 1.1224 + } 1.1225 + } 1.1226 + 1.1227 + public Object eval() throws Exception{ 1.1228 + try 1.1229 + { 1.1230 + Object targetval = target.eval(); 1.1231 + Object[] argvals = new Object[args.count()]; 1.1232 + for(int i = 0; i < args.count(); i++) 1.1233 + argvals[i] = ((Expr) args.nth(i)).eval(); 1.1234 + if(method != null) 1.1235 + { 1.1236 + LinkedList ms = new LinkedList(); 1.1237 + ms.add(method); 1.1238 + return Reflector.invokeMatchingMethod(methodName, ms, targetval, argvals); 1.1239 + } 1.1240 + return Reflector.invokeInstanceMethod(targetval, methodName, argvals); 1.1241 + } 1.1242 + catch(Throwable e) 1.1243 + { 1.1244 + if(!(e instanceof CompilerException)) 1.1245 + throw new CompilerException(source, line, e); 1.1246 + else 1.1247 + throw (CompilerException) e; 1.1248 + } 1.1249 + } 1.1250 + 1.1251 + public boolean canEmitPrimitive(){ 1.1252 + return method != null && Util.isPrimitive(method.getReturnType()); 1.1253 + } 1.1254 + 1.1255 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1256 + gen.visitLineNumber(line, gen.mark()); 1.1257 + if(method != null) 1.1258 + { 1.1259 + Type type = Type.getType(method.getDeclaringClass()); 1.1260 + target.emit(C.EXPRESSION, objx, gen); 1.1261 + //if(!method.getDeclaringClass().isInterface()) 1.1262 + gen.checkCast(type); 1.1263 + MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args); 1.1264 + if(context == C.RETURN) 1.1265 + { 1.1266 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.1267 + method.emitClearLocals(gen); 1.1268 + } 1.1269 + Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method)); 1.1270 + if(method.getDeclaringClass().isInterface()) 1.1271 + gen.invokeInterface(type, m); 1.1272 + else 1.1273 + gen.invokeVirtual(type, m); 1.1274 + } 1.1275 + else 1.1276 + throw new UnsupportedOperationException("Unboxed emit of unknown member"); 1.1277 + } 1.1278 + 1.1279 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1280 + gen.visitLineNumber(line, gen.mark()); 1.1281 + if(method != null) 1.1282 + { 1.1283 + Type type = Type.getType(method.getDeclaringClass()); 1.1284 + target.emit(C.EXPRESSION, objx, gen); 1.1285 + //if(!method.getDeclaringClass().isInterface()) 1.1286 + gen.checkCast(type); 1.1287 + MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args); 1.1288 + if(context == C.RETURN) 1.1289 + { 1.1290 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.1291 + method.emitClearLocals(gen); 1.1292 + } 1.1293 + Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method)); 1.1294 + if(method.getDeclaringClass().isInterface()) 1.1295 + gen.invokeInterface(type, m); 1.1296 + else 1.1297 + gen.invokeVirtual(type, m); 1.1298 + //if(context != C.STATEMENT || method.getReturnType() == Void.TYPE) 1.1299 + HostExpr.emitBoxReturn(objx, gen, method.getReturnType()); 1.1300 + } 1.1301 + else 1.1302 + { 1.1303 + target.emit(C.EXPRESSION, objx, gen); 1.1304 + gen.push(methodName); 1.1305 + emitArgsAsArray(args, objx, gen); 1.1306 + if(context == C.RETURN) 1.1307 + { 1.1308 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.1309 + method.emitClearLocals(gen); 1.1310 + } 1.1311 + gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodMethod); 1.1312 + } 1.1313 + if(context == C.STATEMENT) 1.1314 + gen.pop(); 1.1315 + } 1.1316 + 1.1317 + public boolean hasJavaClass(){ 1.1318 + return method != null || tag != null; 1.1319 + } 1.1320 + 1.1321 + public Class getJavaClass() throws Exception{ 1.1322 + return tag != null ? HostExpr.tagToClass(tag) : method.getReturnType(); 1.1323 + } 1.1324 +} 1.1325 + 1.1326 + 1.1327 +static class StaticMethodExpr extends MethodExpr{ 1.1328 + //final String className; 1.1329 + public final Class c; 1.1330 + public final String methodName; 1.1331 + public final IPersistentVector args; 1.1332 + public final String source; 1.1333 + public final int line; 1.1334 + public final java.lang.reflect.Method method; 1.1335 + public final Symbol tag; 1.1336 + final static Method forNameMethod = Method.getMethod("Class forName(String)"); 1.1337 + final static Method invokeStaticMethodMethod = 1.1338 + Method.getMethod("Object invokeStaticMethod(Class,String,Object[])"); 1.1339 + 1.1340 + 1.1341 + public StaticMethodExpr(String source, int line, Symbol tag, Class c, String methodName, IPersistentVector args) 1.1342 + throws Exception{ 1.1343 + this.c = c; 1.1344 + this.methodName = methodName; 1.1345 + this.args = args; 1.1346 + this.source = source; 1.1347 + this.line = line; 1.1348 + this.tag = tag; 1.1349 + 1.1350 + List methods = Reflector.getMethods(c, args.count(), methodName, true); 1.1351 + if(methods.isEmpty()) 1.1352 + throw new IllegalArgumentException("No matching method: " + methodName); 1.1353 + 1.1354 + int methodidx = 0; 1.1355 + if(methods.size() > 1) 1.1356 + { 1.1357 + ArrayList<Class[]> params = new ArrayList(); 1.1358 + ArrayList<Class> rets = new ArrayList(); 1.1359 + for(int i = 0; i < methods.size(); i++) 1.1360 + { 1.1361 + java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i); 1.1362 + params.add(m.getParameterTypes()); 1.1363 + rets.add(m.getReturnType()); 1.1364 + } 1.1365 + methodidx = getMatchingParams(methodName, params, args, rets); 1.1366 + } 1.1367 + method = (java.lang.reflect.Method) (methodidx >= 0 ? methods.get(methodidx) : null); 1.1368 + if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) 1.1369 + { 1.1370 + RT.errPrintWriter() 1.1371 + .format("Reflection warning, %s:%d - call to %s can't be resolved.\n", 1.1372 + SOURCE_PATH.deref(), line, methodName); 1.1373 + } 1.1374 + } 1.1375 + 1.1376 + public Object eval() throws Exception{ 1.1377 + try 1.1378 + { 1.1379 + Object[] argvals = new Object[args.count()]; 1.1380 + for(int i = 0; i < args.count(); i++) 1.1381 + argvals[i] = ((Expr) args.nth(i)).eval(); 1.1382 + if(method != null) 1.1383 + { 1.1384 + LinkedList ms = new LinkedList(); 1.1385 + ms.add(method); 1.1386 + return Reflector.invokeMatchingMethod(methodName, ms, null, argvals); 1.1387 + } 1.1388 + return Reflector.invokeStaticMethod(c, methodName, argvals); 1.1389 + } 1.1390 + catch(Throwable e) 1.1391 + { 1.1392 + if(!(e instanceof CompilerException)) 1.1393 + throw new CompilerException(source, line, e); 1.1394 + else 1.1395 + throw (CompilerException) e; 1.1396 + } 1.1397 + } 1.1398 + 1.1399 + public boolean canEmitPrimitive(){ 1.1400 + return method != null && Util.isPrimitive(method.getReturnType()); 1.1401 + } 1.1402 + 1.1403 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1404 + gen.visitLineNumber(line, gen.mark()); 1.1405 + if(method != null) 1.1406 + { 1.1407 + MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args); 1.1408 + //Type type = Type.getObjectType(className.replace('.', '/')); 1.1409 + if(context == C.RETURN) 1.1410 + { 1.1411 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.1412 + method.emitClearLocals(gen); 1.1413 + } 1.1414 + Type type = Type.getType(c); 1.1415 + Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method)); 1.1416 + gen.invokeStatic(type, m); 1.1417 + } 1.1418 + else 1.1419 + throw new UnsupportedOperationException("Unboxed emit of unknown member"); 1.1420 + } 1.1421 + 1.1422 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1423 + gen.visitLineNumber(line, gen.mark()); 1.1424 + if(method != null) 1.1425 + { 1.1426 + MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args); 1.1427 + //Type type = Type.getObjectType(className.replace('.', '/')); 1.1428 + if(context == C.RETURN) 1.1429 + { 1.1430 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.1431 + method.emitClearLocals(gen); 1.1432 + } 1.1433 + Type type = Type.getType(c); 1.1434 + Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method)); 1.1435 + gen.invokeStatic(type, m); 1.1436 + //if(context != C.STATEMENT || method.getReturnType() == Void.TYPE) 1.1437 + HostExpr.emitBoxReturn(objx, gen, method.getReturnType()); 1.1438 + } 1.1439 + else 1.1440 + { 1.1441 + gen.push(c.getName()); 1.1442 + gen.invokeStatic(CLASS_TYPE, forNameMethod); 1.1443 + gen.push(methodName); 1.1444 + emitArgsAsArray(args, objx, gen); 1.1445 + if(context == C.RETURN) 1.1446 + { 1.1447 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.1448 + method.emitClearLocals(gen); 1.1449 + } 1.1450 + gen.invokeStatic(REFLECTOR_TYPE, invokeStaticMethodMethod); 1.1451 + } 1.1452 + if(context == C.STATEMENT) 1.1453 + gen.pop(); 1.1454 + } 1.1455 + 1.1456 + public boolean hasJavaClass(){ 1.1457 + return method != null || tag != null; 1.1458 + } 1.1459 + 1.1460 + public Class getJavaClass() throws Exception{ 1.1461 + return tag != null ? HostExpr.tagToClass(tag) : method.getReturnType(); 1.1462 + } 1.1463 +} 1.1464 + 1.1465 +static class UnresolvedVarExpr implements Expr{ 1.1466 + public final Symbol symbol; 1.1467 + 1.1468 + public UnresolvedVarExpr(Symbol symbol){ 1.1469 + this.symbol = symbol; 1.1470 + } 1.1471 + 1.1472 + public boolean hasJavaClass(){ 1.1473 + return false; 1.1474 + } 1.1475 + 1.1476 + public Class getJavaClass() throws Exception{ 1.1477 + throw new IllegalArgumentException( 1.1478 + "UnresolvedVarExpr has no Java class"); 1.1479 + } 1.1480 + 1.1481 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1482 + } 1.1483 + 1.1484 + public Object eval() throws Exception{ 1.1485 + throw new IllegalArgumentException( 1.1486 + "UnresolvedVarExpr cannot be evalled"); 1.1487 + } 1.1488 +} 1.1489 + 1.1490 +static class ConstantExpr extends LiteralExpr{ 1.1491 + //stuff quoted vals in classloader at compile time, pull out at runtime 1.1492 + //this won't work for static compilation... 1.1493 + public final Object v; 1.1494 + public final int id; 1.1495 + 1.1496 + public ConstantExpr(Object v){ 1.1497 + this.v = v; 1.1498 + this.id = registerConstant(v); 1.1499 +// this.id = RT.nextID(); 1.1500 +// DynamicClassLoader loader = (DynamicClassLoader) LOADER.get(); 1.1501 +// loader.registerQuotedVal(id, v); 1.1502 + } 1.1503 + 1.1504 + Object val(){ 1.1505 + return v; 1.1506 + } 1.1507 + 1.1508 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1509 + objx.emitConstant(gen, id); 1.1510 + if(context == C.STATEMENT) 1.1511 + { 1.1512 + gen.pop(); 1.1513 +// gen.loadThis(); 1.1514 +// gen.invokeVirtual(OBJECT_TYPE, getClassMethod); 1.1515 +// gen.invokeVirtual(CLASS_TYPE, getClassLoaderMethod); 1.1516 +// gen.checkCast(DYNAMIC_CLASSLOADER_TYPE); 1.1517 +// gen.push(id); 1.1518 +// gen.invokeVirtual(DYNAMIC_CLASSLOADER_TYPE, getQuotedValMethod); 1.1519 + } 1.1520 + } 1.1521 + 1.1522 + public boolean hasJavaClass(){ 1.1523 + return Modifier.isPublic(v.getClass().getModifiers()); 1.1524 + //return false; 1.1525 + } 1.1526 + 1.1527 + public Class getJavaClass() throws Exception{ 1.1528 + return v.getClass(); 1.1529 + //throw new IllegalArgumentException("Has no Java class"); 1.1530 + } 1.1531 + 1.1532 + static class Parser implements IParser{ 1.1533 + public Expr parse(C context, Object form){ 1.1534 + Object v = RT.second(form); 1.1535 + 1.1536 + if(v == null) 1.1537 + return NIL_EXPR; 1.1538 +// Class fclass = v.getClass(); 1.1539 +// if(fclass == Keyword.class) 1.1540 +// return registerKeyword((Keyword) v); 1.1541 +// else if(v instanceof Num) 1.1542 +// return new NumExpr((Num) v); 1.1543 +// else if(fclass == String.class) 1.1544 +// return new StringExpr((String) v); 1.1545 +// else if(fclass == Character.class) 1.1546 +// return new CharExpr((Character) v); 1.1547 +// else if(v instanceof IPersistentCollection && ((IPersistentCollection) v).count() == 0) 1.1548 +// return new EmptyExpr(v); 1.1549 + else 1.1550 + return new ConstantExpr(v); 1.1551 + } 1.1552 + } 1.1553 +} 1.1554 + 1.1555 +static class NilExpr extends LiteralExpr{ 1.1556 + Object val(){ 1.1557 + return null; 1.1558 + } 1.1559 + 1.1560 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1561 + gen.visitInsn(Opcodes.ACONST_NULL); 1.1562 + if(context == C.STATEMENT) 1.1563 + gen.pop(); 1.1564 + } 1.1565 + 1.1566 + public boolean hasJavaClass(){ 1.1567 + return true; 1.1568 + } 1.1569 + 1.1570 + public Class getJavaClass() throws Exception{ 1.1571 + return null; 1.1572 + } 1.1573 +} 1.1574 + 1.1575 +final static NilExpr NIL_EXPR = new NilExpr(); 1.1576 + 1.1577 +static class BooleanExpr extends LiteralExpr{ 1.1578 + public final boolean val; 1.1579 + 1.1580 + 1.1581 + public BooleanExpr(boolean val){ 1.1582 + this.val = val; 1.1583 + } 1.1584 + 1.1585 + Object val(){ 1.1586 + return val ? RT.T : RT.F; 1.1587 + } 1.1588 + 1.1589 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1590 + if(val) 1.1591 + gen.getStatic(BOOLEAN_OBJECT_TYPE, "TRUE", BOOLEAN_OBJECT_TYPE); 1.1592 + else 1.1593 + gen.getStatic(BOOLEAN_OBJECT_TYPE, "FALSE", BOOLEAN_OBJECT_TYPE); 1.1594 + if(context == C.STATEMENT) 1.1595 + { 1.1596 + gen.pop(); 1.1597 + } 1.1598 + } 1.1599 + 1.1600 + public boolean hasJavaClass(){ 1.1601 + return true; 1.1602 + } 1.1603 + 1.1604 + public Class getJavaClass() throws Exception{ 1.1605 + return Boolean.class; 1.1606 + } 1.1607 +} 1.1608 + 1.1609 +final static BooleanExpr TRUE_EXPR = new BooleanExpr(true); 1.1610 +final static BooleanExpr FALSE_EXPR = new BooleanExpr(false); 1.1611 + 1.1612 +static class StringExpr extends LiteralExpr{ 1.1613 + public final String str; 1.1614 + 1.1615 + public StringExpr(String str){ 1.1616 + this.str = str; 1.1617 + } 1.1618 + 1.1619 + Object val(){ 1.1620 + return str; 1.1621 + } 1.1622 + 1.1623 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1624 + if(context != C.STATEMENT) 1.1625 + gen.push(str); 1.1626 + } 1.1627 + 1.1628 + public boolean hasJavaClass(){ 1.1629 + return true; 1.1630 + } 1.1631 + 1.1632 + public Class getJavaClass() throws Exception{ 1.1633 + return String.class; 1.1634 + } 1.1635 +} 1.1636 + 1.1637 + 1.1638 +static class MonitorEnterExpr extends UntypedExpr{ 1.1639 + final Expr target; 1.1640 + 1.1641 + public MonitorEnterExpr(Expr target){ 1.1642 + this.target = target; 1.1643 + } 1.1644 + 1.1645 + public Object eval() throws Exception{ 1.1646 + throw new UnsupportedOperationException("Can't eval monitor-enter"); 1.1647 + } 1.1648 + 1.1649 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1650 + target.emit(C.EXPRESSION, objx, gen); 1.1651 + gen.monitorEnter(); 1.1652 + NIL_EXPR.emit(context, objx, gen); 1.1653 + } 1.1654 + 1.1655 + static class Parser implements IParser{ 1.1656 + public Expr parse(C context, Object form) throws Exception{ 1.1657 + return new MonitorEnterExpr(analyze(C.EXPRESSION, RT.second(form))); 1.1658 + } 1.1659 + } 1.1660 +} 1.1661 + 1.1662 +static class MonitorExitExpr extends UntypedExpr{ 1.1663 + final Expr target; 1.1664 + 1.1665 + public MonitorExitExpr(Expr target){ 1.1666 + this.target = target; 1.1667 + } 1.1668 + 1.1669 + public Object eval() throws Exception{ 1.1670 + throw new UnsupportedOperationException("Can't eval monitor-exit"); 1.1671 + } 1.1672 + 1.1673 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1674 + target.emit(C.EXPRESSION, objx, gen); 1.1675 + gen.monitorExit(); 1.1676 + NIL_EXPR.emit(context, objx, gen); 1.1677 + } 1.1678 + 1.1679 + static class Parser implements IParser{ 1.1680 + public Expr parse(C context, Object form) throws Exception{ 1.1681 + return new MonitorExitExpr(analyze(C.EXPRESSION, RT.second(form))); 1.1682 + } 1.1683 + } 1.1684 + 1.1685 +} 1.1686 + 1.1687 +public static class TryExpr implements Expr{ 1.1688 + public final Expr tryExpr; 1.1689 + public final Expr finallyExpr; 1.1690 + public final PersistentVector catchExprs; 1.1691 + public final int retLocal; 1.1692 + public final int finallyLocal; 1.1693 + 1.1694 + public static class CatchClause{ 1.1695 + //final String className; 1.1696 + public final Class c; 1.1697 + public final LocalBinding lb; 1.1698 + public final Expr handler; 1.1699 + Label label; 1.1700 + Label endLabel; 1.1701 + 1.1702 + 1.1703 + public CatchClause(Class c, LocalBinding lb, Expr handler){ 1.1704 + this.c = c; 1.1705 + this.lb = lb; 1.1706 + this.handler = handler; 1.1707 + } 1.1708 + } 1.1709 + 1.1710 + public TryExpr(Expr tryExpr, PersistentVector catchExprs, Expr finallyExpr, int retLocal, int finallyLocal){ 1.1711 + this.tryExpr = tryExpr; 1.1712 + this.catchExprs = catchExprs; 1.1713 + this.finallyExpr = finallyExpr; 1.1714 + this.retLocal = retLocal; 1.1715 + this.finallyLocal = finallyLocal; 1.1716 + } 1.1717 + 1.1718 + public Object eval() throws Exception{ 1.1719 + throw new UnsupportedOperationException("Can't eval try"); 1.1720 + } 1.1721 + 1.1722 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1723 + Label startTry = gen.newLabel(); 1.1724 + Label endTry = gen.newLabel(); 1.1725 + Label end = gen.newLabel(); 1.1726 + Label ret = gen.newLabel(); 1.1727 + Label finallyLabel = gen.newLabel(); 1.1728 + for(int i = 0; i < catchExprs.count(); i++) 1.1729 + { 1.1730 + CatchClause clause = (CatchClause) catchExprs.nth(i); 1.1731 + clause.label = gen.newLabel(); 1.1732 + clause.endLabel = gen.newLabel(); 1.1733 + } 1.1734 + 1.1735 + gen.mark(startTry); 1.1736 + tryExpr.emit(context, objx, gen); 1.1737 + if(context != C.STATEMENT) 1.1738 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), retLocal); 1.1739 + gen.mark(endTry); 1.1740 + if(finallyExpr != null) 1.1741 + finallyExpr.emit(C.STATEMENT, objx, gen); 1.1742 + gen.goTo(ret); 1.1743 + 1.1744 + for(int i = 0; i < catchExprs.count(); i++) 1.1745 + { 1.1746 + CatchClause clause = (CatchClause) catchExprs.nth(i); 1.1747 + gen.mark(clause.label); 1.1748 + //exception should be on stack 1.1749 + //put in clause local 1.1750 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), clause.lb.idx); 1.1751 + clause.handler.emit(context, objx, gen); 1.1752 + if(context != C.STATEMENT) 1.1753 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), retLocal); 1.1754 + gen.mark(clause.endLabel); 1.1755 + 1.1756 + if(finallyExpr != null) 1.1757 + finallyExpr.emit(C.STATEMENT, objx, gen); 1.1758 + gen.goTo(ret); 1.1759 + } 1.1760 + if(finallyExpr != null) 1.1761 + { 1.1762 + gen.mark(finallyLabel); 1.1763 + //exception should be on stack 1.1764 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), finallyLocal); 1.1765 + finallyExpr.emit(C.STATEMENT, objx, gen); 1.1766 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), finallyLocal); 1.1767 + gen.throwException(); 1.1768 + } 1.1769 + gen.mark(ret); 1.1770 + if(context != C.STATEMENT) 1.1771 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), retLocal); 1.1772 + gen.mark(end); 1.1773 + for(int i = 0; i < catchExprs.count(); i++) 1.1774 + { 1.1775 + CatchClause clause = (CatchClause) catchExprs.nth(i); 1.1776 + gen.visitTryCatchBlock(startTry, endTry, clause.label, clause.c.getName().replace('.', '/')); 1.1777 + } 1.1778 + if(finallyExpr != null) 1.1779 + { 1.1780 + gen.visitTryCatchBlock(startTry, endTry, finallyLabel, null); 1.1781 + for(int i = 0; i < catchExprs.count(); i++) 1.1782 + { 1.1783 + CatchClause clause = (CatchClause) catchExprs.nth(i); 1.1784 + gen.visitTryCatchBlock(clause.label, clause.endLabel, finallyLabel, null); 1.1785 + } 1.1786 + } 1.1787 + for(int i = 0; i < catchExprs.count(); i++) 1.1788 + { 1.1789 + CatchClause clause = (CatchClause) catchExprs.nth(i); 1.1790 + gen.visitLocalVariable(clause.lb.name, "Ljava/lang/Object;", null, clause.label, clause.endLabel, 1.1791 + clause.lb.idx); 1.1792 + } 1.1793 + } 1.1794 + 1.1795 + public boolean hasJavaClass() throws Exception{ 1.1796 + return tryExpr.hasJavaClass(); 1.1797 + } 1.1798 + 1.1799 + public Class getJavaClass() throws Exception{ 1.1800 + return tryExpr.getJavaClass(); 1.1801 + } 1.1802 + 1.1803 + static class Parser implements IParser{ 1.1804 + 1.1805 + public Expr parse(C context, Object frm) throws Exception{ 1.1806 + ISeq form = (ISeq) frm; 1.1807 +// if(context == C.EVAL || context == C.EXPRESSION) 1.1808 + if(context != C.RETURN) 1.1809 + return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form))); 1.1810 + 1.1811 + //(try try-expr* catch-expr* finally-expr?) 1.1812 + //catch-expr: (catch class sym expr*) 1.1813 + //finally-expr: (finally expr*) 1.1814 + 1.1815 + PersistentVector body = PersistentVector.EMPTY; 1.1816 + PersistentVector catches = PersistentVector.EMPTY; 1.1817 + Expr bodyExpr = null; 1.1818 + Expr finallyExpr = null; 1.1819 + boolean caught = false; 1.1820 + 1.1821 + int retLocal = getAndIncLocalNum(); 1.1822 + int finallyLocal = getAndIncLocalNum(); 1.1823 + for(ISeq fs = form.next(); fs != null; fs = fs.next()) 1.1824 + { 1.1825 + Object f = fs.first(); 1.1826 + Object op = (f instanceof ISeq) ? ((ISeq) f).first() : null; 1.1827 + if(!Util.equals(op, CATCH) && !Util.equals(op, FINALLY)) 1.1828 + { 1.1829 + if(caught) 1.1830 + throw new Exception("Only catch or finally clause can follow catch in try expression"); 1.1831 + body = body.cons(f); 1.1832 + } 1.1833 + else 1.1834 + { 1.1835 + if(bodyExpr == null) 1.1836 + bodyExpr = (new BodyExpr.Parser()).parse(context, RT.seq(body)); 1.1837 + if(Util.equals(op, CATCH)) 1.1838 + { 1.1839 + Class c = HostExpr.maybeClass(RT.second(f), false); 1.1840 + if(c == null) 1.1841 + throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(f)); 1.1842 + if(!(RT.third(f) instanceof Symbol)) 1.1843 + throw new IllegalArgumentException( 1.1844 + "Bad binding form, expected symbol, got: " + RT.third(f)); 1.1845 + Symbol sym = (Symbol) RT.third(f); 1.1846 + if(sym.getNamespace() != null) 1.1847 + throw new Exception("Can't bind qualified name:" + sym); 1.1848 + 1.1849 + IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(), 1.1850 + NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref(), 1.1851 + IN_CATCH_FINALLY, RT.T); 1.1852 + try 1.1853 + { 1.1854 + Var.pushThreadBindings(dynamicBindings); 1.1855 + LocalBinding lb = registerLocal(sym, 1.1856 + (Symbol) (RT.second(f) instanceof Symbol ? RT.second(f) 1.1857 + : null), 1.1858 + null,false); 1.1859 + Expr handler = (new BodyExpr.Parser()).parse(context, RT.next(RT.next(RT.next(f)))); 1.1860 + catches = catches.cons(new CatchClause(c, lb, handler)); 1.1861 + } 1.1862 + finally 1.1863 + { 1.1864 + Var.popThreadBindings(); 1.1865 + } 1.1866 + caught = true; 1.1867 + } 1.1868 + else //finally 1.1869 + { 1.1870 + if(fs.next() != null) 1.1871 + throw new Exception("finally clause must be last in try expression"); 1.1872 + try 1.1873 + { 1.1874 + Var.pushThreadBindings(RT.map(IN_CATCH_FINALLY, RT.T)); 1.1875 + finallyExpr = (new BodyExpr.Parser()).parse(C.STATEMENT, RT.next(f)); 1.1876 + } 1.1877 + finally 1.1878 + { 1.1879 + Var.popThreadBindings(); 1.1880 + } 1.1881 + } 1.1882 + } 1.1883 + } 1.1884 + if(bodyExpr == null) 1.1885 + bodyExpr = (new BodyExpr.Parser()).parse(context, RT.seq(body)); 1.1886 + 1.1887 + return new TryExpr(bodyExpr, catches, finallyExpr, retLocal, 1.1888 + finallyLocal); 1.1889 + } 1.1890 + } 1.1891 +} 1.1892 + 1.1893 +//static class TryFinallyExpr implements Expr{ 1.1894 +// final Expr tryExpr; 1.1895 +// final Expr finallyExpr; 1.1896 +// 1.1897 +// 1.1898 +// public TryFinallyExpr(Expr tryExpr, Expr finallyExpr){ 1.1899 +// this.tryExpr = tryExpr; 1.1900 +// this.finallyExpr = finallyExpr; 1.1901 +// } 1.1902 +// 1.1903 +// public Object eval() throws Exception{ 1.1904 +// throw new UnsupportedOperationException("Can't eval try"); 1.1905 +// } 1.1906 +// 1.1907 +// public void emit(C context, FnExpr fn, GeneratorAdapter gen){ 1.1908 +// Label startTry = gen.newLabel(); 1.1909 +// Label endTry = gen.newLabel(); 1.1910 +// Label end = gen.newLabel(); 1.1911 +// Label finallyLabel = gen.newLabel(); 1.1912 +// gen.visitTryCatchBlock(startTry, endTry, finallyLabel, null); 1.1913 +// gen.mark(startTry); 1.1914 +// tryExpr.emit(context, fn, gen); 1.1915 +// gen.mark(endTry); 1.1916 +// finallyExpr.emit(C.STATEMENT, fn, gen); 1.1917 +// gen.goTo(end); 1.1918 +// gen.mark(finallyLabel); 1.1919 +// //exception should be on stack 1.1920 +// finallyExpr.emit(C.STATEMENT, fn, gen); 1.1921 +// gen.throwException(); 1.1922 +// gen.mark(end); 1.1923 +// } 1.1924 +// 1.1925 +// public boolean hasJavaClass() throws Exception{ 1.1926 +// return tryExpr.hasJavaClass(); 1.1927 +// } 1.1928 +// 1.1929 +// public Class getJavaClass() throws Exception{ 1.1930 +// return tryExpr.getJavaClass(); 1.1931 +// } 1.1932 +// 1.1933 +// static class Parser implements IParser{ 1.1934 +// public Expr parse(C context, Object frm) throws Exception{ 1.1935 +// ISeq form = (ISeq) frm; 1.1936 +// //(try-finally try-expr finally-expr) 1.1937 +// if(form.count() != 3) 1.1938 +// throw new IllegalArgumentException( 1.1939 +// "Wrong number of arguments, expecting: (try-finally try-expr finally-expr) "); 1.1940 +// 1.1941 +// if(context == C.EVAL || context == C.EXPRESSION) 1.1942 +// return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form))); 1.1943 +// 1.1944 +// return new TryFinallyExpr(analyze(context, RT.second(form)), 1.1945 +// analyze(C.STATEMENT, RT.third(form))); 1.1946 +// } 1.1947 +// } 1.1948 +//} 1.1949 + 1.1950 +static class ThrowExpr extends UntypedExpr{ 1.1951 + public final Expr excExpr; 1.1952 + 1.1953 + public ThrowExpr(Expr excExpr){ 1.1954 + this.excExpr = excExpr; 1.1955 + } 1.1956 + 1.1957 + 1.1958 + public Object eval() throws Exception{ 1.1959 + throw new Exception("Can't eval throw"); 1.1960 + } 1.1961 + 1.1962 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.1963 + excExpr.emit(C.EXPRESSION, objx, gen); 1.1964 + gen.checkCast(THROWABLE_TYPE); 1.1965 + gen.throwException(); 1.1966 + } 1.1967 + 1.1968 + static class Parser implements IParser{ 1.1969 + public Expr parse(C context, Object form) throws Exception{ 1.1970 + if(context == C.EVAL) 1.1971 + return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form))); 1.1972 + return new ThrowExpr(analyze(C.EXPRESSION, RT.second(form))); 1.1973 + } 1.1974 + } 1.1975 +} 1.1976 + 1.1977 + 1.1978 +static public boolean subsumes(Class[] c1, Class[] c2){ 1.1979 + //presumes matching lengths 1.1980 + Boolean better = false; 1.1981 + for(int i = 0; i < c1.length; i++) 1.1982 + { 1.1983 + if(c1[i] != c2[i])// || c2[i].isPrimitive() && c1[i] == Object.class)) 1.1984 + { 1.1985 + if(!c1[i].isPrimitive() && c2[i].isPrimitive() 1.1986 + //|| Number.class.isAssignableFrom(c1[i]) && c2[i].isPrimitive() 1.1987 + || 1.1988 + c2[i].isAssignableFrom(c1[i])) 1.1989 + better = true; 1.1990 + else 1.1991 + return false; 1.1992 + } 1.1993 + } 1.1994 + return better; 1.1995 +} 1.1996 + 1.1997 +static int getMatchingParams(String methodName, ArrayList<Class[]> paramlists, IPersistentVector argexprs, 1.1998 + List<Class> rets) 1.1999 + throws Exception{ 1.2000 + //presumes matching lengths 1.2001 + int matchIdx = -1; 1.2002 + boolean tied = false; 1.2003 + boolean foundExact = false; 1.2004 + for(int i = 0; i < paramlists.size(); i++) 1.2005 + { 1.2006 + boolean match = true; 1.2007 + ISeq aseq = argexprs.seq(); 1.2008 + int exact = 0; 1.2009 + for(int p = 0; match && p < argexprs.count() && aseq != null; ++p, aseq = aseq.next()) 1.2010 + { 1.2011 + Expr arg = (Expr) aseq.first(); 1.2012 + Class aclass = arg.hasJavaClass() ? arg.getJavaClass() : Object.class; 1.2013 + Class pclass = paramlists.get(i)[p]; 1.2014 + if(arg.hasJavaClass() && aclass == pclass) 1.2015 + exact++; 1.2016 + else 1.2017 + match = Reflector.paramArgTypeMatch(pclass, aclass); 1.2018 + } 1.2019 + if(exact == argexprs.count()) 1.2020 + { 1.2021 + if(!foundExact || matchIdx == -1 || rets.get(matchIdx).isAssignableFrom(rets.get(i))) 1.2022 + matchIdx = i; 1.2023 + foundExact = true; 1.2024 + } 1.2025 + else if(match && !foundExact) 1.2026 + { 1.2027 + if(matchIdx == -1) 1.2028 + matchIdx = i; 1.2029 + else 1.2030 + { 1.2031 + if(subsumes(paramlists.get(i), paramlists.get(matchIdx))) 1.2032 + { 1.2033 + matchIdx = i; 1.2034 + tied = false; 1.2035 + } 1.2036 + else if(Arrays.equals(paramlists.get(matchIdx), paramlists.get(i))) 1.2037 + { 1.2038 + if(rets.get(matchIdx).isAssignableFrom(rets.get(i))) 1.2039 + matchIdx = i; 1.2040 + } 1.2041 + else if(!(subsumes(paramlists.get(matchIdx), paramlists.get(i)))) 1.2042 + tied = true; 1.2043 + } 1.2044 + } 1.2045 + } 1.2046 + if(tied) 1.2047 + throw new IllegalArgumentException("More than one matching method found: " + methodName); 1.2048 + 1.2049 + return matchIdx; 1.2050 +} 1.2051 + 1.2052 +public static class NewExpr implements Expr{ 1.2053 + public final IPersistentVector args; 1.2054 + public final Constructor ctor; 1.2055 + public final Class c; 1.2056 + final static Method invokeConstructorMethod = 1.2057 + Method.getMethod("Object invokeConstructor(Class,Object[])"); 1.2058 +// final static Method forNameMethod = Method.getMethod("Class classForName(String)"); 1.2059 + final static Method forNameMethod = Method.getMethod("Class forName(String)"); 1.2060 + 1.2061 + 1.2062 + public NewExpr(Class c, IPersistentVector args, int line) throws Exception{ 1.2063 + this.args = args; 1.2064 + this.c = c; 1.2065 + Constructor[] allctors = c.getConstructors(); 1.2066 + ArrayList ctors = new ArrayList(); 1.2067 + ArrayList<Class[]> params = new ArrayList(); 1.2068 + ArrayList<Class> rets = new ArrayList(); 1.2069 + for(int i = 0; i < allctors.length; i++) 1.2070 + { 1.2071 + Constructor ctor = allctors[i]; 1.2072 + if(ctor.getParameterTypes().length == args.count()) 1.2073 + { 1.2074 + ctors.add(ctor); 1.2075 + params.add(ctor.getParameterTypes()); 1.2076 + rets.add(c); 1.2077 + } 1.2078 + } 1.2079 + if(ctors.isEmpty()) 1.2080 + throw new IllegalArgumentException("No matching ctor found for " + c); 1.2081 + 1.2082 + int ctoridx = 0; 1.2083 + if(ctors.size() > 1) 1.2084 + { 1.2085 + ctoridx = getMatchingParams(c.getName(), params, args, rets); 1.2086 + } 1.2087 + 1.2088 + this.ctor = ctoridx >= 0 ? (Constructor) ctors.get(ctoridx) : null; 1.2089 + if(ctor == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) 1.2090 + { 1.2091 + RT.errPrintWriter() 1.2092 + .format("Reflection warning, %s:%d - call to %s ctor can't be resolved.\n", 1.2093 + SOURCE_PATH.deref(), line, c.getName()); 1.2094 + } 1.2095 + } 1.2096 + 1.2097 + public Object eval() throws Exception{ 1.2098 + Object[] argvals = new Object[args.count()]; 1.2099 + for(int i = 0; i < args.count(); i++) 1.2100 + argvals[i] = ((Expr) args.nth(i)).eval(); 1.2101 + if(this.ctor != null) 1.2102 + { 1.2103 + return ctor.newInstance(Reflector.boxArgs(ctor.getParameterTypes(), argvals)); 1.2104 + } 1.2105 + return Reflector.invokeConstructor(c, argvals); 1.2106 + } 1.2107 + 1.2108 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2109 + if(this.ctor != null) 1.2110 + { 1.2111 + Type type = getType(c); 1.2112 + gen.newInstance(type); 1.2113 + gen.dup(); 1.2114 + MethodExpr.emitTypedArgs(objx, gen, ctor.getParameterTypes(), args); 1.2115 + if(context == C.RETURN) 1.2116 + { 1.2117 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.2118 + method.emitClearLocals(gen); 1.2119 + } 1.2120 + gen.invokeConstructor(type, new Method("<init>", Type.getConstructorDescriptor(ctor))); 1.2121 + } 1.2122 + else 1.2123 + { 1.2124 + gen.push(destubClassName(c.getName())); 1.2125 + gen.invokeStatic(CLASS_TYPE, forNameMethod); 1.2126 + MethodExpr.emitArgsAsArray(args, objx, gen); 1.2127 + if(context == C.RETURN) 1.2128 + { 1.2129 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.2130 + method.emitClearLocals(gen); 1.2131 + } 1.2132 + gen.invokeStatic(REFLECTOR_TYPE, invokeConstructorMethod); 1.2133 + } 1.2134 + if(context == C.STATEMENT) 1.2135 + gen.pop(); 1.2136 + } 1.2137 + 1.2138 + public boolean hasJavaClass(){ 1.2139 + return true; 1.2140 + } 1.2141 + 1.2142 + public Class getJavaClass() throws Exception{ 1.2143 + return c; 1.2144 + } 1.2145 + 1.2146 + static class Parser implements IParser{ 1.2147 + public Expr parse(C context, Object frm) throws Exception{ 1.2148 + int line = (Integer) LINE.deref(); 1.2149 + ISeq form = (ISeq) frm; 1.2150 + //(new Classname args...) 1.2151 + if(form.count() < 2) 1.2152 + throw new Exception("wrong number of arguments, expecting: (new Classname args...)"); 1.2153 + Class c = HostExpr.maybeClass(RT.second(form), false); 1.2154 + if(c == null) 1.2155 + throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(form)); 1.2156 + PersistentVector args = PersistentVector.EMPTY; 1.2157 + for(ISeq s = RT.next(RT.next(form)); s != null; s = s.next()) 1.2158 + args = args.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, s.first())); 1.2159 + return new NewExpr(c, args, line); 1.2160 + } 1.2161 + } 1.2162 + 1.2163 +} 1.2164 + 1.2165 +public static class MetaExpr implements Expr{ 1.2166 + public final Expr expr; 1.2167 + public final MapExpr meta; 1.2168 + final static Type IOBJ_TYPE = Type.getType(IObj.class); 1.2169 + final static Method withMetaMethod = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)"); 1.2170 + 1.2171 + 1.2172 + public MetaExpr(Expr expr, MapExpr meta){ 1.2173 + this.expr = expr; 1.2174 + this.meta = meta; 1.2175 + } 1.2176 + 1.2177 + public Object eval() throws Exception{ 1.2178 + return ((IObj) expr.eval()).withMeta((IPersistentMap) meta.eval()); 1.2179 + } 1.2180 + 1.2181 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2182 + expr.emit(C.EXPRESSION, objx, gen); 1.2183 + gen.checkCast(IOBJ_TYPE); 1.2184 + meta.emit(C.EXPRESSION, objx, gen); 1.2185 + gen.checkCast(IPERSISTENTMAP_TYPE); 1.2186 + gen.invokeInterface(IOBJ_TYPE, withMetaMethod); 1.2187 + if(context == C.STATEMENT) 1.2188 + { 1.2189 + gen.pop(); 1.2190 + } 1.2191 + } 1.2192 + 1.2193 + public boolean hasJavaClass() throws Exception{ 1.2194 + return expr.hasJavaClass(); 1.2195 + } 1.2196 + 1.2197 + public Class getJavaClass() throws Exception{ 1.2198 + return expr.getJavaClass(); 1.2199 + } 1.2200 +} 1.2201 + 1.2202 +public static class IfExpr implements Expr, MaybePrimitiveExpr{ 1.2203 + public final Expr testExpr; 1.2204 + public final Expr thenExpr; 1.2205 + public final Expr elseExpr; 1.2206 + public final int line; 1.2207 + 1.2208 + 1.2209 + public IfExpr(int line, Expr testExpr, Expr thenExpr, Expr elseExpr){ 1.2210 + this.testExpr = testExpr; 1.2211 + this.thenExpr = thenExpr; 1.2212 + this.elseExpr = elseExpr; 1.2213 + this.line = line; 1.2214 + } 1.2215 + 1.2216 + public Object eval() throws Exception{ 1.2217 + Object t = testExpr.eval(); 1.2218 + if(t != null && t != Boolean.FALSE) 1.2219 + return thenExpr.eval(); 1.2220 + return elseExpr.eval(); 1.2221 + } 1.2222 + 1.2223 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2224 + doEmit(context, objx, gen,false); 1.2225 + } 1.2226 + 1.2227 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2228 + doEmit(context, objx, gen, true); 1.2229 + } 1.2230 + 1.2231 + public void doEmit(C context, ObjExpr objx, GeneratorAdapter gen, boolean emitUnboxed){ 1.2232 + Label nullLabel = gen.newLabel(); 1.2233 + Label falseLabel = gen.newLabel(); 1.2234 + Label endLabel = gen.newLabel(); 1.2235 + 1.2236 + gen.visitLineNumber(line, gen.mark()); 1.2237 + 1.2238 + try 1.2239 + { 1.2240 + if(maybePrimitiveType(testExpr) == boolean.class) 1.2241 + { 1.2242 + ((MaybePrimitiveExpr) testExpr).emitUnboxed(C.EXPRESSION, objx, gen); 1.2243 + gen.ifZCmp(gen.EQ, falseLabel); 1.2244 + } 1.2245 + else 1.2246 + { 1.2247 + testExpr.emit(C.EXPRESSION, objx, gen); 1.2248 + gen.dup(); 1.2249 + gen.ifNull(nullLabel); 1.2250 + gen.getStatic(BOOLEAN_OBJECT_TYPE, "FALSE", BOOLEAN_OBJECT_TYPE); 1.2251 + gen.visitJumpInsn(IF_ACMPEQ, falseLabel); 1.2252 + } 1.2253 + } 1.2254 + catch(Exception e) 1.2255 + { 1.2256 + throw new RuntimeException(e); 1.2257 + } 1.2258 + if(emitUnboxed) 1.2259 + ((MaybePrimitiveExpr)thenExpr).emitUnboxed(context, objx, gen); 1.2260 + else 1.2261 + thenExpr.emit(context, objx, gen); 1.2262 + gen.goTo(endLabel); 1.2263 + gen.mark(nullLabel); 1.2264 + gen.pop(); 1.2265 + gen.mark(falseLabel); 1.2266 + if(emitUnboxed) 1.2267 + ((MaybePrimitiveExpr)elseExpr).emitUnboxed(context, objx, gen); 1.2268 + else 1.2269 + elseExpr.emit(context, objx, gen); 1.2270 + gen.mark(endLabel); 1.2271 + } 1.2272 + 1.2273 + public boolean hasJavaClass() throws Exception{ 1.2274 + return thenExpr.hasJavaClass() 1.2275 + && elseExpr.hasJavaClass() 1.2276 + && 1.2277 + (thenExpr.getJavaClass() == elseExpr.getJavaClass() 1.2278 + || (thenExpr.getJavaClass() == null && !elseExpr.getJavaClass().isPrimitive()) 1.2279 + || (elseExpr.getJavaClass() == null && !thenExpr.getJavaClass().isPrimitive())); 1.2280 + } 1.2281 + 1.2282 + public boolean canEmitPrimitive(){ 1.2283 + try 1.2284 + { 1.2285 + return thenExpr instanceof MaybePrimitiveExpr 1.2286 + && elseExpr instanceof MaybePrimitiveExpr 1.2287 + && thenExpr.getJavaClass() == elseExpr.getJavaClass() 1.2288 + && ((MaybePrimitiveExpr)thenExpr).canEmitPrimitive() 1.2289 + && ((MaybePrimitiveExpr)elseExpr).canEmitPrimitive(); 1.2290 + } 1.2291 + catch(Exception e) 1.2292 + { 1.2293 + return false; 1.2294 + } 1.2295 + } 1.2296 + 1.2297 + public Class getJavaClass() throws Exception{ 1.2298 + Class thenClass = thenExpr.getJavaClass(); 1.2299 + if(thenClass != null) 1.2300 + return thenClass; 1.2301 + return elseExpr.getJavaClass(); 1.2302 + } 1.2303 + 1.2304 + static class Parser implements IParser{ 1.2305 + public Expr parse(C context, Object frm) throws Exception{ 1.2306 + ISeq form = (ISeq) frm; 1.2307 + //(if test then) or (if test then else) 1.2308 + if(form.count() > 4) 1.2309 + throw new Exception("Too many arguments to if"); 1.2310 + else if(form.count() < 3) 1.2311 + throw new Exception("Too few arguments to if"); 1.2312 + PathNode branch = new PathNode(PATHTYPE.BRANCH, (PathNode) CLEAR_PATH.get()); 1.2313 + Expr testexpr = analyze(context == C.EVAL ? context : C.EXPRESSION, RT.second(form)); 1.2314 + Expr thenexpr, elseexpr; 1.2315 + try { 1.2316 + Var.pushThreadBindings( 1.2317 + RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch))); 1.2318 + thenexpr = analyze(context, RT.third(form)); 1.2319 + } 1.2320 + finally{ 1.2321 + Var.popThreadBindings(); 1.2322 + } 1.2323 + try { 1.2324 + Var.pushThreadBindings( 1.2325 + RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch))); 1.2326 + elseexpr = analyze(context, RT.fourth(form)); 1.2327 + } 1.2328 + finally{ 1.2329 + Var.popThreadBindings(); 1.2330 + } 1.2331 + return new IfExpr((Integer) LINE.deref(), 1.2332 + testexpr, 1.2333 + thenexpr, 1.2334 + elseexpr); 1.2335 + } 1.2336 + } 1.2337 +} 1.2338 + 1.2339 +static final public IPersistentMap CHAR_MAP = 1.2340 + PersistentHashMap.create('-', "_", 1.2341 +// '.', "_DOT_", 1.2342 +':', "_COLON_", 1.2343 +'+', "_PLUS_", 1.2344 +'>', "_GT_", 1.2345 +'<', "_LT_", 1.2346 +'=', "_EQ_", 1.2347 +'~', "_TILDE_", 1.2348 +'!', "_BANG_", 1.2349 +'@', "_CIRCA_", 1.2350 +'#', "_SHARP_", 1.2351 +'$', "_DOLLARSIGN_", 1.2352 +'%', "_PERCENT_", 1.2353 +'^', "_CARET_", 1.2354 +'&', "_AMPERSAND_", 1.2355 +'*', "_STAR_", 1.2356 +'|', "_BAR_", 1.2357 +'{', "_LBRACE_", 1.2358 +'}', "_RBRACE_", 1.2359 +'[', "_LBRACK_", 1.2360 +']', "_RBRACK_", 1.2361 +'/', "_SLASH_", 1.2362 +'\\', "_BSLASH_", 1.2363 +'?', "_QMARK_"); 1.2364 + 1.2365 +static public String munge(String name){ 1.2366 + StringBuilder sb = new StringBuilder(); 1.2367 + for(char c : name.toCharArray()) 1.2368 + { 1.2369 + String sub = (String) CHAR_MAP.valAt(c); 1.2370 + if(sub != null) 1.2371 + sb.append(sub); 1.2372 + else 1.2373 + sb.append(c); 1.2374 + } 1.2375 + return sb.toString(); 1.2376 +} 1.2377 + 1.2378 +public static class EmptyExpr implements Expr{ 1.2379 + public final Object coll; 1.2380 + final static Type HASHMAP_TYPE = Type.getType(PersistentArrayMap.class); 1.2381 + final static Type HASHSET_TYPE = Type.getType(PersistentHashSet.class); 1.2382 + final static Type VECTOR_TYPE = Type.getType(PersistentVector.class); 1.2383 + final static Type LIST_TYPE = Type.getType(PersistentList.class); 1.2384 + final static Type EMPTY_LIST_TYPE = Type.getType(PersistentList.EmptyList.class); 1.2385 + 1.2386 + 1.2387 + public EmptyExpr(Object coll){ 1.2388 + this.coll = coll; 1.2389 + } 1.2390 + 1.2391 + public Object eval() throws Exception{ 1.2392 + return coll; 1.2393 + } 1.2394 + 1.2395 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2396 + if(coll instanceof IPersistentList) 1.2397 + gen.getStatic(LIST_TYPE, "EMPTY", EMPTY_LIST_TYPE); 1.2398 + else if(coll instanceof IPersistentVector) 1.2399 + gen.getStatic(VECTOR_TYPE, "EMPTY", VECTOR_TYPE); 1.2400 + else if(coll instanceof IPersistentMap) 1.2401 + gen.getStatic(HASHMAP_TYPE, "EMPTY", HASHMAP_TYPE); 1.2402 + else if(coll instanceof IPersistentSet) 1.2403 + gen.getStatic(HASHSET_TYPE, "EMPTY", HASHSET_TYPE); 1.2404 + else 1.2405 + throw new UnsupportedOperationException("Unknown Collection type"); 1.2406 + if(context == C.STATEMENT) 1.2407 + { 1.2408 + gen.pop(); 1.2409 + } 1.2410 + } 1.2411 + 1.2412 + public boolean hasJavaClass() throws Exception{ 1.2413 + return true; 1.2414 + } 1.2415 + 1.2416 + public Class getJavaClass() throws Exception{ 1.2417 + if(coll instanceof IPersistentList) 1.2418 + return IPersistentList.class; 1.2419 + else if(coll instanceof IPersistentVector) 1.2420 + return IPersistentVector.class; 1.2421 + else if(coll instanceof IPersistentMap) 1.2422 + return IPersistentMap.class; 1.2423 + else if(coll instanceof IPersistentSet) 1.2424 + return IPersistentSet.class; 1.2425 + else 1.2426 + throw new UnsupportedOperationException("Unknown Collection type"); 1.2427 + } 1.2428 +} 1.2429 + 1.2430 +public static class ListExpr implements Expr{ 1.2431 + public final IPersistentVector args; 1.2432 + final static Method arrayToListMethod = Method.getMethod("clojure.lang.ISeq arrayToList(Object[])"); 1.2433 + 1.2434 + 1.2435 + public ListExpr(IPersistentVector args){ 1.2436 + this.args = args; 1.2437 + } 1.2438 + 1.2439 + public Object eval() throws Exception{ 1.2440 + IPersistentVector ret = PersistentVector.EMPTY; 1.2441 + for(int i = 0; i < args.count(); i++) 1.2442 + ret = (IPersistentVector) ret.cons(((Expr) args.nth(i)).eval()); 1.2443 + return ret.seq(); 1.2444 + } 1.2445 + 1.2446 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2447 + MethodExpr.emitArgsAsArray(args, objx, gen); 1.2448 + gen.invokeStatic(RT_TYPE, arrayToListMethod); 1.2449 + if(context == C.STATEMENT) 1.2450 + gen.pop(); 1.2451 + } 1.2452 + 1.2453 + public boolean hasJavaClass() throws Exception{ 1.2454 + return true; 1.2455 + } 1.2456 + 1.2457 + public Class getJavaClass() throws Exception{ 1.2458 + return IPersistentList.class; 1.2459 + } 1.2460 + 1.2461 +} 1.2462 + 1.2463 +public static class MapExpr implements Expr{ 1.2464 + public final IPersistentVector keyvals; 1.2465 + final static Method mapMethod = Method.getMethod("clojure.lang.IPersistentMap map(Object[])"); 1.2466 + 1.2467 + 1.2468 + public MapExpr(IPersistentVector keyvals){ 1.2469 + this.keyvals = keyvals; 1.2470 + } 1.2471 + 1.2472 + public Object eval() throws Exception{ 1.2473 + Object[] ret = new Object[keyvals.count()]; 1.2474 + for(int i = 0; i < keyvals.count(); i++) 1.2475 + ret[i] = ((Expr) keyvals.nth(i)).eval(); 1.2476 + return RT.map(ret); 1.2477 + } 1.2478 + 1.2479 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2480 + MethodExpr.emitArgsAsArray(keyvals, objx, gen); 1.2481 + gen.invokeStatic(RT_TYPE, mapMethod); 1.2482 + if(context == C.STATEMENT) 1.2483 + gen.pop(); 1.2484 + } 1.2485 + 1.2486 + public boolean hasJavaClass() throws Exception{ 1.2487 + return true; 1.2488 + } 1.2489 + 1.2490 + public Class getJavaClass() throws Exception{ 1.2491 + return IPersistentMap.class; 1.2492 + } 1.2493 + 1.2494 + 1.2495 + static public Expr parse(C context, IPersistentMap form) throws Exception{ 1.2496 + IPersistentVector keyvals = PersistentVector.EMPTY; 1.2497 + for(ISeq s = RT.seq(form); s != null; s = s.next()) 1.2498 + { 1.2499 + IMapEntry e = (IMapEntry) s.first(); 1.2500 + keyvals = (IPersistentVector) keyvals.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e.key())); 1.2501 + keyvals = (IPersistentVector) keyvals.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e.val())); 1.2502 + } 1.2503 + Expr ret = new MapExpr(keyvals); 1.2504 + if(form instanceof IObj && ((IObj) form).meta() != null) 1.2505 + return new MetaExpr(ret, (MapExpr) MapExpr 1.2506 + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); 1.2507 + else 1.2508 + return ret; 1.2509 + } 1.2510 +} 1.2511 + 1.2512 +public static class SetExpr implements Expr{ 1.2513 + public final IPersistentVector keys; 1.2514 + final static Method setMethod = Method.getMethod("clojure.lang.IPersistentSet set(Object[])"); 1.2515 + 1.2516 + 1.2517 + public SetExpr(IPersistentVector keys){ 1.2518 + this.keys = keys; 1.2519 + } 1.2520 + 1.2521 + public Object eval() throws Exception{ 1.2522 + Object[] ret = new Object[keys.count()]; 1.2523 + for(int i = 0; i < keys.count(); i++) 1.2524 + ret[i] = ((Expr) keys.nth(i)).eval(); 1.2525 + return RT.set(ret); 1.2526 + } 1.2527 + 1.2528 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2529 + MethodExpr.emitArgsAsArray(keys, objx, gen); 1.2530 + gen.invokeStatic(RT_TYPE, setMethod); 1.2531 + if(context == C.STATEMENT) 1.2532 + gen.pop(); 1.2533 + } 1.2534 + 1.2535 + public boolean hasJavaClass() throws Exception{ 1.2536 + return true; 1.2537 + } 1.2538 + 1.2539 + public Class getJavaClass() throws Exception{ 1.2540 + return IPersistentSet.class; 1.2541 + } 1.2542 + 1.2543 + 1.2544 + static public Expr parse(C context, IPersistentSet form) throws Exception{ 1.2545 + IPersistentVector keys = PersistentVector.EMPTY; 1.2546 + for(ISeq s = RT.seq(form); s != null; s = s.next()) 1.2547 + { 1.2548 + Object e = s.first(); 1.2549 + keys = (IPersistentVector) keys.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e)); 1.2550 + } 1.2551 + Expr ret = new SetExpr(keys); 1.2552 + if(form instanceof IObj && ((IObj) form).meta() != null) 1.2553 + return new MetaExpr(ret, (MapExpr) MapExpr 1.2554 + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); 1.2555 + else 1.2556 + return ret; 1.2557 + } 1.2558 +} 1.2559 + 1.2560 +public static class VectorExpr implements Expr{ 1.2561 + public final IPersistentVector args; 1.2562 + final static Method vectorMethod = Method.getMethod("clojure.lang.IPersistentVector vector(Object[])"); 1.2563 + 1.2564 + 1.2565 + public VectorExpr(IPersistentVector args){ 1.2566 + this.args = args; 1.2567 + } 1.2568 + 1.2569 + public Object eval() throws Exception{ 1.2570 + IPersistentVector ret = PersistentVector.EMPTY; 1.2571 + for(int i = 0; i < args.count(); i++) 1.2572 + ret = (IPersistentVector) ret.cons(((Expr) args.nth(i)).eval()); 1.2573 + return ret; 1.2574 + } 1.2575 + 1.2576 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2577 + MethodExpr.emitArgsAsArray(args, objx, gen); 1.2578 + gen.invokeStatic(RT_TYPE, vectorMethod); 1.2579 + if(context == C.STATEMENT) 1.2580 + gen.pop(); 1.2581 + } 1.2582 + 1.2583 + public boolean hasJavaClass() throws Exception{ 1.2584 + return true; 1.2585 + } 1.2586 + 1.2587 + public Class getJavaClass() throws Exception{ 1.2588 + return IPersistentVector.class; 1.2589 + } 1.2590 + 1.2591 + static public Expr parse(C context, IPersistentVector form) throws Exception{ 1.2592 + IPersistentVector args = PersistentVector.EMPTY; 1.2593 + for(int i = 0; i < form.count(); i++) 1.2594 + args = (IPersistentVector) args.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, form.nth(i))); 1.2595 + Expr ret = new VectorExpr(args); 1.2596 + if(form instanceof IObj && ((IObj) form).meta() != null) 1.2597 + return new MetaExpr(ret, (MapExpr) MapExpr 1.2598 + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); 1.2599 + else 1.2600 + return ret; 1.2601 + } 1.2602 + 1.2603 +} 1.2604 + 1.2605 +static class KeywordInvokeExpr implements Expr{ 1.2606 + public final KeywordExpr kw; 1.2607 + public final Object tag; 1.2608 + public final Expr target; 1.2609 + public final int line; 1.2610 + public final int siteIndex; 1.2611 + public final String source; 1.2612 + static Type ILOOKUP_TYPE = Type.getType(ILookup.class); 1.2613 + 1.2614 + public KeywordInvokeExpr(String source, int line, Symbol tag, KeywordExpr kw, Expr target){ 1.2615 + this.source = source; 1.2616 + this.kw = kw; 1.2617 + this.target = target; 1.2618 + this.line = line; 1.2619 + this.tag = tag; 1.2620 + this.siteIndex = registerKeywordCallsite(kw.k); 1.2621 + } 1.2622 + 1.2623 + public Object eval() throws Exception{ 1.2624 + try 1.2625 + { 1.2626 + return kw.k.invoke(target.eval()); 1.2627 + } 1.2628 + catch(Throwable e) 1.2629 + { 1.2630 + if(!(e instanceof CompilerException)) 1.2631 + throw new CompilerException(source, line, e); 1.2632 + else 1.2633 + throw (CompilerException) e; 1.2634 + } 1.2635 + } 1.2636 + 1.2637 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2638 + Label endLabel = gen.newLabel(); 1.2639 + Label faultLabel = gen.newLabel(); 1.2640 + 1.2641 + gen.visitLineNumber(line, gen.mark()); 1.2642 + gen.getStatic(objx.objtype, objx.thunkNameStatic(siteIndex),ObjExpr.ILOOKUP_THUNK_TYPE); 1.2643 + gen.dup(); 1.2644 + target.emit(C.EXPRESSION, objx, gen); 1.2645 + gen.dupX2(); 1.2646 + gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE, Method.getMethod("Object get(Object)")); 1.2647 + gen.dupX2(); 1.2648 + gen.visitJumpInsn(IF_ACMPEQ, faultLabel); 1.2649 + gen.pop(); 1.2650 + gen.goTo(endLabel); 1.2651 + 1.2652 + gen.mark(faultLabel); 1.2653 + gen.swap(); 1.2654 + gen.pop(); 1.2655 + gen.getStatic(objx.objtype, objx.siteNameStatic(siteIndex),ObjExpr.KEYWORD_LOOKUPSITE_TYPE); 1.2656 + gen.swap(); 1.2657 + gen.loadThis(); 1.2658 + gen.invokeInterface(ObjExpr.ILOOKUP_SITE_TYPE, 1.2659 + Method.getMethod("Object fault(Object, clojure.lang.ILookupHost)")); 1.2660 + 1.2661 + gen.mark(endLabel); 1.2662 + if(context == C.STATEMENT) 1.2663 + gen.pop(); 1.2664 + } 1.2665 + 1.2666 + public void emit2(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2667 + Label endLabel = gen.newLabel(); 1.2668 + Label faultLabel = gen.newLabel(); 1.2669 + 1.2670 + gen.visitLineNumber(line, gen.mark()); 1.2671 + target.emit(C.EXPRESSION, objx, gen); 1.2672 + gen.dup(); 1.2673 + gen.getStatic(objx.objtype, objx.thunkNameStatic(siteIndex),ObjExpr.ILOOKUP_THUNK_TYPE); 1.2674 + gen.swap(); 1.2675 + gen.getStatic(objx.objtype, objx.siteNameStatic(siteIndex),ObjExpr.KEYWORD_LOOKUPSITE_TYPE); 1.2676 +/// gen.loadThis(); 1.2677 + gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE, 1.2678 + Method.getMethod("Object get(Object,clojure.lang.ILookupSite)")); 1.2679 +// gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE, 1.2680 +// Method.getMethod("Object get(Object,clojure.lang.ILookupSite,clojure.lang.ILookupHost)")); 1.2681 + gen.dup(); 1.2682 + gen.getStatic(objx.objtype, objx.siteNameStatic(siteIndex),ObjExpr.KEYWORD_LOOKUPSITE_TYPE); 1.2683 + gen.visitJumpInsn(IF_ACMPEQ, faultLabel); 1.2684 + gen.swap(); 1.2685 + gen.pop(); 1.2686 + gen.goTo(endLabel); 1.2687 + 1.2688 + gen.mark(faultLabel); 1.2689 + gen.swap(); 1.2690 + gen.loadThis(); 1.2691 + gen.invokeInterface(ObjExpr.ILOOKUP_SITE_TYPE, 1.2692 + Method.getMethod("Object fault(Object, clojure.lang.ILookupHost)")); 1.2693 + 1.2694 + gen.mark(endLabel); 1.2695 + if(context == C.STATEMENT) 1.2696 + gen.pop(); 1.2697 + } 1.2698 + 1.2699 + public void emitInstance(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2700 + gen.visitLineNumber(line, gen.mark()); 1.2701 + gen.loadThis(); 1.2702 + gen.getField(objx.objtype, objx.thunkName(siteIndex),ObjExpr.ILOOKUP_THUNK_TYPE); 1.2703 + target.emit(C.EXPRESSION, objx, gen); 1.2704 + gen.loadThis(); 1.2705 + gen.getField(objx.objtype, objx.siteName(siteIndex),ObjExpr.ILOOKUP_SITE_TYPE); 1.2706 + gen.loadThis(); 1.2707 + gen.checkCast(Type.getType(ILookupHost.class)); 1.2708 + gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE, 1.2709 + Method.getMethod("Object get(Object,clojure.lang.ILookupSite,clojure.lang.ILookupHost)")); 1.2710 + if(context == C.STATEMENT) 1.2711 + gen.pop(); 1.2712 + } 1.2713 + 1.2714 + public void emitNormal(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2715 + Label slowLabel = gen.newLabel(); 1.2716 + Label endLabel = gen.newLabel(); 1.2717 + 1.2718 + gen.visitLineNumber(line, gen.mark()); 1.2719 + target.emit(C.EXPRESSION, objx, gen); 1.2720 + gen.dup(); 1.2721 + gen.instanceOf(ILOOKUP_TYPE); 1.2722 + gen.ifZCmp(GeneratorAdapter.EQ, slowLabel); 1.2723 + kw.emit(C.EXPRESSION, objx, gen); 1.2724 + gen.invokeInterface(ILOOKUP_TYPE, new Method("valAt", OBJECT_TYPE, ARG_TYPES[1])); 1.2725 + gen.goTo(endLabel); 1.2726 + 1.2727 + gen.mark(slowLabel); 1.2728 + kw.emit(C.EXPRESSION, objx, gen); 1.2729 + gen.invokeStatic(RT_TYPE, new Method("get", OBJECT_TYPE, ARG_TYPES[2])); 1.2730 + 1.2731 + gen.mark(endLabel); 1.2732 + 1.2733 + if(context == C.STATEMENT) 1.2734 + gen.pop(); 1.2735 + } 1.2736 + 1.2737 + public boolean hasJavaClass() throws Exception{ 1.2738 + return tag != null; 1.2739 + } 1.2740 + 1.2741 + public Class getJavaClass() throws Exception{ 1.2742 + return HostExpr.tagToClass(tag); 1.2743 + } 1.2744 + 1.2745 +} 1.2746 +//static class KeywordSiteInvokeExpr implements Expr{ 1.2747 +// public final Expr site; 1.2748 +// public final Object tag; 1.2749 +// public final Expr target; 1.2750 +// public final int line; 1.2751 +// public final String source; 1.2752 +// 1.2753 +// public KeywordSiteInvokeExpr(String source, int line, Symbol tag, Expr site, Expr target){ 1.2754 +// this.source = source; 1.2755 +// this.site = site; 1.2756 +// this.target = target; 1.2757 +// this.line = line; 1.2758 +// this.tag = tag; 1.2759 +// } 1.2760 +// 1.2761 +// public Object eval() throws Exception{ 1.2762 +// try 1.2763 +// { 1.2764 +// KeywordCallSite s = (KeywordCallSite) site.eval(); 1.2765 +// return s.thunk.invoke(s,target.eval()); 1.2766 +// } 1.2767 +// catch(Throwable e) 1.2768 +// { 1.2769 +// if(!(e instanceof CompilerException)) 1.2770 +// throw new CompilerException(source, line, e); 1.2771 +// else 1.2772 +// throw (CompilerException) e; 1.2773 +// } 1.2774 +// } 1.2775 +// 1.2776 +// public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2777 +// gen.visitLineNumber(line, gen.mark()); 1.2778 +// site.emit(C.EXPRESSION, objx, gen); 1.2779 +// gen.dup(); 1.2780 +// gen.getField(Type.getType(KeywordCallSite.class),"thunk",IFN_TYPE); 1.2781 +// gen.swap(); 1.2782 +// target.emit(C.EXPRESSION, objx, gen); 1.2783 +// 1.2784 +// gen.invokeInterface(IFN_TYPE, new Method("invoke", OBJECT_TYPE, ARG_TYPES[2])); 1.2785 +// if(context == C.STATEMENT) 1.2786 +// gen.pop(); 1.2787 +// } 1.2788 +// 1.2789 +// public boolean hasJavaClass() throws Exception{ 1.2790 +// return tag != null; 1.2791 +// } 1.2792 +// 1.2793 +// public Class getJavaClass() throws Exception{ 1.2794 +// return HostExpr.tagToClass(tag); 1.2795 +// } 1.2796 +// 1.2797 +//} 1.2798 + 1.2799 +public static class InstanceOfExpr implements Expr, MaybePrimitiveExpr{ 1.2800 + Expr expr; 1.2801 + Class c; 1.2802 + 1.2803 + public InstanceOfExpr(Class c, Expr expr){ 1.2804 + this.expr = expr; 1.2805 + this.c = c; 1.2806 + } 1.2807 + 1.2808 + public Object eval() throws Exception{ 1.2809 + if(c.isInstance(expr.eval())) 1.2810 + return RT.T; 1.2811 + return RT.F; 1.2812 + } 1.2813 + 1.2814 + public boolean canEmitPrimitive(){ 1.2815 + return true; 1.2816 + } 1.2817 + 1.2818 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2819 + expr.emit(C.EXPRESSION,objx,gen); 1.2820 + gen.instanceOf(Type.getType(c)); 1.2821 + } 1.2822 + 1.2823 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2824 + emitUnboxed(context,objx,gen); 1.2825 + HostExpr.emitBoxReturn(objx,gen,Boolean.TYPE); 1.2826 + if(context == C.STATEMENT) 1.2827 + gen.pop(); 1.2828 + } 1.2829 + 1.2830 + public boolean hasJavaClass() throws Exception{ 1.2831 + return true; 1.2832 + } 1.2833 + 1.2834 + public Class getJavaClass() throws Exception{ 1.2835 + return Boolean.TYPE; 1.2836 + } 1.2837 + 1.2838 +} 1.2839 + 1.2840 +static class InvokeExpr implements Expr{ 1.2841 + public final Expr fexpr; 1.2842 + public final Object tag; 1.2843 + public final IPersistentVector args; 1.2844 + public final int line; 1.2845 + public final String source; 1.2846 + public boolean isProtocol = false; 1.2847 + public boolean isDirect = false; 1.2848 + public int siteIndex = -1; 1.2849 + public Class protocolOn; 1.2850 + public java.lang.reflect.Method onMethod; 1.2851 + static Keyword onKey = Keyword.intern("on"); 1.2852 + static Keyword methodMapKey = Keyword.intern("method-map"); 1.2853 + static Keyword dynamicKey = Keyword.intern("dynamic"); 1.2854 + 1.2855 + public InvokeExpr(String source, int line, Symbol tag, Expr fexpr, IPersistentVector args) throws Exception{ 1.2856 + this.source = source; 1.2857 + this.fexpr = fexpr; 1.2858 + this.args = args; 1.2859 + this.line = line; 1.2860 + if(fexpr instanceof VarExpr) 1.2861 + { 1.2862 + Var fvar = ((VarExpr)fexpr).var; 1.2863 + Var pvar = (Var)RT.get(fvar.meta(), protocolKey); 1.2864 + if(pvar != null && PROTOCOL_CALLSITES.isBound()) 1.2865 + { 1.2866 + this.isProtocol = true; 1.2867 + this.siteIndex = registerProtocolCallsite(((VarExpr)fexpr).var); 1.2868 + Object pon = RT.get(pvar.get(), onKey); 1.2869 + this.protocolOn = HostExpr.maybeClass(pon,false); 1.2870 + if(this.protocolOn != null) 1.2871 + { 1.2872 + IPersistentMap mmap = (IPersistentMap) RT.get(pvar.get(), methodMapKey); 1.2873 + Keyword mmapVal = (Keyword) mmap.valAt(Keyword.intern(fvar.sym)); 1.2874 + if (mmapVal == null) { 1.2875 + throw new IllegalArgumentException( 1.2876 + "No method of interface: " + protocolOn.getName() + 1.2877 + " found for function: " + fvar.sym + " of protocol: " + pvar.sym + 1.2878 + " (The protocol method may have been defined before and removed.)"); 1.2879 + } 1.2880 + String mname = munge(mmapVal.sym.toString()); 1.2881 + List methods = Reflector.getMethods(protocolOn, args.count() - 1, mname, false); 1.2882 + if(methods.size() != 1) 1.2883 + throw new IllegalArgumentException( 1.2884 + "No single method: " + mname + " of interface: " + protocolOn.getName() + 1.2885 + " found for function: " + fvar.sym + " of protocol: " + pvar.sym); 1.2886 + this.onMethod = (java.lang.reflect.Method) methods.get(0); 1.2887 + } 1.2888 + } 1.2889 +// else if(pvar == null && VAR_CALLSITES.isBound() 1.2890 +// && fvar.ns.name.name.startsWith("clojure") 1.2891 +// && !RT.booleanCast(RT.get(RT.meta(fvar),dynamicKey)) 1.2892 +// ) 1.2893 +// { 1.2894 +// //todo - more specific criteria for binding these 1.2895 +// this.isDirect = true; 1.2896 +// this.siteIndex = registerVarCallsite(((VarExpr) fexpr).var); 1.2897 +// } 1.2898 + } 1.2899 + this.tag = tag != null ? tag : (fexpr instanceof VarExpr ? ((VarExpr) fexpr).tag : null); 1.2900 + } 1.2901 + 1.2902 + public Object eval() throws Exception{ 1.2903 + try 1.2904 + { 1.2905 + IFn fn = (IFn) fexpr.eval(); 1.2906 + PersistentVector argvs = PersistentVector.EMPTY; 1.2907 + for(int i = 0; i < args.count(); i++) 1.2908 + argvs = argvs.cons(((Expr) args.nth(i)).eval()); 1.2909 + return fn.applyTo(RT.seq(argvs)); 1.2910 + } 1.2911 + catch(Throwable e) 1.2912 + { 1.2913 + if(!(e instanceof CompilerException)) 1.2914 + throw new CompilerException(source, line, e); 1.2915 + else 1.2916 + throw (CompilerException) e; 1.2917 + } 1.2918 + } 1.2919 + 1.2920 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2921 + gen.visitLineNumber(line, gen.mark()); 1.2922 + if(isProtocol) 1.2923 + { 1.2924 + emitProto(context,objx,gen); 1.2925 + } 1.2926 + else if(isDirect) 1.2927 + { 1.2928 + Label callLabel = gen.newLabel(); 1.2929 + 1.2930 + gen.getStatic(objx.objtype, objx.varCallsiteName(siteIndex), IFN_TYPE); 1.2931 + gen.dup(); 1.2932 + gen.ifNonNull(callLabel); 1.2933 + 1.2934 + gen.pop(); 1.2935 + fexpr.emit(C.EXPRESSION, objx, gen); 1.2936 + gen.checkCast(IFN_TYPE); 1.2937 +// gen.dup(); 1.2938 +// gen.putStatic(objx.objtype, objx.varCallsiteName(siteIndex), IFN_TYPE); 1.2939 + 1.2940 + gen.mark(callLabel); 1.2941 + emitArgsAndCall(0, context,objx,gen); 1.2942 + } 1.2943 + else 1.2944 + { 1.2945 + fexpr.emit(C.EXPRESSION, objx, gen); 1.2946 + gen.checkCast(IFN_TYPE); 1.2947 + emitArgsAndCall(0, context,objx,gen); 1.2948 + } 1.2949 + if(context == C.STATEMENT) 1.2950 + gen.pop(); 1.2951 + } 1.2952 + 1.2953 + public void emitProto(C context, ObjExpr objx, GeneratorAdapter gen){ 1.2954 + Label onLabel = gen.newLabel(); 1.2955 + Label callLabel = gen.newLabel(); 1.2956 + Label endLabel = gen.newLabel(); 1.2957 + 1.2958 + Var v = ((VarExpr)fexpr).var; 1.2959 + 1.2960 + Expr e = (Expr) args.nth(0); 1.2961 + e.emit(C.EXPRESSION, objx, gen); 1.2962 + gen.dup(); //target, target 1.2963 + gen.invokeStatic(UTIL_TYPE,Method.getMethod("Class classOf(Object)")); //target,class 1.2964 + gen.loadThis(); 1.2965 + gen.getField(objx.objtype, objx.cachedClassName(siteIndex),CLASS_TYPE); //target,class,cached-class 1.2966 + gen.visitJumpInsn(IF_ACMPEQ, callLabel); //target 1.2967 + if(protocolOn != null) 1.2968 + { 1.2969 + gen.dup(); //target, target 1.2970 + gen.instanceOf(Type.getType(protocolOn)); 1.2971 + gen.ifZCmp(GeneratorAdapter.NE, onLabel); 1.2972 + } 1.2973 + 1.2974 + gen.mark(callLabel); //target 1.2975 + gen.dup(); //target, target 1.2976 + gen.invokeStatic(UTIL_TYPE,Method.getMethod("Class classOf(Object)")); //target,class 1.2977 + gen.loadThis(); 1.2978 + gen.swap(); 1.2979 + gen.putField(objx.objtype, objx.cachedClassName(siteIndex),CLASS_TYPE); //target 1.2980 + objx.emitVar(gen, v); 1.2981 + gen.invokeVirtual(VAR_TYPE, Method.getMethod("Object getRawRoot()")); //target, proto-fn 1.2982 + gen.swap(); 1.2983 + emitArgsAndCall(1, context,objx,gen); 1.2984 + gen.goTo(endLabel); 1.2985 + 1.2986 + gen.mark(onLabel); //target 1.2987 + if(protocolOn != null) 1.2988 + { 1.2989 + MethodExpr.emitTypedArgs(objx, gen, onMethod.getParameterTypes(), RT.subvec(args,1,args.count())); 1.2990 + if(context == C.RETURN) 1.2991 + { 1.2992 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.2993 + method.emitClearLocals(gen); 1.2994 + } 1.2995 + Method m = new Method(onMethod.getName(), Type.getReturnType(onMethod), Type.getArgumentTypes(onMethod)); 1.2996 + gen.invokeInterface(Type.getType(protocolOn), m); 1.2997 + HostExpr.emitBoxReturn(objx, gen, onMethod.getReturnType()); 1.2998 + } 1.2999 + gen.mark(endLabel); 1.3000 + } 1.3001 + 1.3002 + void emitArgsAndCall(int firstArgToEmit, C context, ObjExpr objx, GeneratorAdapter gen){ 1.3003 + for(int i = firstArgToEmit; i < Math.min(MAX_POSITIONAL_ARITY, args.count()); i++) 1.3004 + { 1.3005 + Expr e = (Expr) args.nth(i); 1.3006 + e.emit(C.EXPRESSION, objx, gen); 1.3007 + } 1.3008 + if(args.count() > MAX_POSITIONAL_ARITY) 1.3009 + { 1.3010 + PersistentVector restArgs = PersistentVector.EMPTY; 1.3011 + for(int i = MAX_POSITIONAL_ARITY; i < args.count(); i++) 1.3012 + { 1.3013 + restArgs = restArgs.cons(args.nth(i)); 1.3014 + } 1.3015 + MethodExpr.emitArgsAsArray(restArgs, objx, gen); 1.3016 + } 1.3017 + 1.3018 + if(context == C.RETURN) 1.3019 + { 1.3020 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.3021 + method.emitClearLocals(gen); 1.3022 + } 1.3023 + 1.3024 + gen.invokeInterface(IFN_TYPE, new Method("invoke", OBJECT_TYPE, ARG_TYPES[Math.min(MAX_POSITIONAL_ARITY + 1, 1.3025 + args.count())])); 1.3026 + } 1.3027 + 1.3028 + public boolean hasJavaClass() throws Exception{ 1.3029 + return tag != null; 1.3030 + } 1.3031 + 1.3032 + public Class getJavaClass() throws Exception{ 1.3033 + return HostExpr.tagToClass(tag); 1.3034 + } 1.3035 + 1.3036 + static public Expr parse(C context, ISeq form) throws Exception{ 1.3037 + if(context != C.EVAL) 1.3038 + context = C.EXPRESSION; 1.3039 + Expr fexpr = analyze(context, form.first()); 1.3040 + if(fexpr instanceof VarExpr && ((VarExpr)fexpr).var.equals(INSTANCE)) 1.3041 + { 1.3042 + if(RT.second(form) instanceof Symbol) 1.3043 + { 1.3044 + Class c = HostExpr.maybeClass(RT.second(form),false); 1.3045 + if(c != null) 1.3046 + return new InstanceOfExpr(c, analyze(context, RT.third(form))); 1.3047 + } 1.3048 + } 1.3049 + 1.3050 + if(fexpr instanceof KeywordExpr && RT.count(form) == 2 && KEYWORD_CALLSITES.isBound()) 1.3051 + { 1.3052 +// fexpr = new ConstantExpr(new KeywordCallSite(((KeywordExpr)fexpr).k)); 1.3053 + Expr target = analyze(context, RT.second(form)); 1.3054 + return new KeywordInvokeExpr((String) SOURCE.deref(), (Integer) LINE.deref(), tagOf(form), 1.3055 + (KeywordExpr) fexpr, target); 1.3056 + } 1.3057 + PersistentVector args = PersistentVector.EMPTY; 1.3058 + for(ISeq s = RT.seq(form.next()); s != null; s = s.next()) 1.3059 + { 1.3060 + args = args.cons(analyze(context, s.first())); 1.3061 + } 1.3062 +// if(args.count() > MAX_POSITIONAL_ARITY) 1.3063 +// throw new IllegalArgumentException( 1.3064 +// String.format("No more than %d args supported", MAX_POSITIONAL_ARITY)); 1.3065 + 1.3066 + return new InvokeExpr((String) SOURCE.deref(), (Integer) LINE.deref(), tagOf(form), fexpr, args); 1.3067 + } 1.3068 +} 1.3069 + 1.3070 +static class SourceDebugExtensionAttribute extends Attribute{ 1.3071 + public SourceDebugExtensionAttribute(){ 1.3072 + super("SourceDebugExtension"); 1.3073 + } 1.3074 + 1.3075 + void writeSMAP(ClassWriter cw, String smap){ 1.3076 + ByteVector bv = write(cw, null, -1, -1, -1); 1.3077 + bv.putUTF8(smap); 1.3078 + } 1.3079 +} 1.3080 + 1.3081 +static public class FnExpr extends ObjExpr{ 1.3082 + final static Type aFnType = Type.getType(AFunction.class); 1.3083 + final static Type restFnType = Type.getType(RestFn.class); 1.3084 + //if there is a variadic overload (there can only be one) it is stored here 1.3085 + FnMethod variadicMethod = null; 1.3086 + IPersistentCollection methods; 1.3087 + // String superName = null; 1.3088 + 1.3089 + public FnExpr(Object tag){ 1.3090 + super(tag); 1.3091 + } 1.3092 + 1.3093 + public boolean hasJavaClass() throws Exception{ 1.3094 + return true; 1.3095 + } 1.3096 + 1.3097 + public Class getJavaClass() throws Exception{ 1.3098 + return AFunction.class; 1.3099 + } 1.3100 + 1.3101 + protected void emitMethods(ClassVisitor cv){ 1.3102 + //override of invoke/doInvoke for each method 1.3103 + for(ISeq s = RT.seq(methods); s != null; s = s.next()) 1.3104 + { 1.3105 + ObjMethod method = (ObjMethod) s.first(); 1.3106 + method.emit(this, cv); 1.3107 + } 1.3108 + 1.3109 + if(isVariadic()) 1.3110 + { 1.3111 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, 1.3112 + Method.getMethod("int getRequiredArity()"), 1.3113 + null, 1.3114 + null, 1.3115 + cv); 1.3116 + gen.visitCode(); 1.3117 + gen.push(variadicMethod.reqParms.count()); 1.3118 + gen.returnValue(); 1.3119 + gen.endMethod(); 1.3120 + } 1.3121 + } 1.3122 + 1.3123 + static Expr parse(C context, ISeq form, String name) throws Exception{ 1.3124 + ISeq origForm = form; 1.3125 + FnExpr fn = new FnExpr(tagOf(form)); 1.3126 + fn.src = form; 1.3127 + ObjMethod enclosingMethod = (ObjMethod) METHOD.deref(); 1.3128 + if(((IMeta) form.first()).meta() != null) 1.3129 + { 1.3130 + fn.onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), Keyword.intern(null, "once"))); 1.3131 +// fn.superName = (String) RT.get(RT.meta(form.first()), Keyword.intern(null, "super-name")); 1.3132 + } 1.3133 + //fn.thisName = name; 1.3134 + String basename = enclosingMethod != null ? 1.3135 + (enclosingMethod.objx.name + "$") 1.3136 + : //"clojure.fns." + 1.3137 + (munge(currentNS().name.name) + "$"); 1.3138 + if(RT.second(form) instanceof Symbol) 1.3139 + name = ((Symbol) RT.second(form)).name; 1.3140 + String simpleName = name != null ? 1.3141 + (munge(name).replace(".", "_DOT_") 1.3142 + + (enclosingMethod != null ? "__" + RT.nextID() : "")) 1.3143 + : ("fn" 1.3144 + + "__" + RT.nextID()); 1.3145 + fn.name = basename + simpleName; 1.3146 + fn.internalName = fn.name.replace('.', '/'); 1.3147 + fn.objtype = Type.getObjectType(fn.internalName); 1.3148 + try 1.3149 + { 1.3150 + Var.pushThreadBindings( 1.3151 + RT.map(CONSTANTS, PersistentVector.EMPTY, 1.3152 + CONSTANT_IDS, new IdentityHashMap(), 1.3153 + KEYWORDS, PersistentHashMap.EMPTY, 1.3154 + VARS, PersistentHashMap.EMPTY, 1.3155 + KEYWORD_CALLSITES, PersistentVector.EMPTY, 1.3156 + PROTOCOL_CALLSITES, PersistentVector.EMPTY, 1.3157 + VAR_CALLSITES, PersistentVector.EMPTY 1.3158 + )); 1.3159 + 1.3160 + //arglist might be preceded by symbol naming this fn 1.3161 + if(RT.second(form) instanceof Symbol) 1.3162 + { 1.3163 + fn.thisName = ((Symbol) RT.second(form)).name; 1.3164 + form = RT.cons(FN, RT.next(RT.next(form))); 1.3165 + } 1.3166 + 1.3167 + //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...) 1.3168 + //turn former into latter 1.3169 + if(RT.second(form) instanceof IPersistentVector) 1.3170 + form = RT.list(FN, RT.next(form)); 1.3171 + fn.line = (Integer) LINE.deref(); 1.3172 + FnMethod[] methodArray = new FnMethod[MAX_POSITIONAL_ARITY + 1]; 1.3173 + FnMethod variadicMethod = null; 1.3174 + for(ISeq s = RT.next(form); s != null; s = RT.next(s)) 1.3175 + { 1.3176 + FnMethod f = FnMethod.parse(fn, (ISeq) RT.first(s)); 1.3177 + if(f.isVariadic()) 1.3178 + { 1.3179 + if(variadicMethod == null) 1.3180 + variadicMethod = f; 1.3181 + else 1.3182 + throw new Exception("Can't have more than 1 variadic overload"); 1.3183 + } 1.3184 + else if(methodArray[f.reqParms.count()] == null) 1.3185 + methodArray[f.reqParms.count()] = f; 1.3186 + else 1.3187 + throw new Exception("Can't have 2 overloads with same arity"); 1.3188 + } 1.3189 + if(variadicMethod != null) 1.3190 + { 1.3191 + for(int i = variadicMethod.reqParms.count() + 1; i <= MAX_POSITIONAL_ARITY; i++) 1.3192 + if(methodArray[i] != null) 1.3193 + throw new Exception( 1.3194 + "Can't have fixed arity function with more params than variadic function"); 1.3195 + } 1.3196 + 1.3197 + IPersistentCollection methods = null; 1.3198 + for(int i = 0; i < methodArray.length; i++) 1.3199 + if(methodArray[i] != null) 1.3200 + methods = RT.conj(methods, methodArray[i]); 1.3201 + if(variadicMethod != null) 1.3202 + methods = RT.conj(methods, variadicMethod); 1.3203 + 1.3204 + fn.methods = methods; 1.3205 + fn.variadicMethod = variadicMethod; 1.3206 + fn.keywords = (IPersistentMap) KEYWORDS.deref(); 1.3207 + fn.vars = (IPersistentMap) VARS.deref(); 1.3208 + fn.constants = (PersistentVector) CONSTANTS.deref(); 1.3209 + fn.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); 1.3210 + fn.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); 1.3211 + fn.varCallsites = (IPersistentVector) VAR_CALLSITES.deref(); 1.3212 + 1.3213 + fn.constantsID = RT.nextID(); 1.3214 +// DynamicClassLoader loader = (DynamicClassLoader) LOADER.get(); 1.3215 +// loader.registerConstants(fn.constantsID, fn.constants.toArray()); 1.3216 + } 1.3217 + finally 1.3218 + { 1.3219 + Var.popThreadBindings(); 1.3220 + } 1.3221 + fn.compile(fn.isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction",null,fn.onceOnly); 1.3222 + fn.getCompiledClass(); 1.3223 + 1.3224 + if(origForm instanceof IObj && ((IObj) origForm).meta() != null) 1.3225 + return new MetaExpr(fn, (MapExpr) MapExpr 1.3226 + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) origForm).meta())); 1.3227 + else 1.3228 + return fn; 1.3229 + } 1.3230 + 1.3231 + public final ObjMethod variadicMethod(){ 1.3232 + return variadicMethod; 1.3233 + } 1.3234 + 1.3235 + boolean isVariadic(){ 1.3236 + return variadicMethod != null; 1.3237 + } 1.3238 + 1.3239 + public final IPersistentCollection methods(){ 1.3240 + return methods; 1.3241 + } 1.3242 +} 1.3243 + 1.3244 +static public class ObjExpr implements Expr{ 1.3245 + static final String CONST_PREFIX = "const__"; 1.3246 + String name; 1.3247 + //String simpleName; 1.3248 + String internalName; 1.3249 + String thisName; 1.3250 + Type objtype; 1.3251 + public final Object tag; 1.3252 + //localbinding->itself 1.3253 + IPersistentMap closes = PersistentHashMap.EMPTY; 1.3254 + //localbndingexprs 1.3255 + IPersistentVector closesExprs = PersistentVector.EMPTY; 1.3256 + //symbols 1.3257 + IPersistentSet volatiles = PersistentHashSet.EMPTY; 1.3258 + 1.3259 + //symbol->lb 1.3260 + IPersistentMap fields = null; 1.3261 + 1.3262 + //Keyword->KeywordExpr 1.3263 + IPersistentMap keywords = PersistentHashMap.EMPTY; 1.3264 + IPersistentMap vars = PersistentHashMap.EMPTY; 1.3265 + Class compiledClass; 1.3266 + int line; 1.3267 + PersistentVector constants; 1.3268 + int constantsID; 1.3269 + int altCtorDrops = 0; 1.3270 + 1.3271 + IPersistentVector keywordCallsites; 1.3272 + IPersistentVector protocolCallsites; 1.3273 + IPersistentVector varCallsites; 1.3274 + boolean onceOnly = false; 1.3275 + 1.3276 + Object src; 1.3277 + 1.3278 + final static Method voidctor = Method.getMethod("void <init>()"); 1.3279 + protected IPersistentMap classMeta; 1.3280 + 1.3281 + public final String name(){ 1.3282 + return name; 1.3283 + } 1.3284 + 1.3285 +// public final String simpleName(){ 1.3286 +// return simpleName; 1.3287 +// } 1.3288 + 1.3289 + public final String internalName(){ 1.3290 + return internalName; 1.3291 + } 1.3292 + 1.3293 + public final String thisName(){ 1.3294 + return thisName; 1.3295 + } 1.3296 + 1.3297 + public final Type objtype(){ 1.3298 + return objtype; 1.3299 + } 1.3300 + 1.3301 + public final IPersistentMap closes(){ 1.3302 + return closes; 1.3303 + } 1.3304 + 1.3305 + public final IPersistentMap keywords(){ 1.3306 + return keywords; 1.3307 + } 1.3308 + 1.3309 + public final IPersistentMap vars(){ 1.3310 + return vars; 1.3311 + } 1.3312 + 1.3313 + public final Class compiledClass(){ 1.3314 + return compiledClass; 1.3315 + } 1.3316 + 1.3317 + public final int line(){ 1.3318 + return line; 1.3319 + } 1.3320 + 1.3321 + public final PersistentVector constants(){ 1.3322 + return constants; 1.3323 + } 1.3324 + 1.3325 + public final int constantsID(){ 1.3326 + return constantsID; 1.3327 + } 1.3328 + 1.3329 + final static Method kwintern = Method.getMethod("clojure.lang.Keyword intern(String, String)"); 1.3330 + final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String)"); 1.3331 + final static Method varintern = 1.3332 + Method.getMethod("clojure.lang.Var intern(clojure.lang.Symbol, clojure.lang.Symbol)"); 1.3333 + 1.3334 + final static Type DYNAMIC_CLASSLOADER_TYPE = Type.getType(DynamicClassLoader.class); 1.3335 + final static Method getClassMethod = Method.getMethod("Class getClass()"); 1.3336 + final static Method getClassLoaderMethod = Method.getMethod("ClassLoader getClassLoader()"); 1.3337 + final static Method getConstantsMethod = Method.getMethod("Object[] getConstants(int)"); 1.3338 + final static Method readStringMethod = Method.getMethod("Object readString(String)"); 1.3339 + 1.3340 + final static Type ILOOKUP_SITE_TYPE = Type.getType(ILookupSite.class); 1.3341 + final static Type ILOOKUP_THUNK_TYPE = Type.getType(ILookupThunk.class); 1.3342 + final static Type KEYWORD_LOOKUPSITE_TYPE = Type.getType(KeywordLookupSite.class); 1.3343 + 1.3344 + private DynamicClassLoader loader; 1.3345 + private byte[] bytecode; 1.3346 + 1.3347 + public ObjExpr(Object tag){ 1.3348 + this.tag = tag; 1.3349 + } 1.3350 + 1.3351 + static String trimGenID(String name){ 1.3352 + int i = name.lastIndexOf("__"); 1.3353 + return i==-1?name:name.substring(0,i); 1.3354 + } 1.3355 + 1.3356 + 1.3357 + 1.3358 + Type[] ctorTypes(){ 1.3359 + IPersistentVector tv = isDeftype()?PersistentVector.EMPTY:RT.vector(IPERSISTENTMAP_TYPE); 1.3360 + for(ISeq s = RT.keys(closes); s != null; s = s.next()) 1.3361 + { 1.3362 + LocalBinding lb = (LocalBinding) s.first(); 1.3363 + if(lb.getPrimitiveType() != null) 1.3364 + tv = tv.cons(Type.getType(lb.getPrimitiveType())); 1.3365 + else 1.3366 + tv = tv.cons(OBJECT_TYPE); 1.3367 + } 1.3368 + Type[] ret = new Type[tv.count()]; 1.3369 + for(int i = 0; i < tv.count(); i++) 1.3370 + ret[i] = (Type) tv.nth(i); 1.3371 + return ret; 1.3372 + } 1.3373 + 1.3374 + void compile(String superName, String[] interfaceNames, boolean oneTimeUse) throws Exception{ 1.3375 + //create bytecode for a class 1.3376 + //with name current_ns.defname[$letname]+ 1.3377 + //anonymous fns get names fn__id 1.3378 + //derived from AFn/RestFn 1.3379 + if(keywordCallsites.count() > 0) 1.3380 + { 1.3381 + if(interfaceNames == null) 1.3382 + interfaceNames = new String[]{"clojure/lang/ILookupHost"}; 1.3383 + else 1.3384 + { 1.3385 + String[] inames = new String[interfaceNames.length + 1]; 1.3386 + System.arraycopy(interfaceNames,0,inames,0,interfaceNames.length); 1.3387 + inames[interfaceNames.length] = "clojure/lang/ILookupHost"; 1.3388 + interfaceNames = inames; 1.3389 + } 1.3390 + } 1.3391 + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 1.3392 +// ClassWriter cw = new ClassWriter(0); 1.3393 + ClassVisitor cv = cw; 1.3394 +// ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out)); 1.3395 + //ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out)); 1.3396 + cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER + ACC_FINAL, internalName, null,superName,interfaceNames); 1.3397 +// superName != null ? superName : 1.3398 +// (isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction"), null); 1.3399 + String source = (String) SOURCE.deref(); 1.3400 + int lineBefore = (Integer) LINE_BEFORE.deref(); 1.3401 + int lineAfter = (Integer) LINE_AFTER.deref() + 1; 1.3402 + 1.3403 + if(source != null && SOURCE_PATH.deref() != null) 1.3404 + { 1.3405 + //cv.visitSource(source, null); 1.3406 + String smap = "SMAP\n" + 1.3407 + ((source.lastIndexOf('.') > 0) ? 1.3408 + source.substring(0, source.lastIndexOf('.')) 1.3409 + :source) 1.3410 + // : simpleName) 1.3411 + + ".java\n" + 1.3412 + "Clojure\n" + 1.3413 + "*S Clojure\n" + 1.3414 + "*F\n" + 1.3415 + "+ 1 " + source + "\n" + 1.3416 + (String) SOURCE_PATH.deref() + "\n" + 1.3417 + "*L\n" + 1.3418 + String.format("%d#1,%d:%d\n", lineBefore, lineAfter - lineBefore, lineBefore) + 1.3419 + "*E"; 1.3420 + cv.visitSource(source, smap); 1.3421 + } 1.3422 + addAnnotation(cv, classMeta); 1.3423 + //static fields for constants 1.3424 + for(int i = 0; i < constants.count(); i++) 1.3425 + { 1.3426 + cv.visitField(ACC_PUBLIC + ACC_FINAL 1.3427 + + ACC_STATIC, constantName(i), constantType(i).getDescriptor(), 1.3428 + null, null); 1.3429 + } 1.3430 + 1.3431 + //static fields for lookup sites 1.3432 + for(int i = 0; i < keywordCallsites.count(); i++) 1.3433 + { 1.3434 + cv.visitField(ACC_FINAL 1.3435 + + ACC_STATIC, siteNameStatic(i), KEYWORD_LOOKUPSITE_TYPE.getDescriptor(), 1.3436 + null, null); 1.3437 + cv.visitField(ACC_STATIC, thunkNameStatic(i), ILOOKUP_THUNK_TYPE.getDescriptor(), 1.3438 + null, null); 1.3439 + } 1.3440 + 1.3441 + for(int i=0;i<varCallsites.count();i++) 1.3442 + { 1.3443 + cv.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL 1.3444 + , varCallsiteName(i), IFN_TYPE.getDescriptor(), null, null); 1.3445 + } 1.3446 + 1.3447 + //static init for constants, keywords and vars 1.3448 + GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, 1.3449 + Method.getMethod("void <clinit> ()"), 1.3450 + null, 1.3451 + null, 1.3452 + cv); 1.3453 + clinitgen.visitCode(); 1.3454 + clinitgen.visitLineNumber(line, clinitgen.mark()); 1.3455 + 1.3456 + if(constants.count() > 0) 1.3457 + { 1.3458 + emitConstants(clinitgen); 1.3459 + } 1.3460 + 1.3461 + if(keywordCallsites.count() > 0) 1.3462 + emitKeywordCallsites(clinitgen); 1.3463 + 1.3464 + for(int i=0;i<varCallsites.count();i++) 1.3465 + { 1.3466 + Label skipLabel = clinitgen.newLabel(); 1.3467 + Label endLabel = clinitgen.newLabel(); 1.3468 + Var var = (Var) varCallsites.nth(i); 1.3469 + clinitgen.push(var.ns.name.toString()); 1.3470 + clinitgen.push(var.sym.toString()); 1.3471 + clinitgen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)")); 1.3472 + clinitgen.dup(); 1.3473 + clinitgen.invokeVirtual(VAR_TYPE,Method.getMethod("boolean hasRoot()")); 1.3474 + clinitgen.ifZCmp(GeneratorAdapter.EQ,skipLabel); 1.3475 + 1.3476 + clinitgen.invokeVirtual(VAR_TYPE,Method.getMethod("Object getRoot()")); 1.3477 + clinitgen.dup(); 1.3478 + clinitgen.instanceOf(AFUNCTION_TYPE); 1.3479 + clinitgen.ifZCmp(GeneratorAdapter.EQ,skipLabel); 1.3480 + clinitgen.checkCast(IFN_TYPE); 1.3481 + clinitgen.putStatic(objtype, varCallsiteName(i), IFN_TYPE); 1.3482 + clinitgen.goTo(endLabel); 1.3483 + 1.3484 + clinitgen.mark(skipLabel); 1.3485 + clinitgen.pop(); 1.3486 + 1.3487 + clinitgen.mark(endLabel); 1.3488 + } 1.3489 + 1.3490 + clinitgen.returnValue(); 1.3491 + 1.3492 + clinitgen.endMethod(); 1.3493 + if(!isDeftype()) 1.3494 + { 1.3495 + cv.visitField(ACC_FINAL, "__meta", IPERSISTENTMAP_TYPE.getDescriptor(), null, null); 1.3496 + } 1.3497 + //instance fields for closed-overs 1.3498 + for(ISeq s = RT.keys(closes); s != null; s = s.next()) 1.3499 + { 1.3500 + LocalBinding lb = (LocalBinding) s.first(); 1.3501 + if(isDeftype()) 1.3502 + { 1.3503 + int access = isVolatile(lb) ? ACC_VOLATILE : 1.3504 + isMutable(lb) ? 0 : 1.3505 + (ACC_PUBLIC + ACC_FINAL); 1.3506 + FieldVisitor fv; 1.3507 + if(lb.getPrimitiveType() != null) 1.3508 + fv = cv.visitField(access 1.3509 + , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(), 1.3510 + null, null); 1.3511 + else 1.3512 + //todo - when closed-overs are fields, use more specific types here and in ctor and emitLocal? 1.3513 + fv = cv.visitField(access 1.3514 + , lb.name, OBJECT_TYPE.getDescriptor(), null, null); 1.3515 + addAnnotation(fv, RT.meta(lb.sym)); 1.3516 + } 1.3517 + else 1.3518 + { 1.3519 + //todo - only enable this non-private+writability for letfns where we need it 1.3520 + if(lb.getPrimitiveType() != null) 1.3521 + cv.visitField(0 + (isVolatile(lb) ? ACC_VOLATILE : 0) 1.3522 + , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(), 1.3523 + null, null); 1.3524 + else 1.3525 + cv.visitField(0 //+ (oneTimeUse ? 0 : ACC_FINAL) 1.3526 + , lb.name, OBJECT_TYPE.getDescriptor(), null, null); 1.3527 + } 1.3528 + } 1.3529 + 1.3530 + //instance fields for callsites and thunks 1.3531 + for(int i=0;i<protocolCallsites.count();i++) 1.3532 + { 1.3533 + cv.visitField(ACC_PRIVATE, cachedClassName(i), CLASS_TYPE.getDescriptor(), null, null); 1.3534 + cv.visitField(ACC_PRIVATE, cachedProtoFnName(i), AFUNCTION_TYPE.getDescriptor(), null, null); 1.3535 + cv.visitField(ACC_PRIVATE, cachedProtoImplName(i), IFN_TYPE.getDescriptor(), null, null); 1.3536 + } 1.3537 + 1.3538 + //ctor that takes closed-overs and inits base + fields 1.3539 + Method m = new Method("<init>", Type.VOID_TYPE, ctorTypes()); 1.3540 + GeneratorAdapter ctorgen = new GeneratorAdapter(ACC_PUBLIC, 1.3541 + m, 1.3542 + null, 1.3543 + null, 1.3544 + cv); 1.3545 + Label start = ctorgen.newLabel(); 1.3546 + Label end = ctorgen.newLabel(); 1.3547 + ctorgen.visitCode(); 1.3548 + ctorgen.visitLineNumber(line, ctorgen.mark()); 1.3549 + ctorgen.visitLabel(start); 1.3550 + ctorgen.loadThis(); 1.3551 +// if(superName != null) 1.3552 + ctorgen.invokeConstructor(Type.getObjectType(superName), voidctor); 1.3553 +// else if(isVariadic()) //RestFn ctor takes reqArity arg 1.3554 +// { 1.3555 +// ctorgen.push(variadicMethod.reqParms.count()); 1.3556 +// ctorgen.invokeConstructor(restFnType, restfnctor); 1.3557 +// } 1.3558 +// else 1.3559 +// ctorgen.invokeConstructor(aFnType, voidctor); 1.3560 + if(!isDeftype()) 1.3561 + { 1.3562 + ctorgen.loadThis(); 1.3563 + ctorgen.visitVarInsn(IPERSISTENTMAP_TYPE.getOpcode(Opcodes.ILOAD), 1); 1.3564 + ctorgen.putField(objtype, "__meta", IPERSISTENTMAP_TYPE); 1.3565 + } 1.3566 + 1.3567 + int a = isDeftype()?1:2; 1.3568 + for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a) 1.3569 + { 1.3570 + LocalBinding lb = (LocalBinding) s.first(); 1.3571 + ctorgen.loadThis(); 1.3572 + Class primc = lb.getPrimitiveType(); 1.3573 + if(primc != null) 1.3574 + { 1.3575 + ctorgen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ILOAD), a); 1.3576 + ctorgen.putField(objtype, lb.name, Type.getType(primc)); 1.3577 + if(primc == Long.TYPE || primc == Double.TYPE) 1.3578 + ++a; 1.3579 + } 1.3580 + else 1.3581 + { 1.3582 + ctorgen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), a); 1.3583 + ctorgen.putField(objtype, lb.name, OBJECT_TYPE); 1.3584 + } 1.3585 + closesExprs = closesExprs.cons(new LocalBindingExpr(lb, null)); 1.3586 + } 1.3587 + 1.3588 + 1.3589 + ctorgen.visitLabel(end); 1.3590 + 1.3591 + ctorgen.returnValue(); 1.3592 + 1.3593 + ctorgen.endMethod(); 1.3594 + 1.3595 + if(altCtorDrops > 0) 1.3596 + { 1.3597 + //ctor that takes closed-overs and inits base + fields 1.3598 + Type[] ctorTypes = ctorTypes(); 1.3599 + Type[] altCtorTypes = new Type[ctorTypes.length-altCtorDrops]; 1.3600 + for(int i=0;i<altCtorTypes.length;i++) 1.3601 + altCtorTypes[i] = ctorTypes[i]; 1.3602 + Method alt = new Method("<init>", Type.VOID_TYPE, altCtorTypes); 1.3603 + ctorgen = new GeneratorAdapter(ACC_PUBLIC, 1.3604 + alt, 1.3605 + null, 1.3606 + null, 1.3607 + cv); 1.3608 + ctorgen.visitCode(); 1.3609 + ctorgen.loadThis(); 1.3610 + ctorgen.loadArgs(); 1.3611 + for(int i=0;i<altCtorDrops;i++) 1.3612 + ctorgen.visitInsn(Opcodes.ACONST_NULL); 1.3613 + 1.3614 + ctorgen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes)); 1.3615 + 1.3616 + ctorgen.returnValue(); 1.3617 + ctorgen.endMethod(); 1.3618 + } 1.3619 + 1.3620 + if(!isDeftype()) 1.3621 + { 1.3622 + //ctor that takes closed-overs but not meta 1.3623 + Type[] ctorTypes = ctorTypes(); 1.3624 + Type[] noMetaCtorTypes = new Type[ctorTypes.length-1]; 1.3625 + for(int i=1;i<ctorTypes.length;i++) 1.3626 + noMetaCtorTypes[i-1] = ctorTypes[i]; 1.3627 + Method alt = new Method("<init>", Type.VOID_TYPE, noMetaCtorTypes); 1.3628 + ctorgen = new GeneratorAdapter(ACC_PUBLIC, 1.3629 + alt, 1.3630 + null, 1.3631 + null, 1.3632 + cv); 1.3633 + ctorgen.visitCode(); 1.3634 + ctorgen.loadThis(); 1.3635 + ctorgen.visitInsn(Opcodes.ACONST_NULL); //null meta 1.3636 + ctorgen.loadArgs(); 1.3637 + ctorgen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes)); 1.3638 + 1.3639 + ctorgen.returnValue(); 1.3640 + ctorgen.endMethod(); 1.3641 + 1.3642 + //meta() 1.3643 + Method meth = Method.getMethod("clojure.lang.IPersistentMap meta()"); 1.3644 + 1.3645 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, 1.3646 + meth, 1.3647 + null, 1.3648 + null, 1.3649 + cv); 1.3650 + gen.visitCode(); 1.3651 + gen.loadThis(); 1.3652 + gen.getField(objtype,"__meta",IPERSISTENTMAP_TYPE); 1.3653 + 1.3654 + gen.returnValue(); 1.3655 + gen.endMethod(); 1.3656 + 1.3657 + //withMeta() 1.3658 + meth = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)"); 1.3659 + 1.3660 + gen = new GeneratorAdapter(ACC_PUBLIC, 1.3661 + meth, 1.3662 + null, 1.3663 + null, 1.3664 + cv); 1.3665 + gen.visitCode(); 1.3666 + gen.newInstance(objtype); 1.3667 + gen.dup(); 1.3668 + gen.loadArg(0); 1.3669 + 1.3670 + for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a) 1.3671 + { 1.3672 + LocalBinding lb = (LocalBinding) s.first(); 1.3673 + gen.loadThis(); 1.3674 + Class primc = lb.getPrimitiveType(); 1.3675 + if(primc != null) 1.3676 + { 1.3677 + gen.getField(objtype, lb.name, Type.getType(primc)); 1.3678 + } 1.3679 + else 1.3680 + { 1.3681 + gen.getField(objtype, lb.name, OBJECT_TYPE); 1.3682 + } 1.3683 + } 1.3684 + 1.3685 + gen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes)); 1.3686 + gen.returnValue(); 1.3687 + gen.endMethod(); 1.3688 + } 1.3689 + 1.3690 + emitMethods(cv); 1.3691 + 1.3692 + if(keywordCallsites.count() > 0) 1.3693 + { 1.3694 + Method meth = Method.getMethod("void swapThunk(int,clojure.lang.ILookupThunk)"); 1.3695 + 1.3696 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, 1.3697 + meth, 1.3698 + null, 1.3699 + null, 1.3700 + cv); 1.3701 + gen.visitCode(); 1.3702 + Label endLabel = gen.newLabel(); 1.3703 + 1.3704 + Label[] labels = new Label[keywordCallsites.count()]; 1.3705 + for(int i = 0; i < keywordCallsites.count();i++) 1.3706 + { 1.3707 + labels[i] = gen.newLabel(); 1.3708 + } 1.3709 + gen.loadArg(0); 1.3710 + gen.visitTableSwitchInsn(0,keywordCallsites.count()-1,endLabel,labels); 1.3711 + 1.3712 + for(int i = 0; i < keywordCallsites.count();i++) 1.3713 + { 1.3714 + gen.mark(labels[i]); 1.3715 +// gen.loadThis(); 1.3716 + gen.loadArg(1); 1.3717 + gen.putStatic(objtype, thunkNameStatic(i),ILOOKUP_THUNK_TYPE); 1.3718 + gen.goTo(endLabel); 1.3719 + } 1.3720 + 1.3721 + gen.mark(endLabel); 1.3722 + 1.3723 + gen.returnValue(); 1.3724 + gen.endMethod(); 1.3725 + } 1.3726 + 1.3727 + //end of class 1.3728 + cv.visitEnd(); 1.3729 + 1.3730 + bytecode = cw.toByteArray(); 1.3731 + if(RT.booleanCast(COMPILE_FILES.deref())) 1.3732 + writeClassFile(internalName, bytecode); 1.3733 +// else 1.3734 +// getCompiledClass(); 1.3735 + } 1.3736 + 1.3737 + private void emitKeywordCallsites(GeneratorAdapter clinitgen){ 1.3738 + for(int i=0;i<keywordCallsites.count();i++) 1.3739 + { 1.3740 + Keyword k = (Keyword) keywordCallsites.nth(i); 1.3741 + clinitgen.newInstance(KEYWORD_LOOKUPSITE_TYPE); 1.3742 + clinitgen.dup(); 1.3743 + clinitgen.push(i); 1.3744 + emitValue(k,clinitgen); 1.3745 + clinitgen.invokeConstructor(KEYWORD_LOOKUPSITE_TYPE, 1.3746 + Method.getMethod("void <init>(int,clojure.lang.Keyword)")); 1.3747 + clinitgen.dup(); 1.3748 + clinitgen.putStatic(objtype, siteNameStatic(i), KEYWORD_LOOKUPSITE_TYPE); 1.3749 + clinitgen.putStatic(objtype, thunkNameStatic(i), ILOOKUP_THUNK_TYPE); 1.3750 + } 1.3751 + } 1.3752 + 1.3753 + protected void emitMethods(ClassVisitor gen){ 1.3754 + } 1.3755 + 1.3756 + void emitListAsObjectArray(Object value, GeneratorAdapter gen){ 1.3757 + gen.push(((List) value).size()); 1.3758 + gen.newArray(OBJECT_TYPE); 1.3759 + int i = 0; 1.3760 + for(Iterator it = ((List) value).iterator(); it.hasNext(); i++) 1.3761 + { 1.3762 + gen.dup(); 1.3763 + gen.push(i); 1.3764 + emitValue(it.next(), gen); 1.3765 + gen.arrayStore(OBJECT_TYPE); 1.3766 + } 1.3767 + } 1.3768 + 1.3769 + void emitValue(Object value, GeneratorAdapter gen){ 1.3770 + boolean partial = true; 1.3771 + //System.out.println(value.getClass().toString()); 1.3772 + 1.3773 + if(value instanceof String) 1.3774 + { 1.3775 + gen.push((String) value); 1.3776 + } 1.3777 + else if(value instanceof Integer) 1.3778 + { 1.3779 + gen.push(((Integer) value).intValue()); 1.3780 + gen.invokeStatic(Type.getType(Integer.class), Method.getMethod("Integer valueOf(int)")); 1.3781 + } 1.3782 + else if(value instanceof Double) 1.3783 + { 1.3784 + gen.push(((Double) value).doubleValue()); 1.3785 + gen.invokeStatic(Type.getType(Double.class), Method.getMethod("Double valueOf(double)")); 1.3786 + } 1.3787 + else if(value instanceof Character) 1.3788 + { 1.3789 + gen.push(((Character) value).charValue()); 1.3790 + gen.invokeStatic(Type.getType(Character.class), Method.getMethod("Character valueOf(char)")); 1.3791 + } 1.3792 + else if(value instanceof Class) 1.3793 + { 1.3794 + Class cc = (Class)value; 1.3795 + if(cc.isPrimitive()) 1.3796 + { 1.3797 + Type bt; 1.3798 + if ( cc == boolean.class ) bt = Type.getType(Boolean.class); 1.3799 + else if ( cc == byte.class ) bt = Type.getType(Byte.class); 1.3800 + else if ( cc == char.class ) bt = Type.getType(Character.class); 1.3801 + else if ( cc == double.class ) bt = Type.getType(Double.class); 1.3802 + else if ( cc == float.class ) bt = Type.getType(Float.class); 1.3803 + else if ( cc == int.class ) bt = Type.getType(Integer.class); 1.3804 + else if ( cc == long.class ) bt = Type.getType(Long.class); 1.3805 + else if ( cc == short.class ) bt = Type.getType(Short.class); 1.3806 + else throw new RuntimeException( 1.3807 + "Can't embed unknown primitive in code: " + value); 1.3808 + gen.getStatic( bt, "TYPE", Type.getType(Class.class) ); 1.3809 + } 1.3810 + else 1.3811 + { 1.3812 + gen.push(destubClassName(cc.getName())); 1.3813 + gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)")); 1.3814 + } 1.3815 + } 1.3816 + else if(value instanceof Symbol) 1.3817 + { 1.3818 + gen.push(((Symbol) value).ns); 1.3819 + gen.push(((Symbol) value).name); 1.3820 + gen.invokeStatic(Type.getType(Symbol.class), 1.3821 + Method.getMethod("clojure.lang.Symbol create(String,String)")); 1.3822 + } 1.3823 + else if(value instanceof Keyword) 1.3824 + { 1.3825 + emitValue(((Keyword) value).sym, gen); 1.3826 + gen.invokeStatic(Type.getType(Keyword.class), 1.3827 + Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)")); 1.3828 + } 1.3829 +// else if(value instanceof KeywordCallSite) 1.3830 +// { 1.3831 +// emitValue(((KeywordCallSite) value).k.sym, gen); 1.3832 +// gen.invokeStatic(Type.getType(KeywordCallSite.class), 1.3833 +// Method.getMethod("clojure.lang.KeywordCallSite create(clojure.lang.Symbol)")); 1.3834 +// } 1.3835 + else if(value instanceof Var) 1.3836 + { 1.3837 + Var var = (Var) value; 1.3838 + gen.push(var.ns.name.toString()); 1.3839 + gen.push(var.sym.toString()); 1.3840 + gen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)")); 1.3841 + } 1.3842 + else if(value instanceof IPersistentMap) 1.3843 + { 1.3844 + List entries = new ArrayList(); 1.3845 + for(Map.Entry entry : (Set<Map.Entry>) ((Map) value).entrySet()) 1.3846 + { 1.3847 + entries.add(entry.getKey()); 1.3848 + entries.add(entry.getValue()); 1.3849 + } 1.3850 + emitListAsObjectArray(entries, gen); 1.3851 + gen.invokeStatic(RT_TYPE, 1.3852 + Method.getMethod("clojure.lang.IPersistentMap map(Object[])")); 1.3853 + } 1.3854 + else if(value instanceof IPersistentVector) 1.3855 + { 1.3856 + emitListAsObjectArray(value, gen); 1.3857 + gen.invokeStatic(RT_TYPE, Method.getMethod( 1.3858 + "clojure.lang.IPersistentVector vector(Object[])")); 1.3859 + } 1.3860 + else if(value instanceof ISeq || value instanceof IPersistentList) 1.3861 + { 1.3862 + emitListAsObjectArray(value, gen); 1.3863 + gen.invokeStatic(Type.getType(java.util.Arrays.class), 1.3864 + Method.getMethod("java.util.List asList(Object[])")); 1.3865 + gen.invokeStatic(Type.getType(PersistentList.class), 1.3866 + Method.getMethod( 1.3867 + "clojure.lang.IPersistentList create(java.util.List)")); 1.3868 + } 1.3869 + else 1.3870 + { 1.3871 + String cs = null; 1.3872 + try 1.3873 + { 1.3874 + cs = RT.printString(value); 1.3875 + //System.out.println("WARNING SLOW CODE: " + value.getClass() + " -> " + cs); 1.3876 + } 1.3877 + catch(Exception e) 1.3878 + { 1.3879 + throw new RuntimeException( 1.3880 + "Can't embed object in code, maybe print-dup not defined: " + 1.3881 + value); 1.3882 + } 1.3883 + if(cs.length() == 0) 1.3884 + throw new RuntimeException( 1.3885 + "Can't embed unreadable object in code: " + value); 1.3886 + 1.3887 + if(cs.startsWith("#<")) 1.3888 + throw new RuntimeException( 1.3889 + "Can't embed unreadable object in code: " + cs); 1.3890 + 1.3891 + gen.push(cs); 1.3892 + gen.invokeStatic(RT_TYPE, readStringMethod); 1.3893 + partial = false; 1.3894 + } 1.3895 + 1.3896 + if(partial) 1.3897 + { 1.3898 + if(value instanceof IObj && RT.count(((IObj) value).meta()) > 0) 1.3899 + { 1.3900 + gen.checkCast(IOBJ_TYPE); 1.3901 + emitValue(((IObj) value).meta(), gen); 1.3902 + gen.checkCast(IPERSISTENTMAP_TYPE); 1.3903 + gen.invokeInterface(IOBJ_TYPE, 1.3904 + Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)")); 1.3905 + } 1.3906 + } 1.3907 + } 1.3908 + 1.3909 + 1.3910 + void emitConstants(GeneratorAdapter clinitgen){ 1.3911 + try 1.3912 + { 1.3913 + Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T)); 1.3914 + 1.3915 + for(int i = 0; i < constants.count(); i++) 1.3916 + { 1.3917 + emitValue(constants.nth(i), clinitgen); 1.3918 + clinitgen.checkCast(constantType(i)); 1.3919 + clinitgen.putStatic(objtype, constantName(i), constantType(i)); 1.3920 + } 1.3921 + } 1.3922 + finally 1.3923 + { 1.3924 + Var.popThreadBindings(); 1.3925 + } 1.3926 + } 1.3927 + 1.3928 + boolean isMutable(LocalBinding lb){ 1.3929 + return isVolatile(lb) || 1.3930 + RT.booleanCast(RT.contains(fields, lb.sym)) && 1.3931 + RT.booleanCast(RT.get(lb.sym.meta(), Keyword.intern("unsynchronized-mutable"))); 1.3932 + } 1.3933 + 1.3934 + boolean isVolatile(LocalBinding lb){ 1.3935 + return RT.booleanCast(RT.contains(fields, lb.sym)) && 1.3936 + RT.booleanCast(RT.get(lb.sym.meta(), Keyword.intern("volatile-mutable"))); 1.3937 + } 1.3938 + 1.3939 + boolean isDeftype(){ 1.3940 + return fields != null; 1.3941 + } 1.3942 + 1.3943 + void emitClearCloses(GeneratorAdapter gen){ 1.3944 +// int a = 1; 1.3945 +// for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a) 1.3946 +// { 1.3947 +// LocalBinding lb = (LocalBinding) s.first(); 1.3948 +// Class primc = lb.getPrimitiveType(); 1.3949 +// if(primc == null) 1.3950 +// { 1.3951 +// gen.loadThis(); 1.3952 +// gen.visitInsn(Opcodes.ACONST_NULL); 1.3953 +// gen.putField(objtype, lb.name, OBJECT_TYPE); 1.3954 +// } 1.3955 +// } 1.3956 + } 1.3957 + 1.3958 + synchronized Class getCompiledClass(){ 1.3959 + if(compiledClass == null) 1.3960 + try 1.3961 + { 1.3962 +// if(RT.booleanCast(COMPILE_FILES.deref())) 1.3963 +// compiledClass = RT.classForName(name);//loader.defineClass(name, bytecode); 1.3964 +// else 1.3965 + { 1.3966 + loader = (DynamicClassLoader) LOADER.deref(); 1.3967 + compiledClass = loader.defineClass(name, bytecode, src); 1.3968 + } 1.3969 + } 1.3970 + catch(Exception e) 1.3971 + { 1.3972 + throw new RuntimeException(e); 1.3973 + } 1.3974 + return compiledClass; 1.3975 + } 1.3976 + 1.3977 + public Object eval() throws Exception{ 1.3978 + if(isDeftype()) 1.3979 + return null; 1.3980 + return getCompiledClass().newInstance(); 1.3981 + } 1.3982 + 1.3983 + public void emitLetFnInits(GeneratorAdapter gen, ObjExpr objx, IPersistentSet letFnLocals){ 1.3984 + //objx arg is enclosing objx, not this 1.3985 + gen.checkCast(objtype); 1.3986 + 1.3987 + for(ISeq s = RT.keys(closes); s != null; s = s.next()) 1.3988 + { 1.3989 + LocalBinding lb = (LocalBinding) s.first(); 1.3990 + if(letFnLocals.contains(lb)) 1.3991 + { 1.3992 + Class primc = lb.getPrimitiveType(); 1.3993 + gen.dup(); 1.3994 + if(primc != null) 1.3995 + { 1.3996 + objx.emitUnboxedLocal(gen, lb); 1.3997 + gen.putField(objtype, lb.name, Type.getType(primc)); 1.3998 + } 1.3999 + else 1.4000 + { 1.4001 + objx.emitLocal(gen, lb, false); 1.4002 + gen.putField(objtype, lb.name, OBJECT_TYPE); 1.4003 + } 1.4004 + } 1.4005 + } 1.4006 + gen.pop(); 1.4007 + 1.4008 + } 1.4009 + 1.4010 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4011 + //emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any 1.4012 + //objx arg is enclosing objx, not this 1.4013 +// getCompiledClass(); 1.4014 + if(isDeftype()) 1.4015 + { 1.4016 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4017 + } 1.4018 + else 1.4019 + { 1.4020 + gen.newInstance(objtype); 1.4021 + gen.dup(); 1.4022 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4023 + for(ISeq s = RT.seq(closesExprs); s != null; s = s.next()) 1.4024 + { 1.4025 + LocalBindingExpr lbe = (LocalBindingExpr) s.first(); 1.4026 + LocalBinding lb = lbe.b; 1.4027 + if(lb.getPrimitiveType() != null) 1.4028 + objx.emitUnboxedLocal(gen, lb); 1.4029 + else 1.4030 + objx.emitLocal(gen, lb, lbe.shouldClear); 1.4031 + } 1.4032 + gen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes())); 1.4033 + } 1.4034 + if(context == C.STATEMENT) 1.4035 + gen.pop(); 1.4036 + } 1.4037 + 1.4038 + public boolean hasJavaClass() throws Exception{ 1.4039 + return true; 1.4040 + } 1.4041 + 1.4042 + public Class getJavaClass() throws Exception{ 1.4043 + return (compiledClass != null) ? compiledClass 1.4044 + : (tag != null) ? HostExpr.tagToClass(tag) 1.4045 + : IFn.class; 1.4046 + } 1.4047 + 1.4048 + public void emitAssignLocal(GeneratorAdapter gen, LocalBinding lb,Expr val){ 1.4049 + if(!isMutable(lb)) 1.4050 + throw new IllegalArgumentException("Cannot assign to non-mutable: " + lb.name); 1.4051 + Class primc = lb.getPrimitiveType(); 1.4052 + gen.loadThis(); 1.4053 + if(primc != null) 1.4054 + { 1.4055 + if(!(val instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr) val).canEmitPrimitive())) 1.4056 + throw new IllegalArgumentException("Must assign primitive to primitive mutable: " + lb.name); 1.4057 + MaybePrimitiveExpr me = (MaybePrimitiveExpr) val; 1.4058 + me.emitUnboxed(C.EXPRESSION, this, gen); 1.4059 + gen.putField(objtype, lb.name, Type.getType(primc)); 1.4060 + } 1.4061 + else 1.4062 + { 1.4063 + val.emit(C.EXPRESSION, this, gen); 1.4064 + gen.putField(objtype, lb.name, OBJECT_TYPE); 1.4065 + } 1.4066 + } 1.4067 + 1.4068 + private void emitLocal(GeneratorAdapter gen, LocalBinding lb, boolean clear){ 1.4069 + if(closes.containsKey(lb)) 1.4070 + { 1.4071 + Class primc = lb.getPrimitiveType(); 1.4072 + gen.loadThis(); 1.4073 + if(primc != null) 1.4074 + { 1.4075 + gen.getField(objtype, lb.name, Type.getType(primc)); 1.4076 + HostExpr.emitBoxReturn(this, gen, primc); 1.4077 + } 1.4078 + else 1.4079 + { 1.4080 + gen.getField(objtype, lb.name, OBJECT_TYPE); 1.4081 + if(onceOnly && clear && lb.canBeCleared) 1.4082 + { 1.4083 + gen.loadThis(); 1.4084 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4085 + gen.putField(objtype, lb.name, OBJECT_TYPE); 1.4086 + } 1.4087 + } 1.4088 + } 1.4089 + else 1.4090 + { 1.4091 + Class primc = lb.getPrimitiveType(); 1.4092 +// String rep = lb.sym.name + " " + lb.toString().substring(lb.toString().lastIndexOf('@')); 1.4093 + if(lb.isArg) 1.4094 + { 1.4095 + gen.loadArg(lb.idx-1); 1.4096 + if(primc != null) 1.4097 + HostExpr.emitBoxReturn(this, gen, primc); 1.4098 + else 1.4099 + { 1.4100 + if(clear && lb.canBeCleared) 1.4101 + { 1.4102 +// System.out.println("clear: " + rep); 1.4103 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4104 + gen.storeArg(lb.idx - 1); 1.4105 + } 1.4106 + else 1.4107 + { 1.4108 +// System.out.println("use: " + rep); 1.4109 + } 1.4110 + } 1.4111 + } 1.4112 + else 1.4113 + { 1.4114 + if(primc != null) 1.4115 + { 1.4116 + gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ILOAD), lb.idx); 1.4117 + HostExpr.emitBoxReturn(this, gen, primc); 1.4118 + } 1.4119 + else 1.4120 + { 1.4121 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), lb.idx); 1.4122 + if(clear && lb.canBeCleared) 1.4123 + { 1.4124 +// System.out.println("clear: " + rep); 1.4125 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4126 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), lb.idx); 1.4127 + } 1.4128 + else 1.4129 + { 1.4130 +// System.out.println("use: " + rep); 1.4131 + } 1.4132 + } 1.4133 + } 1.4134 + } 1.4135 + } 1.4136 + 1.4137 + private void emitUnboxedLocal(GeneratorAdapter gen, LocalBinding lb){ 1.4138 + Class primc = lb.getPrimitiveType(); 1.4139 + if(closes.containsKey(lb)) 1.4140 + { 1.4141 + gen.loadThis(); 1.4142 + gen.getField(objtype, lb.name, Type.getType(primc)); 1.4143 + } 1.4144 + else if(lb.isArg) 1.4145 + gen.loadArg(lb.idx-1); 1.4146 + else 1.4147 + gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ILOAD), lb.idx); 1.4148 + } 1.4149 + 1.4150 + public void emitVar(GeneratorAdapter gen, Var var){ 1.4151 + Integer i = (Integer) vars.valAt(var); 1.4152 + emitConstant(gen, i); 1.4153 + //gen.getStatic(fntype, munge(var.sym.toString()), VAR_TYPE); 1.4154 + } 1.4155 + 1.4156 + public void emitKeyword(GeneratorAdapter gen, Keyword k){ 1.4157 + Integer i = (Integer) keywords.valAt(k); 1.4158 + emitConstant(gen, i); 1.4159 +// gen.getStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE); 1.4160 + } 1.4161 + 1.4162 + public void emitConstant(GeneratorAdapter gen, int id){ 1.4163 + gen.getStatic(objtype, constantName(id), constantType(id)); 1.4164 + } 1.4165 + 1.4166 + 1.4167 + String constantName(int id){ 1.4168 + return CONST_PREFIX + id; 1.4169 + } 1.4170 + 1.4171 + String siteName(int n){ 1.4172 + return "__site__" + n; 1.4173 + } 1.4174 + 1.4175 + String siteNameStatic(int n){ 1.4176 + return siteName(n) + "__"; 1.4177 + } 1.4178 + 1.4179 + String thunkName(int n){ 1.4180 + return "__thunk__" + n; 1.4181 + } 1.4182 + 1.4183 + String cachedClassName(int n){ 1.4184 + return "__cached_class__" + n; 1.4185 + } 1.4186 + 1.4187 + String cachedProtoFnName(int n){ 1.4188 + return "__cached_proto_fn__" + n; 1.4189 + } 1.4190 + 1.4191 + String cachedProtoImplName(int n){ 1.4192 + return "__cached_proto_impl__" + n; 1.4193 + } 1.4194 + 1.4195 + String varCallsiteName(int n){ 1.4196 + return "__var__callsite__" + n; 1.4197 + } 1.4198 + 1.4199 + String thunkNameStatic(int n){ 1.4200 + return thunkName(n) + "__"; 1.4201 + } 1.4202 + 1.4203 + Type constantType(int id){ 1.4204 + Object o = constants.nth(id); 1.4205 + Class c = o.getClass(); 1.4206 + if(Modifier.isPublic(c.getModifiers())) 1.4207 + { 1.4208 + //can't emit derived fn types due to visibility 1.4209 + if(LazySeq.class.isAssignableFrom(c)) 1.4210 + return Type.getType(ISeq.class); 1.4211 + else if(c == Keyword.class) 1.4212 + return Type.getType(Keyword.class); 1.4213 +// else if(c == KeywordCallSite.class) 1.4214 +// return Type.getType(KeywordCallSite.class); 1.4215 + else if(RestFn.class.isAssignableFrom(c)) 1.4216 + return Type.getType(RestFn.class); 1.4217 + else if(AFn.class.isAssignableFrom(c)) 1.4218 + return Type.getType(AFn.class); 1.4219 + else if(c == Var.class) 1.4220 + return Type.getType(Var.class); 1.4221 + else if(c == String.class) 1.4222 + return Type.getType(String.class); 1.4223 + 1.4224 +// return Type.getType(c); 1.4225 + } 1.4226 + return OBJECT_TYPE; 1.4227 + } 1.4228 + 1.4229 +} 1.4230 + 1.4231 +enum PATHTYPE { 1.4232 + PATH, BRANCH; 1.4233 +} 1.4234 + 1.4235 +static class PathNode{ 1.4236 + final PATHTYPE type; 1.4237 + final PathNode parent; 1.4238 + 1.4239 + PathNode(PATHTYPE type, PathNode parent) { 1.4240 + this.type = type; 1.4241 + this.parent = parent; 1.4242 + } 1.4243 +} 1.4244 + 1.4245 +static PathNode clearPathRoot(){ 1.4246 + return (PathNode) CLEAR_ROOT.get(); 1.4247 +} 1.4248 + 1.4249 +enum PSTATE{ 1.4250 + REQ, REST, DONE 1.4251 +} 1.4252 + 1.4253 +public static class FnMethod extends ObjMethod{ 1.4254 + //localbinding->localbinding 1.4255 + PersistentVector reqParms = PersistentVector.EMPTY; 1.4256 + LocalBinding restParm = null; 1.4257 + 1.4258 + public FnMethod(ObjExpr objx, ObjMethod parent){ 1.4259 + super(objx, parent); 1.4260 + } 1.4261 + 1.4262 + static FnMethod parse(ObjExpr objx, ISeq form) throws Exception{ 1.4263 + //([args] body...) 1.4264 + IPersistentVector parms = (IPersistentVector) RT.first(form); 1.4265 + ISeq body = RT.next(form); 1.4266 + try 1.4267 + { 1.4268 + FnMethod method = new FnMethod(objx, (ObjMethod) METHOD.deref()); 1.4269 + method.line = (Integer) LINE.deref(); 1.4270 + //register as the current method and set up a new env frame 1.4271 + PathNode pnode = (PathNode) CLEAR_PATH.get(); 1.4272 + if(pnode == null) 1.4273 + pnode = new PathNode(PATHTYPE.PATH,null); 1.4274 + Var.pushThreadBindings( 1.4275 + RT.map( 1.4276 + METHOD, method, 1.4277 + LOCAL_ENV, LOCAL_ENV.deref(), 1.4278 + LOOP_LOCALS, null, 1.4279 + NEXT_LOCAL_NUM, 0 1.4280 + ,CLEAR_PATH, pnode 1.4281 + ,CLEAR_ROOT, pnode 1.4282 + ,CLEAR_SITES, PersistentHashMap.EMPTY 1.4283 + )); 1.4284 + 1.4285 + //register 'this' as local 0 1.4286 + //registerLocal(THISFN, null, null); 1.4287 + if(objx.thisName != null) 1.4288 + registerLocal(Symbol.intern(objx.thisName), null, null,false); 1.4289 + else 1.4290 + getAndIncLocalNum(); 1.4291 + PSTATE state = PSTATE.REQ; 1.4292 + PersistentVector argLocals = PersistentVector.EMPTY; 1.4293 + for(int i = 0; i < parms.count(); i++) 1.4294 + { 1.4295 + if(!(parms.nth(i) instanceof Symbol)) 1.4296 + throw new IllegalArgumentException("fn params must be Symbols"); 1.4297 + Symbol p = (Symbol) parms.nth(i); 1.4298 + if(p.getNamespace() != null) 1.4299 + throw new Exception("Can't use qualified name as parameter: " + p); 1.4300 + if(p.equals(_AMP_)) 1.4301 + { 1.4302 + if(state == PSTATE.REQ) 1.4303 + state = PSTATE.REST; 1.4304 + else 1.4305 + throw new Exception("Invalid parameter list"); 1.4306 + } 1.4307 + 1.4308 + else 1.4309 + { 1.4310 + LocalBinding lb = registerLocal(p, state == PSTATE.REST ? ISEQ : tagOf(p), null,true); 1.4311 + argLocals = argLocals.cons(lb); 1.4312 + switch(state) 1.4313 + { 1.4314 + case REQ: 1.4315 + method.reqParms = method.reqParms.cons(lb); 1.4316 + break; 1.4317 + case REST: 1.4318 + method.restParm = lb; 1.4319 + state = PSTATE.DONE; 1.4320 + break; 1.4321 + 1.4322 + default: 1.4323 + throw new Exception("Unexpected parameter"); 1.4324 + } 1.4325 + } 1.4326 + } 1.4327 + if(method.reqParms.count() > MAX_POSITIONAL_ARITY) 1.4328 + throw new Exception("Can't specify more than " + MAX_POSITIONAL_ARITY + " params"); 1.4329 + LOOP_LOCALS.set(argLocals); 1.4330 + method.argLocals = argLocals; 1.4331 + method.body = (new BodyExpr.Parser()).parse(C.RETURN, body); 1.4332 + return method; 1.4333 + } 1.4334 + finally 1.4335 + { 1.4336 + Var.popThreadBindings(); 1.4337 + } 1.4338 + } 1.4339 + 1.4340 + public final PersistentVector reqParms(){ 1.4341 + return reqParms; 1.4342 + } 1.4343 + 1.4344 + public final LocalBinding restParm(){ 1.4345 + return restParm; 1.4346 + } 1.4347 + 1.4348 + boolean isVariadic(){ 1.4349 + return restParm != null; 1.4350 + } 1.4351 + 1.4352 + int numParams(){ 1.4353 + return reqParms.count() + (isVariadic() ? 1 : 0); 1.4354 + } 1.4355 + 1.4356 + String getMethodName(){ 1.4357 + return isVariadic()?"doInvoke":"invoke"; 1.4358 + } 1.4359 + 1.4360 + Type getReturnType(){ 1.4361 + return OBJECT_TYPE; 1.4362 + } 1.4363 + 1.4364 + Type[] getArgTypes(){ 1.4365 + if(isVariadic() && reqParms.count() == MAX_POSITIONAL_ARITY) 1.4366 + { 1.4367 + Type[] ret = new Type[MAX_POSITIONAL_ARITY + 1]; 1.4368 + for(int i = 0;i<MAX_POSITIONAL_ARITY + 1;i++) 1.4369 + ret[i] = OBJECT_TYPE; 1.4370 + return ret; 1.4371 + } 1.4372 + return ARG_TYPES[numParams()]; 1.4373 + } 1.4374 + 1.4375 + void emitClearLocals(GeneratorAdapter gen){ 1.4376 +// for(int i = 1; i < numParams() + 1; i++) 1.4377 +// { 1.4378 +// if(!localsUsedInCatchFinally.contains(i)) 1.4379 +// { 1.4380 +// gen.visitInsn(Opcodes.ACONST_NULL); 1.4381 +// gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i); 1.4382 +// } 1.4383 +// } 1.4384 +// for(int i = numParams() + 1; i < maxLocal + 1; i++) 1.4385 +// { 1.4386 +// if(!localsUsedInCatchFinally.contains(i)) 1.4387 +// { 1.4388 +// LocalBinding b = (LocalBinding) RT.get(indexlocals, i); 1.4389 +// if(b == null || maybePrimitiveType(b.init) == null) 1.4390 +// { 1.4391 +// gen.visitInsn(Opcodes.ACONST_NULL); 1.4392 +// gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i); 1.4393 +// } 1.4394 +// } 1.4395 +// } 1.4396 +// if(((FnExpr)objx).onceOnly) 1.4397 +// { 1.4398 +// objx.emitClearCloses(gen); 1.4399 +// } 1.4400 + } 1.4401 +} 1.4402 + 1.4403 +abstract public static class ObjMethod{ 1.4404 + //when closures are defined inside other closures, 1.4405 + //the closed over locals need to be propagated to the enclosing objx 1.4406 + public final ObjMethod parent; 1.4407 + //localbinding->localbinding 1.4408 + IPersistentMap locals = null; 1.4409 + //num->localbinding 1.4410 + IPersistentMap indexlocals = null; 1.4411 + Expr body = null; 1.4412 + ObjExpr objx; 1.4413 + PersistentVector argLocals; 1.4414 + int maxLocal = 0; 1.4415 + int line; 1.4416 + PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY; 1.4417 + protected IPersistentMap methodMeta; 1.4418 + 1.4419 + public final IPersistentMap locals(){ 1.4420 + return locals; 1.4421 + } 1.4422 + 1.4423 + public final Expr body(){ 1.4424 + return body; 1.4425 + } 1.4426 + 1.4427 + public final ObjExpr objx(){ 1.4428 + return objx; 1.4429 + } 1.4430 + 1.4431 + public final PersistentVector argLocals(){ 1.4432 + return argLocals; 1.4433 + } 1.4434 + 1.4435 + public final int maxLocal(){ 1.4436 + return maxLocal; 1.4437 + } 1.4438 + 1.4439 + public final int line(){ 1.4440 + return line; 1.4441 + } 1.4442 + 1.4443 + public ObjMethod(ObjExpr objx, ObjMethod parent){ 1.4444 + this.parent = parent; 1.4445 + this.objx = objx; 1.4446 + } 1.4447 + 1.4448 + abstract int numParams(); 1.4449 + abstract String getMethodName(); 1.4450 + abstract Type getReturnType(); 1.4451 + abstract Type[] getArgTypes(); 1.4452 + 1.4453 + public void emit(ObjExpr fn, ClassVisitor cv){ 1.4454 + Method m = new Method(getMethodName(), getReturnType(), getArgTypes()); 1.4455 + 1.4456 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, 1.4457 + m, 1.4458 + null, 1.4459 + //todo don't hardwire this 1.4460 + EXCEPTION_TYPES, 1.4461 + cv); 1.4462 + gen.visitCode(); 1.4463 + Label loopLabel = gen.mark(); 1.4464 + gen.visitLineNumber(line, loopLabel); 1.4465 + try 1.4466 + { 1.4467 + Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this)); 1.4468 + body.emit(C.RETURN, fn, gen); 1.4469 + Label end = gen.mark(); 1.4470 + gen.visitLocalVariable("this", "Ljava/lang/Object;", null, loopLabel, end, 0); 1.4471 + for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next()) 1.4472 + { 1.4473 + LocalBinding lb = (LocalBinding) lbs.first(); 1.4474 + gen.visitLocalVariable(lb.name, "Ljava/lang/Object;", null, loopLabel, end, lb.idx); 1.4475 + } 1.4476 + } 1.4477 + finally 1.4478 + { 1.4479 + Var.popThreadBindings(); 1.4480 + } 1.4481 + 1.4482 + gen.returnValue(); 1.4483 + //gen.visitMaxs(1, 1); 1.4484 + gen.endMethod(); 1.4485 + } 1.4486 + 1.4487 + void emitClearLocals(GeneratorAdapter gen){ 1.4488 + } 1.4489 + 1.4490 + void emitClearLocalsOld(GeneratorAdapter gen){ 1.4491 + for(int i=0;i<argLocals.count();i++) 1.4492 + { 1.4493 + LocalBinding lb = (LocalBinding) argLocals.nth(i); 1.4494 + if(!localsUsedInCatchFinally.contains(lb.idx) && lb.getPrimitiveType() == null) 1.4495 + { 1.4496 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4497 + gen.storeArg(lb.idx - 1); 1.4498 + } 1.4499 + 1.4500 + } 1.4501 +// for(int i = 1; i < numParams() + 1; i++) 1.4502 +// { 1.4503 +// if(!localsUsedInCatchFinally.contains(i)) 1.4504 +// { 1.4505 +// gen.visitInsn(Opcodes.ACONST_NULL); 1.4506 +// gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i); 1.4507 +// } 1.4508 +// } 1.4509 + for(int i = numParams() + 1; i < maxLocal + 1; i++) 1.4510 + { 1.4511 + if(!localsUsedInCatchFinally.contains(i)) 1.4512 + { 1.4513 + LocalBinding b = (LocalBinding) RT.get(indexlocals, i); 1.4514 + if(b == null || maybePrimitiveType(b.init) == null) 1.4515 + { 1.4516 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4517 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i); 1.4518 + } 1.4519 + } 1.4520 + } 1.4521 + } 1.4522 +} 1.4523 + 1.4524 +public static class LocalBinding{ 1.4525 + public final Symbol sym; 1.4526 + public final Symbol tag; 1.4527 + public Expr init; 1.4528 + public final int idx; 1.4529 + public final String name; 1.4530 + public final boolean isArg; 1.4531 + public final PathNode clearPathRoot; 1.4532 + public boolean canBeCleared = true; 1.4533 + 1.4534 + public LocalBinding(int num, Symbol sym, Symbol tag, Expr init, boolean isArg,PathNode clearPathRoot) 1.4535 + throws Exception{ 1.4536 + if(maybePrimitiveType(init) != null && tag != null) 1.4537 + throw new UnsupportedOperationException("Can't type hint a local with a primitive initializer"); 1.4538 + this.idx = num; 1.4539 + this.sym = sym; 1.4540 + this.tag = tag; 1.4541 + this.init = init; 1.4542 + this.isArg = isArg; 1.4543 + this.clearPathRoot = clearPathRoot; 1.4544 + name = munge(sym.name); 1.4545 + } 1.4546 + 1.4547 + public boolean hasJavaClass() throws Exception{ 1.4548 + if(init != null && init.hasJavaClass() 1.4549 + && Util.isPrimitive(init.getJavaClass()) 1.4550 + && !(init instanceof MaybePrimitiveExpr)) 1.4551 + return false; 1.4552 + return tag != null 1.4553 + || (init != null && init.hasJavaClass()); 1.4554 + } 1.4555 + 1.4556 + public Class getJavaClass() throws Exception{ 1.4557 + return tag != null ? HostExpr.tagToClass(tag) 1.4558 + : init.getJavaClass(); 1.4559 + } 1.4560 + 1.4561 + public Class getPrimitiveType(){ 1.4562 + return maybePrimitiveType(init); 1.4563 + } 1.4564 +} 1.4565 + 1.4566 +public static class LocalBindingExpr implements Expr, MaybePrimitiveExpr, AssignableExpr{ 1.4567 + public final LocalBinding b; 1.4568 + public final Symbol tag; 1.4569 + 1.4570 + public final PathNode clearPath; 1.4571 + public final PathNode clearRoot; 1.4572 + public boolean shouldClear = false; 1.4573 + 1.4574 + 1.4575 + public LocalBindingExpr(LocalBinding b, Symbol tag) 1.4576 + throws Exception{ 1.4577 + if(b.getPrimitiveType() != null && tag != null) 1.4578 + throw new UnsupportedOperationException("Can't type hint a primitive local"); 1.4579 + this.b = b; 1.4580 + this.tag = tag; 1.4581 + 1.4582 + this.clearPath = (PathNode)CLEAR_PATH.get(); 1.4583 + this.clearRoot = (PathNode)CLEAR_ROOT.get(); 1.4584 + IPersistentCollection sites = (IPersistentCollection) RT.get(CLEAR_SITES.get(),b); 1.4585 + 1.4586 + if(b.idx > 0) 1.4587 + { 1.4588 +// Object dummy; 1.4589 + 1.4590 + if(sites != null) 1.4591 + { 1.4592 + for(ISeq s = sites.seq();s!=null;s = s.next()) 1.4593 + { 1.4594 + LocalBindingExpr o = (LocalBindingExpr) s.first(); 1.4595 + PathNode common = commonPath(clearPath,o.clearPath); 1.4596 + if(common != null && common.type == PATHTYPE.PATH) 1.4597 + o.shouldClear = false; 1.4598 +// else 1.4599 +// dummy = null; 1.4600 + } 1.4601 + } 1.4602 + 1.4603 + if(clearRoot == b.clearPathRoot) 1.4604 + { 1.4605 + this.shouldClear = true; 1.4606 + sites = RT.conj(sites,this); 1.4607 + CLEAR_SITES.set(RT.assoc(CLEAR_SITES.get(), b, sites)); 1.4608 + } 1.4609 +// else 1.4610 +// dummy = null; 1.4611 + } 1.4612 + } 1.4613 + 1.4614 + public Object eval() throws Exception{ 1.4615 + throw new UnsupportedOperationException("Can't eval locals"); 1.4616 + } 1.4617 + 1.4618 + public boolean canEmitPrimitive(){ 1.4619 + return b.getPrimitiveType() != null; 1.4620 + } 1.4621 + 1.4622 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4623 + objx.emitUnboxedLocal(gen, b); 1.4624 + } 1.4625 + 1.4626 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4627 + if(context != C.STATEMENT) 1.4628 + objx.emitLocal(gen, b, shouldClear); 1.4629 + } 1.4630 + 1.4631 + public Object evalAssign(Expr val) throws Exception{ 1.4632 + throw new UnsupportedOperationException("Can't eval locals"); 1.4633 + } 1.4634 + 1.4635 + public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, Expr val){ 1.4636 + objx.emitAssignLocal(gen, b,val); 1.4637 + if(context != C.STATEMENT) 1.4638 + objx.emitLocal(gen, b, false); 1.4639 + } 1.4640 + 1.4641 + public boolean hasJavaClass() throws Exception{ 1.4642 + return tag != null || b.hasJavaClass(); 1.4643 + } 1.4644 + 1.4645 + public Class getJavaClass() throws Exception{ 1.4646 + if(tag != null) 1.4647 + return HostExpr.tagToClass(tag); 1.4648 + return b.getJavaClass(); 1.4649 + } 1.4650 + 1.4651 + 1.4652 +} 1.4653 + 1.4654 +public static class BodyExpr implements Expr, MaybePrimitiveExpr{ 1.4655 + PersistentVector exprs; 1.4656 + 1.4657 + public final PersistentVector exprs(){ 1.4658 + return exprs; 1.4659 + } 1.4660 + 1.4661 + public BodyExpr(PersistentVector exprs){ 1.4662 + this.exprs = exprs; 1.4663 + } 1.4664 + 1.4665 + static class Parser implements IParser{ 1.4666 + public Expr parse(C context, Object frms) throws Exception{ 1.4667 + ISeq forms = (ISeq) frms; 1.4668 + if(Util.equals(RT.first(forms), DO)) 1.4669 + forms = RT.next(forms); 1.4670 + PersistentVector exprs = PersistentVector.EMPTY; 1.4671 + for(; forms != null; forms = forms.next()) 1.4672 + { 1.4673 + Expr e = (context != C.EVAL && 1.4674 + (context == C.STATEMENT || forms.next() != null)) ? 1.4675 + analyze(C.STATEMENT, forms.first()) 1.4676 + : 1.4677 + analyze(context, forms.first()); 1.4678 + exprs = exprs.cons(e); 1.4679 + } 1.4680 + if(exprs.count() == 0) 1.4681 + exprs = exprs.cons(NIL_EXPR); 1.4682 + return new BodyExpr(exprs); 1.4683 + } 1.4684 + } 1.4685 + 1.4686 + public Object eval() throws Exception{ 1.4687 + Object ret = null; 1.4688 + for(Object o : exprs) 1.4689 + { 1.4690 + Expr e = (Expr) o; 1.4691 + ret = e.eval(); 1.4692 + } 1.4693 + return ret; 1.4694 + } 1.4695 + 1.4696 + public boolean canEmitPrimitive(){ 1.4697 + return lastExpr() instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr)lastExpr()).canEmitPrimitive(); 1.4698 + } 1.4699 + 1.4700 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4701 + for(int i = 0; i < exprs.count() - 1; i++) 1.4702 + { 1.4703 + Expr e = (Expr) exprs.nth(i); 1.4704 + e.emit(C.STATEMENT, objx, gen); 1.4705 + } 1.4706 + MaybePrimitiveExpr last = (MaybePrimitiveExpr) exprs.nth(exprs.count() - 1); 1.4707 + last.emitUnboxed(context, objx, gen); 1.4708 + } 1.4709 + 1.4710 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4711 + for(int i = 0; i < exprs.count() - 1; i++) 1.4712 + { 1.4713 + Expr e = (Expr) exprs.nth(i); 1.4714 + e.emit(C.STATEMENT, objx, gen); 1.4715 + } 1.4716 + Expr last = (Expr) exprs.nth(exprs.count() - 1); 1.4717 + last.emit(context, objx, gen); 1.4718 + } 1.4719 + 1.4720 + public boolean hasJavaClass() throws Exception{ 1.4721 + return lastExpr().hasJavaClass(); 1.4722 + } 1.4723 + 1.4724 + public Class getJavaClass() throws Exception{ 1.4725 + return lastExpr().getJavaClass(); 1.4726 + } 1.4727 + 1.4728 + private Expr lastExpr(){ 1.4729 + return (Expr) exprs.nth(exprs.count() - 1); 1.4730 + } 1.4731 +} 1.4732 + 1.4733 +public static class BindingInit{ 1.4734 + LocalBinding binding; 1.4735 + Expr init; 1.4736 + 1.4737 + public final LocalBinding binding(){ 1.4738 + return binding; 1.4739 + } 1.4740 + 1.4741 + public final Expr init(){ 1.4742 + return init; 1.4743 + } 1.4744 + 1.4745 + public BindingInit(LocalBinding binding, Expr init){ 1.4746 + this.binding = binding; 1.4747 + this.init = init; 1.4748 + } 1.4749 +} 1.4750 + 1.4751 +public static class LetFnExpr implements Expr{ 1.4752 + public final PersistentVector bindingInits; 1.4753 + public final Expr body; 1.4754 + 1.4755 + public LetFnExpr(PersistentVector bindingInits, Expr body){ 1.4756 + this.bindingInits = bindingInits; 1.4757 + this.body = body; 1.4758 + } 1.4759 + 1.4760 + static class Parser implements IParser{ 1.4761 + public Expr parse(C context, Object frm) throws Exception{ 1.4762 + ISeq form = (ISeq) frm; 1.4763 + //(letfns* [var (fn [args] body) ...] body...) 1.4764 + if(!(RT.second(form) instanceof IPersistentVector)) 1.4765 + throw new IllegalArgumentException("Bad binding form, expected vector"); 1.4766 + 1.4767 + IPersistentVector bindings = (IPersistentVector) RT.second(form); 1.4768 + if((bindings.count() % 2) != 0) 1.4769 + throw new IllegalArgumentException("Bad binding form, expected matched symbol expression pairs"); 1.4770 + 1.4771 + ISeq body = RT.next(RT.next(form)); 1.4772 + 1.4773 + if(context == C.EVAL) 1.4774 + return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form))); 1.4775 + 1.4776 + IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(), 1.4777 + NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref()); 1.4778 + 1.4779 + try 1.4780 + { 1.4781 + Var.pushThreadBindings(dynamicBindings); 1.4782 + 1.4783 + //pre-seed env (like Lisp labels) 1.4784 + PersistentVector lbs = PersistentVector.EMPTY; 1.4785 + for(int i = 0; i < bindings.count(); i += 2) 1.4786 + { 1.4787 + if(!(bindings.nth(i) instanceof Symbol)) 1.4788 + throw new IllegalArgumentException( 1.4789 + "Bad binding form, expected symbol, got: " + bindings.nth(i)); 1.4790 + Symbol sym = (Symbol) bindings.nth(i); 1.4791 + if(sym.getNamespace() != null) 1.4792 + throw new Exception("Can't let qualified name: " + sym); 1.4793 + LocalBinding lb = registerLocal(sym, tagOf(sym), null,false); 1.4794 + lb.canBeCleared = false; 1.4795 + lbs = lbs.cons(lb); 1.4796 + } 1.4797 + PersistentVector bindingInits = PersistentVector.EMPTY; 1.4798 + for(int i = 0; i < bindings.count(); i += 2) 1.4799 + { 1.4800 + Symbol sym = (Symbol) bindings.nth(i); 1.4801 + Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name); 1.4802 + LocalBinding lb = (LocalBinding) lbs.nth(i / 2); 1.4803 + lb.init = init; 1.4804 + BindingInit bi = new BindingInit(lb, init); 1.4805 + bindingInits = bindingInits.cons(bi); 1.4806 + } 1.4807 + return new LetFnExpr(bindingInits, (new BodyExpr.Parser()).parse(context, body)); 1.4808 + } 1.4809 + finally 1.4810 + { 1.4811 + Var.popThreadBindings(); 1.4812 + } 1.4813 + } 1.4814 + } 1.4815 + 1.4816 + public Object eval() throws Exception{ 1.4817 + throw new UnsupportedOperationException("Can't eval letfns"); 1.4818 + } 1.4819 + 1.4820 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4821 + for(int i = 0; i < bindingInits.count(); i++) 1.4822 + { 1.4823 + BindingInit bi = (BindingInit) bindingInits.nth(i); 1.4824 + gen.visitInsn(Opcodes.ACONST_NULL); 1.4825 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), bi.binding.idx); 1.4826 + } 1.4827 + 1.4828 + IPersistentSet lbset = PersistentHashSet.EMPTY; 1.4829 + 1.4830 + for(int i = 0; i < bindingInits.count(); i++) 1.4831 + { 1.4832 + BindingInit bi = (BindingInit) bindingInits.nth(i); 1.4833 + lbset = (IPersistentSet) lbset.cons(bi.binding); 1.4834 + bi.init.emit(C.EXPRESSION, objx, gen); 1.4835 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), bi.binding.idx); 1.4836 + } 1.4837 + 1.4838 + for(int i = 0; i < bindingInits.count(); i++) 1.4839 + { 1.4840 + BindingInit bi = (BindingInit) bindingInits.nth(i); 1.4841 + ObjExpr fe = (ObjExpr) bi.init; 1.4842 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), bi.binding.idx); 1.4843 + fe.emitLetFnInits(gen, objx, lbset); 1.4844 + } 1.4845 + 1.4846 + Label loopLabel = gen.mark(); 1.4847 + 1.4848 + body.emit(context, objx, gen); 1.4849 + 1.4850 + Label end = gen.mark(); 1.4851 +// gen.visitLocalVariable("this", "Ljava/lang/Object;", null, loopLabel, end, 0); 1.4852 + for(ISeq bis = bindingInits.seq(); bis != null; bis = bis.next()) 1.4853 + { 1.4854 + BindingInit bi = (BindingInit) bis.first(); 1.4855 + String lname = bi.binding.name; 1.4856 + if(lname.endsWith("__auto__")) 1.4857 + lname += RT.nextID(); 1.4858 + Class primc = maybePrimitiveType(bi.init); 1.4859 + if(primc != null) 1.4860 + gen.visitLocalVariable(lname, Type.getDescriptor(primc), null, loopLabel, end, 1.4861 + bi.binding.idx); 1.4862 + else 1.4863 + gen.visitLocalVariable(lname, "Ljava/lang/Object;", null, loopLabel, end, bi.binding.idx); 1.4864 + } 1.4865 + } 1.4866 + 1.4867 + public boolean hasJavaClass() throws Exception{ 1.4868 + return body.hasJavaClass(); 1.4869 + } 1.4870 + 1.4871 + public Class getJavaClass() throws Exception{ 1.4872 + return body.getJavaClass(); 1.4873 + } 1.4874 +} 1.4875 + 1.4876 +public static class LetExpr implements Expr, MaybePrimitiveExpr{ 1.4877 + public final PersistentVector bindingInits; 1.4878 + public final Expr body; 1.4879 + public final boolean isLoop; 1.4880 + 1.4881 + public LetExpr(PersistentVector bindingInits, Expr body, boolean isLoop){ 1.4882 + this.bindingInits = bindingInits; 1.4883 + this.body = body; 1.4884 + this.isLoop = isLoop; 1.4885 + } 1.4886 + 1.4887 + static class Parser implements IParser{ 1.4888 + public Expr parse(C context, Object frm) throws Exception{ 1.4889 + ISeq form = (ISeq) frm; 1.4890 + //(let [var val var2 val2 ...] body...) 1.4891 + boolean isLoop = RT.first(form).equals(LOOP); 1.4892 + if(!(RT.second(form) instanceof IPersistentVector)) 1.4893 + throw new IllegalArgumentException("Bad binding form, expected vector"); 1.4894 + 1.4895 + IPersistentVector bindings = (IPersistentVector) RT.second(form); 1.4896 + if((bindings.count() % 2) != 0) 1.4897 + throw new IllegalArgumentException("Bad binding form, expected matched symbol expression pairs"); 1.4898 + 1.4899 + ISeq body = RT.next(RT.next(form)); 1.4900 + 1.4901 + if(context == C.EVAL 1.4902 + || (context == C.EXPRESSION && isLoop)) 1.4903 + return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form))); 1.4904 + 1.4905 + IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(), 1.4906 + NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref()); 1.4907 + if(isLoop) 1.4908 + dynamicBindings = dynamicBindings.assoc(LOOP_LOCALS, null); 1.4909 + 1.4910 + try 1.4911 + { 1.4912 + Var.pushThreadBindings(dynamicBindings); 1.4913 + 1.4914 + PersistentVector bindingInits = PersistentVector.EMPTY; 1.4915 + PersistentVector loopLocals = PersistentVector.EMPTY; 1.4916 + for(int i = 0; i < bindings.count(); i += 2) 1.4917 + { 1.4918 + if(!(bindings.nth(i) instanceof Symbol)) 1.4919 + throw new IllegalArgumentException( 1.4920 + "Bad binding form, expected symbol, got: " + bindings.nth(i)); 1.4921 + Symbol sym = (Symbol) bindings.nth(i); 1.4922 + if(sym.getNamespace() != null) 1.4923 + throw new Exception("Can't let qualified name: " + sym); 1.4924 + Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name); 1.4925 + //sequential enhancement of env (like Lisp let*) 1.4926 + LocalBinding lb = registerLocal(sym, tagOf(sym), init,false); 1.4927 + BindingInit bi = new BindingInit(lb, init); 1.4928 + bindingInits = bindingInits.cons(bi); 1.4929 + 1.4930 + if(isLoop) 1.4931 + loopLocals = loopLocals.cons(lb); 1.4932 + } 1.4933 + if(isLoop) 1.4934 + LOOP_LOCALS.set(loopLocals); 1.4935 + Expr bodyExpr; 1.4936 + try { 1.4937 + if(isLoop) 1.4938 + { 1.4939 + PathNode root = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get()); 1.4940 + Var.pushThreadBindings( 1.4941 + RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,root), 1.4942 + CLEAR_ROOT, new PathNode(PATHTYPE.PATH,root))); 1.4943 + } 1.4944 + bodyExpr = (new BodyExpr.Parser()).parse(isLoop ? C.RETURN : context, body); 1.4945 + } 1.4946 + finally{ 1.4947 + if(isLoop) 1.4948 + Var.popThreadBindings(); 1.4949 + } 1.4950 + return new LetExpr(bindingInits, bodyExpr, 1.4951 + isLoop); 1.4952 + } 1.4953 + finally 1.4954 + { 1.4955 + Var.popThreadBindings(); 1.4956 + } 1.4957 + } 1.4958 + } 1.4959 + 1.4960 + public Object eval() throws Exception{ 1.4961 + throw new UnsupportedOperationException("Can't eval let/loop"); 1.4962 + } 1.4963 + 1.4964 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4965 + doEmit(context, objx, gen, false); 1.4966 + } 1.4967 + 1.4968 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.4969 + doEmit(context, objx, gen, true); 1.4970 + } 1.4971 + 1.4972 + 1.4973 + public void doEmit(C context, ObjExpr objx, GeneratorAdapter gen, boolean emitUnboxed){ 1.4974 + for(int i = 0; i < bindingInits.count(); i++) 1.4975 + { 1.4976 + BindingInit bi = (BindingInit) bindingInits.nth(i); 1.4977 + Class primc = maybePrimitiveType(bi.init); 1.4978 + if(primc != null) 1.4979 + { 1.4980 + ((MaybePrimitiveExpr) bi.init).emitUnboxed(C.EXPRESSION, objx, gen); 1.4981 + gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ISTORE), bi.binding.idx); 1.4982 + } 1.4983 + else 1.4984 + { 1.4985 + bi.init.emit(C.EXPRESSION, objx, gen); 1.4986 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), bi.binding.idx); 1.4987 + } 1.4988 + } 1.4989 + Label loopLabel = gen.mark(); 1.4990 + if(isLoop) 1.4991 + { 1.4992 + try 1.4993 + { 1.4994 + Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel)); 1.4995 + if(emitUnboxed) 1.4996 + ((MaybePrimitiveExpr)body).emitUnboxed(context, objx, gen); 1.4997 + else 1.4998 + body.emit(context, objx, gen); 1.4999 + } 1.5000 + finally 1.5001 + { 1.5002 + Var.popThreadBindings(); 1.5003 + } 1.5004 + } 1.5005 + else 1.5006 + { 1.5007 + if(emitUnboxed) 1.5008 + ((MaybePrimitiveExpr)body).emitUnboxed(context, objx, gen); 1.5009 + else 1.5010 + body.emit(context, objx, gen); 1.5011 + } 1.5012 + Label end = gen.mark(); 1.5013 +// gen.visitLocalVariable("this", "Ljava/lang/Object;", null, loopLabel, end, 0); 1.5014 + for(ISeq bis = bindingInits.seq(); bis != null; bis = bis.next()) 1.5015 + { 1.5016 + BindingInit bi = (BindingInit) bis.first(); 1.5017 + String lname = bi.binding.name; 1.5018 + if(lname.endsWith("__auto__")) 1.5019 + lname += RT.nextID(); 1.5020 + Class primc = maybePrimitiveType(bi.init); 1.5021 + if(primc != null) 1.5022 + gen.visitLocalVariable(lname, Type.getDescriptor(primc), null, loopLabel, end, 1.5023 + bi.binding.idx); 1.5024 + else 1.5025 + gen.visitLocalVariable(lname, "Ljava/lang/Object;", null, loopLabel, end, bi.binding.idx); 1.5026 + } 1.5027 + } 1.5028 + 1.5029 + public boolean hasJavaClass() throws Exception{ 1.5030 + return body.hasJavaClass(); 1.5031 + } 1.5032 + 1.5033 + public Class getJavaClass() throws Exception{ 1.5034 + return body.getJavaClass(); 1.5035 + } 1.5036 + 1.5037 + public boolean canEmitPrimitive(){ 1.5038 + return body instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr)body).canEmitPrimitive(); 1.5039 + } 1.5040 + 1.5041 +} 1.5042 + 1.5043 +public static class RecurExpr implements Expr{ 1.5044 + public final IPersistentVector args; 1.5045 + public final IPersistentVector loopLocals; 1.5046 + 1.5047 + public RecurExpr(IPersistentVector loopLocals, IPersistentVector args){ 1.5048 + this.loopLocals = loopLocals; 1.5049 + this.args = args; 1.5050 + } 1.5051 + 1.5052 + public Object eval() throws Exception{ 1.5053 + throw new UnsupportedOperationException("Can't eval recur"); 1.5054 + } 1.5055 + 1.5056 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.5057 + Label loopLabel = (Label) LOOP_LABEL.deref(); 1.5058 + if(loopLabel == null) 1.5059 + throw new IllegalStateException(); 1.5060 + for(int i = 0; i < loopLocals.count(); i++) 1.5061 + { 1.5062 + LocalBinding lb = (LocalBinding) loopLocals.nth(i); 1.5063 + Expr arg = (Expr) args.nth(i); 1.5064 + if(lb.getPrimitiveType() != null) 1.5065 + { 1.5066 + Class primc = lb.getPrimitiveType(); 1.5067 + try 1.5068 + { 1.5069 + if(!(arg instanceof MaybePrimitiveExpr && arg.hasJavaClass() && arg.getJavaClass() == primc)) 1.5070 + throw new IllegalArgumentException("recur arg for primitive local: " + 1.5071 + lb.name + " must be matching primitive"); 1.5072 + } 1.5073 + catch(Exception e) 1.5074 + { 1.5075 + throw new RuntimeException(e); 1.5076 + } 1.5077 + ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); 1.5078 + } 1.5079 + else 1.5080 + { 1.5081 + arg.emit(C.EXPRESSION, objx, gen); 1.5082 + } 1.5083 + } 1.5084 + 1.5085 + for(int i = loopLocals.count() - 1; i >= 0; i--) 1.5086 + { 1.5087 + LocalBinding lb = (LocalBinding) loopLocals.nth(i); 1.5088 + Class primc = lb.getPrimitiveType(); 1.5089 + if(lb.isArg) 1.5090 + gen.storeArg(lb.idx-1); 1.5091 + else 1.5092 + { 1.5093 + if(primc != null) 1.5094 + gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ISTORE), lb.idx); 1.5095 + else 1.5096 + gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), lb.idx); 1.5097 + } 1.5098 + } 1.5099 + 1.5100 + gen.goTo(loopLabel); 1.5101 + } 1.5102 + 1.5103 + public boolean hasJavaClass() throws Exception{ 1.5104 + return true; 1.5105 + } 1.5106 + 1.5107 + public Class getJavaClass() throws Exception{ 1.5108 + return null; 1.5109 + } 1.5110 + 1.5111 + static class Parser implements IParser{ 1.5112 + public Expr parse(C context, Object frm) throws Exception{ 1.5113 + ISeq form = (ISeq) frm; 1.5114 + IPersistentVector loopLocals = (IPersistentVector) LOOP_LOCALS.deref(); 1.5115 + if(context != C.RETURN || loopLocals == null) 1.5116 + throw new UnsupportedOperationException("Can only recur from tail position"); 1.5117 + if(IN_CATCH_FINALLY.deref() != null) 1.5118 + throw new UnsupportedOperationException("Cannot recur from catch/finally"); 1.5119 + PersistentVector args = PersistentVector.EMPTY; 1.5120 + for(ISeq s = RT.seq(form.next()); s != null; s = s.next()) 1.5121 + { 1.5122 + args = args.cons(analyze(C.EXPRESSION, s.first())); 1.5123 + } 1.5124 + if(args.count() != loopLocals.count()) 1.5125 + throw new IllegalArgumentException( 1.5126 + String.format("Mismatched argument count to recur, expected: %d args, got: %d", 1.5127 + loopLocals.count(), args.count())); 1.5128 + return new RecurExpr(loopLocals, args); 1.5129 + } 1.5130 + } 1.5131 +} 1.5132 + 1.5133 +private static LocalBinding registerLocal(Symbol sym, Symbol tag, Expr init, boolean isArg) throws Exception{ 1.5134 + int num = getAndIncLocalNum(); 1.5135 + LocalBinding b = new LocalBinding(num, sym, tag, init, isArg, clearPathRoot()); 1.5136 + IPersistentMap localsMap = (IPersistentMap) LOCAL_ENV.deref(); 1.5137 + LOCAL_ENV.set(RT.assoc(localsMap, b.sym, b)); 1.5138 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.5139 + method.locals = (IPersistentMap) RT.assoc(method.locals, b, b); 1.5140 + method.indexlocals = (IPersistentMap) RT.assoc(method.indexlocals, num, b); 1.5141 + return b; 1.5142 +} 1.5143 + 1.5144 +private static int getAndIncLocalNum(){ 1.5145 + int num = ((Number) NEXT_LOCAL_NUM.deref()).intValue(); 1.5146 + ObjMethod m = (ObjMethod) METHOD.deref(); 1.5147 + if(num > m.maxLocal) 1.5148 + m.maxLocal = num; 1.5149 + NEXT_LOCAL_NUM.set(num + 1); 1.5150 + return num; 1.5151 +} 1.5152 + 1.5153 +public static Expr analyze(C context, Object form) throws Exception{ 1.5154 + return analyze(context, form, null); 1.5155 +} 1.5156 + 1.5157 +private static Expr analyze(C context, Object form, String name) throws Exception{ 1.5158 + //todo symbol macro expansion? 1.5159 + try 1.5160 + { 1.5161 + if(form instanceof LazySeq) 1.5162 + { 1.5163 + form = RT.seq(form); 1.5164 + if(form == null) 1.5165 + form = PersistentList.EMPTY; 1.5166 + } 1.5167 + if(form == null) 1.5168 + return NIL_EXPR; 1.5169 + else if(form == Boolean.TRUE) 1.5170 + return TRUE_EXPR; 1.5171 + else if(form == Boolean.FALSE) 1.5172 + return FALSE_EXPR; 1.5173 + Class fclass = form.getClass(); 1.5174 + if(fclass == Symbol.class) 1.5175 + return analyzeSymbol((Symbol) form); 1.5176 + else if(fclass == Keyword.class) 1.5177 + return registerKeyword((Keyword) form); 1.5178 +// else if(form instanceof Num) 1.5179 +// return new NumExpr((Num) form); 1.5180 + else if(fclass == String.class) 1.5181 + return new StringExpr(((String) form).intern()); 1.5182 +// else if(fclass == Character.class) 1.5183 +// return new CharExpr((Character) form); 1.5184 + else if(form instanceof IPersistentCollection && ((IPersistentCollection) form).count() == 0) 1.5185 + { 1.5186 + Expr ret = new EmptyExpr(form); 1.5187 + if(RT.meta(form) != null) 1.5188 + ret = new MetaExpr(ret, (MapExpr) MapExpr 1.5189 + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); 1.5190 + return ret; 1.5191 + } 1.5192 + else if(form instanceof ISeq) 1.5193 + return analyzeSeq(context, (ISeq) form, name); 1.5194 + else if(form instanceof IPersistentVector) 1.5195 + return VectorExpr.parse(context, (IPersistentVector) form); 1.5196 + else if(form instanceof IPersistentMap) 1.5197 + return MapExpr.parse(context, (IPersistentMap) form); 1.5198 + else if(form instanceof IPersistentSet) 1.5199 + return SetExpr.parse(context, (IPersistentSet) form); 1.5200 + 1.5201 +// else 1.5202 + //throw new UnsupportedOperationException(); 1.5203 + return new ConstantExpr(form); 1.5204 + } 1.5205 + catch(Throwable e) 1.5206 + { 1.5207 + if(!(e instanceof CompilerException)) 1.5208 + throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e); 1.5209 + else 1.5210 + throw (CompilerException) e; 1.5211 + } 1.5212 +} 1.5213 + 1.5214 +static public class CompilerException extends Exception{ 1.5215 + 1.5216 + public CompilerException(String source, int line, Throwable cause){ 1.5217 + super(errorMsg(source, line, cause.toString()), cause); 1.5218 + } 1.5219 + 1.5220 + public String toString(){ 1.5221 + return getMessage(); 1.5222 + } 1.5223 +} 1.5224 + 1.5225 +static public Var isMacro(Object op) throws Exception{ 1.5226 + //no local macros for now 1.5227 + if(op instanceof Symbol && referenceLocal((Symbol) op) != null) 1.5228 + return null; 1.5229 + if(op instanceof Symbol || op instanceof Var) 1.5230 + { 1.5231 + Var v = (op instanceof Var) ? (Var) op : lookupVar((Symbol) op, false); 1.5232 + if(v != null && v.isMacro()) 1.5233 + { 1.5234 + if(v.ns != currentNS() && !v.isPublic()) 1.5235 + throw new IllegalStateException("var: " + v + " is not public"); 1.5236 + return v; 1.5237 + } 1.5238 + } 1.5239 + return null; 1.5240 +} 1.5241 + 1.5242 +static public IFn isInline(Object op, int arity) throws Exception{ 1.5243 + //no local inlines for now 1.5244 + if(op instanceof Symbol && referenceLocal((Symbol) op) != null) 1.5245 + return null; 1.5246 + if(op instanceof Symbol || op instanceof Var) 1.5247 + { 1.5248 + Var v = (op instanceof Var) ? (Var) op : lookupVar((Symbol) op, false); 1.5249 + if(v != null) 1.5250 + { 1.5251 + if(v.ns != currentNS() && !v.isPublic()) 1.5252 + throw new IllegalStateException("var: " + v + " is not public"); 1.5253 + IFn ret = (IFn) RT.get(v.meta(), inlineKey); 1.5254 + if(ret != null) 1.5255 + { 1.5256 + IFn arityPred = (IFn) RT.get(v.meta(), inlineAritiesKey); 1.5257 + if(arityPred == null || RT.booleanCast(arityPred.invoke(arity))) 1.5258 + return ret; 1.5259 + } 1.5260 + } 1.5261 + } 1.5262 + return null; 1.5263 +} 1.5264 + 1.5265 +public static boolean namesStaticMember(Symbol sym){ 1.5266 + return sym.ns != null && namespaceFor(sym) == null; 1.5267 +} 1.5268 + 1.5269 +public static Object preserveTag(ISeq src, Object dst) { 1.5270 + Symbol tag = tagOf(src); 1.5271 + if (tag != null && dst instanceof IObj) { 1.5272 + IPersistentMap meta = RT.meta(dst); 1.5273 + return ((IObj) dst).withMeta((IPersistentMap) RT.assoc(meta, RT.TAG_KEY, tag)); 1.5274 + } 1.5275 + return dst; 1.5276 +} 1.5277 + 1.5278 +public static Object macroexpand1(Object x) throws Exception{ 1.5279 + if(x instanceof ISeq) 1.5280 + { 1.5281 + ISeq form = (ISeq) x; 1.5282 + Object op = RT.first(form); 1.5283 + if(isSpecial(op)) 1.5284 + return x; 1.5285 + //macro expansion 1.5286 + Var v = isMacro(op); 1.5287 + if(v != null) 1.5288 + { 1.5289 + return v.applyTo(RT.cons(form,RT.cons(LOCAL_ENV.get(),form.next()))); 1.5290 + } 1.5291 + else 1.5292 + { 1.5293 + if(op instanceof Symbol) 1.5294 + { 1.5295 + Symbol sym = (Symbol) op; 1.5296 + String sname = sym.name; 1.5297 + //(.substring s 2 5) => (. s substring 2 5) 1.5298 + if(sym.name.charAt(0) == '.') 1.5299 + { 1.5300 + if(RT.length(form) < 2) 1.5301 + throw new IllegalArgumentException( 1.5302 + "Malformed member expression, expecting (.member target ...)"); 1.5303 + Symbol meth = Symbol.intern(sname.substring(1)); 1.5304 + Object target = RT.second(form); 1.5305 + if(HostExpr.maybeClass(target, false) != null) 1.5306 + { 1.5307 + target = ((IObj)RT.list(IDENTITY, target)).withMeta(RT.map(RT.TAG_KEY,CLASS)); 1.5308 + } 1.5309 + return preserveTag(form, RT.listStar(DOT, target, meth, form.next().next())); 1.5310 + } 1.5311 + else if(namesStaticMember(sym)) 1.5312 + { 1.5313 + Symbol target = Symbol.intern(sym.ns); 1.5314 + Class c = HostExpr.maybeClass(target, false); 1.5315 + if(c != null) 1.5316 + { 1.5317 + Symbol meth = Symbol.intern(sym.name); 1.5318 + return preserveTag(form, RT.listStar(DOT, target, meth, form.next())); 1.5319 + } 1.5320 + } 1.5321 + else 1.5322 + { 1.5323 + //(s.substring 2 5) => (. s substring 2 5) 1.5324 + //also (package.class.name ...) (. package.class name ...) 1.5325 + int idx = sname.lastIndexOf('.'); 1.5326 +// if(idx > 0 && idx < sname.length() - 1) 1.5327 +// { 1.5328 +// Symbol target = Symbol.intern(sname.substring(0, idx)); 1.5329 +// Symbol meth = Symbol.intern(sname.substring(idx + 1)); 1.5330 +// return RT.listStar(DOT, target, meth, form.rest()); 1.5331 +// } 1.5332 + //(StringBuilder. "foo") => (new StringBuilder "foo") 1.5333 + //else 1.5334 + if(idx == sname.length() - 1) 1.5335 + return RT.listStar(NEW, Symbol.intern(sname.substring(0, idx)), form.next()); 1.5336 + } 1.5337 + } 1.5338 + } 1.5339 + } 1.5340 + return x; 1.5341 +} 1.5342 + 1.5343 +static Object macroexpand(Object form) throws Exception{ 1.5344 + Object exf = macroexpand1(form); 1.5345 + if(exf != form) 1.5346 + return macroexpand(exf); 1.5347 + return form; 1.5348 +} 1.5349 + 1.5350 +private static Expr analyzeSeq(C context, ISeq form, String name) throws Exception{ 1.5351 + Integer line = (Integer) LINE.deref(); 1.5352 + if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY)) 1.5353 + line = (Integer) RT.meta(form).valAt(RT.LINE_KEY); 1.5354 + Var.pushThreadBindings( 1.5355 + RT.map(LINE, line)); 1.5356 + try 1.5357 + { 1.5358 + Object me = macroexpand1(form); 1.5359 + if(me != form) 1.5360 + return analyze(context, me, name); 1.5361 + 1.5362 + Object op = RT.first(form); 1.5363 + if(op == null) 1.5364 + throw new IllegalArgumentException("Can't call nil"); 1.5365 + IFn inline = isInline(op, RT.count(RT.next(form))); 1.5366 + if(inline != null) 1.5367 + return analyze(context, preserveTag(form, inline.applyTo(RT.next(form)))); 1.5368 + IParser p; 1.5369 + if(op.equals(FN)) 1.5370 + return FnExpr.parse(context, form, name); 1.5371 + else if((p = (IParser) specials.valAt(op)) != null) 1.5372 + return p.parse(context, form); 1.5373 + else 1.5374 + return InvokeExpr.parse(context, form); 1.5375 + } 1.5376 + catch(Throwable e) 1.5377 + { 1.5378 + if(!(e instanceof CompilerException)) 1.5379 + throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e); 1.5380 + else 1.5381 + throw (CompilerException) e; 1.5382 + } 1.5383 + finally 1.5384 + { 1.5385 + Var.popThreadBindings(); 1.5386 + } 1.5387 +} 1.5388 + 1.5389 +static String errorMsg(String source, int line, String s){ 1.5390 + return String.format("%s (%s:%d)", s, source, line); 1.5391 +} 1.5392 + 1.5393 +public static Object eval(Object form) throws Exception{ 1.5394 + return eval(form, true); 1.5395 +} 1.5396 + 1.5397 +public static Object eval(Object form, boolean freshLoader) throws Exception{ 1.5398 + boolean createdLoader = false; 1.5399 + if(true)//!LOADER.isBound()) 1.5400 + { 1.5401 + Var.pushThreadBindings(RT.map(LOADER, RT.makeClassLoader())); 1.5402 + createdLoader = true; 1.5403 + } 1.5404 + try 1.5405 + { 1.5406 + Integer line = (Integer) LINE.deref(); 1.5407 + if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY)) 1.5408 + line = (Integer) RT.meta(form).valAt(RT.LINE_KEY); 1.5409 + Var.pushThreadBindings(RT.map(LINE, line)); 1.5410 + try 1.5411 + { 1.5412 + form = macroexpand(form); 1.5413 + if(form instanceof IPersistentCollection && Util.equals(RT.first(form), DO)) 1.5414 + { 1.5415 + ISeq s = RT.next(form); 1.5416 + for(; RT.next(s) != null; s = RT.next(s)) 1.5417 + eval(RT.first(s),false); 1.5418 + return eval(RT.first(s),false); 1.5419 + } 1.5420 + else if(form instanceof IPersistentCollection 1.5421 + && !(RT.first(form) instanceof Symbol 1.5422 + && ((Symbol) RT.first(form)).name.startsWith("def"))) 1.5423 + { 1.5424 + ObjExpr fexpr = (ObjExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form), 1.5425 + "eval" + RT.nextID()); 1.5426 + IFn fn = (IFn) fexpr.eval(); 1.5427 + return fn.invoke(); 1.5428 + } 1.5429 + else 1.5430 + { 1.5431 + Expr expr = analyze(C.EVAL, form); 1.5432 + return expr.eval(); 1.5433 + } 1.5434 + } 1.5435 + finally 1.5436 + { 1.5437 + Var.popThreadBindings(); 1.5438 + } 1.5439 + } 1.5440 + catch(Throwable e) 1.5441 + { 1.5442 + if(!(e instanceof CompilerException)) 1.5443 + throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e); 1.5444 + else 1.5445 + throw (CompilerException) e; 1.5446 + } 1.5447 + finally 1.5448 + { 1.5449 + if(createdLoader) 1.5450 + Var.popThreadBindings(); 1.5451 + } 1.5452 +} 1.5453 + 1.5454 +private static int registerConstant(Object o){ 1.5455 + if(!CONSTANTS.isBound()) 1.5456 + return -1; 1.5457 + PersistentVector v = (PersistentVector) CONSTANTS.deref(); 1.5458 + IdentityHashMap<Object,Integer> ids = (IdentityHashMap<Object,Integer>) CONSTANT_IDS.deref(); 1.5459 + Integer i = ids.get(o); 1.5460 + if(i != null) 1.5461 + return i; 1.5462 + CONSTANTS.set(RT.conj(v, o)); 1.5463 + ids.put(o, v.count()); 1.5464 + return v.count(); 1.5465 +} 1.5466 + 1.5467 +private static KeywordExpr registerKeyword(Keyword keyword){ 1.5468 + if(!KEYWORDS.isBound()) 1.5469 + return new KeywordExpr(keyword); 1.5470 + 1.5471 + IPersistentMap keywordsMap = (IPersistentMap) KEYWORDS.deref(); 1.5472 + Object id = RT.get(keywordsMap, keyword); 1.5473 + if(id == null) 1.5474 + { 1.5475 + KEYWORDS.set(RT.assoc(keywordsMap, keyword, registerConstant(keyword))); 1.5476 + } 1.5477 + return new KeywordExpr(keyword); 1.5478 +// KeywordExpr ke = (KeywordExpr) RT.get(keywordsMap, keyword); 1.5479 +// if(ke == null) 1.5480 +// KEYWORDS.set(RT.assoc(keywordsMap, keyword, ke = new KeywordExpr(keyword))); 1.5481 +// return ke; 1.5482 +} 1.5483 + 1.5484 +private static int registerKeywordCallsite(Keyword keyword){ 1.5485 + if(!KEYWORD_CALLSITES.isBound()) 1.5486 + throw new IllegalAccessError("KEYWORD_CALLSITES is not bound"); 1.5487 + 1.5488 + IPersistentVector keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); 1.5489 + 1.5490 + keywordCallsites = keywordCallsites.cons(keyword); 1.5491 + KEYWORD_CALLSITES.set(keywordCallsites); 1.5492 + return keywordCallsites.count()-1; 1.5493 +} 1.5494 + 1.5495 +private static int registerProtocolCallsite(Var v){ 1.5496 + if(!PROTOCOL_CALLSITES.isBound()) 1.5497 + throw new IllegalAccessError("PROTOCOL_CALLSITES is not bound"); 1.5498 + 1.5499 + IPersistentVector protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); 1.5500 + 1.5501 + protocolCallsites = protocolCallsites.cons(v); 1.5502 + PROTOCOL_CALLSITES.set(protocolCallsites); 1.5503 + return protocolCallsites.count()-1; 1.5504 +} 1.5505 + 1.5506 +private static int registerVarCallsite(Var v){ 1.5507 + if(!VAR_CALLSITES.isBound()) 1.5508 + throw new IllegalAccessError("VAR_CALLSITES is not bound"); 1.5509 + 1.5510 + IPersistentVector varCallsites = (IPersistentVector) VAR_CALLSITES.deref(); 1.5511 + 1.5512 + varCallsites = varCallsites.cons(v); 1.5513 + VAR_CALLSITES.set(varCallsites); 1.5514 + return varCallsites.count()-1; 1.5515 +} 1.5516 + 1.5517 +static ISeq fwdPath(PathNode p1){ 1.5518 + ISeq ret = null; 1.5519 + for(;p1 != null;p1 = p1.parent) 1.5520 + ret = RT.cons(p1,ret); 1.5521 + return ret; 1.5522 +} 1.5523 + 1.5524 +static PathNode commonPath(PathNode n1, PathNode n2){ 1.5525 + ISeq xp = fwdPath(n1); 1.5526 + ISeq yp = fwdPath(n2); 1.5527 + if(RT.first(xp) != RT.first(yp)) 1.5528 + return null; 1.5529 + while(RT.second(xp) != null && RT.second(xp) == RT.second(yp)) 1.5530 + { 1.5531 + xp = xp.next(); 1.5532 + yp = yp.next(); 1.5533 + } 1.5534 + return (PathNode) RT.first(xp); 1.5535 +} 1.5536 + 1.5537 +static void addAnnotation(Object visitor, IPersistentMap meta){ 1.5538 + try{ 1.5539 + if(meta != null && ADD_ANNOTATIONS.isBound()) 1.5540 + ADD_ANNOTATIONS.invoke(visitor, meta); 1.5541 + } 1.5542 + catch (Exception e) 1.5543 + { 1.5544 + throw new RuntimeException(e); 1.5545 + } 1.5546 +} 1.5547 + 1.5548 +static void addParameterAnnotation(Object visitor, IPersistentMap meta, int i){ 1.5549 + try{ 1.5550 + if(meta != null && ADD_ANNOTATIONS.isBound()) 1.5551 + ADD_ANNOTATIONS.invoke(visitor, meta, i); 1.5552 + } 1.5553 + catch (Exception e) 1.5554 + { 1.5555 + throw new RuntimeException(e); 1.5556 + } 1.5557 +} 1.5558 + 1.5559 +private static Expr analyzeSymbol(Symbol sym) throws Exception{ 1.5560 + Symbol tag = tagOf(sym); 1.5561 + if(sym.ns == null) //ns-qualified syms are always Vars 1.5562 + { 1.5563 + LocalBinding b = referenceLocal(sym); 1.5564 + if(b != null) 1.5565 + { 1.5566 + return new LocalBindingExpr(b, tag); 1.5567 + } 1.5568 + } 1.5569 + else 1.5570 + { 1.5571 + if(namespaceFor(sym) == null) 1.5572 + { 1.5573 + Symbol nsSym = Symbol.create(sym.ns); 1.5574 + Class c = HostExpr.maybeClass(nsSym, false); 1.5575 + if(c != null) 1.5576 + { 1.5577 + if(Reflector.getField(c, sym.name, true) != null) 1.5578 + return new StaticFieldExpr((Integer) LINE.deref(), c, sym.name, tag); 1.5579 + throw new Exception("Unable to find static field: " + sym.name + " in " + c); 1.5580 + } 1.5581 + } 1.5582 + } 1.5583 + //Var v = lookupVar(sym, false); 1.5584 +// Var v = lookupVar(sym, false); 1.5585 +// if(v != null) 1.5586 +// return new VarExpr(v, tag); 1.5587 + Object o = resolve(sym); 1.5588 + if(o instanceof Var) 1.5589 + { 1.5590 + Var v = (Var) o; 1.5591 + if(isMacro(v) != null) 1.5592 + throw new Exception("Can't take value of a macro: " + v); 1.5593 + registerVar(v); 1.5594 + return new VarExpr(v, tag); 1.5595 + } 1.5596 + else if(o instanceof Class) 1.5597 + return new ConstantExpr(o); 1.5598 + else if(o instanceof Symbol) 1.5599 + return new UnresolvedVarExpr((Symbol) o); 1.5600 + 1.5601 + throw new Exception("Unable to resolve symbol: " + sym + " in this context"); 1.5602 + 1.5603 +} 1.5604 + 1.5605 +static String destubClassName(String className){ 1.5606 + //skip over prefix + '.' or '/' 1.5607 + if(className.startsWith(COMPILE_STUB_PREFIX)) 1.5608 + return className.substring(COMPILE_STUB_PREFIX.length()+1); 1.5609 + return className; 1.5610 +} 1.5611 + 1.5612 +static Type getType(Class c){ 1.5613 + String descriptor = Type.getType(c).getDescriptor(); 1.5614 + if(descriptor.startsWith("L")) 1.5615 + descriptor = "L" + destubClassName(descriptor.substring(1)); 1.5616 + return Type.getType(descriptor); 1.5617 +} 1.5618 + 1.5619 +static Object resolve(Symbol sym, boolean allowPrivate) throws Exception{ 1.5620 + return resolveIn(currentNS(), sym, allowPrivate); 1.5621 +} 1.5622 + 1.5623 +static Object resolve(Symbol sym) throws Exception{ 1.5624 + return resolveIn(currentNS(), sym, false); 1.5625 +} 1.5626 + 1.5627 +static Namespace namespaceFor(Symbol sym){ 1.5628 + return namespaceFor(currentNS(), sym); 1.5629 +} 1.5630 + 1.5631 +static Namespace namespaceFor(Namespace inns, Symbol sym){ 1.5632 + //note, presumes non-nil sym.ns 1.5633 + // first check against currentNS' aliases... 1.5634 + Symbol nsSym = Symbol.create(sym.ns); 1.5635 + Namespace ns = inns.lookupAlias(nsSym); 1.5636 + if(ns == null) 1.5637 + { 1.5638 + // ...otherwise check the Namespaces map. 1.5639 + ns = Namespace.find(nsSym); 1.5640 + } 1.5641 + return ns; 1.5642 +} 1.5643 + 1.5644 +static public Object resolveIn(Namespace n, Symbol sym, boolean allowPrivate) throws Exception{ 1.5645 + //note - ns-qualified vars must already exist 1.5646 + if(sym.ns != null) 1.5647 + { 1.5648 + Namespace ns = namespaceFor(n, sym); 1.5649 + if(ns == null) 1.5650 + throw new Exception("No such namespace: " + sym.ns); 1.5651 + 1.5652 + Var v = ns.findInternedVar(Symbol.create(sym.name)); 1.5653 + if(v == null) 1.5654 + throw new Exception("No such var: " + sym); 1.5655 + else if(v.ns != currentNS() && !v.isPublic() && !allowPrivate) 1.5656 + throw new IllegalStateException("var: " + sym + " is not public"); 1.5657 + return v; 1.5658 + } 1.5659 + else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') 1.5660 + { 1.5661 + return RT.classForName(sym.name); 1.5662 + } 1.5663 + else if(sym.equals(NS)) 1.5664 + return RT.NS_VAR; 1.5665 + else if(sym.equals(IN_NS)) 1.5666 + return RT.IN_NS_VAR; 1.5667 + else 1.5668 + { 1.5669 + if(Util.equals(sym,COMPILE_STUB_SYM.get())) 1.5670 + return COMPILE_STUB_CLASS.get(); 1.5671 + Object o = n.getMapping(sym); 1.5672 + if(o == null) 1.5673 + { 1.5674 + if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref())) 1.5675 + { 1.5676 + return sym; 1.5677 + } 1.5678 + else 1.5679 + { 1.5680 + throw new Exception("Unable to resolve symbol: " + sym + " in this context"); 1.5681 + } 1.5682 + } 1.5683 + return o; 1.5684 + } 1.5685 +} 1.5686 + 1.5687 + 1.5688 +static public Object maybeResolveIn(Namespace n, Symbol sym) throws Exception{ 1.5689 + //note - ns-qualified vars must already exist 1.5690 + if(sym.ns != null) 1.5691 + { 1.5692 + Namespace ns = namespaceFor(n, sym); 1.5693 + if(ns == null) 1.5694 + return null; 1.5695 + Var v = ns.findInternedVar(Symbol.create(sym.name)); 1.5696 + if(v == null) 1.5697 + return null; 1.5698 + return v; 1.5699 + } 1.5700 + else if(sym.name.indexOf('.') > 0 && !sym.name.endsWith(".") 1.5701 + || sym.name.charAt(0) == '[') 1.5702 + { 1.5703 + return RT.classForName(sym.name); 1.5704 + } 1.5705 + else if(sym.equals(NS)) 1.5706 + return RT.NS_VAR; 1.5707 + else if(sym.equals(IN_NS)) 1.5708 + return RT.IN_NS_VAR; 1.5709 + else 1.5710 + { 1.5711 + Object o = n.getMapping(sym); 1.5712 + return o; 1.5713 + } 1.5714 +} 1.5715 + 1.5716 + 1.5717 +static Var lookupVar(Symbol sym, boolean internNew) throws Exception{ 1.5718 + Var var = null; 1.5719 + 1.5720 + //note - ns-qualified vars in other namespaces must already exist 1.5721 + if(sym.ns != null) 1.5722 + { 1.5723 + Namespace ns = namespaceFor(sym); 1.5724 + if(ns == null) 1.5725 + return null; 1.5726 + //throw new Exception("No such namespace: " + sym.ns); 1.5727 + Symbol name = Symbol.create(sym.name); 1.5728 + if(internNew && ns == currentNS()) 1.5729 + var = currentNS().intern(name); 1.5730 + else 1.5731 + var = ns.findInternedVar(name); 1.5732 + } 1.5733 + else if(sym.equals(NS)) 1.5734 + var = RT.NS_VAR; 1.5735 + else if(sym.equals(IN_NS)) 1.5736 + var = RT.IN_NS_VAR; 1.5737 + else 1.5738 + { 1.5739 + //is it mapped? 1.5740 + Object o = currentNS().getMapping(sym); 1.5741 + if(o == null) 1.5742 + { 1.5743 + //introduce a new var in the current ns 1.5744 + if(internNew) 1.5745 + var = currentNS().intern(Symbol.create(sym.name)); 1.5746 + } 1.5747 + else if(o instanceof Var) 1.5748 + { 1.5749 + var = (Var) o; 1.5750 + } 1.5751 + else 1.5752 + { 1.5753 + throw new Exception("Expecting var, but " + sym + " is mapped to " + o); 1.5754 + } 1.5755 + } 1.5756 + if(var != null) 1.5757 + registerVar(var); 1.5758 + return var; 1.5759 +} 1.5760 + 1.5761 +private static void registerVar(Var var) throws Exception{ 1.5762 + if(!VARS.isBound()) 1.5763 + return; 1.5764 + IPersistentMap varsMap = (IPersistentMap) VARS.deref(); 1.5765 + Object id = RT.get(varsMap, var); 1.5766 + if(id == null) 1.5767 + { 1.5768 + VARS.set(RT.assoc(varsMap, var, registerConstant(var))); 1.5769 + } 1.5770 +// if(varsMap != null && RT.get(varsMap, var) == null) 1.5771 +// VARS.set(RT.assoc(varsMap, var, var)); 1.5772 +} 1.5773 + 1.5774 +static Namespace currentNS(){ 1.5775 + return (Namespace) RT.CURRENT_NS.deref(); 1.5776 +} 1.5777 + 1.5778 +static void closeOver(LocalBinding b, ObjMethod method){ 1.5779 + if(b != null && method != null) 1.5780 + { 1.5781 + if(RT.get(method.locals, b) == null) 1.5782 + { 1.5783 + method.objx.closes = (IPersistentMap) RT.assoc(method.objx.closes, b, b); 1.5784 + closeOver(b, method.parent); 1.5785 + } 1.5786 + else if(IN_CATCH_FINALLY.deref() != null) 1.5787 + { 1.5788 + method.localsUsedInCatchFinally = (PersistentHashSet) method.localsUsedInCatchFinally.cons(b.idx); 1.5789 + } 1.5790 + } 1.5791 +} 1.5792 + 1.5793 + 1.5794 +static LocalBinding referenceLocal(Symbol sym) throws Exception{ 1.5795 + if(!LOCAL_ENV.isBound()) 1.5796 + return null; 1.5797 + LocalBinding b = (LocalBinding) RT.get(LOCAL_ENV.deref(), sym); 1.5798 + if(b != null) 1.5799 + { 1.5800 + ObjMethod method = (ObjMethod) METHOD.deref(); 1.5801 + closeOver(b, method); 1.5802 + } 1.5803 + return b; 1.5804 +} 1.5805 + 1.5806 +private static Symbol tagOf(Object o){ 1.5807 + Object tag = RT.get(RT.meta(o), RT.TAG_KEY); 1.5808 + if(tag instanceof Symbol) 1.5809 + return (Symbol) tag; 1.5810 + else if(tag instanceof String) 1.5811 + return Symbol.intern(null, (String) tag); 1.5812 + return null; 1.5813 +} 1.5814 + 1.5815 +public static Object loadFile(String file) throws Exception{ 1.5816 +// File fo = new File(file); 1.5817 +// if(!fo.exists()) 1.5818 +// return null; 1.5819 + 1.5820 + FileInputStream f = new FileInputStream(file); 1.5821 + try 1.5822 + { 1.5823 + return load(new InputStreamReader(f, RT.UTF8), new File(file).getAbsolutePath(), (new File(file)).getName()); 1.5824 + } 1.5825 + finally 1.5826 + { 1.5827 + f.close(); 1.5828 + } 1.5829 +} 1.5830 + 1.5831 +public static Object load(Reader rdr) throws Exception{ 1.5832 + return load(rdr, null, "NO_SOURCE_FILE"); 1.5833 +} 1.5834 + 1.5835 +public static Object load(Reader rdr, String sourcePath, String sourceName) throws Exception{ 1.5836 + Object EOF = new Object(); 1.5837 + Object ret = null; 1.5838 + LineNumberingPushbackReader pushbackReader = 1.5839 + (rdr instanceof LineNumberingPushbackReader) ? (LineNumberingPushbackReader) rdr : 1.5840 + new LineNumberingPushbackReader(rdr); 1.5841 + Var.pushThreadBindings( 1.5842 + RT.map(LOADER, RT.makeClassLoader(), 1.5843 + SOURCE_PATH, sourcePath, 1.5844 + SOURCE, sourceName, 1.5845 + METHOD, null, 1.5846 + LOCAL_ENV, null, 1.5847 + LOOP_LOCALS, null, 1.5848 + NEXT_LOCAL_NUM, 0, 1.5849 + RT.CURRENT_NS, RT.CURRENT_NS.deref(), 1.5850 + LINE_BEFORE, pushbackReader.getLineNumber(), 1.5851 + LINE_AFTER, pushbackReader.getLineNumber() 1.5852 + )); 1.5853 + 1.5854 + try 1.5855 + { 1.5856 + for(Object r = LispReader.read(pushbackReader, false, EOF, false); r != EOF; 1.5857 + r = LispReader.read(pushbackReader, false, EOF, false)) 1.5858 + { 1.5859 + LINE_AFTER.set(pushbackReader.getLineNumber()); 1.5860 + ret = eval(r,false); 1.5861 + LINE_BEFORE.set(pushbackReader.getLineNumber()); 1.5862 + } 1.5863 + } 1.5864 + catch(LispReader.ReaderException e) 1.5865 + { 1.5866 + throw new CompilerException(sourceName, e.line, e.getCause()); 1.5867 + } 1.5868 + finally 1.5869 + { 1.5870 + Var.popThreadBindings(); 1.5871 + } 1.5872 + return ret; 1.5873 +} 1.5874 + 1.5875 +static public void writeClassFile(String internalName, byte[] bytecode) throws Exception{ 1.5876 + String genPath = (String) COMPILE_PATH.deref(); 1.5877 + if(genPath == null) 1.5878 + throw new Exception("*compile-path* not set"); 1.5879 + String[] dirs = internalName.split("/"); 1.5880 + String p = genPath; 1.5881 + for(int i = 0; i < dirs.length - 1; i++) 1.5882 + { 1.5883 + p += File.separator + dirs[i]; 1.5884 + (new File(p)).mkdir(); 1.5885 + } 1.5886 + String path = genPath + File.separator + internalName + ".class"; 1.5887 + File cf = new File(path); 1.5888 + cf.createNewFile(); 1.5889 + FileOutputStream cfs = new FileOutputStream(cf); 1.5890 + try 1.5891 + { 1.5892 + cfs.write(bytecode); 1.5893 + cfs.flush(); 1.5894 + cfs.getFD().sync(); 1.5895 + } 1.5896 + finally 1.5897 + { 1.5898 + cfs.close(); 1.5899 + } 1.5900 +} 1.5901 + 1.5902 +public static void pushNS(){ 1.5903 + Var.pushThreadBindings(PersistentHashMap.create(Var.intern(Symbol.create("clojure.core"), 1.5904 + Symbol.create("*ns*")), null)); 1.5905 +} 1.5906 + 1.5907 +public static ILookupThunk getLookupThunk(Object target, Keyword k){ 1.5908 + return null; //To change body of created methods use File | Settings | File Templates. 1.5909 +} 1.5910 + 1.5911 +static void compile1(GeneratorAdapter gen, ObjExpr objx, Object form) throws Exception{ 1.5912 + Integer line = (Integer) LINE.deref(); 1.5913 + if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY)) 1.5914 + line = (Integer) RT.meta(form).valAt(RT.LINE_KEY); 1.5915 + Var.pushThreadBindings( 1.5916 + RT.map(LINE, line 1.5917 + ,LOADER, RT.makeClassLoader() 1.5918 + )); 1.5919 + try 1.5920 + { 1.5921 + form = macroexpand(form); 1.5922 + if(form instanceof IPersistentCollection && Util.equals(RT.first(form), DO)) 1.5923 + { 1.5924 + for(ISeq s = RT.next(form); s != null; s = RT.next(s)) 1.5925 + { 1.5926 + compile1(gen, objx, RT.first(s)); 1.5927 + } 1.5928 + } 1.5929 + else 1.5930 + { 1.5931 + Expr expr = analyze(C.EVAL, form); 1.5932 + objx.keywords = (IPersistentMap) KEYWORDS.deref(); 1.5933 + objx.vars = (IPersistentMap) VARS.deref(); 1.5934 + objx.constants = (PersistentVector) CONSTANTS.deref(); 1.5935 + expr.emit(C.EXPRESSION, objx, gen); 1.5936 + expr.eval(); 1.5937 + } 1.5938 + } 1.5939 + finally 1.5940 + { 1.5941 + Var.popThreadBindings(); 1.5942 + } 1.5943 +} 1.5944 + 1.5945 +public static Object compile(Reader rdr, String sourcePath, String sourceName) throws Exception{ 1.5946 + if(COMPILE_PATH.deref() == null) 1.5947 + throw new Exception("*compile-path* not set"); 1.5948 + 1.5949 + Object EOF = new Object(); 1.5950 + Object ret = null; 1.5951 + LineNumberingPushbackReader pushbackReader = 1.5952 + (rdr instanceof LineNumberingPushbackReader) ? (LineNumberingPushbackReader) rdr : 1.5953 + new LineNumberingPushbackReader(rdr); 1.5954 + Var.pushThreadBindings( 1.5955 + RT.map(SOURCE_PATH, sourcePath, 1.5956 + SOURCE, sourceName, 1.5957 + METHOD, null, 1.5958 + LOCAL_ENV, null, 1.5959 + LOOP_LOCALS, null, 1.5960 + NEXT_LOCAL_NUM, 0, 1.5961 + RT.CURRENT_NS, RT.CURRENT_NS.deref(), 1.5962 + LINE_BEFORE, pushbackReader.getLineNumber(), 1.5963 + LINE_AFTER, pushbackReader.getLineNumber(), 1.5964 + CONSTANTS, PersistentVector.EMPTY, 1.5965 + CONSTANT_IDS, new IdentityHashMap(), 1.5966 + KEYWORDS, PersistentHashMap.EMPTY, 1.5967 + VARS, PersistentHashMap.EMPTY 1.5968 + // ,LOADER, RT.makeClassLoader() 1.5969 + )); 1.5970 + 1.5971 + try 1.5972 + { 1.5973 + //generate loader class 1.5974 + ObjExpr objx = new ObjExpr(null); 1.5975 + objx.internalName = sourcePath.replace(File.separator, "/").substring(0, sourcePath.lastIndexOf('.')) 1.5976 + + RT.LOADER_SUFFIX; 1.5977 + 1.5978 + objx.objtype = Type.getObjectType(objx.internalName); 1.5979 + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 1.5980 + ClassVisitor cv = cw; 1.5981 + cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, objx.internalName, null, "java/lang/Object", null); 1.5982 + 1.5983 + //static load method 1.5984 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, 1.5985 + Method.getMethod("void load ()"), 1.5986 + null, 1.5987 + null, 1.5988 + cv); 1.5989 + gen.visitCode(); 1.5990 + 1.5991 + for(Object r = LispReader.read(pushbackReader, false, EOF, false); r != EOF; 1.5992 + r = LispReader.read(pushbackReader, false, EOF, false)) 1.5993 + { 1.5994 + LINE_AFTER.set(pushbackReader.getLineNumber()); 1.5995 + compile1(gen, objx, r); 1.5996 + LINE_BEFORE.set(pushbackReader.getLineNumber()); 1.5997 + } 1.5998 + //end of load 1.5999 + gen.returnValue(); 1.6000 + gen.endMethod(); 1.6001 + 1.6002 + //static fields for constants 1.6003 + for(int i = 0; i < objx.constants.count(); i++) 1.6004 + { 1.6005 + cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, objx.constantName(i), objx.constantType(i).getDescriptor(), 1.6006 + null, null); 1.6007 + } 1.6008 + 1.6009 + //static init for constants, keywords and vars 1.6010 + GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, 1.6011 + Method.getMethod("void <clinit> ()"), 1.6012 + null, 1.6013 + null, 1.6014 + cv); 1.6015 + clinitgen.visitCode(); 1.6016 + Label startTry = clinitgen.newLabel(); 1.6017 + Label endTry = clinitgen.newLabel(); 1.6018 + Label end = clinitgen.newLabel(); 1.6019 + Label finallyLabel = clinitgen.newLabel(); 1.6020 + 1.6021 + if(objx.constants.count() > 0) 1.6022 + { 1.6023 + objx.emitConstants(clinitgen); 1.6024 + } 1.6025 + clinitgen.invokeStatic(Type.getType(Compiler.class), Method.getMethod("void pushNS()")); 1.6026 + clinitgen.mark(startTry); 1.6027 + clinitgen.invokeStatic(objx.objtype, Method.getMethod("void load()")); 1.6028 + clinitgen.mark(endTry); 1.6029 + clinitgen.invokeStatic(VAR_TYPE, Method.getMethod("void popThreadBindings()")); 1.6030 + clinitgen.goTo(end); 1.6031 + 1.6032 + clinitgen.mark(finallyLabel); 1.6033 + //exception should be on stack 1.6034 + clinitgen.invokeStatic(VAR_TYPE, Method.getMethod("void popThreadBindings()")); 1.6035 + clinitgen.throwException(); 1.6036 + clinitgen.mark(end); 1.6037 + clinitgen.visitTryCatchBlock(startTry, endTry, finallyLabel, null); 1.6038 + 1.6039 + //end of static init 1.6040 + clinitgen.returnValue(); 1.6041 + clinitgen.endMethod(); 1.6042 + 1.6043 + //end of class 1.6044 + cv.visitEnd(); 1.6045 + 1.6046 + writeClassFile(objx.internalName, cw.toByteArray()); 1.6047 + } 1.6048 + catch(LispReader.ReaderException e) 1.6049 + { 1.6050 + throw new CompilerException(sourceName, e.line, e.getCause()); 1.6051 + } 1.6052 + finally 1.6053 + { 1.6054 + Var.popThreadBindings(); 1.6055 + } 1.6056 + return ret; 1.6057 +} 1.6058 + 1.6059 + 1.6060 +static public class NewInstanceExpr extends ObjExpr{ 1.6061 + //IPersistentMap optionsMap = PersistentArrayMap.EMPTY; 1.6062 + IPersistentCollection methods; 1.6063 + 1.6064 + Map<IPersistentVector,java.lang.reflect.Method> mmap; 1.6065 + Map<IPersistentVector,Set<Class>> covariants; 1.6066 + 1.6067 + public NewInstanceExpr(Object tag){ 1.6068 + super(tag); 1.6069 + } 1.6070 + 1.6071 + static class DeftypeParser implements IParser{ 1.6072 + public Expr parse(C context, final Object frm) throws Exception{ 1.6073 + ISeq rform = (ISeq) frm; 1.6074 + //(deftype* tagname classname [fields] :implements [interfaces] :tag tagname methods*) 1.6075 + rform = RT.next(rform); 1.6076 + String tagname = ((Symbol) rform.first()).toString(); 1.6077 + rform = rform.next(); 1.6078 + Symbol classname = (Symbol) rform.first(); 1.6079 + rform = rform.next(); 1.6080 + IPersistentVector fields = (IPersistentVector) rform.first(); 1.6081 + rform = rform.next(); 1.6082 + IPersistentMap opts = PersistentHashMap.EMPTY; 1.6083 + while(rform != null && rform.first() instanceof Keyword) 1.6084 + { 1.6085 + opts = opts.assoc(rform.first(), RT.second(rform)); 1.6086 + rform = rform.next().next(); 1.6087 + } 1.6088 + 1.6089 + ObjExpr ret = build((IPersistentVector)RT.get(opts,implementsKey,PersistentVector.EMPTY),fields,null,tagname, classname, 1.6090 + (Symbol) RT.get(opts,RT.TAG_KEY),rform, frm); 1.6091 + return ret; 1.6092 + } 1.6093 + } 1.6094 + 1.6095 + static class ReifyParser implements IParser{ 1.6096 + public Expr parse(C context, Object frm) throws Exception{ 1.6097 + //(reify this-name? [interfaces] (method-name [args] body)*) 1.6098 + ISeq form = (ISeq) frm; 1.6099 + ObjMethod enclosingMethod = (ObjMethod) METHOD.deref(); 1.6100 + String basename = enclosingMethod != null ? 1.6101 + (trimGenID(enclosingMethod.objx.name) + "$") 1.6102 + : (munge(currentNS().name.name) + "$"); 1.6103 + String simpleName = "reify__" + RT.nextID(); 1.6104 + String classname = basename + simpleName; 1.6105 + 1.6106 + ISeq rform = RT.next(form); 1.6107 + 1.6108 + IPersistentVector interfaces = ((IPersistentVector) RT.first(rform)).cons(Symbol.intern("clojure.lang.IObj")); 1.6109 + 1.6110 + 1.6111 + rform = RT.next(rform); 1.6112 + 1.6113 + 1.6114 + ObjExpr ret = build(interfaces, null, null, classname, Symbol.intern(classname), null, rform, frm); 1.6115 + if(frm instanceof IObj && ((IObj) frm).meta() != null) 1.6116 + return new MetaExpr(ret, (MapExpr) MapExpr 1.6117 + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) frm).meta())); 1.6118 + else 1.6119 + return ret; 1.6120 + } 1.6121 + } 1.6122 + 1.6123 + static ObjExpr build(IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym, 1.6124 + String tagName, Symbol className, 1.6125 + Symbol typeTag, ISeq methodForms, Object frm) throws Exception{ 1.6126 + NewInstanceExpr ret = new NewInstanceExpr(null); 1.6127 + 1.6128 + ret.src = frm; 1.6129 + ret.name = className.toString(); 1.6130 + ret.classMeta = RT.meta(className); 1.6131 + ret.internalName = ret.name.replace('.', '/'); 1.6132 + ret.objtype = Type.getObjectType(ret.internalName); 1.6133 + 1.6134 + if(thisSym != null) 1.6135 + ret.thisName = thisSym.name; 1.6136 + 1.6137 + if(fieldSyms != null) 1.6138 + { 1.6139 + IPersistentMap fmap = PersistentHashMap.EMPTY; 1.6140 + Object[] closesvec = new Object[2 * fieldSyms.count()]; 1.6141 + for(int i=0;i<fieldSyms.count();i++) 1.6142 + { 1.6143 + Symbol sym = (Symbol) fieldSyms.nth(i); 1.6144 + LocalBinding lb = new LocalBinding(-1, sym, null, 1.6145 + new MethodParamExpr(tagClass(tagOf(sym))),false,null); 1.6146 + fmap = fmap.assoc(sym, lb); 1.6147 + closesvec[i*2] = lb; 1.6148 + closesvec[i*2 + 1] = lb; 1.6149 + } 1.6150 + 1.6151 + //todo - inject __meta et al into closes - when? 1.6152 + //use array map to preserve ctor order 1.6153 + ret.closes = new PersistentArrayMap(closesvec); 1.6154 + ret.fields = fmap; 1.6155 + for(int i=fieldSyms.count()-1;i >= 0 && ((Symbol)fieldSyms.nth(i)).name.startsWith("__");--i) 1.6156 + ret.altCtorDrops++; 1.6157 + } 1.6158 + //todo - set up volatiles 1.6159 +// ret.volatiles = PersistentHashSet.create(RT.seq(RT.get(ret.optionsMap, volatileKey))); 1.6160 + 1.6161 + PersistentVector interfaces = PersistentVector.EMPTY; 1.6162 + for(ISeq s = RT.seq(interfaceSyms);s!=null;s = s.next()) 1.6163 + { 1.6164 + Class c = (Class) resolve((Symbol) s.first()); 1.6165 + if(!c.isInterface()) 1.6166 + throw new IllegalArgumentException("only interfaces are supported, had: " + c.getName()); 1.6167 + interfaces = interfaces.cons(c); 1.6168 + } 1.6169 + Class superClass = Object.class; 1.6170 + Map[] mc = gatherMethods(superClass,RT.seq(interfaces)); 1.6171 + Map overrideables = mc[0]; 1.6172 + Map covariants = mc[1]; 1.6173 + ret.mmap = overrideables; 1.6174 + ret.covariants = covariants; 1.6175 + 1.6176 + String[] inames = interfaceNames(interfaces); 1.6177 + 1.6178 + Class stub = compileStub(slashname(superClass),ret, inames, frm); 1.6179 + Symbol thistag = Symbol.intern(null,stub.getName()); 1.6180 + 1.6181 + try 1.6182 + { 1.6183 + Var.pushThreadBindings( 1.6184 + RT.map(CONSTANTS, PersistentVector.EMPTY, 1.6185 + CONSTANT_IDS, new IdentityHashMap(), 1.6186 + KEYWORDS, PersistentHashMap.EMPTY, 1.6187 + VARS, PersistentHashMap.EMPTY, 1.6188 + KEYWORD_CALLSITES, PersistentVector.EMPTY, 1.6189 + PROTOCOL_CALLSITES, PersistentVector.EMPTY, 1.6190 + VAR_CALLSITES, PersistentVector.EMPTY 1.6191 + )); 1.6192 + if(ret.isDeftype()) 1.6193 + { 1.6194 + Var.pushThreadBindings(RT.map(METHOD, null, 1.6195 + LOCAL_ENV, ret.fields 1.6196 + , COMPILE_STUB_SYM, Symbol.intern(null, tagName) 1.6197 + , COMPILE_STUB_CLASS, stub)); 1.6198 + } 1.6199 + 1.6200 + //now (methodname [args] body)* 1.6201 + ret.line = (Integer) LINE.deref(); 1.6202 + IPersistentCollection methods = null; 1.6203 + for(ISeq s = methodForms; s != null; s = RT.next(s)) 1.6204 + { 1.6205 + NewInstanceMethod m = NewInstanceMethod.parse(ret, (ISeq) RT.first(s),thistag, overrideables); 1.6206 + methods = RT.conj(methods, m); 1.6207 + } 1.6208 + 1.6209 + 1.6210 + ret.methods = methods; 1.6211 + ret.keywords = (IPersistentMap) KEYWORDS.deref(); 1.6212 + ret.vars = (IPersistentMap) VARS.deref(); 1.6213 + ret.constants = (PersistentVector) CONSTANTS.deref(); 1.6214 + ret.constantsID = RT.nextID(); 1.6215 + ret.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); 1.6216 + ret.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); 1.6217 + ret.varCallsites = (IPersistentVector) VAR_CALLSITES.deref(); 1.6218 + } 1.6219 + finally 1.6220 + { 1.6221 + if(ret.isDeftype()) 1.6222 + Var.popThreadBindings(); 1.6223 + Var.popThreadBindings(); 1.6224 + } 1.6225 + 1.6226 + ret.compile(slashname(superClass),inames,false); 1.6227 + ret.getCompiledClass(); 1.6228 + return ret; 1.6229 + } 1.6230 + 1.6231 + /*** 1.6232 + * Current host interop uses reflection, which requires pre-existing classes 1.6233 + * Work around this by: 1.6234 + * Generate a stub class that has the same interfaces and fields as the class we are generating. 1.6235 + * Use it as a type hint for this, and bind the simple name of the class to this stub (in resolve etc) 1.6236 + * Unmunge the name (using a magic prefix) on any code gen for classes 1.6237 + */ 1.6238 + static Class compileStub(String superName, NewInstanceExpr ret, String[] interfaceNames, Object frm){ 1.6239 + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 1.6240 + ClassVisitor cv = cw; 1.6241 + cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, COMPILE_STUB_PREFIX + "/" + ret.internalName, 1.6242 + null,superName,interfaceNames); 1.6243 + 1.6244 + //instance fields for closed-overs 1.6245 + for(ISeq s = RT.keys(ret.closes); s != null; s = s.next()) 1.6246 + { 1.6247 + LocalBinding lb = (LocalBinding) s.first(); 1.6248 + int access = ACC_PUBLIC + (ret.isVolatile(lb) ? ACC_VOLATILE : 1.6249 + ret.isMutable(lb) ? 0 : 1.6250 + ACC_FINAL); 1.6251 + if(lb.getPrimitiveType() != null) 1.6252 + cv.visitField(access 1.6253 + , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(), 1.6254 + null, null); 1.6255 + else 1.6256 + //todo - when closed-overs are fields, use more specific types here and in ctor and emitLocal? 1.6257 + cv.visitField(access 1.6258 + , lb.name, OBJECT_TYPE.getDescriptor(), null, null); 1.6259 + } 1.6260 + 1.6261 + //ctor that takes closed-overs and does nothing 1.6262 + Method m = new Method("<init>", Type.VOID_TYPE, ret.ctorTypes()); 1.6263 + GeneratorAdapter ctorgen = new GeneratorAdapter(ACC_PUBLIC, 1.6264 + m, 1.6265 + null, 1.6266 + null, 1.6267 + cv); 1.6268 + ctorgen.visitCode(); 1.6269 + ctorgen.loadThis(); 1.6270 + ctorgen.invokeConstructor(Type.getObjectType(superName), voidctor); 1.6271 + ctorgen.returnValue(); 1.6272 + ctorgen.endMethod(); 1.6273 + 1.6274 + if(ret.altCtorDrops > 0) 1.6275 + { 1.6276 + Type[] ctorTypes = ret.ctorTypes(); 1.6277 + Type[] altCtorTypes = new Type[ctorTypes.length-ret.altCtorDrops]; 1.6278 + for(int i=0;i<altCtorTypes.length;i++) 1.6279 + altCtorTypes[i] = ctorTypes[i]; 1.6280 + Method alt = new Method("<init>", Type.VOID_TYPE, altCtorTypes); 1.6281 + ctorgen = new GeneratorAdapter(ACC_PUBLIC, 1.6282 + alt, 1.6283 + null, 1.6284 + null, 1.6285 + cv); 1.6286 + ctorgen.visitCode(); 1.6287 + ctorgen.loadThis(); 1.6288 + ctorgen.loadArgs(); 1.6289 + for(int i=0;i<ret.altCtorDrops;i++) 1.6290 + ctorgen.visitInsn(Opcodes.ACONST_NULL); 1.6291 + 1.6292 + ctorgen.invokeConstructor(Type.getObjectType(COMPILE_STUB_PREFIX + "/" + ret.internalName), 1.6293 + new Method("<init>", Type.VOID_TYPE, ctorTypes)); 1.6294 + 1.6295 + ctorgen.returnValue(); 1.6296 + ctorgen.endMethod(); 1.6297 + } 1.6298 + //end of class 1.6299 + cv.visitEnd(); 1.6300 + 1.6301 + byte[] bytecode = cw.toByteArray(); 1.6302 + DynamicClassLoader loader = (DynamicClassLoader) LOADER.deref(); 1.6303 + return loader.defineClass(COMPILE_STUB_PREFIX + "." + ret.name, bytecode, frm); 1.6304 + } 1.6305 + 1.6306 + static String[] interfaceNames(IPersistentVector interfaces){ 1.6307 + int icnt = interfaces.count(); 1.6308 + String[] inames = icnt > 0 ? new String[icnt] : null; 1.6309 + for(int i=0;i<icnt;i++) 1.6310 + inames[i] = slashname((Class) interfaces.nth(i)); 1.6311 + return inames; 1.6312 + } 1.6313 + 1.6314 + 1.6315 + static String slashname(Class c){ 1.6316 + return c.getName().replace('.', '/'); 1.6317 + } 1.6318 + 1.6319 + 1.6320 + protected void emitMethods(ClassVisitor cv){ 1.6321 + for(ISeq s = RT.seq(methods); s != null; s = s.next()) 1.6322 + { 1.6323 + ObjMethod method = (ObjMethod) s.first(); 1.6324 + method.emit(this, cv); 1.6325 + } 1.6326 + //emit bridge methods 1.6327 + for(Map.Entry<IPersistentVector,Set<Class>> e : covariants.entrySet()) 1.6328 + { 1.6329 + java.lang.reflect.Method m = mmap.get(e.getKey()); 1.6330 + Class[] params = m.getParameterTypes(); 1.6331 + Type[] argTypes = new Type[params.length]; 1.6332 + 1.6333 + for(int i = 0; i < params.length; i++) 1.6334 + { 1.6335 + argTypes[i] = Type.getType(params[i]); 1.6336 + } 1.6337 + 1.6338 + Method target = new Method(m.getName(), Type.getType(m.getReturnType()), argTypes); 1.6339 + 1.6340 + for(Class retType : e.getValue()) 1.6341 + { 1.6342 + Method meth = new Method(m.getName(), Type.getType(retType), argTypes); 1.6343 + 1.6344 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_BRIDGE, 1.6345 + meth, 1.6346 + null, 1.6347 + //todo don't hardwire this 1.6348 + EXCEPTION_TYPES, 1.6349 + cv); 1.6350 + gen.visitCode(); 1.6351 + gen.loadThis(); 1.6352 + gen.loadArgs(); 1.6353 + gen.invokeInterface(Type.getType(m.getDeclaringClass()),target); 1.6354 + gen.returnValue(); 1.6355 + gen.endMethod(); 1.6356 + } 1.6357 + } 1.6358 + } 1.6359 + 1.6360 + static public IPersistentVector msig(java.lang.reflect.Method m){ 1.6361 + return RT.vector(m.getName(), RT.seq(m.getParameterTypes()),m.getReturnType()); 1.6362 + } 1.6363 + 1.6364 + static void considerMethod(java.lang.reflect.Method m, Map mm){ 1.6365 + IPersistentVector mk = msig(m); 1.6366 + int mods = m.getModifiers(); 1.6367 + 1.6368 + if(!(mm.containsKey(mk) 1.6369 + || !(Modifier.isPublic(mods) || Modifier.isProtected(mods)) 1.6370 + || Modifier.isStatic(mods) 1.6371 + || Modifier.isFinal(mods))) 1.6372 + { 1.6373 + mm.put(mk, m); 1.6374 + } 1.6375 + } 1.6376 + 1.6377 + static void gatherMethods(Class c, Map mm){ 1.6378 + for(; c != null; c = c.getSuperclass()) 1.6379 + { 1.6380 + for(java.lang.reflect.Method m : c.getDeclaredMethods()) 1.6381 + considerMethod(m, mm); 1.6382 + for(java.lang.reflect.Method m : c.getMethods()) 1.6383 + considerMethod(m, mm); 1.6384 + } 1.6385 + } 1.6386 + 1.6387 + static public Map[] gatherMethods(Class sc, ISeq interfaces){ 1.6388 + Map allm = new HashMap(); 1.6389 + gatherMethods(sc, allm); 1.6390 + for(; interfaces != null; interfaces = interfaces.next()) 1.6391 + gatherMethods((Class) interfaces.first(), allm); 1.6392 + 1.6393 + Map<IPersistentVector,java.lang.reflect.Method> mm = new HashMap<IPersistentVector,java.lang.reflect.Method>(); 1.6394 + Map<IPersistentVector,Set<Class>> covariants = new HashMap<IPersistentVector,Set<Class>>(); 1.6395 + for(Object o : allm.entrySet()) 1.6396 + { 1.6397 + Map.Entry e = (Map.Entry) o; 1.6398 + IPersistentVector mk = (IPersistentVector) e.getKey(); 1.6399 + mk = (IPersistentVector) mk.pop(); 1.6400 + java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue(); 1.6401 + if(mm.containsKey(mk)) //covariant return 1.6402 + { 1.6403 + Set<Class> cvs = covariants.get(mk); 1.6404 + if(cvs == null) 1.6405 + { 1.6406 + cvs = new HashSet<Class>(); 1.6407 + covariants.put(mk,cvs); 1.6408 + } 1.6409 + java.lang.reflect.Method om = mm.get(mk); 1.6410 + if(om.getReturnType().isAssignableFrom(m.getReturnType())) 1.6411 + { 1.6412 + cvs.add(om.getReturnType()); 1.6413 + mm.put(mk, m); 1.6414 + } 1.6415 + else 1.6416 + cvs.add(m.getReturnType()); 1.6417 + } 1.6418 + else 1.6419 + mm.put(mk, m); 1.6420 + } 1.6421 + return new Map[]{mm,covariants}; 1.6422 + } 1.6423 +} 1.6424 + 1.6425 +public static class NewInstanceMethod extends ObjMethod{ 1.6426 + String name; 1.6427 + Type[] argTypes; 1.6428 + Type retType; 1.6429 + Class retClass; 1.6430 + Class[] exclasses; 1.6431 + 1.6432 + static Symbol dummyThis = Symbol.intern(null,"dummy_this_dlskjsdfower"); 1.6433 + private IPersistentVector parms; 1.6434 + 1.6435 + public NewInstanceMethod(ObjExpr objx, ObjMethod parent){ 1.6436 + super(objx, parent); 1.6437 + } 1.6438 + 1.6439 + int numParams(){ 1.6440 + return argLocals.count(); 1.6441 + } 1.6442 + 1.6443 + String getMethodName(){ 1.6444 + return name; 1.6445 + } 1.6446 + 1.6447 + Type getReturnType(){ 1.6448 + return retType; 1.6449 + } 1.6450 + 1.6451 + Type[] getArgTypes(){ 1.6452 + return argTypes; 1.6453 + } 1.6454 + 1.6455 + 1.6456 + 1.6457 + static public IPersistentVector msig(String name,Class[] paramTypes){ 1.6458 + return RT.vector(name,RT.seq(paramTypes)); 1.6459 + } 1.6460 + 1.6461 + static NewInstanceMethod parse(ObjExpr objx, ISeq form, Symbol thistag, 1.6462 + Map overrideables) throws Exception{ 1.6463 + //(methodname [this-name args*] body...) 1.6464 + //this-name might be nil 1.6465 + NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod) METHOD.deref()); 1.6466 + Symbol dotname = (Symbol)RT.first(form); 1.6467 + Symbol name = (Symbol) Symbol.intern(null,munge(dotname.name)).withMeta(RT.meta(dotname)); 1.6468 + IPersistentVector parms = (IPersistentVector) RT.second(form); 1.6469 + if(parms.count() == 0) 1.6470 + { 1.6471 + throw new IllegalArgumentException("Must supply at least one argument for 'this' in: " + dotname); 1.6472 + } 1.6473 + Symbol thisName = (Symbol) parms.nth(0); 1.6474 + parms = RT.subvec(parms,1,parms.count()); 1.6475 + ISeq body = RT.next(RT.next(form)); 1.6476 + try 1.6477 + { 1.6478 + method.line = (Integer) LINE.deref(); 1.6479 + //register as the current method and set up a new env frame 1.6480 + PathNode pnode = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get()); 1.6481 + Var.pushThreadBindings( 1.6482 + RT.map( 1.6483 + METHOD, method, 1.6484 + LOCAL_ENV, LOCAL_ENV.deref(), 1.6485 + LOOP_LOCALS, null, 1.6486 + NEXT_LOCAL_NUM, 0 1.6487 + ,CLEAR_PATH, pnode 1.6488 + ,CLEAR_ROOT, pnode 1.6489 + ,CLEAR_SITES, PersistentHashMap.EMPTY 1.6490 + )); 1.6491 + 1.6492 + //register 'this' as local 0 1.6493 + if(thisName != null) 1.6494 + registerLocal((thisName == null) ? dummyThis:thisName,thistag, null,false); 1.6495 + else 1.6496 + getAndIncLocalNum(); 1.6497 + 1.6498 + PersistentVector argLocals = PersistentVector.EMPTY; 1.6499 + method.retClass = tagClass(tagOf(name)); 1.6500 + method.argTypes = new Type[parms.count()]; 1.6501 + boolean hinted = tagOf(name) != null; 1.6502 + Class[] pclasses = new Class[parms.count()]; 1.6503 + Symbol[] psyms = new Symbol[parms.count()]; 1.6504 + 1.6505 + for(int i = 0; i < parms.count(); i++) 1.6506 + { 1.6507 + if(!(parms.nth(i) instanceof Symbol)) 1.6508 + throw new IllegalArgumentException("params must be Symbols"); 1.6509 + Symbol p = (Symbol) parms.nth(i); 1.6510 + Object tag = tagOf(p); 1.6511 + if(tag != null) 1.6512 + hinted = true; 1.6513 + if(p.getNamespace() != null) 1.6514 + p = Symbol.create(p.name); 1.6515 + Class pclass = tagClass(tag); 1.6516 + pclasses[i] = pclass; 1.6517 + psyms[i] = p; 1.6518 + } 1.6519 + Map matches = findMethodsWithNameAndArity(name.name, parms.count(), overrideables); 1.6520 + Object mk = msig(name.name, pclasses); 1.6521 + java.lang.reflect.Method m = null; 1.6522 + if(matches.size() > 0) 1.6523 + { 1.6524 + //multiple methods 1.6525 + if(matches.size() > 1) 1.6526 + { 1.6527 + //must be hinted and match one method 1.6528 + if(!hinted) 1.6529 + throw new IllegalArgumentException("Must hint overloaded method: " + name.name); 1.6530 + m = (java.lang.reflect.Method) matches.get(mk); 1.6531 + if(m == null) 1.6532 + throw new IllegalArgumentException("Can't find matching overloaded method: " + name.name); 1.6533 + if(m.getReturnType() != method.retClass) 1.6534 + throw new IllegalArgumentException("Mismatched return type: " + name.name + 1.6535 + ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName()); 1.6536 + } 1.6537 + else //one match 1.6538 + { 1.6539 + //if hinted, validate match, 1.6540 + if(hinted) 1.6541 + { 1.6542 + m = (java.lang.reflect.Method) matches.get(mk); 1.6543 + if(m == null) 1.6544 + throw new IllegalArgumentException("Can't find matching method: " + name.name + 1.6545 + ", leave off hints for auto match."); 1.6546 + if(m.getReturnType() != method.retClass) 1.6547 + throw new IllegalArgumentException("Mismatched return type: " + name.name + 1.6548 + ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName()); 1.6549 + } 1.6550 + else //adopt found method sig 1.6551 + { 1.6552 + m = (java.lang.reflect.Method) matches.values().iterator().next(); 1.6553 + method.retClass = m.getReturnType(); 1.6554 + pclasses = m.getParameterTypes(); 1.6555 + } 1.6556 + } 1.6557 + } 1.6558 +// else if(findMethodsWithName(name.name,allmethods).size()>0) 1.6559 +// throw new IllegalArgumentException("Can't override/overload method: " + name.name); 1.6560 + else 1.6561 + throw new IllegalArgumentException("Can't define method not in interfaces: " + name.name); 1.6562 + 1.6563 + //else 1.6564 + //validate unque name+arity among additional methods 1.6565 + 1.6566 + method.retType = Type.getType(method.retClass); 1.6567 + method.exclasses = m.getExceptionTypes(); 1.6568 + 1.6569 + for(int i = 0; i < parms.count(); i++) 1.6570 + { 1.6571 + LocalBinding lb = registerLocal(psyms[i], null, new MethodParamExpr(pclasses[i]),true); 1.6572 + argLocals = argLocals.assocN(i,lb); 1.6573 + method.argTypes[i] = Type.getType(pclasses[i]); 1.6574 + } 1.6575 + for(int i = 0; i < parms.count(); i++) 1.6576 + { 1.6577 + if(pclasses[i] == long.class || pclasses[i] == double.class) 1.6578 + getAndIncLocalNum(); 1.6579 + } 1.6580 + LOOP_LOCALS.set(argLocals); 1.6581 + method.name = name.name; 1.6582 + method.methodMeta = RT.meta(name); 1.6583 + method.parms = parms; 1.6584 + method.argLocals = argLocals; 1.6585 + method.body = (new BodyExpr.Parser()).parse(C.RETURN, body); 1.6586 + return method; 1.6587 + } 1.6588 + finally 1.6589 + { 1.6590 + Var.popThreadBindings(); 1.6591 + } 1.6592 + } 1.6593 + 1.6594 + private static Map findMethodsWithNameAndArity(String name, int arity, Map mm){ 1.6595 + Map ret = new HashMap(); 1.6596 + for(Object o : mm.entrySet()) 1.6597 + { 1.6598 + Map.Entry e = (Map.Entry) o; 1.6599 + java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue(); 1.6600 + if(name.equals(m.getName()) && m.getParameterTypes().length == arity) 1.6601 + ret.put(e.getKey(), e.getValue()); 1.6602 + } 1.6603 + return ret; 1.6604 + } 1.6605 + 1.6606 + private static Map findMethodsWithName(String name, Map mm){ 1.6607 + Map ret = new HashMap(); 1.6608 + for(Object o : mm.entrySet()) 1.6609 + { 1.6610 + Map.Entry e = (Map.Entry) o; 1.6611 + java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue(); 1.6612 + if(name.equals(m.getName())) 1.6613 + ret.put(e.getKey(), e.getValue()); 1.6614 + } 1.6615 + return ret; 1.6616 + } 1.6617 + 1.6618 + public void emit(ObjExpr obj, ClassVisitor cv){ 1.6619 + Method m = new Method(getMethodName(), getReturnType(), getArgTypes()); 1.6620 + 1.6621 + Type[] extypes = null; 1.6622 + if(exclasses.length > 0) 1.6623 + { 1.6624 + extypes = new Type[exclasses.length]; 1.6625 + for(int i=0;i<exclasses.length;i++) 1.6626 + extypes[i] = Type.getType(exclasses[i]); 1.6627 + } 1.6628 + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, 1.6629 + m, 1.6630 + null, 1.6631 + extypes, 1.6632 + cv); 1.6633 + addAnnotation(gen,methodMeta); 1.6634 + for(int i = 0; i < parms.count(); i++) 1.6635 + { 1.6636 + IPersistentMap meta = RT.meta(parms.nth(i)); 1.6637 + addParameterAnnotation(gen, meta, i); 1.6638 + } 1.6639 + gen.visitCode(); 1.6640 + Label loopLabel = gen.mark(); 1.6641 + gen.visitLineNumber(line, loopLabel); 1.6642 + try 1.6643 + { 1.6644 + Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this)); 1.6645 + MaybePrimitiveExpr be = (MaybePrimitiveExpr) body; 1.6646 + if(Util.isPrimitive(retClass) && be.canEmitPrimitive()) 1.6647 + { 1.6648 + if(be.getJavaClass() == retClass) 1.6649 + be.emitUnboxed(C.RETURN,obj,gen); 1.6650 + //todo - support the standard widening conversions 1.6651 + else 1.6652 + throw new IllegalArgumentException("Mismatched primitive return, expected: " 1.6653 + + retClass + ", had: " + be.getJavaClass()); 1.6654 + } 1.6655 + else 1.6656 + { 1.6657 + body.emit(C.RETURN, obj, gen); 1.6658 + if(retClass == void.class) 1.6659 + { 1.6660 + gen.pop(); 1.6661 + } 1.6662 + else 1.6663 + gen.unbox(retType); 1.6664 + } 1.6665 + 1.6666 + Label end = gen.mark(); 1.6667 + gen.visitLocalVariable("this", obj.objtype.getDescriptor(), null, loopLabel, end, 0); 1.6668 + for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next()) 1.6669 + { 1.6670 + LocalBinding lb = (LocalBinding) lbs.first(); 1.6671 + gen.visitLocalVariable(lb.name, argTypes[lb.idx-1].getDescriptor(), null, loopLabel, end, lb.idx); 1.6672 + } 1.6673 + } 1.6674 + catch(Exception e) 1.6675 + { 1.6676 + throw new RuntimeException(e); 1.6677 + } 1.6678 + finally 1.6679 + { 1.6680 + Var.popThreadBindings(); 1.6681 + } 1.6682 + 1.6683 + gen.returnValue(); 1.6684 + //gen.visitMaxs(1, 1); 1.6685 + gen.endMethod(); 1.6686 + } 1.6687 +} 1.6688 + 1.6689 + static Class primClass(Symbol sym){ 1.6690 + if(sym == null) 1.6691 + return null; 1.6692 + Class c = null; 1.6693 + if(sym.name.equals("int")) 1.6694 + c = int.class; 1.6695 + else if(sym.name.equals("long")) 1.6696 + c = long.class; 1.6697 + else if(sym.name.equals("float")) 1.6698 + c = float.class; 1.6699 + else if(sym.name.equals("double")) 1.6700 + c = double.class; 1.6701 + else if(sym.name.equals("char")) 1.6702 + c = char.class; 1.6703 + else if(sym.name.equals("short")) 1.6704 + c = short.class; 1.6705 + else if(sym.name.equals("byte")) 1.6706 + c = byte.class; 1.6707 + else if(sym.name.equals("boolean")) 1.6708 + c = boolean.class; 1.6709 + else if(sym.name.equals("void")) 1.6710 + c = void.class; 1.6711 + return c; 1.6712 + } 1.6713 + 1.6714 + static Class tagClass(Object tag) throws Exception{ 1.6715 + if(tag == null) 1.6716 + return Object.class; 1.6717 + Class c = null; 1.6718 + if(tag instanceof Symbol) 1.6719 + c = primClass((Symbol) tag); 1.6720 + if(c == null) 1.6721 + c = HostExpr.tagToClass(tag); 1.6722 + return c; 1.6723 + } 1.6724 + 1.6725 +static public class MethodParamExpr implements Expr, MaybePrimitiveExpr{ 1.6726 + final Class c; 1.6727 + 1.6728 + public MethodParamExpr(Class c){ 1.6729 + this.c = c; 1.6730 + } 1.6731 + 1.6732 + public Object eval() throws Exception{ 1.6733 + throw new Exception("Can't eval"); 1.6734 + } 1.6735 + 1.6736 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.6737 + throw new RuntimeException("Can't emit"); 1.6738 + } 1.6739 + 1.6740 + public boolean hasJavaClass() throws Exception{ 1.6741 + return c != null; 1.6742 + } 1.6743 + 1.6744 + public Class getJavaClass() throws Exception{ 1.6745 + return c; 1.6746 + } 1.6747 + 1.6748 + public boolean canEmitPrimitive(){ 1.6749 + return Util.isPrimitive(c); 1.6750 + } 1.6751 + 1.6752 + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ 1.6753 + throw new RuntimeException("Can't emit"); 1.6754 + } 1.6755 +} 1.6756 + 1.6757 +public static class CaseExpr extends UntypedExpr{ 1.6758 + public final LocalBindingExpr expr; 1.6759 + public final int shift, mask, low, high; 1.6760 + public final Expr defaultExpr; 1.6761 + public final HashMap<Integer,Expr> tests; 1.6762 + public final HashMap<Integer,Expr> thens; 1.6763 + public final boolean allKeywords; 1.6764 + 1.6765 + public final int line; 1.6766 + 1.6767 + final static Method hashMethod = Method.getMethod("int hash(Object)"); 1.6768 + final static Method hashCodeMethod = Method.getMethod("int hashCode()"); 1.6769 + final static Method equalsMethod = Method.getMethod("boolean equals(Object, Object)"); 1.6770 + 1.6771 + 1.6772 + public CaseExpr(int line, LocalBindingExpr expr, int shift, int mask, int low, int high, Expr defaultExpr, 1.6773 + HashMap<Integer,Expr> tests,HashMap<Integer,Expr> thens, boolean allKeywords){ 1.6774 + this.expr = expr; 1.6775 + this.shift = shift; 1.6776 + this.mask = mask; 1.6777 + this.low = low; 1.6778 + this.high = high; 1.6779 + this.defaultExpr = defaultExpr; 1.6780 + this.tests = tests; 1.6781 + this.thens = thens; 1.6782 + this.line = line; 1.6783 + this.allKeywords = allKeywords; 1.6784 + } 1.6785 + 1.6786 + public Object eval() throws Exception{ 1.6787 + throw new UnsupportedOperationException("Can't eval case"); 1.6788 + } 1.6789 + 1.6790 + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ 1.6791 + Label defaultLabel = gen.newLabel(); 1.6792 + Label endLabel = gen.newLabel(); 1.6793 + HashMap<Integer,Label> labels = new HashMap(); 1.6794 + 1.6795 + for(Integer i : tests.keySet()) 1.6796 + { 1.6797 + labels.put(i, gen.newLabel()); 1.6798 + } 1.6799 + 1.6800 + Label[] la = new Label[(high-low)+1]; 1.6801 + 1.6802 + for(int i=low;i<=high;i++) 1.6803 + { 1.6804 + la[i-low] = labels.containsKey(i) ? labels.get(i) : defaultLabel; 1.6805 + } 1.6806 + 1.6807 + gen.visitLineNumber(line, gen.mark()); 1.6808 + expr.emit(C.EXPRESSION, objx, gen); 1.6809 + gen.invokeStatic(UTIL_TYPE,hashMethod); 1.6810 + gen.push(shift); 1.6811 + gen.visitInsn(ISHR); 1.6812 + gen.push(mask); 1.6813 + gen.visitInsn(IAND); 1.6814 + gen.visitTableSwitchInsn(low, high, defaultLabel, la); 1.6815 + 1.6816 + for(Integer i : labels.keySet()) 1.6817 + { 1.6818 + gen.mark(labels.get(i)); 1.6819 + expr.emit(C.EXPRESSION, objx, gen); 1.6820 + tests.get(i).emit(C.EXPRESSION, objx, gen); 1.6821 + if(allKeywords) 1.6822 + { 1.6823 + gen.visitJumpInsn(IF_ACMPNE, defaultLabel); 1.6824 + } 1.6825 + else 1.6826 + { 1.6827 + gen.invokeStatic(UTIL_TYPE, equalsMethod); 1.6828 + gen.ifZCmp(GeneratorAdapter.EQ, defaultLabel); 1.6829 + } 1.6830 + thens.get(i).emit(C.EXPRESSION,objx,gen); 1.6831 + gen.goTo(endLabel); 1.6832 + } 1.6833 + 1.6834 + gen.mark(defaultLabel); 1.6835 + defaultExpr.emit(C.EXPRESSION, objx, gen); 1.6836 + gen.mark(endLabel); 1.6837 + if(context == C.STATEMENT) 1.6838 + gen.pop(); 1.6839 + } 1.6840 + 1.6841 + static class Parser implements IParser{ 1.6842 + //(case* expr shift mask low high default map<minhash, [test then]> identity?) 1.6843 + //prepared by case macro and presumed correct 1.6844 + //case macro binds actual expr in let so expr is always a local, 1.6845 + //no need to worry about multiple evaluation 1.6846 + public Expr parse(C context, Object frm) throws Exception{ 1.6847 + ISeq form = (ISeq) frm; 1.6848 + if(context == C.EVAL) 1.6849 + return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form))); 1.6850 + PersistentVector args = PersistentVector.create(form.next()); 1.6851 + HashMap<Integer,Expr> tests = new HashMap(); 1.6852 + HashMap<Integer,Expr> thens = new HashMap(); 1.6853 + 1.6854 + LocalBindingExpr testexpr = (LocalBindingExpr) analyze(C.EXPRESSION, args.nth(0)); 1.6855 + testexpr.shouldClear = false; 1.6856 + 1.6857 + PathNode branch = new PathNode(PATHTYPE.BRANCH, (PathNode) CLEAR_PATH.get()); 1.6858 + for(Object o : ((Map)args.nth(6)).entrySet()) 1.6859 + { 1.6860 + Map.Entry e = (Map.Entry) o; 1.6861 + Integer minhash = (Integer) e.getKey(); 1.6862 + MapEntry me = (MapEntry) e.getValue(); 1.6863 + Expr testExpr = new ConstantExpr(me.getKey()); 1.6864 + tests.put(minhash, testExpr); 1.6865 + Expr thenExpr; 1.6866 + try { 1.6867 + Var.pushThreadBindings( 1.6868 + RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch))); 1.6869 + thenExpr = analyze(context, me.getValue()); 1.6870 + } 1.6871 + finally{ 1.6872 + Var.popThreadBindings(); 1.6873 + } 1.6874 + thens.put(minhash, thenExpr); 1.6875 + } 1.6876 + 1.6877 + Expr defaultExpr; 1.6878 + try { 1.6879 + Var.pushThreadBindings( 1.6880 + RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch))); 1.6881 + defaultExpr = analyze(context, args.nth(5)); 1.6882 + } 1.6883 + finally{ 1.6884 + Var.popThreadBindings(); 1.6885 + } 1.6886 + 1.6887 + return new CaseExpr((Integer) LINE.deref(), 1.6888 + testexpr, 1.6889 + (Integer)args.nth(1), 1.6890 + (Integer)args.nth(2), 1.6891 + (Integer)args.nth(3), 1.6892 + (Integer)args.nth(4), 1.6893 + defaultExpr, 1.6894 + tests,thens,args.nth(7) != RT.F); 1.6895 + 1.6896 + } 1.6897 + } 1.6898 +} 1.6899 + 1.6900 +}