duby 0.0.2-java → 0.0.3-java

Sign up to get free protection for your applications and to get access to all the features.
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