|
50 | 50 | "(" (arg-types (:args method)) ")")) |
51 | 51 |
|
52 | 52 | (defn- make-method [method] |
53 | | - (Method/getMethod (method-signature method))) |
| 53 | + (Method/getMethod (method-signature method) |
| 54 | + true)) |
54 | 55 |
|
55 | 56 | (defn- make-class |
56 | 57 | ([cw class-name] |
|
62 | 63 |
|
63 | 64 | (defn- make-constructor |
64 | 65 | ([cw] |
65 | | - (make-constructor cw nil nil)) |
66 | | - ([cw fields class-type] |
| 66 | + (make-constructor cw obj-type)) |
| 67 | + ([cw parent-type] |
67 | 68 | (let [init-gen (GeneratorAdapter. Opcodes/ACC_PUBLIC init nil nil cw)] |
68 | 69 | (doto init-gen |
69 | 70 | (.loadThis) |
70 | | - (.invokeConstructor obj-type init)) |
71 | | - (when fields |
| 71 | + (.invokeConstructor parent-type init)) |
| 72 | + |
| 73 | + ;; probably don't need this ever |
| 74 | + ;; delete when more certain |
| 75 | + #_(when fields |
72 | 76 | (doseq [[name field] fields] |
73 | 77 | (doto init-gen |
74 | 78 | (.loadThis) |
|
137 | 141 | (defmethod generate :class-declaration [class scopes] |
138 | 142 | (let [cw (make-class-writer) |
139 | 143 | class-type (-> class :name type->Type) |
| 144 | + parent-type (if-let [parent (:parent class)] |
| 145 | + (type->Type parent) |
| 146 | + obj-type) |
140 | 147 | _ (make-class cw (:name class) (:parent class)) |
141 | 148 | _ (generate-fields (:vars class) cw) |
142 | | - init (make-constructor cw (:vars class) class-type) |
| 149 | + init (make-constructor cw parent-type) |
143 | 150 | scopes (assoc scopes |
144 | 151 | :class class |
145 | | - :class-type class-type)] |
| 152 | + :class-type class-type |
| 153 | + :parents (semantics/parent-seq class |
| 154 | + (:class-table scopes)))] |
146 | 155 |
|
147 | 156 |
|
148 | 157 | ;; generate methods |
|
159 | 168 | ;; create a new local in the method generator |
160 | 169 | index (.newLocal method-gen type)] |
161 | 170 | ;; store the index in the var |
162 | | - (assoc var :index index))) |
| 171 | + (assoc var :ref-index index))) |
163 | 172 |
|
164 | 173 | (defn- generate-locals [vars method-gen] |
165 | 174 | (-> (fn [m [name var]] |
166 | 175 | (assoc m |
167 | | - name (if-not (:index var) |
| 176 | + name (if-not (:arg-index var) |
168 | 177 | (generate-local var method-gen) |
169 | 178 | var))) |
170 | 179 | (reduce vars vars))) |
|
218 | 227 | (.mark method-gen start-label) |
219 | 228 | ;; push predicate |
220 | 229 | (generate (:pred statement) scopes method-gen) |
221 | | - ;; test predicate |
| 230 | + ;; test predicate, go past body if false |
222 | 231 | (.ifZCmp method-gen GeneratorAdapter/EQ end-label) |
223 | 232 | ;; while body |
224 | 233 | (generate (:body statement) scopes method-gen) |
|
231 | 240 | "Generate a variable assignment statement. |
232 | 241 |
|
233 | 242 | TODO: Only works with locals, fix to work with class fields too." |
234 | | - ;; put source of assignment on stack |
235 | | - (generate (:source statement) scopes method-gen) |
236 | 243 | (let [target-name (:target statement)] |
237 | 244 | (or |
238 | | - (when-let [target (locate-arg target-name scopes)] |
| 245 | + (when-let [target (locate-arg target-name scopes)] |
| 246 | + ;; put source of assignment on stack |
| 247 | + (generate (:source statement) scopes method-gen) |
239 | 248 | (.storeArg method-gen |
240 | | - (:index target)) |
| 249 | + (:arg-index target)) |
241 | 250 | true) |
242 | 251 | (when-let [target (locate-local target-name scopes)] |
| 252 | + ;; put source of assignment on stack |
| 253 | + (generate (:source statement) scopes method-gen) |
243 | 254 | (.storeLocal method-gen |
244 | | - (:index target) |
| 255 | + (:ref-index target) |
245 | 256 | (-> target :type type->Type)) |
246 | 257 | true) |
247 | 258 | (let [target (semantics/locate-var target-name scopes)] |
| 259 | + (.loadThis method-gen) |
| 260 | + ;; put source of assignment on stack |
| 261 | + (generate (:source statement) scopes method-gen) |
| 262 | + ;; store field |
248 | 263 | (.putField method-gen |
249 | 264 | (:class-type scopes) |
250 | 265 | target-name |
251 | 266 | (-> target :type type->Type)))))) |
252 | 267 |
|
| 268 | +(defmethod generate :array-assign-statement [statement scopes method-gen] |
| 269 | + "Generate an array assignment statement." |
| 270 | + |
| 271 | + (let [target-name (:target statement)] |
| 272 | + (or ;; put array reference on stack |
| 273 | + (when-let [target (locate-arg target-name scopes)] |
| 274 | + (.loadArg method-gen |
| 275 | + (:arg-index target)) |
| 276 | + true) |
| 277 | + (when-let [target (locate-local target-name scopes)] |
| 278 | + (.loadLocal method-gen |
| 279 | + (:ref-index target) |
| 280 | + (-> target :type type->Type)) |
| 281 | + true) |
| 282 | + (let [target (semantics/locate-var target-name scopes)] |
| 283 | + (.loadThis method-gen) |
| 284 | + (.getField method-gen |
| 285 | + (:class-type scopes) |
| 286 | + target-name |
| 287 | + (-> target :type type->Type)))) |
| 288 | + ;; put array index on stack |
| 289 | + (generate (:index statement) scopes method-gen) |
| 290 | + ;; put value to store in array on stack |
| 291 | + (generate (:source statement) scopes method-gen) |
| 292 | + ;; store value in array |
| 293 | + (.arrayStore method-gen Type/INT_TYPE))) |
| 294 | + |
253 | 295 | (defmethod generate :print-statement [statement scopes method-gen] |
254 | 296 | (.getStatic method-gen |
255 | 297 | (Type/getType System) |
|
264 | 306 | (generate (:return-value statement) scopes method-gen) |
265 | 307 | (.returnValue method-gen)) |
266 | 308 |
|
| 309 | +(defn- rebind-arg [argument index scopes method-gen] |
| 310 | + (generate argument scopes method-gen) |
| 311 | + (.storeArg method-gen index)) |
| 312 | + |
| 313 | +(defmethod generate :recur-statement [statement scopes method-gen start-label] |
| 314 | + (let [base-label (.newLabel method-gen)] |
| 315 | + (generate (:pred statement) scopes method-gen) |
| 316 | + ;; if predicate is false, goto base case |
| 317 | + (.ifZCmp method-gen GeneratorAdapter/EQ base-label) |
| 318 | + ;; when predicate is true, evaluate arguments, rebind and recur: |
| 319 | + ;; evaluate arguments |
| 320 | + (doseq [arg (:args statement)] |
| 321 | + (generate arg scopes method-gen)) |
| 322 | + ;; rebind arguments |
| 323 | + (doseq [index (-> statement :args count range reverse)] |
| 324 | + (.storeArg method-gen index)) |
| 325 | + ;; recur |
| 326 | + (.goTo method-gen start-label) |
| 327 | + ;; base case |
| 328 | + (.mark method-gen base-label) |
| 329 | + (generate (:base statement) scopes method-gen) |
| 330 | + (.returnValue method-gen))) |
| 331 | + |
| 332 | +(defmethod generate :array-access-expression [expression scopes method-gen] |
| 333 | + (generate (:array expression) scopes method-gen) |
| 334 | + (generate (:index expression) scopes method-gen) |
| 335 | + (.arrayLoad method-gen Type/INT_TYPE)) |
| 336 | + |
| 337 | +(defmethod generate :array-length-expression [expression scopes method-gen] |
| 338 | + ;; load array reference on stack |
| 339 | + (generate (:array expression) scopes method-gen) |
| 340 | + ;; load length of array reference on stack |
| 341 | + (.arrayLength method-gen)) |
| 342 | + |
267 | 343 | (defn- binary-expression [expression scopes method-gen] |
268 | 344 | (generate (:left expression) scopes method-gen) |
269 | 345 | (generate (:right expression) scopes method-gen)) |
|
310 | 386 | (unary-expression expression scopes method-gen) |
311 | 387 | (.math method-gen GeneratorAdapter/NEG Type/INT_TYPE)) |
312 | 388 |
|
| 389 | +(defmethod generate :array-instantiation-expression [expression scopes |
| 390 | + method-gen] |
| 391 | + (generate (:size expression) scopes method-gen) |
| 392 | + (.newArray method-gen Type/INT_TYPE)) |
| 393 | + |
313 | 394 | (defmethod generate :method-call-expression [expression scopes method-gen] |
314 | 395 | ;; push caller onto stack |
315 | 396 | (generate (:caller expression) scopes method-gen) |
|
325 | 406 | signature (method-signature method)] |
326 | 407 | (.invokeVirtual method-gen |
327 | 408 | (Type/getObjectType caller-type) |
328 | | - (Method/getMethod signature)))) |
| 409 | + (Method/getMethod signature true)))) |
329 | 410 |
|
330 | 411 | (defmethod generate :int-lit-expression [expression scopes method-gen] |
331 | 412 | (.push method-gen (:value expression))) |
|
342 | 423 | (or |
343 | 424 | ;; load method argument |
344 | 425 | (when-let [var (locate-arg (:id expression) scopes)] |
345 | | - (.loadArg method-gen (:index var)) |
| 426 | + (.loadArg method-gen (:arg-index var)) |
346 | 427 | true) |
347 | 428 | ;; load local variable |
348 | 429 | (when-let [var (locate-local (:id expression) scopes)] |
349 | | - (.loadLocal method-gen (:index var)) |
| 430 | + (.loadLocal method-gen (:ref-index var)) |
350 | 431 | true) |
351 | 432 | ;; load non-static field |
352 | 433 | (let [field (semantics/locate-var (:id expression) scopes)] |
| 434 | + (.loadThis method-gen) |
353 | 435 | (.getField method-gen |
354 | 436 | ;; field owner |
355 | 437 | (:class-type scopes) |
|
0 commit comments