duby 0.0.2-java → 0.0.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. data/History.txt +7 -0
  2. data/README.txt +18 -7
  3. data/Rakefile +72 -0
  4. data/examples/ant/example-build.xml +7 -0
  5. data/examples/appengine/Rakefile +8 -67
  6. data/examples/appengine/Readme +4 -3
  7. data/examples/appengine/lib/duby/appengine_tasks.rb +173 -0
  8. data/examples/appengine/lib/duby/plugin/datastore.rb +92 -31
  9. data/examples/appengine/lib/duby_task.rb +61 -0
  10. data/examples/appengine/src/com/ribrdb/DubyApp.duby +32 -6
  11. data/examples/appengine/src/com/ribrdb/list.dhtml +2 -2
  12. data/examples/appengine/{config.ru → src/config.ru} +0 -0
  13. data/examples/bintrees.duby +66 -0
  14. data/examples/dynamic.duby +17 -0
  15. data/examples/fib.duby +3 -11
  16. data/examples/fields.duby +3 -3
  17. data/examples/fractal.duby +1 -3
  18. data/examples/sort_closure.duby +7 -0
  19. data/examples/swing.duby +11 -11
  20. data/javalib/duby-bootstrap.jar +0 -0
  21. data/javalib/dynalang-invoke-0.1.jar +0 -0
  22. data/lib/duby.rb +168 -35
  23. data/lib/duby/ast.rb +224 -27
  24. data/lib/duby/ast/call.rb +85 -25
  25. data/lib/duby/ast/class.rb +112 -28
  26. data/lib/duby/ast/flow.rb +65 -44
  27. data/lib/duby/ast/intrinsics.rb +223 -21
  28. data/lib/duby/ast/literal.rb +67 -16
  29. data/lib/duby/ast/local.rb +36 -40
  30. data/lib/duby/ast/method.rb +83 -67
  31. data/lib/duby/ast/structure.rb +105 -23
  32. data/lib/duby/compiler.rb +83 -28
  33. data/lib/duby/env.rb +33 -0
  34. data/lib/duby/jvm/base.rb +210 -0
  35. data/lib/duby/jvm/compiler.rb +293 -219
  36. data/lib/duby/jvm/method_lookup.rb +77 -67
  37. data/lib/duby/jvm/source_compiler.rb +250 -157
  38. data/lib/duby/jvm/source_generator/builder.rb +53 -49
  39. data/lib/duby/jvm/source_generator/loops.rb +9 -9
  40. data/lib/duby/jvm/source_generator/precompile.rb +35 -25
  41. data/lib/duby/jvm/typer.rb +19 -10
  42. data/lib/duby/jvm/types.rb +127 -68
  43. data/lib/duby/jvm/types/basic_types.rb +26 -13
  44. data/lib/duby/jvm/types/enumerable.rb +6 -4
  45. data/lib/duby/jvm/types/factory.rb +49 -13
  46. data/lib/duby/jvm/types/floats.rb +16 -0
  47. data/lib/duby/jvm/types/integers.rb +63 -2
  48. data/lib/duby/jvm/types/intrinsics.rb +43 -21
  49. data/lib/duby/jvm/types/methods.rb +326 -86
  50. data/lib/duby/jvm/types/number.rb +3 -0
  51. data/lib/duby/nbcompiler.rb +1 -1
  52. data/lib/duby/plugin/edb.rb +1 -1
  53. data/lib/duby/plugin/java.rb +10 -1
  54. data/lib/duby/transform.rb +134 -46
  55. data/lib/duby/typer.rb +75 -50
  56. data/test/test_ast.rb +106 -106
  57. data/test/test_compilation.rb +46 -32
  58. data/test/test_env.rb +42 -0
  59. data/test/test_java_typer.rb +35 -51
  60. data/test/test_javac_compiler.rb +4 -1
  61. data/test/test_jvm_compiler.rb +564 -133
  62. data/test/test_typer.rb +68 -92
  63. metadata +37 -21
  64. data/examples/README +0 -16
  65. data/lib/duby/c/compiler.rb +0 -134
  66. data/lib/duby/old/compiler_old.rb +0 -845
  67. data/lib/duby/old/declaration.rb +0 -72
  68. data/lib/duby/old/mapper.rb +0 -72
  69. data/lib/duby/old/signature.rb +0 -52
  70. data/lib/duby/old/typer_old.rb +0 -163
  71. data/lib/duby/plugin/math.rb +0 -84
  72. data/test/test_math_plugin.rb +0 -87
@@ -1,16 +0,0 @@
1
- Duby: A Type-Inferred Ruby-Like JVM Language
2
-
3
- Duby is an experimental project to create a JVM bytecode compiler for a
4
- Ruby-like language that infers static types from argument declarations
5
- and called methods. It is currently under development, but may eventually
6
- be used to implement portions of JRuby, since Duby combines the terse,
7
- neat syntax of Ruby with the performance of statically-typed Java
8
- bytecode.
9
-
10
- To compile the samples, run the following lines:
11
-
12
- jruby lib/ruby/site_ruby/1.8/compiler/duby/compiler.rb <filename>
13
-
14
- And to load and call them, use JRuby's Java integration:
15
-
16
- CLASSPATH=. jruby -rjava -e "p Java::Foo.new.fib(35)"
@@ -1,134 +0,0 @@
1
- require 'duby'
2
- require 'duby/compiler'
3
-
4
- module Duby
5
- module Compiler
6
- class C
7
- class MathCompiler
8
- def call(compiler, call)
9
- call.target.compile(compiler)
10
-
11
- compiler.src << " #{call.name} "
12
-
13
- call.parameters.each {|param| param.compile(compiler)}
14
- end
15
- end
16
-
17
- attr_accessor :filename, :src
18
-
19
- def initialize(filename)
20
- @filename = filename
21
- @src = ""
22
-
23
- self.type_mapper[AST::TypeReference.new(:fixnum)] = "int"
24
-
25
- self.call_compilers[AST::TypeReference.new(:fixnum)] = MathCompiler.new
26
- end
27
-
28
- def compile(ast)
29
- ast.compile(self)
30
- end
31
-
32
- def define_main(body)
33
- old_src, @src = @src, "int main(int argc, char **argv)\n{\n"
34
-
35
- body.compile(self)
36
-
37
- @src << "}\n\n"
38
-
39
- @src = old_src + @src
40
- end
41
-
42
- def define_method(name, signature, args, body)
43
- old_src, @src = @src, "#{type_mapper[signature[:return]]} #{name}("
44
-
45
- args.compile(self)
46
-
47
- @src << ")\n{\n"
48
-
49
- body.compile(self)
50
-
51
- @src << "\n}\n\n"
52
-
53
- @src = old_src + @src
54
- end
55
-
56
- def declare_argument(name, type)
57
- @src << "#{type_mapper[type]} #{name}"
58
- end
59
-
60
- def branch(iff)
61
- @src << "if ("
62
-
63
- iff.condition.compile(self)
64
-
65
- @src << ") {"
66
-
67
- iff.body.compile(self)
68
-
69
- if iff.else
70
- @src << "} else {"
71
-
72
- iff.else.compile(self)
73
- end
74
-
75
- @src << "}"
76
- end
77
-
78
- def call(call)
79
- call_compilers[call.target.inferred_type].call(self, call)
80
- end
81
-
82
- def call_compilers
83
- @call_compilers ||= {}
84
- end
85
-
86
- def self_call(fcall)
87
- @src << "#{fcall.name}("
88
-
89
- fcall.parameters.each {|param| param.compile(self)}
90
-
91
- @src << ")"
92
- end
93
-
94
- def local(name, type)
95
- @src << name
96
- end
97
-
98
- def fixnum(value)
99
- @src << value.to_s
100
- end
101
-
102
- def newline
103
- @src << ";\n"
104
- end
105
-
106
- def ret
107
- @src << "return "
108
-
109
- yield
110
- end
111
-
112
- def generate
113
- @src
114
- end
115
-
116
- def type_mapper
117
- @type_mapper ||= {}
118
- end
119
- end
120
- end
121
- end
122
-
123
- if __FILE__ == $0
124
- ast = Duby::AST.parse(File.read(ARGV[0]))
125
-
126
- typer = Duby::Typer::Simple.new(:script)
127
- ast.infer(typer)
128
- typer.resolve(true)
129
-
130
- compiler = Duby::Compiler::C.new("#{ARGV[0]}.c")
131
- ast.compile(compiler)
132
-
133
- File.open(compiler.filename, "w") {|file| file.write(compiler.generate)}
134
- end
@@ -1,845 +0,0 @@
1
- require 'compiler/builder'
2
- require 'duby/typer'
3
- require 'duby/signature'
4
- require 'duby/mapper'
5
- require 'duby/declaration'
6
- require 'jruby'
7
-
8
- # I don't like these at top-level, but reopened Java classes have trouble with const lookup
9
- def log(str)
10
- puts str if $VERBOSE
11
- end
12
-
13
- class CompileError < Exception
14
- def initialize(position, message)
15
- full_message = "Compile error at #{position.file}:#{position.start_line}: #{message}"
16
- super(full_message)
17
- end
18
- end
19
-
20
- module Compiler
21
- module PrimitiveRuby
22
- JObject = java.lang.Object.java_class
23
- JClass = java.lang.Class.java_class
24
- JString = java.lang.String.java_class
25
- Void = java.lang.Void::TYPE
26
- System = java.lang.System.java_class
27
- PrintStream = java.io.PrintStream.java_class
28
- JInteger = java.lang.Integer.java_class
29
- Jbyte = Java::byte.java_class
30
- Jchar = Java::char.java_class
31
- Jshort = Java::short.java_class
32
- Jint = Java::int.java_class
33
- Jlong = Java::long.java_class
34
- Jfloat = Java::float.java_class
35
- Jdouble = Java::double.java_class
36
- Jboolean = Java::boolean.java_class
37
- JavaClass = Java::JavaClass
38
-
39
- # reload
40
- module Java::OrgJrubyAst
41
- class Node
42
- def compile(builder)
43
- # default behavior is to raise, to expose missing nodes
44
- raise CompileError.new(position, "Unsupported syntax: #{self}")
45
- end
46
- end
47
-
48
- class ArgsNode
49
- def compile(builder)
50
- raise("PRuby only supports normal args") if opt_args || rest_arg != -1 || block_arg_node
51
- return unless args
52
- args.child_nodes.each do |arg|
53
- builder.local(arg.name)
54
- end
55
- end
56
- end
57
-
58
- class ArrayNode
59
- def compile(builder)
60
- # not implemented
61
- raise
62
- end
63
- end
64
-
65
- class BeginNode
66
- def compile(builder)
67
- body_node.compile(builder)
68
- end
69
- end
70
-
71
- class BlockNode
72
- def compile(builder)
73
- size = child_nodes.size
74
- if size == 0
75
- case type
76
- when Jint
77
- builder.iconst_0
78
- else
79
- builder.aconst_null
80
- end
81
- else
82
- i = 0
83
- while i < size
84
- node = child_nodes.get(i)
85
- node = node.next_node while NewlineNode === node
86
- next unless node
87
-
88
- builder.line node.position.start_line + 1
89
-
90
- node.compile(builder)
91
-
92
- if i + 1 < size
93
- builder.pop if builder.method?
94
- end
95
-
96
- i += 1
97
- end
98
- end
99
- end
100
- end
101
-
102
- class ClassNode
103
- def compile(builder)
104
- cb = builder.public_class(cpath.name)
105
- body_node.compile(cb)
106
- end
107
- end
108
-
109
- class CallNode
110
- def compile(builder)
111
- receiver_type = receiver_node.type(builder)
112
-
113
- if receiver_type.primitive?
114
- # we're performing an operation against a primitive, map it accordingly
115
- log "Compiling #{name} at #{position.start_line} as primitive op"
116
- compile_primitive(receiver_type, builder)
117
- elsif receiver_type.array?
118
- log "Compiling #{name} at #{position.start_line} as array op"
119
- compile_array(receiver_type, builder)
120
- else
121
- case name
122
- when "new"
123
- log "Compiling #{name} at #{position.start_line} as object instantiation"
124
- compile_new(receiver_type, builder)
125
- else
126
- log "Compiling #{name} at #{position.start_line} as call"
127
- compile_call(receiver_type, builder)
128
- end
129
- end
130
- end
131
-
132
- def compile_call(receiver_type, builder)
133
- case receiver_node
134
- when ConstNode
135
- # static call
136
- static = true
137
- else
138
- receiver_node.compile(builder)
139
- end
140
-
141
- # I removed this because inference is working...but will it be needed under some circumstances?
142
- # # inefficient to cast every time; better inference will help
143
- # builder.checkcast(receiver_type)
144
-
145
- compile_args(builder)
146
-
147
- if static
148
- builder.invokestatic receiver_type, mapped_name(builder), signature(builder)
149
- else
150
- if (receiver_type.interface?)
151
- builder.invokeinterface receiver_type, mapped_name(builder), signature(builder)
152
- else
153
- builder.invokevirtual receiver_type, mapped_name(builder), signature(builder)
154
- end
155
- end
156
- end
157
-
158
- def compile_args(builder)
159
- args_list = args_node.child_nodes.to_a
160
- args_list.each_index do |idx|
161
- node = args_list[idx]
162
- node.compile(builder)
163
- end
164
- end
165
-
166
- def compile_primitive(type, builder)
167
- receiver_node.compile(builder)
168
-
169
- if !args_node
170
- case type
171
- when Jboolean, Jbyte, Jshort, Jchar
172
- # TODO: cast and do the same as int
173
- raise CompileError.new(position, "Unary primitive operations on #{type} not supported")
174
- when Jint
175
- case name
176
- when "-@"
177
- builder.ineg
178
- when "+@"
179
- # do nothing
180
- else
181
- raise CompileError.new(position, "Primitive int operation #{name} not supported")
182
- end
183
- when Jlong
184
- case name
185
- when "-@"
186
- builder.lneg
187
- when "+@"
188
- # do nothing
189
- else
190
- raise CompileError.new(position, "Primitive long operation #{name} not supported")
191
- end
192
- when Jfloat
193
- case name
194
- when "-@"
195
- builder.fneg
196
- when "+@"
197
- # do nothing
198
- else
199
- raise CompileError.new(position, "Primitive float operation #{name} not supported")
200
- end
201
- when Jdouble
202
- case name
203
- when "-@"
204
- builder.dneg
205
- when "+@"
206
- # do nothing
207
- else
208
- raise CompileError.new(position, "Primitive double operation #{name} not supported")
209
- end
210
- else
211
- raise CompileError.new(position, "Unary primitive operations on #{type} not supported")
212
- end
213
- elsif args_node.size != 1
214
- raise CompileError.new(position, "Binary primitive operations require exactly one argument")
215
- else
216
- node = args_node.get(0)
217
- # TODO: check or cast types according to receiver's type
218
- node.compile(builder)
219
-
220
- case type
221
- when Jboolean, Jbyte, Jshort, Jchar
222
- # TODO: cast and do the same as int
223
- raise CompileError.new(position, "Binary primitive operations on #{type} not supported")
224
- when Jint
225
- case name
226
- when "+"
227
- builder.iadd
228
- when "-"
229
- builder.isub
230
- when "/"
231
- builder.idiv
232
- when "*"
233
- builder.imul
234
- when "&"
235
- builder.iand
236
- when "|"
237
- builder.ior
238
- when "^"
239
- builder.ixor
240
- else
241
- raise CompileError.new(position, "Primitive int operation #{name} not supported")
242
- end
243
- when Jlong
244
- case name
245
- when "+"
246
- builder.ladd
247
- when "-"
248
- builder.lsub
249
- when "/"
250
- builder.ldiv
251
- when "*"
252
- builder.lmul
253
- when "&"
254
- builder.land
255
- when "|"
256
- builder.lor
257
- when "^"
258
- builder.lxor
259
- else
260
- raise CompileError.new(position, "Primitive long operation #{name} not supported")
261
- end
262
- when Jfloat
263
- case name
264
- when "+"
265
- builder.fadd
266
- when "-"
267
- builder.fsub
268
- when "/"
269
- builder.fdiv
270
- when "*"
271
- builder.fmul
272
- else
273
- raise CompileError.new(position, "Primitive float operation #{name} not supported")
274
- end
275
- when Jdouble
276
- case name
277
- when "+"
278
- builder.dadd
279
- when "-"
280
- builder.dsub
281
- when "/"
282
- builder.ddiv
283
- when "*"
284
- builder.dmul
285
- else
286
- raise CompileError.new(position, "Primitive double operation #{name} not supported")
287
- end
288
- else
289
- raise CompileError.new(position, "Primitive #{type} operations not supported")
290
- end
291
- end
292
- end
293
-
294
- def compile_array(type, builder)
295
- receiver_node.compile(builder)
296
-
297
- case name
298
- when "length"
299
- if args_node
300
- raise CompileError.new(position, "Array length does not take an argument")
301
- end
302
-
303
- builder.arraylength
304
- when "[]"
305
- if !args_node || args_node.size != 1
306
- raise CompileError.new(position, "Array accessignment must have exactly one argument")
307
- end
308
-
309
- node = args_node.get(0)
310
- # TODO: check or cast to int for indexing
311
- node.compile(builder)
312
-
313
- if type.component_type.primitive?
314
- case type.component_type
315
- when Jboolean, Jbyte
316
- builder.baload
317
- when Jchar
318
- builder.caload
319
- when Jshort
320
- builder.saload
321
- when Jint
322
- builder.iaload
323
- when Jlong
324
- builder.laload
325
- when Jfloat
326
- builder.faload
327
- when Jdouble
328
- builder.daload
329
- end
330
- else
331
- builder.aaload
332
- end
333
- when "[]="
334
- if !args_node || args_node.size != 2
335
- raise CompileError.new(position, "Array assignment must have exactly two arguments")
336
- end
337
-
338
- # TODO: check or cast to int for indexing
339
- args_node.get(0).compile(builder)
340
- # TODO: check type matches?
341
- args_node.get(1).compile(builder)
342
-
343
- builder.aastore
344
- else
345
- raise CompileError.new(position, "Array operation #{name} not supported")
346
- end
347
- end
348
-
349
- def compile_new(type, builder)
350
- builder.new type
351
- builder.dup
352
-
353
- compile_args(builder)
354
-
355
- builder.invokespecial type, mapped_name(builder), signature(builder)
356
- end
357
- end
358
-
359
- class Colon2Node
360
- end
361
-
362
- class ConstNode
363
- end
364
-
365
- class DefnNode
366
- def compile(builder)
367
- first_real_node = body_node
368
- first_real_node = body_node.child_nodes[0] if BlockNode === body_node
369
- while NewlineNode === first_real_node
370
- first_real_node = first_real_node.next_node
371
- end
372
-
373
- # determine signature from declaration line
374
- signature = first_real_node.signature(builder) if HashNode === first_real_node
375
-
376
- signature ||= [Void]
377
-
378
- log "Compiling instance method for #{name} as #{signature.join(',')}"
379
- builder.method(mapped_name(builder), *signature) do |method|
380
- # Run through any type declarations first
381
- first_real_node.declare_types(method) if HashNode === first_real_node
382
-
383
- # declare args that may not have been declared already
384
- args_node.compile(method)
385
-
386
- body_node.compile(method) if body_node
387
-
388
- # Expectation is that last element leaves the right type on stack
389
- if signature[0].primitive?
390
- case signature[0]
391
- when Void
392
- method.returnvoid
393
- when Jboolean, Jbyte
394
- method.breturn
395
- when Jchar
396
- method.creturn
397
- when Jshort
398
- method.sreturn
399
- when Jint
400
- method.ireturn
401
- when Jlong
402
- method.lreturn
403
- when Jfloat
404
- method.freturn
405
- when Jdouble
406
- method.dreturn
407
- else
408
- raise CompileError.new(position, "Unknown return type: #{signature[0]}")
409
- end
410
- else
411
- method.areturn
412
- end
413
- end
414
- end
415
- end
416
-
417
- class DefsNode
418
- def compile(builder)
419
- first_real_node = body_node
420
- first_real_node = body_node.child_nodes[0] if BlockNode === body_node
421
- while NewlineNode === first_real_node
422
- first_real_node = first_real_node.next_node
423
- end
424
-
425
- # determine signature from declaration line
426
- signature = first_real_node.signature(builder) if HashNode === first_real_node
427
-
428
- signature ||= [Void]
429
-
430
- log "Compiling static method for #{name} as #{signature.join(',')}"
431
- builder.static_method(name, *signature) do |method|
432
- # Run through any type declarations first
433
- first_real_node.declare_types(method) if HashNode === first_real_node
434
-
435
- # declare args that may not have been declared already
436
- args_node.compile(method)
437
-
438
- body_node.compile(method) if body_node
439
-
440
- # Expectation is that last element leaves the right type on stack
441
- if signature[0].primitive?
442
- case signature[0]
443
- when Void
444
- method.returnvoid
445
- when Jboolean, Jbyte
446
- method.breturn
447
- when Jchar
448
- method.creturn
449
- when Jshort
450
- method.sreturn
451
- when Jint
452
- method.ireturn
453
- when Jlong
454
- method.lreturn
455
- when Jfloat
456
- method.freturn
457
- when Jdouble
458
- method.dreturn
459
- else
460
- raise CompileError.new(position, "Unknown return type: #{signature[0]}")
461
- end
462
- else
463
- method.areturn
464
- end
465
- end
466
- end
467
- end
468
-
469
- class FCallNode
470
- def compile(builder)
471
- case name
472
- when "puts"
473
- compile_puts(builder)
474
- when "import"
475
- compile_import(builder)
476
- else
477
- if (builder.static)
478
- arg_types = []
479
- args_node.child_nodes.each do |node|
480
- node.compile(builder)
481
- arg_types << node.type(builder)
482
- end
483
-
484
- builder.invokestatic builder.this, name, builder.static_signature(name, arg_types)
485
- else
486
- builder.aload 0
487
- arg_types = []
488
- args_node.child_nodes.each do |node|
489
- node.compile(builder)
490
- arg_types << node.type(builder)
491
- end
492
-
493
- builder.invokevirtual builder.this, name, builder.instance_signature(name, arg_types)
494
- end
495
- end
496
- end
497
-
498
- def compile_puts(builder)
499
- log "Compiling special #{name} at #{position.start_line}"
500
- builder.getstatic System, "out", [PrintStream]
501
-
502
- arg_types = []
503
- args_node.child_nodes.each do |node|
504
- node.compile(builder)
505
- arg_types << node.type(builder)
506
- end
507
-
508
- builder.invokevirtual PrintStream, "println", special_signature(PrintStream, builder)
509
- builder.aconst_null
510
- end
511
-
512
- def compile_import(builder)
513
- log "Compiling import at #{position.start_line}"
514
- args_node.child_nodes.each do |node|
515
- case node
516
- when StrNode
517
- builder.import(node.value)
518
- else
519
- raise CompileError.new(position, "Imports only allow strings right now")
520
- end
521
- end
522
- end
523
- end
524
-
525
- class FixnumNode
526
- def compile(builder)
527
- builder.ldc_int(value)
528
- end
529
- end
530
-
531
- class FloatNode
532
- def compile(builder)
533
- builder.ldc_float(value)
534
- end
535
- end
536
-
537
- class HashNode
538
- def compile(builder)
539
- @declared ||= false
540
-
541
- if @declared
542
- # hash was used for type declaration, so we just push a null to skip it
543
- # TODO: it would be nice if we could just skip the null too, but BlockNode wants to pop it
544
- builder.aconst_null
545
- else
546
- raise CompileError.new(position, "Literal hash syntax not yet supported")
547
- end
548
- end
549
- end
550
-
551
- class IfNode
552
- def compile(builder)
553
- else_lbl = builder.label
554
- done = builder.label
555
- condition = self.condition
556
- condition = condition.next_node while NewlineNode === condition
557
-
558
- case condition
559
- when CallNode
560
- args = condition.args_node
561
- receiver_type = condition.receiver_node.type(builder)
562
-
563
- if receiver_type.primitive?
564
- case condition.name
565
- when "<"
566
- raise CompileError.new(position, "Primitive < must have exactly one argument") if !args || args.size != 1
567
-
568
- condition.receiver_node.compile(builder)
569
- args.get(0).compile(builder)
570
-
571
- # >= is else for <
572
- case receiver_type
573
- when Jint
574
- builder.if_icmpge(else_lbl)
575
- else
576
- raise CompileError.new(position, "Primitive < is only supported for int")
577
- end
578
- when ">"
579
- raise CompileError.new(position, "Primitive > must have exactly one argument") if !args || args.size != 1
580
-
581
- condition.receiver_node.compile(builder)
582
- args.get(0).compile(builder)
583
-
584
- # <= is else for >
585
- case receiver_type
586
- when Jint
587
- builder.if_icmple(else_lbl)
588
- else
589
- raise CompileError.new(position, "Primitive > is only supported for int")
590
- end
591
- when "=="
592
- raise CompileError.new(position, "Primitive == must have exactly one argument") if !args || args.size != 1
593
-
594
- condition.receiver_node.compile(builder)
595
- args.get(0).compile(builder)
596
-
597
- # ne is else for ==
598
- case receiver_type
599
- when Jint
600
- builder.if_icmpne(else_lbl)
601
- else
602
- raise CompileError.new(position, "Primitive == is only supported for int")
603
- end
604
- else
605
- raise CompileError.new(position, "Conditional not supported: #{condition.inspect}")
606
- end
607
-
608
- then_body.compile(builder)
609
- builder.goto(done)
610
-
611
- else_lbl.set!
612
- else_body.compile(builder)
613
-
614
- done.set!
615
- else
616
- raise CompileError.new(position, "Conditional on non-primitives not supported: #{condition.inspect}")
617
- end
618
- else
619
- raise CompileError.new(position, "Non-call conditional not supported: #{condition.inspect}")
620
- end
621
- end
622
- end
623
-
624
- class InstAsgnNode
625
- def compile(builder)
626
- builder.field(mapped_name(builder), value_node.type(builder))
627
-
628
- # assignment consumes the value, so we dup it
629
- # TODO inefficient if we don't need the result
630
- value_node.compile(builder)
631
- builder.dup
632
-
633
- builder.putfield(mapped_name(builder))
634
- end
635
- end
636
-
637
- class InstVarNode
638
- def compile(builder)
639
- builder.getfield(mapped_name(builder))
640
- end
641
- end
642
-
643
- class LocalAsgnNode
644
- def compile(builder)
645
- local_index = builder.local(name, value_node.type(builder))
646
-
647
- # assignment consumes a value, so we dup it
648
- # TODO: inefficient if we don't actually need the result
649
- value_node.compile(builder)
650
- builder.dup
651
-
652
- case type(builder)
653
- when Jboolean
654
- builder.bistore(local_index)
655
- when Jint
656
- builder.istore(local_index)
657
- when Jlong
658
- builder.lstore(local_index)
659
- when Jfloat
660
- builder.fstore(local_index)
661
- when Jdouble
662
- builder.dstore(local_index)
663
- else
664
- builder.astore(local_index)
665
- end
666
- end
667
- end
668
-
669
- class LocalVarNode
670
- def compile(builder)
671
- local_index = builder.local(name)
672
- case type(builder)
673
- when Jboolean
674
- builder.biload(local_index)
675
- when Jint
676
- builder.iload(local_index)
677
- when Jlong
678
- builder.lload(local_index)
679
- when Jfloat
680
- builder.fload(local_index)
681
- when Jdouble
682
- builder.dload(local_index)
683
- else
684
- builder.aload(local_index)
685
- end
686
- end
687
- end
688
-
689
- class ModuleNode
690
- def compile(builder)
691
- builder.package(cpath.name) {
692
- body_node.compile(builder)
693
- }
694
- end
695
- end
696
-
697
- class NewlineNode
698
- def compile(builder)
699
- builder.line position.start_line
700
- next_node.compile(builder)
701
- end
702
- end
703
-
704
- class ReturnNode
705
- def compile(builder)
706
- value_node.compile(builder)
707
- builder.areturn
708
- end
709
- end
710
-
711
- class RootNode
712
- def compile(builder)
713
- # builder is class builder
714
-
715
- if body_node
716
- body_node.compile(builder)
717
- end
718
- end
719
- end
720
-
721
- class SelfNode
722
- def compile(builder)
723
- builder.local("this")
724
- end
725
- end
726
-
727
- class StrNode
728
- def compile(builder)
729
- builder.ldc value
730
- end
731
- end
732
-
733
- class SymbolNode
734
- end
735
-
736
- class VCallNode
737
- def compile(builder)
738
- if builder.static
739
- builder.invokestatic builder.this, name, builder.static_signature(name, [])
740
- else
741
- builder.aload 0
742
-
743
- builder.invokevirtual builder.this, name, builder.instance_signature(name, [])
744
- end
745
- end
746
- end
747
-
748
- class WhileNode
749
- def compile(builder)
750
- begin_lbl = builder.label
751
- end_lbl = builder.label
752
- cond_lbl = builder.label
753
-
754
- case body_node.type(builder)
755
- when Jint
756
- builder.iconst_0
757
- else
758
- builder.aconst_null
759
- end
760
-
761
- if evaluate_at_start
762
- builder.goto cond_lbl
763
- end
764
-
765
- begin_lbl.set!
766
- builder.pop
767
- body_node.compile(builder)
768
-
769
- cond_lbl.set!
770
- compile_condition(builder, begin_lbl)
771
- end_lbl.set!
772
- end
773
-
774
- def compile_condition(builder, begin_lbl)
775
- condition = condition_node
776
- condition = condition.next_node while NewlineNode === condition
777
-
778
- case condition
779
- when CallNode
780
- args = condition.args_node
781
- receiver_type = condition.receiver_node.type(builder)
782
-
783
- if receiver_type.primitive?
784
- case condition.name
785
- when "<"
786
- raise CompileError.new(position, "Primitive < must have exactly one argument") if !args || args.size != 1
787
-
788
- condition.receiver_node.compile(builder)
789
- args.get(0).compile(builder)
790
-
791
- case receiver_type
792
- when Jint
793
- builder.if_icmplt(begin_lbl)
794
- else
795
- raise CompileError.new(position, "Primitive < is only supported for int")
796
- end
797
- when ">"
798
- raise CompileError.new(position, "Primitive > must have exactly one argument") if !args || args.size != 1
799
-
800
- condition.receiver_node.compile(builder)
801
- args.get(0).compile(builder)
802
-
803
- case receiver_type
804
- when Jint
805
- builder.if_icmpgt(begin_lbl)
806
- else
807
- raise CompileError.new(position, "Primitive < is only supported for int")
808
- end
809
- else
810
- raise CompileError.new(position, "Conditional not supported: #{condition.inspect}")
811
- end
812
- else
813
- raise CompileError.new(position, "Conditional on non-primitives not supported: #{condition.inspect}")
814
- end
815
- else
816
- raise CompileError.new(position, "Non-call conditional not supported: #{condition.inspect}")
817
- end
818
- end
819
- end
820
- end
821
- end
822
- end
823
-
824
- if $0 == __FILE__
825
- n = JRuby.parse(File.read(ARGV[0]), ARGV[0])
826
- compiler = JVMScript::FileBuilder.new(ARGV[0])
827
- begin
828
- n.compile(compiler)
829
-
830
- compiler.generate do |filename, builder|
831
- puts "Compiling #{builder.class_name.gsub('/', '.')}.class"
832
-
833
- class_name = builder.class_name
834
- if class_name.rindex('/')
835
- dir = class_name[0..class_name.rindex('/')]
836
- FileUtils.mkdir_p(dir)
837
- end
838
-
839
- File.open(filename, 'w') {|file| file.write(builder.generate)}
840
- end
841
- rescue CompileError => e
842
- puts e
843
- puts e.backtrace
844
- end
845
- end