mirah 0.0.4-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 (141) hide show
  1. data/History.txt +15 -0
  2. data/README.txt +51 -0
  3. data/Rakefile +86 -0
  4. data/bin/duby +10 -0
  5. data/bin/dubyc +10 -0
  6. data/bin/dubyp +10 -0
  7. data/bin/jrubyp +36 -0
  8. data/bin/mirah +9 -0
  9. data/bin/mirah.cmd +1 -0
  10. data/bin/mirahc +9 -0
  11. data/bin/mirahc.cmd +1 -0
  12. data/bin/mirahp +9 -0
  13. data/bin/mirahp.cmd +1 -0
  14. data/examples/ant/example-build.xml +7 -0
  15. data/examples/appengine/Rakefile +19 -0
  16. data/examples/appengine/Readme +29 -0
  17. data/examples/appengine/src/org/mirah/MirahApp.mirah +57 -0
  18. data/examples/appengine/src/org/mirah/list.dhtml +15 -0
  19. data/examples/appengine/war/WEB-INF/lib/dubydatastore.jar +0 -0
  20. data/examples/bintrees.mirah +66 -0
  21. data/examples/construction.mirah +8 -0
  22. data/examples/dynamic.mirah +17 -0
  23. data/examples/edb.mirah +3 -0
  24. data/examples/fib.mirah +16 -0
  25. data/examples/fields.mirah +22 -0
  26. data/examples/fractal.mirah +55 -0
  27. data/examples/java_thing.mirah +13 -0
  28. data/examples/plugins/appengine/Rakefile +55 -0
  29. data/examples/plugins/appengine/lib/com/google/appengine/ext/duby/db/datastore.rb +375 -0
  30. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +336 -0
  31. data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +113 -0
  32. data/examples/simple_class.mirah +12 -0
  33. data/examples/sort_closure.mirah +7 -0
  34. data/examples/swing.mirah +20 -0
  35. data/examples/tak.mirah +15 -0
  36. data/examples/test.edb +9 -0
  37. data/examples/wiki/Rakefile +18 -0
  38. data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +324 -0
  39. data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +42 -0
  40. data/examples/wiki/src/org/mirah/wiki/error.eduby.html +2 -0
  41. data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +69 -0
  42. data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +7 -0
  43. data/examples/wiki/src/org/mirah/wiki/view.eduby.html +15 -0
  44. data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
  45. data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
  46. data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
  47. data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
  48. data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
  49. data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
  50. data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
  51. data/examples/wiki/war/app.yaml +21 -0
  52. data/examples/wiki/war/public/favicon.ico +0 -0
  53. data/examples/wiki/war/public/images/appengine_duby.png +0 -0
  54. data/examples/wiki/war/public/images/back.gif +0 -0
  55. data/examples/wiki/war/public/images/dir.gif +0 -0
  56. data/examples/wiki/war/public/images/file.gif +0 -0
  57. data/examples/wiki/war/public/javascripts/prettify.js +61 -0
  58. data/examples/wiki/war/public/robots.txt +0 -0
  59. data/examples/wiki/war/public/stylesheets/main.css +156 -0
  60. data/examples/wiki/war/public/stylesheets/prettify.css +1 -0
  61. data/examples/wiki/war/public/stylesheets/sh_style.css +66 -0
  62. data/examples/wiki/war/public/stylesheets/source.css +21 -0
  63. data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
  64. data/examples/wiki/war/public/wmd/images/bg.png +0 -0
  65. data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
  66. data/examples/wiki/war/public/wmd/images/bold.png +0 -0
  67. data/examples/wiki/war/public/wmd/images/code.png +0 -0
  68. data/examples/wiki/war/public/wmd/images/h1.png +0 -0
  69. data/examples/wiki/war/public/wmd/images/hr.png +0 -0
  70. data/examples/wiki/war/public/wmd/images/img.png +0 -0
  71. data/examples/wiki/war/public/wmd/images/italic.png +0 -0
  72. data/examples/wiki/war/public/wmd/images/link.png +0 -0
  73. data/examples/wiki/war/public/wmd/images/ol.png +0 -0
  74. data/examples/wiki/war/public/wmd/images/redo.png +0 -0
  75. data/examples/wiki/war/public/wmd/images/separator.png +0 -0
  76. data/examples/wiki/war/public/wmd/images/ul.png +0 -0
  77. data/examples/wiki/war/public/wmd/images/undo.png +0 -0
  78. data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
  79. data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
  80. data/examples/wiki/war/public/wmd/showdown.js +421 -0
  81. data/examples/wiki/war/public/wmd/wmd-base.js +1799 -0
  82. data/examples/wiki/war/public/wmd/wmd-plus.js +311 -0
  83. data/examples/wiki/war/public/wmd/wmd.js +73 -0
  84. data/javalib/JRubyParser.jar +0 -0
  85. data/javalib/dynalang-invoke-0.1.jar +0 -0
  86. data/javalib/mirah-bootstrap.jar +0 -0
  87. data/javalib/mirah-parser.jar +0 -0
  88. data/lib/duby.rb +2 -0
  89. data/lib/mirah.rb +338 -0
  90. data/lib/mirah/appengine_tasks.rb +146 -0
  91. data/lib/mirah/ast.rb +615 -0
  92. data/lib/mirah/ast/call.rb +307 -0
  93. data/lib/mirah/ast/class.rb +311 -0
  94. data/lib/mirah/ast/flow.rb +364 -0
  95. data/lib/mirah/ast/intrinsics.rb +470 -0
  96. data/lib/mirah/ast/literal.rb +154 -0
  97. data/lib/mirah/ast/local.rb +89 -0
  98. data/lib/mirah/ast/method.rb +360 -0
  99. data/lib/mirah/ast/scope.rb +208 -0
  100. data/lib/mirah/ast/structure.rb +226 -0
  101. data/lib/mirah/ast/type.rb +130 -0
  102. data/lib/mirah/compiler.rb +341 -0
  103. data/lib/mirah/env.rb +33 -0
  104. data/lib/mirah/jvm/base.rb +258 -0
  105. data/lib/mirah/jvm/compiler.rb +885 -0
  106. data/lib/mirah/jvm/method_lookup.rb +203 -0
  107. data/lib/mirah/jvm/source_compiler.rb +737 -0
  108. data/lib/mirah/jvm/source_generator/builder.rb +444 -0
  109. data/lib/mirah/jvm/source_generator/loops.rb +110 -0
  110. data/lib/mirah/jvm/source_generator/precompile.rb +188 -0
  111. data/lib/mirah/jvm/source_generator/typer.rb +11 -0
  112. data/lib/mirah/jvm/typer.rb +151 -0
  113. data/lib/mirah/jvm/types.rb +416 -0
  114. data/lib/mirah/jvm/types/basic_types.rb +33 -0
  115. data/lib/mirah/jvm/types/boolean.rb +17 -0
  116. data/lib/mirah/jvm/types/enumerable.rb +65 -0
  117. data/lib/mirah/jvm/types/extensions.rb +86 -0
  118. data/lib/mirah/jvm/types/factory.rb +186 -0
  119. data/lib/mirah/jvm/types/floats.rb +86 -0
  120. data/lib/mirah/jvm/types/integers.rb +171 -0
  121. data/lib/mirah/jvm/types/intrinsics.rb +376 -0
  122. data/lib/mirah/jvm/types/literals.rb +74 -0
  123. data/lib/mirah/jvm/types/methods.rb +614 -0
  124. data/lib/mirah/jvm/types/number.rb +143 -0
  125. data/lib/mirah/nbcompiler.rb +29 -0
  126. data/lib/mirah/plugin/edb.rb +29 -0
  127. data/lib/mirah/plugin/gwt.rb +173 -0
  128. data/lib/mirah/plugin/java.rb +55 -0
  129. data/lib/mirah/transform.rb +266 -0
  130. data/lib/mirah/transform2.rb +728 -0
  131. data/lib/mirah/typer.rb +407 -0
  132. data/lib/mirah_task.rb +107 -0
  133. data/test/test_ast.rb +359 -0
  134. data/test/test_compilation.rb +112 -0
  135. data/test/test_env.rb +42 -0
  136. data/test/test_gwt.rb +58 -0
  137. data/test/test_java_typer.rb +183 -0
  138. data/test/test_javac_compiler.rb +63 -0
  139. data/test/test_jvm_compiler.rb +2607 -0
  140. data/test/test_typer.rb +221 -0
  141. metadata +235 -0
@@ -0,0 +1,407 @@
1
+ require 'mirah/ast'
2
+ require 'mirah/transform'
3
+
4
+ module Duby
5
+ module Typer
6
+ class << self
7
+ attr_accessor :verbose
8
+
9
+ def log(message)
10
+ puts "* [#{name}] #{message}" if Typer.verbose
11
+ end
12
+ end
13
+
14
+ class InferenceError < Exception
15
+ attr_accessor :node
16
+ def initialize(msg, node = nil)
17
+ super(msg)
18
+ @node = node
19
+ end
20
+ end
21
+
22
+ class BaseTyper
23
+ include Duby
24
+
25
+ def log(message); Typer.log(message); end
26
+
27
+ def to_s
28
+ name
29
+ end
30
+ end
31
+
32
+ class Simple < BaseTyper
33
+ attr_accessor :known_types, :errors, :last_chance
34
+
35
+ def initialize(self_type)
36
+ @known_types = {}
37
+
38
+ @known_types["self"] = type_reference(nil, self_type)
39
+ @known_types["fixnum"] = type_reference(nil, "fixnum")
40
+ @known_types["float"] = type_reference(nil, "float")
41
+ @known_types["string"] = type_reference(nil, "string")
42
+ @known_types["boolean"] = type_reference(nil, "boolean")
43
+ @errors = []
44
+ end
45
+
46
+ def name
47
+ "Simple"
48
+ end
49
+
50
+ def set_filename(scope, name); end
51
+
52
+ def self_type
53
+ known_types["self"]
54
+ end
55
+
56
+ def default_type
57
+ nil
58
+ end
59
+
60
+ def fixnum_type(value=0)
61
+ known_types["fixnum"]
62
+ end
63
+
64
+ def float_type(value=0)
65
+ known_types["float"]
66
+ end
67
+
68
+ def string_type
69
+ known_types["string"]
70
+ end
71
+
72
+ def boolean_type
73
+ known_types["boolean"]
74
+ end
75
+
76
+ def null_type
77
+ AST::TypeReference::NullType
78
+ end
79
+
80
+ def no_type
81
+ AST::TypeReference::NoType
82
+ end
83
+
84
+ # to be overridden
85
+ def array_type
86
+ AST::TypeReference::NullType
87
+ end
88
+
89
+ # to be overridden
90
+ def hash_type
91
+ AST::TypeReference::NullType
92
+ end
93
+
94
+ def known_type(name)
95
+ @known_types[name]
96
+ end
97
+
98
+ def define_type(scope, name, superclass, interfaces)
99
+ log "New type defined: '#{name}' < '#{superclass}'"
100
+ result = type_definition(scope, name, superclass, interfaces)
101
+
102
+ # TODO Get rid of known_types["self"]
103
+ old_self, known_types["self"] = known_types["self"], result
104
+ yield
105
+ known_types["self"] = old_self
106
+
107
+ result
108
+ end
109
+
110
+ def learn_local_type(scope, name, type)
111
+ type = scope.learn_local_type(name, known_types[type] || type)
112
+ log "Learned local type under #{scope} : #{name} = #{type}"
113
+ type
114
+ end
115
+
116
+ def local_type(scope, name)
117
+ type = scope.local_type(name)
118
+ log "Retrieved local type in #{scope} : #{name} = #{type}" if type
119
+ type
120
+ end
121
+
122
+ def local_types
123
+ @local_types ||= {}
124
+ end
125
+
126
+ def local_type_hash(scope)
127
+ local_types[scope] ||= {}
128
+ end
129
+
130
+ def field_types
131
+ @field_types ||= {}
132
+ end
133
+
134
+ def field_type_hash(cls)
135
+ field_types[cls] ||= {}
136
+ end
137
+
138
+ def static_field_types
139
+ @static_field_types ||= {}
140
+ end
141
+
142
+ def static_field_type_hash(cls)
143
+ static_field_types[cls] ||= {}
144
+ end
145
+
146
+ def infer_signature(method_def)
147
+ end
148
+
149
+ def learn_field_type(cls, name, type)
150
+ log "Learned field type under #{cls} : #{name} = #{type}"
151
+
152
+ # TODO check for compatibility?
153
+ field_type_hash(cls)[name] ||= known_types[type] || type
154
+
155
+ type
156
+ end
157
+
158
+ def field_type(cls, name)
159
+ field_type_hash(cls)[name]
160
+ end
161
+
162
+ def learn_static_field_type(cls, name, type)
163
+ log "Learned field type under #{cls} : #{name} = #{type}"
164
+
165
+ # TODO check for compatibility?
166
+ static_field_type_hash(cls)[name] ||= known_types[type] || type
167
+
168
+ type
169
+ end
170
+
171
+ def static_field_type(cls, name)
172
+ static_field_type_hash(cls)[name]
173
+ end
174
+
175
+ def learn_method_type(target_type, name, parameter_types, type, exceptions)
176
+ log "Learned method #{name} (#{parameter_types}) on #{target_type} = #{type}"
177
+
178
+ get_method_type_hash(target_type, name, parameter_types)[:type] = known_types[type] || type
179
+
180
+ # if it's any args are imported types, also add a mapping for the expanded name
181
+ imported_types = parameter_types.map {|param| known_types[param] || param}
182
+ get_method_type_hash(target_type, name, imported_types)[:type] = type
183
+ end
184
+
185
+ def method_type(target_type, name, parameter_types)
186
+ if (target_type && target_type.error?) ||
187
+ parameter_types.any? {|t| t && t.error?}
188
+ return AST.error_type
189
+ end
190
+ constructor = (name == 'new' && target_type && target_type.meta?)
191
+
192
+ if constructor
193
+ # constructor handled different from other methods
194
+ simple_type = get_method_type_hash(target_type.unmeta, 'initialize', parameter_types)[:type]
195
+ else
196
+ simple_type = get_method_type_hash(target_type, name, parameter_types)[:type]
197
+ end
198
+
199
+
200
+ if !simple_type
201
+ log "Method type for \"#{name}\" #{parameter_types} on #{target_type} not found."
202
+
203
+ # allow plugins a go if we're in the inference phase
204
+ simple_type = plugins do |plugin|
205
+ plugin.method_type(self, target_type, name, parameter_types)
206
+ end
207
+ end
208
+
209
+ return nil unless simple_type
210
+
211
+ if constructor
212
+ log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{target_type}"
213
+ target_type.unmeta
214
+ else
215
+ log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{simple_type}"
216
+ simple_type
217
+ end
218
+ end
219
+
220
+ def plugins
221
+ if cycling?
222
+ Duby.typer_plugins.each do |plugin|
223
+ log "Invoking plugin: #{plugin}"
224
+
225
+ result = yield plugin
226
+ return result if result
227
+ end
228
+ end
229
+
230
+ nil
231
+ end
232
+
233
+ def cycling?
234
+ @cycling
235
+ end
236
+
237
+ def cycling=(c)
238
+ @cycling = c
239
+ end
240
+
241
+ def cycle(count)
242
+ @cycling = true
243
+ count.times do |i|
244
+ begin
245
+ log "[Cycle #{i}]: Started..."
246
+ yield i
247
+ ensure
248
+ log "[Cycle #{i}]: Complete!"
249
+ end
250
+ end
251
+ ensure
252
+ @cycling = false
253
+ end
254
+
255
+ def method_types
256
+ @method_types ||= {}
257
+ end
258
+
259
+ def get_method_type_hash(target_type, name, parameter_types)
260
+ method_types[target_type] ||= {}
261
+ method_types[target_type][name] ||= {}
262
+ method_types[target_type][name][parameter_types.size] ||= {}
263
+
264
+ current = method_types[target_type][name][parameter_types.size]
265
+
266
+ parameter_types.each {|type| current[type] ||= {}; current = current[type]}
267
+
268
+ current
269
+ end
270
+
271
+ def type_reference(scope, name, array=false, meta=false)
272
+ AST::TypeReference.new(name, array, meta)
273
+ end
274
+
275
+ def type_definition(scope, name, superclass, interfaces)
276
+ AST::TypeDefinition.new(name, AST::TypeReference.new(superclass), interfaces)
277
+ end
278
+
279
+ def deferred_nodes
280
+ @deferred_nodes ||= {}
281
+ end
282
+
283
+ def infer(node)
284
+ begin
285
+ node.infer(self)
286
+ rescue InferenceError => ex
287
+ ex.node ||= node
288
+ error(node, ex)
289
+ rescue Exception => ex
290
+ error(node, ex.message, ex.backtrace)
291
+ end
292
+ end
293
+
294
+ def error(node, error_or_msg=nil, backtrace=nil)
295
+ if error_or_msg.kind_of? InferenceError
296
+ error = error_or_msg
297
+ elsif error_or_msg
298
+ error = InferenceError.new(error_or_msg, node)
299
+ error.set_backtrace(backtrace) if backtrace
300
+ else
301
+ error = InferenceError.new("Unable to infer type.", node)
302
+ end
303
+ @errors << error
304
+ node.resolve_if(self) do
305
+ AST.error_type
306
+ end
307
+ end
308
+
309
+ def defer(node, error_message=nil)
310
+ if @error_next
311
+ log "Marking #{node} as an error"
312
+ @error_next = false
313
+ error(node, error_message)
314
+ else
315
+ raise "Can't defer nil" if node.nil?
316
+ return if deferred_nodes.include? node
317
+ log "Deferring inference for #{node}"
318
+
319
+ deferred_nodes[node] = self_type
320
+ end
321
+ end
322
+
323
+ def resolve(raise = false)
324
+ count = deferred_nodes.size + 1
325
+
326
+ log "Entering type inference cycle"
327
+
328
+ retried = false
329
+ cycle(count) do |i|
330
+ old_deferred = @deferred_nodes
331
+ @deferred_nodes = {}
332
+ old_deferred.each do |node, saved_type|
333
+ known_types["self"] = saved_type
334
+ type = infer(node)
335
+
336
+ log "[Cycle #{i}]: Inferred type for #{node}: #{type || 'FAILED'}"
337
+
338
+ if type == default_type
339
+ @deferred_nodes[node] = saved_type
340
+ end
341
+ end
342
+
343
+ if @deferred_nodes.size == 0
344
+ log "[Cycle #{i}]: Resolved all types, exiting"
345
+ break
346
+ elsif old_deferred == @deferred_nodes
347
+ if @error_next || retried
348
+ log "[Cycle #{i}]: Made no progress, bailing out"
349
+ break
350
+ elsif @last_chance
351
+ # Retry this iteration, and mark the first deferred
352
+ # type as an error.
353
+ retried = true
354
+ @error_next = true
355
+ redo
356
+ else
357
+ # This is a hack for default constructor support. The right fix
358
+ # is probably to check the AST for constructors. Instead we
359
+ # tell the plugins that we're near the end of inference so they
360
+ # can assume no new constructors are being added. You could
361
+ # easily write some circular constructors that would compile
362
+ # with this technique but fail to run.
363
+ @last_chance = true
364
+ redo
365
+ end
366
+ end
367
+ retried = false
368
+ end
369
+
370
+ # done with n sweeps, if any remain mark them as errors
371
+ error_nodes = @errors.map {|e| e.node}
372
+ (deferred_nodes.keys - error_nodes).each do |deferred_node|
373
+ error_nodes << deferred_node
374
+ error(deferred_node)
375
+ end
376
+ if raise && !error_nodes.empty?
377
+ msg = "Could not infer typing for nodes:"
378
+ error_nodes.map do |e|
379
+ msg << "\n "
380
+ msg << "#{e.inspect} at line #{e.line_number} (child of #{e.parent})"
381
+ end
382
+ raise InferenceError.new(msg)
383
+ end
384
+ end
385
+ end
386
+ end
387
+
388
+ def self.typer_plugins
389
+ @typer_plugins ||= []
390
+ end
391
+ end
392
+
393
+ if __FILE__ == $0
394
+ Duby::AST.verbose = true
395
+ Duby::Typer.verbose = true
396
+ ast = Duby::AST.parse(File.read(ARGV[0]))
397
+ typer = Duby::Typer::Simple.new("script")
398
+ typer.infer(ast)
399
+ begin
400
+ typer.resolve(true)
401
+ rescue Duby::Typer::InferenceError => e
402
+ puts e.message
403
+ end
404
+
405
+ puts "\nAST:"
406
+ p ast
407
+ end
@@ -0,0 +1,107 @@
1
+ require 'mirah'
2
+ module Duby
3
+ class PathArray < Array
4
+ def <<(value)
5
+ super(File.expand_path(value))
6
+ end
7
+ end
8
+
9
+ def self.source_path
10
+ source_paths[0] ||= File.expand_path('.')
11
+ end
12
+
13
+ def self.source_paths
14
+ @source_paths ||= PathArray.new
15
+ end
16
+
17
+ def self.source_path=(path)
18
+ source_paths[0] = File.expand_path(path)
19
+ end
20
+
21
+ def self.dest_paths
22
+ @dest_paths ||= PathArray.new
23
+ end
24
+
25
+ def self.dest_path
26
+ dest_paths[0] ||= File.expand_path('.')
27
+ end
28
+
29
+ def self.dest_path=(path)
30
+ dest_paths[0] = File.expand_path(path)
31
+ end
32
+
33
+ def self.find_dest(path)
34
+ expanded = File.expand_path(path)
35
+ dest_paths.each do |destdir|
36
+ if expanded =~ /^#{destdir}\//
37
+ return destdir
38
+ end
39
+ end
40
+ end
41
+
42
+ def self.find_source(path)
43
+ expanded = File.expand_path(path)
44
+ source_paths.each do |sourcedir|
45
+ if expanded =~ /^#{sourcedir}\//
46
+ return sourcedir
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.dest_to_source_path(target_path)
52
+ destdir = find_dest(target_path)
53
+ path = File.expand_path(target_path).sub(/^#{destdir}\//, '')
54
+ path.sub!(/\.(java|class)$/, '')
55
+ snake_case = File.basename(path).gsub(/[A-Z]/, '_\0').sub(/_/, '').downcase
56
+ snake_case = "#{File.dirname(path)}/#{snake_case}"
57
+ source_paths.each do |source_path|
58
+ ["mirah", "duby"].each do |suffix|
59
+ filename = "#{source_path}/#{path}.#{suffix}"
60
+ return filename if File.exist?(filename)
61
+ filename = "#{source_path}/#{snake_case}.#{suffix}"
62
+ return filename if File.exist?(filename)
63
+ end
64
+ end
65
+ # No source file exists. Just go with the first source path and .mirah
66
+ return "#{self.source_path}/#{path}.mirah"
67
+ end
68
+
69
+ def self.compiler_options
70
+ @compiler_options ||= []
71
+ end
72
+
73
+ def self.compiler_options=(args)
74
+ @compiler_options = args
75
+ end
76
+ end
77
+
78
+ def mirahc(*files)
79
+ if files[-1].kind_of?(Hash)
80
+ options = files.pop
81
+ else
82
+ options = {}
83
+ end
84
+ source_dir = options.fetch(:dir, Duby.source_path)
85
+ dest = File.expand_path(options.fetch(:dest, Duby.dest_path))
86
+ files = files.map {|f| f.sub(/^#{source_dir}\//, '')}
87
+ flags = options.fetch(:options, Duby.compiler_options)
88
+ args = ['-d', dest, *flags] + files
89
+ chdir(source_dir) do
90
+ puts "mirahc #{args.join ' '}"
91
+ Duby.compile(*args)
92
+ Duby.reset
93
+ end
94
+ end
95
+
96
+ rule '.java' => [proc {|n| Duby.dest_to_source_path(n)}] do |t|
97
+ mirahc(t.source,
98
+ :dir=>Duby.find_source(t.source),
99
+ :dest=>Duby.find_dest(t.name),
100
+ :options=>['-java'])
101
+ end
102
+
103
+ rule '.class' => [proc {|n| Duby.dest_to_source_path(n)}] do |t|
104
+ mirahc(t.source,
105
+ :dir=>Duby.find_source(t.source),
106
+ :dest=>Duby.find_dest(t.name))
107
+ end