annotate 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
rev   line source
rlm@10 1 /**
rlm@10 2 * Copyright (c) Rich Hickey. All rights reserved.
rlm@10 3 * The use and distribution terms for this software are covered by the
rlm@10 4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 5 * which can be found in the file epl-v10.html at the root of this distribution.
rlm@10 6 * By using this software in any fashion, you are agreeing to be bound by
rlm@10 7 * the terms of this license.
rlm@10 8 * You must not remove this notice, or any other, from this software.
rlm@10 9 **/
rlm@10 10
rlm@10 11 /* rich Aug 21, 2007 */
rlm@10 12
rlm@10 13 package clojure.lang;
rlm@10 14
rlm@10 15 //*
rlm@10 16
rlm@10 17 import clojure.asm.*;
rlm@10 18 import clojure.asm.commons.Method;
rlm@10 19 import clojure.asm.commons.GeneratorAdapter;
rlm@10 20 //*/
rlm@10 21 /*
rlm@10 22
rlm@10 23 import org.objectweb.asm.*;
rlm@10 24 import org.objectweb.asm.commons.Method;
rlm@10 25 import org.objectweb.asm.commons.GeneratorAdapter;
rlm@10 26 import org.objectweb.asm.util.TraceClassVisitor;
rlm@10 27 import org.objectweb.asm.util.CheckClassAdapter;
rlm@10 28 //*/
rlm@10 29
rlm@10 30 import java.io.*;
rlm@10 31 import java.util.*;
rlm@10 32 import java.lang.reflect.Constructor;
rlm@10 33 import java.lang.reflect.Modifier;
rlm@10 34
rlm@10 35 public class Compiler implements Opcodes{
rlm@10 36
rlm@10 37 static final Symbol DEF = Symbol.create("def");
rlm@10 38 static final Symbol LOOP = Symbol.create("loop*");
rlm@10 39 static final Symbol RECUR = Symbol.create("recur");
rlm@10 40 static final Symbol IF = Symbol.create("if");
rlm@10 41 static final Symbol LET = Symbol.create("let*");
rlm@10 42 static final Symbol LETFN = Symbol.create("letfn*");
rlm@10 43 static final Symbol DO = Symbol.create("do");
rlm@10 44 static final Symbol FN = Symbol.create("fn*");
rlm@10 45 static final Symbol QUOTE = Symbol.create("quote");
rlm@10 46 static final Symbol THE_VAR = Symbol.create("var");
rlm@10 47 static final Symbol DOT = Symbol.create(".");
rlm@10 48 static final Symbol ASSIGN = Symbol.create("set!");
rlm@10 49 //static final Symbol TRY_FINALLY = Symbol.create("try-finally");
rlm@10 50 static final Symbol TRY = Symbol.create("try");
rlm@10 51 static final Symbol CATCH = Symbol.create("catch");
rlm@10 52 static final Symbol FINALLY = Symbol.create("finally");
rlm@10 53 static final Symbol THROW = Symbol.create("throw");
rlm@10 54 static final Symbol MONITOR_ENTER = Symbol.create("monitor-enter");
rlm@10 55 static final Symbol MONITOR_EXIT = Symbol.create("monitor-exit");
rlm@10 56 static final Symbol IMPORT = Symbol.create("clojure.core", "import*");
rlm@10 57 //static final Symbol INSTANCE = Symbol.create("instance?");
rlm@10 58 static final Symbol DEFTYPE = Symbol.create("deftype*");
rlm@10 59 static final Symbol CASE = Symbol.create("case*");
rlm@10 60
rlm@10 61 //static final Symbol THISFN = Symbol.create("thisfn");
rlm@10 62 static final Symbol CLASS = Symbol.create("Class");
rlm@10 63 static final Symbol NEW = Symbol.create("new");
rlm@10 64 static final Symbol THIS = Symbol.create("this");
rlm@10 65 static final Symbol REIFY = Symbol.create("reify*");
rlm@10 66 //static final Symbol UNQUOTE = Symbol.create("unquote");
rlm@10 67 //static final Symbol UNQUOTE_SPLICING = Symbol.create("unquote-splicing");
rlm@10 68 //static final Symbol SYNTAX_QUOTE = Symbol.create("clojure.core", "syntax-quote");
rlm@10 69 static final Symbol LIST = Symbol.create("clojure.core", "list");
rlm@10 70 static final Symbol HASHMAP = Symbol.create("clojure.core", "hash-map");
rlm@10 71 static final Symbol VECTOR = Symbol.create("clojure.core", "vector");
rlm@10 72 static final Symbol IDENTITY = Symbol.create("clojure.core", "identity");
rlm@10 73
rlm@10 74 static final Symbol _AMP_ = Symbol.create("&");
rlm@10 75 static final Symbol ISEQ = Symbol.create("clojure.lang.ISeq");
rlm@10 76
rlm@10 77 static final Keyword inlineKey = Keyword.intern(null, "inline");
rlm@10 78 static final Keyword inlineAritiesKey = Keyword.intern(null, "inline-arities");
rlm@10 79
rlm@10 80 static final Keyword volatileKey = Keyword.intern(null, "volatile");
rlm@10 81 static final Keyword implementsKey = Keyword.intern(null, "implements");
rlm@10 82 static final String COMPILE_STUB_PREFIX = "compile__stub";
rlm@10 83
rlm@10 84 static final Keyword protocolKey = Keyword.intern(null, "protocol");
rlm@10 85 static final Keyword onKey = Keyword.intern(null, "on");
rlm@10 86
rlm@10 87 static final Symbol NS = Symbol.create("ns");
rlm@10 88 static final Symbol IN_NS = Symbol.create("in-ns");
rlm@10 89
rlm@10 90 //static final Symbol IMPORT = Symbol.create("import");
rlm@10 91 //static final Symbol USE = Symbol.create("use");
rlm@10 92
rlm@10 93 //static final Symbol IFN = Symbol.create("clojure.lang", "IFn");
rlm@10 94
rlm@10 95 static final public IPersistentMap specials = PersistentHashMap.create(
rlm@10 96 DEF, new DefExpr.Parser(),
rlm@10 97 LOOP, new LetExpr.Parser(),
rlm@10 98 RECUR, new RecurExpr.Parser(),
rlm@10 99 IF, new IfExpr.Parser(),
rlm@10 100 CASE, new CaseExpr.Parser(),
rlm@10 101 LET, new LetExpr.Parser(),
rlm@10 102 LETFN, new LetFnExpr.Parser(),
rlm@10 103 DO, new BodyExpr.Parser(),
rlm@10 104 FN, null,
rlm@10 105 QUOTE, new ConstantExpr.Parser(),
rlm@10 106 THE_VAR, new TheVarExpr.Parser(),
rlm@10 107 IMPORT, new ImportExpr.Parser(),
rlm@10 108 DOT, new HostExpr.Parser(),
rlm@10 109 ASSIGN, new AssignExpr.Parser(),
rlm@10 110 DEFTYPE, new NewInstanceExpr.DeftypeParser(),
rlm@10 111 REIFY, new NewInstanceExpr.ReifyParser(),
rlm@10 112 // TRY_FINALLY, new TryFinallyExpr.Parser(),
rlm@10 113 TRY, new TryExpr.Parser(),
rlm@10 114 THROW, new ThrowExpr.Parser(),
rlm@10 115 MONITOR_ENTER, new MonitorEnterExpr.Parser(),
rlm@10 116 MONITOR_EXIT, new MonitorExitExpr.Parser(),
rlm@10 117 // INSTANCE, new InstanceExpr.Parser(),
rlm@10 118 // IDENTICAL, new IdenticalExpr.Parser(),
rlm@10 119 //THISFN, null,
rlm@10 120 CATCH, null,
rlm@10 121 FINALLY, null,
rlm@10 122 // CLASS, new ClassExpr.Parser(),
rlm@10 123 NEW, new NewExpr.Parser(),
rlm@10 124 // UNQUOTE, null,
rlm@10 125 // UNQUOTE_SPLICING, null,
rlm@10 126 // SYNTAX_QUOTE, null,
rlm@10 127 _AMP_, null
rlm@10 128 );
rlm@10 129
rlm@10 130 private static final int MAX_POSITIONAL_ARITY = 20;
rlm@10 131 private static final Type OBJECT_TYPE;
rlm@10 132 private static final Type KEYWORD_TYPE = Type.getType(Keyword.class);
rlm@10 133 private static final Type VAR_TYPE = Type.getType(Var.class);
rlm@10 134 private static final Type SYMBOL_TYPE = Type.getType(Symbol.class);
rlm@10 135 //private static final Type NUM_TYPE = Type.getType(Num.class);
rlm@10 136 private static final Type IFN_TYPE = Type.getType(IFn.class);
rlm@10 137 private static final Type AFUNCTION_TYPE = Type.getType(AFunction.class);
rlm@10 138 private static final Type RT_TYPE = Type.getType(RT.class);
rlm@10 139 final static Type CLASS_TYPE = Type.getType(Class.class);
rlm@10 140 final static Type NS_TYPE = Type.getType(Namespace.class);
rlm@10 141 final static Type UTIL_TYPE = Type.getType(Util.class);
rlm@10 142 final static Type REFLECTOR_TYPE = Type.getType(Reflector.class);
rlm@10 143 final static Type THROWABLE_TYPE = Type.getType(Throwable.class);
rlm@10 144 final static Type BOOLEAN_OBJECT_TYPE = Type.getType(Boolean.class);
rlm@10 145 final static Type IPERSISTENTMAP_TYPE = Type.getType(IPersistentMap.class);
rlm@10 146 final static Type IOBJ_TYPE = Type.getType(IObj.class);
rlm@10 147
rlm@10 148 private static final Type[][] ARG_TYPES;
rlm@10 149 private static final Type[] EXCEPTION_TYPES = {Type.getType(Exception.class)};
rlm@10 150
rlm@10 151 static
rlm@10 152 {
rlm@10 153 OBJECT_TYPE = Type.getType(Object.class);
rlm@10 154 ARG_TYPES = new Type[MAX_POSITIONAL_ARITY + 2][];
rlm@10 155 for(int i = 0; i <= MAX_POSITIONAL_ARITY; ++i)
rlm@10 156 {
rlm@10 157 Type[] a = new Type[i];
rlm@10 158 for(int j = 0; j < i; j++)
rlm@10 159 a[j] = OBJECT_TYPE;
rlm@10 160 ARG_TYPES[i] = a;
rlm@10 161 }
rlm@10 162 Type[] a = new Type[MAX_POSITIONAL_ARITY + 1];
rlm@10 163 for(int j = 0; j < MAX_POSITIONAL_ARITY; j++)
rlm@10 164 a[j] = OBJECT_TYPE;
rlm@10 165 a[MAX_POSITIONAL_ARITY] = Type.getType("[Ljava/lang/Object;");
rlm@10 166 ARG_TYPES[MAX_POSITIONAL_ARITY + 1] = a;
rlm@10 167
rlm@10 168
rlm@10 169 }
rlm@10 170
rlm@10 171
rlm@10 172 //symbol->localbinding
rlm@10 173 static final public Var LOCAL_ENV = Var.create(null);
rlm@10 174
rlm@10 175 //vector<localbinding>
rlm@10 176 static final public Var LOOP_LOCALS = Var.create();
rlm@10 177
rlm@10 178 //Label
rlm@10 179 static final public Var LOOP_LABEL = Var.create();
rlm@10 180
rlm@10 181 //vector<object>
rlm@10 182 static final public Var CONSTANTS = Var.create();
rlm@10 183
rlm@10 184 //IdentityHashMap
rlm@10 185 static final public Var CONSTANT_IDS = Var.create();
rlm@10 186
rlm@10 187 //vector<keyword>
rlm@10 188 static final public Var KEYWORD_CALLSITES = Var.create();
rlm@10 189
rlm@10 190 //vector<var>
rlm@10 191 static final public Var PROTOCOL_CALLSITES = Var.create();
rlm@10 192
rlm@10 193 //vector<var>
rlm@10 194 static final public Var VAR_CALLSITES = Var.create();
rlm@10 195
rlm@10 196 //keyword->constid
rlm@10 197 static final public Var KEYWORDS = Var.create();
rlm@10 198
rlm@10 199 //var->constid
rlm@10 200 static final public Var VARS = Var.create();
rlm@10 201
rlm@10 202 //FnFrame
rlm@10 203 static final public Var METHOD = Var.create(null);
rlm@10 204
rlm@10 205 //null or not
rlm@10 206 static final public Var IN_CATCH_FINALLY = Var.create(null);
rlm@10 207
rlm@10 208 //DynamicClassLoader
rlm@10 209 static final public Var LOADER = Var.create();
rlm@10 210
rlm@10 211 //String
rlm@10 212 static final public Var SOURCE = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
rlm@10 213 Symbol.create("*source-path*"), "NO_SOURCE_FILE");
rlm@10 214
rlm@10 215 //String
rlm@10 216 static final public Var SOURCE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
rlm@10 217 Symbol.create("*file*"), "NO_SOURCE_PATH");
rlm@10 218
rlm@10 219 //String
rlm@10 220 static final public Var COMPILE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
rlm@10 221 Symbol.create("*compile-path*"), null);
rlm@10 222 //boolean
rlm@10 223 static final public Var COMPILE_FILES = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
rlm@10 224 Symbol.create("*compile-files*"), Boolean.FALSE);
rlm@10 225
rlm@10 226 static final public Var INSTANCE = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
rlm@10 227 Symbol.create("instance?"));
rlm@10 228
rlm@10 229 static final public Var ADD_ANNOTATIONS = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
rlm@10 230 Symbol.create("add-annotations"));
rlm@10 231
rlm@10 232 //Integer
rlm@10 233 static final public Var LINE = Var.create(0);
rlm@10 234
rlm@10 235 //Integer
rlm@10 236 static final public Var LINE_BEFORE = Var.create(0);
rlm@10 237 static final public Var LINE_AFTER = Var.create(0);
rlm@10 238
rlm@10 239 //Integer
rlm@10 240 static final public Var NEXT_LOCAL_NUM = Var.create(0);
rlm@10 241
rlm@10 242 //Integer
rlm@10 243 static final public Var RET_LOCAL_NUM = Var.create();
rlm@10 244
rlm@10 245
rlm@10 246 static final public Var COMPILE_STUB_SYM = Var.create(null);
rlm@10 247 static final public Var COMPILE_STUB_CLASS = Var.create(null);
rlm@10 248
rlm@10 249
rlm@10 250 //PathNode chain
rlm@10 251 static final public Var CLEAR_PATH = Var.create(null);
rlm@10 252
rlm@10 253 //tail of PathNode chain
rlm@10 254 static final public Var CLEAR_ROOT = Var.create(null);
rlm@10 255
rlm@10 256 //LocalBinding -> Set<LocalBindingExpr>
rlm@10 257 static final public Var CLEAR_SITES = Var.create(null);
rlm@10 258
rlm@10 259 public enum C{
rlm@10 260 STATEMENT, //value ignored
rlm@10 261 EXPRESSION, //value required
rlm@10 262 RETURN, //tail position relative to enclosing recur frame
rlm@10 263 EVAL
rlm@10 264 }
rlm@10 265
rlm@10 266 interface Expr{
rlm@10 267 Object eval() throws Exception;
rlm@10 268
rlm@10 269 void emit(C context, ObjExpr objx, GeneratorAdapter gen);
rlm@10 270
rlm@10 271 boolean hasJavaClass() throws Exception;
rlm@10 272
rlm@10 273 Class getJavaClass() throws Exception;
rlm@10 274 }
rlm@10 275
rlm@10 276 public static abstract class UntypedExpr implements Expr{
rlm@10 277
rlm@10 278 public Class getJavaClass(){
rlm@10 279 throw new IllegalArgumentException("Has no Java class");
rlm@10 280 }
rlm@10 281
rlm@10 282 public boolean hasJavaClass(){
rlm@10 283 return false;
rlm@10 284 }
rlm@10 285 }
rlm@10 286
rlm@10 287 interface IParser{
rlm@10 288 Expr parse(C context, Object form) throws Exception;
rlm@10 289 }
rlm@10 290
rlm@10 291 static boolean isSpecial(Object sym){
rlm@10 292 return specials.containsKey(sym);
rlm@10 293 }
rlm@10 294
rlm@10 295 static Symbol resolveSymbol(Symbol sym){
rlm@10 296 //already qualified or classname?
rlm@10 297 if(sym.name.indexOf('.') > 0)
rlm@10 298 return sym;
rlm@10 299 if(sym.ns != null)
rlm@10 300 {
rlm@10 301 Namespace ns = namespaceFor(sym);
rlm@10 302 if(ns == null || ns.name.name == sym.ns)
rlm@10 303 return sym;
rlm@10 304 return Symbol.create(ns.name.name, sym.name);
rlm@10 305 }
rlm@10 306 Object o = currentNS().getMapping(sym);
rlm@10 307 if(o == null)
rlm@10 308 return Symbol.intern(currentNS().name.name, sym.name);
rlm@10 309 else if(o instanceof Class)
rlm@10 310 return Symbol.intern(null, ((Class) o).getName());
rlm@10 311 else if(o instanceof Var)
rlm@10 312 {
rlm@10 313 Var v = (Var) o;
rlm@10 314 return Symbol.create(v.ns.name.name, v.sym.name);
rlm@10 315 }
rlm@10 316 return null;
rlm@10 317
rlm@10 318 }
rlm@10 319
rlm@10 320 static class DefExpr implements Expr{
rlm@10 321 public final Var var;
rlm@10 322 public final Expr init;
rlm@10 323 public final Expr meta;
rlm@10 324 public final boolean initProvided;
rlm@10 325 public final String source;
rlm@10 326 public final int line;
rlm@10 327 final static Method bindRootMethod = Method.getMethod("void bindRoot(Object)");
rlm@10 328 final static Method setTagMethod = Method.getMethod("void setTag(clojure.lang.Symbol)");
rlm@10 329 final static Method setMetaMethod = Method.getMethod("void setMeta(clojure.lang.IPersistentMap)");
rlm@10 330 final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String, String)");
rlm@10 331
rlm@10 332 public DefExpr(String source, int line, Var var, Expr init, Expr meta, boolean initProvided){
rlm@10 333 this.source = source;
rlm@10 334 this.line = line;
rlm@10 335 this.var = var;
rlm@10 336 this.init = init;
rlm@10 337 this.meta = meta;
rlm@10 338 this.initProvided = initProvided;
rlm@10 339 }
rlm@10 340
rlm@10 341 private boolean includesExplicitMetadata(MapExpr expr) {
rlm@10 342 for(int i=0; i < expr.keyvals.count(); i += 2)
rlm@10 343 {
rlm@10 344 Keyword k = ((KeywordExpr) expr.keyvals.nth(i)).k;
rlm@10 345 if ((k != RT.FILE_KEY) &&
rlm@10 346 (k != RT.DECLARED_KEY) &&
rlm@10 347 (k != RT.LINE_KEY))
rlm@10 348 return true;
rlm@10 349 }
rlm@10 350 return false;
rlm@10 351 }
rlm@10 352
rlm@10 353 public Object eval() throws Exception{
rlm@10 354 try
rlm@10 355 {
rlm@10 356 if(initProvided)
rlm@10 357 {
rlm@10 358 // if(init instanceof FnExpr && ((FnExpr) init).closes.count()==0)
rlm@10 359 // var.bindRoot(new FnLoaderThunk((FnExpr) init,var));
rlm@10 360 // else
rlm@10 361 var.bindRoot(init.eval());
rlm@10 362 }
rlm@10 363 if(meta != null)
rlm@10 364 {
rlm@10 365 IPersistentMap metaMap = (IPersistentMap) meta.eval();
rlm@10 366 if (initProvided || includesExplicitMetadata((MapExpr) meta))
rlm@10 367 var.setMeta((IPersistentMap) meta.eval());
rlm@10 368 }
rlm@10 369 return var;
rlm@10 370 }
rlm@10 371 catch(Throwable e)
rlm@10 372 {
rlm@10 373 if(!(e instanceof CompilerException))
rlm@10 374 throw new CompilerException(source, line, e);
rlm@10 375 else
rlm@10 376 throw (CompilerException) e;
rlm@10 377 }
rlm@10 378 }
rlm@10 379
rlm@10 380 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 381 objx.emitVar(gen, var);
rlm@10 382 if(meta != null)
rlm@10 383 {
rlm@10 384 if (initProvided || includesExplicitMetadata((MapExpr) meta))
rlm@10 385 {
rlm@10 386 gen.dup();
rlm@10 387 meta.emit(C.EXPRESSION, objx, gen);
rlm@10 388 gen.checkCast(IPERSISTENTMAP_TYPE);
rlm@10 389 gen.invokeVirtual(VAR_TYPE, setMetaMethod);
rlm@10 390 }
rlm@10 391 }
rlm@10 392 if(initProvided)
rlm@10 393 {
rlm@10 394 gen.dup();
rlm@10 395 init.emit(C.EXPRESSION, objx, gen);
rlm@10 396 gen.invokeVirtual(VAR_TYPE, bindRootMethod);
rlm@10 397 }
rlm@10 398
rlm@10 399 if(context == C.STATEMENT)
rlm@10 400 gen.pop();
rlm@10 401 }
rlm@10 402
rlm@10 403 public boolean hasJavaClass(){
rlm@10 404 return true;
rlm@10 405 }
rlm@10 406
rlm@10 407 public Class getJavaClass(){
rlm@10 408 return Var.class;
rlm@10 409 }
rlm@10 410
rlm@10 411 static class Parser implements IParser{
rlm@10 412 public Expr parse(C context, Object form) throws Exception{
rlm@10 413 //(def x) or (def x initexpr)
rlm@10 414 if(RT.count(form) > 3)
rlm@10 415 throw new Exception("Too many arguments to def");
rlm@10 416 else if(RT.count(form) < 2)
rlm@10 417 throw new Exception("Too few arguments to def");
rlm@10 418 else if(!(RT.second(form) instanceof Symbol))
rlm@10 419 throw new Exception("First argument to def must be a Symbol");
rlm@10 420 Symbol sym = (Symbol) RT.second(form);
rlm@10 421 Var v = lookupVar(sym, true);
rlm@10 422 if(v == null)
rlm@10 423 throw new Exception("Can't refer to qualified var that doesn't exist");
rlm@10 424 if(!v.ns.equals(currentNS()))
rlm@10 425 {
rlm@10 426 if(sym.ns == null)
rlm@10 427 v = currentNS().intern(sym);
rlm@10 428 // throw new Exception("Name conflict, can't def " + sym + " because namespace: " + currentNS().name +
rlm@10 429 // " refers to:" + v);
rlm@10 430 else
rlm@10 431 throw new Exception("Can't create defs outside of current ns");
rlm@10 432 }
rlm@10 433 IPersistentMap mm = sym.meta();
rlm@10 434 Object source_path = SOURCE_PATH.get();
rlm@10 435 source_path = source_path == null ? "NO_SOURCE_FILE" : source_path;
rlm@10 436 mm = (IPersistentMap) RT.assoc(mm, RT.LINE_KEY, LINE.get()).assoc(RT.FILE_KEY, source_path);
rlm@10 437 Expr meta = analyze(context == C.EVAL ? context : C.EXPRESSION, mm);
rlm@10 438 return new DefExpr((String) SOURCE.deref(), (Integer) LINE.deref(),
rlm@10 439 v, analyze(context == C.EVAL ? context : C.EXPRESSION, RT.third(form), v.sym.name),
rlm@10 440 meta, RT.count(form) == 3);
rlm@10 441 }
rlm@10 442 }
rlm@10 443 }
rlm@10 444
rlm@10 445 public static class AssignExpr implements Expr{
rlm@10 446 public final AssignableExpr target;
rlm@10 447 public final Expr val;
rlm@10 448
rlm@10 449 public AssignExpr(AssignableExpr target, Expr val){
rlm@10 450 this.target = target;
rlm@10 451 this.val = val;
rlm@10 452 }
rlm@10 453
rlm@10 454 public Object eval() throws Exception{
rlm@10 455 return target.evalAssign(val);
rlm@10 456 }
rlm@10 457
rlm@10 458 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 459 target.emitAssign(context, objx, gen, val);
rlm@10 460 }
rlm@10 461
rlm@10 462 public boolean hasJavaClass() throws Exception{
rlm@10 463 return val.hasJavaClass();
rlm@10 464 }
rlm@10 465
rlm@10 466 public Class getJavaClass() throws Exception{
rlm@10 467 return val.getJavaClass();
rlm@10 468 }
rlm@10 469
rlm@10 470 static class Parser implements IParser{
rlm@10 471 public Expr parse(C context, Object frm) throws Exception{
rlm@10 472 ISeq form = (ISeq) frm;
rlm@10 473 if(RT.length(form) != 3)
rlm@10 474 throw new IllegalArgumentException("Malformed assignment, expecting (set! target val)");
rlm@10 475 Expr target = analyze(C.EXPRESSION, RT.second(form));
rlm@10 476 if(!(target instanceof AssignableExpr))
rlm@10 477 throw new IllegalArgumentException("Invalid assignment target");
rlm@10 478 return new AssignExpr((AssignableExpr) target, analyze(C.EXPRESSION, RT.third(form)));
rlm@10 479 }
rlm@10 480 }
rlm@10 481 }
rlm@10 482
rlm@10 483 public static class VarExpr implements Expr, AssignableExpr{
rlm@10 484 public final Var var;
rlm@10 485 public final Object tag;
rlm@10 486 final static Method getMethod = Method.getMethod("Object get()");
rlm@10 487 final static Method setMethod = Method.getMethod("Object set(Object)");
rlm@10 488
rlm@10 489 public VarExpr(Var var, Symbol tag){
rlm@10 490 this.var = var;
rlm@10 491 this.tag = tag != null ? tag : var.getTag();
rlm@10 492 }
rlm@10 493
rlm@10 494 public Object eval() throws Exception{
rlm@10 495 return var.deref();
rlm@10 496 }
rlm@10 497
rlm@10 498 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 499 objx.emitVar(gen, var);
rlm@10 500 gen.invokeVirtual(VAR_TYPE, getMethod);
rlm@10 501 if(context == C.STATEMENT)
rlm@10 502 {
rlm@10 503 gen.pop();
rlm@10 504 }
rlm@10 505 }
rlm@10 506
rlm@10 507 public boolean hasJavaClass(){
rlm@10 508 return tag != null;
rlm@10 509 }
rlm@10 510
rlm@10 511 public Class getJavaClass() throws Exception{
rlm@10 512 return HostExpr.tagToClass(tag);
rlm@10 513 }
rlm@10 514
rlm@10 515 public Object evalAssign(Expr val) throws Exception{
rlm@10 516 return var.set(val.eval());
rlm@10 517 }
rlm@10 518
rlm@10 519 public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen,
rlm@10 520 Expr val){
rlm@10 521 objx.emitVar(gen, var);
rlm@10 522 val.emit(C.EXPRESSION, objx, gen);
rlm@10 523 gen.invokeVirtual(VAR_TYPE, setMethod);
rlm@10 524 if(context == C.STATEMENT)
rlm@10 525 gen.pop();
rlm@10 526 }
rlm@10 527 }
rlm@10 528
rlm@10 529 public static class TheVarExpr implements Expr{
rlm@10 530 public final Var var;
rlm@10 531
rlm@10 532 public TheVarExpr(Var var){
rlm@10 533 this.var = var;
rlm@10 534 }
rlm@10 535
rlm@10 536 public Object eval() throws Exception{
rlm@10 537 return var;
rlm@10 538 }
rlm@10 539
rlm@10 540 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 541 objx.emitVar(gen, var);
rlm@10 542 if(context == C.STATEMENT)
rlm@10 543 gen.pop();
rlm@10 544 }
rlm@10 545
rlm@10 546 public boolean hasJavaClass(){
rlm@10 547 return true;
rlm@10 548 }
rlm@10 549
rlm@10 550 public Class getJavaClass() throws ClassNotFoundException{
rlm@10 551 return Var.class;
rlm@10 552 }
rlm@10 553
rlm@10 554 static class Parser implements IParser{
rlm@10 555 public Expr parse(C context, Object form) throws Exception{
rlm@10 556 Symbol sym = (Symbol) RT.second(form);
rlm@10 557 Var v = lookupVar(sym, false);
rlm@10 558 if(v != null)
rlm@10 559 return new TheVarExpr(v);
rlm@10 560 throw new Exception("Unable to resolve var: " + sym + " in this context");
rlm@10 561 }
rlm@10 562 }
rlm@10 563 }
rlm@10 564
rlm@10 565 public static class KeywordExpr implements Expr{
rlm@10 566 public final Keyword k;
rlm@10 567
rlm@10 568 public KeywordExpr(Keyword k){
rlm@10 569 this.k = k;
rlm@10 570 }
rlm@10 571
rlm@10 572 public Object eval() throws Exception{
rlm@10 573 return k;
rlm@10 574 }
rlm@10 575
rlm@10 576 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 577 objx.emitKeyword(gen, k);
rlm@10 578 if(context == C.STATEMENT)
rlm@10 579 gen.pop();
rlm@10 580
rlm@10 581 }
rlm@10 582
rlm@10 583 public boolean hasJavaClass(){
rlm@10 584 return true;
rlm@10 585 }
rlm@10 586
rlm@10 587 public Class getJavaClass() throws ClassNotFoundException{
rlm@10 588 return Keyword.class;
rlm@10 589 }
rlm@10 590 }
rlm@10 591
rlm@10 592 public static class ImportExpr implements Expr{
rlm@10 593 public final String c;
rlm@10 594 final static Method forNameMethod = Method.getMethod("Class forName(String)");
rlm@10 595 final static Method importClassMethod = Method.getMethod("Class importClass(Class)");
rlm@10 596 final static Method derefMethod = Method.getMethod("Object deref()");
rlm@10 597
rlm@10 598 public ImportExpr(String c){
rlm@10 599 this.c = c;
rlm@10 600 }
rlm@10 601
rlm@10 602 public Object eval() throws Exception{
rlm@10 603 Namespace ns = (Namespace) RT.CURRENT_NS.deref();
rlm@10 604 ns.importClass(RT.classForName(c));
rlm@10 605 return null;
rlm@10 606 }
rlm@10 607
rlm@10 608 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 609 gen.getStatic(RT_TYPE,"CURRENT_NS",VAR_TYPE);
rlm@10 610 gen.invokeVirtual(VAR_TYPE, derefMethod);
rlm@10 611 gen.checkCast(NS_TYPE);
rlm@10 612 gen.push(c);
rlm@10 613 gen.invokeStatic(CLASS_TYPE, forNameMethod);
rlm@10 614 gen.invokeVirtual(NS_TYPE, importClassMethod);
rlm@10 615 if(context == C.STATEMENT)
rlm@10 616 gen.pop();
rlm@10 617 }
rlm@10 618
rlm@10 619 public boolean hasJavaClass(){
rlm@10 620 return false;
rlm@10 621 }
rlm@10 622
rlm@10 623 public Class getJavaClass() throws ClassNotFoundException{
rlm@10 624 throw new IllegalArgumentException("ImportExpr has no Java class");
rlm@10 625 }
rlm@10 626
rlm@10 627 static class Parser implements IParser{
rlm@10 628 public Expr parse(C context, Object form) throws Exception{
rlm@10 629 return new ImportExpr((String) RT.second(form));
rlm@10 630 }
rlm@10 631 }
rlm@10 632 }
rlm@10 633
rlm@10 634 public static abstract class LiteralExpr implements Expr{
rlm@10 635 abstract Object val();
rlm@10 636
rlm@10 637 public Object eval(){
rlm@10 638 return val();
rlm@10 639 }
rlm@10 640 }
rlm@10 641
rlm@10 642 static interface AssignableExpr{
rlm@10 643 Object evalAssign(Expr val) throws Exception;
rlm@10 644
rlm@10 645 void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, Expr val);
rlm@10 646 }
rlm@10 647
rlm@10 648 static public interface MaybePrimitiveExpr extends Expr{
rlm@10 649 public boolean canEmitPrimitive();
rlm@10 650 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen);
rlm@10 651 }
rlm@10 652
rlm@10 653 static public abstract class HostExpr implements Expr, MaybePrimitiveExpr{
rlm@10 654 final static Type BOOLEAN_TYPE = Type.getType(Boolean.class);
rlm@10 655 final static Type CHAR_TYPE = Type.getType(Character.class);
rlm@10 656 final static Type INTEGER_TYPE = Type.getType(Integer.class);
rlm@10 657 final static Type LONG_TYPE = Type.getType(Long.class);
rlm@10 658 final static Type FLOAT_TYPE = Type.getType(Float.class);
rlm@10 659 final static Type DOUBLE_TYPE = Type.getType(Double.class);
rlm@10 660 final static Type SHORT_TYPE = Type.getType(Short.class);
rlm@10 661 final static Type BYTE_TYPE = Type.getType(Byte.class);
rlm@10 662 final static Type NUMBER_TYPE = Type.getType(Number.class);
rlm@10 663
rlm@10 664 final static Method charValueMethod = Method.getMethod("char charValue()");
rlm@10 665 final static Method booleanValueMethod = Method.getMethod("boolean booleanValue()");
rlm@10 666
rlm@10 667 final static Method charValueOfMethod = Method.getMethod("Character valueOf(char)");
rlm@10 668 final static Method intValueOfMethod = Method.getMethod("Integer valueOf(int)");
rlm@10 669 final static Method longValueOfMethod = Method.getMethod("Long valueOf(long)");
rlm@10 670 final static Method floatValueOfMethod = Method.getMethod("Float valueOf(float)");
rlm@10 671 final static Method doubleValueOfMethod = Method.getMethod("Double valueOf(double)");
rlm@10 672 final static Method shortValueOfMethod = Method.getMethod("Short valueOf(short)");
rlm@10 673 final static Method byteValueOfMethod = Method.getMethod("Byte valueOf(byte)");
rlm@10 674
rlm@10 675 final static Method intValueMethod = Method.getMethod("int intValue()");
rlm@10 676 final static Method longValueMethod = Method.getMethod("long longValue()");
rlm@10 677 final static Method floatValueMethod = Method.getMethod("float floatValue()");
rlm@10 678 final static Method doubleValueMethod = Method.getMethod("double doubleValue()");
rlm@10 679 final static Method byteValueMethod = Method.getMethod("byte byteValue()");
rlm@10 680 final static Method shortValueMethod = Method.getMethod("short shortValue()");
rlm@10 681
rlm@10 682 final static Method fromIntMethod = Method.getMethod("clojure.lang.Num from(int)");
rlm@10 683 final static Method fromLongMethod = Method.getMethod("clojure.lang.Num from(long)");
rlm@10 684 final static Method fromDoubleMethod = Method.getMethod("clojure.lang.Num from(double)");
rlm@10 685
rlm@10 686
rlm@10 687 //*
rlm@10 688 public static void emitBoxReturn(ObjExpr objx, GeneratorAdapter gen, Class returnType){
rlm@10 689 if(returnType.isPrimitive())
rlm@10 690 {
rlm@10 691 if(returnType == boolean.class)
rlm@10 692 {
rlm@10 693 Label falseLabel = gen.newLabel();
rlm@10 694 Label endLabel = gen.newLabel();
rlm@10 695 gen.ifZCmp(GeneratorAdapter.EQ, falseLabel);
rlm@10 696 gen.getStatic(BOOLEAN_OBJECT_TYPE, "TRUE", BOOLEAN_OBJECT_TYPE);
rlm@10 697 gen.goTo(endLabel);
rlm@10 698 gen.mark(falseLabel);
rlm@10 699 gen.getStatic(BOOLEAN_OBJECT_TYPE, "FALSE", BOOLEAN_OBJECT_TYPE);
rlm@10 700 // NIL_EXPR.emit(C.EXPRESSION, fn, gen);
rlm@10 701 gen.mark(endLabel);
rlm@10 702 }
rlm@10 703 else if(returnType == void.class)
rlm@10 704 {
rlm@10 705 NIL_EXPR.emit(C.EXPRESSION, objx, gen);
rlm@10 706 }
rlm@10 707 else if(returnType == char.class)
rlm@10 708 {
rlm@10 709 gen.invokeStatic(CHAR_TYPE, charValueOfMethod);
rlm@10 710 }
rlm@10 711 else
rlm@10 712 {
rlm@10 713 if(returnType == int.class)
rlm@10 714 //gen.invokeStatic(NUM_TYPE, fromIntMethod);
rlm@10 715 gen.invokeStatic(INTEGER_TYPE, intValueOfMethod);
rlm@10 716 else if(returnType == float.class)
rlm@10 717 {
rlm@10 718 //gen.visitInsn(F2D);
rlm@10 719 gen.invokeStatic(FLOAT_TYPE, floatValueOfMethod);
rlm@10 720 //m = floatValueOfMethod;
rlm@10 721 }
rlm@10 722 else if(returnType == double.class)
rlm@10 723 gen.invokeStatic(DOUBLE_TYPE, doubleValueOfMethod);
rlm@10 724 else if(returnType == long.class)
rlm@10 725 gen.invokeStatic(LONG_TYPE, longValueOfMethod);
rlm@10 726 else if(returnType == byte.class)
rlm@10 727 gen.invokeStatic(BYTE_TYPE, byteValueOfMethod);
rlm@10 728 else if(returnType == short.class)
rlm@10 729 gen.invokeStatic(SHORT_TYPE, shortValueOfMethod);
rlm@10 730 }
rlm@10 731 }
rlm@10 732 }
rlm@10 733
rlm@10 734 //*/
rlm@10 735 public static void emitUnboxArg(ObjExpr objx, GeneratorAdapter gen, Class paramType){
rlm@10 736 if(paramType.isPrimitive())
rlm@10 737 {
rlm@10 738 if(paramType == boolean.class)
rlm@10 739 {
rlm@10 740 gen.checkCast(BOOLEAN_TYPE);
rlm@10 741 gen.invokeVirtual(BOOLEAN_TYPE, booleanValueMethod);
rlm@10 742 // Label falseLabel = gen.newLabel();
rlm@10 743 // Label endLabel = gen.newLabel();
rlm@10 744 // gen.ifNull(falseLabel);
rlm@10 745 // gen.push(1);
rlm@10 746 // gen.goTo(endLabel);
rlm@10 747 // gen.mark(falseLabel);
rlm@10 748 // gen.push(0);
rlm@10 749 // gen.mark(endLabel);
rlm@10 750 }
rlm@10 751 else if(paramType == char.class)
rlm@10 752 {
rlm@10 753 gen.checkCast(CHAR_TYPE);
rlm@10 754 gen.invokeVirtual(CHAR_TYPE, charValueMethod);
rlm@10 755 }
rlm@10 756 else
rlm@10 757 {
rlm@10 758 Method m = intValueMethod;
rlm@10 759 gen.checkCast(NUMBER_TYPE);
rlm@10 760 if(paramType == int.class)
rlm@10 761 m = intValueMethod;
rlm@10 762 else if(paramType == float.class)
rlm@10 763 m = floatValueMethod;
rlm@10 764 else if(paramType == double.class)
rlm@10 765 m = doubleValueMethod;
rlm@10 766 else if(paramType == long.class)
rlm@10 767 m = longValueMethod;
rlm@10 768 else if(paramType == byte.class)
rlm@10 769 m = byteValueMethod;
rlm@10 770 else if(paramType == short.class)
rlm@10 771 m = shortValueMethod;
rlm@10 772 gen.invokeVirtual(NUMBER_TYPE, m);
rlm@10 773 }
rlm@10 774 }
rlm@10 775 else
rlm@10 776 {
rlm@10 777 gen.checkCast(Type.getType(paramType));
rlm@10 778 }
rlm@10 779 }
rlm@10 780
rlm@10 781 static class Parser implements IParser{
rlm@10 782 public Expr parse(C context, Object frm) throws Exception{
rlm@10 783 ISeq form = (ISeq) frm;
rlm@10 784 //(. x fieldname-sym) or
rlm@10 785 //(. x 0-ary-method)
rlm@10 786 // (. x methodname-sym args+)
rlm@10 787 // (. x (methodname-sym args?))
rlm@10 788 if(RT.length(form) < 3)
rlm@10 789 throw new IllegalArgumentException("Malformed member expression, expecting (. target member ...)");
rlm@10 790 //determine static or instance
rlm@10 791 //static target must be symbol, either fully.qualified.Classname or Classname that has been imported
rlm@10 792 int line = (Integer) LINE.deref();
rlm@10 793 String source = (String) SOURCE.deref();
rlm@10 794 Class c = maybeClass(RT.second(form), false);
rlm@10 795 //at this point c will be non-null if static
rlm@10 796 Expr instance = null;
rlm@10 797 if(c == null)
rlm@10 798 instance = analyze(context == C.EVAL ? context : C.EXPRESSION, RT.second(form));
rlm@10 799 boolean maybeField = RT.length(form) == 3 &&
rlm@10 800 (RT.third(form) instanceof Symbol
rlm@10 801 || RT.third(form) instanceof Keyword);
rlm@10 802 if(maybeField && !(RT.third(form) instanceof Keyword))
rlm@10 803 {
rlm@10 804 Symbol sym = (Symbol) RT.third(form);
rlm@10 805 if(c != null)
rlm@10 806 maybeField = Reflector.getMethods(c, 0, munge(sym.name), true).size() == 0;
rlm@10 807 else if(instance != null && instance.hasJavaClass() && instance.getJavaClass() != null)
rlm@10 808 maybeField = Reflector.getMethods(instance.getJavaClass(), 0, munge(sym.name), false).size() == 0;
rlm@10 809 }
rlm@10 810 if(maybeField) //field
rlm@10 811 {
rlm@10 812 Symbol sym = (RT.third(form) instanceof Keyword)?
rlm@10 813 ((Keyword)RT.third(form)).sym
rlm@10 814 :(Symbol) RT.third(form);
rlm@10 815 Symbol tag = tagOf(form);
rlm@10 816 if(c != null) {
rlm@10 817 return new StaticFieldExpr(line, c, munge(sym.name), tag);
rlm@10 818 } else
rlm@10 819 return new InstanceFieldExpr(line, instance, munge(sym.name), tag);
rlm@10 820 }
rlm@10 821 else
rlm@10 822 {
rlm@10 823 ISeq call = (ISeq) ((RT.third(form) instanceof ISeq) ? RT.third(form) : RT.next(RT.next(form)));
rlm@10 824 if(!(RT.first(call) instanceof Symbol))
rlm@10 825 throw new IllegalArgumentException("Malformed member expression");
rlm@10 826 Symbol sym = (Symbol) RT.first(call);
rlm@10 827 Symbol tag = tagOf(form);
rlm@10 828 PersistentVector args = PersistentVector.EMPTY;
rlm@10 829 for(ISeq s = RT.next(call); s != null; s = s.next())
rlm@10 830 args = args.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, s.first()));
rlm@10 831 if(c != null)
rlm@10 832 return new StaticMethodExpr(source, line, tag, c, munge(sym.name), args);
rlm@10 833 else
rlm@10 834 return new InstanceMethodExpr(source, line, tag, instance, munge(sym.name), args);
rlm@10 835 }
rlm@10 836 }
rlm@10 837 }
rlm@10 838
rlm@10 839 private static Class maybeClass(Object form, boolean stringOk) throws Exception{
rlm@10 840 if(form instanceof Class)
rlm@10 841 return (Class) form;
rlm@10 842 Class c = null;
rlm@10 843 if(form instanceof Symbol)
rlm@10 844 {
rlm@10 845 Symbol sym = (Symbol) form;
rlm@10 846 if(sym.ns == null) //if ns-qualified can't be classname
rlm@10 847 {
rlm@10 848 if(Util.equals(sym,COMPILE_STUB_SYM.get()))
rlm@10 849 return (Class) COMPILE_STUB_CLASS.get();
rlm@10 850 if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
rlm@10 851 c = RT.classForName(sym.name);
rlm@10 852 else
rlm@10 853 {
rlm@10 854 Object o = currentNS().getMapping(sym);
rlm@10 855 if(o instanceof Class)
rlm@10 856 c = (Class) o;
rlm@10 857 }
rlm@10 858 }
rlm@10 859 }
rlm@10 860 else if(stringOk && form instanceof String)
rlm@10 861 c = RT.classForName((String) form);
rlm@10 862 return c;
rlm@10 863 }
rlm@10 864
rlm@10 865 /*
rlm@10 866 private static String maybeClassName(Object form, boolean stringOk){
rlm@10 867 String className = null;
rlm@10 868 if(form instanceof Symbol)
rlm@10 869 {
rlm@10 870 Symbol sym = (Symbol) form;
rlm@10 871 if(sym.ns == null) //if ns-qualified can't be classname
rlm@10 872 {
rlm@10 873 if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
rlm@10 874 className = sym.name;
rlm@10 875 else
rlm@10 876 {
rlm@10 877 IPersistentMap imports = (IPersistentMap) ((Var) RT.NS_IMPORTS.get()).get();
rlm@10 878 className = (String) imports.valAt(sym);
rlm@10 879 }
rlm@10 880 }
rlm@10 881 }
rlm@10 882 else if(stringOk && form instanceof String)
rlm@10 883 className = (String) form;
rlm@10 884 return className;
rlm@10 885 }
rlm@10 886 */
rlm@10 887 static Class tagToClass(Object tag) throws Exception{
rlm@10 888 Class c = maybeClass(tag, true);
rlm@10 889 if(tag instanceof Symbol)
rlm@10 890 {
rlm@10 891 Symbol sym = (Symbol) tag;
rlm@10 892 if(sym.ns == null) //if ns-qualified can't be classname
rlm@10 893 {
rlm@10 894 if(sym.name.equals("objects"))
rlm@10 895 c = Object[].class;
rlm@10 896 else if(sym.name.equals("ints"))
rlm@10 897 c = int[].class;
rlm@10 898 else if(sym.name.equals("longs"))
rlm@10 899 c = long[].class;
rlm@10 900 else if(sym.name.equals("floats"))
rlm@10 901 c = float[].class;
rlm@10 902 else if(sym.name.equals("doubles"))
rlm@10 903 c = double[].class;
rlm@10 904 else if(sym.name.equals("chars"))
rlm@10 905 c = char[].class;
rlm@10 906 else if(sym.name.equals("shorts"))
rlm@10 907 c = short[].class;
rlm@10 908 else if(sym.name.equals("bytes"))
rlm@10 909 c = byte[].class;
rlm@10 910 else if(sym.name.equals("booleans"))
rlm@10 911 c = boolean[].class;
rlm@10 912 }
rlm@10 913 }
rlm@10 914 if(c != null)
rlm@10 915 return c;
rlm@10 916 throw new IllegalArgumentException("Unable to resolve classname: " + tag);
rlm@10 917 }
rlm@10 918 }
rlm@10 919
rlm@10 920 static abstract class FieldExpr extends HostExpr{
rlm@10 921 }
rlm@10 922
rlm@10 923 static class InstanceFieldExpr extends FieldExpr implements AssignableExpr{
rlm@10 924 public final Expr target;
rlm@10 925 public final Class targetClass;
rlm@10 926 public final java.lang.reflect.Field field;
rlm@10 927 public final String fieldName;
rlm@10 928 public final int line;
rlm@10 929 public final Symbol tag;
rlm@10 930 final static Method invokeNoArgInstanceMember = Method.getMethod("Object invokeNoArgInstanceMember(Object,String)");
rlm@10 931 final static Method setInstanceFieldMethod = Method.getMethod("Object setInstanceField(Object,String,Object)");
rlm@10 932
rlm@10 933
rlm@10 934 public InstanceFieldExpr(int line, Expr target, String fieldName, Symbol tag) throws Exception{
rlm@10 935 this.target = target;
rlm@10 936 this.targetClass = target.hasJavaClass() ? target.getJavaClass() : null;
rlm@10 937 this.field = targetClass != null ? Reflector.getField(targetClass, fieldName, false) : null;
rlm@10 938 this.fieldName = fieldName;
rlm@10 939 this.line = line;
rlm@10 940 this.tag = tag;
rlm@10 941 if(field == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))
rlm@10 942 {
rlm@10 943 RT.errPrintWriter()
rlm@10 944 .format("Reflection warning, %s:%d - reference to field %s can't be resolved.\n",
rlm@10 945 SOURCE_PATH.deref(), line, fieldName);
rlm@10 946 }
rlm@10 947 }
rlm@10 948
rlm@10 949 public Object eval() throws Exception{
rlm@10 950 return Reflector.invokeNoArgInstanceMember(target.eval(), fieldName);
rlm@10 951 }
rlm@10 952
rlm@10 953 public boolean canEmitPrimitive(){
rlm@10 954 return targetClass != null && field != null &&
rlm@10 955 Util.isPrimitive(field.getType());
rlm@10 956 }
rlm@10 957
rlm@10 958 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 959 gen.visitLineNumber(line, gen.mark());
rlm@10 960 if(targetClass != null && field != null)
rlm@10 961 {
rlm@10 962 target.emit(C.EXPRESSION, objx, gen);
rlm@10 963 gen.checkCast(getType(targetClass));
rlm@10 964 gen.getField(getType(targetClass), fieldName, Type.getType(field.getType()));
rlm@10 965 }
rlm@10 966 else
rlm@10 967 throw new UnsupportedOperationException("Unboxed emit of unknown member");
rlm@10 968 }
rlm@10 969
rlm@10 970 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 971 gen.visitLineNumber(line, gen.mark());
rlm@10 972 if(targetClass != null && field != null)
rlm@10 973 {
rlm@10 974 target.emit(C.EXPRESSION, objx, gen);
rlm@10 975 gen.checkCast(getType(targetClass));
rlm@10 976 gen.getField(getType(targetClass), fieldName, Type.getType(field.getType()));
rlm@10 977 //if(context != C.STATEMENT)
rlm@10 978 HostExpr.emitBoxReturn(objx, gen, field.getType());
rlm@10 979 if(context == C.STATEMENT)
rlm@10 980 {
rlm@10 981 gen.pop();
rlm@10 982 }
rlm@10 983 }
rlm@10 984 else
rlm@10 985 {
rlm@10 986 target.emit(C.EXPRESSION, objx, gen);
rlm@10 987 gen.push(fieldName);
rlm@10 988 gen.invokeStatic(REFLECTOR_TYPE, invokeNoArgInstanceMember);
rlm@10 989 if(context == C.STATEMENT)
rlm@10 990 gen.pop();
rlm@10 991 }
rlm@10 992 }
rlm@10 993
rlm@10 994 public boolean hasJavaClass() throws Exception{
rlm@10 995 return field != null || tag != null;
rlm@10 996 }
rlm@10 997
rlm@10 998 public Class getJavaClass() throws Exception{
rlm@10 999 return tag != null ? HostExpr.tagToClass(tag) : field.getType();
rlm@10 1000 }
rlm@10 1001
rlm@10 1002 public Object evalAssign(Expr val) throws Exception{
rlm@10 1003 return Reflector.setInstanceField(target.eval(), fieldName, val.eval());
rlm@10 1004 }
rlm@10 1005
rlm@10 1006 public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen,
rlm@10 1007 Expr val){
rlm@10 1008 gen.visitLineNumber(line, gen.mark());
rlm@10 1009 if(targetClass != null && field != null)
rlm@10 1010 {
rlm@10 1011 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1012 gen.checkCast(Type.getType(targetClass));
rlm@10 1013 val.emit(C.EXPRESSION, objx, gen);
rlm@10 1014 gen.dupX1();
rlm@10 1015 HostExpr.emitUnboxArg(objx, gen, field.getType());
rlm@10 1016 gen.putField(Type.getType(targetClass), fieldName, Type.getType(field.getType()));
rlm@10 1017 }
rlm@10 1018 else
rlm@10 1019 {
rlm@10 1020 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1021 gen.push(fieldName);
rlm@10 1022 val.emit(C.EXPRESSION, objx, gen);
rlm@10 1023 gen.invokeStatic(REFLECTOR_TYPE, setInstanceFieldMethod);
rlm@10 1024 }
rlm@10 1025 if(context == C.STATEMENT)
rlm@10 1026 gen.pop();
rlm@10 1027 }
rlm@10 1028 }
rlm@10 1029
rlm@10 1030 static class StaticFieldExpr extends FieldExpr implements AssignableExpr{
rlm@10 1031 //final String className;
rlm@10 1032 public final String fieldName;
rlm@10 1033 public final Class c;
rlm@10 1034 public final java.lang.reflect.Field field;
rlm@10 1035 public final Symbol tag;
rlm@10 1036 // final static Method getStaticFieldMethod = Method.getMethod("Object getStaticField(String,String)");
rlm@10 1037 // final static Method setStaticFieldMethod = Method.getMethod("Object setStaticField(String,String,Object)");
rlm@10 1038 final int line;
rlm@10 1039
rlm@10 1040 public StaticFieldExpr(int line, Class c, String fieldName, Symbol tag) throws Exception{
rlm@10 1041 //this.className = className;
rlm@10 1042 this.fieldName = fieldName;
rlm@10 1043 this.line = line;
rlm@10 1044 //c = Class.forName(className);
rlm@10 1045 this.c = c;
rlm@10 1046 field = c.getField(fieldName);
rlm@10 1047 this.tag = tag;
rlm@10 1048 }
rlm@10 1049
rlm@10 1050 public Object eval() throws Exception{
rlm@10 1051 return Reflector.getStaticField(c, fieldName);
rlm@10 1052 }
rlm@10 1053
rlm@10 1054 public boolean canEmitPrimitive(){
rlm@10 1055 return Util.isPrimitive(field.getType());
rlm@10 1056 }
rlm@10 1057
rlm@10 1058 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1059 gen.visitLineNumber(line, gen.mark());
rlm@10 1060 gen.getStatic(Type.getType(c), fieldName, Type.getType(field.getType()));
rlm@10 1061 }
rlm@10 1062
rlm@10 1063 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1064 gen.visitLineNumber(line, gen.mark());
rlm@10 1065
rlm@10 1066 gen.getStatic(Type.getType(c), fieldName, Type.getType(field.getType()));
rlm@10 1067 //if(context != C.STATEMENT)
rlm@10 1068 HostExpr.emitBoxReturn(objx, gen, field.getType());
rlm@10 1069 if(context == C.STATEMENT)
rlm@10 1070 {
rlm@10 1071 gen.pop();
rlm@10 1072 }
rlm@10 1073 // gen.push(className);
rlm@10 1074 // gen.push(fieldName);
rlm@10 1075 // gen.invokeStatic(REFLECTOR_TYPE, getStaticFieldMethod);
rlm@10 1076 }
rlm@10 1077
rlm@10 1078 public boolean hasJavaClass(){
rlm@10 1079 return true;
rlm@10 1080 }
rlm@10 1081
rlm@10 1082 public Class getJavaClass() throws Exception{
rlm@10 1083 //Class c = Class.forName(className);
rlm@10 1084 //java.lang.reflect.Field field = c.getField(fieldName);
rlm@10 1085 return tag != null ? HostExpr.tagToClass(tag) : field.getType();
rlm@10 1086 }
rlm@10 1087
rlm@10 1088 public Object evalAssign(Expr val) throws Exception{
rlm@10 1089 return Reflector.setStaticField(c, fieldName, val.eval());
rlm@10 1090 }
rlm@10 1091
rlm@10 1092 public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen,
rlm@10 1093 Expr val){
rlm@10 1094 gen.visitLineNumber(line, gen.mark());
rlm@10 1095 val.emit(C.EXPRESSION, objx, gen);
rlm@10 1096 gen.dup();
rlm@10 1097 HostExpr.emitUnboxArg(objx, gen, field.getType());
rlm@10 1098 gen.putStatic(Type.getType(c), fieldName, Type.getType(field.getType()));
rlm@10 1099 if(context == C.STATEMENT)
rlm@10 1100 gen.pop();
rlm@10 1101 }
rlm@10 1102
rlm@10 1103
rlm@10 1104 }
rlm@10 1105
rlm@10 1106 static Class maybePrimitiveType(Expr e){
rlm@10 1107 try
rlm@10 1108 {
rlm@10 1109 if(e instanceof MaybePrimitiveExpr && e.hasJavaClass() && ((MaybePrimitiveExpr)e).canEmitPrimitive())
rlm@10 1110 {
rlm@10 1111 Class c = e.getJavaClass();
rlm@10 1112 if(Util.isPrimitive(c))
rlm@10 1113 return c;
rlm@10 1114 }
rlm@10 1115 }
rlm@10 1116 catch(Exception ex)
rlm@10 1117 {
rlm@10 1118 throw new RuntimeException(ex);
rlm@10 1119 }
rlm@10 1120 return null;
rlm@10 1121 }
rlm@10 1122
rlm@10 1123 static abstract class MethodExpr extends HostExpr{
rlm@10 1124 static void emitArgsAsArray(IPersistentVector args, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1125 gen.push(args.count());
rlm@10 1126 gen.newArray(OBJECT_TYPE);
rlm@10 1127 for(int i = 0; i < args.count(); i++)
rlm@10 1128 {
rlm@10 1129 gen.dup();
rlm@10 1130 gen.push(i);
rlm@10 1131 ((Expr) args.nth(i)).emit(C.EXPRESSION, objx, gen);
rlm@10 1132 gen.arrayStore(OBJECT_TYPE);
rlm@10 1133 }
rlm@10 1134 }
rlm@10 1135
rlm@10 1136 public static void emitTypedArgs(ObjExpr objx, GeneratorAdapter gen, Class[] parameterTypes, IPersistentVector args){
rlm@10 1137 for(int i = 0; i < parameterTypes.length; i++)
rlm@10 1138 {
rlm@10 1139 Expr e = (Expr) args.nth(i);
rlm@10 1140 try
rlm@10 1141 {
rlm@10 1142 if(maybePrimitiveType(e) == parameterTypes[i])
rlm@10 1143 {
rlm@10 1144 ((MaybePrimitiveExpr) e).emitUnboxed(C.EXPRESSION, objx, gen);
rlm@10 1145 }
rlm@10 1146 else
rlm@10 1147 {
rlm@10 1148 e.emit(C.EXPRESSION, objx, gen);
rlm@10 1149 HostExpr.emitUnboxArg(objx, gen, parameterTypes[i]);
rlm@10 1150 }
rlm@10 1151 }
rlm@10 1152 catch(Exception e1)
rlm@10 1153 {
rlm@10 1154 e1.printStackTrace(RT.errPrintWriter());
rlm@10 1155 }
rlm@10 1156
rlm@10 1157 }
rlm@10 1158 }
rlm@10 1159 }
rlm@10 1160
rlm@10 1161 static class InstanceMethodExpr extends MethodExpr{
rlm@10 1162 public final Expr target;
rlm@10 1163 public final String methodName;
rlm@10 1164 public final IPersistentVector args;
rlm@10 1165 public final String source;
rlm@10 1166 public final int line;
rlm@10 1167 public final Symbol tag;
rlm@10 1168 public final java.lang.reflect.Method method;
rlm@10 1169
rlm@10 1170 final static Method invokeInstanceMethodMethod =
rlm@10 1171 Method.getMethod("Object invokeInstanceMethod(Object,String,Object[])");
rlm@10 1172
rlm@10 1173
rlm@10 1174 public InstanceMethodExpr(String source, int line, Symbol tag, Expr target, String methodName, IPersistentVector args)
rlm@10 1175 throws Exception{
rlm@10 1176 this.source = source;
rlm@10 1177 this.line = line;
rlm@10 1178 this.args = args;
rlm@10 1179 this.methodName = methodName;
rlm@10 1180 this.target = target;
rlm@10 1181 this.tag = tag;
rlm@10 1182 if(target.hasJavaClass() && target.getJavaClass() != null)
rlm@10 1183 {
rlm@10 1184 List methods = Reflector.getMethods(target.getJavaClass(), args.count(), methodName, false);
rlm@10 1185 if(methods.isEmpty())
rlm@10 1186 method = null;
rlm@10 1187 //throw new IllegalArgumentException("No matching method found");
rlm@10 1188 else
rlm@10 1189 {
rlm@10 1190 int methodidx = 0;
rlm@10 1191 if(methods.size() > 1)
rlm@10 1192 {
rlm@10 1193 ArrayList<Class[]> params = new ArrayList();
rlm@10 1194 ArrayList<Class> rets = new ArrayList();
rlm@10 1195 for(int i = 0; i < methods.size(); i++)
rlm@10 1196 {
rlm@10 1197 java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i);
rlm@10 1198 params.add(m.getParameterTypes());
rlm@10 1199 rets.add(m.getReturnType());
rlm@10 1200 }
rlm@10 1201 methodidx = getMatchingParams(methodName, params, args, rets);
rlm@10 1202 }
rlm@10 1203 java.lang.reflect.Method m =
rlm@10 1204 (java.lang.reflect.Method) (methodidx >= 0 ? methods.get(methodidx) : null);
rlm@10 1205 if(m != null && !Modifier.isPublic(m.getDeclaringClass().getModifiers()))
rlm@10 1206 {
rlm@10 1207 //public method of non-public class, try to find it in hierarchy
rlm@10 1208 m = Reflector.getAsMethodOfPublicBase(m.getDeclaringClass(), m);
rlm@10 1209 }
rlm@10 1210 method = m;
rlm@10 1211 }
rlm@10 1212 }
rlm@10 1213 else
rlm@10 1214 method = null;
rlm@10 1215
rlm@10 1216 if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))
rlm@10 1217 {
rlm@10 1218 RT.errPrintWriter()
rlm@10 1219 .format("Reflection warning, %s:%d - call to %s can't be resolved.\n",
rlm@10 1220 SOURCE_PATH.deref(), line, methodName);
rlm@10 1221 }
rlm@10 1222 }
rlm@10 1223
rlm@10 1224 public Object eval() throws Exception{
rlm@10 1225 try
rlm@10 1226 {
rlm@10 1227 Object targetval = target.eval();
rlm@10 1228 Object[] argvals = new Object[args.count()];
rlm@10 1229 for(int i = 0; i < args.count(); i++)
rlm@10 1230 argvals[i] = ((Expr) args.nth(i)).eval();
rlm@10 1231 if(method != null)
rlm@10 1232 {
rlm@10 1233 LinkedList ms = new LinkedList();
rlm@10 1234 ms.add(method);
rlm@10 1235 return Reflector.invokeMatchingMethod(methodName, ms, targetval, argvals);
rlm@10 1236 }
rlm@10 1237 return Reflector.invokeInstanceMethod(targetval, methodName, argvals);
rlm@10 1238 }
rlm@10 1239 catch(Throwable e)
rlm@10 1240 {
rlm@10 1241 if(!(e instanceof CompilerException))
rlm@10 1242 throw new CompilerException(source, line, e);
rlm@10 1243 else
rlm@10 1244 throw (CompilerException) e;
rlm@10 1245 }
rlm@10 1246 }
rlm@10 1247
rlm@10 1248 public boolean canEmitPrimitive(){
rlm@10 1249 return method != null && Util.isPrimitive(method.getReturnType());
rlm@10 1250 }
rlm@10 1251
rlm@10 1252 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1253 gen.visitLineNumber(line, gen.mark());
rlm@10 1254 if(method != null)
rlm@10 1255 {
rlm@10 1256 Type type = Type.getType(method.getDeclaringClass());
rlm@10 1257 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1258 //if(!method.getDeclaringClass().isInterface())
rlm@10 1259 gen.checkCast(type);
rlm@10 1260 MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args);
rlm@10 1261 if(context == C.RETURN)
rlm@10 1262 {
rlm@10 1263 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 1264 method.emitClearLocals(gen);
rlm@10 1265 }
rlm@10 1266 Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method));
rlm@10 1267 if(method.getDeclaringClass().isInterface())
rlm@10 1268 gen.invokeInterface(type, m);
rlm@10 1269 else
rlm@10 1270 gen.invokeVirtual(type, m);
rlm@10 1271 }
rlm@10 1272 else
rlm@10 1273 throw new UnsupportedOperationException("Unboxed emit of unknown member");
rlm@10 1274 }
rlm@10 1275
rlm@10 1276 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1277 gen.visitLineNumber(line, gen.mark());
rlm@10 1278 if(method != null)
rlm@10 1279 {
rlm@10 1280 Type type = Type.getType(method.getDeclaringClass());
rlm@10 1281 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1282 //if(!method.getDeclaringClass().isInterface())
rlm@10 1283 gen.checkCast(type);
rlm@10 1284 MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args);
rlm@10 1285 if(context == C.RETURN)
rlm@10 1286 {
rlm@10 1287 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 1288 method.emitClearLocals(gen);
rlm@10 1289 }
rlm@10 1290 Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method));
rlm@10 1291 if(method.getDeclaringClass().isInterface())
rlm@10 1292 gen.invokeInterface(type, m);
rlm@10 1293 else
rlm@10 1294 gen.invokeVirtual(type, m);
rlm@10 1295 //if(context != C.STATEMENT || method.getReturnType() == Void.TYPE)
rlm@10 1296 HostExpr.emitBoxReturn(objx, gen, method.getReturnType());
rlm@10 1297 }
rlm@10 1298 else
rlm@10 1299 {
rlm@10 1300 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1301 gen.push(methodName);
rlm@10 1302 emitArgsAsArray(args, objx, gen);
rlm@10 1303 if(context == C.RETURN)
rlm@10 1304 {
rlm@10 1305 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 1306 method.emitClearLocals(gen);
rlm@10 1307 }
rlm@10 1308 gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodMethod);
rlm@10 1309 }
rlm@10 1310 if(context == C.STATEMENT)
rlm@10 1311 gen.pop();
rlm@10 1312 }
rlm@10 1313
rlm@10 1314 public boolean hasJavaClass(){
rlm@10 1315 return method != null || tag != null;
rlm@10 1316 }
rlm@10 1317
rlm@10 1318 public Class getJavaClass() throws Exception{
rlm@10 1319 return tag != null ? HostExpr.tagToClass(tag) : method.getReturnType();
rlm@10 1320 }
rlm@10 1321 }
rlm@10 1322
rlm@10 1323
rlm@10 1324 static class StaticMethodExpr extends MethodExpr{
rlm@10 1325 //final String className;
rlm@10 1326 public final Class c;
rlm@10 1327 public final String methodName;
rlm@10 1328 public final IPersistentVector args;
rlm@10 1329 public final String source;
rlm@10 1330 public final int line;
rlm@10 1331 public final java.lang.reflect.Method method;
rlm@10 1332 public final Symbol tag;
rlm@10 1333 final static Method forNameMethod = Method.getMethod("Class forName(String)");
rlm@10 1334 final static Method invokeStaticMethodMethod =
rlm@10 1335 Method.getMethod("Object invokeStaticMethod(Class,String,Object[])");
rlm@10 1336
rlm@10 1337
rlm@10 1338 public StaticMethodExpr(String source, int line, Symbol tag, Class c, String methodName, IPersistentVector args)
rlm@10 1339 throws Exception{
rlm@10 1340 this.c = c;
rlm@10 1341 this.methodName = methodName;
rlm@10 1342 this.args = args;
rlm@10 1343 this.source = source;
rlm@10 1344 this.line = line;
rlm@10 1345 this.tag = tag;
rlm@10 1346
rlm@10 1347 List methods = Reflector.getMethods(c, args.count(), methodName, true);
rlm@10 1348 if(methods.isEmpty())
rlm@10 1349 throw new IllegalArgumentException("No matching method: " + methodName);
rlm@10 1350
rlm@10 1351 int methodidx = 0;
rlm@10 1352 if(methods.size() > 1)
rlm@10 1353 {
rlm@10 1354 ArrayList<Class[]> params = new ArrayList();
rlm@10 1355 ArrayList<Class> rets = new ArrayList();
rlm@10 1356 for(int i = 0; i < methods.size(); i++)
rlm@10 1357 {
rlm@10 1358 java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i);
rlm@10 1359 params.add(m.getParameterTypes());
rlm@10 1360 rets.add(m.getReturnType());
rlm@10 1361 }
rlm@10 1362 methodidx = getMatchingParams(methodName, params, args, rets);
rlm@10 1363 }
rlm@10 1364 method = (java.lang.reflect.Method) (methodidx >= 0 ? methods.get(methodidx) : null);
rlm@10 1365 if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))
rlm@10 1366 {
rlm@10 1367 RT.errPrintWriter()
rlm@10 1368 .format("Reflection warning, %s:%d - call to %s can't be resolved.\n",
rlm@10 1369 SOURCE_PATH.deref(), line, methodName);
rlm@10 1370 }
rlm@10 1371 }
rlm@10 1372
rlm@10 1373 public Object eval() throws Exception{
rlm@10 1374 try
rlm@10 1375 {
rlm@10 1376 Object[] argvals = new Object[args.count()];
rlm@10 1377 for(int i = 0; i < args.count(); i++)
rlm@10 1378 argvals[i] = ((Expr) args.nth(i)).eval();
rlm@10 1379 if(method != null)
rlm@10 1380 {
rlm@10 1381 LinkedList ms = new LinkedList();
rlm@10 1382 ms.add(method);
rlm@10 1383 return Reflector.invokeMatchingMethod(methodName, ms, null, argvals);
rlm@10 1384 }
rlm@10 1385 return Reflector.invokeStaticMethod(c, methodName, argvals);
rlm@10 1386 }
rlm@10 1387 catch(Throwable e)
rlm@10 1388 {
rlm@10 1389 if(!(e instanceof CompilerException))
rlm@10 1390 throw new CompilerException(source, line, e);
rlm@10 1391 else
rlm@10 1392 throw (CompilerException) e;
rlm@10 1393 }
rlm@10 1394 }
rlm@10 1395
rlm@10 1396 public boolean canEmitPrimitive(){
rlm@10 1397 return method != null && Util.isPrimitive(method.getReturnType());
rlm@10 1398 }
rlm@10 1399
rlm@10 1400 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1401 gen.visitLineNumber(line, gen.mark());
rlm@10 1402 if(method != null)
rlm@10 1403 {
rlm@10 1404 MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args);
rlm@10 1405 //Type type = Type.getObjectType(className.replace('.', '/'));
rlm@10 1406 if(context == C.RETURN)
rlm@10 1407 {
rlm@10 1408 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 1409 method.emitClearLocals(gen);
rlm@10 1410 }
rlm@10 1411 Type type = Type.getType(c);
rlm@10 1412 Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method));
rlm@10 1413 gen.invokeStatic(type, m);
rlm@10 1414 }
rlm@10 1415 else
rlm@10 1416 throw new UnsupportedOperationException("Unboxed emit of unknown member");
rlm@10 1417 }
rlm@10 1418
rlm@10 1419 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1420 gen.visitLineNumber(line, gen.mark());
rlm@10 1421 if(method != null)
rlm@10 1422 {
rlm@10 1423 MethodExpr.emitTypedArgs(objx, gen, method.getParameterTypes(), args);
rlm@10 1424 //Type type = Type.getObjectType(className.replace('.', '/'));
rlm@10 1425 if(context == C.RETURN)
rlm@10 1426 {
rlm@10 1427 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 1428 method.emitClearLocals(gen);
rlm@10 1429 }
rlm@10 1430 Type type = Type.getType(c);
rlm@10 1431 Method m = new Method(methodName, Type.getReturnType(method), Type.getArgumentTypes(method));
rlm@10 1432 gen.invokeStatic(type, m);
rlm@10 1433 //if(context != C.STATEMENT || method.getReturnType() == Void.TYPE)
rlm@10 1434 HostExpr.emitBoxReturn(objx, gen, method.getReturnType());
rlm@10 1435 }
rlm@10 1436 else
rlm@10 1437 {
rlm@10 1438 gen.push(c.getName());
rlm@10 1439 gen.invokeStatic(CLASS_TYPE, forNameMethod);
rlm@10 1440 gen.push(methodName);
rlm@10 1441 emitArgsAsArray(args, objx, gen);
rlm@10 1442 if(context == C.RETURN)
rlm@10 1443 {
rlm@10 1444 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 1445 method.emitClearLocals(gen);
rlm@10 1446 }
rlm@10 1447 gen.invokeStatic(REFLECTOR_TYPE, invokeStaticMethodMethod);
rlm@10 1448 }
rlm@10 1449 if(context == C.STATEMENT)
rlm@10 1450 gen.pop();
rlm@10 1451 }
rlm@10 1452
rlm@10 1453 public boolean hasJavaClass(){
rlm@10 1454 return method != null || tag != null;
rlm@10 1455 }
rlm@10 1456
rlm@10 1457 public Class getJavaClass() throws Exception{
rlm@10 1458 return tag != null ? HostExpr.tagToClass(tag) : method.getReturnType();
rlm@10 1459 }
rlm@10 1460 }
rlm@10 1461
rlm@10 1462 static class UnresolvedVarExpr implements Expr{
rlm@10 1463 public final Symbol symbol;
rlm@10 1464
rlm@10 1465 public UnresolvedVarExpr(Symbol symbol){
rlm@10 1466 this.symbol = symbol;
rlm@10 1467 }
rlm@10 1468
rlm@10 1469 public boolean hasJavaClass(){
rlm@10 1470 return false;
rlm@10 1471 }
rlm@10 1472
rlm@10 1473 public Class getJavaClass() throws Exception{
rlm@10 1474 throw new IllegalArgumentException(
rlm@10 1475 "UnresolvedVarExpr has no Java class");
rlm@10 1476 }
rlm@10 1477
rlm@10 1478 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1479 }
rlm@10 1480
rlm@10 1481 public Object eval() throws Exception{
rlm@10 1482 throw new IllegalArgumentException(
rlm@10 1483 "UnresolvedVarExpr cannot be evalled");
rlm@10 1484 }
rlm@10 1485 }
rlm@10 1486
rlm@10 1487 static class ConstantExpr extends LiteralExpr{
rlm@10 1488 //stuff quoted vals in classloader at compile time, pull out at runtime
rlm@10 1489 //this won't work for static compilation...
rlm@10 1490 public final Object v;
rlm@10 1491 public final int id;
rlm@10 1492
rlm@10 1493 public ConstantExpr(Object v){
rlm@10 1494 this.v = v;
rlm@10 1495 this.id = registerConstant(v);
rlm@10 1496 // this.id = RT.nextID();
rlm@10 1497 // DynamicClassLoader loader = (DynamicClassLoader) LOADER.get();
rlm@10 1498 // loader.registerQuotedVal(id, v);
rlm@10 1499 }
rlm@10 1500
rlm@10 1501 Object val(){
rlm@10 1502 return v;
rlm@10 1503 }
rlm@10 1504
rlm@10 1505 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1506 objx.emitConstant(gen, id);
rlm@10 1507 if(context == C.STATEMENT)
rlm@10 1508 {
rlm@10 1509 gen.pop();
rlm@10 1510 // gen.loadThis();
rlm@10 1511 // gen.invokeVirtual(OBJECT_TYPE, getClassMethod);
rlm@10 1512 // gen.invokeVirtual(CLASS_TYPE, getClassLoaderMethod);
rlm@10 1513 // gen.checkCast(DYNAMIC_CLASSLOADER_TYPE);
rlm@10 1514 // gen.push(id);
rlm@10 1515 // gen.invokeVirtual(DYNAMIC_CLASSLOADER_TYPE, getQuotedValMethod);
rlm@10 1516 }
rlm@10 1517 }
rlm@10 1518
rlm@10 1519 public boolean hasJavaClass(){
rlm@10 1520 return Modifier.isPublic(v.getClass().getModifiers());
rlm@10 1521 //return false;
rlm@10 1522 }
rlm@10 1523
rlm@10 1524 public Class getJavaClass() throws Exception{
rlm@10 1525 return v.getClass();
rlm@10 1526 //throw new IllegalArgumentException("Has no Java class");
rlm@10 1527 }
rlm@10 1528
rlm@10 1529 static class Parser implements IParser{
rlm@10 1530 public Expr parse(C context, Object form){
rlm@10 1531 Object v = RT.second(form);
rlm@10 1532
rlm@10 1533 if(v == null)
rlm@10 1534 return NIL_EXPR;
rlm@10 1535 // Class fclass = v.getClass();
rlm@10 1536 // if(fclass == Keyword.class)
rlm@10 1537 // return registerKeyword((Keyword) v);
rlm@10 1538 // else if(v instanceof Num)
rlm@10 1539 // return new NumExpr((Num) v);
rlm@10 1540 // else if(fclass == String.class)
rlm@10 1541 // return new StringExpr((String) v);
rlm@10 1542 // else if(fclass == Character.class)
rlm@10 1543 // return new CharExpr((Character) v);
rlm@10 1544 // else if(v instanceof IPersistentCollection && ((IPersistentCollection) v).count() == 0)
rlm@10 1545 // return new EmptyExpr(v);
rlm@10 1546 else
rlm@10 1547 return new ConstantExpr(v);
rlm@10 1548 }
rlm@10 1549 }
rlm@10 1550 }
rlm@10 1551
rlm@10 1552 static class NilExpr extends LiteralExpr{
rlm@10 1553 Object val(){
rlm@10 1554 return null;
rlm@10 1555 }
rlm@10 1556
rlm@10 1557 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1558 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 1559 if(context == C.STATEMENT)
rlm@10 1560 gen.pop();
rlm@10 1561 }
rlm@10 1562
rlm@10 1563 public boolean hasJavaClass(){
rlm@10 1564 return true;
rlm@10 1565 }
rlm@10 1566
rlm@10 1567 public Class getJavaClass() throws Exception{
rlm@10 1568 return null;
rlm@10 1569 }
rlm@10 1570 }
rlm@10 1571
rlm@10 1572 final static NilExpr NIL_EXPR = new NilExpr();
rlm@10 1573
rlm@10 1574 static class BooleanExpr extends LiteralExpr{
rlm@10 1575 public final boolean val;
rlm@10 1576
rlm@10 1577
rlm@10 1578 public BooleanExpr(boolean val){
rlm@10 1579 this.val = val;
rlm@10 1580 }
rlm@10 1581
rlm@10 1582 Object val(){
rlm@10 1583 return val ? RT.T : RT.F;
rlm@10 1584 }
rlm@10 1585
rlm@10 1586 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1587 if(val)
rlm@10 1588 gen.getStatic(BOOLEAN_OBJECT_TYPE, "TRUE", BOOLEAN_OBJECT_TYPE);
rlm@10 1589 else
rlm@10 1590 gen.getStatic(BOOLEAN_OBJECT_TYPE, "FALSE", BOOLEAN_OBJECT_TYPE);
rlm@10 1591 if(context == C.STATEMENT)
rlm@10 1592 {
rlm@10 1593 gen.pop();
rlm@10 1594 }
rlm@10 1595 }
rlm@10 1596
rlm@10 1597 public boolean hasJavaClass(){
rlm@10 1598 return true;
rlm@10 1599 }
rlm@10 1600
rlm@10 1601 public Class getJavaClass() throws Exception{
rlm@10 1602 return Boolean.class;
rlm@10 1603 }
rlm@10 1604 }
rlm@10 1605
rlm@10 1606 final static BooleanExpr TRUE_EXPR = new BooleanExpr(true);
rlm@10 1607 final static BooleanExpr FALSE_EXPR = new BooleanExpr(false);
rlm@10 1608
rlm@10 1609 static class StringExpr extends LiteralExpr{
rlm@10 1610 public final String str;
rlm@10 1611
rlm@10 1612 public StringExpr(String str){
rlm@10 1613 this.str = str;
rlm@10 1614 }
rlm@10 1615
rlm@10 1616 Object val(){
rlm@10 1617 return str;
rlm@10 1618 }
rlm@10 1619
rlm@10 1620 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1621 if(context != C.STATEMENT)
rlm@10 1622 gen.push(str);
rlm@10 1623 }
rlm@10 1624
rlm@10 1625 public boolean hasJavaClass(){
rlm@10 1626 return true;
rlm@10 1627 }
rlm@10 1628
rlm@10 1629 public Class getJavaClass() throws Exception{
rlm@10 1630 return String.class;
rlm@10 1631 }
rlm@10 1632 }
rlm@10 1633
rlm@10 1634
rlm@10 1635 static class MonitorEnterExpr extends UntypedExpr{
rlm@10 1636 final Expr target;
rlm@10 1637
rlm@10 1638 public MonitorEnterExpr(Expr target){
rlm@10 1639 this.target = target;
rlm@10 1640 }
rlm@10 1641
rlm@10 1642 public Object eval() throws Exception{
rlm@10 1643 throw new UnsupportedOperationException("Can't eval monitor-enter");
rlm@10 1644 }
rlm@10 1645
rlm@10 1646 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1647 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1648 gen.monitorEnter();
rlm@10 1649 NIL_EXPR.emit(context, objx, gen);
rlm@10 1650 }
rlm@10 1651
rlm@10 1652 static class Parser implements IParser{
rlm@10 1653 public Expr parse(C context, Object form) throws Exception{
rlm@10 1654 return new MonitorEnterExpr(analyze(C.EXPRESSION, RT.second(form)));
rlm@10 1655 }
rlm@10 1656 }
rlm@10 1657 }
rlm@10 1658
rlm@10 1659 static class MonitorExitExpr extends UntypedExpr{
rlm@10 1660 final Expr target;
rlm@10 1661
rlm@10 1662 public MonitorExitExpr(Expr target){
rlm@10 1663 this.target = target;
rlm@10 1664 }
rlm@10 1665
rlm@10 1666 public Object eval() throws Exception{
rlm@10 1667 throw new UnsupportedOperationException("Can't eval monitor-exit");
rlm@10 1668 }
rlm@10 1669
rlm@10 1670 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1671 target.emit(C.EXPRESSION, objx, gen);
rlm@10 1672 gen.monitorExit();
rlm@10 1673 NIL_EXPR.emit(context, objx, gen);
rlm@10 1674 }
rlm@10 1675
rlm@10 1676 static class Parser implements IParser{
rlm@10 1677 public Expr parse(C context, Object form) throws Exception{
rlm@10 1678 return new MonitorExitExpr(analyze(C.EXPRESSION, RT.second(form)));
rlm@10 1679 }
rlm@10 1680 }
rlm@10 1681
rlm@10 1682 }
rlm@10 1683
rlm@10 1684 public static class TryExpr implements Expr{
rlm@10 1685 public final Expr tryExpr;
rlm@10 1686 public final Expr finallyExpr;
rlm@10 1687 public final PersistentVector catchExprs;
rlm@10 1688 public final int retLocal;
rlm@10 1689 public final int finallyLocal;
rlm@10 1690
rlm@10 1691 public static class CatchClause{
rlm@10 1692 //final String className;
rlm@10 1693 public final Class c;
rlm@10 1694 public final LocalBinding lb;
rlm@10 1695 public final Expr handler;
rlm@10 1696 Label label;
rlm@10 1697 Label endLabel;
rlm@10 1698
rlm@10 1699
rlm@10 1700 public CatchClause(Class c, LocalBinding lb, Expr handler){
rlm@10 1701 this.c = c;
rlm@10 1702 this.lb = lb;
rlm@10 1703 this.handler = handler;
rlm@10 1704 }
rlm@10 1705 }
rlm@10 1706
rlm@10 1707 public TryExpr(Expr tryExpr, PersistentVector catchExprs, Expr finallyExpr, int retLocal, int finallyLocal){
rlm@10 1708 this.tryExpr = tryExpr;
rlm@10 1709 this.catchExprs = catchExprs;
rlm@10 1710 this.finallyExpr = finallyExpr;
rlm@10 1711 this.retLocal = retLocal;
rlm@10 1712 this.finallyLocal = finallyLocal;
rlm@10 1713 }
rlm@10 1714
rlm@10 1715 public Object eval() throws Exception{
rlm@10 1716 throw new UnsupportedOperationException("Can't eval try");
rlm@10 1717 }
rlm@10 1718
rlm@10 1719 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1720 Label startTry = gen.newLabel();
rlm@10 1721 Label endTry = gen.newLabel();
rlm@10 1722 Label end = gen.newLabel();
rlm@10 1723 Label ret = gen.newLabel();
rlm@10 1724 Label finallyLabel = gen.newLabel();
rlm@10 1725 for(int i = 0; i < catchExprs.count(); i++)
rlm@10 1726 {
rlm@10 1727 CatchClause clause = (CatchClause) catchExprs.nth(i);
rlm@10 1728 clause.label = gen.newLabel();
rlm@10 1729 clause.endLabel = gen.newLabel();
rlm@10 1730 }
rlm@10 1731
rlm@10 1732 gen.mark(startTry);
rlm@10 1733 tryExpr.emit(context, objx, gen);
rlm@10 1734 if(context != C.STATEMENT)
rlm@10 1735 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), retLocal);
rlm@10 1736 gen.mark(endTry);
rlm@10 1737 if(finallyExpr != null)
rlm@10 1738 finallyExpr.emit(C.STATEMENT, objx, gen);
rlm@10 1739 gen.goTo(ret);
rlm@10 1740
rlm@10 1741 for(int i = 0; i < catchExprs.count(); i++)
rlm@10 1742 {
rlm@10 1743 CatchClause clause = (CatchClause) catchExprs.nth(i);
rlm@10 1744 gen.mark(clause.label);
rlm@10 1745 //exception should be on stack
rlm@10 1746 //put in clause local
rlm@10 1747 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), clause.lb.idx);
rlm@10 1748 clause.handler.emit(context, objx, gen);
rlm@10 1749 if(context != C.STATEMENT)
rlm@10 1750 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), retLocal);
rlm@10 1751 gen.mark(clause.endLabel);
rlm@10 1752
rlm@10 1753 if(finallyExpr != null)
rlm@10 1754 finallyExpr.emit(C.STATEMENT, objx, gen);
rlm@10 1755 gen.goTo(ret);
rlm@10 1756 }
rlm@10 1757 if(finallyExpr != null)
rlm@10 1758 {
rlm@10 1759 gen.mark(finallyLabel);
rlm@10 1760 //exception should be on stack
rlm@10 1761 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), finallyLocal);
rlm@10 1762 finallyExpr.emit(C.STATEMENT, objx, gen);
rlm@10 1763 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), finallyLocal);
rlm@10 1764 gen.throwException();
rlm@10 1765 }
rlm@10 1766 gen.mark(ret);
rlm@10 1767 if(context != C.STATEMENT)
rlm@10 1768 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), retLocal);
rlm@10 1769 gen.mark(end);
rlm@10 1770 for(int i = 0; i < catchExprs.count(); i++)
rlm@10 1771 {
rlm@10 1772 CatchClause clause = (CatchClause) catchExprs.nth(i);
rlm@10 1773 gen.visitTryCatchBlock(startTry, endTry, clause.label, clause.c.getName().replace('.', '/'));
rlm@10 1774 }
rlm@10 1775 if(finallyExpr != null)
rlm@10 1776 {
rlm@10 1777 gen.visitTryCatchBlock(startTry, endTry, finallyLabel, null);
rlm@10 1778 for(int i = 0; i < catchExprs.count(); i++)
rlm@10 1779 {
rlm@10 1780 CatchClause clause = (CatchClause) catchExprs.nth(i);
rlm@10 1781 gen.visitTryCatchBlock(clause.label, clause.endLabel, finallyLabel, null);
rlm@10 1782 }
rlm@10 1783 }
rlm@10 1784 for(int i = 0; i < catchExprs.count(); i++)
rlm@10 1785 {
rlm@10 1786 CatchClause clause = (CatchClause) catchExprs.nth(i);
rlm@10 1787 gen.visitLocalVariable(clause.lb.name, "Ljava/lang/Object;", null, clause.label, clause.endLabel,
rlm@10 1788 clause.lb.idx);
rlm@10 1789 }
rlm@10 1790 }
rlm@10 1791
rlm@10 1792 public boolean hasJavaClass() throws Exception{
rlm@10 1793 return tryExpr.hasJavaClass();
rlm@10 1794 }
rlm@10 1795
rlm@10 1796 public Class getJavaClass() throws Exception{
rlm@10 1797 return tryExpr.getJavaClass();
rlm@10 1798 }
rlm@10 1799
rlm@10 1800 static class Parser implements IParser{
rlm@10 1801
rlm@10 1802 public Expr parse(C context, Object frm) throws Exception{
rlm@10 1803 ISeq form = (ISeq) frm;
rlm@10 1804 // if(context == C.EVAL || context == C.EXPRESSION)
rlm@10 1805 if(context != C.RETURN)
rlm@10 1806 return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
rlm@10 1807
rlm@10 1808 //(try try-expr* catch-expr* finally-expr?)
rlm@10 1809 //catch-expr: (catch class sym expr*)
rlm@10 1810 //finally-expr: (finally expr*)
rlm@10 1811
rlm@10 1812 PersistentVector body = PersistentVector.EMPTY;
rlm@10 1813 PersistentVector catches = PersistentVector.EMPTY;
rlm@10 1814 Expr bodyExpr = null;
rlm@10 1815 Expr finallyExpr = null;
rlm@10 1816 boolean caught = false;
rlm@10 1817
rlm@10 1818 int retLocal = getAndIncLocalNum();
rlm@10 1819 int finallyLocal = getAndIncLocalNum();
rlm@10 1820 for(ISeq fs = form.next(); fs != null; fs = fs.next())
rlm@10 1821 {
rlm@10 1822 Object f = fs.first();
rlm@10 1823 Object op = (f instanceof ISeq) ? ((ISeq) f).first() : null;
rlm@10 1824 if(!Util.equals(op, CATCH) && !Util.equals(op, FINALLY))
rlm@10 1825 {
rlm@10 1826 if(caught)
rlm@10 1827 throw new Exception("Only catch or finally clause can follow catch in try expression");
rlm@10 1828 body = body.cons(f);
rlm@10 1829 }
rlm@10 1830 else
rlm@10 1831 {
rlm@10 1832 if(bodyExpr == null)
rlm@10 1833 bodyExpr = (new BodyExpr.Parser()).parse(context, RT.seq(body));
rlm@10 1834 if(Util.equals(op, CATCH))
rlm@10 1835 {
rlm@10 1836 Class c = HostExpr.maybeClass(RT.second(f), false);
rlm@10 1837 if(c == null)
rlm@10 1838 throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(f));
rlm@10 1839 if(!(RT.third(f) instanceof Symbol))
rlm@10 1840 throw new IllegalArgumentException(
rlm@10 1841 "Bad binding form, expected symbol, got: " + RT.third(f));
rlm@10 1842 Symbol sym = (Symbol) RT.third(f);
rlm@10 1843 if(sym.getNamespace() != null)
rlm@10 1844 throw new Exception("Can't bind qualified name:" + sym);
rlm@10 1845
rlm@10 1846 IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(),
rlm@10 1847 NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref(),
rlm@10 1848 IN_CATCH_FINALLY, RT.T);
rlm@10 1849 try
rlm@10 1850 {
rlm@10 1851 Var.pushThreadBindings(dynamicBindings);
rlm@10 1852 LocalBinding lb = registerLocal(sym,
rlm@10 1853 (Symbol) (RT.second(f) instanceof Symbol ? RT.second(f)
rlm@10 1854 : null),
rlm@10 1855 null,false);
rlm@10 1856 Expr handler = (new BodyExpr.Parser()).parse(context, RT.next(RT.next(RT.next(f))));
rlm@10 1857 catches = catches.cons(new CatchClause(c, lb, handler));
rlm@10 1858 }
rlm@10 1859 finally
rlm@10 1860 {
rlm@10 1861 Var.popThreadBindings();
rlm@10 1862 }
rlm@10 1863 caught = true;
rlm@10 1864 }
rlm@10 1865 else //finally
rlm@10 1866 {
rlm@10 1867 if(fs.next() != null)
rlm@10 1868 throw new Exception("finally clause must be last in try expression");
rlm@10 1869 try
rlm@10 1870 {
rlm@10 1871 Var.pushThreadBindings(RT.map(IN_CATCH_FINALLY, RT.T));
rlm@10 1872 finallyExpr = (new BodyExpr.Parser()).parse(C.STATEMENT, RT.next(f));
rlm@10 1873 }
rlm@10 1874 finally
rlm@10 1875 {
rlm@10 1876 Var.popThreadBindings();
rlm@10 1877 }
rlm@10 1878 }
rlm@10 1879 }
rlm@10 1880 }
rlm@10 1881 if(bodyExpr == null)
rlm@10 1882 bodyExpr = (new BodyExpr.Parser()).parse(context, RT.seq(body));
rlm@10 1883
rlm@10 1884 return new TryExpr(bodyExpr, catches, finallyExpr, retLocal,
rlm@10 1885 finallyLocal);
rlm@10 1886 }
rlm@10 1887 }
rlm@10 1888 }
rlm@10 1889
rlm@10 1890 //static class TryFinallyExpr implements Expr{
rlm@10 1891 // final Expr tryExpr;
rlm@10 1892 // final Expr finallyExpr;
rlm@10 1893 //
rlm@10 1894 //
rlm@10 1895 // public TryFinallyExpr(Expr tryExpr, Expr finallyExpr){
rlm@10 1896 // this.tryExpr = tryExpr;
rlm@10 1897 // this.finallyExpr = finallyExpr;
rlm@10 1898 // }
rlm@10 1899 //
rlm@10 1900 // public Object eval() throws Exception{
rlm@10 1901 // throw new UnsupportedOperationException("Can't eval try");
rlm@10 1902 // }
rlm@10 1903 //
rlm@10 1904 // public void emit(C context, FnExpr fn, GeneratorAdapter gen){
rlm@10 1905 // Label startTry = gen.newLabel();
rlm@10 1906 // Label endTry = gen.newLabel();
rlm@10 1907 // Label end = gen.newLabel();
rlm@10 1908 // Label finallyLabel = gen.newLabel();
rlm@10 1909 // gen.visitTryCatchBlock(startTry, endTry, finallyLabel, null);
rlm@10 1910 // gen.mark(startTry);
rlm@10 1911 // tryExpr.emit(context, fn, gen);
rlm@10 1912 // gen.mark(endTry);
rlm@10 1913 // finallyExpr.emit(C.STATEMENT, fn, gen);
rlm@10 1914 // gen.goTo(end);
rlm@10 1915 // gen.mark(finallyLabel);
rlm@10 1916 // //exception should be on stack
rlm@10 1917 // finallyExpr.emit(C.STATEMENT, fn, gen);
rlm@10 1918 // gen.throwException();
rlm@10 1919 // gen.mark(end);
rlm@10 1920 // }
rlm@10 1921 //
rlm@10 1922 // public boolean hasJavaClass() throws Exception{
rlm@10 1923 // return tryExpr.hasJavaClass();
rlm@10 1924 // }
rlm@10 1925 //
rlm@10 1926 // public Class getJavaClass() throws Exception{
rlm@10 1927 // return tryExpr.getJavaClass();
rlm@10 1928 // }
rlm@10 1929 //
rlm@10 1930 // static class Parser implements IParser{
rlm@10 1931 // public Expr parse(C context, Object frm) throws Exception{
rlm@10 1932 // ISeq form = (ISeq) frm;
rlm@10 1933 // //(try-finally try-expr finally-expr)
rlm@10 1934 // if(form.count() != 3)
rlm@10 1935 // throw new IllegalArgumentException(
rlm@10 1936 // "Wrong number of arguments, expecting: (try-finally try-expr finally-expr) ");
rlm@10 1937 //
rlm@10 1938 // if(context == C.EVAL || context == C.EXPRESSION)
rlm@10 1939 // return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
rlm@10 1940 //
rlm@10 1941 // return new TryFinallyExpr(analyze(context, RT.second(form)),
rlm@10 1942 // analyze(C.STATEMENT, RT.third(form)));
rlm@10 1943 // }
rlm@10 1944 // }
rlm@10 1945 //}
rlm@10 1946
rlm@10 1947 static class ThrowExpr extends UntypedExpr{
rlm@10 1948 public final Expr excExpr;
rlm@10 1949
rlm@10 1950 public ThrowExpr(Expr excExpr){
rlm@10 1951 this.excExpr = excExpr;
rlm@10 1952 }
rlm@10 1953
rlm@10 1954
rlm@10 1955 public Object eval() throws Exception{
rlm@10 1956 throw new Exception("Can't eval throw");
rlm@10 1957 }
rlm@10 1958
rlm@10 1959 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 1960 excExpr.emit(C.EXPRESSION, objx, gen);
rlm@10 1961 gen.checkCast(THROWABLE_TYPE);
rlm@10 1962 gen.throwException();
rlm@10 1963 }
rlm@10 1964
rlm@10 1965 static class Parser implements IParser{
rlm@10 1966 public Expr parse(C context, Object form) throws Exception{
rlm@10 1967 if(context == C.EVAL)
rlm@10 1968 return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
rlm@10 1969 return new ThrowExpr(analyze(C.EXPRESSION, RT.second(form)));
rlm@10 1970 }
rlm@10 1971 }
rlm@10 1972 }
rlm@10 1973
rlm@10 1974
rlm@10 1975 static public boolean subsumes(Class[] c1, Class[] c2){
rlm@10 1976 //presumes matching lengths
rlm@10 1977 Boolean better = false;
rlm@10 1978 for(int i = 0; i < c1.length; i++)
rlm@10 1979 {
rlm@10 1980 if(c1[i] != c2[i])// || c2[i].isPrimitive() && c1[i] == Object.class))
rlm@10 1981 {
rlm@10 1982 if(!c1[i].isPrimitive() && c2[i].isPrimitive()
rlm@10 1983 //|| Number.class.isAssignableFrom(c1[i]) && c2[i].isPrimitive()
rlm@10 1984 ||
rlm@10 1985 c2[i].isAssignableFrom(c1[i]))
rlm@10 1986 better = true;
rlm@10 1987 else
rlm@10 1988 return false;
rlm@10 1989 }
rlm@10 1990 }
rlm@10 1991 return better;
rlm@10 1992 }
rlm@10 1993
rlm@10 1994 static int getMatchingParams(String methodName, ArrayList<Class[]> paramlists, IPersistentVector argexprs,
rlm@10 1995 List<Class> rets)
rlm@10 1996 throws Exception{
rlm@10 1997 //presumes matching lengths
rlm@10 1998 int matchIdx = -1;
rlm@10 1999 boolean tied = false;
rlm@10 2000 boolean foundExact = false;
rlm@10 2001 for(int i = 0; i < paramlists.size(); i++)
rlm@10 2002 {
rlm@10 2003 boolean match = true;
rlm@10 2004 ISeq aseq = argexprs.seq();
rlm@10 2005 int exact = 0;
rlm@10 2006 for(int p = 0; match && p < argexprs.count() && aseq != null; ++p, aseq = aseq.next())
rlm@10 2007 {
rlm@10 2008 Expr arg = (Expr) aseq.first();
rlm@10 2009 Class aclass = arg.hasJavaClass() ? arg.getJavaClass() : Object.class;
rlm@10 2010 Class pclass = paramlists.get(i)[p];
rlm@10 2011 if(arg.hasJavaClass() && aclass == pclass)
rlm@10 2012 exact++;
rlm@10 2013 else
rlm@10 2014 match = Reflector.paramArgTypeMatch(pclass, aclass);
rlm@10 2015 }
rlm@10 2016 if(exact == argexprs.count())
rlm@10 2017 {
rlm@10 2018 if(!foundExact || matchIdx == -1 || rets.get(matchIdx).isAssignableFrom(rets.get(i)))
rlm@10 2019 matchIdx = i;
rlm@10 2020 foundExact = true;
rlm@10 2021 }
rlm@10 2022 else if(match && !foundExact)
rlm@10 2023 {
rlm@10 2024 if(matchIdx == -1)
rlm@10 2025 matchIdx = i;
rlm@10 2026 else
rlm@10 2027 {
rlm@10 2028 if(subsumes(paramlists.get(i), paramlists.get(matchIdx)))
rlm@10 2029 {
rlm@10 2030 matchIdx = i;
rlm@10 2031 tied = false;
rlm@10 2032 }
rlm@10 2033 else if(Arrays.equals(paramlists.get(matchIdx), paramlists.get(i)))
rlm@10 2034 {
rlm@10 2035 if(rets.get(matchIdx).isAssignableFrom(rets.get(i)))
rlm@10 2036 matchIdx = i;
rlm@10 2037 }
rlm@10 2038 else if(!(subsumes(paramlists.get(matchIdx), paramlists.get(i))))
rlm@10 2039 tied = true;
rlm@10 2040 }
rlm@10 2041 }
rlm@10 2042 }
rlm@10 2043 if(tied)
rlm@10 2044 throw new IllegalArgumentException("More than one matching method found: " + methodName);
rlm@10 2045
rlm@10 2046 return matchIdx;
rlm@10 2047 }
rlm@10 2048
rlm@10 2049 public static class NewExpr implements Expr{
rlm@10 2050 public final IPersistentVector args;
rlm@10 2051 public final Constructor ctor;
rlm@10 2052 public final Class c;
rlm@10 2053 final static Method invokeConstructorMethod =
rlm@10 2054 Method.getMethod("Object invokeConstructor(Class,Object[])");
rlm@10 2055 // final static Method forNameMethod = Method.getMethod("Class classForName(String)");
rlm@10 2056 final static Method forNameMethod = Method.getMethod("Class forName(String)");
rlm@10 2057
rlm@10 2058
rlm@10 2059 public NewExpr(Class c, IPersistentVector args, int line) throws Exception{
rlm@10 2060 this.args = args;
rlm@10 2061 this.c = c;
rlm@10 2062 Constructor[] allctors = c.getConstructors();
rlm@10 2063 ArrayList ctors = new ArrayList();
rlm@10 2064 ArrayList<Class[]> params = new ArrayList();
rlm@10 2065 ArrayList<Class> rets = new ArrayList();
rlm@10 2066 for(int i = 0; i < allctors.length; i++)
rlm@10 2067 {
rlm@10 2068 Constructor ctor = allctors[i];
rlm@10 2069 if(ctor.getParameterTypes().length == args.count())
rlm@10 2070 {
rlm@10 2071 ctors.add(ctor);
rlm@10 2072 params.add(ctor.getParameterTypes());
rlm@10 2073 rets.add(c);
rlm@10 2074 }
rlm@10 2075 }
rlm@10 2076 if(ctors.isEmpty())
rlm@10 2077 throw new IllegalArgumentException("No matching ctor found for " + c);
rlm@10 2078
rlm@10 2079 int ctoridx = 0;
rlm@10 2080 if(ctors.size() > 1)
rlm@10 2081 {
rlm@10 2082 ctoridx = getMatchingParams(c.getName(), params, args, rets);
rlm@10 2083 }
rlm@10 2084
rlm@10 2085 this.ctor = ctoridx >= 0 ? (Constructor) ctors.get(ctoridx) : null;
rlm@10 2086 if(ctor == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))
rlm@10 2087 {
rlm@10 2088 RT.errPrintWriter()
rlm@10 2089 .format("Reflection warning, %s:%d - call to %s ctor can't be resolved.\n",
rlm@10 2090 SOURCE_PATH.deref(), line, c.getName());
rlm@10 2091 }
rlm@10 2092 }
rlm@10 2093
rlm@10 2094 public Object eval() throws Exception{
rlm@10 2095 Object[] argvals = new Object[args.count()];
rlm@10 2096 for(int i = 0; i < args.count(); i++)
rlm@10 2097 argvals[i] = ((Expr) args.nth(i)).eval();
rlm@10 2098 if(this.ctor != null)
rlm@10 2099 {
rlm@10 2100 return ctor.newInstance(Reflector.boxArgs(ctor.getParameterTypes(), argvals));
rlm@10 2101 }
rlm@10 2102 return Reflector.invokeConstructor(c, argvals);
rlm@10 2103 }
rlm@10 2104
rlm@10 2105 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2106 if(this.ctor != null)
rlm@10 2107 {
rlm@10 2108 Type type = getType(c);
rlm@10 2109 gen.newInstance(type);
rlm@10 2110 gen.dup();
rlm@10 2111 MethodExpr.emitTypedArgs(objx, gen, ctor.getParameterTypes(), args);
rlm@10 2112 if(context == C.RETURN)
rlm@10 2113 {
rlm@10 2114 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 2115 method.emitClearLocals(gen);
rlm@10 2116 }
rlm@10 2117 gen.invokeConstructor(type, new Method("<init>", Type.getConstructorDescriptor(ctor)));
rlm@10 2118 }
rlm@10 2119 else
rlm@10 2120 {
rlm@10 2121 gen.push(destubClassName(c.getName()));
rlm@10 2122 gen.invokeStatic(CLASS_TYPE, forNameMethod);
rlm@10 2123 MethodExpr.emitArgsAsArray(args, objx, gen);
rlm@10 2124 if(context == C.RETURN)
rlm@10 2125 {
rlm@10 2126 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 2127 method.emitClearLocals(gen);
rlm@10 2128 }
rlm@10 2129 gen.invokeStatic(REFLECTOR_TYPE, invokeConstructorMethod);
rlm@10 2130 }
rlm@10 2131 if(context == C.STATEMENT)
rlm@10 2132 gen.pop();
rlm@10 2133 }
rlm@10 2134
rlm@10 2135 public boolean hasJavaClass(){
rlm@10 2136 return true;
rlm@10 2137 }
rlm@10 2138
rlm@10 2139 public Class getJavaClass() throws Exception{
rlm@10 2140 return c;
rlm@10 2141 }
rlm@10 2142
rlm@10 2143 static class Parser implements IParser{
rlm@10 2144 public Expr parse(C context, Object frm) throws Exception{
rlm@10 2145 int line = (Integer) LINE.deref();
rlm@10 2146 ISeq form = (ISeq) frm;
rlm@10 2147 //(new Classname args...)
rlm@10 2148 if(form.count() < 2)
rlm@10 2149 throw new Exception("wrong number of arguments, expecting: (new Classname args...)");
rlm@10 2150 Class c = HostExpr.maybeClass(RT.second(form), false);
rlm@10 2151 if(c == null)
rlm@10 2152 throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(form));
rlm@10 2153 PersistentVector args = PersistentVector.EMPTY;
rlm@10 2154 for(ISeq s = RT.next(RT.next(form)); s != null; s = s.next())
rlm@10 2155 args = args.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, s.first()));
rlm@10 2156 return new NewExpr(c, args, line);
rlm@10 2157 }
rlm@10 2158 }
rlm@10 2159
rlm@10 2160 }
rlm@10 2161
rlm@10 2162 public static class MetaExpr implements Expr{
rlm@10 2163 public final Expr expr;
rlm@10 2164 public final MapExpr meta;
rlm@10 2165 final static Type IOBJ_TYPE = Type.getType(IObj.class);
rlm@10 2166 final static Method withMetaMethod = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)");
rlm@10 2167
rlm@10 2168
rlm@10 2169 public MetaExpr(Expr expr, MapExpr meta){
rlm@10 2170 this.expr = expr;
rlm@10 2171 this.meta = meta;
rlm@10 2172 }
rlm@10 2173
rlm@10 2174 public Object eval() throws Exception{
rlm@10 2175 return ((IObj) expr.eval()).withMeta((IPersistentMap) meta.eval());
rlm@10 2176 }
rlm@10 2177
rlm@10 2178 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2179 expr.emit(C.EXPRESSION, objx, gen);
rlm@10 2180 gen.checkCast(IOBJ_TYPE);
rlm@10 2181 meta.emit(C.EXPRESSION, objx, gen);
rlm@10 2182 gen.checkCast(IPERSISTENTMAP_TYPE);
rlm@10 2183 gen.invokeInterface(IOBJ_TYPE, withMetaMethod);
rlm@10 2184 if(context == C.STATEMENT)
rlm@10 2185 {
rlm@10 2186 gen.pop();
rlm@10 2187 }
rlm@10 2188 }
rlm@10 2189
rlm@10 2190 public boolean hasJavaClass() throws Exception{
rlm@10 2191 return expr.hasJavaClass();
rlm@10 2192 }
rlm@10 2193
rlm@10 2194 public Class getJavaClass() throws Exception{
rlm@10 2195 return expr.getJavaClass();
rlm@10 2196 }
rlm@10 2197 }
rlm@10 2198
rlm@10 2199 public static class IfExpr implements Expr, MaybePrimitiveExpr{
rlm@10 2200 public final Expr testExpr;
rlm@10 2201 public final Expr thenExpr;
rlm@10 2202 public final Expr elseExpr;
rlm@10 2203 public final int line;
rlm@10 2204
rlm@10 2205
rlm@10 2206 public IfExpr(int line, Expr testExpr, Expr thenExpr, Expr elseExpr){
rlm@10 2207 this.testExpr = testExpr;
rlm@10 2208 this.thenExpr = thenExpr;
rlm@10 2209 this.elseExpr = elseExpr;
rlm@10 2210 this.line = line;
rlm@10 2211 }
rlm@10 2212
rlm@10 2213 public Object eval() throws Exception{
rlm@10 2214 Object t = testExpr.eval();
rlm@10 2215 if(t != null && t != Boolean.FALSE)
rlm@10 2216 return thenExpr.eval();
rlm@10 2217 return elseExpr.eval();
rlm@10 2218 }
rlm@10 2219
rlm@10 2220 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2221 doEmit(context, objx, gen,false);
rlm@10 2222 }
rlm@10 2223
rlm@10 2224 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2225 doEmit(context, objx, gen, true);
rlm@10 2226 }
rlm@10 2227
rlm@10 2228 public void doEmit(C context, ObjExpr objx, GeneratorAdapter gen, boolean emitUnboxed){
rlm@10 2229 Label nullLabel = gen.newLabel();
rlm@10 2230 Label falseLabel = gen.newLabel();
rlm@10 2231 Label endLabel = gen.newLabel();
rlm@10 2232
rlm@10 2233 gen.visitLineNumber(line, gen.mark());
rlm@10 2234
rlm@10 2235 try
rlm@10 2236 {
rlm@10 2237 if(maybePrimitiveType(testExpr) == boolean.class)
rlm@10 2238 {
rlm@10 2239 ((MaybePrimitiveExpr) testExpr).emitUnboxed(C.EXPRESSION, objx, gen);
rlm@10 2240 gen.ifZCmp(gen.EQ, falseLabel);
rlm@10 2241 }
rlm@10 2242 else
rlm@10 2243 {
rlm@10 2244 testExpr.emit(C.EXPRESSION, objx, gen);
rlm@10 2245 gen.dup();
rlm@10 2246 gen.ifNull(nullLabel);
rlm@10 2247 gen.getStatic(BOOLEAN_OBJECT_TYPE, "FALSE", BOOLEAN_OBJECT_TYPE);
rlm@10 2248 gen.visitJumpInsn(IF_ACMPEQ, falseLabel);
rlm@10 2249 }
rlm@10 2250 }
rlm@10 2251 catch(Exception e)
rlm@10 2252 {
rlm@10 2253 throw new RuntimeException(e);
rlm@10 2254 }
rlm@10 2255 if(emitUnboxed)
rlm@10 2256 ((MaybePrimitiveExpr)thenExpr).emitUnboxed(context, objx, gen);
rlm@10 2257 else
rlm@10 2258 thenExpr.emit(context, objx, gen);
rlm@10 2259 gen.goTo(endLabel);
rlm@10 2260 gen.mark(nullLabel);
rlm@10 2261 gen.pop();
rlm@10 2262 gen.mark(falseLabel);
rlm@10 2263 if(emitUnboxed)
rlm@10 2264 ((MaybePrimitiveExpr)elseExpr).emitUnboxed(context, objx, gen);
rlm@10 2265 else
rlm@10 2266 elseExpr.emit(context, objx, gen);
rlm@10 2267 gen.mark(endLabel);
rlm@10 2268 }
rlm@10 2269
rlm@10 2270 public boolean hasJavaClass() throws Exception{
rlm@10 2271 return thenExpr.hasJavaClass()
rlm@10 2272 && elseExpr.hasJavaClass()
rlm@10 2273 &&
rlm@10 2274 (thenExpr.getJavaClass() == elseExpr.getJavaClass()
rlm@10 2275 || (thenExpr.getJavaClass() == null && !elseExpr.getJavaClass().isPrimitive())
rlm@10 2276 || (elseExpr.getJavaClass() == null && !thenExpr.getJavaClass().isPrimitive()));
rlm@10 2277 }
rlm@10 2278
rlm@10 2279 public boolean canEmitPrimitive(){
rlm@10 2280 try
rlm@10 2281 {
rlm@10 2282 return thenExpr instanceof MaybePrimitiveExpr
rlm@10 2283 && elseExpr instanceof MaybePrimitiveExpr
rlm@10 2284 && thenExpr.getJavaClass() == elseExpr.getJavaClass()
rlm@10 2285 && ((MaybePrimitiveExpr)thenExpr).canEmitPrimitive()
rlm@10 2286 && ((MaybePrimitiveExpr)elseExpr).canEmitPrimitive();
rlm@10 2287 }
rlm@10 2288 catch(Exception e)
rlm@10 2289 {
rlm@10 2290 return false;
rlm@10 2291 }
rlm@10 2292 }
rlm@10 2293
rlm@10 2294 public Class getJavaClass() throws Exception{
rlm@10 2295 Class thenClass = thenExpr.getJavaClass();
rlm@10 2296 if(thenClass != null)
rlm@10 2297 return thenClass;
rlm@10 2298 return elseExpr.getJavaClass();
rlm@10 2299 }
rlm@10 2300
rlm@10 2301 static class Parser implements IParser{
rlm@10 2302 public Expr parse(C context, Object frm) throws Exception{
rlm@10 2303 ISeq form = (ISeq) frm;
rlm@10 2304 //(if test then) or (if test then else)
rlm@10 2305 if(form.count() > 4)
rlm@10 2306 throw new Exception("Too many arguments to if");
rlm@10 2307 else if(form.count() < 3)
rlm@10 2308 throw new Exception("Too few arguments to if");
rlm@10 2309 PathNode branch = new PathNode(PATHTYPE.BRANCH, (PathNode) CLEAR_PATH.get());
rlm@10 2310 Expr testexpr = analyze(context == C.EVAL ? context : C.EXPRESSION, RT.second(form));
rlm@10 2311 Expr thenexpr, elseexpr;
rlm@10 2312 try {
rlm@10 2313 Var.pushThreadBindings(
rlm@10 2314 RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch)));
rlm@10 2315 thenexpr = analyze(context, RT.third(form));
rlm@10 2316 }
rlm@10 2317 finally{
rlm@10 2318 Var.popThreadBindings();
rlm@10 2319 }
rlm@10 2320 try {
rlm@10 2321 Var.pushThreadBindings(
rlm@10 2322 RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch)));
rlm@10 2323 elseexpr = analyze(context, RT.fourth(form));
rlm@10 2324 }
rlm@10 2325 finally{
rlm@10 2326 Var.popThreadBindings();
rlm@10 2327 }
rlm@10 2328 return new IfExpr((Integer) LINE.deref(),
rlm@10 2329 testexpr,
rlm@10 2330 thenexpr,
rlm@10 2331 elseexpr);
rlm@10 2332 }
rlm@10 2333 }
rlm@10 2334 }
rlm@10 2335
rlm@10 2336 static final public IPersistentMap CHAR_MAP =
rlm@10 2337 PersistentHashMap.create('-', "_",
rlm@10 2338 // '.', "_DOT_",
rlm@10 2339 ':', "_COLON_",
rlm@10 2340 '+', "_PLUS_",
rlm@10 2341 '>', "_GT_",
rlm@10 2342 '<', "_LT_",
rlm@10 2343 '=', "_EQ_",
rlm@10 2344 '~', "_TILDE_",
rlm@10 2345 '!', "_BANG_",
rlm@10 2346 '@', "_CIRCA_",
rlm@10 2347 '#', "_SHARP_",
rlm@10 2348 '$', "_DOLLARSIGN_",
rlm@10 2349 '%', "_PERCENT_",
rlm@10 2350 '^', "_CARET_",
rlm@10 2351 '&', "_AMPERSAND_",
rlm@10 2352 '*', "_STAR_",
rlm@10 2353 '|', "_BAR_",
rlm@10 2354 '{', "_LBRACE_",
rlm@10 2355 '}', "_RBRACE_",
rlm@10 2356 '[', "_LBRACK_",
rlm@10 2357 ']', "_RBRACK_",
rlm@10 2358 '/', "_SLASH_",
rlm@10 2359 '\\', "_BSLASH_",
rlm@10 2360 '?', "_QMARK_");
rlm@10 2361
rlm@10 2362 static public String munge(String name){
rlm@10 2363 StringBuilder sb = new StringBuilder();
rlm@10 2364 for(char c : name.toCharArray())
rlm@10 2365 {
rlm@10 2366 String sub = (String) CHAR_MAP.valAt(c);
rlm@10 2367 if(sub != null)
rlm@10 2368 sb.append(sub);
rlm@10 2369 else
rlm@10 2370 sb.append(c);
rlm@10 2371 }
rlm@10 2372 return sb.toString();
rlm@10 2373 }
rlm@10 2374
rlm@10 2375 public static class EmptyExpr implements Expr{
rlm@10 2376 public final Object coll;
rlm@10 2377 final static Type HASHMAP_TYPE = Type.getType(PersistentArrayMap.class);
rlm@10 2378 final static Type HASHSET_TYPE = Type.getType(PersistentHashSet.class);
rlm@10 2379 final static Type VECTOR_TYPE = Type.getType(PersistentVector.class);
rlm@10 2380 final static Type LIST_TYPE = Type.getType(PersistentList.class);
rlm@10 2381 final static Type EMPTY_LIST_TYPE = Type.getType(PersistentList.EmptyList.class);
rlm@10 2382
rlm@10 2383
rlm@10 2384 public EmptyExpr(Object coll){
rlm@10 2385 this.coll = coll;
rlm@10 2386 }
rlm@10 2387
rlm@10 2388 public Object eval() throws Exception{
rlm@10 2389 return coll;
rlm@10 2390 }
rlm@10 2391
rlm@10 2392 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2393 if(coll instanceof IPersistentList)
rlm@10 2394 gen.getStatic(LIST_TYPE, "EMPTY", EMPTY_LIST_TYPE);
rlm@10 2395 else if(coll instanceof IPersistentVector)
rlm@10 2396 gen.getStatic(VECTOR_TYPE, "EMPTY", VECTOR_TYPE);
rlm@10 2397 else if(coll instanceof IPersistentMap)
rlm@10 2398 gen.getStatic(HASHMAP_TYPE, "EMPTY", HASHMAP_TYPE);
rlm@10 2399 else if(coll instanceof IPersistentSet)
rlm@10 2400 gen.getStatic(HASHSET_TYPE, "EMPTY", HASHSET_TYPE);
rlm@10 2401 else
rlm@10 2402 throw new UnsupportedOperationException("Unknown Collection type");
rlm@10 2403 if(context == C.STATEMENT)
rlm@10 2404 {
rlm@10 2405 gen.pop();
rlm@10 2406 }
rlm@10 2407 }
rlm@10 2408
rlm@10 2409 public boolean hasJavaClass() throws Exception{
rlm@10 2410 return true;
rlm@10 2411 }
rlm@10 2412
rlm@10 2413 public Class getJavaClass() throws Exception{
rlm@10 2414 if(coll instanceof IPersistentList)
rlm@10 2415 return IPersistentList.class;
rlm@10 2416 else if(coll instanceof IPersistentVector)
rlm@10 2417 return IPersistentVector.class;
rlm@10 2418 else if(coll instanceof IPersistentMap)
rlm@10 2419 return IPersistentMap.class;
rlm@10 2420 else if(coll instanceof IPersistentSet)
rlm@10 2421 return IPersistentSet.class;
rlm@10 2422 else
rlm@10 2423 throw new UnsupportedOperationException("Unknown Collection type");
rlm@10 2424 }
rlm@10 2425 }
rlm@10 2426
rlm@10 2427 public static class ListExpr implements Expr{
rlm@10 2428 public final IPersistentVector args;
rlm@10 2429 final static Method arrayToListMethod = Method.getMethod("clojure.lang.ISeq arrayToList(Object[])");
rlm@10 2430
rlm@10 2431
rlm@10 2432 public ListExpr(IPersistentVector args){
rlm@10 2433 this.args = args;
rlm@10 2434 }
rlm@10 2435
rlm@10 2436 public Object eval() throws Exception{
rlm@10 2437 IPersistentVector ret = PersistentVector.EMPTY;
rlm@10 2438 for(int i = 0; i < args.count(); i++)
rlm@10 2439 ret = (IPersistentVector) ret.cons(((Expr) args.nth(i)).eval());
rlm@10 2440 return ret.seq();
rlm@10 2441 }
rlm@10 2442
rlm@10 2443 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2444 MethodExpr.emitArgsAsArray(args, objx, gen);
rlm@10 2445 gen.invokeStatic(RT_TYPE, arrayToListMethod);
rlm@10 2446 if(context == C.STATEMENT)
rlm@10 2447 gen.pop();
rlm@10 2448 }
rlm@10 2449
rlm@10 2450 public boolean hasJavaClass() throws Exception{
rlm@10 2451 return true;
rlm@10 2452 }
rlm@10 2453
rlm@10 2454 public Class getJavaClass() throws Exception{
rlm@10 2455 return IPersistentList.class;
rlm@10 2456 }
rlm@10 2457
rlm@10 2458 }
rlm@10 2459
rlm@10 2460 public static class MapExpr implements Expr{
rlm@10 2461 public final IPersistentVector keyvals;
rlm@10 2462 final static Method mapMethod = Method.getMethod("clojure.lang.IPersistentMap map(Object[])");
rlm@10 2463
rlm@10 2464
rlm@10 2465 public MapExpr(IPersistentVector keyvals){
rlm@10 2466 this.keyvals = keyvals;
rlm@10 2467 }
rlm@10 2468
rlm@10 2469 public Object eval() throws Exception{
rlm@10 2470 Object[] ret = new Object[keyvals.count()];
rlm@10 2471 for(int i = 0; i < keyvals.count(); i++)
rlm@10 2472 ret[i] = ((Expr) keyvals.nth(i)).eval();
rlm@10 2473 return RT.map(ret);
rlm@10 2474 }
rlm@10 2475
rlm@10 2476 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2477 MethodExpr.emitArgsAsArray(keyvals, objx, gen);
rlm@10 2478 gen.invokeStatic(RT_TYPE, mapMethod);
rlm@10 2479 if(context == C.STATEMENT)
rlm@10 2480 gen.pop();
rlm@10 2481 }
rlm@10 2482
rlm@10 2483 public boolean hasJavaClass() throws Exception{
rlm@10 2484 return true;
rlm@10 2485 }
rlm@10 2486
rlm@10 2487 public Class getJavaClass() throws Exception{
rlm@10 2488 return IPersistentMap.class;
rlm@10 2489 }
rlm@10 2490
rlm@10 2491
rlm@10 2492 static public Expr parse(C context, IPersistentMap form) throws Exception{
rlm@10 2493 IPersistentVector keyvals = PersistentVector.EMPTY;
rlm@10 2494 for(ISeq s = RT.seq(form); s != null; s = s.next())
rlm@10 2495 {
rlm@10 2496 IMapEntry e = (IMapEntry) s.first();
rlm@10 2497 keyvals = (IPersistentVector) keyvals.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e.key()));
rlm@10 2498 keyvals = (IPersistentVector) keyvals.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e.val()));
rlm@10 2499 }
rlm@10 2500 Expr ret = new MapExpr(keyvals);
rlm@10 2501 if(form instanceof IObj && ((IObj) form).meta() != null)
rlm@10 2502 return new MetaExpr(ret, (MapExpr) MapExpr
rlm@10 2503 .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
rlm@10 2504 else
rlm@10 2505 return ret;
rlm@10 2506 }
rlm@10 2507 }
rlm@10 2508
rlm@10 2509 public static class SetExpr implements Expr{
rlm@10 2510 public final IPersistentVector keys;
rlm@10 2511 final static Method setMethod = Method.getMethod("clojure.lang.IPersistentSet set(Object[])");
rlm@10 2512
rlm@10 2513
rlm@10 2514 public SetExpr(IPersistentVector keys){
rlm@10 2515 this.keys = keys;
rlm@10 2516 }
rlm@10 2517
rlm@10 2518 public Object eval() throws Exception{
rlm@10 2519 Object[] ret = new Object[keys.count()];
rlm@10 2520 for(int i = 0; i < keys.count(); i++)
rlm@10 2521 ret[i] = ((Expr) keys.nth(i)).eval();
rlm@10 2522 return RT.set(ret);
rlm@10 2523 }
rlm@10 2524
rlm@10 2525 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2526 MethodExpr.emitArgsAsArray(keys, objx, gen);
rlm@10 2527 gen.invokeStatic(RT_TYPE, setMethod);
rlm@10 2528 if(context == C.STATEMENT)
rlm@10 2529 gen.pop();
rlm@10 2530 }
rlm@10 2531
rlm@10 2532 public boolean hasJavaClass() throws Exception{
rlm@10 2533 return true;
rlm@10 2534 }
rlm@10 2535
rlm@10 2536 public Class getJavaClass() throws Exception{
rlm@10 2537 return IPersistentSet.class;
rlm@10 2538 }
rlm@10 2539
rlm@10 2540
rlm@10 2541 static public Expr parse(C context, IPersistentSet form) throws Exception{
rlm@10 2542 IPersistentVector keys = PersistentVector.EMPTY;
rlm@10 2543 for(ISeq s = RT.seq(form); s != null; s = s.next())
rlm@10 2544 {
rlm@10 2545 Object e = s.first();
rlm@10 2546 keys = (IPersistentVector) keys.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, e));
rlm@10 2547 }
rlm@10 2548 Expr ret = new SetExpr(keys);
rlm@10 2549 if(form instanceof IObj && ((IObj) form).meta() != null)
rlm@10 2550 return new MetaExpr(ret, (MapExpr) MapExpr
rlm@10 2551 .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
rlm@10 2552 else
rlm@10 2553 return ret;
rlm@10 2554 }
rlm@10 2555 }
rlm@10 2556
rlm@10 2557 public static class VectorExpr implements Expr{
rlm@10 2558 public final IPersistentVector args;
rlm@10 2559 final static Method vectorMethod = Method.getMethod("clojure.lang.IPersistentVector vector(Object[])");
rlm@10 2560
rlm@10 2561
rlm@10 2562 public VectorExpr(IPersistentVector args){
rlm@10 2563 this.args = args;
rlm@10 2564 }
rlm@10 2565
rlm@10 2566 public Object eval() throws Exception{
rlm@10 2567 IPersistentVector ret = PersistentVector.EMPTY;
rlm@10 2568 for(int i = 0; i < args.count(); i++)
rlm@10 2569 ret = (IPersistentVector) ret.cons(((Expr) args.nth(i)).eval());
rlm@10 2570 return ret;
rlm@10 2571 }
rlm@10 2572
rlm@10 2573 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2574 MethodExpr.emitArgsAsArray(args, objx, gen);
rlm@10 2575 gen.invokeStatic(RT_TYPE, vectorMethod);
rlm@10 2576 if(context == C.STATEMENT)
rlm@10 2577 gen.pop();
rlm@10 2578 }
rlm@10 2579
rlm@10 2580 public boolean hasJavaClass() throws Exception{
rlm@10 2581 return true;
rlm@10 2582 }
rlm@10 2583
rlm@10 2584 public Class getJavaClass() throws Exception{
rlm@10 2585 return IPersistentVector.class;
rlm@10 2586 }
rlm@10 2587
rlm@10 2588 static public Expr parse(C context, IPersistentVector form) throws Exception{
rlm@10 2589 IPersistentVector args = PersistentVector.EMPTY;
rlm@10 2590 for(int i = 0; i < form.count(); i++)
rlm@10 2591 args = (IPersistentVector) args.cons(analyze(context == C.EVAL ? context : C.EXPRESSION, form.nth(i)));
rlm@10 2592 Expr ret = new VectorExpr(args);
rlm@10 2593 if(form instanceof IObj && ((IObj) form).meta() != null)
rlm@10 2594 return new MetaExpr(ret, (MapExpr) MapExpr
rlm@10 2595 .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
rlm@10 2596 else
rlm@10 2597 return ret;
rlm@10 2598 }
rlm@10 2599
rlm@10 2600 }
rlm@10 2601
rlm@10 2602 static class KeywordInvokeExpr implements Expr{
rlm@10 2603 public final KeywordExpr kw;
rlm@10 2604 public final Object tag;
rlm@10 2605 public final Expr target;
rlm@10 2606 public final int line;
rlm@10 2607 public final int siteIndex;
rlm@10 2608 public final String source;
rlm@10 2609 static Type ILOOKUP_TYPE = Type.getType(ILookup.class);
rlm@10 2610
rlm@10 2611 public KeywordInvokeExpr(String source, int line, Symbol tag, KeywordExpr kw, Expr target){
rlm@10 2612 this.source = source;
rlm@10 2613 this.kw = kw;
rlm@10 2614 this.target = target;
rlm@10 2615 this.line = line;
rlm@10 2616 this.tag = tag;
rlm@10 2617 this.siteIndex = registerKeywordCallsite(kw.k);
rlm@10 2618 }
rlm@10 2619
rlm@10 2620 public Object eval() throws Exception{
rlm@10 2621 try
rlm@10 2622 {
rlm@10 2623 return kw.k.invoke(target.eval());
rlm@10 2624 }
rlm@10 2625 catch(Throwable e)
rlm@10 2626 {
rlm@10 2627 if(!(e instanceof CompilerException))
rlm@10 2628 throw new CompilerException(source, line, e);
rlm@10 2629 else
rlm@10 2630 throw (CompilerException) e;
rlm@10 2631 }
rlm@10 2632 }
rlm@10 2633
rlm@10 2634 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2635 Label endLabel = gen.newLabel();
rlm@10 2636 Label faultLabel = gen.newLabel();
rlm@10 2637
rlm@10 2638 gen.visitLineNumber(line, gen.mark());
rlm@10 2639 gen.getStatic(objx.objtype, objx.thunkNameStatic(siteIndex),ObjExpr.ILOOKUP_THUNK_TYPE);
rlm@10 2640 gen.dup();
rlm@10 2641 target.emit(C.EXPRESSION, objx, gen);
rlm@10 2642 gen.dupX2();
rlm@10 2643 gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE, Method.getMethod("Object get(Object)"));
rlm@10 2644 gen.dupX2();
rlm@10 2645 gen.visitJumpInsn(IF_ACMPEQ, faultLabel);
rlm@10 2646 gen.pop();
rlm@10 2647 gen.goTo(endLabel);
rlm@10 2648
rlm@10 2649 gen.mark(faultLabel);
rlm@10 2650 gen.swap();
rlm@10 2651 gen.pop();
rlm@10 2652 gen.getStatic(objx.objtype, objx.siteNameStatic(siteIndex),ObjExpr.KEYWORD_LOOKUPSITE_TYPE);
rlm@10 2653 gen.swap();
rlm@10 2654 gen.loadThis();
rlm@10 2655 gen.invokeInterface(ObjExpr.ILOOKUP_SITE_TYPE,
rlm@10 2656 Method.getMethod("Object fault(Object, clojure.lang.ILookupHost)"));
rlm@10 2657
rlm@10 2658 gen.mark(endLabel);
rlm@10 2659 if(context == C.STATEMENT)
rlm@10 2660 gen.pop();
rlm@10 2661 }
rlm@10 2662
rlm@10 2663 public void emit2(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2664 Label endLabel = gen.newLabel();
rlm@10 2665 Label faultLabel = gen.newLabel();
rlm@10 2666
rlm@10 2667 gen.visitLineNumber(line, gen.mark());
rlm@10 2668 target.emit(C.EXPRESSION, objx, gen);
rlm@10 2669 gen.dup();
rlm@10 2670 gen.getStatic(objx.objtype, objx.thunkNameStatic(siteIndex),ObjExpr.ILOOKUP_THUNK_TYPE);
rlm@10 2671 gen.swap();
rlm@10 2672 gen.getStatic(objx.objtype, objx.siteNameStatic(siteIndex),ObjExpr.KEYWORD_LOOKUPSITE_TYPE);
rlm@10 2673 /// gen.loadThis();
rlm@10 2674 gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE,
rlm@10 2675 Method.getMethod("Object get(Object,clojure.lang.ILookupSite)"));
rlm@10 2676 // gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE,
rlm@10 2677 // Method.getMethod("Object get(Object,clojure.lang.ILookupSite,clojure.lang.ILookupHost)"));
rlm@10 2678 gen.dup();
rlm@10 2679 gen.getStatic(objx.objtype, objx.siteNameStatic(siteIndex),ObjExpr.KEYWORD_LOOKUPSITE_TYPE);
rlm@10 2680 gen.visitJumpInsn(IF_ACMPEQ, faultLabel);
rlm@10 2681 gen.swap();
rlm@10 2682 gen.pop();
rlm@10 2683 gen.goTo(endLabel);
rlm@10 2684
rlm@10 2685 gen.mark(faultLabel);
rlm@10 2686 gen.swap();
rlm@10 2687 gen.loadThis();
rlm@10 2688 gen.invokeInterface(ObjExpr.ILOOKUP_SITE_TYPE,
rlm@10 2689 Method.getMethod("Object fault(Object, clojure.lang.ILookupHost)"));
rlm@10 2690
rlm@10 2691 gen.mark(endLabel);
rlm@10 2692 if(context == C.STATEMENT)
rlm@10 2693 gen.pop();
rlm@10 2694 }
rlm@10 2695
rlm@10 2696 public void emitInstance(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2697 gen.visitLineNumber(line, gen.mark());
rlm@10 2698 gen.loadThis();
rlm@10 2699 gen.getField(objx.objtype, objx.thunkName(siteIndex),ObjExpr.ILOOKUP_THUNK_TYPE);
rlm@10 2700 target.emit(C.EXPRESSION, objx, gen);
rlm@10 2701 gen.loadThis();
rlm@10 2702 gen.getField(objx.objtype, objx.siteName(siteIndex),ObjExpr.ILOOKUP_SITE_TYPE);
rlm@10 2703 gen.loadThis();
rlm@10 2704 gen.checkCast(Type.getType(ILookupHost.class));
rlm@10 2705 gen.invokeInterface(ObjExpr.ILOOKUP_THUNK_TYPE,
rlm@10 2706 Method.getMethod("Object get(Object,clojure.lang.ILookupSite,clojure.lang.ILookupHost)"));
rlm@10 2707 if(context == C.STATEMENT)
rlm@10 2708 gen.pop();
rlm@10 2709 }
rlm@10 2710
rlm@10 2711 public void emitNormal(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2712 Label slowLabel = gen.newLabel();
rlm@10 2713 Label endLabel = gen.newLabel();
rlm@10 2714
rlm@10 2715 gen.visitLineNumber(line, gen.mark());
rlm@10 2716 target.emit(C.EXPRESSION, objx, gen);
rlm@10 2717 gen.dup();
rlm@10 2718 gen.instanceOf(ILOOKUP_TYPE);
rlm@10 2719 gen.ifZCmp(GeneratorAdapter.EQ, slowLabel);
rlm@10 2720 kw.emit(C.EXPRESSION, objx, gen);
rlm@10 2721 gen.invokeInterface(ILOOKUP_TYPE, new Method("valAt", OBJECT_TYPE, ARG_TYPES[1]));
rlm@10 2722 gen.goTo(endLabel);
rlm@10 2723
rlm@10 2724 gen.mark(slowLabel);
rlm@10 2725 kw.emit(C.EXPRESSION, objx, gen);
rlm@10 2726 gen.invokeStatic(RT_TYPE, new Method("get", OBJECT_TYPE, ARG_TYPES[2]));
rlm@10 2727
rlm@10 2728 gen.mark(endLabel);
rlm@10 2729
rlm@10 2730 if(context == C.STATEMENT)
rlm@10 2731 gen.pop();
rlm@10 2732 }
rlm@10 2733
rlm@10 2734 public boolean hasJavaClass() throws Exception{
rlm@10 2735 return tag != null;
rlm@10 2736 }
rlm@10 2737
rlm@10 2738 public Class getJavaClass() throws Exception{
rlm@10 2739 return HostExpr.tagToClass(tag);
rlm@10 2740 }
rlm@10 2741
rlm@10 2742 }
rlm@10 2743 //static class KeywordSiteInvokeExpr implements Expr{
rlm@10 2744 // public final Expr site;
rlm@10 2745 // public final Object tag;
rlm@10 2746 // public final Expr target;
rlm@10 2747 // public final int line;
rlm@10 2748 // public final String source;
rlm@10 2749 //
rlm@10 2750 // public KeywordSiteInvokeExpr(String source, int line, Symbol tag, Expr site, Expr target){
rlm@10 2751 // this.source = source;
rlm@10 2752 // this.site = site;
rlm@10 2753 // this.target = target;
rlm@10 2754 // this.line = line;
rlm@10 2755 // this.tag = tag;
rlm@10 2756 // }
rlm@10 2757 //
rlm@10 2758 // public Object eval() throws Exception{
rlm@10 2759 // try
rlm@10 2760 // {
rlm@10 2761 // KeywordCallSite s = (KeywordCallSite) site.eval();
rlm@10 2762 // return s.thunk.invoke(s,target.eval());
rlm@10 2763 // }
rlm@10 2764 // catch(Throwable e)
rlm@10 2765 // {
rlm@10 2766 // if(!(e instanceof CompilerException))
rlm@10 2767 // throw new CompilerException(source, line, e);
rlm@10 2768 // else
rlm@10 2769 // throw (CompilerException) e;
rlm@10 2770 // }
rlm@10 2771 // }
rlm@10 2772 //
rlm@10 2773 // public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2774 // gen.visitLineNumber(line, gen.mark());
rlm@10 2775 // site.emit(C.EXPRESSION, objx, gen);
rlm@10 2776 // gen.dup();
rlm@10 2777 // gen.getField(Type.getType(KeywordCallSite.class),"thunk",IFN_TYPE);
rlm@10 2778 // gen.swap();
rlm@10 2779 // target.emit(C.EXPRESSION, objx, gen);
rlm@10 2780 //
rlm@10 2781 // gen.invokeInterface(IFN_TYPE, new Method("invoke", OBJECT_TYPE, ARG_TYPES[2]));
rlm@10 2782 // if(context == C.STATEMENT)
rlm@10 2783 // gen.pop();
rlm@10 2784 // }
rlm@10 2785 //
rlm@10 2786 // public boolean hasJavaClass() throws Exception{
rlm@10 2787 // return tag != null;
rlm@10 2788 // }
rlm@10 2789 //
rlm@10 2790 // public Class getJavaClass() throws Exception{
rlm@10 2791 // return HostExpr.tagToClass(tag);
rlm@10 2792 // }
rlm@10 2793 //
rlm@10 2794 //}
rlm@10 2795
rlm@10 2796 public static class InstanceOfExpr implements Expr, MaybePrimitiveExpr{
rlm@10 2797 Expr expr;
rlm@10 2798 Class c;
rlm@10 2799
rlm@10 2800 public InstanceOfExpr(Class c, Expr expr){
rlm@10 2801 this.expr = expr;
rlm@10 2802 this.c = c;
rlm@10 2803 }
rlm@10 2804
rlm@10 2805 public Object eval() throws Exception{
rlm@10 2806 if(c.isInstance(expr.eval()))
rlm@10 2807 return RT.T;
rlm@10 2808 return RT.F;
rlm@10 2809 }
rlm@10 2810
rlm@10 2811 public boolean canEmitPrimitive(){
rlm@10 2812 return true;
rlm@10 2813 }
rlm@10 2814
rlm@10 2815 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2816 expr.emit(C.EXPRESSION,objx,gen);
rlm@10 2817 gen.instanceOf(Type.getType(c));
rlm@10 2818 }
rlm@10 2819
rlm@10 2820 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2821 emitUnboxed(context,objx,gen);
rlm@10 2822 HostExpr.emitBoxReturn(objx,gen,Boolean.TYPE);
rlm@10 2823 if(context == C.STATEMENT)
rlm@10 2824 gen.pop();
rlm@10 2825 }
rlm@10 2826
rlm@10 2827 public boolean hasJavaClass() throws Exception{
rlm@10 2828 return true;
rlm@10 2829 }
rlm@10 2830
rlm@10 2831 public Class getJavaClass() throws Exception{
rlm@10 2832 return Boolean.TYPE;
rlm@10 2833 }
rlm@10 2834
rlm@10 2835 }
rlm@10 2836
rlm@10 2837 static class InvokeExpr implements Expr{
rlm@10 2838 public final Expr fexpr;
rlm@10 2839 public final Object tag;
rlm@10 2840 public final IPersistentVector args;
rlm@10 2841 public final int line;
rlm@10 2842 public final String source;
rlm@10 2843 public boolean isProtocol = false;
rlm@10 2844 public boolean isDirect = false;
rlm@10 2845 public int siteIndex = -1;
rlm@10 2846 public Class protocolOn;
rlm@10 2847 public java.lang.reflect.Method onMethod;
rlm@10 2848 static Keyword onKey = Keyword.intern("on");
rlm@10 2849 static Keyword methodMapKey = Keyword.intern("method-map");
rlm@10 2850 static Keyword dynamicKey = Keyword.intern("dynamic");
rlm@10 2851
rlm@10 2852 public InvokeExpr(String source, int line, Symbol tag, Expr fexpr, IPersistentVector args) throws Exception{
rlm@10 2853 this.source = source;
rlm@10 2854 this.fexpr = fexpr;
rlm@10 2855 this.args = args;
rlm@10 2856 this.line = line;
rlm@10 2857 if(fexpr instanceof VarExpr)
rlm@10 2858 {
rlm@10 2859 Var fvar = ((VarExpr)fexpr).var;
rlm@10 2860 Var pvar = (Var)RT.get(fvar.meta(), protocolKey);
rlm@10 2861 if(pvar != null && PROTOCOL_CALLSITES.isBound())
rlm@10 2862 {
rlm@10 2863 this.isProtocol = true;
rlm@10 2864 this.siteIndex = registerProtocolCallsite(((VarExpr)fexpr).var);
rlm@10 2865 Object pon = RT.get(pvar.get(), onKey);
rlm@10 2866 this.protocolOn = HostExpr.maybeClass(pon,false);
rlm@10 2867 if(this.protocolOn != null)
rlm@10 2868 {
rlm@10 2869 IPersistentMap mmap = (IPersistentMap) RT.get(pvar.get(), methodMapKey);
rlm@10 2870 Keyword mmapVal = (Keyword) mmap.valAt(Keyword.intern(fvar.sym));
rlm@10 2871 if (mmapVal == null) {
rlm@10 2872 throw new IllegalArgumentException(
rlm@10 2873 "No method of interface: " + protocolOn.getName() +
rlm@10 2874 " found for function: " + fvar.sym + " of protocol: " + pvar.sym +
rlm@10 2875 " (The protocol method may have been defined before and removed.)");
rlm@10 2876 }
rlm@10 2877 String mname = munge(mmapVal.sym.toString());
rlm@10 2878 List methods = Reflector.getMethods(protocolOn, args.count() - 1, mname, false);
rlm@10 2879 if(methods.size() != 1)
rlm@10 2880 throw new IllegalArgumentException(
rlm@10 2881 "No single method: " + mname + " of interface: " + protocolOn.getName() +
rlm@10 2882 " found for function: " + fvar.sym + " of protocol: " + pvar.sym);
rlm@10 2883 this.onMethod = (java.lang.reflect.Method) methods.get(0);
rlm@10 2884 }
rlm@10 2885 }
rlm@10 2886 // else if(pvar == null && VAR_CALLSITES.isBound()
rlm@10 2887 // && fvar.ns.name.name.startsWith("clojure")
rlm@10 2888 // && !RT.booleanCast(RT.get(RT.meta(fvar),dynamicKey))
rlm@10 2889 // )
rlm@10 2890 // {
rlm@10 2891 // //todo - more specific criteria for binding these
rlm@10 2892 // this.isDirect = true;
rlm@10 2893 // this.siteIndex = registerVarCallsite(((VarExpr) fexpr).var);
rlm@10 2894 // }
rlm@10 2895 }
rlm@10 2896 this.tag = tag != null ? tag : (fexpr instanceof VarExpr ? ((VarExpr) fexpr).tag : null);
rlm@10 2897 }
rlm@10 2898
rlm@10 2899 public Object eval() throws Exception{
rlm@10 2900 try
rlm@10 2901 {
rlm@10 2902 IFn fn = (IFn) fexpr.eval();
rlm@10 2903 PersistentVector argvs = PersistentVector.EMPTY;
rlm@10 2904 for(int i = 0; i < args.count(); i++)
rlm@10 2905 argvs = argvs.cons(((Expr) args.nth(i)).eval());
rlm@10 2906 return fn.applyTo(RT.seq(argvs));
rlm@10 2907 }
rlm@10 2908 catch(Throwable e)
rlm@10 2909 {
rlm@10 2910 if(!(e instanceof CompilerException))
rlm@10 2911 throw new CompilerException(source, line, e);
rlm@10 2912 else
rlm@10 2913 throw (CompilerException) e;
rlm@10 2914 }
rlm@10 2915 }
rlm@10 2916
rlm@10 2917 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2918 gen.visitLineNumber(line, gen.mark());
rlm@10 2919 if(isProtocol)
rlm@10 2920 {
rlm@10 2921 emitProto(context,objx,gen);
rlm@10 2922 }
rlm@10 2923 else if(isDirect)
rlm@10 2924 {
rlm@10 2925 Label callLabel = gen.newLabel();
rlm@10 2926
rlm@10 2927 gen.getStatic(objx.objtype, objx.varCallsiteName(siteIndex), IFN_TYPE);
rlm@10 2928 gen.dup();
rlm@10 2929 gen.ifNonNull(callLabel);
rlm@10 2930
rlm@10 2931 gen.pop();
rlm@10 2932 fexpr.emit(C.EXPRESSION, objx, gen);
rlm@10 2933 gen.checkCast(IFN_TYPE);
rlm@10 2934 // gen.dup();
rlm@10 2935 // gen.putStatic(objx.objtype, objx.varCallsiteName(siteIndex), IFN_TYPE);
rlm@10 2936
rlm@10 2937 gen.mark(callLabel);
rlm@10 2938 emitArgsAndCall(0, context,objx,gen);
rlm@10 2939 }
rlm@10 2940 else
rlm@10 2941 {
rlm@10 2942 fexpr.emit(C.EXPRESSION, objx, gen);
rlm@10 2943 gen.checkCast(IFN_TYPE);
rlm@10 2944 emitArgsAndCall(0, context,objx,gen);
rlm@10 2945 }
rlm@10 2946 if(context == C.STATEMENT)
rlm@10 2947 gen.pop();
rlm@10 2948 }
rlm@10 2949
rlm@10 2950 public void emitProto(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 2951 Label onLabel = gen.newLabel();
rlm@10 2952 Label callLabel = gen.newLabel();
rlm@10 2953 Label endLabel = gen.newLabel();
rlm@10 2954
rlm@10 2955 Var v = ((VarExpr)fexpr).var;
rlm@10 2956
rlm@10 2957 Expr e = (Expr) args.nth(0);
rlm@10 2958 e.emit(C.EXPRESSION, objx, gen);
rlm@10 2959 gen.dup(); //target, target
rlm@10 2960 gen.invokeStatic(UTIL_TYPE,Method.getMethod("Class classOf(Object)")); //target,class
rlm@10 2961 gen.loadThis();
rlm@10 2962 gen.getField(objx.objtype, objx.cachedClassName(siteIndex),CLASS_TYPE); //target,class,cached-class
rlm@10 2963 gen.visitJumpInsn(IF_ACMPEQ, callLabel); //target
rlm@10 2964 if(protocolOn != null)
rlm@10 2965 {
rlm@10 2966 gen.dup(); //target, target
rlm@10 2967 gen.instanceOf(Type.getType(protocolOn));
rlm@10 2968 gen.ifZCmp(GeneratorAdapter.NE, onLabel);
rlm@10 2969 }
rlm@10 2970
rlm@10 2971 gen.mark(callLabel); //target
rlm@10 2972 gen.dup(); //target, target
rlm@10 2973 gen.invokeStatic(UTIL_TYPE,Method.getMethod("Class classOf(Object)")); //target,class
rlm@10 2974 gen.loadThis();
rlm@10 2975 gen.swap();
rlm@10 2976 gen.putField(objx.objtype, objx.cachedClassName(siteIndex),CLASS_TYPE); //target
rlm@10 2977 objx.emitVar(gen, v);
rlm@10 2978 gen.invokeVirtual(VAR_TYPE, Method.getMethod("Object getRawRoot()")); //target, proto-fn
rlm@10 2979 gen.swap();
rlm@10 2980 emitArgsAndCall(1, context,objx,gen);
rlm@10 2981 gen.goTo(endLabel);
rlm@10 2982
rlm@10 2983 gen.mark(onLabel); //target
rlm@10 2984 if(protocolOn != null)
rlm@10 2985 {
rlm@10 2986 MethodExpr.emitTypedArgs(objx, gen, onMethod.getParameterTypes(), RT.subvec(args,1,args.count()));
rlm@10 2987 if(context == C.RETURN)
rlm@10 2988 {
rlm@10 2989 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 2990 method.emitClearLocals(gen);
rlm@10 2991 }
rlm@10 2992 Method m = new Method(onMethod.getName(), Type.getReturnType(onMethod), Type.getArgumentTypes(onMethod));
rlm@10 2993 gen.invokeInterface(Type.getType(protocolOn), m);
rlm@10 2994 HostExpr.emitBoxReturn(objx, gen, onMethod.getReturnType());
rlm@10 2995 }
rlm@10 2996 gen.mark(endLabel);
rlm@10 2997 }
rlm@10 2998
rlm@10 2999 void emitArgsAndCall(int firstArgToEmit, C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 3000 for(int i = firstArgToEmit; i < Math.min(MAX_POSITIONAL_ARITY, args.count()); i++)
rlm@10 3001 {
rlm@10 3002 Expr e = (Expr) args.nth(i);
rlm@10 3003 e.emit(C.EXPRESSION, objx, gen);
rlm@10 3004 }
rlm@10 3005 if(args.count() > MAX_POSITIONAL_ARITY)
rlm@10 3006 {
rlm@10 3007 PersistentVector restArgs = PersistentVector.EMPTY;
rlm@10 3008 for(int i = MAX_POSITIONAL_ARITY; i < args.count(); i++)
rlm@10 3009 {
rlm@10 3010 restArgs = restArgs.cons(args.nth(i));
rlm@10 3011 }
rlm@10 3012 MethodExpr.emitArgsAsArray(restArgs, objx, gen);
rlm@10 3013 }
rlm@10 3014
rlm@10 3015 if(context == C.RETURN)
rlm@10 3016 {
rlm@10 3017 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 3018 method.emitClearLocals(gen);
rlm@10 3019 }
rlm@10 3020
rlm@10 3021 gen.invokeInterface(IFN_TYPE, new Method("invoke", OBJECT_TYPE, ARG_TYPES[Math.min(MAX_POSITIONAL_ARITY + 1,
rlm@10 3022 args.count())]));
rlm@10 3023 }
rlm@10 3024
rlm@10 3025 public boolean hasJavaClass() throws Exception{
rlm@10 3026 return tag != null;
rlm@10 3027 }
rlm@10 3028
rlm@10 3029 public Class getJavaClass() throws Exception{
rlm@10 3030 return HostExpr.tagToClass(tag);
rlm@10 3031 }
rlm@10 3032
rlm@10 3033 static public Expr parse(C context, ISeq form) throws Exception{
rlm@10 3034 if(context != C.EVAL)
rlm@10 3035 context = C.EXPRESSION;
rlm@10 3036 Expr fexpr = analyze(context, form.first());
rlm@10 3037 if(fexpr instanceof VarExpr && ((VarExpr)fexpr).var.equals(INSTANCE))
rlm@10 3038 {
rlm@10 3039 if(RT.second(form) instanceof Symbol)
rlm@10 3040 {
rlm@10 3041 Class c = HostExpr.maybeClass(RT.second(form),false);
rlm@10 3042 if(c != null)
rlm@10 3043 return new InstanceOfExpr(c, analyze(context, RT.third(form)));
rlm@10 3044 }
rlm@10 3045 }
rlm@10 3046
rlm@10 3047 if(fexpr instanceof KeywordExpr && RT.count(form) == 2 && KEYWORD_CALLSITES.isBound())
rlm@10 3048 {
rlm@10 3049 // fexpr = new ConstantExpr(new KeywordCallSite(((KeywordExpr)fexpr).k));
rlm@10 3050 Expr target = analyze(context, RT.second(form));
rlm@10 3051 return new KeywordInvokeExpr((String) SOURCE.deref(), (Integer) LINE.deref(), tagOf(form),
rlm@10 3052 (KeywordExpr) fexpr, target);
rlm@10 3053 }
rlm@10 3054 PersistentVector args = PersistentVector.EMPTY;
rlm@10 3055 for(ISeq s = RT.seq(form.next()); s != null; s = s.next())
rlm@10 3056 {
rlm@10 3057 args = args.cons(analyze(context, s.first()));
rlm@10 3058 }
rlm@10 3059 // if(args.count() > MAX_POSITIONAL_ARITY)
rlm@10 3060 // throw new IllegalArgumentException(
rlm@10 3061 // String.format("No more than %d args supported", MAX_POSITIONAL_ARITY));
rlm@10 3062
rlm@10 3063 return new InvokeExpr((String) SOURCE.deref(), (Integer) LINE.deref(), tagOf(form), fexpr, args);
rlm@10 3064 }
rlm@10 3065 }
rlm@10 3066
rlm@10 3067 static class SourceDebugExtensionAttribute extends Attribute{
rlm@10 3068 public SourceDebugExtensionAttribute(){
rlm@10 3069 super("SourceDebugExtension");
rlm@10 3070 }
rlm@10 3071
rlm@10 3072 void writeSMAP(ClassWriter cw, String smap){
rlm@10 3073 ByteVector bv = write(cw, null, -1, -1, -1);
rlm@10 3074 bv.putUTF8(smap);
rlm@10 3075 }
rlm@10 3076 }
rlm@10 3077
rlm@10 3078 static public class FnExpr extends ObjExpr{
rlm@10 3079 final static Type aFnType = Type.getType(AFunction.class);
rlm@10 3080 final static Type restFnType = Type.getType(RestFn.class);
rlm@10 3081 //if there is a variadic overload (there can only be one) it is stored here
rlm@10 3082 FnMethod variadicMethod = null;
rlm@10 3083 IPersistentCollection methods;
rlm@10 3084 // String superName = null;
rlm@10 3085
rlm@10 3086 public FnExpr(Object tag){
rlm@10 3087 super(tag);
rlm@10 3088 }
rlm@10 3089
rlm@10 3090 public boolean hasJavaClass() throws Exception{
rlm@10 3091 return true;
rlm@10 3092 }
rlm@10 3093
rlm@10 3094 public Class getJavaClass() throws Exception{
rlm@10 3095 return AFunction.class;
rlm@10 3096 }
rlm@10 3097
rlm@10 3098 protected void emitMethods(ClassVisitor cv){
rlm@10 3099 //override of invoke/doInvoke for each method
rlm@10 3100 for(ISeq s = RT.seq(methods); s != null; s = s.next())
rlm@10 3101 {
rlm@10 3102 ObjMethod method = (ObjMethod) s.first();
rlm@10 3103 method.emit(this, cv);
rlm@10 3104 }
rlm@10 3105
rlm@10 3106 if(isVariadic())
rlm@10 3107 {
rlm@10 3108 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3109 Method.getMethod("int getRequiredArity()"),
rlm@10 3110 null,
rlm@10 3111 null,
rlm@10 3112 cv);
rlm@10 3113 gen.visitCode();
rlm@10 3114 gen.push(variadicMethod.reqParms.count());
rlm@10 3115 gen.returnValue();
rlm@10 3116 gen.endMethod();
rlm@10 3117 }
rlm@10 3118 }
rlm@10 3119
rlm@10 3120 static Expr parse(C context, ISeq form, String name) throws Exception{
rlm@10 3121 ISeq origForm = form;
rlm@10 3122 FnExpr fn = new FnExpr(tagOf(form));
rlm@10 3123 fn.src = form;
rlm@10 3124 ObjMethod enclosingMethod = (ObjMethod) METHOD.deref();
rlm@10 3125 if(((IMeta) form.first()).meta() != null)
rlm@10 3126 {
rlm@10 3127 fn.onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), Keyword.intern(null, "once")));
rlm@10 3128 // fn.superName = (String) RT.get(RT.meta(form.first()), Keyword.intern(null, "super-name"));
rlm@10 3129 }
rlm@10 3130 //fn.thisName = name;
rlm@10 3131 String basename = enclosingMethod != null ?
rlm@10 3132 (enclosingMethod.objx.name + "$")
rlm@10 3133 : //"clojure.fns." +
rlm@10 3134 (munge(currentNS().name.name) + "$");
rlm@10 3135 if(RT.second(form) instanceof Symbol)
rlm@10 3136 name = ((Symbol) RT.second(form)).name;
rlm@10 3137 String simpleName = name != null ?
rlm@10 3138 (munge(name).replace(".", "_DOT_")
rlm@10 3139 + (enclosingMethod != null ? "__" + RT.nextID() : ""))
rlm@10 3140 : ("fn"
rlm@10 3141 + "__" + RT.nextID());
rlm@10 3142 fn.name = basename + simpleName;
rlm@10 3143 fn.internalName = fn.name.replace('.', '/');
rlm@10 3144 fn.objtype = Type.getObjectType(fn.internalName);
rlm@10 3145 try
rlm@10 3146 {
rlm@10 3147 Var.pushThreadBindings(
rlm@10 3148 RT.map(CONSTANTS, PersistentVector.EMPTY,
rlm@10 3149 CONSTANT_IDS, new IdentityHashMap(),
rlm@10 3150 KEYWORDS, PersistentHashMap.EMPTY,
rlm@10 3151 VARS, PersistentHashMap.EMPTY,
rlm@10 3152 KEYWORD_CALLSITES, PersistentVector.EMPTY,
rlm@10 3153 PROTOCOL_CALLSITES, PersistentVector.EMPTY,
rlm@10 3154 VAR_CALLSITES, PersistentVector.EMPTY
rlm@10 3155 ));
rlm@10 3156
rlm@10 3157 //arglist might be preceded by symbol naming this fn
rlm@10 3158 if(RT.second(form) instanceof Symbol)
rlm@10 3159 {
rlm@10 3160 fn.thisName = ((Symbol) RT.second(form)).name;
rlm@10 3161 form = RT.cons(FN, RT.next(RT.next(form)));
rlm@10 3162 }
rlm@10 3163
rlm@10 3164 //now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...)
rlm@10 3165 //turn former into latter
rlm@10 3166 if(RT.second(form) instanceof IPersistentVector)
rlm@10 3167 form = RT.list(FN, RT.next(form));
rlm@10 3168 fn.line = (Integer) LINE.deref();
rlm@10 3169 FnMethod[] methodArray = new FnMethod[MAX_POSITIONAL_ARITY + 1];
rlm@10 3170 FnMethod variadicMethod = null;
rlm@10 3171 for(ISeq s = RT.next(form); s != null; s = RT.next(s))
rlm@10 3172 {
rlm@10 3173 FnMethod f = FnMethod.parse(fn, (ISeq) RT.first(s));
rlm@10 3174 if(f.isVariadic())
rlm@10 3175 {
rlm@10 3176 if(variadicMethod == null)
rlm@10 3177 variadicMethod = f;
rlm@10 3178 else
rlm@10 3179 throw new Exception("Can't have more than 1 variadic overload");
rlm@10 3180 }
rlm@10 3181 else if(methodArray[f.reqParms.count()] == null)
rlm@10 3182 methodArray[f.reqParms.count()] = f;
rlm@10 3183 else
rlm@10 3184 throw new Exception("Can't have 2 overloads with same arity");
rlm@10 3185 }
rlm@10 3186 if(variadicMethod != null)
rlm@10 3187 {
rlm@10 3188 for(int i = variadicMethod.reqParms.count() + 1; i <= MAX_POSITIONAL_ARITY; i++)
rlm@10 3189 if(methodArray[i] != null)
rlm@10 3190 throw new Exception(
rlm@10 3191 "Can't have fixed arity function with more params than variadic function");
rlm@10 3192 }
rlm@10 3193
rlm@10 3194 IPersistentCollection methods = null;
rlm@10 3195 for(int i = 0; i < methodArray.length; i++)
rlm@10 3196 if(methodArray[i] != null)
rlm@10 3197 methods = RT.conj(methods, methodArray[i]);
rlm@10 3198 if(variadicMethod != null)
rlm@10 3199 methods = RT.conj(methods, variadicMethod);
rlm@10 3200
rlm@10 3201 fn.methods = methods;
rlm@10 3202 fn.variadicMethod = variadicMethod;
rlm@10 3203 fn.keywords = (IPersistentMap) KEYWORDS.deref();
rlm@10 3204 fn.vars = (IPersistentMap) VARS.deref();
rlm@10 3205 fn.constants = (PersistentVector) CONSTANTS.deref();
rlm@10 3206 fn.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref();
rlm@10 3207 fn.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref();
rlm@10 3208 fn.varCallsites = (IPersistentVector) VAR_CALLSITES.deref();
rlm@10 3209
rlm@10 3210 fn.constantsID = RT.nextID();
rlm@10 3211 // DynamicClassLoader loader = (DynamicClassLoader) LOADER.get();
rlm@10 3212 // loader.registerConstants(fn.constantsID, fn.constants.toArray());
rlm@10 3213 }
rlm@10 3214 finally
rlm@10 3215 {
rlm@10 3216 Var.popThreadBindings();
rlm@10 3217 }
rlm@10 3218 fn.compile(fn.isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction",null,fn.onceOnly);
rlm@10 3219 fn.getCompiledClass();
rlm@10 3220
rlm@10 3221 if(origForm instanceof IObj && ((IObj) origForm).meta() != null)
rlm@10 3222 return new MetaExpr(fn, (MapExpr) MapExpr
rlm@10 3223 .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) origForm).meta()));
rlm@10 3224 else
rlm@10 3225 return fn;
rlm@10 3226 }
rlm@10 3227
rlm@10 3228 public final ObjMethod variadicMethod(){
rlm@10 3229 return variadicMethod;
rlm@10 3230 }
rlm@10 3231
rlm@10 3232 boolean isVariadic(){
rlm@10 3233 return variadicMethod != null;
rlm@10 3234 }
rlm@10 3235
rlm@10 3236 public final IPersistentCollection methods(){
rlm@10 3237 return methods;
rlm@10 3238 }
rlm@10 3239 }
rlm@10 3240
rlm@10 3241 static public class ObjExpr implements Expr{
rlm@10 3242 static final String CONST_PREFIX = "const__";
rlm@10 3243 String name;
rlm@10 3244 //String simpleName;
rlm@10 3245 String internalName;
rlm@10 3246 String thisName;
rlm@10 3247 Type objtype;
rlm@10 3248 public final Object tag;
rlm@10 3249 //localbinding->itself
rlm@10 3250 IPersistentMap closes = PersistentHashMap.EMPTY;
rlm@10 3251 //localbndingexprs
rlm@10 3252 IPersistentVector closesExprs = PersistentVector.EMPTY;
rlm@10 3253 //symbols
rlm@10 3254 IPersistentSet volatiles = PersistentHashSet.EMPTY;
rlm@10 3255
rlm@10 3256 //symbol->lb
rlm@10 3257 IPersistentMap fields = null;
rlm@10 3258
rlm@10 3259 //Keyword->KeywordExpr
rlm@10 3260 IPersistentMap keywords = PersistentHashMap.EMPTY;
rlm@10 3261 IPersistentMap vars = PersistentHashMap.EMPTY;
rlm@10 3262 Class compiledClass;
rlm@10 3263 int line;
rlm@10 3264 PersistentVector constants;
rlm@10 3265 int constantsID;
rlm@10 3266 int altCtorDrops = 0;
rlm@10 3267
rlm@10 3268 IPersistentVector keywordCallsites;
rlm@10 3269 IPersistentVector protocolCallsites;
rlm@10 3270 IPersistentVector varCallsites;
rlm@10 3271 boolean onceOnly = false;
rlm@10 3272
rlm@10 3273 Object src;
rlm@10 3274
rlm@10 3275 final static Method voidctor = Method.getMethod("void <init>()");
rlm@10 3276 protected IPersistentMap classMeta;
rlm@10 3277
rlm@10 3278 public final String name(){
rlm@10 3279 return name;
rlm@10 3280 }
rlm@10 3281
rlm@10 3282 // public final String simpleName(){
rlm@10 3283 // return simpleName;
rlm@10 3284 // }
rlm@10 3285
rlm@10 3286 public final String internalName(){
rlm@10 3287 return internalName;
rlm@10 3288 }
rlm@10 3289
rlm@10 3290 public final String thisName(){
rlm@10 3291 return thisName;
rlm@10 3292 }
rlm@10 3293
rlm@10 3294 public final Type objtype(){
rlm@10 3295 return objtype;
rlm@10 3296 }
rlm@10 3297
rlm@10 3298 public final IPersistentMap closes(){
rlm@10 3299 return closes;
rlm@10 3300 }
rlm@10 3301
rlm@10 3302 public final IPersistentMap keywords(){
rlm@10 3303 return keywords;
rlm@10 3304 }
rlm@10 3305
rlm@10 3306 public final IPersistentMap vars(){
rlm@10 3307 return vars;
rlm@10 3308 }
rlm@10 3309
rlm@10 3310 public final Class compiledClass(){
rlm@10 3311 return compiledClass;
rlm@10 3312 }
rlm@10 3313
rlm@10 3314 public final int line(){
rlm@10 3315 return line;
rlm@10 3316 }
rlm@10 3317
rlm@10 3318 public final PersistentVector constants(){
rlm@10 3319 return constants;
rlm@10 3320 }
rlm@10 3321
rlm@10 3322 public final int constantsID(){
rlm@10 3323 return constantsID;
rlm@10 3324 }
rlm@10 3325
rlm@10 3326 final static Method kwintern = Method.getMethod("clojure.lang.Keyword intern(String, String)");
rlm@10 3327 final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String)");
rlm@10 3328 final static Method varintern =
rlm@10 3329 Method.getMethod("clojure.lang.Var intern(clojure.lang.Symbol, clojure.lang.Symbol)");
rlm@10 3330
rlm@10 3331 final static Type DYNAMIC_CLASSLOADER_TYPE = Type.getType(DynamicClassLoader.class);
rlm@10 3332 final static Method getClassMethod = Method.getMethod("Class getClass()");
rlm@10 3333 final static Method getClassLoaderMethod = Method.getMethod("ClassLoader getClassLoader()");
rlm@10 3334 final static Method getConstantsMethod = Method.getMethod("Object[] getConstants(int)");
rlm@10 3335 final static Method readStringMethod = Method.getMethod("Object readString(String)");
rlm@10 3336
rlm@10 3337 final static Type ILOOKUP_SITE_TYPE = Type.getType(ILookupSite.class);
rlm@10 3338 final static Type ILOOKUP_THUNK_TYPE = Type.getType(ILookupThunk.class);
rlm@10 3339 final static Type KEYWORD_LOOKUPSITE_TYPE = Type.getType(KeywordLookupSite.class);
rlm@10 3340
rlm@10 3341 private DynamicClassLoader loader;
rlm@10 3342 private byte[] bytecode;
rlm@10 3343
rlm@10 3344 public ObjExpr(Object tag){
rlm@10 3345 this.tag = tag;
rlm@10 3346 }
rlm@10 3347
rlm@10 3348 static String trimGenID(String name){
rlm@10 3349 int i = name.lastIndexOf("__");
rlm@10 3350 return i==-1?name:name.substring(0,i);
rlm@10 3351 }
rlm@10 3352
rlm@10 3353
rlm@10 3354
rlm@10 3355 Type[] ctorTypes(){
rlm@10 3356 IPersistentVector tv = isDeftype()?PersistentVector.EMPTY:RT.vector(IPERSISTENTMAP_TYPE);
rlm@10 3357 for(ISeq s = RT.keys(closes); s != null; s = s.next())
rlm@10 3358 {
rlm@10 3359 LocalBinding lb = (LocalBinding) s.first();
rlm@10 3360 if(lb.getPrimitiveType() != null)
rlm@10 3361 tv = tv.cons(Type.getType(lb.getPrimitiveType()));
rlm@10 3362 else
rlm@10 3363 tv = tv.cons(OBJECT_TYPE);
rlm@10 3364 }
rlm@10 3365 Type[] ret = new Type[tv.count()];
rlm@10 3366 for(int i = 0; i < tv.count(); i++)
rlm@10 3367 ret[i] = (Type) tv.nth(i);
rlm@10 3368 return ret;
rlm@10 3369 }
rlm@10 3370
rlm@10 3371 void compile(String superName, String[] interfaceNames, boolean oneTimeUse) throws Exception{
rlm@10 3372 //create bytecode for a class
rlm@10 3373 //with name current_ns.defname[$letname]+
rlm@10 3374 //anonymous fns get names fn__id
rlm@10 3375 //derived from AFn/RestFn
rlm@10 3376 if(keywordCallsites.count() > 0)
rlm@10 3377 {
rlm@10 3378 if(interfaceNames == null)
rlm@10 3379 interfaceNames = new String[]{"clojure/lang/ILookupHost"};
rlm@10 3380 else
rlm@10 3381 {
rlm@10 3382 String[] inames = new String[interfaceNames.length + 1];
rlm@10 3383 System.arraycopy(interfaceNames,0,inames,0,interfaceNames.length);
rlm@10 3384 inames[interfaceNames.length] = "clojure/lang/ILookupHost";
rlm@10 3385 interfaceNames = inames;
rlm@10 3386 }
rlm@10 3387 }
rlm@10 3388 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
rlm@10 3389 // ClassWriter cw = new ClassWriter(0);
rlm@10 3390 ClassVisitor cv = cw;
rlm@10 3391 // ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out));
rlm@10 3392 //ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));
rlm@10 3393 cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER + ACC_FINAL, internalName, null,superName,interfaceNames);
rlm@10 3394 // superName != null ? superName :
rlm@10 3395 // (isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction"), null);
rlm@10 3396 String source = (String) SOURCE.deref();
rlm@10 3397 int lineBefore = (Integer) LINE_BEFORE.deref();
rlm@10 3398 int lineAfter = (Integer) LINE_AFTER.deref() + 1;
rlm@10 3399
rlm@10 3400 if(source != null && SOURCE_PATH.deref() != null)
rlm@10 3401 {
rlm@10 3402 //cv.visitSource(source, null);
rlm@10 3403 String smap = "SMAP\n" +
rlm@10 3404 ((source.lastIndexOf('.') > 0) ?
rlm@10 3405 source.substring(0, source.lastIndexOf('.'))
rlm@10 3406 :source)
rlm@10 3407 // : simpleName)
rlm@10 3408 + ".java\n" +
rlm@10 3409 "Clojure\n" +
rlm@10 3410 "*S Clojure\n" +
rlm@10 3411 "*F\n" +
rlm@10 3412 "+ 1 " + source + "\n" +
rlm@10 3413 (String) SOURCE_PATH.deref() + "\n" +
rlm@10 3414 "*L\n" +
rlm@10 3415 String.format("%d#1,%d:%d\n", lineBefore, lineAfter - lineBefore, lineBefore) +
rlm@10 3416 "*E";
rlm@10 3417 cv.visitSource(source, smap);
rlm@10 3418 }
rlm@10 3419 addAnnotation(cv, classMeta);
rlm@10 3420 //static fields for constants
rlm@10 3421 for(int i = 0; i < constants.count(); i++)
rlm@10 3422 {
rlm@10 3423 cv.visitField(ACC_PUBLIC + ACC_FINAL
rlm@10 3424 + ACC_STATIC, constantName(i), constantType(i).getDescriptor(),
rlm@10 3425 null, null);
rlm@10 3426 }
rlm@10 3427
rlm@10 3428 //static fields for lookup sites
rlm@10 3429 for(int i = 0; i < keywordCallsites.count(); i++)
rlm@10 3430 {
rlm@10 3431 cv.visitField(ACC_FINAL
rlm@10 3432 + ACC_STATIC, siteNameStatic(i), KEYWORD_LOOKUPSITE_TYPE.getDescriptor(),
rlm@10 3433 null, null);
rlm@10 3434 cv.visitField(ACC_STATIC, thunkNameStatic(i), ILOOKUP_THUNK_TYPE.getDescriptor(),
rlm@10 3435 null, null);
rlm@10 3436 }
rlm@10 3437
rlm@10 3438 for(int i=0;i<varCallsites.count();i++)
rlm@10 3439 {
rlm@10 3440 cv.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL
rlm@10 3441 , varCallsiteName(i), IFN_TYPE.getDescriptor(), null, null);
rlm@10 3442 }
rlm@10 3443
rlm@10 3444 //static init for constants, keywords and vars
rlm@10 3445 GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
rlm@10 3446 Method.getMethod("void <clinit> ()"),
rlm@10 3447 null,
rlm@10 3448 null,
rlm@10 3449 cv);
rlm@10 3450 clinitgen.visitCode();
rlm@10 3451 clinitgen.visitLineNumber(line, clinitgen.mark());
rlm@10 3452
rlm@10 3453 if(constants.count() > 0)
rlm@10 3454 {
rlm@10 3455 emitConstants(clinitgen);
rlm@10 3456 }
rlm@10 3457
rlm@10 3458 if(keywordCallsites.count() > 0)
rlm@10 3459 emitKeywordCallsites(clinitgen);
rlm@10 3460
rlm@10 3461 for(int i=0;i<varCallsites.count();i++)
rlm@10 3462 {
rlm@10 3463 Label skipLabel = clinitgen.newLabel();
rlm@10 3464 Label endLabel = clinitgen.newLabel();
rlm@10 3465 Var var = (Var) varCallsites.nth(i);
rlm@10 3466 clinitgen.push(var.ns.name.toString());
rlm@10 3467 clinitgen.push(var.sym.toString());
rlm@10 3468 clinitgen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)"));
rlm@10 3469 clinitgen.dup();
rlm@10 3470 clinitgen.invokeVirtual(VAR_TYPE,Method.getMethod("boolean hasRoot()"));
rlm@10 3471 clinitgen.ifZCmp(GeneratorAdapter.EQ,skipLabel);
rlm@10 3472
rlm@10 3473 clinitgen.invokeVirtual(VAR_TYPE,Method.getMethod("Object getRoot()"));
rlm@10 3474 clinitgen.dup();
rlm@10 3475 clinitgen.instanceOf(AFUNCTION_TYPE);
rlm@10 3476 clinitgen.ifZCmp(GeneratorAdapter.EQ,skipLabel);
rlm@10 3477 clinitgen.checkCast(IFN_TYPE);
rlm@10 3478 clinitgen.putStatic(objtype, varCallsiteName(i), IFN_TYPE);
rlm@10 3479 clinitgen.goTo(endLabel);
rlm@10 3480
rlm@10 3481 clinitgen.mark(skipLabel);
rlm@10 3482 clinitgen.pop();
rlm@10 3483
rlm@10 3484 clinitgen.mark(endLabel);
rlm@10 3485 }
rlm@10 3486
rlm@10 3487 clinitgen.returnValue();
rlm@10 3488
rlm@10 3489 clinitgen.endMethod();
rlm@10 3490 if(!isDeftype())
rlm@10 3491 {
rlm@10 3492 cv.visitField(ACC_FINAL, "__meta", IPERSISTENTMAP_TYPE.getDescriptor(), null, null);
rlm@10 3493 }
rlm@10 3494 //instance fields for closed-overs
rlm@10 3495 for(ISeq s = RT.keys(closes); s != null; s = s.next())
rlm@10 3496 {
rlm@10 3497 LocalBinding lb = (LocalBinding) s.first();
rlm@10 3498 if(isDeftype())
rlm@10 3499 {
rlm@10 3500 int access = isVolatile(lb) ? ACC_VOLATILE :
rlm@10 3501 isMutable(lb) ? 0 :
rlm@10 3502 (ACC_PUBLIC + ACC_FINAL);
rlm@10 3503 FieldVisitor fv;
rlm@10 3504 if(lb.getPrimitiveType() != null)
rlm@10 3505 fv = cv.visitField(access
rlm@10 3506 , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(),
rlm@10 3507 null, null);
rlm@10 3508 else
rlm@10 3509 //todo - when closed-overs are fields, use more specific types here and in ctor and emitLocal?
rlm@10 3510 fv = cv.visitField(access
rlm@10 3511 , lb.name, OBJECT_TYPE.getDescriptor(), null, null);
rlm@10 3512 addAnnotation(fv, RT.meta(lb.sym));
rlm@10 3513 }
rlm@10 3514 else
rlm@10 3515 {
rlm@10 3516 //todo - only enable this non-private+writability for letfns where we need it
rlm@10 3517 if(lb.getPrimitiveType() != null)
rlm@10 3518 cv.visitField(0 + (isVolatile(lb) ? ACC_VOLATILE : 0)
rlm@10 3519 , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(),
rlm@10 3520 null, null);
rlm@10 3521 else
rlm@10 3522 cv.visitField(0 //+ (oneTimeUse ? 0 : ACC_FINAL)
rlm@10 3523 , lb.name, OBJECT_TYPE.getDescriptor(), null, null);
rlm@10 3524 }
rlm@10 3525 }
rlm@10 3526
rlm@10 3527 //instance fields for callsites and thunks
rlm@10 3528 for(int i=0;i<protocolCallsites.count();i++)
rlm@10 3529 {
rlm@10 3530 cv.visitField(ACC_PRIVATE, cachedClassName(i), CLASS_TYPE.getDescriptor(), null, null);
rlm@10 3531 cv.visitField(ACC_PRIVATE, cachedProtoFnName(i), AFUNCTION_TYPE.getDescriptor(), null, null);
rlm@10 3532 cv.visitField(ACC_PRIVATE, cachedProtoImplName(i), IFN_TYPE.getDescriptor(), null, null);
rlm@10 3533 }
rlm@10 3534
rlm@10 3535 //ctor that takes closed-overs and inits base + fields
rlm@10 3536 Method m = new Method("<init>", Type.VOID_TYPE, ctorTypes());
rlm@10 3537 GeneratorAdapter ctorgen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3538 m,
rlm@10 3539 null,
rlm@10 3540 null,
rlm@10 3541 cv);
rlm@10 3542 Label start = ctorgen.newLabel();
rlm@10 3543 Label end = ctorgen.newLabel();
rlm@10 3544 ctorgen.visitCode();
rlm@10 3545 ctorgen.visitLineNumber(line, ctorgen.mark());
rlm@10 3546 ctorgen.visitLabel(start);
rlm@10 3547 ctorgen.loadThis();
rlm@10 3548 // if(superName != null)
rlm@10 3549 ctorgen.invokeConstructor(Type.getObjectType(superName), voidctor);
rlm@10 3550 // else if(isVariadic()) //RestFn ctor takes reqArity arg
rlm@10 3551 // {
rlm@10 3552 // ctorgen.push(variadicMethod.reqParms.count());
rlm@10 3553 // ctorgen.invokeConstructor(restFnType, restfnctor);
rlm@10 3554 // }
rlm@10 3555 // else
rlm@10 3556 // ctorgen.invokeConstructor(aFnType, voidctor);
rlm@10 3557 if(!isDeftype())
rlm@10 3558 {
rlm@10 3559 ctorgen.loadThis();
rlm@10 3560 ctorgen.visitVarInsn(IPERSISTENTMAP_TYPE.getOpcode(Opcodes.ILOAD), 1);
rlm@10 3561 ctorgen.putField(objtype, "__meta", IPERSISTENTMAP_TYPE);
rlm@10 3562 }
rlm@10 3563
rlm@10 3564 int a = isDeftype()?1:2;
rlm@10 3565 for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a)
rlm@10 3566 {
rlm@10 3567 LocalBinding lb = (LocalBinding) s.first();
rlm@10 3568 ctorgen.loadThis();
rlm@10 3569 Class primc = lb.getPrimitiveType();
rlm@10 3570 if(primc != null)
rlm@10 3571 {
rlm@10 3572 ctorgen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ILOAD), a);
rlm@10 3573 ctorgen.putField(objtype, lb.name, Type.getType(primc));
rlm@10 3574 if(primc == Long.TYPE || primc == Double.TYPE)
rlm@10 3575 ++a;
rlm@10 3576 }
rlm@10 3577 else
rlm@10 3578 {
rlm@10 3579 ctorgen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), a);
rlm@10 3580 ctorgen.putField(objtype, lb.name, OBJECT_TYPE);
rlm@10 3581 }
rlm@10 3582 closesExprs = closesExprs.cons(new LocalBindingExpr(lb, null));
rlm@10 3583 }
rlm@10 3584
rlm@10 3585
rlm@10 3586 ctorgen.visitLabel(end);
rlm@10 3587
rlm@10 3588 ctorgen.returnValue();
rlm@10 3589
rlm@10 3590 ctorgen.endMethod();
rlm@10 3591
rlm@10 3592 if(altCtorDrops > 0)
rlm@10 3593 {
rlm@10 3594 //ctor that takes closed-overs and inits base + fields
rlm@10 3595 Type[] ctorTypes = ctorTypes();
rlm@10 3596 Type[] altCtorTypes = new Type[ctorTypes.length-altCtorDrops];
rlm@10 3597 for(int i=0;i<altCtorTypes.length;i++)
rlm@10 3598 altCtorTypes[i] = ctorTypes[i];
rlm@10 3599 Method alt = new Method("<init>", Type.VOID_TYPE, altCtorTypes);
rlm@10 3600 ctorgen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3601 alt,
rlm@10 3602 null,
rlm@10 3603 null,
rlm@10 3604 cv);
rlm@10 3605 ctorgen.visitCode();
rlm@10 3606 ctorgen.loadThis();
rlm@10 3607 ctorgen.loadArgs();
rlm@10 3608 for(int i=0;i<altCtorDrops;i++)
rlm@10 3609 ctorgen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 3610
rlm@10 3611 ctorgen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes));
rlm@10 3612
rlm@10 3613 ctorgen.returnValue();
rlm@10 3614 ctorgen.endMethod();
rlm@10 3615 }
rlm@10 3616
rlm@10 3617 if(!isDeftype())
rlm@10 3618 {
rlm@10 3619 //ctor that takes closed-overs but not meta
rlm@10 3620 Type[] ctorTypes = ctorTypes();
rlm@10 3621 Type[] noMetaCtorTypes = new Type[ctorTypes.length-1];
rlm@10 3622 for(int i=1;i<ctorTypes.length;i++)
rlm@10 3623 noMetaCtorTypes[i-1] = ctorTypes[i];
rlm@10 3624 Method alt = new Method("<init>", Type.VOID_TYPE, noMetaCtorTypes);
rlm@10 3625 ctorgen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3626 alt,
rlm@10 3627 null,
rlm@10 3628 null,
rlm@10 3629 cv);
rlm@10 3630 ctorgen.visitCode();
rlm@10 3631 ctorgen.loadThis();
rlm@10 3632 ctorgen.visitInsn(Opcodes.ACONST_NULL); //null meta
rlm@10 3633 ctorgen.loadArgs();
rlm@10 3634 ctorgen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes));
rlm@10 3635
rlm@10 3636 ctorgen.returnValue();
rlm@10 3637 ctorgen.endMethod();
rlm@10 3638
rlm@10 3639 //meta()
rlm@10 3640 Method meth = Method.getMethod("clojure.lang.IPersistentMap meta()");
rlm@10 3641
rlm@10 3642 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3643 meth,
rlm@10 3644 null,
rlm@10 3645 null,
rlm@10 3646 cv);
rlm@10 3647 gen.visitCode();
rlm@10 3648 gen.loadThis();
rlm@10 3649 gen.getField(objtype,"__meta",IPERSISTENTMAP_TYPE);
rlm@10 3650
rlm@10 3651 gen.returnValue();
rlm@10 3652 gen.endMethod();
rlm@10 3653
rlm@10 3654 //withMeta()
rlm@10 3655 meth = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)");
rlm@10 3656
rlm@10 3657 gen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3658 meth,
rlm@10 3659 null,
rlm@10 3660 null,
rlm@10 3661 cv);
rlm@10 3662 gen.visitCode();
rlm@10 3663 gen.newInstance(objtype);
rlm@10 3664 gen.dup();
rlm@10 3665 gen.loadArg(0);
rlm@10 3666
rlm@10 3667 for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a)
rlm@10 3668 {
rlm@10 3669 LocalBinding lb = (LocalBinding) s.first();
rlm@10 3670 gen.loadThis();
rlm@10 3671 Class primc = lb.getPrimitiveType();
rlm@10 3672 if(primc != null)
rlm@10 3673 {
rlm@10 3674 gen.getField(objtype, lb.name, Type.getType(primc));
rlm@10 3675 }
rlm@10 3676 else
rlm@10 3677 {
rlm@10 3678 gen.getField(objtype, lb.name, OBJECT_TYPE);
rlm@10 3679 }
rlm@10 3680 }
rlm@10 3681
rlm@10 3682 gen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes));
rlm@10 3683 gen.returnValue();
rlm@10 3684 gen.endMethod();
rlm@10 3685 }
rlm@10 3686
rlm@10 3687 emitMethods(cv);
rlm@10 3688
rlm@10 3689 if(keywordCallsites.count() > 0)
rlm@10 3690 {
rlm@10 3691 Method meth = Method.getMethod("void swapThunk(int,clojure.lang.ILookupThunk)");
rlm@10 3692
rlm@10 3693 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 3694 meth,
rlm@10 3695 null,
rlm@10 3696 null,
rlm@10 3697 cv);
rlm@10 3698 gen.visitCode();
rlm@10 3699 Label endLabel = gen.newLabel();
rlm@10 3700
rlm@10 3701 Label[] labels = new Label[keywordCallsites.count()];
rlm@10 3702 for(int i = 0; i < keywordCallsites.count();i++)
rlm@10 3703 {
rlm@10 3704 labels[i] = gen.newLabel();
rlm@10 3705 }
rlm@10 3706 gen.loadArg(0);
rlm@10 3707 gen.visitTableSwitchInsn(0,keywordCallsites.count()-1,endLabel,labels);
rlm@10 3708
rlm@10 3709 for(int i = 0; i < keywordCallsites.count();i++)
rlm@10 3710 {
rlm@10 3711 gen.mark(labels[i]);
rlm@10 3712 // gen.loadThis();
rlm@10 3713 gen.loadArg(1);
rlm@10 3714 gen.putStatic(objtype, thunkNameStatic(i),ILOOKUP_THUNK_TYPE);
rlm@10 3715 gen.goTo(endLabel);
rlm@10 3716 }
rlm@10 3717
rlm@10 3718 gen.mark(endLabel);
rlm@10 3719
rlm@10 3720 gen.returnValue();
rlm@10 3721 gen.endMethod();
rlm@10 3722 }
rlm@10 3723
rlm@10 3724 //end of class
rlm@10 3725 cv.visitEnd();
rlm@10 3726
rlm@10 3727 bytecode = cw.toByteArray();
rlm@10 3728 if(RT.booleanCast(COMPILE_FILES.deref()))
rlm@10 3729 writeClassFile(internalName, bytecode);
rlm@10 3730 // else
rlm@10 3731 // getCompiledClass();
rlm@10 3732 }
rlm@10 3733
rlm@10 3734 private void emitKeywordCallsites(GeneratorAdapter clinitgen){
rlm@10 3735 for(int i=0;i<keywordCallsites.count();i++)
rlm@10 3736 {
rlm@10 3737 Keyword k = (Keyword) keywordCallsites.nth(i);
rlm@10 3738 clinitgen.newInstance(KEYWORD_LOOKUPSITE_TYPE);
rlm@10 3739 clinitgen.dup();
rlm@10 3740 clinitgen.push(i);
rlm@10 3741 emitValue(k,clinitgen);
rlm@10 3742 clinitgen.invokeConstructor(KEYWORD_LOOKUPSITE_TYPE,
rlm@10 3743 Method.getMethod("void <init>(int,clojure.lang.Keyword)"));
rlm@10 3744 clinitgen.dup();
rlm@10 3745 clinitgen.putStatic(objtype, siteNameStatic(i), KEYWORD_LOOKUPSITE_TYPE);
rlm@10 3746 clinitgen.putStatic(objtype, thunkNameStatic(i), ILOOKUP_THUNK_TYPE);
rlm@10 3747 }
rlm@10 3748 }
rlm@10 3749
rlm@10 3750 protected void emitMethods(ClassVisitor gen){
rlm@10 3751 }
rlm@10 3752
rlm@10 3753 void emitListAsObjectArray(Object value, GeneratorAdapter gen){
rlm@10 3754 gen.push(((List) value).size());
rlm@10 3755 gen.newArray(OBJECT_TYPE);
rlm@10 3756 int i = 0;
rlm@10 3757 for(Iterator it = ((List) value).iterator(); it.hasNext(); i++)
rlm@10 3758 {
rlm@10 3759 gen.dup();
rlm@10 3760 gen.push(i);
rlm@10 3761 emitValue(it.next(), gen);
rlm@10 3762 gen.arrayStore(OBJECT_TYPE);
rlm@10 3763 }
rlm@10 3764 }
rlm@10 3765
rlm@10 3766 void emitValue(Object value, GeneratorAdapter gen){
rlm@10 3767 boolean partial = true;
rlm@10 3768 //System.out.println(value.getClass().toString());
rlm@10 3769
rlm@10 3770 if(value instanceof String)
rlm@10 3771 {
rlm@10 3772 gen.push((String) value);
rlm@10 3773 }
rlm@10 3774 else if(value instanceof Integer)
rlm@10 3775 {
rlm@10 3776 gen.push(((Integer) value).intValue());
rlm@10 3777 gen.invokeStatic(Type.getType(Integer.class), Method.getMethod("Integer valueOf(int)"));
rlm@10 3778 }
rlm@10 3779 else if(value instanceof Double)
rlm@10 3780 {
rlm@10 3781 gen.push(((Double) value).doubleValue());
rlm@10 3782 gen.invokeStatic(Type.getType(Double.class), Method.getMethod("Double valueOf(double)"));
rlm@10 3783 }
rlm@10 3784 else if(value instanceof Character)
rlm@10 3785 {
rlm@10 3786 gen.push(((Character) value).charValue());
rlm@10 3787 gen.invokeStatic(Type.getType(Character.class), Method.getMethod("Character valueOf(char)"));
rlm@10 3788 }
rlm@10 3789 else if(value instanceof Class)
rlm@10 3790 {
rlm@10 3791 Class cc = (Class)value;
rlm@10 3792 if(cc.isPrimitive())
rlm@10 3793 {
rlm@10 3794 Type bt;
rlm@10 3795 if ( cc == boolean.class ) bt = Type.getType(Boolean.class);
rlm@10 3796 else if ( cc == byte.class ) bt = Type.getType(Byte.class);
rlm@10 3797 else if ( cc == char.class ) bt = Type.getType(Character.class);
rlm@10 3798 else if ( cc == double.class ) bt = Type.getType(Double.class);
rlm@10 3799 else if ( cc == float.class ) bt = Type.getType(Float.class);
rlm@10 3800 else if ( cc == int.class ) bt = Type.getType(Integer.class);
rlm@10 3801 else if ( cc == long.class ) bt = Type.getType(Long.class);
rlm@10 3802 else if ( cc == short.class ) bt = Type.getType(Short.class);
rlm@10 3803 else throw new RuntimeException(
rlm@10 3804 "Can't embed unknown primitive in code: " + value);
rlm@10 3805 gen.getStatic( bt, "TYPE", Type.getType(Class.class) );
rlm@10 3806 }
rlm@10 3807 else
rlm@10 3808 {
rlm@10 3809 gen.push(destubClassName(cc.getName()));
rlm@10 3810 gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)"));
rlm@10 3811 }
rlm@10 3812 }
rlm@10 3813 else if(value instanceof Symbol)
rlm@10 3814 {
rlm@10 3815 gen.push(((Symbol) value).ns);
rlm@10 3816 gen.push(((Symbol) value).name);
rlm@10 3817 gen.invokeStatic(Type.getType(Symbol.class),
rlm@10 3818 Method.getMethod("clojure.lang.Symbol create(String,String)"));
rlm@10 3819 }
rlm@10 3820 else if(value instanceof Keyword)
rlm@10 3821 {
rlm@10 3822 emitValue(((Keyword) value).sym, gen);
rlm@10 3823 gen.invokeStatic(Type.getType(Keyword.class),
rlm@10 3824 Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)"));
rlm@10 3825 }
rlm@10 3826 // else if(value instanceof KeywordCallSite)
rlm@10 3827 // {
rlm@10 3828 // emitValue(((KeywordCallSite) value).k.sym, gen);
rlm@10 3829 // gen.invokeStatic(Type.getType(KeywordCallSite.class),
rlm@10 3830 // Method.getMethod("clojure.lang.KeywordCallSite create(clojure.lang.Symbol)"));
rlm@10 3831 // }
rlm@10 3832 else if(value instanceof Var)
rlm@10 3833 {
rlm@10 3834 Var var = (Var) value;
rlm@10 3835 gen.push(var.ns.name.toString());
rlm@10 3836 gen.push(var.sym.toString());
rlm@10 3837 gen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)"));
rlm@10 3838 }
rlm@10 3839 else if(value instanceof IPersistentMap)
rlm@10 3840 {
rlm@10 3841 List entries = new ArrayList();
rlm@10 3842 for(Map.Entry entry : (Set<Map.Entry>) ((Map) value).entrySet())
rlm@10 3843 {
rlm@10 3844 entries.add(entry.getKey());
rlm@10 3845 entries.add(entry.getValue());
rlm@10 3846 }
rlm@10 3847 emitListAsObjectArray(entries, gen);
rlm@10 3848 gen.invokeStatic(RT_TYPE,
rlm@10 3849 Method.getMethod("clojure.lang.IPersistentMap map(Object[])"));
rlm@10 3850 }
rlm@10 3851 else if(value instanceof IPersistentVector)
rlm@10 3852 {
rlm@10 3853 emitListAsObjectArray(value, gen);
rlm@10 3854 gen.invokeStatic(RT_TYPE, Method.getMethod(
rlm@10 3855 "clojure.lang.IPersistentVector vector(Object[])"));
rlm@10 3856 }
rlm@10 3857 else if(value instanceof ISeq || value instanceof IPersistentList)
rlm@10 3858 {
rlm@10 3859 emitListAsObjectArray(value, gen);
rlm@10 3860 gen.invokeStatic(Type.getType(java.util.Arrays.class),
rlm@10 3861 Method.getMethod("java.util.List asList(Object[])"));
rlm@10 3862 gen.invokeStatic(Type.getType(PersistentList.class),
rlm@10 3863 Method.getMethod(
rlm@10 3864 "clojure.lang.IPersistentList create(java.util.List)"));
rlm@10 3865 }
rlm@10 3866 else
rlm@10 3867 {
rlm@10 3868 String cs = null;
rlm@10 3869 try
rlm@10 3870 {
rlm@10 3871 cs = RT.printString(value);
rlm@10 3872 //System.out.println("WARNING SLOW CODE: " + value.getClass() + " -> " + cs);
rlm@10 3873 }
rlm@10 3874 catch(Exception e)
rlm@10 3875 {
rlm@10 3876 throw new RuntimeException(
rlm@10 3877 "Can't embed object in code, maybe print-dup not defined: " +
rlm@10 3878 value);
rlm@10 3879 }
rlm@10 3880 if(cs.length() == 0)
rlm@10 3881 throw new RuntimeException(
rlm@10 3882 "Can't embed unreadable object in code: " + value);
rlm@10 3883
rlm@10 3884 if(cs.startsWith("#<"))
rlm@10 3885 throw new RuntimeException(
rlm@10 3886 "Can't embed unreadable object in code: " + cs);
rlm@10 3887
rlm@10 3888 gen.push(cs);
rlm@10 3889 gen.invokeStatic(RT_TYPE, readStringMethod);
rlm@10 3890 partial = false;
rlm@10 3891 }
rlm@10 3892
rlm@10 3893 if(partial)
rlm@10 3894 {
rlm@10 3895 if(value instanceof IObj && RT.count(((IObj) value).meta()) > 0)
rlm@10 3896 {
rlm@10 3897 gen.checkCast(IOBJ_TYPE);
rlm@10 3898 emitValue(((IObj) value).meta(), gen);
rlm@10 3899 gen.checkCast(IPERSISTENTMAP_TYPE);
rlm@10 3900 gen.invokeInterface(IOBJ_TYPE,
rlm@10 3901 Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)"));
rlm@10 3902 }
rlm@10 3903 }
rlm@10 3904 }
rlm@10 3905
rlm@10 3906
rlm@10 3907 void emitConstants(GeneratorAdapter clinitgen){
rlm@10 3908 try
rlm@10 3909 {
rlm@10 3910 Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T));
rlm@10 3911
rlm@10 3912 for(int i = 0; i < constants.count(); i++)
rlm@10 3913 {
rlm@10 3914 emitValue(constants.nth(i), clinitgen);
rlm@10 3915 clinitgen.checkCast(constantType(i));
rlm@10 3916 clinitgen.putStatic(objtype, constantName(i), constantType(i));
rlm@10 3917 }
rlm@10 3918 }
rlm@10 3919 finally
rlm@10 3920 {
rlm@10 3921 Var.popThreadBindings();
rlm@10 3922 }
rlm@10 3923 }
rlm@10 3924
rlm@10 3925 boolean isMutable(LocalBinding lb){
rlm@10 3926 return isVolatile(lb) ||
rlm@10 3927 RT.booleanCast(RT.contains(fields, lb.sym)) &&
rlm@10 3928 RT.booleanCast(RT.get(lb.sym.meta(), Keyword.intern("unsynchronized-mutable")));
rlm@10 3929 }
rlm@10 3930
rlm@10 3931 boolean isVolatile(LocalBinding lb){
rlm@10 3932 return RT.booleanCast(RT.contains(fields, lb.sym)) &&
rlm@10 3933 RT.booleanCast(RT.get(lb.sym.meta(), Keyword.intern("volatile-mutable")));
rlm@10 3934 }
rlm@10 3935
rlm@10 3936 boolean isDeftype(){
rlm@10 3937 return fields != null;
rlm@10 3938 }
rlm@10 3939
rlm@10 3940 void emitClearCloses(GeneratorAdapter gen){
rlm@10 3941 // int a = 1;
rlm@10 3942 // for(ISeq s = RT.keys(closes); s != null; s = s.next(), ++a)
rlm@10 3943 // {
rlm@10 3944 // LocalBinding lb = (LocalBinding) s.first();
rlm@10 3945 // Class primc = lb.getPrimitiveType();
rlm@10 3946 // if(primc == null)
rlm@10 3947 // {
rlm@10 3948 // gen.loadThis();
rlm@10 3949 // gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 3950 // gen.putField(objtype, lb.name, OBJECT_TYPE);
rlm@10 3951 // }
rlm@10 3952 // }
rlm@10 3953 }
rlm@10 3954
rlm@10 3955 synchronized Class getCompiledClass(){
rlm@10 3956 if(compiledClass == null)
rlm@10 3957 try
rlm@10 3958 {
rlm@10 3959 // if(RT.booleanCast(COMPILE_FILES.deref()))
rlm@10 3960 // compiledClass = RT.classForName(name);//loader.defineClass(name, bytecode);
rlm@10 3961 // else
rlm@10 3962 {
rlm@10 3963 loader = (DynamicClassLoader) LOADER.deref();
rlm@10 3964 compiledClass = loader.defineClass(name, bytecode, src);
rlm@10 3965 }
rlm@10 3966 }
rlm@10 3967 catch(Exception e)
rlm@10 3968 {
rlm@10 3969 throw new RuntimeException(e);
rlm@10 3970 }
rlm@10 3971 return compiledClass;
rlm@10 3972 }
rlm@10 3973
rlm@10 3974 public Object eval() throws Exception{
rlm@10 3975 if(isDeftype())
rlm@10 3976 return null;
rlm@10 3977 return getCompiledClass().newInstance();
rlm@10 3978 }
rlm@10 3979
rlm@10 3980 public void emitLetFnInits(GeneratorAdapter gen, ObjExpr objx, IPersistentSet letFnLocals){
rlm@10 3981 //objx arg is enclosing objx, not this
rlm@10 3982 gen.checkCast(objtype);
rlm@10 3983
rlm@10 3984 for(ISeq s = RT.keys(closes); s != null; s = s.next())
rlm@10 3985 {
rlm@10 3986 LocalBinding lb = (LocalBinding) s.first();
rlm@10 3987 if(letFnLocals.contains(lb))
rlm@10 3988 {
rlm@10 3989 Class primc = lb.getPrimitiveType();
rlm@10 3990 gen.dup();
rlm@10 3991 if(primc != null)
rlm@10 3992 {
rlm@10 3993 objx.emitUnboxedLocal(gen, lb);
rlm@10 3994 gen.putField(objtype, lb.name, Type.getType(primc));
rlm@10 3995 }
rlm@10 3996 else
rlm@10 3997 {
rlm@10 3998 objx.emitLocal(gen, lb, false);
rlm@10 3999 gen.putField(objtype, lb.name, OBJECT_TYPE);
rlm@10 4000 }
rlm@10 4001 }
rlm@10 4002 }
rlm@10 4003 gen.pop();
rlm@10 4004
rlm@10 4005 }
rlm@10 4006
rlm@10 4007 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4008 //emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any
rlm@10 4009 //objx arg is enclosing objx, not this
rlm@10 4010 // getCompiledClass();
rlm@10 4011 if(isDeftype())
rlm@10 4012 {
rlm@10 4013 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4014 }
rlm@10 4015 else
rlm@10 4016 {
rlm@10 4017 gen.newInstance(objtype);
rlm@10 4018 gen.dup();
rlm@10 4019 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4020 for(ISeq s = RT.seq(closesExprs); s != null; s = s.next())
rlm@10 4021 {
rlm@10 4022 LocalBindingExpr lbe = (LocalBindingExpr) s.first();
rlm@10 4023 LocalBinding lb = lbe.b;
rlm@10 4024 if(lb.getPrimitiveType() != null)
rlm@10 4025 objx.emitUnboxedLocal(gen, lb);
rlm@10 4026 else
rlm@10 4027 objx.emitLocal(gen, lb, lbe.shouldClear);
rlm@10 4028 }
rlm@10 4029 gen.invokeConstructor(objtype, new Method("<init>", Type.VOID_TYPE, ctorTypes()));
rlm@10 4030 }
rlm@10 4031 if(context == C.STATEMENT)
rlm@10 4032 gen.pop();
rlm@10 4033 }
rlm@10 4034
rlm@10 4035 public boolean hasJavaClass() throws Exception{
rlm@10 4036 return true;
rlm@10 4037 }
rlm@10 4038
rlm@10 4039 public Class getJavaClass() throws Exception{
rlm@10 4040 return (compiledClass != null) ? compiledClass
rlm@10 4041 : (tag != null) ? HostExpr.tagToClass(tag)
rlm@10 4042 : IFn.class;
rlm@10 4043 }
rlm@10 4044
rlm@10 4045 public void emitAssignLocal(GeneratorAdapter gen, LocalBinding lb,Expr val){
rlm@10 4046 if(!isMutable(lb))
rlm@10 4047 throw new IllegalArgumentException("Cannot assign to non-mutable: " + lb.name);
rlm@10 4048 Class primc = lb.getPrimitiveType();
rlm@10 4049 gen.loadThis();
rlm@10 4050 if(primc != null)
rlm@10 4051 {
rlm@10 4052 if(!(val instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr) val).canEmitPrimitive()))
rlm@10 4053 throw new IllegalArgumentException("Must assign primitive to primitive mutable: " + lb.name);
rlm@10 4054 MaybePrimitiveExpr me = (MaybePrimitiveExpr) val;
rlm@10 4055 me.emitUnboxed(C.EXPRESSION, this, gen);
rlm@10 4056 gen.putField(objtype, lb.name, Type.getType(primc));
rlm@10 4057 }
rlm@10 4058 else
rlm@10 4059 {
rlm@10 4060 val.emit(C.EXPRESSION, this, gen);
rlm@10 4061 gen.putField(objtype, lb.name, OBJECT_TYPE);
rlm@10 4062 }
rlm@10 4063 }
rlm@10 4064
rlm@10 4065 private void emitLocal(GeneratorAdapter gen, LocalBinding lb, boolean clear){
rlm@10 4066 if(closes.containsKey(lb))
rlm@10 4067 {
rlm@10 4068 Class primc = lb.getPrimitiveType();
rlm@10 4069 gen.loadThis();
rlm@10 4070 if(primc != null)
rlm@10 4071 {
rlm@10 4072 gen.getField(objtype, lb.name, Type.getType(primc));
rlm@10 4073 HostExpr.emitBoxReturn(this, gen, primc);
rlm@10 4074 }
rlm@10 4075 else
rlm@10 4076 {
rlm@10 4077 gen.getField(objtype, lb.name, OBJECT_TYPE);
rlm@10 4078 if(onceOnly && clear && lb.canBeCleared)
rlm@10 4079 {
rlm@10 4080 gen.loadThis();
rlm@10 4081 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4082 gen.putField(objtype, lb.name, OBJECT_TYPE);
rlm@10 4083 }
rlm@10 4084 }
rlm@10 4085 }
rlm@10 4086 else
rlm@10 4087 {
rlm@10 4088 Class primc = lb.getPrimitiveType();
rlm@10 4089 // String rep = lb.sym.name + " " + lb.toString().substring(lb.toString().lastIndexOf('@'));
rlm@10 4090 if(lb.isArg)
rlm@10 4091 {
rlm@10 4092 gen.loadArg(lb.idx-1);
rlm@10 4093 if(primc != null)
rlm@10 4094 HostExpr.emitBoxReturn(this, gen, primc);
rlm@10 4095 else
rlm@10 4096 {
rlm@10 4097 if(clear && lb.canBeCleared)
rlm@10 4098 {
rlm@10 4099 // System.out.println("clear: " + rep);
rlm@10 4100 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4101 gen.storeArg(lb.idx - 1);
rlm@10 4102 }
rlm@10 4103 else
rlm@10 4104 {
rlm@10 4105 // System.out.println("use: " + rep);
rlm@10 4106 }
rlm@10 4107 }
rlm@10 4108 }
rlm@10 4109 else
rlm@10 4110 {
rlm@10 4111 if(primc != null)
rlm@10 4112 {
rlm@10 4113 gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ILOAD), lb.idx);
rlm@10 4114 HostExpr.emitBoxReturn(this, gen, primc);
rlm@10 4115 }
rlm@10 4116 else
rlm@10 4117 {
rlm@10 4118 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), lb.idx);
rlm@10 4119 if(clear && lb.canBeCleared)
rlm@10 4120 {
rlm@10 4121 // System.out.println("clear: " + rep);
rlm@10 4122 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4123 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), lb.idx);
rlm@10 4124 }
rlm@10 4125 else
rlm@10 4126 {
rlm@10 4127 // System.out.println("use: " + rep);
rlm@10 4128 }
rlm@10 4129 }
rlm@10 4130 }
rlm@10 4131 }
rlm@10 4132 }
rlm@10 4133
rlm@10 4134 private void emitUnboxedLocal(GeneratorAdapter gen, LocalBinding lb){
rlm@10 4135 Class primc = lb.getPrimitiveType();
rlm@10 4136 if(closes.containsKey(lb))
rlm@10 4137 {
rlm@10 4138 gen.loadThis();
rlm@10 4139 gen.getField(objtype, lb.name, Type.getType(primc));
rlm@10 4140 }
rlm@10 4141 else if(lb.isArg)
rlm@10 4142 gen.loadArg(lb.idx-1);
rlm@10 4143 else
rlm@10 4144 gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ILOAD), lb.idx);
rlm@10 4145 }
rlm@10 4146
rlm@10 4147 public void emitVar(GeneratorAdapter gen, Var var){
rlm@10 4148 Integer i = (Integer) vars.valAt(var);
rlm@10 4149 emitConstant(gen, i);
rlm@10 4150 //gen.getStatic(fntype, munge(var.sym.toString()), VAR_TYPE);
rlm@10 4151 }
rlm@10 4152
rlm@10 4153 public void emitKeyword(GeneratorAdapter gen, Keyword k){
rlm@10 4154 Integer i = (Integer) keywords.valAt(k);
rlm@10 4155 emitConstant(gen, i);
rlm@10 4156 // gen.getStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
rlm@10 4157 }
rlm@10 4158
rlm@10 4159 public void emitConstant(GeneratorAdapter gen, int id){
rlm@10 4160 gen.getStatic(objtype, constantName(id), constantType(id));
rlm@10 4161 }
rlm@10 4162
rlm@10 4163
rlm@10 4164 String constantName(int id){
rlm@10 4165 return CONST_PREFIX + id;
rlm@10 4166 }
rlm@10 4167
rlm@10 4168 String siteName(int n){
rlm@10 4169 return "__site__" + n;
rlm@10 4170 }
rlm@10 4171
rlm@10 4172 String siteNameStatic(int n){
rlm@10 4173 return siteName(n) + "__";
rlm@10 4174 }
rlm@10 4175
rlm@10 4176 String thunkName(int n){
rlm@10 4177 return "__thunk__" + n;
rlm@10 4178 }
rlm@10 4179
rlm@10 4180 String cachedClassName(int n){
rlm@10 4181 return "__cached_class__" + n;
rlm@10 4182 }
rlm@10 4183
rlm@10 4184 String cachedProtoFnName(int n){
rlm@10 4185 return "__cached_proto_fn__" + n;
rlm@10 4186 }
rlm@10 4187
rlm@10 4188 String cachedProtoImplName(int n){
rlm@10 4189 return "__cached_proto_impl__" + n;
rlm@10 4190 }
rlm@10 4191
rlm@10 4192 String varCallsiteName(int n){
rlm@10 4193 return "__var__callsite__" + n;
rlm@10 4194 }
rlm@10 4195
rlm@10 4196 String thunkNameStatic(int n){
rlm@10 4197 return thunkName(n) + "__";
rlm@10 4198 }
rlm@10 4199
rlm@10 4200 Type constantType(int id){
rlm@10 4201 Object o = constants.nth(id);
rlm@10 4202 Class c = o.getClass();
rlm@10 4203 if(Modifier.isPublic(c.getModifiers()))
rlm@10 4204 {
rlm@10 4205 //can't emit derived fn types due to visibility
rlm@10 4206 if(LazySeq.class.isAssignableFrom(c))
rlm@10 4207 return Type.getType(ISeq.class);
rlm@10 4208 else if(c == Keyword.class)
rlm@10 4209 return Type.getType(Keyword.class);
rlm@10 4210 // else if(c == KeywordCallSite.class)
rlm@10 4211 // return Type.getType(KeywordCallSite.class);
rlm@10 4212 else if(RestFn.class.isAssignableFrom(c))
rlm@10 4213 return Type.getType(RestFn.class);
rlm@10 4214 else if(AFn.class.isAssignableFrom(c))
rlm@10 4215 return Type.getType(AFn.class);
rlm@10 4216 else if(c == Var.class)
rlm@10 4217 return Type.getType(Var.class);
rlm@10 4218 else if(c == String.class)
rlm@10 4219 return Type.getType(String.class);
rlm@10 4220
rlm@10 4221 // return Type.getType(c);
rlm@10 4222 }
rlm@10 4223 return OBJECT_TYPE;
rlm@10 4224 }
rlm@10 4225
rlm@10 4226 }
rlm@10 4227
rlm@10 4228 enum PATHTYPE {
rlm@10 4229 PATH, BRANCH;
rlm@10 4230 }
rlm@10 4231
rlm@10 4232 static class PathNode{
rlm@10 4233 final PATHTYPE type;
rlm@10 4234 final PathNode parent;
rlm@10 4235
rlm@10 4236 PathNode(PATHTYPE type, PathNode parent) {
rlm@10 4237 this.type = type;
rlm@10 4238 this.parent = parent;
rlm@10 4239 }
rlm@10 4240 }
rlm@10 4241
rlm@10 4242 static PathNode clearPathRoot(){
rlm@10 4243 return (PathNode) CLEAR_ROOT.get();
rlm@10 4244 }
rlm@10 4245
rlm@10 4246 enum PSTATE{
rlm@10 4247 REQ, REST, DONE
rlm@10 4248 }
rlm@10 4249
rlm@10 4250 public static class FnMethod extends ObjMethod{
rlm@10 4251 //localbinding->localbinding
rlm@10 4252 PersistentVector reqParms = PersistentVector.EMPTY;
rlm@10 4253 LocalBinding restParm = null;
rlm@10 4254
rlm@10 4255 public FnMethod(ObjExpr objx, ObjMethod parent){
rlm@10 4256 super(objx, parent);
rlm@10 4257 }
rlm@10 4258
rlm@10 4259 static FnMethod parse(ObjExpr objx, ISeq form) throws Exception{
rlm@10 4260 //([args] body...)
rlm@10 4261 IPersistentVector parms = (IPersistentVector) RT.first(form);
rlm@10 4262 ISeq body = RT.next(form);
rlm@10 4263 try
rlm@10 4264 {
rlm@10 4265 FnMethod method = new FnMethod(objx, (ObjMethod) METHOD.deref());
rlm@10 4266 method.line = (Integer) LINE.deref();
rlm@10 4267 //register as the current method and set up a new env frame
rlm@10 4268 PathNode pnode = (PathNode) CLEAR_PATH.get();
rlm@10 4269 if(pnode == null)
rlm@10 4270 pnode = new PathNode(PATHTYPE.PATH,null);
rlm@10 4271 Var.pushThreadBindings(
rlm@10 4272 RT.map(
rlm@10 4273 METHOD, method,
rlm@10 4274 LOCAL_ENV, LOCAL_ENV.deref(),
rlm@10 4275 LOOP_LOCALS, null,
rlm@10 4276 NEXT_LOCAL_NUM, 0
rlm@10 4277 ,CLEAR_PATH, pnode
rlm@10 4278 ,CLEAR_ROOT, pnode
rlm@10 4279 ,CLEAR_SITES, PersistentHashMap.EMPTY
rlm@10 4280 ));
rlm@10 4281
rlm@10 4282 //register 'this' as local 0
rlm@10 4283 //registerLocal(THISFN, null, null);
rlm@10 4284 if(objx.thisName != null)
rlm@10 4285 registerLocal(Symbol.intern(objx.thisName), null, null,false);
rlm@10 4286 else
rlm@10 4287 getAndIncLocalNum();
rlm@10 4288 PSTATE state = PSTATE.REQ;
rlm@10 4289 PersistentVector argLocals = PersistentVector.EMPTY;
rlm@10 4290 for(int i = 0; i < parms.count(); i++)
rlm@10 4291 {
rlm@10 4292 if(!(parms.nth(i) instanceof Symbol))
rlm@10 4293 throw new IllegalArgumentException("fn params must be Symbols");
rlm@10 4294 Symbol p = (Symbol) parms.nth(i);
rlm@10 4295 if(p.getNamespace() != null)
rlm@10 4296 throw new Exception("Can't use qualified name as parameter: " + p);
rlm@10 4297 if(p.equals(_AMP_))
rlm@10 4298 {
rlm@10 4299 if(state == PSTATE.REQ)
rlm@10 4300 state = PSTATE.REST;
rlm@10 4301 else
rlm@10 4302 throw new Exception("Invalid parameter list");
rlm@10 4303 }
rlm@10 4304
rlm@10 4305 else
rlm@10 4306 {
rlm@10 4307 LocalBinding lb = registerLocal(p, state == PSTATE.REST ? ISEQ : tagOf(p), null,true);
rlm@10 4308 argLocals = argLocals.cons(lb);
rlm@10 4309 switch(state)
rlm@10 4310 {
rlm@10 4311 case REQ:
rlm@10 4312 method.reqParms = method.reqParms.cons(lb);
rlm@10 4313 break;
rlm@10 4314 case REST:
rlm@10 4315 method.restParm = lb;
rlm@10 4316 state = PSTATE.DONE;
rlm@10 4317 break;
rlm@10 4318
rlm@10 4319 default:
rlm@10 4320 throw new Exception("Unexpected parameter");
rlm@10 4321 }
rlm@10 4322 }
rlm@10 4323 }
rlm@10 4324 if(method.reqParms.count() > MAX_POSITIONAL_ARITY)
rlm@10 4325 throw new Exception("Can't specify more than " + MAX_POSITIONAL_ARITY + " params");
rlm@10 4326 LOOP_LOCALS.set(argLocals);
rlm@10 4327 method.argLocals = argLocals;
rlm@10 4328 method.body = (new BodyExpr.Parser()).parse(C.RETURN, body);
rlm@10 4329 return method;
rlm@10 4330 }
rlm@10 4331 finally
rlm@10 4332 {
rlm@10 4333 Var.popThreadBindings();
rlm@10 4334 }
rlm@10 4335 }
rlm@10 4336
rlm@10 4337 public final PersistentVector reqParms(){
rlm@10 4338 return reqParms;
rlm@10 4339 }
rlm@10 4340
rlm@10 4341 public final LocalBinding restParm(){
rlm@10 4342 return restParm;
rlm@10 4343 }
rlm@10 4344
rlm@10 4345 boolean isVariadic(){
rlm@10 4346 return restParm != null;
rlm@10 4347 }
rlm@10 4348
rlm@10 4349 int numParams(){
rlm@10 4350 return reqParms.count() + (isVariadic() ? 1 : 0);
rlm@10 4351 }
rlm@10 4352
rlm@10 4353 String getMethodName(){
rlm@10 4354 return isVariadic()?"doInvoke":"invoke";
rlm@10 4355 }
rlm@10 4356
rlm@10 4357 Type getReturnType(){
rlm@10 4358 return OBJECT_TYPE;
rlm@10 4359 }
rlm@10 4360
rlm@10 4361 Type[] getArgTypes(){
rlm@10 4362 if(isVariadic() && reqParms.count() == MAX_POSITIONAL_ARITY)
rlm@10 4363 {
rlm@10 4364 Type[] ret = new Type[MAX_POSITIONAL_ARITY + 1];
rlm@10 4365 for(int i = 0;i<MAX_POSITIONAL_ARITY + 1;i++)
rlm@10 4366 ret[i] = OBJECT_TYPE;
rlm@10 4367 return ret;
rlm@10 4368 }
rlm@10 4369 return ARG_TYPES[numParams()];
rlm@10 4370 }
rlm@10 4371
rlm@10 4372 void emitClearLocals(GeneratorAdapter gen){
rlm@10 4373 // for(int i = 1; i < numParams() + 1; i++)
rlm@10 4374 // {
rlm@10 4375 // if(!localsUsedInCatchFinally.contains(i))
rlm@10 4376 // {
rlm@10 4377 // gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4378 // gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i);
rlm@10 4379 // }
rlm@10 4380 // }
rlm@10 4381 // for(int i = numParams() + 1; i < maxLocal + 1; i++)
rlm@10 4382 // {
rlm@10 4383 // if(!localsUsedInCatchFinally.contains(i))
rlm@10 4384 // {
rlm@10 4385 // LocalBinding b = (LocalBinding) RT.get(indexlocals, i);
rlm@10 4386 // if(b == null || maybePrimitiveType(b.init) == null)
rlm@10 4387 // {
rlm@10 4388 // gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4389 // gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i);
rlm@10 4390 // }
rlm@10 4391 // }
rlm@10 4392 // }
rlm@10 4393 // if(((FnExpr)objx).onceOnly)
rlm@10 4394 // {
rlm@10 4395 // objx.emitClearCloses(gen);
rlm@10 4396 // }
rlm@10 4397 }
rlm@10 4398 }
rlm@10 4399
rlm@10 4400 abstract public static class ObjMethod{
rlm@10 4401 //when closures are defined inside other closures,
rlm@10 4402 //the closed over locals need to be propagated to the enclosing objx
rlm@10 4403 public final ObjMethod parent;
rlm@10 4404 //localbinding->localbinding
rlm@10 4405 IPersistentMap locals = null;
rlm@10 4406 //num->localbinding
rlm@10 4407 IPersistentMap indexlocals = null;
rlm@10 4408 Expr body = null;
rlm@10 4409 ObjExpr objx;
rlm@10 4410 PersistentVector argLocals;
rlm@10 4411 int maxLocal = 0;
rlm@10 4412 int line;
rlm@10 4413 PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY;
rlm@10 4414 protected IPersistentMap methodMeta;
rlm@10 4415
rlm@10 4416 public final IPersistentMap locals(){
rlm@10 4417 return locals;
rlm@10 4418 }
rlm@10 4419
rlm@10 4420 public final Expr body(){
rlm@10 4421 return body;
rlm@10 4422 }
rlm@10 4423
rlm@10 4424 public final ObjExpr objx(){
rlm@10 4425 return objx;
rlm@10 4426 }
rlm@10 4427
rlm@10 4428 public final PersistentVector argLocals(){
rlm@10 4429 return argLocals;
rlm@10 4430 }
rlm@10 4431
rlm@10 4432 public final int maxLocal(){
rlm@10 4433 return maxLocal;
rlm@10 4434 }
rlm@10 4435
rlm@10 4436 public final int line(){
rlm@10 4437 return line;
rlm@10 4438 }
rlm@10 4439
rlm@10 4440 public ObjMethod(ObjExpr objx, ObjMethod parent){
rlm@10 4441 this.parent = parent;
rlm@10 4442 this.objx = objx;
rlm@10 4443 }
rlm@10 4444
rlm@10 4445 abstract int numParams();
rlm@10 4446 abstract String getMethodName();
rlm@10 4447 abstract Type getReturnType();
rlm@10 4448 abstract Type[] getArgTypes();
rlm@10 4449
rlm@10 4450 public void emit(ObjExpr fn, ClassVisitor cv){
rlm@10 4451 Method m = new Method(getMethodName(), getReturnType(), getArgTypes());
rlm@10 4452
rlm@10 4453 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 4454 m,
rlm@10 4455 null,
rlm@10 4456 //todo don't hardwire this
rlm@10 4457 EXCEPTION_TYPES,
rlm@10 4458 cv);
rlm@10 4459 gen.visitCode();
rlm@10 4460 Label loopLabel = gen.mark();
rlm@10 4461 gen.visitLineNumber(line, loopLabel);
rlm@10 4462 try
rlm@10 4463 {
rlm@10 4464 Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this));
rlm@10 4465 body.emit(C.RETURN, fn, gen);
rlm@10 4466 Label end = gen.mark();
rlm@10 4467 gen.visitLocalVariable("this", "Ljava/lang/Object;", null, loopLabel, end, 0);
rlm@10 4468 for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next())
rlm@10 4469 {
rlm@10 4470 LocalBinding lb = (LocalBinding) lbs.first();
rlm@10 4471 gen.visitLocalVariable(lb.name, "Ljava/lang/Object;", null, loopLabel, end, lb.idx);
rlm@10 4472 }
rlm@10 4473 }
rlm@10 4474 finally
rlm@10 4475 {
rlm@10 4476 Var.popThreadBindings();
rlm@10 4477 }
rlm@10 4478
rlm@10 4479 gen.returnValue();
rlm@10 4480 //gen.visitMaxs(1, 1);
rlm@10 4481 gen.endMethod();
rlm@10 4482 }
rlm@10 4483
rlm@10 4484 void emitClearLocals(GeneratorAdapter gen){
rlm@10 4485 }
rlm@10 4486
rlm@10 4487 void emitClearLocalsOld(GeneratorAdapter gen){
rlm@10 4488 for(int i=0;i<argLocals.count();i++)
rlm@10 4489 {
rlm@10 4490 LocalBinding lb = (LocalBinding) argLocals.nth(i);
rlm@10 4491 if(!localsUsedInCatchFinally.contains(lb.idx) && lb.getPrimitiveType() == null)
rlm@10 4492 {
rlm@10 4493 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4494 gen.storeArg(lb.idx - 1);
rlm@10 4495 }
rlm@10 4496
rlm@10 4497 }
rlm@10 4498 // for(int i = 1; i < numParams() + 1; i++)
rlm@10 4499 // {
rlm@10 4500 // if(!localsUsedInCatchFinally.contains(i))
rlm@10 4501 // {
rlm@10 4502 // gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4503 // gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i);
rlm@10 4504 // }
rlm@10 4505 // }
rlm@10 4506 for(int i = numParams() + 1; i < maxLocal + 1; i++)
rlm@10 4507 {
rlm@10 4508 if(!localsUsedInCatchFinally.contains(i))
rlm@10 4509 {
rlm@10 4510 LocalBinding b = (LocalBinding) RT.get(indexlocals, i);
rlm@10 4511 if(b == null || maybePrimitiveType(b.init) == null)
rlm@10 4512 {
rlm@10 4513 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4514 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i);
rlm@10 4515 }
rlm@10 4516 }
rlm@10 4517 }
rlm@10 4518 }
rlm@10 4519 }
rlm@10 4520
rlm@10 4521 public static class LocalBinding{
rlm@10 4522 public final Symbol sym;
rlm@10 4523 public final Symbol tag;
rlm@10 4524 public Expr init;
rlm@10 4525 public final int idx;
rlm@10 4526 public final String name;
rlm@10 4527 public final boolean isArg;
rlm@10 4528 public final PathNode clearPathRoot;
rlm@10 4529 public boolean canBeCleared = true;
rlm@10 4530
rlm@10 4531 public LocalBinding(int num, Symbol sym, Symbol tag, Expr init, boolean isArg,PathNode clearPathRoot)
rlm@10 4532 throws Exception{
rlm@10 4533 if(maybePrimitiveType(init) != null && tag != null)
rlm@10 4534 throw new UnsupportedOperationException("Can't type hint a local with a primitive initializer");
rlm@10 4535 this.idx = num;
rlm@10 4536 this.sym = sym;
rlm@10 4537 this.tag = tag;
rlm@10 4538 this.init = init;
rlm@10 4539 this.isArg = isArg;
rlm@10 4540 this.clearPathRoot = clearPathRoot;
rlm@10 4541 name = munge(sym.name);
rlm@10 4542 }
rlm@10 4543
rlm@10 4544 public boolean hasJavaClass() throws Exception{
rlm@10 4545 if(init != null && init.hasJavaClass()
rlm@10 4546 && Util.isPrimitive(init.getJavaClass())
rlm@10 4547 && !(init instanceof MaybePrimitiveExpr))
rlm@10 4548 return false;
rlm@10 4549 return tag != null
rlm@10 4550 || (init != null && init.hasJavaClass());
rlm@10 4551 }
rlm@10 4552
rlm@10 4553 public Class getJavaClass() throws Exception{
rlm@10 4554 return tag != null ? HostExpr.tagToClass(tag)
rlm@10 4555 : init.getJavaClass();
rlm@10 4556 }
rlm@10 4557
rlm@10 4558 public Class getPrimitiveType(){
rlm@10 4559 return maybePrimitiveType(init);
rlm@10 4560 }
rlm@10 4561 }
rlm@10 4562
rlm@10 4563 public static class LocalBindingExpr implements Expr, MaybePrimitiveExpr, AssignableExpr{
rlm@10 4564 public final LocalBinding b;
rlm@10 4565 public final Symbol tag;
rlm@10 4566
rlm@10 4567 public final PathNode clearPath;
rlm@10 4568 public final PathNode clearRoot;
rlm@10 4569 public boolean shouldClear = false;
rlm@10 4570
rlm@10 4571
rlm@10 4572 public LocalBindingExpr(LocalBinding b, Symbol tag)
rlm@10 4573 throws Exception{
rlm@10 4574 if(b.getPrimitiveType() != null && tag != null)
rlm@10 4575 throw new UnsupportedOperationException("Can't type hint a primitive local");
rlm@10 4576 this.b = b;
rlm@10 4577 this.tag = tag;
rlm@10 4578
rlm@10 4579 this.clearPath = (PathNode)CLEAR_PATH.get();
rlm@10 4580 this.clearRoot = (PathNode)CLEAR_ROOT.get();
rlm@10 4581 IPersistentCollection sites = (IPersistentCollection) RT.get(CLEAR_SITES.get(),b);
rlm@10 4582
rlm@10 4583 if(b.idx > 0)
rlm@10 4584 {
rlm@10 4585 // Object dummy;
rlm@10 4586
rlm@10 4587 if(sites != null)
rlm@10 4588 {
rlm@10 4589 for(ISeq s = sites.seq();s!=null;s = s.next())
rlm@10 4590 {
rlm@10 4591 LocalBindingExpr o = (LocalBindingExpr) s.first();
rlm@10 4592 PathNode common = commonPath(clearPath,o.clearPath);
rlm@10 4593 if(common != null && common.type == PATHTYPE.PATH)
rlm@10 4594 o.shouldClear = false;
rlm@10 4595 // else
rlm@10 4596 // dummy = null;
rlm@10 4597 }
rlm@10 4598 }
rlm@10 4599
rlm@10 4600 if(clearRoot == b.clearPathRoot)
rlm@10 4601 {
rlm@10 4602 this.shouldClear = true;
rlm@10 4603 sites = RT.conj(sites,this);
rlm@10 4604 CLEAR_SITES.set(RT.assoc(CLEAR_SITES.get(), b, sites));
rlm@10 4605 }
rlm@10 4606 // else
rlm@10 4607 // dummy = null;
rlm@10 4608 }
rlm@10 4609 }
rlm@10 4610
rlm@10 4611 public Object eval() throws Exception{
rlm@10 4612 throw new UnsupportedOperationException("Can't eval locals");
rlm@10 4613 }
rlm@10 4614
rlm@10 4615 public boolean canEmitPrimitive(){
rlm@10 4616 return b.getPrimitiveType() != null;
rlm@10 4617 }
rlm@10 4618
rlm@10 4619 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4620 objx.emitUnboxedLocal(gen, b);
rlm@10 4621 }
rlm@10 4622
rlm@10 4623 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4624 if(context != C.STATEMENT)
rlm@10 4625 objx.emitLocal(gen, b, shouldClear);
rlm@10 4626 }
rlm@10 4627
rlm@10 4628 public Object evalAssign(Expr val) throws Exception{
rlm@10 4629 throw new UnsupportedOperationException("Can't eval locals");
rlm@10 4630 }
rlm@10 4631
rlm@10 4632 public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, Expr val){
rlm@10 4633 objx.emitAssignLocal(gen, b,val);
rlm@10 4634 if(context != C.STATEMENT)
rlm@10 4635 objx.emitLocal(gen, b, false);
rlm@10 4636 }
rlm@10 4637
rlm@10 4638 public boolean hasJavaClass() throws Exception{
rlm@10 4639 return tag != null || b.hasJavaClass();
rlm@10 4640 }
rlm@10 4641
rlm@10 4642 public Class getJavaClass() throws Exception{
rlm@10 4643 if(tag != null)
rlm@10 4644 return HostExpr.tagToClass(tag);
rlm@10 4645 return b.getJavaClass();
rlm@10 4646 }
rlm@10 4647
rlm@10 4648
rlm@10 4649 }
rlm@10 4650
rlm@10 4651 public static class BodyExpr implements Expr, MaybePrimitiveExpr{
rlm@10 4652 PersistentVector exprs;
rlm@10 4653
rlm@10 4654 public final PersistentVector exprs(){
rlm@10 4655 return exprs;
rlm@10 4656 }
rlm@10 4657
rlm@10 4658 public BodyExpr(PersistentVector exprs){
rlm@10 4659 this.exprs = exprs;
rlm@10 4660 }
rlm@10 4661
rlm@10 4662 static class Parser implements IParser{
rlm@10 4663 public Expr parse(C context, Object frms) throws Exception{
rlm@10 4664 ISeq forms = (ISeq) frms;
rlm@10 4665 if(Util.equals(RT.first(forms), DO))
rlm@10 4666 forms = RT.next(forms);
rlm@10 4667 PersistentVector exprs = PersistentVector.EMPTY;
rlm@10 4668 for(; forms != null; forms = forms.next())
rlm@10 4669 {
rlm@10 4670 Expr e = (context != C.EVAL &&
rlm@10 4671 (context == C.STATEMENT || forms.next() != null)) ?
rlm@10 4672 analyze(C.STATEMENT, forms.first())
rlm@10 4673 :
rlm@10 4674 analyze(context, forms.first());
rlm@10 4675 exprs = exprs.cons(e);
rlm@10 4676 }
rlm@10 4677 if(exprs.count() == 0)
rlm@10 4678 exprs = exprs.cons(NIL_EXPR);
rlm@10 4679 return new BodyExpr(exprs);
rlm@10 4680 }
rlm@10 4681 }
rlm@10 4682
rlm@10 4683 public Object eval() throws Exception{
rlm@10 4684 Object ret = null;
rlm@10 4685 for(Object o : exprs)
rlm@10 4686 {
rlm@10 4687 Expr e = (Expr) o;
rlm@10 4688 ret = e.eval();
rlm@10 4689 }
rlm@10 4690 return ret;
rlm@10 4691 }
rlm@10 4692
rlm@10 4693 public boolean canEmitPrimitive(){
rlm@10 4694 return lastExpr() instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr)lastExpr()).canEmitPrimitive();
rlm@10 4695 }
rlm@10 4696
rlm@10 4697 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4698 for(int i = 0; i < exprs.count() - 1; i++)
rlm@10 4699 {
rlm@10 4700 Expr e = (Expr) exprs.nth(i);
rlm@10 4701 e.emit(C.STATEMENT, objx, gen);
rlm@10 4702 }
rlm@10 4703 MaybePrimitiveExpr last = (MaybePrimitiveExpr) exprs.nth(exprs.count() - 1);
rlm@10 4704 last.emitUnboxed(context, objx, gen);
rlm@10 4705 }
rlm@10 4706
rlm@10 4707 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4708 for(int i = 0; i < exprs.count() - 1; i++)
rlm@10 4709 {
rlm@10 4710 Expr e = (Expr) exprs.nth(i);
rlm@10 4711 e.emit(C.STATEMENT, objx, gen);
rlm@10 4712 }
rlm@10 4713 Expr last = (Expr) exprs.nth(exprs.count() - 1);
rlm@10 4714 last.emit(context, objx, gen);
rlm@10 4715 }
rlm@10 4716
rlm@10 4717 public boolean hasJavaClass() throws Exception{
rlm@10 4718 return lastExpr().hasJavaClass();
rlm@10 4719 }
rlm@10 4720
rlm@10 4721 public Class getJavaClass() throws Exception{
rlm@10 4722 return lastExpr().getJavaClass();
rlm@10 4723 }
rlm@10 4724
rlm@10 4725 private Expr lastExpr(){
rlm@10 4726 return (Expr) exprs.nth(exprs.count() - 1);
rlm@10 4727 }
rlm@10 4728 }
rlm@10 4729
rlm@10 4730 public static class BindingInit{
rlm@10 4731 LocalBinding binding;
rlm@10 4732 Expr init;
rlm@10 4733
rlm@10 4734 public final LocalBinding binding(){
rlm@10 4735 return binding;
rlm@10 4736 }
rlm@10 4737
rlm@10 4738 public final Expr init(){
rlm@10 4739 return init;
rlm@10 4740 }
rlm@10 4741
rlm@10 4742 public BindingInit(LocalBinding binding, Expr init){
rlm@10 4743 this.binding = binding;
rlm@10 4744 this.init = init;
rlm@10 4745 }
rlm@10 4746 }
rlm@10 4747
rlm@10 4748 public static class LetFnExpr implements Expr{
rlm@10 4749 public final PersistentVector bindingInits;
rlm@10 4750 public final Expr body;
rlm@10 4751
rlm@10 4752 public LetFnExpr(PersistentVector bindingInits, Expr body){
rlm@10 4753 this.bindingInits = bindingInits;
rlm@10 4754 this.body = body;
rlm@10 4755 }
rlm@10 4756
rlm@10 4757 static class Parser implements IParser{
rlm@10 4758 public Expr parse(C context, Object frm) throws Exception{
rlm@10 4759 ISeq form = (ISeq) frm;
rlm@10 4760 //(letfns* [var (fn [args] body) ...] body...)
rlm@10 4761 if(!(RT.second(form) instanceof IPersistentVector))
rlm@10 4762 throw new IllegalArgumentException("Bad binding form, expected vector");
rlm@10 4763
rlm@10 4764 IPersistentVector bindings = (IPersistentVector) RT.second(form);
rlm@10 4765 if((bindings.count() % 2) != 0)
rlm@10 4766 throw new IllegalArgumentException("Bad binding form, expected matched symbol expression pairs");
rlm@10 4767
rlm@10 4768 ISeq body = RT.next(RT.next(form));
rlm@10 4769
rlm@10 4770 if(context == C.EVAL)
rlm@10 4771 return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
rlm@10 4772
rlm@10 4773 IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(),
rlm@10 4774 NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref());
rlm@10 4775
rlm@10 4776 try
rlm@10 4777 {
rlm@10 4778 Var.pushThreadBindings(dynamicBindings);
rlm@10 4779
rlm@10 4780 //pre-seed env (like Lisp labels)
rlm@10 4781 PersistentVector lbs = PersistentVector.EMPTY;
rlm@10 4782 for(int i = 0; i < bindings.count(); i += 2)
rlm@10 4783 {
rlm@10 4784 if(!(bindings.nth(i) instanceof Symbol))
rlm@10 4785 throw new IllegalArgumentException(
rlm@10 4786 "Bad binding form, expected symbol, got: " + bindings.nth(i));
rlm@10 4787 Symbol sym = (Symbol) bindings.nth(i);
rlm@10 4788 if(sym.getNamespace() != null)
rlm@10 4789 throw new Exception("Can't let qualified name: " + sym);
rlm@10 4790 LocalBinding lb = registerLocal(sym, tagOf(sym), null,false);
rlm@10 4791 lb.canBeCleared = false;
rlm@10 4792 lbs = lbs.cons(lb);
rlm@10 4793 }
rlm@10 4794 PersistentVector bindingInits = PersistentVector.EMPTY;
rlm@10 4795 for(int i = 0; i < bindings.count(); i += 2)
rlm@10 4796 {
rlm@10 4797 Symbol sym = (Symbol) bindings.nth(i);
rlm@10 4798 Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name);
rlm@10 4799 LocalBinding lb = (LocalBinding) lbs.nth(i / 2);
rlm@10 4800 lb.init = init;
rlm@10 4801 BindingInit bi = new BindingInit(lb, init);
rlm@10 4802 bindingInits = bindingInits.cons(bi);
rlm@10 4803 }
rlm@10 4804 return new LetFnExpr(bindingInits, (new BodyExpr.Parser()).parse(context, body));
rlm@10 4805 }
rlm@10 4806 finally
rlm@10 4807 {
rlm@10 4808 Var.popThreadBindings();
rlm@10 4809 }
rlm@10 4810 }
rlm@10 4811 }
rlm@10 4812
rlm@10 4813 public Object eval() throws Exception{
rlm@10 4814 throw new UnsupportedOperationException("Can't eval letfns");
rlm@10 4815 }
rlm@10 4816
rlm@10 4817 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4818 for(int i = 0; i < bindingInits.count(); i++)
rlm@10 4819 {
rlm@10 4820 BindingInit bi = (BindingInit) bindingInits.nth(i);
rlm@10 4821 gen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 4822 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), bi.binding.idx);
rlm@10 4823 }
rlm@10 4824
rlm@10 4825 IPersistentSet lbset = PersistentHashSet.EMPTY;
rlm@10 4826
rlm@10 4827 for(int i = 0; i < bindingInits.count(); i++)
rlm@10 4828 {
rlm@10 4829 BindingInit bi = (BindingInit) bindingInits.nth(i);
rlm@10 4830 lbset = (IPersistentSet) lbset.cons(bi.binding);
rlm@10 4831 bi.init.emit(C.EXPRESSION, objx, gen);
rlm@10 4832 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), bi.binding.idx);
rlm@10 4833 }
rlm@10 4834
rlm@10 4835 for(int i = 0; i < bindingInits.count(); i++)
rlm@10 4836 {
rlm@10 4837 BindingInit bi = (BindingInit) bindingInits.nth(i);
rlm@10 4838 ObjExpr fe = (ObjExpr) bi.init;
rlm@10 4839 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), bi.binding.idx);
rlm@10 4840 fe.emitLetFnInits(gen, objx, lbset);
rlm@10 4841 }
rlm@10 4842
rlm@10 4843 Label loopLabel = gen.mark();
rlm@10 4844
rlm@10 4845 body.emit(context, objx, gen);
rlm@10 4846
rlm@10 4847 Label end = gen.mark();
rlm@10 4848 // gen.visitLocalVariable("this", "Ljava/lang/Object;", null, loopLabel, end, 0);
rlm@10 4849 for(ISeq bis = bindingInits.seq(); bis != null; bis = bis.next())
rlm@10 4850 {
rlm@10 4851 BindingInit bi = (BindingInit) bis.first();
rlm@10 4852 String lname = bi.binding.name;
rlm@10 4853 if(lname.endsWith("__auto__"))
rlm@10 4854 lname += RT.nextID();
rlm@10 4855 Class primc = maybePrimitiveType(bi.init);
rlm@10 4856 if(primc != null)
rlm@10 4857 gen.visitLocalVariable(lname, Type.getDescriptor(primc), null, loopLabel, end,
rlm@10 4858 bi.binding.idx);
rlm@10 4859 else
rlm@10 4860 gen.visitLocalVariable(lname, "Ljava/lang/Object;", null, loopLabel, end, bi.binding.idx);
rlm@10 4861 }
rlm@10 4862 }
rlm@10 4863
rlm@10 4864 public boolean hasJavaClass() throws Exception{
rlm@10 4865 return body.hasJavaClass();
rlm@10 4866 }
rlm@10 4867
rlm@10 4868 public Class getJavaClass() throws Exception{
rlm@10 4869 return body.getJavaClass();
rlm@10 4870 }
rlm@10 4871 }
rlm@10 4872
rlm@10 4873 public static class LetExpr implements Expr, MaybePrimitiveExpr{
rlm@10 4874 public final PersistentVector bindingInits;
rlm@10 4875 public final Expr body;
rlm@10 4876 public final boolean isLoop;
rlm@10 4877
rlm@10 4878 public LetExpr(PersistentVector bindingInits, Expr body, boolean isLoop){
rlm@10 4879 this.bindingInits = bindingInits;
rlm@10 4880 this.body = body;
rlm@10 4881 this.isLoop = isLoop;
rlm@10 4882 }
rlm@10 4883
rlm@10 4884 static class Parser implements IParser{
rlm@10 4885 public Expr parse(C context, Object frm) throws Exception{
rlm@10 4886 ISeq form = (ISeq) frm;
rlm@10 4887 //(let [var val var2 val2 ...] body...)
rlm@10 4888 boolean isLoop = RT.first(form).equals(LOOP);
rlm@10 4889 if(!(RT.second(form) instanceof IPersistentVector))
rlm@10 4890 throw new IllegalArgumentException("Bad binding form, expected vector");
rlm@10 4891
rlm@10 4892 IPersistentVector bindings = (IPersistentVector) RT.second(form);
rlm@10 4893 if((bindings.count() % 2) != 0)
rlm@10 4894 throw new IllegalArgumentException("Bad binding form, expected matched symbol expression pairs");
rlm@10 4895
rlm@10 4896 ISeq body = RT.next(RT.next(form));
rlm@10 4897
rlm@10 4898 if(context == C.EVAL
rlm@10 4899 || (context == C.EXPRESSION && isLoop))
rlm@10 4900 return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
rlm@10 4901
rlm@10 4902 IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(),
rlm@10 4903 NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref());
rlm@10 4904 if(isLoop)
rlm@10 4905 dynamicBindings = dynamicBindings.assoc(LOOP_LOCALS, null);
rlm@10 4906
rlm@10 4907 try
rlm@10 4908 {
rlm@10 4909 Var.pushThreadBindings(dynamicBindings);
rlm@10 4910
rlm@10 4911 PersistentVector bindingInits = PersistentVector.EMPTY;
rlm@10 4912 PersistentVector loopLocals = PersistentVector.EMPTY;
rlm@10 4913 for(int i = 0; i < bindings.count(); i += 2)
rlm@10 4914 {
rlm@10 4915 if(!(bindings.nth(i) instanceof Symbol))
rlm@10 4916 throw new IllegalArgumentException(
rlm@10 4917 "Bad binding form, expected symbol, got: " + bindings.nth(i));
rlm@10 4918 Symbol sym = (Symbol) bindings.nth(i);
rlm@10 4919 if(sym.getNamespace() != null)
rlm@10 4920 throw new Exception("Can't let qualified name: " + sym);
rlm@10 4921 Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name);
rlm@10 4922 //sequential enhancement of env (like Lisp let*)
rlm@10 4923 LocalBinding lb = registerLocal(sym, tagOf(sym), init,false);
rlm@10 4924 BindingInit bi = new BindingInit(lb, init);
rlm@10 4925 bindingInits = bindingInits.cons(bi);
rlm@10 4926
rlm@10 4927 if(isLoop)
rlm@10 4928 loopLocals = loopLocals.cons(lb);
rlm@10 4929 }
rlm@10 4930 if(isLoop)
rlm@10 4931 LOOP_LOCALS.set(loopLocals);
rlm@10 4932 Expr bodyExpr;
rlm@10 4933 try {
rlm@10 4934 if(isLoop)
rlm@10 4935 {
rlm@10 4936 PathNode root = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get());
rlm@10 4937 Var.pushThreadBindings(
rlm@10 4938 RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,root),
rlm@10 4939 CLEAR_ROOT, new PathNode(PATHTYPE.PATH,root)));
rlm@10 4940 }
rlm@10 4941 bodyExpr = (new BodyExpr.Parser()).parse(isLoop ? C.RETURN : context, body);
rlm@10 4942 }
rlm@10 4943 finally{
rlm@10 4944 if(isLoop)
rlm@10 4945 Var.popThreadBindings();
rlm@10 4946 }
rlm@10 4947 return new LetExpr(bindingInits, bodyExpr,
rlm@10 4948 isLoop);
rlm@10 4949 }
rlm@10 4950 finally
rlm@10 4951 {
rlm@10 4952 Var.popThreadBindings();
rlm@10 4953 }
rlm@10 4954 }
rlm@10 4955 }
rlm@10 4956
rlm@10 4957 public Object eval() throws Exception{
rlm@10 4958 throw new UnsupportedOperationException("Can't eval let/loop");
rlm@10 4959 }
rlm@10 4960
rlm@10 4961 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4962 doEmit(context, objx, gen, false);
rlm@10 4963 }
rlm@10 4964
rlm@10 4965 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 4966 doEmit(context, objx, gen, true);
rlm@10 4967 }
rlm@10 4968
rlm@10 4969
rlm@10 4970 public void doEmit(C context, ObjExpr objx, GeneratorAdapter gen, boolean emitUnboxed){
rlm@10 4971 for(int i = 0; i < bindingInits.count(); i++)
rlm@10 4972 {
rlm@10 4973 BindingInit bi = (BindingInit) bindingInits.nth(i);
rlm@10 4974 Class primc = maybePrimitiveType(bi.init);
rlm@10 4975 if(primc != null)
rlm@10 4976 {
rlm@10 4977 ((MaybePrimitiveExpr) bi.init).emitUnboxed(C.EXPRESSION, objx, gen);
rlm@10 4978 gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ISTORE), bi.binding.idx);
rlm@10 4979 }
rlm@10 4980 else
rlm@10 4981 {
rlm@10 4982 bi.init.emit(C.EXPRESSION, objx, gen);
rlm@10 4983 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), bi.binding.idx);
rlm@10 4984 }
rlm@10 4985 }
rlm@10 4986 Label loopLabel = gen.mark();
rlm@10 4987 if(isLoop)
rlm@10 4988 {
rlm@10 4989 try
rlm@10 4990 {
rlm@10 4991 Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel));
rlm@10 4992 if(emitUnboxed)
rlm@10 4993 ((MaybePrimitiveExpr)body).emitUnboxed(context, objx, gen);
rlm@10 4994 else
rlm@10 4995 body.emit(context, objx, gen);
rlm@10 4996 }
rlm@10 4997 finally
rlm@10 4998 {
rlm@10 4999 Var.popThreadBindings();
rlm@10 5000 }
rlm@10 5001 }
rlm@10 5002 else
rlm@10 5003 {
rlm@10 5004 if(emitUnboxed)
rlm@10 5005 ((MaybePrimitiveExpr)body).emitUnboxed(context, objx, gen);
rlm@10 5006 else
rlm@10 5007 body.emit(context, objx, gen);
rlm@10 5008 }
rlm@10 5009 Label end = gen.mark();
rlm@10 5010 // gen.visitLocalVariable("this", "Ljava/lang/Object;", null, loopLabel, end, 0);
rlm@10 5011 for(ISeq bis = bindingInits.seq(); bis != null; bis = bis.next())
rlm@10 5012 {
rlm@10 5013 BindingInit bi = (BindingInit) bis.first();
rlm@10 5014 String lname = bi.binding.name;
rlm@10 5015 if(lname.endsWith("__auto__"))
rlm@10 5016 lname += RT.nextID();
rlm@10 5017 Class primc = maybePrimitiveType(bi.init);
rlm@10 5018 if(primc != null)
rlm@10 5019 gen.visitLocalVariable(lname, Type.getDescriptor(primc), null, loopLabel, end,
rlm@10 5020 bi.binding.idx);
rlm@10 5021 else
rlm@10 5022 gen.visitLocalVariable(lname, "Ljava/lang/Object;", null, loopLabel, end, bi.binding.idx);
rlm@10 5023 }
rlm@10 5024 }
rlm@10 5025
rlm@10 5026 public boolean hasJavaClass() throws Exception{
rlm@10 5027 return body.hasJavaClass();
rlm@10 5028 }
rlm@10 5029
rlm@10 5030 public Class getJavaClass() throws Exception{
rlm@10 5031 return body.getJavaClass();
rlm@10 5032 }
rlm@10 5033
rlm@10 5034 public boolean canEmitPrimitive(){
rlm@10 5035 return body instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr)body).canEmitPrimitive();
rlm@10 5036 }
rlm@10 5037
rlm@10 5038 }
rlm@10 5039
rlm@10 5040 public static class RecurExpr implements Expr{
rlm@10 5041 public final IPersistentVector args;
rlm@10 5042 public final IPersistentVector loopLocals;
rlm@10 5043
rlm@10 5044 public RecurExpr(IPersistentVector loopLocals, IPersistentVector args){
rlm@10 5045 this.loopLocals = loopLocals;
rlm@10 5046 this.args = args;
rlm@10 5047 }
rlm@10 5048
rlm@10 5049 public Object eval() throws Exception{
rlm@10 5050 throw new UnsupportedOperationException("Can't eval recur");
rlm@10 5051 }
rlm@10 5052
rlm@10 5053 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 5054 Label loopLabel = (Label) LOOP_LABEL.deref();
rlm@10 5055 if(loopLabel == null)
rlm@10 5056 throw new IllegalStateException();
rlm@10 5057 for(int i = 0; i < loopLocals.count(); i++)
rlm@10 5058 {
rlm@10 5059 LocalBinding lb = (LocalBinding) loopLocals.nth(i);
rlm@10 5060 Expr arg = (Expr) args.nth(i);
rlm@10 5061 if(lb.getPrimitiveType() != null)
rlm@10 5062 {
rlm@10 5063 Class primc = lb.getPrimitiveType();
rlm@10 5064 try
rlm@10 5065 {
rlm@10 5066 if(!(arg instanceof MaybePrimitiveExpr && arg.hasJavaClass() && arg.getJavaClass() == primc))
rlm@10 5067 throw new IllegalArgumentException("recur arg for primitive local: " +
rlm@10 5068 lb.name + " must be matching primitive");
rlm@10 5069 }
rlm@10 5070 catch(Exception e)
rlm@10 5071 {
rlm@10 5072 throw new RuntimeException(e);
rlm@10 5073 }
rlm@10 5074 ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen);
rlm@10 5075 }
rlm@10 5076 else
rlm@10 5077 {
rlm@10 5078 arg.emit(C.EXPRESSION, objx, gen);
rlm@10 5079 }
rlm@10 5080 }
rlm@10 5081
rlm@10 5082 for(int i = loopLocals.count() - 1; i >= 0; i--)
rlm@10 5083 {
rlm@10 5084 LocalBinding lb = (LocalBinding) loopLocals.nth(i);
rlm@10 5085 Class primc = lb.getPrimitiveType();
rlm@10 5086 if(lb.isArg)
rlm@10 5087 gen.storeArg(lb.idx-1);
rlm@10 5088 else
rlm@10 5089 {
rlm@10 5090 if(primc != null)
rlm@10 5091 gen.visitVarInsn(Type.getType(primc).getOpcode(Opcodes.ISTORE), lb.idx);
rlm@10 5092 else
rlm@10 5093 gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), lb.idx);
rlm@10 5094 }
rlm@10 5095 }
rlm@10 5096
rlm@10 5097 gen.goTo(loopLabel);
rlm@10 5098 }
rlm@10 5099
rlm@10 5100 public boolean hasJavaClass() throws Exception{
rlm@10 5101 return true;
rlm@10 5102 }
rlm@10 5103
rlm@10 5104 public Class getJavaClass() throws Exception{
rlm@10 5105 return null;
rlm@10 5106 }
rlm@10 5107
rlm@10 5108 static class Parser implements IParser{
rlm@10 5109 public Expr parse(C context, Object frm) throws Exception{
rlm@10 5110 ISeq form = (ISeq) frm;
rlm@10 5111 IPersistentVector loopLocals = (IPersistentVector) LOOP_LOCALS.deref();
rlm@10 5112 if(context != C.RETURN || loopLocals == null)
rlm@10 5113 throw new UnsupportedOperationException("Can only recur from tail position");
rlm@10 5114 if(IN_CATCH_FINALLY.deref() != null)
rlm@10 5115 throw new UnsupportedOperationException("Cannot recur from catch/finally");
rlm@10 5116 PersistentVector args = PersistentVector.EMPTY;
rlm@10 5117 for(ISeq s = RT.seq(form.next()); s != null; s = s.next())
rlm@10 5118 {
rlm@10 5119 args = args.cons(analyze(C.EXPRESSION, s.first()));
rlm@10 5120 }
rlm@10 5121 if(args.count() != loopLocals.count())
rlm@10 5122 throw new IllegalArgumentException(
rlm@10 5123 String.format("Mismatched argument count to recur, expected: %d args, got: %d",
rlm@10 5124 loopLocals.count(), args.count()));
rlm@10 5125 return new RecurExpr(loopLocals, args);
rlm@10 5126 }
rlm@10 5127 }
rlm@10 5128 }
rlm@10 5129
rlm@10 5130 private static LocalBinding registerLocal(Symbol sym, Symbol tag, Expr init, boolean isArg) throws Exception{
rlm@10 5131 int num = getAndIncLocalNum();
rlm@10 5132 LocalBinding b = new LocalBinding(num, sym, tag, init, isArg, clearPathRoot());
rlm@10 5133 IPersistentMap localsMap = (IPersistentMap) LOCAL_ENV.deref();
rlm@10 5134 LOCAL_ENV.set(RT.assoc(localsMap, b.sym, b));
rlm@10 5135 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 5136 method.locals = (IPersistentMap) RT.assoc(method.locals, b, b);
rlm@10 5137 method.indexlocals = (IPersistentMap) RT.assoc(method.indexlocals, num, b);
rlm@10 5138 return b;
rlm@10 5139 }
rlm@10 5140
rlm@10 5141 private static int getAndIncLocalNum(){
rlm@10 5142 int num = ((Number) NEXT_LOCAL_NUM.deref()).intValue();
rlm@10 5143 ObjMethod m = (ObjMethod) METHOD.deref();
rlm@10 5144 if(num > m.maxLocal)
rlm@10 5145 m.maxLocal = num;
rlm@10 5146 NEXT_LOCAL_NUM.set(num + 1);
rlm@10 5147 return num;
rlm@10 5148 }
rlm@10 5149
rlm@10 5150 public static Expr analyze(C context, Object form) throws Exception{
rlm@10 5151 return analyze(context, form, null);
rlm@10 5152 }
rlm@10 5153
rlm@10 5154 private static Expr analyze(C context, Object form, String name) throws Exception{
rlm@10 5155 //todo symbol macro expansion?
rlm@10 5156 try
rlm@10 5157 {
rlm@10 5158 if(form instanceof LazySeq)
rlm@10 5159 {
rlm@10 5160 form = RT.seq(form);
rlm@10 5161 if(form == null)
rlm@10 5162 form = PersistentList.EMPTY;
rlm@10 5163 }
rlm@10 5164 if(form == null)
rlm@10 5165 return NIL_EXPR;
rlm@10 5166 else if(form == Boolean.TRUE)
rlm@10 5167 return TRUE_EXPR;
rlm@10 5168 else if(form == Boolean.FALSE)
rlm@10 5169 return FALSE_EXPR;
rlm@10 5170 Class fclass = form.getClass();
rlm@10 5171 if(fclass == Symbol.class)
rlm@10 5172 return analyzeSymbol((Symbol) form);
rlm@10 5173 else if(fclass == Keyword.class)
rlm@10 5174 return registerKeyword((Keyword) form);
rlm@10 5175 // else if(form instanceof Num)
rlm@10 5176 // return new NumExpr((Num) form);
rlm@10 5177 else if(fclass == String.class)
rlm@10 5178 return new StringExpr(((String) form).intern());
rlm@10 5179 // else if(fclass == Character.class)
rlm@10 5180 // return new CharExpr((Character) form);
rlm@10 5181 else if(form instanceof IPersistentCollection && ((IPersistentCollection) form).count() == 0)
rlm@10 5182 {
rlm@10 5183 Expr ret = new EmptyExpr(form);
rlm@10 5184 if(RT.meta(form) != null)
rlm@10 5185 ret = new MetaExpr(ret, (MapExpr) MapExpr
rlm@10 5186 .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta()));
rlm@10 5187 return ret;
rlm@10 5188 }
rlm@10 5189 else if(form instanceof ISeq)
rlm@10 5190 return analyzeSeq(context, (ISeq) form, name);
rlm@10 5191 else if(form instanceof IPersistentVector)
rlm@10 5192 return VectorExpr.parse(context, (IPersistentVector) form);
rlm@10 5193 else if(form instanceof IPersistentMap)
rlm@10 5194 return MapExpr.parse(context, (IPersistentMap) form);
rlm@10 5195 else if(form instanceof IPersistentSet)
rlm@10 5196 return SetExpr.parse(context, (IPersistentSet) form);
rlm@10 5197
rlm@10 5198 // else
rlm@10 5199 //throw new UnsupportedOperationException();
rlm@10 5200 return new ConstantExpr(form);
rlm@10 5201 }
rlm@10 5202 catch(Throwable e)
rlm@10 5203 {
rlm@10 5204 if(!(e instanceof CompilerException))
rlm@10 5205 throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e);
rlm@10 5206 else
rlm@10 5207 throw (CompilerException) e;
rlm@10 5208 }
rlm@10 5209 }
rlm@10 5210
rlm@10 5211 static public class CompilerException extends Exception{
rlm@10 5212
rlm@10 5213 public CompilerException(String source, int line, Throwable cause){
rlm@10 5214 super(errorMsg(source, line, cause.toString()), cause);
rlm@10 5215 }
rlm@10 5216
rlm@10 5217 public String toString(){
rlm@10 5218 return getMessage();
rlm@10 5219 }
rlm@10 5220 }
rlm@10 5221
rlm@10 5222 static public Var isMacro(Object op) throws Exception{
rlm@10 5223 //no local macros for now
rlm@10 5224 if(op instanceof Symbol && referenceLocal((Symbol) op) != null)
rlm@10 5225 return null;
rlm@10 5226 if(op instanceof Symbol || op instanceof Var)
rlm@10 5227 {
rlm@10 5228 Var v = (op instanceof Var) ? (Var) op : lookupVar((Symbol) op, false);
rlm@10 5229 if(v != null && v.isMacro())
rlm@10 5230 {
rlm@10 5231 if(v.ns != currentNS() && !v.isPublic())
rlm@10 5232 throw new IllegalStateException("var: " + v + " is not public");
rlm@10 5233 return v;
rlm@10 5234 }
rlm@10 5235 }
rlm@10 5236 return null;
rlm@10 5237 }
rlm@10 5238
rlm@10 5239 static public IFn isInline(Object op, int arity) throws Exception{
rlm@10 5240 //no local inlines for now
rlm@10 5241 if(op instanceof Symbol && referenceLocal((Symbol) op) != null)
rlm@10 5242 return null;
rlm@10 5243 if(op instanceof Symbol || op instanceof Var)
rlm@10 5244 {
rlm@10 5245 Var v = (op instanceof Var) ? (Var) op : lookupVar((Symbol) op, false);
rlm@10 5246 if(v != null)
rlm@10 5247 {
rlm@10 5248 if(v.ns != currentNS() && !v.isPublic())
rlm@10 5249 throw new IllegalStateException("var: " + v + " is not public");
rlm@10 5250 IFn ret = (IFn) RT.get(v.meta(), inlineKey);
rlm@10 5251 if(ret != null)
rlm@10 5252 {
rlm@10 5253 IFn arityPred = (IFn) RT.get(v.meta(), inlineAritiesKey);
rlm@10 5254 if(arityPred == null || RT.booleanCast(arityPred.invoke(arity)))
rlm@10 5255 return ret;
rlm@10 5256 }
rlm@10 5257 }
rlm@10 5258 }
rlm@10 5259 return null;
rlm@10 5260 }
rlm@10 5261
rlm@10 5262 public static boolean namesStaticMember(Symbol sym){
rlm@10 5263 return sym.ns != null && namespaceFor(sym) == null;
rlm@10 5264 }
rlm@10 5265
rlm@10 5266 public static Object preserveTag(ISeq src, Object dst) {
rlm@10 5267 Symbol tag = tagOf(src);
rlm@10 5268 if (tag != null && dst instanceof IObj) {
rlm@10 5269 IPersistentMap meta = RT.meta(dst);
rlm@10 5270 return ((IObj) dst).withMeta((IPersistentMap) RT.assoc(meta, RT.TAG_KEY, tag));
rlm@10 5271 }
rlm@10 5272 return dst;
rlm@10 5273 }
rlm@10 5274
rlm@10 5275 public static Object macroexpand1(Object x) throws Exception{
rlm@10 5276 if(x instanceof ISeq)
rlm@10 5277 {
rlm@10 5278 ISeq form = (ISeq) x;
rlm@10 5279 Object op = RT.first(form);
rlm@10 5280 if(isSpecial(op))
rlm@10 5281 return x;
rlm@10 5282 //macro expansion
rlm@10 5283 Var v = isMacro(op);
rlm@10 5284 if(v != null)
rlm@10 5285 {
rlm@10 5286 return v.applyTo(RT.cons(form,RT.cons(LOCAL_ENV.get(),form.next())));
rlm@10 5287 }
rlm@10 5288 else
rlm@10 5289 {
rlm@10 5290 if(op instanceof Symbol)
rlm@10 5291 {
rlm@10 5292 Symbol sym = (Symbol) op;
rlm@10 5293 String sname = sym.name;
rlm@10 5294 //(.substring s 2 5) => (. s substring 2 5)
rlm@10 5295 if(sym.name.charAt(0) == '.')
rlm@10 5296 {
rlm@10 5297 if(RT.length(form) < 2)
rlm@10 5298 throw new IllegalArgumentException(
rlm@10 5299 "Malformed member expression, expecting (.member target ...)");
rlm@10 5300 Symbol meth = Symbol.intern(sname.substring(1));
rlm@10 5301 Object target = RT.second(form);
rlm@10 5302 if(HostExpr.maybeClass(target, false) != null)
rlm@10 5303 {
rlm@10 5304 target = ((IObj)RT.list(IDENTITY, target)).withMeta(RT.map(RT.TAG_KEY,CLASS));
rlm@10 5305 }
rlm@10 5306 return preserveTag(form, RT.listStar(DOT, target, meth, form.next().next()));
rlm@10 5307 }
rlm@10 5308 else if(namesStaticMember(sym))
rlm@10 5309 {
rlm@10 5310 Symbol target = Symbol.intern(sym.ns);
rlm@10 5311 Class c = HostExpr.maybeClass(target, false);
rlm@10 5312 if(c != null)
rlm@10 5313 {
rlm@10 5314 Symbol meth = Symbol.intern(sym.name);
rlm@10 5315 return preserveTag(form, RT.listStar(DOT, target, meth, form.next()));
rlm@10 5316 }
rlm@10 5317 }
rlm@10 5318 else
rlm@10 5319 {
rlm@10 5320 //(s.substring 2 5) => (. s substring 2 5)
rlm@10 5321 //also (package.class.name ...) (. package.class name ...)
rlm@10 5322 int idx = sname.lastIndexOf('.');
rlm@10 5323 // if(idx > 0 && idx < sname.length() - 1)
rlm@10 5324 // {
rlm@10 5325 // Symbol target = Symbol.intern(sname.substring(0, idx));
rlm@10 5326 // Symbol meth = Symbol.intern(sname.substring(idx + 1));
rlm@10 5327 // return RT.listStar(DOT, target, meth, form.rest());
rlm@10 5328 // }
rlm@10 5329 //(StringBuilder. "foo") => (new StringBuilder "foo")
rlm@10 5330 //else
rlm@10 5331 if(idx == sname.length() - 1)
rlm@10 5332 return RT.listStar(NEW, Symbol.intern(sname.substring(0, idx)), form.next());
rlm@10 5333 }
rlm@10 5334 }
rlm@10 5335 }
rlm@10 5336 }
rlm@10 5337 return x;
rlm@10 5338 }
rlm@10 5339
rlm@10 5340 static Object macroexpand(Object form) throws Exception{
rlm@10 5341 Object exf = macroexpand1(form);
rlm@10 5342 if(exf != form)
rlm@10 5343 return macroexpand(exf);
rlm@10 5344 return form;
rlm@10 5345 }
rlm@10 5346
rlm@10 5347 private static Expr analyzeSeq(C context, ISeq form, String name) throws Exception{
rlm@10 5348 Integer line = (Integer) LINE.deref();
rlm@10 5349 if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY))
rlm@10 5350 line = (Integer) RT.meta(form).valAt(RT.LINE_KEY);
rlm@10 5351 Var.pushThreadBindings(
rlm@10 5352 RT.map(LINE, line));
rlm@10 5353 try
rlm@10 5354 {
rlm@10 5355 Object me = macroexpand1(form);
rlm@10 5356 if(me != form)
rlm@10 5357 return analyze(context, me, name);
rlm@10 5358
rlm@10 5359 Object op = RT.first(form);
rlm@10 5360 if(op == null)
rlm@10 5361 throw new IllegalArgumentException("Can't call nil");
rlm@10 5362 IFn inline = isInline(op, RT.count(RT.next(form)));
rlm@10 5363 if(inline != null)
rlm@10 5364 return analyze(context, preserveTag(form, inline.applyTo(RT.next(form))));
rlm@10 5365 IParser p;
rlm@10 5366 if(op.equals(FN))
rlm@10 5367 return FnExpr.parse(context, form, name);
rlm@10 5368 else if((p = (IParser) specials.valAt(op)) != null)
rlm@10 5369 return p.parse(context, form);
rlm@10 5370 else
rlm@10 5371 return InvokeExpr.parse(context, form);
rlm@10 5372 }
rlm@10 5373 catch(Throwable e)
rlm@10 5374 {
rlm@10 5375 if(!(e instanceof CompilerException))
rlm@10 5376 throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e);
rlm@10 5377 else
rlm@10 5378 throw (CompilerException) e;
rlm@10 5379 }
rlm@10 5380 finally
rlm@10 5381 {
rlm@10 5382 Var.popThreadBindings();
rlm@10 5383 }
rlm@10 5384 }
rlm@10 5385
rlm@10 5386 static String errorMsg(String source, int line, String s){
rlm@10 5387 return String.format("%s (%s:%d)", s, source, line);
rlm@10 5388 }
rlm@10 5389
rlm@10 5390 public static Object eval(Object form) throws Exception{
rlm@10 5391 return eval(form, true);
rlm@10 5392 }
rlm@10 5393
rlm@10 5394 public static Object eval(Object form, boolean freshLoader) throws Exception{
rlm@10 5395 boolean createdLoader = false;
rlm@10 5396 if(true)//!LOADER.isBound())
rlm@10 5397 {
rlm@10 5398 Var.pushThreadBindings(RT.map(LOADER, RT.makeClassLoader()));
rlm@10 5399 createdLoader = true;
rlm@10 5400 }
rlm@10 5401 try
rlm@10 5402 {
rlm@10 5403 Integer line = (Integer) LINE.deref();
rlm@10 5404 if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY))
rlm@10 5405 line = (Integer) RT.meta(form).valAt(RT.LINE_KEY);
rlm@10 5406 Var.pushThreadBindings(RT.map(LINE, line));
rlm@10 5407 try
rlm@10 5408 {
rlm@10 5409 form = macroexpand(form);
rlm@10 5410 if(form instanceof IPersistentCollection && Util.equals(RT.first(form), DO))
rlm@10 5411 {
rlm@10 5412 ISeq s = RT.next(form);
rlm@10 5413 for(; RT.next(s) != null; s = RT.next(s))
rlm@10 5414 eval(RT.first(s),false);
rlm@10 5415 return eval(RT.first(s),false);
rlm@10 5416 }
rlm@10 5417 else if(form instanceof IPersistentCollection
rlm@10 5418 && !(RT.first(form) instanceof Symbol
rlm@10 5419 && ((Symbol) RT.first(form)).name.startsWith("def")))
rlm@10 5420 {
rlm@10 5421 ObjExpr fexpr = (ObjExpr) analyze(C.EXPRESSION, RT.list(FN, PersistentVector.EMPTY, form),
rlm@10 5422 "eval" + RT.nextID());
rlm@10 5423 IFn fn = (IFn) fexpr.eval();
rlm@10 5424 return fn.invoke();
rlm@10 5425 }
rlm@10 5426 else
rlm@10 5427 {
rlm@10 5428 Expr expr = analyze(C.EVAL, form);
rlm@10 5429 return expr.eval();
rlm@10 5430 }
rlm@10 5431 }
rlm@10 5432 finally
rlm@10 5433 {
rlm@10 5434 Var.popThreadBindings();
rlm@10 5435 }
rlm@10 5436 }
rlm@10 5437 catch(Throwable e)
rlm@10 5438 {
rlm@10 5439 if(!(e instanceof CompilerException))
rlm@10 5440 throw new CompilerException((String) SOURCE.deref(), (Integer) LINE.deref(), e);
rlm@10 5441 else
rlm@10 5442 throw (CompilerException) e;
rlm@10 5443 }
rlm@10 5444 finally
rlm@10 5445 {
rlm@10 5446 if(createdLoader)
rlm@10 5447 Var.popThreadBindings();
rlm@10 5448 }
rlm@10 5449 }
rlm@10 5450
rlm@10 5451 private static int registerConstant(Object o){
rlm@10 5452 if(!CONSTANTS.isBound())
rlm@10 5453 return -1;
rlm@10 5454 PersistentVector v = (PersistentVector) CONSTANTS.deref();
rlm@10 5455 IdentityHashMap<Object,Integer> ids = (IdentityHashMap<Object,Integer>) CONSTANT_IDS.deref();
rlm@10 5456 Integer i = ids.get(o);
rlm@10 5457 if(i != null)
rlm@10 5458 return i;
rlm@10 5459 CONSTANTS.set(RT.conj(v, o));
rlm@10 5460 ids.put(o, v.count());
rlm@10 5461 return v.count();
rlm@10 5462 }
rlm@10 5463
rlm@10 5464 private static KeywordExpr registerKeyword(Keyword keyword){
rlm@10 5465 if(!KEYWORDS.isBound())
rlm@10 5466 return new KeywordExpr(keyword);
rlm@10 5467
rlm@10 5468 IPersistentMap keywordsMap = (IPersistentMap) KEYWORDS.deref();
rlm@10 5469 Object id = RT.get(keywordsMap, keyword);
rlm@10 5470 if(id == null)
rlm@10 5471 {
rlm@10 5472 KEYWORDS.set(RT.assoc(keywordsMap, keyword, registerConstant(keyword)));
rlm@10 5473 }
rlm@10 5474 return new KeywordExpr(keyword);
rlm@10 5475 // KeywordExpr ke = (KeywordExpr) RT.get(keywordsMap, keyword);
rlm@10 5476 // if(ke == null)
rlm@10 5477 // KEYWORDS.set(RT.assoc(keywordsMap, keyword, ke = new KeywordExpr(keyword)));
rlm@10 5478 // return ke;
rlm@10 5479 }
rlm@10 5480
rlm@10 5481 private static int registerKeywordCallsite(Keyword keyword){
rlm@10 5482 if(!KEYWORD_CALLSITES.isBound())
rlm@10 5483 throw new IllegalAccessError("KEYWORD_CALLSITES is not bound");
rlm@10 5484
rlm@10 5485 IPersistentVector keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref();
rlm@10 5486
rlm@10 5487 keywordCallsites = keywordCallsites.cons(keyword);
rlm@10 5488 KEYWORD_CALLSITES.set(keywordCallsites);
rlm@10 5489 return keywordCallsites.count()-1;
rlm@10 5490 }
rlm@10 5491
rlm@10 5492 private static int registerProtocolCallsite(Var v){
rlm@10 5493 if(!PROTOCOL_CALLSITES.isBound())
rlm@10 5494 throw new IllegalAccessError("PROTOCOL_CALLSITES is not bound");
rlm@10 5495
rlm@10 5496 IPersistentVector protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref();
rlm@10 5497
rlm@10 5498 protocolCallsites = protocolCallsites.cons(v);
rlm@10 5499 PROTOCOL_CALLSITES.set(protocolCallsites);
rlm@10 5500 return protocolCallsites.count()-1;
rlm@10 5501 }
rlm@10 5502
rlm@10 5503 private static int registerVarCallsite(Var v){
rlm@10 5504 if(!VAR_CALLSITES.isBound())
rlm@10 5505 throw new IllegalAccessError("VAR_CALLSITES is not bound");
rlm@10 5506
rlm@10 5507 IPersistentVector varCallsites = (IPersistentVector) VAR_CALLSITES.deref();
rlm@10 5508
rlm@10 5509 varCallsites = varCallsites.cons(v);
rlm@10 5510 VAR_CALLSITES.set(varCallsites);
rlm@10 5511 return varCallsites.count()-1;
rlm@10 5512 }
rlm@10 5513
rlm@10 5514 static ISeq fwdPath(PathNode p1){
rlm@10 5515 ISeq ret = null;
rlm@10 5516 for(;p1 != null;p1 = p1.parent)
rlm@10 5517 ret = RT.cons(p1,ret);
rlm@10 5518 return ret;
rlm@10 5519 }
rlm@10 5520
rlm@10 5521 static PathNode commonPath(PathNode n1, PathNode n2){
rlm@10 5522 ISeq xp = fwdPath(n1);
rlm@10 5523 ISeq yp = fwdPath(n2);
rlm@10 5524 if(RT.first(xp) != RT.first(yp))
rlm@10 5525 return null;
rlm@10 5526 while(RT.second(xp) != null && RT.second(xp) == RT.second(yp))
rlm@10 5527 {
rlm@10 5528 xp = xp.next();
rlm@10 5529 yp = yp.next();
rlm@10 5530 }
rlm@10 5531 return (PathNode) RT.first(xp);
rlm@10 5532 }
rlm@10 5533
rlm@10 5534 static void addAnnotation(Object visitor, IPersistentMap meta){
rlm@10 5535 try{
rlm@10 5536 if(meta != null && ADD_ANNOTATIONS.isBound())
rlm@10 5537 ADD_ANNOTATIONS.invoke(visitor, meta);
rlm@10 5538 }
rlm@10 5539 catch (Exception e)
rlm@10 5540 {
rlm@10 5541 throw new RuntimeException(e);
rlm@10 5542 }
rlm@10 5543 }
rlm@10 5544
rlm@10 5545 static void addParameterAnnotation(Object visitor, IPersistentMap meta, int i){
rlm@10 5546 try{
rlm@10 5547 if(meta != null && ADD_ANNOTATIONS.isBound())
rlm@10 5548 ADD_ANNOTATIONS.invoke(visitor, meta, i);
rlm@10 5549 }
rlm@10 5550 catch (Exception e)
rlm@10 5551 {
rlm@10 5552 throw new RuntimeException(e);
rlm@10 5553 }
rlm@10 5554 }
rlm@10 5555
rlm@10 5556 private static Expr analyzeSymbol(Symbol sym) throws Exception{
rlm@10 5557 Symbol tag = tagOf(sym);
rlm@10 5558 if(sym.ns == null) //ns-qualified syms are always Vars
rlm@10 5559 {
rlm@10 5560 LocalBinding b = referenceLocal(sym);
rlm@10 5561 if(b != null)
rlm@10 5562 {
rlm@10 5563 return new LocalBindingExpr(b, tag);
rlm@10 5564 }
rlm@10 5565 }
rlm@10 5566 else
rlm@10 5567 {
rlm@10 5568 if(namespaceFor(sym) == null)
rlm@10 5569 {
rlm@10 5570 Symbol nsSym = Symbol.create(sym.ns);
rlm@10 5571 Class c = HostExpr.maybeClass(nsSym, false);
rlm@10 5572 if(c != null)
rlm@10 5573 {
rlm@10 5574 if(Reflector.getField(c, sym.name, true) != null)
rlm@10 5575 return new StaticFieldExpr((Integer) LINE.deref(), c, sym.name, tag);
rlm@10 5576 throw new Exception("Unable to find static field: " + sym.name + " in " + c);
rlm@10 5577 }
rlm@10 5578 }
rlm@10 5579 }
rlm@10 5580 //Var v = lookupVar(sym, false);
rlm@10 5581 // Var v = lookupVar(sym, false);
rlm@10 5582 // if(v != null)
rlm@10 5583 // return new VarExpr(v, tag);
rlm@10 5584 Object o = resolve(sym);
rlm@10 5585 if(o instanceof Var)
rlm@10 5586 {
rlm@10 5587 Var v = (Var) o;
rlm@10 5588 if(isMacro(v) != null)
rlm@10 5589 throw new Exception("Can't take value of a macro: " + v);
rlm@10 5590 registerVar(v);
rlm@10 5591 return new VarExpr(v, tag);
rlm@10 5592 }
rlm@10 5593 else if(o instanceof Class)
rlm@10 5594 return new ConstantExpr(o);
rlm@10 5595 else if(o instanceof Symbol)
rlm@10 5596 return new UnresolvedVarExpr((Symbol) o);
rlm@10 5597
rlm@10 5598 throw new Exception("Unable to resolve symbol: " + sym + " in this context");
rlm@10 5599
rlm@10 5600 }
rlm@10 5601
rlm@10 5602 static String destubClassName(String className){
rlm@10 5603 //skip over prefix + '.' or '/'
rlm@10 5604 if(className.startsWith(COMPILE_STUB_PREFIX))
rlm@10 5605 return className.substring(COMPILE_STUB_PREFIX.length()+1);
rlm@10 5606 return className;
rlm@10 5607 }
rlm@10 5608
rlm@10 5609 static Type getType(Class c){
rlm@10 5610 String descriptor = Type.getType(c).getDescriptor();
rlm@10 5611 if(descriptor.startsWith("L"))
rlm@10 5612 descriptor = "L" + destubClassName(descriptor.substring(1));
rlm@10 5613 return Type.getType(descriptor);
rlm@10 5614 }
rlm@10 5615
rlm@10 5616 static Object resolve(Symbol sym, boolean allowPrivate) throws Exception{
rlm@10 5617 return resolveIn(currentNS(), sym, allowPrivate);
rlm@10 5618 }
rlm@10 5619
rlm@10 5620 static Object resolve(Symbol sym) throws Exception{
rlm@10 5621 return resolveIn(currentNS(), sym, false);
rlm@10 5622 }
rlm@10 5623
rlm@10 5624 static Namespace namespaceFor(Symbol sym){
rlm@10 5625 return namespaceFor(currentNS(), sym);
rlm@10 5626 }
rlm@10 5627
rlm@10 5628 static Namespace namespaceFor(Namespace inns, Symbol sym){
rlm@10 5629 //note, presumes non-nil sym.ns
rlm@10 5630 // first check against currentNS' aliases...
rlm@10 5631 Symbol nsSym = Symbol.create(sym.ns);
rlm@10 5632 Namespace ns = inns.lookupAlias(nsSym);
rlm@10 5633 if(ns == null)
rlm@10 5634 {
rlm@10 5635 // ...otherwise check the Namespaces map.
rlm@10 5636 ns = Namespace.find(nsSym);
rlm@10 5637 }
rlm@10 5638 return ns;
rlm@10 5639 }
rlm@10 5640
rlm@10 5641 static public Object resolveIn(Namespace n, Symbol sym, boolean allowPrivate) throws Exception{
rlm@10 5642 //note - ns-qualified vars must already exist
rlm@10 5643 if(sym.ns != null)
rlm@10 5644 {
rlm@10 5645 Namespace ns = namespaceFor(n, sym);
rlm@10 5646 if(ns == null)
rlm@10 5647 throw new Exception("No such namespace: " + sym.ns);
rlm@10 5648
rlm@10 5649 Var v = ns.findInternedVar(Symbol.create(sym.name));
rlm@10 5650 if(v == null)
rlm@10 5651 throw new Exception("No such var: " + sym);
rlm@10 5652 else if(v.ns != currentNS() && !v.isPublic() && !allowPrivate)
rlm@10 5653 throw new IllegalStateException("var: " + sym + " is not public");
rlm@10 5654 return v;
rlm@10 5655 }
rlm@10 5656 else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
rlm@10 5657 {
rlm@10 5658 return RT.classForName(sym.name);
rlm@10 5659 }
rlm@10 5660 else if(sym.equals(NS))
rlm@10 5661 return RT.NS_VAR;
rlm@10 5662 else if(sym.equals(IN_NS))
rlm@10 5663 return RT.IN_NS_VAR;
rlm@10 5664 else
rlm@10 5665 {
rlm@10 5666 if(Util.equals(sym,COMPILE_STUB_SYM.get()))
rlm@10 5667 return COMPILE_STUB_CLASS.get();
rlm@10 5668 Object o = n.getMapping(sym);
rlm@10 5669 if(o == null)
rlm@10 5670 {
rlm@10 5671 if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref()))
rlm@10 5672 {
rlm@10 5673 return sym;
rlm@10 5674 }
rlm@10 5675 else
rlm@10 5676 {
rlm@10 5677 throw new Exception("Unable to resolve symbol: " + sym + " in this context");
rlm@10 5678 }
rlm@10 5679 }
rlm@10 5680 return o;
rlm@10 5681 }
rlm@10 5682 }
rlm@10 5683
rlm@10 5684
rlm@10 5685 static public Object maybeResolveIn(Namespace n, Symbol sym) throws Exception{
rlm@10 5686 //note - ns-qualified vars must already exist
rlm@10 5687 if(sym.ns != null)
rlm@10 5688 {
rlm@10 5689 Namespace ns = namespaceFor(n, sym);
rlm@10 5690 if(ns == null)
rlm@10 5691 return null;
rlm@10 5692 Var v = ns.findInternedVar(Symbol.create(sym.name));
rlm@10 5693 if(v == null)
rlm@10 5694 return null;
rlm@10 5695 return v;
rlm@10 5696 }
rlm@10 5697 else if(sym.name.indexOf('.') > 0 && !sym.name.endsWith(".")
rlm@10 5698 || sym.name.charAt(0) == '[')
rlm@10 5699 {
rlm@10 5700 return RT.classForName(sym.name);
rlm@10 5701 }
rlm@10 5702 else if(sym.equals(NS))
rlm@10 5703 return RT.NS_VAR;
rlm@10 5704 else if(sym.equals(IN_NS))
rlm@10 5705 return RT.IN_NS_VAR;
rlm@10 5706 else
rlm@10 5707 {
rlm@10 5708 Object o = n.getMapping(sym);
rlm@10 5709 return o;
rlm@10 5710 }
rlm@10 5711 }
rlm@10 5712
rlm@10 5713
rlm@10 5714 static Var lookupVar(Symbol sym, boolean internNew) throws Exception{
rlm@10 5715 Var var = null;
rlm@10 5716
rlm@10 5717 //note - ns-qualified vars in other namespaces must already exist
rlm@10 5718 if(sym.ns != null)
rlm@10 5719 {
rlm@10 5720 Namespace ns = namespaceFor(sym);
rlm@10 5721 if(ns == null)
rlm@10 5722 return null;
rlm@10 5723 //throw new Exception("No such namespace: " + sym.ns);
rlm@10 5724 Symbol name = Symbol.create(sym.name);
rlm@10 5725 if(internNew && ns == currentNS())
rlm@10 5726 var = currentNS().intern(name);
rlm@10 5727 else
rlm@10 5728 var = ns.findInternedVar(name);
rlm@10 5729 }
rlm@10 5730 else if(sym.equals(NS))
rlm@10 5731 var = RT.NS_VAR;
rlm@10 5732 else if(sym.equals(IN_NS))
rlm@10 5733 var = RT.IN_NS_VAR;
rlm@10 5734 else
rlm@10 5735 {
rlm@10 5736 //is it mapped?
rlm@10 5737 Object o = currentNS().getMapping(sym);
rlm@10 5738 if(o == null)
rlm@10 5739 {
rlm@10 5740 //introduce a new var in the current ns
rlm@10 5741 if(internNew)
rlm@10 5742 var = currentNS().intern(Symbol.create(sym.name));
rlm@10 5743 }
rlm@10 5744 else if(o instanceof Var)
rlm@10 5745 {
rlm@10 5746 var = (Var) o;
rlm@10 5747 }
rlm@10 5748 else
rlm@10 5749 {
rlm@10 5750 throw new Exception("Expecting var, but " + sym + " is mapped to " + o);
rlm@10 5751 }
rlm@10 5752 }
rlm@10 5753 if(var != null)
rlm@10 5754 registerVar(var);
rlm@10 5755 return var;
rlm@10 5756 }
rlm@10 5757
rlm@10 5758 private static void registerVar(Var var) throws Exception{
rlm@10 5759 if(!VARS.isBound())
rlm@10 5760 return;
rlm@10 5761 IPersistentMap varsMap = (IPersistentMap) VARS.deref();
rlm@10 5762 Object id = RT.get(varsMap, var);
rlm@10 5763 if(id == null)
rlm@10 5764 {
rlm@10 5765 VARS.set(RT.assoc(varsMap, var, registerConstant(var)));
rlm@10 5766 }
rlm@10 5767 // if(varsMap != null && RT.get(varsMap, var) == null)
rlm@10 5768 // VARS.set(RT.assoc(varsMap, var, var));
rlm@10 5769 }
rlm@10 5770
rlm@10 5771 static Namespace currentNS(){
rlm@10 5772 return (Namespace) RT.CURRENT_NS.deref();
rlm@10 5773 }
rlm@10 5774
rlm@10 5775 static void closeOver(LocalBinding b, ObjMethod method){
rlm@10 5776 if(b != null && method != null)
rlm@10 5777 {
rlm@10 5778 if(RT.get(method.locals, b) == null)
rlm@10 5779 {
rlm@10 5780 method.objx.closes = (IPersistentMap) RT.assoc(method.objx.closes, b, b);
rlm@10 5781 closeOver(b, method.parent);
rlm@10 5782 }
rlm@10 5783 else if(IN_CATCH_FINALLY.deref() != null)
rlm@10 5784 {
rlm@10 5785 method.localsUsedInCatchFinally = (PersistentHashSet) method.localsUsedInCatchFinally.cons(b.idx);
rlm@10 5786 }
rlm@10 5787 }
rlm@10 5788 }
rlm@10 5789
rlm@10 5790
rlm@10 5791 static LocalBinding referenceLocal(Symbol sym) throws Exception{
rlm@10 5792 if(!LOCAL_ENV.isBound())
rlm@10 5793 return null;
rlm@10 5794 LocalBinding b = (LocalBinding) RT.get(LOCAL_ENV.deref(), sym);
rlm@10 5795 if(b != null)
rlm@10 5796 {
rlm@10 5797 ObjMethod method = (ObjMethod) METHOD.deref();
rlm@10 5798 closeOver(b, method);
rlm@10 5799 }
rlm@10 5800 return b;
rlm@10 5801 }
rlm@10 5802
rlm@10 5803 private static Symbol tagOf(Object o){
rlm@10 5804 Object tag = RT.get(RT.meta(o), RT.TAG_KEY);
rlm@10 5805 if(tag instanceof Symbol)
rlm@10 5806 return (Symbol) tag;
rlm@10 5807 else if(tag instanceof String)
rlm@10 5808 return Symbol.intern(null, (String) tag);
rlm@10 5809 return null;
rlm@10 5810 }
rlm@10 5811
rlm@10 5812 public static Object loadFile(String file) throws Exception{
rlm@10 5813 // File fo = new File(file);
rlm@10 5814 // if(!fo.exists())
rlm@10 5815 // return null;
rlm@10 5816
rlm@10 5817 FileInputStream f = new FileInputStream(file);
rlm@10 5818 try
rlm@10 5819 {
rlm@10 5820 return load(new InputStreamReader(f, RT.UTF8), new File(file).getAbsolutePath(), (new File(file)).getName());
rlm@10 5821 }
rlm@10 5822 finally
rlm@10 5823 {
rlm@10 5824 f.close();
rlm@10 5825 }
rlm@10 5826 }
rlm@10 5827
rlm@10 5828 public static Object load(Reader rdr) throws Exception{
rlm@10 5829 return load(rdr, null, "NO_SOURCE_FILE");
rlm@10 5830 }
rlm@10 5831
rlm@10 5832 public static Object load(Reader rdr, String sourcePath, String sourceName) throws Exception{
rlm@10 5833 Object EOF = new Object();
rlm@10 5834 Object ret = null;
rlm@10 5835 LineNumberingPushbackReader pushbackReader =
rlm@10 5836 (rdr instanceof LineNumberingPushbackReader) ? (LineNumberingPushbackReader) rdr :
rlm@10 5837 new LineNumberingPushbackReader(rdr);
rlm@10 5838 Var.pushThreadBindings(
rlm@10 5839 RT.map(LOADER, RT.makeClassLoader(),
rlm@10 5840 SOURCE_PATH, sourcePath,
rlm@10 5841 SOURCE, sourceName,
rlm@10 5842 METHOD, null,
rlm@10 5843 LOCAL_ENV, null,
rlm@10 5844 LOOP_LOCALS, null,
rlm@10 5845 NEXT_LOCAL_NUM, 0,
rlm@10 5846 RT.CURRENT_NS, RT.CURRENT_NS.deref(),
rlm@10 5847 LINE_BEFORE, pushbackReader.getLineNumber(),
rlm@10 5848 LINE_AFTER, pushbackReader.getLineNumber()
rlm@10 5849 ));
rlm@10 5850
rlm@10 5851 try
rlm@10 5852 {
rlm@10 5853 for(Object r = LispReader.read(pushbackReader, false, EOF, false); r != EOF;
rlm@10 5854 r = LispReader.read(pushbackReader, false, EOF, false))
rlm@10 5855 {
rlm@10 5856 LINE_AFTER.set(pushbackReader.getLineNumber());
rlm@10 5857 ret = eval(r,false);
rlm@10 5858 LINE_BEFORE.set(pushbackReader.getLineNumber());
rlm@10 5859 }
rlm@10 5860 }
rlm@10 5861 catch(LispReader.ReaderException e)
rlm@10 5862 {
rlm@10 5863 throw new CompilerException(sourceName, e.line, e.getCause());
rlm@10 5864 }
rlm@10 5865 finally
rlm@10 5866 {
rlm@10 5867 Var.popThreadBindings();
rlm@10 5868 }
rlm@10 5869 return ret;
rlm@10 5870 }
rlm@10 5871
rlm@10 5872 static public void writeClassFile(String internalName, byte[] bytecode) throws Exception{
rlm@10 5873 String genPath = (String) COMPILE_PATH.deref();
rlm@10 5874 if(genPath == null)
rlm@10 5875 throw new Exception("*compile-path* not set");
rlm@10 5876 String[] dirs = internalName.split("/");
rlm@10 5877 String p = genPath;
rlm@10 5878 for(int i = 0; i < dirs.length - 1; i++)
rlm@10 5879 {
rlm@10 5880 p += File.separator + dirs[i];
rlm@10 5881 (new File(p)).mkdir();
rlm@10 5882 }
rlm@10 5883 String path = genPath + File.separator + internalName + ".class";
rlm@10 5884 File cf = new File(path);
rlm@10 5885 cf.createNewFile();
rlm@10 5886 FileOutputStream cfs = new FileOutputStream(cf);
rlm@10 5887 try
rlm@10 5888 {
rlm@10 5889 cfs.write(bytecode);
rlm@10 5890 cfs.flush();
rlm@10 5891 cfs.getFD().sync();
rlm@10 5892 }
rlm@10 5893 finally
rlm@10 5894 {
rlm@10 5895 cfs.close();
rlm@10 5896 }
rlm@10 5897 }
rlm@10 5898
rlm@10 5899 public static void pushNS(){
rlm@10 5900 Var.pushThreadBindings(PersistentHashMap.create(Var.intern(Symbol.create("clojure.core"),
rlm@10 5901 Symbol.create("*ns*")), null));
rlm@10 5902 }
rlm@10 5903
rlm@10 5904 public static ILookupThunk getLookupThunk(Object target, Keyword k){
rlm@10 5905 return null; //To change body of created methods use File | Settings | File Templates.
rlm@10 5906 }
rlm@10 5907
rlm@10 5908 static void compile1(GeneratorAdapter gen, ObjExpr objx, Object form) throws Exception{
rlm@10 5909 Integer line = (Integer) LINE.deref();
rlm@10 5910 if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY))
rlm@10 5911 line = (Integer) RT.meta(form).valAt(RT.LINE_KEY);
rlm@10 5912 Var.pushThreadBindings(
rlm@10 5913 RT.map(LINE, line
rlm@10 5914 ,LOADER, RT.makeClassLoader()
rlm@10 5915 ));
rlm@10 5916 try
rlm@10 5917 {
rlm@10 5918 form = macroexpand(form);
rlm@10 5919 if(form instanceof IPersistentCollection && Util.equals(RT.first(form), DO))
rlm@10 5920 {
rlm@10 5921 for(ISeq s = RT.next(form); s != null; s = RT.next(s))
rlm@10 5922 {
rlm@10 5923 compile1(gen, objx, RT.first(s));
rlm@10 5924 }
rlm@10 5925 }
rlm@10 5926 else
rlm@10 5927 {
rlm@10 5928 Expr expr = analyze(C.EVAL, form);
rlm@10 5929 objx.keywords = (IPersistentMap) KEYWORDS.deref();
rlm@10 5930 objx.vars = (IPersistentMap) VARS.deref();
rlm@10 5931 objx.constants = (PersistentVector) CONSTANTS.deref();
rlm@10 5932 expr.emit(C.EXPRESSION, objx, gen);
rlm@10 5933 expr.eval();
rlm@10 5934 }
rlm@10 5935 }
rlm@10 5936 finally
rlm@10 5937 {
rlm@10 5938 Var.popThreadBindings();
rlm@10 5939 }
rlm@10 5940 }
rlm@10 5941
rlm@10 5942 public static Object compile(Reader rdr, String sourcePath, String sourceName) throws Exception{
rlm@10 5943 if(COMPILE_PATH.deref() == null)
rlm@10 5944 throw new Exception("*compile-path* not set");
rlm@10 5945
rlm@10 5946 Object EOF = new Object();
rlm@10 5947 Object ret = null;
rlm@10 5948 LineNumberingPushbackReader pushbackReader =
rlm@10 5949 (rdr instanceof LineNumberingPushbackReader) ? (LineNumberingPushbackReader) rdr :
rlm@10 5950 new LineNumberingPushbackReader(rdr);
rlm@10 5951 Var.pushThreadBindings(
rlm@10 5952 RT.map(SOURCE_PATH, sourcePath,
rlm@10 5953 SOURCE, sourceName,
rlm@10 5954 METHOD, null,
rlm@10 5955 LOCAL_ENV, null,
rlm@10 5956 LOOP_LOCALS, null,
rlm@10 5957 NEXT_LOCAL_NUM, 0,
rlm@10 5958 RT.CURRENT_NS, RT.CURRENT_NS.deref(),
rlm@10 5959 LINE_BEFORE, pushbackReader.getLineNumber(),
rlm@10 5960 LINE_AFTER, pushbackReader.getLineNumber(),
rlm@10 5961 CONSTANTS, PersistentVector.EMPTY,
rlm@10 5962 CONSTANT_IDS, new IdentityHashMap(),
rlm@10 5963 KEYWORDS, PersistentHashMap.EMPTY,
rlm@10 5964 VARS, PersistentHashMap.EMPTY
rlm@10 5965 // ,LOADER, RT.makeClassLoader()
rlm@10 5966 ));
rlm@10 5967
rlm@10 5968 try
rlm@10 5969 {
rlm@10 5970 //generate loader class
rlm@10 5971 ObjExpr objx = new ObjExpr(null);
rlm@10 5972 objx.internalName = sourcePath.replace(File.separator, "/").substring(0, sourcePath.lastIndexOf('.'))
rlm@10 5973 + RT.LOADER_SUFFIX;
rlm@10 5974
rlm@10 5975 objx.objtype = Type.getObjectType(objx.internalName);
rlm@10 5976 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
rlm@10 5977 ClassVisitor cv = cw;
rlm@10 5978 cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, objx.internalName, null, "java/lang/Object", null);
rlm@10 5979
rlm@10 5980 //static load method
rlm@10 5981 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
rlm@10 5982 Method.getMethod("void load ()"),
rlm@10 5983 null,
rlm@10 5984 null,
rlm@10 5985 cv);
rlm@10 5986 gen.visitCode();
rlm@10 5987
rlm@10 5988 for(Object r = LispReader.read(pushbackReader, false, EOF, false); r != EOF;
rlm@10 5989 r = LispReader.read(pushbackReader, false, EOF, false))
rlm@10 5990 {
rlm@10 5991 LINE_AFTER.set(pushbackReader.getLineNumber());
rlm@10 5992 compile1(gen, objx, r);
rlm@10 5993 LINE_BEFORE.set(pushbackReader.getLineNumber());
rlm@10 5994 }
rlm@10 5995 //end of load
rlm@10 5996 gen.returnValue();
rlm@10 5997 gen.endMethod();
rlm@10 5998
rlm@10 5999 //static fields for constants
rlm@10 6000 for(int i = 0; i < objx.constants.count(); i++)
rlm@10 6001 {
rlm@10 6002 cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, objx.constantName(i), objx.constantType(i).getDescriptor(),
rlm@10 6003 null, null);
rlm@10 6004 }
rlm@10 6005
rlm@10 6006 //static init for constants, keywords and vars
rlm@10 6007 GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
rlm@10 6008 Method.getMethod("void <clinit> ()"),
rlm@10 6009 null,
rlm@10 6010 null,
rlm@10 6011 cv);
rlm@10 6012 clinitgen.visitCode();
rlm@10 6013 Label startTry = clinitgen.newLabel();
rlm@10 6014 Label endTry = clinitgen.newLabel();
rlm@10 6015 Label end = clinitgen.newLabel();
rlm@10 6016 Label finallyLabel = clinitgen.newLabel();
rlm@10 6017
rlm@10 6018 if(objx.constants.count() > 0)
rlm@10 6019 {
rlm@10 6020 objx.emitConstants(clinitgen);
rlm@10 6021 }
rlm@10 6022 clinitgen.invokeStatic(Type.getType(Compiler.class), Method.getMethod("void pushNS()"));
rlm@10 6023 clinitgen.mark(startTry);
rlm@10 6024 clinitgen.invokeStatic(objx.objtype, Method.getMethod("void load()"));
rlm@10 6025 clinitgen.mark(endTry);
rlm@10 6026 clinitgen.invokeStatic(VAR_TYPE, Method.getMethod("void popThreadBindings()"));
rlm@10 6027 clinitgen.goTo(end);
rlm@10 6028
rlm@10 6029 clinitgen.mark(finallyLabel);
rlm@10 6030 //exception should be on stack
rlm@10 6031 clinitgen.invokeStatic(VAR_TYPE, Method.getMethod("void popThreadBindings()"));
rlm@10 6032 clinitgen.throwException();
rlm@10 6033 clinitgen.mark(end);
rlm@10 6034 clinitgen.visitTryCatchBlock(startTry, endTry, finallyLabel, null);
rlm@10 6035
rlm@10 6036 //end of static init
rlm@10 6037 clinitgen.returnValue();
rlm@10 6038 clinitgen.endMethod();
rlm@10 6039
rlm@10 6040 //end of class
rlm@10 6041 cv.visitEnd();
rlm@10 6042
rlm@10 6043 writeClassFile(objx.internalName, cw.toByteArray());
rlm@10 6044 }
rlm@10 6045 catch(LispReader.ReaderException e)
rlm@10 6046 {
rlm@10 6047 throw new CompilerException(sourceName, e.line, e.getCause());
rlm@10 6048 }
rlm@10 6049 finally
rlm@10 6050 {
rlm@10 6051 Var.popThreadBindings();
rlm@10 6052 }
rlm@10 6053 return ret;
rlm@10 6054 }
rlm@10 6055
rlm@10 6056
rlm@10 6057 static public class NewInstanceExpr extends ObjExpr{
rlm@10 6058 //IPersistentMap optionsMap = PersistentArrayMap.EMPTY;
rlm@10 6059 IPersistentCollection methods;
rlm@10 6060
rlm@10 6061 Map<IPersistentVector,java.lang.reflect.Method> mmap;
rlm@10 6062 Map<IPersistentVector,Set<Class>> covariants;
rlm@10 6063
rlm@10 6064 public NewInstanceExpr(Object tag){
rlm@10 6065 super(tag);
rlm@10 6066 }
rlm@10 6067
rlm@10 6068 static class DeftypeParser implements IParser{
rlm@10 6069 public Expr parse(C context, final Object frm) throws Exception{
rlm@10 6070 ISeq rform = (ISeq) frm;
rlm@10 6071 //(deftype* tagname classname [fields] :implements [interfaces] :tag tagname methods*)
rlm@10 6072 rform = RT.next(rform);
rlm@10 6073 String tagname = ((Symbol) rform.first()).toString();
rlm@10 6074 rform = rform.next();
rlm@10 6075 Symbol classname = (Symbol) rform.first();
rlm@10 6076 rform = rform.next();
rlm@10 6077 IPersistentVector fields = (IPersistentVector) rform.first();
rlm@10 6078 rform = rform.next();
rlm@10 6079 IPersistentMap opts = PersistentHashMap.EMPTY;
rlm@10 6080 while(rform != null && rform.first() instanceof Keyword)
rlm@10 6081 {
rlm@10 6082 opts = opts.assoc(rform.first(), RT.second(rform));
rlm@10 6083 rform = rform.next().next();
rlm@10 6084 }
rlm@10 6085
rlm@10 6086 ObjExpr ret = build((IPersistentVector)RT.get(opts,implementsKey,PersistentVector.EMPTY),fields,null,tagname, classname,
rlm@10 6087 (Symbol) RT.get(opts,RT.TAG_KEY),rform, frm);
rlm@10 6088 return ret;
rlm@10 6089 }
rlm@10 6090 }
rlm@10 6091
rlm@10 6092 static class ReifyParser implements IParser{
rlm@10 6093 public Expr parse(C context, Object frm) throws Exception{
rlm@10 6094 //(reify this-name? [interfaces] (method-name [args] body)*)
rlm@10 6095 ISeq form = (ISeq) frm;
rlm@10 6096 ObjMethod enclosingMethod = (ObjMethod) METHOD.deref();
rlm@10 6097 String basename = enclosingMethod != null ?
rlm@10 6098 (trimGenID(enclosingMethod.objx.name) + "$")
rlm@10 6099 : (munge(currentNS().name.name) + "$");
rlm@10 6100 String simpleName = "reify__" + RT.nextID();
rlm@10 6101 String classname = basename + simpleName;
rlm@10 6102
rlm@10 6103 ISeq rform = RT.next(form);
rlm@10 6104
rlm@10 6105 IPersistentVector interfaces = ((IPersistentVector) RT.first(rform)).cons(Symbol.intern("clojure.lang.IObj"));
rlm@10 6106
rlm@10 6107
rlm@10 6108 rform = RT.next(rform);
rlm@10 6109
rlm@10 6110
rlm@10 6111 ObjExpr ret = build(interfaces, null, null, classname, Symbol.intern(classname), null, rform, frm);
rlm@10 6112 if(frm instanceof IObj && ((IObj) frm).meta() != null)
rlm@10 6113 return new MetaExpr(ret, (MapExpr) MapExpr
rlm@10 6114 .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) frm).meta()));
rlm@10 6115 else
rlm@10 6116 return ret;
rlm@10 6117 }
rlm@10 6118 }
rlm@10 6119
rlm@10 6120 static ObjExpr build(IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym,
rlm@10 6121 String tagName, Symbol className,
rlm@10 6122 Symbol typeTag, ISeq methodForms, Object frm) throws Exception{
rlm@10 6123 NewInstanceExpr ret = new NewInstanceExpr(null);
rlm@10 6124
rlm@10 6125 ret.src = frm;
rlm@10 6126 ret.name = className.toString();
rlm@10 6127 ret.classMeta = RT.meta(className);
rlm@10 6128 ret.internalName = ret.name.replace('.', '/');
rlm@10 6129 ret.objtype = Type.getObjectType(ret.internalName);
rlm@10 6130
rlm@10 6131 if(thisSym != null)
rlm@10 6132 ret.thisName = thisSym.name;
rlm@10 6133
rlm@10 6134 if(fieldSyms != null)
rlm@10 6135 {
rlm@10 6136 IPersistentMap fmap = PersistentHashMap.EMPTY;
rlm@10 6137 Object[] closesvec = new Object[2 * fieldSyms.count()];
rlm@10 6138 for(int i=0;i<fieldSyms.count();i++)
rlm@10 6139 {
rlm@10 6140 Symbol sym = (Symbol) fieldSyms.nth(i);
rlm@10 6141 LocalBinding lb = new LocalBinding(-1, sym, null,
rlm@10 6142 new MethodParamExpr(tagClass(tagOf(sym))),false,null);
rlm@10 6143 fmap = fmap.assoc(sym, lb);
rlm@10 6144 closesvec[i*2] = lb;
rlm@10 6145 closesvec[i*2 + 1] = lb;
rlm@10 6146 }
rlm@10 6147
rlm@10 6148 //todo - inject __meta et al into closes - when?
rlm@10 6149 //use array map to preserve ctor order
rlm@10 6150 ret.closes = new PersistentArrayMap(closesvec);
rlm@10 6151 ret.fields = fmap;
rlm@10 6152 for(int i=fieldSyms.count()-1;i >= 0 && ((Symbol)fieldSyms.nth(i)).name.startsWith("__");--i)
rlm@10 6153 ret.altCtorDrops++;
rlm@10 6154 }
rlm@10 6155 //todo - set up volatiles
rlm@10 6156 // ret.volatiles = PersistentHashSet.create(RT.seq(RT.get(ret.optionsMap, volatileKey)));
rlm@10 6157
rlm@10 6158 PersistentVector interfaces = PersistentVector.EMPTY;
rlm@10 6159 for(ISeq s = RT.seq(interfaceSyms);s!=null;s = s.next())
rlm@10 6160 {
rlm@10 6161 Class c = (Class) resolve((Symbol) s.first());
rlm@10 6162 if(!c.isInterface())
rlm@10 6163 throw new IllegalArgumentException("only interfaces are supported, had: " + c.getName());
rlm@10 6164 interfaces = interfaces.cons(c);
rlm@10 6165 }
rlm@10 6166 Class superClass = Object.class;
rlm@10 6167 Map[] mc = gatherMethods(superClass,RT.seq(interfaces));
rlm@10 6168 Map overrideables = mc[0];
rlm@10 6169 Map covariants = mc[1];
rlm@10 6170 ret.mmap = overrideables;
rlm@10 6171 ret.covariants = covariants;
rlm@10 6172
rlm@10 6173 String[] inames = interfaceNames(interfaces);
rlm@10 6174
rlm@10 6175 Class stub = compileStub(slashname(superClass),ret, inames, frm);
rlm@10 6176 Symbol thistag = Symbol.intern(null,stub.getName());
rlm@10 6177
rlm@10 6178 try
rlm@10 6179 {
rlm@10 6180 Var.pushThreadBindings(
rlm@10 6181 RT.map(CONSTANTS, PersistentVector.EMPTY,
rlm@10 6182 CONSTANT_IDS, new IdentityHashMap(),
rlm@10 6183 KEYWORDS, PersistentHashMap.EMPTY,
rlm@10 6184 VARS, PersistentHashMap.EMPTY,
rlm@10 6185 KEYWORD_CALLSITES, PersistentVector.EMPTY,
rlm@10 6186 PROTOCOL_CALLSITES, PersistentVector.EMPTY,
rlm@10 6187 VAR_CALLSITES, PersistentVector.EMPTY
rlm@10 6188 ));
rlm@10 6189 if(ret.isDeftype())
rlm@10 6190 {
rlm@10 6191 Var.pushThreadBindings(RT.map(METHOD, null,
rlm@10 6192 LOCAL_ENV, ret.fields
rlm@10 6193 , COMPILE_STUB_SYM, Symbol.intern(null, tagName)
rlm@10 6194 , COMPILE_STUB_CLASS, stub));
rlm@10 6195 }
rlm@10 6196
rlm@10 6197 //now (methodname [args] body)*
rlm@10 6198 ret.line = (Integer) LINE.deref();
rlm@10 6199 IPersistentCollection methods = null;
rlm@10 6200 for(ISeq s = methodForms; s != null; s = RT.next(s))
rlm@10 6201 {
rlm@10 6202 NewInstanceMethod m = NewInstanceMethod.parse(ret, (ISeq) RT.first(s),thistag, overrideables);
rlm@10 6203 methods = RT.conj(methods, m);
rlm@10 6204 }
rlm@10 6205
rlm@10 6206
rlm@10 6207 ret.methods = methods;
rlm@10 6208 ret.keywords = (IPersistentMap) KEYWORDS.deref();
rlm@10 6209 ret.vars = (IPersistentMap) VARS.deref();
rlm@10 6210 ret.constants = (PersistentVector) CONSTANTS.deref();
rlm@10 6211 ret.constantsID = RT.nextID();
rlm@10 6212 ret.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref();
rlm@10 6213 ret.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref();
rlm@10 6214 ret.varCallsites = (IPersistentVector) VAR_CALLSITES.deref();
rlm@10 6215 }
rlm@10 6216 finally
rlm@10 6217 {
rlm@10 6218 if(ret.isDeftype())
rlm@10 6219 Var.popThreadBindings();
rlm@10 6220 Var.popThreadBindings();
rlm@10 6221 }
rlm@10 6222
rlm@10 6223 ret.compile(slashname(superClass),inames,false);
rlm@10 6224 ret.getCompiledClass();
rlm@10 6225 return ret;
rlm@10 6226 }
rlm@10 6227
rlm@10 6228 /***
rlm@10 6229 * Current host interop uses reflection, which requires pre-existing classes
rlm@10 6230 * Work around this by:
rlm@10 6231 * Generate a stub class that has the same interfaces and fields as the class we are generating.
rlm@10 6232 * Use it as a type hint for this, and bind the simple name of the class to this stub (in resolve etc)
rlm@10 6233 * Unmunge the name (using a magic prefix) on any code gen for classes
rlm@10 6234 */
rlm@10 6235 static Class compileStub(String superName, NewInstanceExpr ret, String[] interfaceNames, Object frm){
rlm@10 6236 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
rlm@10 6237 ClassVisitor cv = cw;
rlm@10 6238 cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, COMPILE_STUB_PREFIX + "/" + ret.internalName,
rlm@10 6239 null,superName,interfaceNames);
rlm@10 6240
rlm@10 6241 //instance fields for closed-overs
rlm@10 6242 for(ISeq s = RT.keys(ret.closes); s != null; s = s.next())
rlm@10 6243 {
rlm@10 6244 LocalBinding lb = (LocalBinding) s.first();
rlm@10 6245 int access = ACC_PUBLIC + (ret.isVolatile(lb) ? ACC_VOLATILE :
rlm@10 6246 ret.isMutable(lb) ? 0 :
rlm@10 6247 ACC_FINAL);
rlm@10 6248 if(lb.getPrimitiveType() != null)
rlm@10 6249 cv.visitField(access
rlm@10 6250 , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(),
rlm@10 6251 null, null);
rlm@10 6252 else
rlm@10 6253 //todo - when closed-overs are fields, use more specific types here and in ctor and emitLocal?
rlm@10 6254 cv.visitField(access
rlm@10 6255 , lb.name, OBJECT_TYPE.getDescriptor(), null, null);
rlm@10 6256 }
rlm@10 6257
rlm@10 6258 //ctor that takes closed-overs and does nothing
rlm@10 6259 Method m = new Method("<init>", Type.VOID_TYPE, ret.ctorTypes());
rlm@10 6260 GeneratorAdapter ctorgen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 6261 m,
rlm@10 6262 null,
rlm@10 6263 null,
rlm@10 6264 cv);
rlm@10 6265 ctorgen.visitCode();
rlm@10 6266 ctorgen.loadThis();
rlm@10 6267 ctorgen.invokeConstructor(Type.getObjectType(superName), voidctor);
rlm@10 6268 ctorgen.returnValue();
rlm@10 6269 ctorgen.endMethod();
rlm@10 6270
rlm@10 6271 if(ret.altCtorDrops > 0)
rlm@10 6272 {
rlm@10 6273 Type[] ctorTypes = ret.ctorTypes();
rlm@10 6274 Type[] altCtorTypes = new Type[ctorTypes.length-ret.altCtorDrops];
rlm@10 6275 for(int i=0;i<altCtorTypes.length;i++)
rlm@10 6276 altCtorTypes[i] = ctorTypes[i];
rlm@10 6277 Method alt = new Method("<init>", Type.VOID_TYPE, altCtorTypes);
rlm@10 6278 ctorgen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 6279 alt,
rlm@10 6280 null,
rlm@10 6281 null,
rlm@10 6282 cv);
rlm@10 6283 ctorgen.visitCode();
rlm@10 6284 ctorgen.loadThis();
rlm@10 6285 ctorgen.loadArgs();
rlm@10 6286 for(int i=0;i<ret.altCtorDrops;i++)
rlm@10 6287 ctorgen.visitInsn(Opcodes.ACONST_NULL);
rlm@10 6288
rlm@10 6289 ctorgen.invokeConstructor(Type.getObjectType(COMPILE_STUB_PREFIX + "/" + ret.internalName),
rlm@10 6290 new Method("<init>", Type.VOID_TYPE, ctorTypes));
rlm@10 6291
rlm@10 6292 ctorgen.returnValue();
rlm@10 6293 ctorgen.endMethod();
rlm@10 6294 }
rlm@10 6295 //end of class
rlm@10 6296 cv.visitEnd();
rlm@10 6297
rlm@10 6298 byte[] bytecode = cw.toByteArray();
rlm@10 6299 DynamicClassLoader loader = (DynamicClassLoader) LOADER.deref();
rlm@10 6300 return loader.defineClass(COMPILE_STUB_PREFIX + "." + ret.name, bytecode, frm);
rlm@10 6301 }
rlm@10 6302
rlm@10 6303 static String[] interfaceNames(IPersistentVector interfaces){
rlm@10 6304 int icnt = interfaces.count();
rlm@10 6305 String[] inames = icnt > 0 ? new String[icnt] : null;
rlm@10 6306 for(int i=0;i<icnt;i++)
rlm@10 6307 inames[i] = slashname((Class) interfaces.nth(i));
rlm@10 6308 return inames;
rlm@10 6309 }
rlm@10 6310
rlm@10 6311
rlm@10 6312 static String slashname(Class c){
rlm@10 6313 return c.getName().replace('.', '/');
rlm@10 6314 }
rlm@10 6315
rlm@10 6316
rlm@10 6317 protected void emitMethods(ClassVisitor cv){
rlm@10 6318 for(ISeq s = RT.seq(methods); s != null; s = s.next())
rlm@10 6319 {
rlm@10 6320 ObjMethod method = (ObjMethod) s.first();
rlm@10 6321 method.emit(this, cv);
rlm@10 6322 }
rlm@10 6323 //emit bridge methods
rlm@10 6324 for(Map.Entry<IPersistentVector,Set<Class>> e : covariants.entrySet())
rlm@10 6325 {
rlm@10 6326 java.lang.reflect.Method m = mmap.get(e.getKey());
rlm@10 6327 Class[] params = m.getParameterTypes();
rlm@10 6328 Type[] argTypes = new Type[params.length];
rlm@10 6329
rlm@10 6330 for(int i = 0; i < params.length; i++)
rlm@10 6331 {
rlm@10 6332 argTypes[i] = Type.getType(params[i]);
rlm@10 6333 }
rlm@10 6334
rlm@10 6335 Method target = new Method(m.getName(), Type.getType(m.getReturnType()), argTypes);
rlm@10 6336
rlm@10 6337 for(Class retType : e.getValue())
rlm@10 6338 {
rlm@10 6339 Method meth = new Method(m.getName(), Type.getType(retType), argTypes);
rlm@10 6340
rlm@10 6341 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_BRIDGE,
rlm@10 6342 meth,
rlm@10 6343 null,
rlm@10 6344 //todo don't hardwire this
rlm@10 6345 EXCEPTION_TYPES,
rlm@10 6346 cv);
rlm@10 6347 gen.visitCode();
rlm@10 6348 gen.loadThis();
rlm@10 6349 gen.loadArgs();
rlm@10 6350 gen.invokeInterface(Type.getType(m.getDeclaringClass()),target);
rlm@10 6351 gen.returnValue();
rlm@10 6352 gen.endMethod();
rlm@10 6353 }
rlm@10 6354 }
rlm@10 6355 }
rlm@10 6356
rlm@10 6357 static public IPersistentVector msig(java.lang.reflect.Method m){
rlm@10 6358 return RT.vector(m.getName(), RT.seq(m.getParameterTypes()),m.getReturnType());
rlm@10 6359 }
rlm@10 6360
rlm@10 6361 static void considerMethod(java.lang.reflect.Method m, Map mm){
rlm@10 6362 IPersistentVector mk = msig(m);
rlm@10 6363 int mods = m.getModifiers();
rlm@10 6364
rlm@10 6365 if(!(mm.containsKey(mk)
rlm@10 6366 || !(Modifier.isPublic(mods) || Modifier.isProtected(mods))
rlm@10 6367 || Modifier.isStatic(mods)
rlm@10 6368 || Modifier.isFinal(mods)))
rlm@10 6369 {
rlm@10 6370 mm.put(mk, m);
rlm@10 6371 }
rlm@10 6372 }
rlm@10 6373
rlm@10 6374 static void gatherMethods(Class c, Map mm){
rlm@10 6375 for(; c != null; c = c.getSuperclass())
rlm@10 6376 {
rlm@10 6377 for(java.lang.reflect.Method m : c.getDeclaredMethods())
rlm@10 6378 considerMethod(m, mm);
rlm@10 6379 for(java.lang.reflect.Method m : c.getMethods())
rlm@10 6380 considerMethod(m, mm);
rlm@10 6381 }
rlm@10 6382 }
rlm@10 6383
rlm@10 6384 static public Map[] gatherMethods(Class sc, ISeq interfaces){
rlm@10 6385 Map allm = new HashMap();
rlm@10 6386 gatherMethods(sc, allm);
rlm@10 6387 for(; interfaces != null; interfaces = interfaces.next())
rlm@10 6388 gatherMethods((Class) interfaces.first(), allm);
rlm@10 6389
rlm@10 6390 Map<IPersistentVector,java.lang.reflect.Method> mm = new HashMap<IPersistentVector,java.lang.reflect.Method>();
rlm@10 6391 Map<IPersistentVector,Set<Class>> covariants = new HashMap<IPersistentVector,Set<Class>>();
rlm@10 6392 for(Object o : allm.entrySet())
rlm@10 6393 {
rlm@10 6394 Map.Entry e = (Map.Entry) o;
rlm@10 6395 IPersistentVector mk = (IPersistentVector) e.getKey();
rlm@10 6396 mk = (IPersistentVector) mk.pop();
rlm@10 6397 java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue();
rlm@10 6398 if(mm.containsKey(mk)) //covariant return
rlm@10 6399 {
rlm@10 6400 Set<Class> cvs = covariants.get(mk);
rlm@10 6401 if(cvs == null)
rlm@10 6402 {
rlm@10 6403 cvs = new HashSet<Class>();
rlm@10 6404 covariants.put(mk,cvs);
rlm@10 6405 }
rlm@10 6406 java.lang.reflect.Method om = mm.get(mk);
rlm@10 6407 if(om.getReturnType().isAssignableFrom(m.getReturnType()))
rlm@10 6408 {
rlm@10 6409 cvs.add(om.getReturnType());
rlm@10 6410 mm.put(mk, m);
rlm@10 6411 }
rlm@10 6412 else
rlm@10 6413 cvs.add(m.getReturnType());
rlm@10 6414 }
rlm@10 6415 else
rlm@10 6416 mm.put(mk, m);
rlm@10 6417 }
rlm@10 6418 return new Map[]{mm,covariants};
rlm@10 6419 }
rlm@10 6420 }
rlm@10 6421
rlm@10 6422 public static class NewInstanceMethod extends ObjMethod{
rlm@10 6423 String name;
rlm@10 6424 Type[] argTypes;
rlm@10 6425 Type retType;
rlm@10 6426 Class retClass;
rlm@10 6427 Class[] exclasses;
rlm@10 6428
rlm@10 6429 static Symbol dummyThis = Symbol.intern(null,"dummy_this_dlskjsdfower");
rlm@10 6430 private IPersistentVector parms;
rlm@10 6431
rlm@10 6432 public NewInstanceMethod(ObjExpr objx, ObjMethod parent){
rlm@10 6433 super(objx, parent);
rlm@10 6434 }
rlm@10 6435
rlm@10 6436 int numParams(){
rlm@10 6437 return argLocals.count();
rlm@10 6438 }
rlm@10 6439
rlm@10 6440 String getMethodName(){
rlm@10 6441 return name;
rlm@10 6442 }
rlm@10 6443
rlm@10 6444 Type getReturnType(){
rlm@10 6445 return retType;
rlm@10 6446 }
rlm@10 6447
rlm@10 6448 Type[] getArgTypes(){
rlm@10 6449 return argTypes;
rlm@10 6450 }
rlm@10 6451
rlm@10 6452
rlm@10 6453
rlm@10 6454 static public IPersistentVector msig(String name,Class[] paramTypes){
rlm@10 6455 return RT.vector(name,RT.seq(paramTypes));
rlm@10 6456 }
rlm@10 6457
rlm@10 6458 static NewInstanceMethod parse(ObjExpr objx, ISeq form, Symbol thistag,
rlm@10 6459 Map overrideables) throws Exception{
rlm@10 6460 //(methodname [this-name args*] body...)
rlm@10 6461 //this-name might be nil
rlm@10 6462 NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod) METHOD.deref());
rlm@10 6463 Symbol dotname = (Symbol)RT.first(form);
rlm@10 6464 Symbol name = (Symbol) Symbol.intern(null,munge(dotname.name)).withMeta(RT.meta(dotname));
rlm@10 6465 IPersistentVector parms = (IPersistentVector) RT.second(form);
rlm@10 6466 if(parms.count() == 0)
rlm@10 6467 {
rlm@10 6468 throw new IllegalArgumentException("Must supply at least one argument for 'this' in: " + dotname);
rlm@10 6469 }
rlm@10 6470 Symbol thisName = (Symbol) parms.nth(0);
rlm@10 6471 parms = RT.subvec(parms,1,parms.count());
rlm@10 6472 ISeq body = RT.next(RT.next(form));
rlm@10 6473 try
rlm@10 6474 {
rlm@10 6475 method.line = (Integer) LINE.deref();
rlm@10 6476 //register as the current method and set up a new env frame
rlm@10 6477 PathNode pnode = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get());
rlm@10 6478 Var.pushThreadBindings(
rlm@10 6479 RT.map(
rlm@10 6480 METHOD, method,
rlm@10 6481 LOCAL_ENV, LOCAL_ENV.deref(),
rlm@10 6482 LOOP_LOCALS, null,
rlm@10 6483 NEXT_LOCAL_NUM, 0
rlm@10 6484 ,CLEAR_PATH, pnode
rlm@10 6485 ,CLEAR_ROOT, pnode
rlm@10 6486 ,CLEAR_SITES, PersistentHashMap.EMPTY
rlm@10 6487 ));
rlm@10 6488
rlm@10 6489 //register 'this' as local 0
rlm@10 6490 if(thisName != null)
rlm@10 6491 registerLocal((thisName == null) ? dummyThis:thisName,thistag, null,false);
rlm@10 6492 else
rlm@10 6493 getAndIncLocalNum();
rlm@10 6494
rlm@10 6495 PersistentVector argLocals = PersistentVector.EMPTY;
rlm@10 6496 method.retClass = tagClass(tagOf(name));
rlm@10 6497 method.argTypes = new Type[parms.count()];
rlm@10 6498 boolean hinted = tagOf(name) != null;
rlm@10 6499 Class[] pclasses = new Class[parms.count()];
rlm@10 6500 Symbol[] psyms = new Symbol[parms.count()];
rlm@10 6501
rlm@10 6502 for(int i = 0; i < parms.count(); i++)
rlm@10 6503 {
rlm@10 6504 if(!(parms.nth(i) instanceof Symbol))
rlm@10 6505 throw new IllegalArgumentException("params must be Symbols");
rlm@10 6506 Symbol p = (Symbol) parms.nth(i);
rlm@10 6507 Object tag = tagOf(p);
rlm@10 6508 if(tag != null)
rlm@10 6509 hinted = true;
rlm@10 6510 if(p.getNamespace() != null)
rlm@10 6511 p = Symbol.create(p.name);
rlm@10 6512 Class pclass = tagClass(tag);
rlm@10 6513 pclasses[i] = pclass;
rlm@10 6514 psyms[i] = p;
rlm@10 6515 }
rlm@10 6516 Map matches = findMethodsWithNameAndArity(name.name, parms.count(), overrideables);
rlm@10 6517 Object mk = msig(name.name, pclasses);
rlm@10 6518 java.lang.reflect.Method m = null;
rlm@10 6519 if(matches.size() > 0)
rlm@10 6520 {
rlm@10 6521 //multiple methods
rlm@10 6522 if(matches.size() > 1)
rlm@10 6523 {
rlm@10 6524 //must be hinted and match one method
rlm@10 6525 if(!hinted)
rlm@10 6526 throw new IllegalArgumentException("Must hint overloaded method: " + name.name);
rlm@10 6527 m = (java.lang.reflect.Method) matches.get(mk);
rlm@10 6528 if(m == null)
rlm@10 6529 throw new IllegalArgumentException("Can't find matching overloaded method: " + name.name);
rlm@10 6530 if(m.getReturnType() != method.retClass)
rlm@10 6531 throw new IllegalArgumentException("Mismatched return type: " + name.name +
rlm@10 6532 ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName());
rlm@10 6533 }
rlm@10 6534 else //one match
rlm@10 6535 {
rlm@10 6536 //if hinted, validate match,
rlm@10 6537 if(hinted)
rlm@10 6538 {
rlm@10 6539 m = (java.lang.reflect.Method) matches.get(mk);
rlm@10 6540 if(m == null)
rlm@10 6541 throw new IllegalArgumentException("Can't find matching method: " + name.name +
rlm@10 6542 ", leave off hints for auto match.");
rlm@10 6543 if(m.getReturnType() != method.retClass)
rlm@10 6544 throw new IllegalArgumentException("Mismatched return type: " + name.name +
rlm@10 6545 ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName());
rlm@10 6546 }
rlm@10 6547 else //adopt found method sig
rlm@10 6548 {
rlm@10 6549 m = (java.lang.reflect.Method) matches.values().iterator().next();
rlm@10 6550 method.retClass = m.getReturnType();
rlm@10 6551 pclasses = m.getParameterTypes();
rlm@10 6552 }
rlm@10 6553 }
rlm@10 6554 }
rlm@10 6555 // else if(findMethodsWithName(name.name,allmethods).size()>0)
rlm@10 6556 // throw new IllegalArgumentException("Can't override/overload method: " + name.name);
rlm@10 6557 else
rlm@10 6558 throw new IllegalArgumentException("Can't define method not in interfaces: " + name.name);
rlm@10 6559
rlm@10 6560 //else
rlm@10 6561 //validate unque name+arity among additional methods
rlm@10 6562
rlm@10 6563 method.retType = Type.getType(method.retClass);
rlm@10 6564 method.exclasses = m.getExceptionTypes();
rlm@10 6565
rlm@10 6566 for(int i = 0; i < parms.count(); i++)
rlm@10 6567 {
rlm@10 6568 LocalBinding lb = registerLocal(psyms[i], null, new MethodParamExpr(pclasses[i]),true);
rlm@10 6569 argLocals = argLocals.assocN(i,lb);
rlm@10 6570 method.argTypes[i] = Type.getType(pclasses[i]);
rlm@10 6571 }
rlm@10 6572 for(int i = 0; i < parms.count(); i++)
rlm@10 6573 {
rlm@10 6574 if(pclasses[i] == long.class || pclasses[i] == double.class)
rlm@10 6575 getAndIncLocalNum();
rlm@10 6576 }
rlm@10 6577 LOOP_LOCALS.set(argLocals);
rlm@10 6578 method.name = name.name;
rlm@10 6579 method.methodMeta = RT.meta(name);
rlm@10 6580 method.parms = parms;
rlm@10 6581 method.argLocals = argLocals;
rlm@10 6582 method.body = (new BodyExpr.Parser()).parse(C.RETURN, body);
rlm@10 6583 return method;
rlm@10 6584 }
rlm@10 6585 finally
rlm@10 6586 {
rlm@10 6587 Var.popThreadBindings();
rlm@10 6588 }
rlm@10 6589 }
rlm@10 6590
rlm@10 6591 private static Map findMethodsWithNameAndArity(String name, int arity, Map mm){
rlm@10 6592 Map ret = new HashMap();
rlm@10 6593 for(Object o : mm.entrySet())
rlm@10 6594 {
rlm@10 6595 Map.Entry e = (Map.Entry) o;
rlm@10 6596 java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue();
rlm@10 6597 if(name.equals(m.getName()) && m.getParameterTypes().length == arity)
rlm@10 6598 ret.put(e.getKey(), e.getValue());
rlm@10 6599 }
rlm@10 6600 return ret;
rlm@10 6601 }
rlm@10 6602
rlm@10 6603 private static Map findMethodsWithName(String name, Map mm){
rlm@10 6604 Map ret = new HashMap();
rlm@10 6605 for(Object o : mm.entrySet())
rlm@10 6606 {
rlm@10 6607 Map.Entry e = (Map.Entry) o;
rlm@10 6608 java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue();
rlm@10 6609 if(name.equals(m.getName()))
rlm@10 6610 ret.put(e.getKey(), e.getValue());
rlm@10 6611 }
rlm@10 6612 return ret;
rlm@10 6613 }
rlm@10 6614
rlm@10 6615 public void emit(ObjExpr obj, ClassVisitor cv){
rlm@10 6616 Method m = new Method(getMethodName(), getReturnType(), getArgTypes());
rlm@10 6617
rlm@10 6618 Type[] extypes = null;
rlm@10 6619 if(exclasses.length > 0)
rlm@10 6620 {
rlm@10 6621 extypes = new Type[exclasses.length];
rlm@10 6622 for(int i=0;i<exclasses.length;i++)
rlm@10 6623 extypes[i] = Type.getType(exclasses[i]);
rlm@10 6624 }
rlm@10 6625 GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC,
rlm@10 6626 m,
rlm@10 6627 null,
rlm@10 6628 extypes,
rlm@10 6629 cv);
rlm@10 6630 addAnnotation(gen,methodMeta);
rlm@10 6631 for(int i = 0; i < parms.count(); i++)
rlm@10 6632 {
rlm@10 6633 IPersistentMap meta = RT.meta(parms.nth(i));
rlm@10 6634 addParameterAnnotation(gen, meta, i);
rlm@10 6635 }
rlm@10 6636 gen.visitCode();
rlm@10 6637 Label loopLabel = gen.mark();
rlm@10 6638 gen.visitLineNumber(line, loopLabel);
rlm@10 6639 try
rlm@10 6640 {
rlm@10 6641 Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this));
rlm@10 6642 MaybePrimitiveExpr be = (MaybePrimitiveExpr) body;
rlm@10 6643 if(Util.isPrimitive(retClass) && be.canEmitPrimitive())
rlm@10 6644 {
rlm@10 6645 if(be.getJavaClass() == retClass)
rlm@10 6646 be.emitUnboxed(C.RETURN,obj,gen);
rlm@10 6647 //todo - support the standard widening conversions
rlm@10 6648 else
rlm@10 6649 throw new IllegalArgumentException("Mismatched primitive return, expected: "
rlm@10 6650 + retClass + ", had: " + be.getJavaClass());
rlm@10 6651 }
rlm@10 6652 else
rlm@10 6653 {
rlm@10 6654 body.emit(C.RETURN, obj, gen);
rlm@10 6655 if(retClass == void.class)
rlm@10 6656 {
rlm@10 6657 gen.pop();
rlm@10 6658 }
rlm@10 6659 else
rlm@10 6660 gen.unbox(retType);
rlm@10 6661 }
rlm@10 6662
rlm@10 6663 Label end = gen.mark();
rlm@10 6664 gen.visitLocalVariable("this", obj.objtype.getDescriptor(), null, loopLabel, end, 0);
rlm@10 6665 for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next())
rlm@10 6666 {
rlm@10 6667 LocalBinding lb = (LocalBinding) lbs.first();
rlm@10 6668 gen.visitLocalVariable(lb.name, argTypes[lb.idx-1].getDescriptor(), null, loopLabel, end, lb.idx);
rlm@10 6669 }
rlm@10 6670 }
rlm@10 6671 catch(Exception e)
rlm@10 6672 {
rlm@10 6673 throw new RuntimeException(e);
rlm@10 6674 }
rlm@10 6675 finally
rlm@10 6676 {
rlm@10 6677 Var.popThreadBindings();
rlm@10 6678 }
rlm@10 6679
rlm@10 6680 gen.returnValue();
rlm@10 6681 //gen.visitMaxs(1, 1);
rlm@10 6682 gen.endMethod();
rlm@10 6683 }
rlm@10 6684 }
rlm@10 6685
rlm@10 6686 static Class primClass(Symbol sym){
rlm@10 6687 if(sym == null)
rlm@10 6688 return null;
rlm@10 6689 Class c = null;
rlm@10 6690 if(sym.name.equals("int"))
rlm@10 6691 c = int.class;
rlm@10 6692 else if(sym.name.equals("long"))
rlm@10 6693 c = long.class;
rlm@10 6694 else if(sym.name.equals("float"))
rlm@10 6695 c = float.class;
rlm@10 6696 else if(sym.name.equals("double"))
rlm@10 6697 c = double.class;
rlm@10 6698 else if(sym.name.equals("char"))
rlm@10 6699 c = char.class;
rlm@10 6700 else if(sym.name.equals("short"))
rlm@10 6701 c = short.class;
rlm@10 6702 else if(sym.name.equals("byte"))
rlm@10 6703 c = byte.class;
rlm@10 6704 else if(sym.name.equals("boolean"))
rlm@10 6705 c = boolean.class;
rlm@10 6706 else if(sym.name.equals("void"))
rlm@10 6707 c = void.class;
rlm@10 6708 return c;
rlm@10 6709 }
rlm@10 6710
rlm@10 6711 static Class tagClass(Object tag) throws Exception{
rlm@10 6712 if(tag == null)
rlm@10 6713 return Object.class;
rlm@10 6714 Class c = null;
rlm@10 6715 if(tag instanceof Symbol)
rlm@10 6716 c = primClass((Symbol) tag);
rlm@10 6717 if(c == null)
rlm@10 6718 c = HostExpr.tagToClass(tag);
rlm@10 6719 return c;
rlm@10 6720 }
rlm@10 6721
rlm@10 6722 static public class MethodParamExpr implements Expr, MaybePrimitiveExpr{
rlm@10 6723 final Class c;
rlm@10 6724
rlm@10 6725 public MethodParamExpr(Class c){
rlm@10 6726 this.c = c;
rlm@10 6727 }
rlm@10 6728
rlm@10 6729 public Object eval() throws Exception{
rlm@10 6730 throw new Exception("Can't eval");
rlm@10 6731 }
rlm@10 6732
rlm@10 6733 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 6734 throw new RuntimeException("Can't emit");
rlm@10 6735 }
rlm@10 6736
rlm@10 6737 public boolean hasJavaClass() throws Exception{
rlm@10 6738 return c != null;
rlm@10 6739 }
rlm@10 6740
rlm@10 6741 public Class getJavaClass() throws Exception{
rlm@10 6742 return c;
rlm@10 6743 }
rlm@10 6744
rlm@10 6745 public boolean canEmitPrimitive(){
rlm@10 6746 return Util.isPrimitive(c);
rlm@10 6747 }
rlm@10 6748
rlm@10 6749 public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 6750 throw new RuntimeException("Can't emit");
rlm@10 6751 }
rlm@10 6752 }
rlm@10 6753
rlm@10 6754 public static class CaseExpr extends UntypedExpr{
rlm@10 6755 public final LocalBindingExpr expr;
rlm@10 6756 public final int shift, mask, low, high;
rlm@10 6757 public final Expr defaultExpr;
rlm@10 6758 public final HashMap<Integer,Expr> tests;
rlm@10 6759 public final HashMap<Integer,Expr> thens;
rlm@10 6760 public final boolean allKeywords;
rlm@10 6761
rlm@10 6762 public final int line;
rlm@10 6763
rlm@10 6764 final static Method hashMethod = Method.getMethod("int hash(Object)");
rlm@10 6765 final static Method hashCodeMethod = Method.getMethod("int hashCode()");
rlm@10 6766 final static Method equalsMethod = Method.getMethod("boolean equals(Object, Object)");
rlm@10 6767
rlm@10 6768
rlm@10 6769 public CaseExpr(int line, LocalBindingExpr expr, int shift, int mask, int low, int high, Expr defaultExpr,
rlm@10 6770 HashMap<Integer,Expr> tests,HashMap<Integer,Expr> thens, boolean allKeywords){
rlm@10 6771 this.expr = expr;
rlm@10 6772 this.shift = shift;
rlm@10 6773 this.mask = mask;
rlm@10 6774 this.low = low;
rlm@10 6775 this.high = high;
rlm@10 6776 this.defaultExpr = defaultExpr;
rlm@10 6777 this.tests = tests;
rlm@10 6778 this.thens = thens;
rlm@10 6779 this.line = line;
rlm@10 6780 this.allKeywords = allKeywords;
rlm@10 6781 }
rlm@10 6782
rlm@10 6783 public Object eval() throws Exception{
rlm@10 6784 throw new UnsupportedOperationException("Can't eval case");
rlm@10 6785 }
rlm@10 6786
rlm@10 6787 public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
rlm@10 6788 Label defaultLabel = gen.newLabel();
rlm@10 6789 Label endLabel = gen.newLabel();
rlm@10 6790 HashMap<Integer,Label> labels = new HashMap();
rlm@10 6791
rlm@10 6792 for(Integer i : tests.keySet())
rlm@10 6793 {
rlm@10 6794 labels.put(i, gen.newLabel());
rlm@10 6795 }
rlm@10 6796
rlm@10 6797 Label[] la = new Label[(high-low)+1];
rlm@10 6798
rlm@10 6799 for(int i=low;i<=high;i++)
rlm@10 6800 {
rlm@10 6801 la[i-low] = labels.containsKey(i) ? labels.get(i) : defaultLabel;
rlm@10 6802 }
rlm@10 6803
rlm@10 6804 gen.visitLineNumber(line, gen.mark());
rlm@10 6805 expr.emit(C.EXPRESSION, objx, gen);
rlm@10 6806 gen.invokeStatic(UTIL_TYPE,hashMethod);
rlm@10 6807 gen.push(shift);
rlm@10 6808 gen.visitInsn(ISHR);
rlm@10 6809 gen.push(mask);
rlm@10 6810 gen.visitInsn(IAND);
rlm@10 6811 gen.visitTableSwitchInsn(low, high, defaultLabel, la);
rlm@10 6812
rlm@10 6813 for(Integer i : labels.keySet())
rlm@10 6814 {
rlm@10 6815 gen.mark(labels.get(i));
rlm@10 6816 expr.emit(C.EXPRESSION, objx, gen);
rlm@10 6817 tests.get(i).emit(C.EXPRESSION, objx, gen);
rlm@10 6818 if(allKeywords)
rlm@10 6819 {
rlm@10 6820 gen.visitJumpInsn(IF_ACMPNE, defaultLabel);
rlm@10 6821 }
rlm@10 6822 else
rlm@10 6823 {
rlm@10 6824 gen.invokeStatic(UTIL_TYPE, equalsMethod);
rlm@10 6825 gen.ifZCmp(GeneratorAdapter.EQ, defaultLabel);
rlm@10 6826 }
rlm@10 6827 thens.get(i).emit(C.EXPRESSION,objx,gen);
rlm@10 6828 gen.goTo(endLabel);
rlm@10 6829 }
rlm@10 6830
rlm@10 6831 gen.mark(defaultLabel);
rlm@10 6832 defaultExpr.emit(C.EXPRESSION, objx, gen);
rlm@10 6833 gen.mark(endLabel);
rlm@10 6834 if(context == C.STATEMENT)
rlm@10 6835 gen.pop();
rlm@10 6836 }
rlm@10 6837
rlm@10 6838 static class Parser implements IParser{
rlm@10 6839 //(case* expr shift mask low high default map<minhash, [test then]> identity?)
rlm@10 6840 //prepared by case macro and presumed correct
rlm@10 6841 //case macro binds actual expr in let so expr is always a local,
rlm@10 6842 //no need to worry about multiple evaluation
rlm@10 6843 public Expr parse(C context, Object frm) throws Exception{
rlm@10 6844 ISeq form = (ISeq) frm;
rlm@10 6845 if(context == C.EVAL)
rlm@10 6846 return analyze(context, RT.list(RT.list(FN, PersistentVector.EMPTY, form)));
rlm@10 6847 PersistentVector args = PersistentVector.create(form.next());
rlm@10 6848 HashMap<Integer,Expr> tests = new HashMap();
rlm@10 6849 HashMap<Integer,Expr> thens = new HashMap();
rlm@10 6850
rlm@10 6851 LocalBindingExpr testexpr = (LocalBindingExpr) analyze(C.EXPRESSION, args.nth(0));
rlm@10 6852 testexpr.shouldClear = false;
rlm@10 6853
rlm@10 6854 PathNode branch = new PathNode(PATHTYPE.BRANCH, (PathNode) CLEAR_PATH.get());
rlm@10 6855 for(Object o : ((Map)args.nth(6)).entrySet())
rlm@10 6856 {
rlm@10 6857 Map.Entry e = (Map.Entry) o;
rlm@10 6858 Integer minhash = (Integer) e.getKey();
rlm@10 6859 MapEntry me = (MapEntry) e.getValue();
rlm@10 6860 Expr testExpr = new ConstantExpr(me.getKey());
rlm@10 6861 tests.put(minhash, testExpr);
rlm@10 6862 Expr thenExpr;
rlm@10 6863 try {
rlm@10 6864 Var.pushThreadBindings(
rlm@10 6865 RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch)));
rlm@10 6866 thenExpr = analyze(context, me.getValue());
rlm@10 6867 }
rlm@10 6868 finally{
rlm@10 6869 Var.popThreadBindings();
rlm@10 6870 }
rlm@10 6871 thens.put(minhash, thenExpr);
rlm@10 6872 }
rlm@10 6873
rlm@10 6874 Expr defaultExpr;
rlm@10 6875 try {
rlm@10 6876 Var.pushThreadBindings(
rlm@10 6877 RT.map(CLEAR_PATH, new PathNode(PATHTYPE.PATH,branch)));
rlm@10 6878 defaultExpr = analyze(context, args.nth(5));
rlm@10 6879 }
rlm@10 6880 finally{
rlm@10 6881 Var.popThreadBindings();
rlm@10 6882 }
rlm@10 6883
rlm@10 6884 return new CaseExpr((Integer) LINE.deref(),
rlm@10 6885 testexpr,
rlm@10 6886 (Integer)args.nth(1),
rlm@10 6887 (Integer)args.nth(2),
rlm@10 6888 (Integer)args.nth(3),
rlm@10 6889 (Integer)args.nth(4),
rlm@10 6890 defaultExpr,
rlm@10 6891 tests,thens,args.nth(7) != RT.F);
rlm@10 6892
rlm@10 6893 }
rlm@10 6894 }
rlm@10 6895 }
rlm@10 6896
rlm@10 6897 }