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,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