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 }
|