headius (owner)

Revisions

gist: 217978 Download_button fork
public
Public Clone URL: git://gist.github.com/217978.git
Embed All Files: show embed
Text only #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
~/projects/duby ➔ bin/duby -e "def foo(a:1); puts a; end; foo; foo(2)"
1
2
 
~/projects/duby ➔ bin/dubyc -e "def foo(a:1); puts a; end; foo; foo(2)"
 
~/projects/duby ➔ javap -c dash_e
Compiled from dash_e
public class dash_e extends java.lang.Object{
public static void main(java.lang.String[]);
  Code:
   0: invokestatic #26; //Method foo:()V
   3: iconst_2
   4: invokestatic #24; //Method foo:(I)V
   7: return
 
public static void foo(int);
  Code:
   0: getstatic #14; //Field java/lang/System.out:Ljava/io/PrintStream;
   3: iload_0
   4: invokevirtual #19; //Method java/io/PrintStream.println:(I)V
   7: return
 
public static void foo();
  Code:
   0: iconst_1
   1: invokestatic #24; //Method foo:(I)V
   4: return
 
public dash_e();
  Code:
   0: aload_0
   1: invokespecial #31; //Method java/lang/Object."<init>":()V
   4: return
 
}
 
Diff #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
commit 08fcff36cf9b22e9487fa681b0b195090290257d
Author: Charles Oliver Nutter <headius@headius.com>
Date: Sun Oct 25 04:05:59 2009 -0500
 
    Add basic optional argument support; no tests yet, and only literal expressions seem to work right.
 
diff --git a/lib/duby/ast/method.rb b/lib/duby/ast/method.rb
index 6cba226..36fb28e 100644
--- a/lib/duby/ast/method.rb
+++ b/lib/duby/ast/method.rb
@@ -55,10 +55,29 @@ module Duby::AST
     include Scoped
     attr_accessor :child
     
- def initialize(parent, line_number, &block)
+ def initialize(parent, line_number, name, &block)
       super(parent, line_number, &block)
       @child = children[0]
- @name = @child.name
+ @name = name
+ end
+
+ def infer(typer)
+ unless @inferred_type
+ # if not already typed, check parent of parent (MethodDefinition) for signature info
+ method_def = parent.parent
+ signature = method_def.signature
+
+ # if signature, search for this argument
+ @inferred_type = child.infer(typer)
+ if @inferred_type
+ typer.learn_local_type(scope, name, @inferred_type)
+ signature[name.intern] = @inferred_type
+ else
+ typer.defer(self)
+ end
+ end
+
+ @inferred_type
     end
   end
       
@@ -96,8 +115,8 @@ module Duby::AST
     
     def infer(typer)
       @defining_class ||= typer.self_type
- typer.infer_signature(self)
       typer.infer(arguments)
+ typer.infer_signature(self)
       forced_type = signature[:return]
       inferred_type = body ? typer.infer(body) : typer.no_type
         
@@ -122,6 +141,21 @@ module Duby::AST
         end
 
         @inferred_type = typer.learn_method_type(defining_class, name, arguments.inferred_type, actual_type, signature[:throws])
+
+ # learn the other overloads as well
+ args_for_opt = []
+ if arguments.args
+ arguments.args.each do |arg|
+ if OptionalArgument === arg
+ arg_types_for_opt = args_for_opt.map do |arg_for_opt|
+ arg_for_opt.infer(typer)
+ end
+ typer.learn_method_type(defining_class, name, arg_types_for_opt, actual_type, signature[:throws])
+ end
+ args_for_opt << arg
+ end
+ end
+
         signature[:return] = @inferred_type
       end
         
diff --git a/lib/duby/jvm/compiler.rb b/lib/duby/jvm/compiler.rb
index cef9128..fa01d05 100644
--- a/lib/duby/jvm/compiler.rb
+++ b/lib/duby/jvm/compiler.rb
@@ -130,6 +130,59 @@ module Duby
           @method.stop
         end
 
+ arg_types_for_opt = []
+ args_for_opt = []
+ if args.args
+ args.args.each do |arg|
+ if AST::OptionalArgument === arg
+ if @static || force_static
+ method = @class.public_static_method(name.to_s, exceptions, return_type, *arg_types_for_opt)
+ else
+ if name == "initialize"
+ method = @class.public_constructor(exceptions, *arg_types_for_opt)
+ method.start
+ method.aload 0
+ method.invokespecial @class.superclass, "<init>", [@method.void]
+ started = true
+ else
+ method = @class.public_method(name.to_s, exceptions, return_type, *arg_types_for_opt)
+ end
+ end
+
+ with :method => method, :static => @static || force_static do
+ log "Starting new method #{name}(#{arg_types_for_opt})"
+
+ @method.start unless started
+
+ # declare all args so they get their values
+
+ expression = signature[:return] != Types::Void
+
+ @method.aload(0) unless @static
+ args_for_opt.each {|req_arg| @method.local(req_arg.name, req_arg.inferred_type)}
+ arg.children[0].compile(self, true)
+
+ # invoke the next one in the chain
+ if @static
+ @method.invokestatic(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
+ else
+ @method.invokevirtual(@class, name.to_s, [return_type] + arg_types_for_opt + [arg.inferred_type])
+ end
+
+ if name == "initialize"
+ @method.returnvoid
+ else
+ signature[:return].return(@method)
+ end
+
+ @method.stop
+ end
+ end
+ arg_types_for_opt << arg.inferred_type
+ args_for_opt << arg
+ end
+ end
+
         log "Method #{name}(#{arg_types}) complete!"
       end
 
diff --git a/lib/duby/transform.rb b/lib/duby/transform.rb
index 3e82685..35e9848 100644
--- a/lib/duby/transform.rb
+++ b/lib/duby/transform.rb
@@ -221,7 +221,11 @@ module Duby
         def transform(transformer, parent)
           Arguments.new(parent, position) do |args_node|
             arg_list = args.child_nodes.map do |node|
- RequiredArgument.new(args_node, node.position, node.name)
+ if !node.respond_to?(:type_node) || node.type_node.respond_to?(:type_reference)
+ RequiredArgument.new(args_node, node.position, node.name)
+ else
+ OptionalArgument.new(args_node, node.position, node.name) {|opt_arg| [transformer.transform(node, opt_arg)]}
+ end
               # argument nodes will have type soon
               #RequiredArgument.new(args_node, node.name, node.type)
             end if args
@@ -399,7 +403,7 @@ module Duby
 
             if args_node && args_node.args
               args_node.args.child_nodes.each do |arg|
- if arg.respond_to? :type_node
+ if arg.respond_to?(:type_node) && arg.type_node.respond_to?(:type_reference)
                   signature[arg.name.intern] =
                     arg.type_node.type_reference(parent)
                 end
@@ -812,6 +816,9 @@ module Duby
       end
       
       class TypedArgumentNode
+ def transform(transformer, parent)
+ type_node.transform(transformer, parent)
+ end
       end
 
         def transform(transformer, parent)