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,54 +1,256 @@
1
+ require 'fileutils'
2
+
1
3
  module Duby::AST
2
- class Print < Node
3
- attr_accessor :parameters
4
- attr_accessor :println
5
-
6
- def initialize(parent, line_number, println, &block)
4
+
5
+ class MacroDefinition < Node
6
+ include Named
7
+
8
+ child :arguments
9
+ child :body
10
+
11
+ attr_accessor :proxy
12
+
13
+ def self.new(*args, &block)
14
+ real_node = super
15
+ real_node.proxy = NodeProxy.new(real_node)
16
+ end
17
+
18
+ def initialize(parent, line_number, name, &block)
7
19
  super(parent, line_number, &block)
8
- @parameters = children
9
- @println = println
20
+ @name = name
10
21
  end
11
22
 
12
23
  def infer(typer)
13
- if parameters.size > 0
14
- resolved = parameters.select {|param| typer.infer(param); param.resolved?}
15
- resolved! if resolved.size == parameters.size
24
+ resolve_if(typer) do
25
+ self_type = typer.self_type
26
+ extension_name = "%s$%s" % [self_type.name,
27
+ typer.transformer.tmp("Extension%s")]
28
+ klass = build_and_load_extension(self_type,
29
+ extension_name,
30
+ typer.transformer.state)
31
+
32
+ # restore the self type since we're sharing a type factory
33
+ typer.known_types['self'] = self_type
34
+
35
+ arg_types = argument_types
36
+ macro = self_type.add_macro(name, *arg_types) do |duby, call|
37
+ expander = klass.constructors[0].newInstance(duby, call)
38
+ expander.expand
39
+ end
40
+ if arguments[-1].kind_of?(BlockArgument) && arguments[-1].optional?
41
+ arg_types.pop
42
+ typer.self_type.add_method(name, arg_types, macro)
43
+ end
44
+ proxy.__inline__(Noop.new(parent, position))
45
+ proxy.infer(typer)
46
+ end
47
+ end
48
+
49
+ def argument_types
50
+ arguments.map do |arg|
51
+ if arg.kind_of?(BlockArgument)
52
+ TypeReference::BlockType
53
+ else
54
+ # TODO support typed args. Also there should be a way
55
+ # to accept any AST node.
56
+ Duby::JVM::Types::Object
57
+ end
58
+ end
59
+ end
60
+
61
+ def signature
62
+ args = argument_types
63
+ if args.size > 0 && args[-1].block?
64
+ args[-1] = BiteScript::ASM::Type.getObjectType('duby.lang.compiler.Block')
65
+ end
66
+ [nil] + args
67
+ end
68
+
69
+ def build_and_load_extension(parent, name, state)
70
+ transformer = Duby::Transform::Transformer.new(state)
71
+ ast = build_ast(name, parent, transformer)
72
+ puts ast.inspect if state.verbose
73
+ classes = compile_ast(name, ast, transformer)
74
+ loader = DubyClassLoader.new(
75
+ JRuby.runtime.jruby_class_loader, classes)
76
+ klass = loader.loadClass(name, true)
77
+ annotate(parent, name)
78
+ klass
79
+ end
80
+
81
+ def annotate(type, name)
82
+ node = type.unmeta.node
83
+ if node
84
+ extension = node.annotation('duby.anno.Extensions')
85
+ extension ||= begin
86
+ node.annotations << Annotation.new(
87
+ nil, nil, BiteScript::ASM::Type.getObjectType('duby/anno/Extensions'))
88
+ node.annotations[-1].runtime = false
89
+ node.annotations[-1]
90
+ end
91
+ extension['macros'] ||= []
92
+ macro = Annotation.new(nil, nil,
93
+ BiteScript::ASM::Type.getObjectType('duby/anno/Macro'))
94
+ macro['name'] = name
95
+ macro['signature'] = BiteScript::Signature.signature(*signature)
96
+ extension['macros'] << macro
16
97
  else
17
- resolved!
98
+ puts "Warning: No ClassDefinition for #{type.name}. Macros can't be loaded from disk."
18
99
  end
19
- typer.no_type
100
+ end
101
+
102
+ def compile_ast(name, ast, transformer)
103
+ filename = name.gsub(".", "/")
104
+ typer = Duby::Typer::JVM.new(filename, transformer)
105
+ typer.infer(ast)
106
+ typer.resolve(true)
107
+ compiler = Duby::Compiler::JVM.new(filename)
108
+ ast.compile(compiler, false)
109
+ class_map = {}
110
+ compiler.generate do |outfile, builder|
111
+ outfile = "#{transformer.destination}#{outfile}"
112
+ FileUtils.mkdir_p(File.dirname(outfile))
113
+ File.open(outfile, 'w') do |f|
114
+ bytes = builder.generate
115
+ name = builder.class_name.gsub(/\//, '.')
116
+ class_map[name] = bytes
117
+ f.write(bytes)
118
+ end
119
+ end
120
+ class_map
121
+ end
122
+
123
+ def build_ast(name, parent, transformer)
124
+ # TODO should use a new type factory too.
125
+ ast = Duby::AST.parse_ruby("import duby.lang.compiler.Node")
126
+ ast = transformer.transform(ast, nil)
127
+
128
+ # Start building the extension class
129
+ extension = transformer.define_class(position, name)
130
+ #extension.superclass = Duby::AST.type('duby.lang.compiler.Macro')
131
+ extension.interfaces = [Duby::AST.type('duby.lang.compiler.Macro')]
132
+
133
+ # The constructor just saves the state
134
+ extension.define_constructor(
135
+ position,
136
+ ['duby', Duby::AST.type('duby.lang.compiler.Compiler')],
137
+ ['call', Duby::AST.type('duby.lang.compiler.Call')]) do |c|
138
+ transformer.eval("@duby = duby;@call = call", '-', c, 'duby', 'call')
139
+ end
140
+
141
+ node_type = Duby::AST.type('duby.lang.compiler.Node')
142
+
143
+ # expand() parses the arguments out of call and then passes them off to
144
+ # _expand
145
+ expand = extension.define_method(
146
+ position, 'expand', node_type)
147
+ args = []
148
+ arguments.each_with_index do |arg, i|
149
+ # TODO optional args
150
+ args << if arg.kind_of?(BlockArgument)
151
+ "@call.block"
152
+ else
153
+ "Node(args.get(#{i}))"
154
+ end
155
+ end
156
+ expand.body = transformer.eval(<<-end)
157
+ args = @call.arguments
158
+ _expand(#{args.join(', ')})
159
+ end
160
+ actual_args = arguments.map do |arg|
161
+ [arg.name, node_type, arg.position]
162
+ end
163
+ m = extension.define_method(position, '_expand', node_type, *actual_args)
164
+ m.body = self.body
165
+ ast
20
166
  end
21
167
  end
22
-
168
+
169
+ defmacro('defmacro') do |duby, fcall, parent|
170
+ macro = fcall.args_node[0]
171
+ block_arg = nil
172
+ args_node = macro.args_node
173
+ body = macro.iter_node || fcall.iter_node
174
+ if args_node.respond_to? :getBodyNode
175
+ block_arg = args_node.body_node
176
+ args_node = args_node.args_node
177
+ body = fcall.iter_node
178
+ end
179
+ MacroDefinition.new(parent, fcall.position, macro.name) do |mdef|
180
+ # TODO optional args?
181
+ args = if args_node
182
+ args_node.map do |arg|
183
+ case arg
184
+ when JRubyAst::LocalAsgnNode
185
+ OptionalArgument.new(mdef, arg.position, arg.name) do |optarg|
186
+ # TODO check that they actually passed nil as the value
187
+ Null.new(parent, arg.value_node.position)
188
+ end
189
+ when JRubyAst::VCallNode, JRubyAst::LocalVarNode
190
+ RequiredArgument.new(mdef, arg.position, arg.name)
191
+ end
192
+ end
193
+ else
194
+ []
195
+ end
196
+ if block_arg
197
+ args << BlockArgument.new(mdef, block_arg.position, block_arg.name)
198
+ args[-1].optional = block_arg.kind_of?(JRubyAst::LocalAsgnNode)
199
+ end
200
+ body_node = duby.transform(body.body_node, mdef) if body.body_node
201
+ [args, body_node]
202
+ end
203
+ end
204
+
23
205
  defmacro('puts') do |transformer, fcall, parent|
24
- Print.new(parent, fcall.position, true) do |print|
25
- if fcall.respond_to?(:args_node) && fcall.args_node
206
+ Call.new(parent, fcall.position, "println") do |x|
207
+ args = if fcall.respond_to?(:args_node) && fcall.args_node
26
208
  fcall.args_node.child_nodes.map do |arg|
27
- transformer.transform(arg, print)
209
+ transformer.transform(arg, x)
28
210
  end
29
211
  else
30
212
  []
31
213
  end
214
+ [
215
+ Call.new(x, fcall.position, "out") do |y|
216
+ [
217
+ Constant.new(y, fcall.position, "System"),
218
+ []
219
+ ]
220
+ end,
221
+ args,
222
+ nil
223
+ ]
32
224
  end
33
225
  end
34
226
 
35
227
  defmacro('print') do |transformer, fcall, parent|
36
- Print.new(parent, fcall.position, false) do |print|
37
- if fcall.respond_to?(:args_node) && fcall.args_node
228
+ Call.new(parent, fcall.position, "print") do |x|
229
+ args = if fcall.respond_to?(:args_node) && fcall.args_node
38
230
  fcall.args_node.child_nodes.map do |arg|
39
- transformer.transform(arg, print)
231
+ transformer.transform(arg, x)
40
232
  end
41
233
  else
42
234
  []
43
235
  end
236
+ [
237
+ Call.new(x, fcall.position, "out") do |y|
238
+ [
239
+ Constant.new(y, fcall.position, "System"),
240
+ []
241
+ ]
242
+ end,
243
+ args,
244
+ nil
245
+ ]
44
246
  end
45
247
  end
46
-
248
+
47
249
  class InlineCode
48
250
  def initialize(&block)
49
251
  @block = block
50
252
  end
51
-
253
+
52
254
  def inline(transformer, call)
53
255
  @block.call(transformer, call)
54
256
  end
@@ -5,75 +5,126 @@ module Duby::AST
5
5
  end
6
6
 
7
7
  def infer(typer)
8
+ children.each do |kid|
9
+ kid.infer(typer)
10
+ end
8
11
  @inferred_type = typer.array_type
9
12
  end
10
13
  end
11
-
14
+
12
15
  class Fixnum < Node
13
16
  include Literal
14
-
17
+
15
18
  def initialize(parent, line_number, literal)
16
19
  super(parent, line_number)
17
20
  @literal = literal
18
21
  end
19
-
22
+
20
23
  def infer(typer)
21
24
  return @inferred_type if resolved?
22
25
  resolved!
23
26
  @inferred_type = typer.fixnum_type
24
27
  end
25
-
28
+
26
29
  def ==(other)
27
30
  @literal == other.literal
28
31
  end
29
-
32
+
30
33
  def eql?(other)
31
34
  self.class == other.class && @literal.eql?(other.literal)
32
35
  end
33
36
  end
34
-
37
+
35
38
  class Float < Node
36
39
  include Literal
37
-
40
+
38
41
  def initialize(parent, line_number, literal)
39
42
  super(parent, line_number)
40
43
  @literal = literal
41
44
  end
42
-
45
+
43
46
  def infer(typer)
44
47
  return @inferred_type if resolved?
45
48
  resolved!
46
49
  @inferred_type = typer.float_type
47
50
  end
48
51
  end
49
-
52
+
50
53
  class Hash < Node; end
51
-
54
+
55
+ class Regexp < Node
56
+ include Literal
57
+
58
+ def initialize(parent, line_number, literal)
59
+ super(parent, line_number)
60
+ @literal = literal
61
+ end
62
+
63
+ def infer(typer)
64
+ return @inferred_type if resolved?
65
+ resolved!
66
+ @inferred_type ||= typer.regexp_type
67
+ end
68
+ end
69
+
52
70
  class String < Node
53
71
  include Literal
54
-
72
+
55
73
  def initialize(parent, line_number, literal)
56
74
  super(parent, line_number)
57
75
  @literal = literal
58
76
  end
59
-
77
+
60
78
  def infer(typer)
61
79
  return @inferred_type if resolved?
62
80
  resolved!
63
81
  @inferred_type ||= typer.string_type
64
82
  end
65
83
  end
66
-
84
+
85
+ class StringConcat < Node
86
+ def initialize(parent, position, &block)
87
+ super(parent, position, &block)
88
+ end
89
+
90
+ def infer(typer)
91
+ unless resolved?
92
+ resolved = true
93
+ children.each {|node| node.infer(typer); resolved &&= node.resolved?}
94
+ resolved! if resolved
95
+ @inferred_type ||= typer.string_type
96
+ end
97
+ @inferred_type
98
+ end
99
+ end
100
+
101
+ class ToString < Node
102
+ child :body
103
+
104
+ def initialize(parent, position)
105
+ super(parent, position)
106
+ end
107
+
108
+ def infer(typer)
109
+ unless resolved?
110
+ body.infer(typer)
111
+ resolved! if body.resolved?
112
+ @inferred_type ||= typer.string_type
113
+ end
114
+ @inferred_type
115
+ end
116
+ end
117
+
67
118
  class Symbol < Node; end
68
-
119
+
69
120
  class Boolean < Node
70
121
  include Literal
71
-
122
+
72
123
  def initialize(parent, line_number, literal)
73
124
  super(parent, line_number)
74
125
  @literal = literal
75
126
  end
76
-
127
+
77
128
  def infer(typer)
78
129
  return @inferred_type if resolved?
79
130
  resolved!
@@ -4,89 +4,85 @@ module Duby::AST
4
4
  include Typed
5
5
  include Scoped
6
6
 
7
- def initialize(parent, line_number, name, captured=false, &block)
7
+ child :type
8
+
9
+ def initialize(parent, line_number, name, &block)
8
10
  super(parent, line_number, &block)
9
11
  @name = name
10
- @captured = captured
11
- @type = children[0]
12
12
  end
13
13
 
14
14
  def captured?
15
- @captured
15
+ scope.static_scope.captured?(name)
16
16
  end
17
17
 
18
18
  def infer(typer)
19
- unless resolved?
20
- resolved!
21
- @inferred_type = typer.known_types[type] || type
22
- if @inferred_type
23
- resolved!
24
- typer.learn_local_type(scope, name, @inferred_type)
25
- else
26
- typer.defer(self)
27
- end
19
+ resolve_if(typer) do
20
+ scope.static_scope << name
21
+ typer.known_types[type] || type
28
22
  end
29
- @inferred_type
23
+ end
24
+
25
+ def resolved!(typer)
26
+ typer.learn_local_type(containing_scope, name, @inferred_type)
27
+ super
30
28
  end
31
29
  end
32
-
30
+
33
31
  class LocalAssignment < Node
34
32
  include Named
35
33
  include Valued
36
34
  include Scoped
37
-
38
- def initialize(parent, line_number, name, captured=false, &block)
39
- super(parent, line_number, children, &block)
40
- @captured = captured
41
- @value = children[0]
35
+
36
+ child :value
37
+
38
+ def initialize(parent, line_number, name, &block)
39
+ super(parent, line_number, &block)
42
40
  @name = name
43
41
  end
44
42
 
45
43
  def captured?
46
- @captured
44
+ scope.static_scope.captured?(name)
47
45
  end
48
46
 
49
47
  def to_s
50
- "LocalAssignment(name = #{name}, scope = #{scope}, captured = #{captured?})"
48
+ "LocalAssignment(name = #{name}, scope = #{scope}, captured = #{captured? == true})"
51
49
  end
52
-
53
- def infer(typer)
54
- unless @inferred_type
55
- @inferred_type = typer.learn_local_type(scope, name, typer.infer(value))
56
50
 
57
- @inferred_type ? resolved! : typer.defer(self)
51
+ def infer(typer)
52
+ resolve_if(typer) do
53
+ scope.static_scope << name
54
+ typer.infer(value)
58
55
  end
56
+ end
59
57
 
60
- @inferred_type
58
+ def resolved!(typer)
59
+ typer.learn_local_type(containing_scope, name, @inferred_type)
60
+ super
61
61
  end
62
62
  end
63
63
 
64
64
  class Local < Node
65
65
  include Named
66
66
  include Scoped
67
-
68
- def initialize(parent, line_number, name, captured=false)
67
+
68
+ def initialize(parent, line_number, name)
69
69
  super(parent, line_number, [])
70
70
  @name = name
71
- @captured = captured
72
71
  end
73
72
 
74
73
  def captured?
75
- @captured
74
+ scope.static_scope.captured?(name)
76
75
  end
77
76
 
78
77
  def to_s
79
- "Local(name = #{name}, scope = #{scope}, captured = #{captured?})"
78
+ "Local(name = #{name}, scope = #{scope}, captured = #{captured? == true})"
80
79
  end
81
-
82
- def infer(typer)
83
- unless @inferred_type
84
- @inferred_type = typer.local_type(scope, name)
85
80
 
86
- @inferred_type ? resolved! : typer.defer(self)
81
+ def infer(typer)
82
+ resolve_if(typer) do
83
+ scope.static_scope << name
84
+ typer.local_type(containing_scope, name)
87
85
  end
88
-
89
- @inferred_type
90
86
  end
91
87
  end
92
88
  end