reflexive 0.0.1
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.
- data/lib/reflexive/application.rb +171 -0
- data/lib/reflexive/coderay_html_encoder.rb +46 -0
- data/lib/reflexive/coderay_ruby_scanner.rb +234 -0
- data/lib/reflexive/columnizer.rb +73 -0
- data/lib/reflexive/constantize.rb +71 -0
- data/lib/reflexive/descendants.rb +39 -0
- data/lib/reflexive/faster_open_struct.rb +116 -0
- data/lib/reflexive/helpers.rb +189 -0
- data/lib/reflexive/methods.rb +140 -0
- data/lib/reflexive/parse_tree_top_down_walker.rb +392 -0
- data/lib/reflexive/reflexive_ripper.rb +274 -0
- data/lib/reflexive/routing_helpers.rb +70 -0
- data/lib/reflexive/variables_scope.rb +16 -0
- data/lib/reflexive.rb +1 -0
- data/public/javascripts/reflexive/jquery-1.4.2.js +6240 -0
- data/public/javascripts/reflexive/reflexive.js +12 -0
- data/public/stylesheets/reflexive/coderay.css +130 -0
- data/public/stylesheets/reflexive/reflexive.css +111 -0
- data/reflexive.gemspec +25 -0
- data/views/constants_methods.html.erb +0 -0
- data/views/constants_show.erb +96 -0
- data/views/dashboard.erb +50 -0
- data/views/directories_show.erb +16 -0
- data/views/error.erb +5 -0
- data/views/files_show.erb +27 -0
- data/views/layout.erb +20 -0
- data/views/methods_apidock.erb +17 -0
- data/views/methods_definition.erb +37 -0
- data/views/methods_rubydoc.erb +16 -0
- metadata +231 -0
@@ -0,0 +1,392 @@
|
|
1
|
+
require "zlib"
|
2
|
+
require "reflexive/variables_scope"
|
3
|
+
|
4
|
+
module Reflexive
|
5
|
+
class ParseTreeTopDownWalker
|
6
|
+
def initialize(events_tree)
|
7
|
+
@events_tree = events_tree
|
8
|
+
@local_variables = []
|
9
|
+
@dynamic_variables = []
|
10
|
+
@variables_scope_id = 1
|
11
|
+
VariablesScope.reset_guid
|
12
|
+
# empty - top level
|
13
|
+
# ["Module", "Class"] - class Class in module Module, class dev level
|
14
|
+
# ["Module", "Class", :instance] - class Class in module Module, instance level
|
15
|
+
@scope = [] # @scope.last - is basically "implicit self"
|
16
|
+
# also used for constant lookup
|
17
|
+
end
|
18
|
+
|
19
|
+
def push_namespace_scope(namespace_name)
|
20
|
+
@scope << namespace_name
|
21
|
+
end
|
22
|
+
|
23
|
+
def push_namespace_instance_scope
|
24
|
+
@scope << :instance
|
25
|
+
end
|
26
|
+
|
27
|
+
def pop_namespace_scope
|
28
|
+
@scope.pop
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_variables_scope
|
32
|
+
(@dynamic_variables.size > 0 ? @dynamic_variables : @local_variables).last
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_local_variable(scanner_event)
|
36
|
+
current_variables_scope.merge!(scanner_event[:ident] => scanner_event)
|
37
|
+
local_variable_assignment(scanner_event)
|
38
|
+
end
|
39
|
+
|
40
|
+
def variables_scope
|
41
|
+
merged_scope = @dynamic_variables.dup.reverse
|
42
|
+
merged_scope << @local_variables.last if @local_variables.size > 0
|
43
|
+
merged_scope
|
44
|
+
end
|
45
|
+
|
46
|
+
# TODO crazy, replace that with something more appropriate
|
47
|
+
def variables_scope_id
|
48
|
+
current_variables_scope.guid
|
49
|
+
end
|
50
|
+
|
51
|
+
def local_variable_defined?(name)
|
52
|
+
variables_scope.any? { |variables| variables.has_key?(name) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def local_variable_scope_id(name)
|
56
|
+
variables_scope.detect { |variables| variables.has_key?(name) }.guid
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_local_variables_from_lhs(lhs_event)
|
60
|
+
# [:var_field, {:ident=>"v1"}]
|
61
|
+
if lhs_event[0] == :var_field
|
62
|
+
if (scanner_event = lhs_event[1]).is_a?(Hash)
|
63
|
+
if scanner_event[:ident]
|
64
|
+
add_local_variable(scanner_event)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
# raise "don't know how to add local variables from lhs_event : #{ lhs_event }"
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_local_variables_from_mlhs(mlhs_event)
|
72
|
+
# [{:ident=>"a"}, {:ident=>"b"}],
|
73
|
+
if mlhs_event.is_a?(Array)
|
74
|
+
if mlhs_event[0] == :mlhs_add_star
|
75
|
+
add_local_variables_from_mlhs(mlhs_event[1])
|
76
|
+
add_local_variable(mlhs_event[2]) if mlhs_event[2][:ident]
|
77
|
+
add_local_variables_from_mlhs(mlhs_event[3]) if mlhs_event[3].is_a?(Array)
|
78
|
+
else
|
79
|
+
mlhs_event.each do |event|
|
80
|
+
next unless scanner_event?(event)
|
81
|
+
if event[:ident]
|
82
|
+
add_local_variable(event)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
# raise "don't know how to add local variables from lhs_event : #{ lhs_event }"
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_local_variables_from_params_event(params_event)
|
91
|
+
return unless params_event
|
92
|
+
params_event = params_event[1] if params_event[0] == :paren # ?
|
93
|
+
found = false
|
94
|
+
for scanner_event in extract_scanner_events_from_tree(params_event)
|
95
|
+
if scanner_event[:ident]
|
96
|
+
found = true
|
97
|
+
add_local_variable(scanner_event)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
# raise "don't know how to add local variables from params_event: #{ params_event }" unless found
|
101
|
+
end
|
102
|
+
|
103
|
+
def extract_scanner_events_from_tree(tree)
|
104
|
+
tree.flatten.select { |e| scanner_event?(e) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def push_local_variables_context
|
108
|
+
@local_variables << VariablesScope.new
|
109
|
+
end
|
110
|
+
|
111
|
+
def pop_local_variables_context
|
112
|
+
@local_variables.pop
|
113
|
+
end
|
114
|
+
|
115
|
+
def push_dynamic_variables_context
|
116
|
+
@dynamic_variables << VariablesScope.new
|
117
|
+
end
|
118
|
+
|
119
|
+
def pop_dynamic_variables_context
|
120
|
+
@dynamic_variables.pop
|
121
|
+
end
|
122
|
+
|
123
|
+
def walk(event = @events_tree)
|
124
|
+
type, *args = event
|
125
|
+
if respond_to?("on_#{ type }")
|
126
|
+
send("on_#{ type }", *args) #rescue r($!, event)
|
127
|
+
else
|
128
|
+
on_default(type, args)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def on_default(type, event_args)
|
133
|
+
return unless event_args # no-args event
|
134
|
+
event_args.each do |arg|
|
135
|
+
if arg == nil
|
136
|
+
# empty arg - pass
|
137
|
+
|
138
|
+
# why the following isn't reported with scanner events?
|
139
|
+
elsif type == :call && [:".", :"::"].include?(arg)
|
140
|
+
elsif type == :var_ref && [:".", :"::"].include?(arg)
|
141
|
+
elsif type == :field && [:".", :"::"].include?(arg)
|
142
|
+
elsif type == :command_call && ([:".", :"::"].include?(arg) || arg == false)
|
143
|
+
elsif type == :args_add_block && arg == false
|
144
|
+
elsif type == :unary && arg.is_a?(Symbol)
|
145
|
+
elsif type == :binary && arg.is_a?(Symbol)
|
146
|
+
elsif scanner_event?(arg)
|
147
|
+
# scanner event - pass
|
148
|
+
elsif (parser_events?(arg) rescue r(type, event_args))
|
149
|
+
arg.each do |event|
|
150
|
+
walk(event)
|
151
|
+
end
|
152
|
+
elsif parser_event?(arg)
|
153
|
+
walk(arg)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def keep_walking(*args)
|
159
|
+
on_default(nil, args)
|
160
|
+
end
|
161
|
+
|
162
|
+
def on_program(body)
|
163
|
+
push_local_variables_context
|
164
|
+
keep_walking(body)
|
165
|
+
pop_local_variables_context
|
166
|
+
end
|
167
|
+
|
168
|
+
def on_def(name, params, body)
|
169
|
+
push_local_variables_context
|
170
|
+
add_local_variables_from_params_event(params)
|
171
|
+
push_namespace_instance_scope
|
172
|
+
keep_walking(body)
|
173
|
+
pop_namespace_scope
|
174
|
+
pop_local_variables_context
|
175
|
+
end
|
176
|
+
|
177
|
+
def on_defs(target, period, name, params, body)
|
178
|
+
push_local_variables_context
|
179
|
+
add_local_variables_from_params_event(params)
|
180
|
+
keep_walking(body)
|
181
|
+
pop_local_variables_context
|
182
|
+
end
|
183
|
+
|
184
|
+
def on_class(name, ancestor, body)
|
185
|
+
keep_walking(name)
|
186
|
+
push_local_variables_context
|
187
|
+
push_namespace_scope(resolve_constant_ref(name))
|
188
|
+
keep_walking(body)
|
189
|
+
pop_namespace_scope
|
190
|
+
pop_local_variables_context
|
191
|
+
end
|
192
|
+
|
193
|
+
def on_sclass(target, body)
|
194
|
+
push_local_variables_context
|
195
|
+
keep_walking(body)
|
196
|
+
pop_local_variables_context
|
197
|
+
end
|
198
|
+
|
199
|
+
def on_module(name, body)
|
200
|
+
keep_walking(name)
|
201
|
+
push_local_variables_context
|
202
|
+
push_namespace_scope(resolve_constant_ref(name))
|
203
|
+
keep_walking(body)
|
204
|
+
pop_namespace_scope
|
205
|
+
pop_local_variables_context
|
206
|
+
end
|
207
|
+
|
208
|
+
def on_do_block(params, body)
|
209
|
+
push_dynamic_variables_context
|
210
|
+
add_local_variables_from_params_event(params)
|
211
|
+
keep_walking(body)
|
212
|
+
pop_dynamic_variables_context
|
213
|
+
end
|
214
|
+
|
215
|
+
def on_brace_block(params, body)
|
216
|
+
push_dynamic_variables_context
|
217
|
+
add_local_variables_from_params_event(params)
|
218
|
+
keep_walking(body)
|
219
|
+
pop_dynamic_variables_context
|
220
|
+
end
|
221
|
+
|
222
|
+
def on_assign(lhs, rhs)
|
223
|
+
add_local_variables_from_lhs(lhs)
|
224
|
+
keep_walking(rhs)
|
225
|
+
end
|
226
|
+
|
227
|
+
def on_massign(mlhs, mrhs)
|
228
|
+
add_local_variables_from_mlhs(mlhs)
|
229
|
+
keep_walking(mrhs)
|
230
|
+
end
|
231
|
+
|
232
|
+
def on_command(operation, command_args)
|
233
|
+
method_call(operation, nil) if is_ident?(operation)
|
234
|
+
keep_walking(command_args)
|
235
|
+
end
|
236
|
+
|
237
|
+
def on_fcall(operation)
|
238
|
+
method_call(operation, nil) if is_ident?(operation)
|
239
|
+
end
|
240
|
+
|
241
|
+
# primary_value => anything
|
242
|
+
# operation2 : tIDENTIFIER
|
243
|
+
# | tCONSTANT
|
244
|
+
# | tFID
|
245
|
+
# | op
|
246
|
+
# ;
|
247
|
+
# command_args => anything
|
248
|
+
def on_command_call(receiver, dot, method, args)
|
249
|
+
if is_ident?(method) &&
|
250
|
+
(constant = resolve_constant_ref(receiver))
|
251
|
+
method_call(method, [constant])
|
252
|
+
end
|
253
|
+
keep_walking(receiver, args)
|
254
|
+
end
|
255
|
+
|
256
|
+
def resolve_constant_ref(events)
|
257
|
+
if events[0] == :var_ref || events[0] == :const_ref &&
|
258
|
+
scanner_event?(events[1]) &&
|
259
|
+
events[1][:const]
|
260
|
+
events[1][:const]
|
261
|
+
elsif events[0] == :top_const_ref &&
|
262
|
+
scanner_event?(events[1]) &&
|
263
|
+
events[1][:const]
|
264
|
+
"::" + events[1][:const]
|
265
|
+
elsif events[0] == :const_path_ref &&
|
266
|
+
(constant = resolve_constant_ref(events[1]))
|
267
|
+
"#{ constant }::#{ events[2][:const] }"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def resolve_receiver(receiver)
|
272
|
+
resolve_constant_ref(receiver)
|
273
|
+
end
|
274
|
+
|
275
|
+
# [:call,
|
276
|
+
# [:var_ref, {:ident=>"subclasses"}]
|
277
|
+
def on_call(receiver, dot, method)
|
278
|
+
if rcv = resolve_receiver(receiver)
|
279
|
+
method_call(method, [rcv])
|
280
|
+
else
|
281
|
+
keep_walking(receiver)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def on_var_ref(ref_event)
|
286
|
+
# [:var_ref, {:kw=>"false"}]
|
287
|
+
# [:var_ref, {:cvar=>"@@subclasses"}]
|
288
|
+
# [:var_ref, {:ident=>"child"}] (sic!)
|
289
|
+
# [:binary,
|
290
|
+
# [:var_ref, {:ident=>"nonreloadables"}],
|
291
|
+
# :<<,
|
292
|
+
# [:var_ref, {:ident=>"klass"}]
|
293
|
+
#
|
294
|
+
#[:call,
|
295
|
+
# [:var_ref, {:ident=>"klass"}],
|
296
|
+
# :".",
|
297
|
+
# {:ident=>"instance_variables"}],
|
298
|
+
#
|
299
|
+
#
|
300
|
+
if scanner_event?(ref_event)
|
301
|
+
if ref_event[:ident]
|
302
|
+
if local_variable_defined?(ref_event[:ident])
|
303
|
+
local_variable_access(ref_event)
|
304
|
+
else
|
305
|
+
method_call(ref_event, nil)
|
306
|
+
end
|
307
|
+
elsif ref_event[:const]
|
308
|
+
constant_access(ref_event)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def on_const_ref(const_ref_event)
|
314
|
+
if scanner_event?(const_ref_event)
|
315
|
+
if const_ref_event[:const]
|
316
|
+
constant_access(const_ref_event)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def on_const_path_ref(primary_value, name)
|
322
|
+
keep_walking(primary_value)
|
323
|
+
if (constant = resolve_constant_ref(primary_value)) &&
|
324
|
+
scanner_event?(name) && name[:const]
|
325
|
+
constant_access(name, "#{ constant }::#{ name[:const] }")
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def method_call(scanner_event, receiver, *args)
|
330
|
+
unless receiver
|
331
|
+
# implict self concept
|
332
|
+
receiver = @scope.dup
|
333
|
+
end
|
334
|
+
merge_tags(scanner_event,
|
335
|
+
{:method_call =>
|
336
|
+
{:name => scanner_event[:ident],
|
337
|
+
:receiver => receiver,
|
338
|
+
:scope => constant_access_scope}})
|
339
|
+
end
|
340
|
+
|
341
|
+
def local_variable_access(scanner_event)
|
342
|
+
existing_variable_id = "#{ local_variable_scope_id(scanner_event[:ident]) }:#{ scanner_event[:ident] }"
|
343
|
+
merge_tags(scanner_event,
|
344
|
+
:local_variable_access => existing_variable_id )
|
345
|
+
end
|
346
|
+
|
347
|
+
def constant_access_scope
|
348
|
+
scope = @scope.dup
|
349
|
+
scope.pop if scope.last == :instance # class/instance doesn't matter for constant lookup
|
350
|
+
scope
|
351
|
+
end
|
352
|
+
|
353
|
+
def constant_access(scanner_event, name = nil)
|
354
|
+
unless name
|
355
|
+
name = scanner_event[:const]
|
356
|
+
end
|
357
|
+
merge_tags(scanner_event,
|
358
|
+
:constant_access => { :name => name,
|
359
|
+
:scope => constant_access_scope })
|
360
|
+
end
|
361
|
+
|
362
|
+
def local_variable_assignment(scanner_event)
|
363
|
+
merge_tags(scanner_event,
|
364
|
+
:local_variable_assignment => variable_id(scanner_event))
|
365
|
+
end
|
366
|
+
|
367
|
+
def variable_id(scanner_event)
|
368
|
+
"#{ variables_scope_id }:#{ scanner_event[:ident] }"
|
369
|
+
end
|
370
|
+
|
371
|
+
def merge_tags(scanner_event, tags)
|
372
|
+
scanner_event[:tags] ||= {}
|
373
|
+
scanner_event[:tags].merge!(tags)
|
374
|
+
end
|
375
|
+
|
376
|
+
def scanner_event?(event)
|
377
|
+
event.is_a?(Hash)
|
378
|
+
end
|
379
|
+
|
380
|
+
def parser_event?(event)
|
381
|
+
event.is_a?(Array) && event[0].is_a?(Symbol)
|
382
|
+
end
|
383
|
+
|
384
|
+
def parser_events?(events)
|
385
|
+
events.all? { |event| parser_event?(event) }
|
386
|
+
end
|
387
|
+
|
388
|
+
def is_ident?(event)
|
389
|
+
scanner_event?(event) && event[:ident]
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require "ripper"
|
2
|
+
require "reflexive/parse_tree_top_down_walker"
|
3
|
+
|
4
|
+
module Reflexive
|
5
|
+
# Records all scanner events, injects meta-events when scope
|
6
|
+
# changes (required to implement constant/method look-up)
|
7
|
+
class ReflexiveRipper < Ripper
|
8
|
+
attr_accessor :scanner_events
|
9
|
+
|
10
|
+
META_EVENT = [ :meta_scope ].freeze
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
@scanner_events = []
|
15
|
+
@await_scope_change = false
|
16
|
+
@scope = []
|
17
|
+
@new_scope = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse
|
21
|
+
parse_tree = super
|
22
|
+
require 'pp'
|
23
|
+
# pp parse_tree
|
24
|
+
|
25
|
+
ParseTreeTopDownWalker.new(parse_tree).walk
|
26
|
+
parse_tree
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns array in format: [event_value, event_name, tags]
|
30
|
+
def self.destruct_scanner_event(scanner_event)
|
31
|
+
tags = scanner_event.delete(:tags)
|
32
|
+
[ scanner_event.values.first, scanner_event.keys.first, tags ]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.is_meta_event?(event)
|
36
|
+
META_EVENT.include?(event)
|
37
|
+
end
|
38
|
+
|
39
|
+
Ripper::SCANNER_EVENTS.each do |meth|
|
40
|
+
define_method("on_#{ meth }") do |*args|
|
41
|
+
result = super(*args)
|
42
|
+
@scanner_events << { meth.to_sym => args[0] }
|
43
|
+
stop_await_scope_change
|
44
|
+
@scanner_events[-1]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop_await_scope_change
|
49
|
+
# get here when any of 3 possible constant reference ends,
|
50
|
+
# which means we have new scope in effect
|
51
|
+
if @await_scope_change
|
52
|
+
if @new_scope
|
53
|
+
@scope << @new_scope.dup
|
54
|
+
inject_current_scope
|
55
|
+
@new_scope = nil
|
56
|
+
end
|
57
|
+
@await_scope_change = false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def inject_current_scope
|
62
|
+
@scanner_events << { :meta_scope => @scope.dup }
|
63
|
+
end
|
64
|
+
|
65
|
+
PARSER_EVENT_TABLE.each do |event, arity|
|
66
|
+
if /_new\z/ =~ event.to_s and arity == 0
|
67
|
+
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
68
|
+
def on_#{event}
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
End
|
72
|
+
elsif /_add\z/ =~ event.to_s
|
73
|
+
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
74
|
+
def on_#{event}(list, item)
|
75
|
+
list.push item
|
76
|
+
list
|
77
|
+
end
|
78
|
+
End
|
79
|
+
else
|
80
|
+
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
81
|
+
def on_#{event}(*args)
|
82
|
+
[:#{event}, *args]
|
83
|
+
end
|
84
|
+
End
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Two parser events which fire when class/module definition ends
|
89
|
+
def on_class(*args)
|
90
|
+
@scope.pop
|
91
|
+
inject_current_scope
|
92
|
+
|
93
|
+
[:class, *args]
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_module(*args)
|
97
|
+
@scope.pop
|
98
|
+
inject_current_scope
|
99
|
+
|
100
|
+
[:module, *args]
|
101
|
+
end
|
102
|
+
|
103
|
+
def on_parse_error(*args)
|
104
|
+
raise SyntaxError, "#{ lineno }: #{ args[0] }"
|
105
|
+
end
|
106
|
+
|
107
|
+
# def on_call(*args)
|
108
|
+
# # puts "PARSE: on_call: #{ args.inspect }"
|
109
|
+
# if args.size == 3 &&
|
110
|
+
# (constant = resolve_constant_ref(args[0])) &&
|
111
|
+
# args[1] == :"." &&
|
112
|
+
# args[2][1] == :ident
|
113
|
+
#
|
114
|
+
# meth_ident_token = args[2]
|
115
|
+
# index = token_index(meth_ident_token)
|
116
|
+
# tags = { :constant => constant, :method => args[2][0] }
|
117
|
+
# # wrap the method identifier token in :method_call meta tokens
|
118
|
+
# @scanner_events[index .. index] = [
|
119
|
+
# # [ :method_call, :open, tags ],
|
120
|
+
# meth_ident_token,
|
121
|
+
# # [ :method_call, :close ]
|
122
|
+
# ]
|
123
|
+
# end
|
124
|
+
# [:call, *args]
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# def on_var_ref(*args)
|
128
|
+
# # puts "PARSER: var_ref: #{ args.inspect }"
|
129
|
+
# if args.size == 1 &&
|
130
|
+
# args[0].size == 2 &&
|
131
|
+
# args[0][1] == :ident
|
132
|
+
# meth_ident_token = args[0]
|
133
|
+
# index = token_index(meth_ident_token)
|
134
|
+
# tags = { :instance_method => args[0][0] }
|
135
|
+
# @scanner_events[index .. index] = [
|
136
|
+
# [ :method_call, :open, tags ],
|
137
|
+
# meth_ident_token,
|
138
|
+
# [ :method_call, :close ]
|
139
|
+
# ]
|
140
|
+
# # r @scanner_events[177]
|
141
|
+
# end
|
142
|
+
# [:var_ref, *args]
|
143
|
+
# end
|
144
|
+
|
145
|
+
def token_index(token)
|
146
|
+
@scanner_events.index do |t|
|
147
|
+
t.object_id == token.object_id
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def resolve_constant_ref(tokens)
|
152
|
+
self.class.resolve_constant_ref(tokens)
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.resolve_constant_ref(tokens)
|
156
|
+
if tokens[0] == :var_ref && tokens[1][1] == :const
|
157
|
+
# [:var_ref, ["B", :const]]
|
158
|
+
tokens[1][0]
|
159
|
+
elsif tokens[0] == :top_const_ref && tokens[1][1] == :const
|
160
|
+
# [:top_const_ref, ["A", :const]]
|
161
|
+
"::" + tokens[1][0]
|
162
|
+
# [:const_path_ref, [:top_const_ref, ["A", :const]], ["B", :const]]
|
163
|
+
# [:const_path_ref, [:var_ref, ["A", :const]], ["B", :const]]
|
164
|
+
elsif tokens[0] == :const_path_ref && (constant = resolve_constant_ref(tokens[1]))
|
165
|
+
"#{ constant }::#{ tokens[2][0] }"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def on_sp(*args)
|
170
|
+
@scanner_events << { :sp => args[0] }
|
171
|
+
# ignore space tokens when waiting for scope changes:
|
172
|
+
# stop_await_scope_change
|
173
|
+
|
174
|
+
@scanner_events[-1]
|
175
|
+
end
|
176
|
+
|
177
|
+
# parse.y:
|
178
|
+
#
|
179
|
+
# | k_class cpath superclass
|
180
|
+
# | k_module cpath
|
181
|
+
#
|
182
|
+
# matches "class"
|
183
|
+
def on_kw(kw)
|
184
|
+
if %w(class module).include?(kw)
|
185
|
+
@await_scope_change = "k_class"
|
186
|
+
else
|
187
|
+
stop_await_scope_change
|
188
|
+
end
|
189
|
+
|
190
|
+
@scanner_events << { :kw => kw }
|
191
|
+
|
192
|
+
@scanner_events[-1]
|
193
|
+
end
|
194
|
+
|
195
|
+
# matches "::" in two cases
|
196
|
+
# 1. "class ::TopLevel",
|
197
|
+
# 2. "class Nested::Class"
|
198
|
+
def on_op(token)
|
199
|
+
if @await_scope_change == "k_class" &&
|
200
|
+
token == "::"
|
201
|
+
# tCOLON2, tCOLON3
|
202
|
+
# cpath : tCOLON3 cname
|
203
|
+
# {
|
204
|
+
# /*%%%*/
|
205
|
+
# $$ = NEW_COLON3($2);
|
206
|
+
# /*%
|
207
|
+
# $$ = dispatch1(top_const_ref, $2);
|
208
|
+
# %*/
|
209
|
+
# }
|
210
|
+
@await_scope_change = "k_class tCOLON3"
|
211
|
+
elsif @await_scope_change == "k_class primary_value tCOLON2" &&
|
212
|
+
token == "::" # tCOLON2, tCOLON3
|
213
|
+
@new_scope << "::" # append to the last defined scope
|
214
|
+
else
|
215
|
+
stop_await_scope_change
|
216
|
+
end
|
217
|
+
|
218
|
+
@scanner_events << { :op => token }
|
219
|
+
|
220
|
+
@scanner_events[-1]
|
221
|
+
end
|
222
|
+
|
223
|
+
# cname : tIDENTIFIER
|
224
|
+
# {
|
225
|
+
# /*%%%*/
|
226
|
+
# yyerror("class/module name must be CONSTANT");
|
227
|
+
# /*%
|
228
|
+
# $$ = dispatch1(class_name_error, $1);
|
229
|
+
# %*/
|
230
|
+
# }
|
231
|
+
# | tCONSTANT
|
232
|
+
# ;
|
233
|
+
#
|
234
|
+
# "ClassName"
|
235
|
+
# or
|
236
|
+
# "ClassName::NestedClassName"
|
237
|
+
def on_const(const_name)
|
238
|
+
if @await_scope_change == "k_class tCOLON3" # "class ::TopClass"
|
239
|
+
@new_scope = "::#{ const_name }"
|
240
|
+
elsif @await_scope_change == "k_class" # "class NormalClass"
|
241
|
+
# | cname
|
242
|
+
# {
|
243
|
+
# /*%%%*/
|
244
|
+
# $$ = NEW_COLON2(0, $$);
|
245
|
+
# /*%
|
246
|
+
# $$ = dispatch1(const_ref, $1);
|
247
|
+
# %*/
|
248
|
+
# }
|
249
|
+
@new_scope = "#{ const_name }"
|
250
|
+
@await_scope_change = "k_class primary_value tCOLON2" # "class Class::NestedClass"
|
251
|
+
elsif @await_scope_change == "k_class primary_value tCOLON2"
|
252
|
+
#
|
253
|
+
# | primary_value tCOLON2 cname
|
254
|
+
# {
|
255
|
+
# /*%%%*/
|
256
|
+
# $$ = NEW_COLON2($1, $3);
|
257
|
+
# /*%
|
258
|
+
# $$ = dispatch2(const_path_ref, $1, $3);
|
259
|
+
# %*/
|
260
|
+
# }
|
261
|
+
# ;
|
262
|
+
#
|
263
|
+
# cname : tIDENTIFIER
|
264
|
+
@new_scope << "#{ const_name }" # append to the scope
|
265
|
+
else
|
266
|
+
stop_await_scope_change
|
267
|
+
end
|
268
|
+
|
269
|
+
@scanner_events << { :const => const_name }
|
270
|
+
|
271
|
+
@scanner_events[-1]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|