archruby 0.2.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/README.md +1 -1
- data/Rakefile +46 -0
- data/TODO.rtf +20 -0
- data/architecture.yml +51 -0
- data/archruby.gemspec +3 -0
- data/bin/archruby +1 -0
- data/lib/archruby.rb +14 -2
- data/lib/archruby/architecture/architecture.rb +6 -6
- data/lib/archruby/architecture/config_definition.rb +13 -13
- data/lib/archruby/architecture/constraint_break.rb +1 -1
- data/lib/archruby/architecture/dependency.rb +3 -1
- data/lib/archruby/architecture/file_content.rb +2 -2
- data/lib/archruby/architecture/module_definition.rb +33 -20
- data/lib/archruby/architecture/parser.rb +25 -11
- data/lib/archruby/architecture/type_inference_checker.rb +29 -13
- data/lib/archruby/presenters/dsm.rb +163 -0
- data/lib/archruby/presenters/dsm/cell_dsm.rb +17 -0
- data/lib/archruby/presenters/dsm/dsm_css.css +77 -0
- data/lib/archruby/presenters/graph.rb +12 -9
- data/lib/archruby/ruby/parser.rb +131 -125
- data/lib/archruby/ruby/type_inference/dependency_organizer.rb +53 -0
- data/lib/archruby/ruby/type_inference/ruby/class_dependency.rb +22 -0
- data/lib/archruby/ruby/type_inference/ruby/internal_method_invocation.rb +20 -0
- data/lib/archruby/ruby/type_inference/ruby/method_definition.rb +20 -0
- data/lib/archruby/ruby/type_inference/ruby/parser_for_typeinference.rb +537 -0
- data/lib/archruby/ruby/type_inference/ruby/process_method_arguments.rb +155 -0
- data/lib/archruby/ruby/type_inference/ruby/process_method_body.rb +427 -0
- data/lib/archruby/ruby/type_inference/ruby/process_method_params.rb +276 -0
- data/lib/archruby/ruby/type_inference/type_inference_checker.rb +126 -0
- data/lib/archruby/version.rb +1 -1
- data/spec/architecture/file_content_spec.rb +2 -1
- data/spec/architecture/module_definition_spec.rb +9 -9
- data/spec/dummy_app/lib/teste_class.rb +6 -0
- data/spec/ruby/type_inference/dependency_organizer_spec.rb +20 -0
- data/spec/ruby/type_inference/fixtures/homebrew_bottles_class.rb +139 -0
- data/spec/ruby/type_inference/fixtures/homebrew_brew_teste.rb +1323 -0
- data/spec/ruby/type_inference/fixtures/rails_action_view_class_teste.rb +89 -0
- data/spec/ruby/type_inference/fixtures/rails_active_record_class.rb +99 -0
- data/spec/ruby/type_inference/fixtures/rails_teste_active_record.rb +55 -0
- data/spec/ruby/type_inference/fixtures/teste2.rb +16 -0
- data/spec/ruby/type_inference/fixtures/teste_class_and_args.rb +49 -0
- data/spec/ruby/type_inference/fixtures/teste_class_and_args2.rb +11 -0
- data/spec/ruby/type_inference/parser_for_typeinference_spec.rb +69 -0
- data/spec/ruby/type_inference/type_inference_checker_spec.rb +47 -0
- metadata +84 -3
@@ -0,0 +1,53 @@
|
|
1
|
+
module Archruby
|
2
|
+
module Ruby
|
3
|
+
module TypeInference
|
4
|
+
|
5
|
+
class DependencyOrganizer
|
6
|
+
attr_reader :dependencies, :method_definitions
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@dependencies = {}
|
10
|
+
@method_definitions = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_dependencies(found_dependencies)
|
14
|
+
found_dependencies.each do |class_dependency|
|
15
|
+
class_name = class_dependency.name
|
16
|
+
@dependencies[class_name] ||= Set.new
|
17
|
+
@dependencies[class_name].merge(class_dependency.dependencies)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_method_calls(found_calls)
|
22
|
+
found_calls.each do |method_definition|
|
23
|
+
next if unused_method_definition?(method_definition)
|
24
|
+
method_name = method_definition.method_name
|
25
|
+
class_name = method_definition.class_name
|
26
|
+
args = method_definition.args
|
27
|
+
internal_method_calls = []
|
28
|
+
method_definition.method_calls.each do |internal_method_call|
|
29
|
+
next if unused_internal_method_call?(internal_method_call)
|
30
|
+
internal_method_calls << internal_method_call
|
31
|
+
end
|
32
|
+
if !internal_method_calls.empty?
|
33
|
+
method_def = Ruby::MethodDefinition.new(class_name, method_name, args, internal_method_calls)
|
34
|
+
@method_definitions[class_name] ||= []
|
35
|
+
@method_definitions[class_name] << method_def
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def unused_method_definition?(method_definition)
|
41
|
+
method_definition.method_calls.empty? || method_definition.class_name.to_s.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def unused_internal_method_call?(internal_method_call)
|
45
|
+
internal_method_call.params.nil? ||
|
46
|
+
internal_method_call.params.empty? ||
|
47
|
+
internal_method_call.class_name.to_s.empty?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Archruby
|
2
|
+
module Ruby
|
3
|
+
module TypeInference
|
4
|
+
module Ruby
|
5
|
+
|
6
|
+
class ClassDependency
|
7
|
+
attr_reader :dependencies, :name
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
@dependencies = Set.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_dependency(class_name)
|
15
|
+
@dependencies.add(class_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Archruby
|
2
|
+
module Ruby
|
3
|
+
module TypeInference
|
4
|
+
module Ruby
|
5
|
+
|
6
|
+
class InternalMethodInvocation
|
7
|
+
attr_reader :class_name, :method_name, :params, :linenum
|
8
|
+
|
9
|
+
def initialize(class_name, method_name, params=nil, linenum = nil)
|
10
|
+
@class_name = class_name
|
11
|
+
@method_name = method_name
|
12
|
+
@params = params
|
13
|
+
@linenum = linenum
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Archruby
|
2
|
+
module Ruby
|
3
|
+
module TypeInference
|
4
|
+
module Ruby
|
5
|
+
|
6
|
+
class MethodDefinition
|
7
|
+
attr_reader :class_name, :method_name, :args, :method_calls
|
8
|
+
|
9
|
+
def initialize(class_name, method_name, args, method_calls)
|
10
|
+
@class_name = class_name
|
11
|
+
@method_name = method_name
|
12
|
+
@args = args
|
13
|
+
@method_calls = method_calls
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,537 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
module Archruby
|
5
|
+
module Ruby
|
6
|
+
module TypeInference
|
7
|
+
module Ruby
|
8
|
+
|
9
|
+
class ParserForTypeinference < SexpInterpreter
|
10
|
+
attr_reader :dependencies, :method_definitions
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
super()
|
14
|
+
@current_scope = LocalScope.new
|
15
|
+
@current_dependency_class = []
|
16
|
+
@current_dependency_class_name = nil
|
17
|
+
@current_class = nil
|
18
|
+
@module_names = []
|
19
|
+
@complete_class_name = []
|
20
|
+
@classes = []
|
21
|
+
@current_class = []
|
22
|
+
@method_definitions = []
|
23
|
+
@dependencies = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(content)
|
27
|
+
ast = ruby_parser.parse(content)
|
28
|
+
process(ast)
|
29
|
+
[@dependencies, @method_definitions]
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_block(exp)
|
33
|
+
_, *args = exp
|
34
|
+
args.map! { |subtree| process(subtree) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_lasgn(exp)
|
38
|
+
_, variable_name, *args = exp
|
39
|
+
args.map! { |subtree| process(subtree) }
|
40
|
+
if @current_dependency_class_name
|
41
|
+
@current_scope.add_variable(variable_name, @current_dependency_class_name)
|
42
|
+
end
|
43
|
+
@current_dependency_class_name = nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_call(exp)
|
47
|
+
_, receiver, method_name, *args = exp
|
48
|
+
process(receiver)
|
49
|
+
args.map! { |subtree| process(subtree) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_const(exp)
|
53
|
+
_, const_name = exp
|
54
|
+
if !@current_dependency_class.empty?
|
55
|
+
@current_dependency_class_name = build_full_name(const_name)
|
56
|
+
else
|
57
|
+
@current_dependency_class_name = const_name.to_s
|
58
|
+
end
|
59
|
+
add_dependencies(nil, nil, @current_dependency_class_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def process_colon2(exp)
|
63
|
+
_, first_part, last_part = exp
|
64
|
+
@current_dependency_class.unshift(last_part)
|
65
|
+
process(first_part)
|
66
|
+
end
|
67
|
+
|
68
|
+
def process_colon3(exp)
|
69
|
+
_, constant_name = exp
|
70
|
+
const_name = build_full_name("::#{constant_name}")
|
71
|
+
add_dependencies(nil, nil, const_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def build_full_name(const_name)
|
75
|
+
@current_dependency_class.unshift(const_name)
|
76
|
+
full_class_path = @current_dependency_class.join('::')
|
77
|
+
@current_dependency_class = []
|
78
|
+
full_class_path
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_module(exp)
|
82
|
+
_, module_name, *args = exp
|
83
|
+
if module_name.class == Symbol
|
84
|
+
@module_names.push(module_name.to_s)
|
85
|
+
end
|
86
|
+
args.map! {|sub_tree| process(sub_tree)}
|
87
|
+
end
|
88
|
+
|
89
|
+
def process_class exp
|
90
|
+
_, class_name, *args = exp
|
91
|
+
if class_name.class == Symbol
|
92
|
+
if !@module_names.empty?
|
93
|
+
@classes << "#{@module_names.join("::")}::#{class_name}"
|
94
|
+
else
|
95
|
+
@classes << class_name.to_s
|
96
|
+
end
|
97
|
+
@current_class << @classes.last
|
98
|
+
else
|
99
|
+
# cai aqui quando a definicao é algo do tipo: class Teste::De end
|
100
|
+
get_complete_class_name class_name
|
101
|
+
@classes << @complete_class_name.join("::")
|
102
|
+
@complete_class_name = []
|
103
|
+
@current_class << @classes.last
|
104
|
+
end
|
105
|
+
args.map! {|sub_tree| process(sub_tree) if sub_tree.class == Sexp}
|
106
|
+
@current_class.pop
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_complete_class_name exp
|
110
|
+
if exp[0] == :const
|
111
|
+
_, const_name = exp
|
112
|
+
@complete_class_name.unshift const_name
|
113
|
+
return
|
114
|
+
else
|
115
|
+
_, first_part, last_constant_part = exp
|
116
|
+
if ( _ == :colon3 )
|
117
|
+
process(exp)
|
118
|
+
else
|
119
|
+
@complete_class_name.unshift(last_constant_part)
|
120
|
+
get_complete_class_name first_part
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def process_defn(exp)
|
126
|
+
_, method_name, method_arguments, *method_body = exp
|
127
|
+
@current_scope.add_new_scope
|
128
|
+
args = ProcessMethodArguments.new(method_arguments).parse
|
129
|
+
populate_scope_with_formal_parameters(args)
|
130
|
+
method_calls = ProcessMethodBody.new(method_body, @current_scope).parse
|
131
|
+
add_method_definition(method_name, args, method_calls)
|
132
|
+
add_dependencies(args, method_calls)
|
133
|
+
@current_scope.remove_scope
|
134
|
+
end
|
135
|
+
|
136
|
+
def process_defs(exp)
|
137
|
+
#transformando em um defn
|
138
|
+
without_node_type = exp[2..-1].to_a
|
139
|
+
without_node_type.unshift(:defn)
|
140
|
+
new_sexp = Sexp.from_array(without_node_type)
|
141
|
+
process_defn(new_sexp)
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_method_definition(method_name, args, method_calls)
|
145
|
+
@method_definitions << MethodDefinition.new(
|
146
|
+
@classes.last,
|
147
|
+
method_name,
|
148
|
+
args,
|
149
|
+
method_calls
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
def add_dependencies(args = nil, method_calls = nil, class_name = nil)
|
154
|
+
return if @current_class.last.nil?
|
155
|
+
class_dependency = ClassDependency.new(@classes.last)
|
156
|
+
if class_name
|
157
|
+
class_dependency.add_dependency(class_name)
|
158
|
+
end
|
159
|
+
if args
|
160
|
+
args.each do |key, value|
|
161
|
+
if value.length > 0 #it is a set object
|
162
|
+
class_dependency.add_dependency(value.first)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
if method_calls
|
167
|
+
method_calls.each do |method_call|
|
168
|
+
class_dependency.add_dependency(method_call.class_name)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
@dependencies << class_dependency
|
172
|
+
end
|
173
|
+
|
174
|
+
def populate_scope_with_formal_parameters(args)
|
175
|
+
if !args.empty?
|
176
|
+
args.each do |key, value|
|
177
|
+
#value it is a set object
|
178
|
+
@current_scope.add_formal_parameter(key, value.first)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def process_lit(exp)
|
184
|
+
end
|
185
|
+
|
186
|
+
def process_cdecl(exp)
|
187
|
+
end
|
188
|
+
|
189
|
+
def process_if(exp)
|
190
|
+
_, *args = exp
|
191
|
+
args.map! {|sub_tree| process(sub_tree) if sub_tree.class == Sexp }
|
192
|
+
end
|
193
|
+
|
194
|
+
def process_array(exp)
|
195
|
+
_, *args = exp
|
196
|
+
args.map! {|sub_tree| process(sub_tree)}
|
197
|
+
end
|
198
|
+
|
199
|
+
def process_gvar(exp)
|
200
|
+
#global variables
|
201
|
+
end
|
202
|
+
|
203
|
+
def process_and(exp)
|
204
|
+
_, left_side, right_side = exp
|
205
|
+
process(left_side)
|
206
|
+
process(right_side)
|
207
|
+
end
|
208
|
+
|
209
|
+
def process_or(exp)
|
210
|
+
_, left_side, right_side = exp
|
211
|
+
process(left_side)
|
212
|
+
process(right_side)
|
213
|
+
end
|
214
|
+
|
215
|
+
def process_case(exp)
|
216
|
+
_, condition, when_part, ensure_part = exp
|
217
|
+
process(condition)
|
218
|
+
process(when_part)
|
219
|
+
process(ensure_part)
|
220
|
+
end
|
221
|
+
|
222
|
+
def process_when(exp)
|
223
|
+
_, condition, body = exp
|
224
|
+
process(condition)
|
225
|
+
process(body)
|
226
|
+
end
|
227
|
+
|
228
|
+
def process_rescue(exp)
|
229
|
+
_, body, rescbody = exp
|
230
|
+
process(body)
|
231
|
+
process(rescbody)
|
232
|
+
end
|
233
|
+
|
234
|
+
def process_dregx(exp)
|
235
|
+
_, str, *args = exp
|
236
|
+
args.map! {|sub_tree| process(sub_tree)}
|
237
|
+
end
|
238
|
+
|
239
|
+
def process_dregx_once(exp)
|
240
|
+
_, start, *args = exp
|
241
|
+
args.map! {|sub_tree| process(sub_tree) if sub_tree.class == Sexp}
|
242
|
+
end
|
243
|
+
|
244
|
+
def process_evstr(exp)
|
245
|
+
_, *args = exp
|
246
|
+
args.map! {|sub_tree| process(sub_tree)}
|
247
|
+
end
|
248
|
+
|
249
|
+
def process_dxstr(exp)
|
250
|
+
_, str, *args = exp
|
251
|
+
args.map! {|sub_tree| process(sub_tree)}
|
252
|
+
end
|
253
|
+
|
254
|
+
def process_resbody(exp)
|
255
|
+
_, body, resbody = exp
|
256
|
+
process(body)
|
257
|
+
process(resbody)
|
258
|
+
end
|
259
|
+
|
260
|
+
def process_ensure(exp)
|
261
|
+
_, *args = exp
|
262
|
+
args.map! {|sub_tree| process(sub_tree)}
|
263
|
+
end
|
264
|
+
|
265
|
+
def process_block_pass(exp)
|
266
|
+
_, *args = exp
|
267
|
+
args.map! {|sub_tree| process(sub_tree)}
|
268
|
+
end
|
269
|
+
|
270
|
+
def process_op_asgn2(exp)
|
271
|
+
_, receiver, method, met, last = exp
|
272
|
+
process(receiver)
|
273
|
+
process(last)
|
274
|
+
end
|
275
|
+
|
276
|
+
def process_return(exp)
|
277
|
+
end
|
278
|
+
|
279
|
+
def process_next(exp)
|
280
|
+
end
|
281
|
+
|
282
|
+
def process_alias(exp)
|
283
|
+
end
|
284
|
+
|
285
|
+
def process_ivar(exp)
|
286
|
+
_, var_name, *args = exp
|
287
|
+
args.map! {|sub_tree| process(sub_tree)}
|
288
|
+
end
|
289
|
+
|
290
|
+
def process_svalue(exp)
|
291
|
+
_, *args = exp
|
292
|
+
args.map! {|sub_tree| process(sub_tree)}
|
293
|
+
end
|
294
|
+
|
295
|
+
def process_not(exp)
|
296
|
+
_, *args = exp
|
297
|
+
args.map! {|sub_tree| process(sub_tree)}
|
298
|
+
end
|
299
|
+
|
300
|
+
def process_dot2(exp)
|
301
|
+
_, left, right = exp
|
302
|
+
process(left)
|
303
|
+
process(right)
|
304
|
+
end
|
305
|
+
|
306
|
+
def process_to_ary(exp)
|
307
|
+
_, *args = exp
|
308
|
+
args.map! {|sub_tree| process(sub_tree)}
|
309
|
+
end
|
310
|
+
|
311
|
+
def process_masgn(exp)
|
312
|
+
_, *args = exp
|
313
|
+
args.map! {|sub_tree| process(sub_tree)}
|
314
|
+
end
|
315
|
+
|
316
|
+
def process_match2(exp)
|
317
|
+
_, rec, *args = exp
|
318
|
+
args.map! {|sub_tree| process(sub_tree)}
|
319
|
+
end
|
320
|
+
|
321
|
+
def process_match3(exp)
|
322
|
+
_, first, second = exp
|
323
|
+
process(first)
|
324
|
+
process(second)
|
325
|
+
end
|
326
|
+
|
327
|
+
def process_while(exp)
|
328
|
+
_, condition, body = exp
|
329
|
+
process(condition)
|
330
|
+
process(body)
|
331
|
+
end
|
332
|
+
|
333
|
+
def process_until(exp)
|
334
|
+
_, condition, body = exp
|
335
|
+
process(condition)
|
336
|
+
process(body)
|
337
|
+
end
|
338
|
+
|
339
|
+
def process_for(exp)
|
340
|
+
_, x, y, body = exp
|
341
|
+
process(x)
|
342
|
+
process(y)
|
343
|
+
process(body)
|
344
|
+
end
|
345
|
+
|
346
|
+
def process_valias(exp)
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
def process_xstr(exp)
|
351
|
+
end
|
352
|
+
|
353
|
+
def process_lvar(exp)
|
354
|
+
#chamado para pegar o valor
|
355
|
+
end
|
356
|
+
|
357
|
+
def process_str(exp)
|
358
|
+
end
|
359
|
+
|
360
|
+
def process_begin(exp)
|
361
|
+
end
|
362
|
+
|
363
|
+
def process_retry(exp)
|
364
|
+
end
|
365
|
+
|
366
|
+
def process_cvdecl(exp)
|
367
|
+
_, instance_classvar_name, *value = exp
|
368
|
+
value.map! {|sub_tree| process(sub_tree)}
|
369
|
+
end
|
370
|
+
|
371
|
+
def process_defined(exp)
|
372
|
+
_, *args = exp
|
373
|
+
args.map! {|sub_tree| process(sub_tree)}
|
374
|
+
end
|
375
|
+
|
376
|
+
def process_postexe(exp)
|
377
|
+
end
|
378
|
+
|
379
|
+
def process_iasgn(exp)
|
380
|
+
_, instance_varialbe_name, *value = exp
|
381
|
+
value.map! { |subtree| process(subtree) }
|
382
|
+
end
|
383
|
+
|
384
|
+
def process_dsym(exp)
|
385
|
+
_, str, *args = exp
|
386
|
+
args.map! {|sub_tree| process(sub_tree)}
|
387
|
+
end
|
388
|
+
|
389
|
+
def process_undef(exp)
|
390
|
+
end
|
391
|
+
|
392
|
+
def process_super(exp)
|
393
|
+
end
|
394
|
+
|
395
|
+
def process_attrasgn(exp)
|
396
|
+
_, receiver, method, arg, value = exp
|
397
|
+
process(receiver)
|
398
|
+
process(value)
|
399
|
+
end
|
400
|
+
|
401
|
+
def process_splat(exp)
|
402
|
+
_, *args = exp
|
403
|
+
args.map! {|sub_tree| process(sub_tree)}
|
404
|
+
end
|
405
|
+
|
406
|
+
def process_iter(exp)
|
407
|
+
_, first_part, second_part, *body = exp
|
408
|
+
process(first_part)
|
409
|
+
body.map! {|sub_tree| process(sub_tree)}
|
410
|
+
end
|
411
|
+
|
412
|
+
def process_sclass(exp)
|
413
|
+
_, singleton_class, *body = exp
|
414
|
+
body.map! {|sub_tree| process(sub_tree)}
|
415
|
+
end
|
416
|
+
|
417
|
+
def process_hash(exp)
|
418
|
+
_, key, value = exp
|
419
|
+
process(key)
|
420
|
+
process(value)
|
421
|
+
end
|
422
|
+
|
423
|
+
def process_op_asgn1(exp)
|
424
|
+
_, receiver, arg, method_name, *args = exp
|
425
|
+
args.map! {|sub_tree| process(sub_tree)}
|
426
|
+
end
|
427
|
+
|
428
|
+
def process_op_asgn_or(exp)
|
429
|
+
_, *args = exp
|
430
|
+
args.map! {|sub_tree| process(sub_tree)}
|
431
|
+
end
|
432
|
+
|
433
|
+
def process_gasgn(exp)
|
434
|
+
_, global_var_name, *value = exp
|
435
|
+
value.map! {|sub_tree| process(sub_tree)}
|
436
|
+
end
|
437
|
+
|
438
|
+
def process_cvar(exp)
|
439
|
+
# class variable
|
440
|
+
end
|
441
|
+
|
442
|
+
def process_break(exp)
|
443
|
+
end
|
444
|
+
|
445
|
+
def process_nth_ref(exp)
|
446
|
+
end
|
447
|
+
|
448
|
+
def process_dstr(exp)
|
449
|
+
# string dinamica, pode ser interessante se
|
450
|
+
# quisermos pegar alguma coisa dentro delas
|
451
|
+
|
452
|
+
end
|
453
|
+
|
454
|
+
def process_true(exp)
|
455
|
+
end
|
456
|
+
|
457
|
+
def process_false(exp)
|
458
|
+
end
|
459
|
+
|
460
|
+
def process_self(exp)
|
461
|
+
end
|
462
|
+
|
463
|
+
def process_nil(exp)
|
464
|
+
end
|
465
|
+
|
466
|
+
# def process_sclass(exp)
|
467
|
+
# binding.pry
|
468
|
+
# end
|
469
|
+
|
470
|
+
def ruby_parser
|
471
|
+
RubyParser.new
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
class LocalScope
|
476
|
+
def initialize
|
477
|
+
@scopes = [Set.new]
|
478
|
+
@formal_parameters = [Set.new]
|
479
|
+
@current_scope = @scopes.last
|
480
|
+
@current_formal_parameters = @formal_parameters.last
|
481
|
+
end
|
482
|
+
|
483
|
+
def add_variable(name, type)
|
484
|
+
@current_scope.add([name, type])
|
485
|
+
end
|
486
|
+
|
487
|
+
def add_formal_parameter(name, type)
|
488
|
+
@current_formal_parameters.add([name, type])
|
489
|
+
end
|
490
|
+
|
491
|
+
def var_type(name)
|
492
|
+
@current_scope.each do |var_info|
|
493
|
+
if var_info[0].to_s == name.to_s
|
494
|
+
return var_info[1]
|
495
|
+
end
|
496
|
+
end
|
497
|
+
return nil
|
498
|
+
end
|
499
|
+
|
500
|
+
def has_formal_parameter(name)
|
501
|
+
check_from_collection(@current_formal_parameters, name)
|
502
|
+
end
|
503
|
+
|
504
|
+
def has_local_params(name)
|
505
|
+
check_from_collection(@current_scope, name)
|
506
|
+
end
|
507
|
+
|
508
|
+
def add_new_scope
|
509
|
+
@scopes << Set.new
|
510
|
+
@current_scope = @scopes.last
|
511
|
+
@formal_parameters << Set.new
|
512
|
+
@current_formal_parameters = @formal_parameters.last
|
513
|
+
end
|
514
|
+
|
515
|
+
def remove_scope
|
516
|
+
@scopes.pop
|
517
|
+
@current_scope = @scopes.last
|
518
|
+
@formal_parameters.pop
|
519
|
+
@current_formal_parameters = @formal_parameters.last
|
520
|
+
end
|
521
|
+
|
522
|
+
private
|
523
|
+
|
524
|
+
def check_from_collection(collection, name)
|
525
|
+
collection.each do |var_info|
|
526
|
+
if var_info[0].to_s == name.to_s
|
527
|
+
return true
|
528
|
+
end
|
529
|
+
end
|
530
|
+
return false
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|