linecache19 0.5.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env rake
2
+ # -*- Ruby -*-
3
+ require 'rubygems'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+ require 'rake/extensiontask'
8
+
9
+ Rake::ExtensionTask.new('trace_nums')
10
+
11
+ SO_NAME = "trace_nums.so"
12
+
13
+ # ------- Default Package ----------
14
+ PKG_VERSION = open(File.join(File.dirname(__FILE__), 'VERSION')) do
15
+ |f| f.readlines[0].chomp
16
+ end
17
+ PKG_NAME = 'linecache'
18
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
19
+ RUBY_FORGE_PROJECT = 'rocky-hacks'
20
+ RUBY_FORGE_USER = 'rockyb'
21
+
22
+ FILES = FileList[
23
+ 'AUTHORS',
24
+ 'COPYING',
25
+ 'ChangeLog',
26
+ 'NEWS',
27
+ 'README',
28
+ 'Rakefile',
29
+ 'VERSION',
30
+ 'ext/trace_nums.c',
31
+ 'ext/trace_nums.h',
32
+ 'ext/extconf.rb',
33
+ 'lib/*.rb',
34
+ 'test/*.rb',
35
+ 'test/data/*.rb',
36
+ 'test/short-file'
37
+ ]
38
+
39
+ desc "Test everything."
40
+ test_task = task :test => :lib do
41
+ Rake::TestTask.new(:test) do |t|
42
+ t.pattern = 'test/test-*.rb'
43
+ t.verbose = true
44
+ end
45
+ end
46
+
47
+ desc "Create the core ruby-debug shared library extension"
48
+ task :lib do
49
+ Dir.chdir("ext") do
50
+ system("#{Gem.ruby} extconf.rb && make")
51
+ end
52
+ end
53
+
54
+
55
+ desc "Test everything - same as test."
56
+ task :check => :test
57
+
58
+ desc "Create a GNU-style ChangeLog via svn2cl"
59
+ task :ChangeLog do
60
+ system("svn2cl --authors=svn2cl_usermap")
61
+ end
62
+
63
+ # Base GEM Specification
64
+ default_spec = Gem::Specification.new do |spec|
65
+ spec.name = "linecache"
66
+
67
+ spec.homepage = "http://rubyforge.org/projects/rocky-hacks/linecache"
68
+ spec.summary = "Read file with caching"
69
+ spec.description = <<-EOF
70
+ LineCache is a module for reading and caching lines. This may be useful for
71
+ example in a debugger where the same lines are shown many times.
72
+ EOF
73
+
74
+ spec.version = PKG_VERSION
75
+
76
+ spec.author = "R. Bernstein"
77
+ spec.email = "rockyb@rubyforge.net"
78
+ spec.platform = Gem::Platform::RUBY
79
+ spec.require_path = "lib"
80
+ spec.files = FILES.to_a
81
+ spec.extensions = ["ext/extconf.rb"]
82
+
83
+ spec.required_ruby_version = '>= 1.8.2'
84
+ spec.date = Time.now
85
+ spec.rubyforge_project = 'rocky-hacks'
86
+
87
+ # rdoc
88
+ spec.has_rdoc = true
89
+ spec.extra_rdoc_files = ['README', 'lib/linecache.rb', 'lib/tracelines.rb']
90
+
91
+ spec.test_files = FileList['test/*.rb']
92
+ end
93
+
94
+ # Rake task to build the default package
95
+ Rake::GemPackageTask.new(default_spec) do |pkg|
96
+ pkg.need_tar = true
97
+ end
98
+
99
+ task :default => [:test]
100
+
101
+ # Windows specification
102
+ win_spec = default_spec.clone
103
+ win_spec.extensions = []
104
+ ## win_spec.platform = Gem::Platform::WIN32 # deprecated
105
+ win_spec.platform = 'mswin32'
106
+ win_spec.files += ["lib/#{SO_NAME}"]
107
+
108
+ desc "Create Windows Gem"
109
+ task :win32_gem do
110
+ # Copy the win32 extension the top level directory.
111
+ current_dir = File.expand_path(File.dirname(__FILE__))
112
+ source = File.join(current_dir, "ext", "win32", SO_NAME)
113
+ target = File.join(current_dir, "lib", SO_NAME)
114
+ cp(source, target)
115
+
116
+ # Create the gem, then move it to pkg.
117
+ Gem::Builder.new(win_spec).build
118
+ gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
119
+ mv(gem_file, "pkg/#{gem_file}")
120
+
121
+ # Remove win extension from top level directory.
122
+ rm(target)
123
+ end
124
+
125
+ desc "Publish linecache to RubyForge."
126
+ task :publish do
127
+ require 'rake/contrib/sshpublisher'
128
+
129
+ # Get ruby-debug path.
130
+ ruby_debug_path = File.expand_path(File.dirname(__FILE__))
131
+
132
+ publisher = Rake::SshDirPublisher.new("rockyb@rubyforge.org",
133
+ "/var/www/gforge-projects/rocky-hacks/linecache", ruby_debug_path)
134
+ end
135
+
136
+ desc "Remove built files"
137
+ task :clean => [:clobber_package, :clobber_rdoc] do
138
+ cd "ext" do
139
+ if File.exists?("Makefile")
140
+ sh "make clean"
141
+ rm "Makefile"
142
+ end
143
+ derived_files = Dir.glob(".o") + Dir.glob("*.so")
144
+ rm derived_files unless derived_files.empty?
145
+ end
146
+ end
147
+
148
+ # --------- RDoc Documentation ------
149
+ desc "Generate rdoc documentation"
150
+ Rake::RDocTask.new("rdoc") do |rdoc|
151
+ rdoc.rdoc_dir = 'doc'
152
+ rdoc.title = "linecache"
153
+ # Show source inline with line numbers
154
+ rdoc.options << "--inline-source" << "--line-numbers"
155
+ # Make the readme file the start page for the generated html
156
+ rdoc.options << '--main' << 'README'
157
+ rdoc.rdoc_files.include('ext/**/*.c',
158
+ 'lib/*.rb',
159
+ 'README',
160
+ 'COPYING')
161
+ end
162
+
163
+ desc "Publish the release files to RubyForge."
164
+ task :rubyforge_upload do
165
+ `rubyforge login`
166
+ release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
167
+ puts release_command
168
+ system(release_command)
169
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.1
@@ -0,0 +1,27 @@
1
+ require "mkmf"
2
+ require "ruby_core_source"
3
+
4
+ if RUBY_VERSION >= "1.8"
5
+ if RUBY_RELEASE_DATE < "2005-03-22"
6
+ STDERR.print("Ruby version is too old\n")
7
+ exit(1)
8
+ end
9
+ else
10
+ STDERR.print("Ruby version is too old\n")
11
+ exit(1)
12
+ end
13
+
14
+ hdrs = proc {
15
+ have_header("vm_core.h") and have_header("version.h") and
16
+ have_macro("RUBY_VERSION_MAJOR", "version.h")
17
+ }
18
+
19
+ dir_config("ruby")
20
+ if !Ruby_core_source::create_makefile_with_core(hdrs, "trace_nums19")
21
+ STDERR.print("Makefile creation failed\n")
22
+ STDERR.print("*************************************************************\n\n")
23
+ STDERR.print(" NOTE: For Ruby 1.9 installation instructions, please see:\n\n")
24
+ STDERR.print(" http://wiki.github.com/mark-moseley/ruby-debug\n\n")
25
+ STDERR.print("*************************************************************\n\n")
26
+ exit(1)
27
+ end
@@ -0,0 +1,840 @@
1
+ /*
2
+ Ruby 1.9 version: (7/20/2009, Mark Moseley, mark@fast-software.com)
3
+
4
+ Now works with Ruby-1.9.1. Tested with p129 and p243.
5
+ Old code remains and is #ifdef'd around.
6
+
7
+ This does not (and can not) function identically to the 1.8 version.
8
+ Line numbers are ordered differently. But ruby-debug doesn't seem
9
+ to mind the difference.
10
+
11
+ Also, 1.9 does not number lines with a "begin" statement.
12
+
13
+ All this 1.9 version does is compile into bytecode, disassemble it
14
+ using rb_iseq_disasm(), and parse the text output. This isn't a
15
+ great solution; it will break if the disassembly format changes.
16
+ Walking the iseq tree and decoding each instruction is pretty hairy,
17
+ though, so until I have a really compelling reason to go that route,
18
+ I'll leave it at this.
19
+
20
+ My first stab at this walked the nodes, like before, but there's no
21
+ NODE_NEWLINE node types any more. So I just output all line numbers
22
+ that came in, regardless of the node type, and then sorted it and
23
+ removed dups. The problem with that approach is that Ruby 1.9 is not
24
+ consistently sending the debugger hook RUBY_EVENT_LINE messages for
25
+ all lines. In particular:
26
+
27
+ 1: def foo
28
+ 2: a = 5
29
+ 3: return a
30
+ 4: end
31
+
32
+ The disassembly of this code doesn't have a RUBY_EVENT_LINE trace
33
+ message for line 3; it has it only for lines 1 and 2. Oddly, if you
34
+ remove the "return", leaving just "a" on line 3, then you'll get the
35
+ trace message.
36
+
37
+ So the advantage of this approach is that ruby-debug won't let you
38
+ set a breakpoint on lines that don't get the trace message. I think
39
+ it would be more confusing to be allowed to set a breakpoint, and
40
+ never break when the line does get hit, than to be prevented to set
41
+ the breakpoint in the first place even when you should be able to.
42
+
43
+ Ruby 1.8 version:
44
+
45
+ This code creates module TraceLineNumbers with one method
46
+ lnums_for_str. lnums_for_str returns an array lines for which
47
+ RUBY_EVENT_LINE can be called on. In other words, the line numbers
48
+ that can be traced (such as via Tracer) or stopped at in a
49
+ debugger (such as ruby-debug).
50
+
51
+ This code has been tested on Ruby 1.8.6; it does not work on Ruby
52
+ 1.9.x. The code was created via culling from various sources.
53
+
54
+ Ruby 1.8's eval.c, and rb_eval() in particular, is the definitive
55
+ source of how the tree is evaluated. However we don't want to
56
+ actually evaluate the code, which simplifies things. In contrast,
57
+ we need lines for all branches, and not just the ones that get
58
+ executed on a given run. For example in an "if" node the "then"
59
+ part may or may not get executed, but we want to get the trace line
60
+ numbers for the "then" part regardless.
61
+
62
+ Code enclosed in the ***'s contains code from eval.c which is
63
+ included for comparison.
64
+
65
+ Also parse.y from Ruby 1.8 can shed light on how the nodes get
66
+ created.
67
+
68
+ Some legacy code in ParseTree is similar and necessarily more
69
+ complex. We would have used that gem from the outside and lived
70
+ with the additional bloat were it not broken for our purposes and
71
+ were it not for the author's lack of interest in extending it to
72
+ handle what's needed here.
73
+
74
+ Finally, node_help.txt from nodewrap contains descriptions of many
75
+ of the node types.
76
+ */
77
+ #include <ruby.h>
78
+ #include <version.h>
79
+ #if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8
80
+ #define RUBY_VERSION_1_8
81
+ #include <node.h>
82
+ #include <rubysig.h>
83
+ #else
84
+ #include <vm_core.h>
85
+ #endif
86
+ #include "trace_nums.h"
87
+
88
+ VALUE mTraceLineNumbers;
89
+
90
+ #ifdef RUBY_VERSION_1_8
91
+ RUBY_EXTERN NODE *ruby_eval_tree_begin;
92
+ RUBY_EXTERN int ruby_in_eval;
93
+
94
+ #define nd_3rd u3.node
95
+
96
+ extern struct FRAME {
97
+ VALUE self;
98
+ int argc;
99
+ ID last_func;
100
+ ID orig_func;
101
+ VALUE last_class;
102
+ struct FRAME *prev;
103
+ struct FRAME *tmp;
104
+ struct RNode *node;
105
+ int iter;
106
+ int flags;
107
+ unsigned long uniq;
108
+ } *ruby_frame;
109
+
110
+ struct METHOD {
111
+ VALUE klass, rklass;
112
+ VALUE recv;
113
+ ID id, oid;
114
+ #if RUBY_VERSION_CODE > 182
115
+ int safe_level;
116
+ #endif
117
+ NODE *body;
118
+ };
119
+
120
+ struct BLOCK {
121
+ NODE *var;
122
+ NODE *body;
123
+ VALUE self;
124
+ struct FRAME frame;
125
+ struct SCOPE *scope;
126
+ VALUE klass;
127
+ NODE *cref;
128
+ int iter;
129
+ int vmode;
130
+ int flags;
131
+ int uniq;
132
+ struct RVarmap *dyna_vars;
133
+ VALUE orig_thread;
134
+ VALUE wrapper;
135
+ VALUE block_obj;
136
+ struct BLOCK *outer;
137
+ struct BLOCK *prev;
138
+ };
139
+ #endif /* RUBY_VERSION_1_8 */
140
+
141
+ #define RETURN \
142
+ goto finish
143
+
144
+ #define EVENT_LINE(node) \
145
+ rb_ary_push(ary, INT2NUM(nd_line(node)))
146
+
147
+ #ifdef FINISHED
148
+ #define EVENT_CALL(node) \
149
+ rb_ary_push(ary, INT2NUM(nd_line(node)))
150
+ #else
151
+ #define EVENT_CALL(node)
152
+ #endif
153
+
154
+ /* Used just in debugging. */
155
+ static int indent_level = 0;
156
+
157
+ #ifdef RUBY_VERSION_1_8
158
+ static
159
+ void ln_eval(VALUE self, NODE * n, VALUE ary) {
160
+ NODE * volatile contnode = 0;
161
+ NODE * volatile node = n;
162
+
163
+ if (RTEST(ruby_debug)) {
164
+ char fmt[30] = { '\0', };
165
+ snprintf(fmt, sizeof(fmt), "%%%ds", indent_level+1);
166
+ fprintf(stderr, fmt, "[");
167
+ indent_level += 2;
168
+ }
169
+
170
+ again:
171
+ if (!node) RETURN;
172
+
173
+ if (RTEST(ruby_debug)) {
174
+ NODE *r = RNODE(node); /* For debugging */
175
+ fprintf(stderr, "%s ", NODE2NAME[nd_type(node)]);
176
+ }
177
+
178
+ switch (nd_type(node)) {
179
+ case NODE_BLOCK:
180
+ while (node) {
181
+ ln_eval(self, node->nd_head, ary);
182
+ node = node->nd_next;
183
+ }
184
+
185
+ case NODE_POSTEXE: /* END { ... } */
186
+ /* Nothing to do here... we are in an iter block */
187
+ /***
188
+ rb_f_END();
189
+ nd_set_type(node, NODE_NIL); /+ exec just once +/
190
+ result = Qnil;
191
+ ***/
192
+ break;
193
+
194
+ /* begin .. end without clauses */
195
+ case NODE_BEGIN:
196
+ /* node for speed-up(top-level loop for -n/-p) */
197
+ node = node->nd_body;
198
+ goto again;
199
+
200
+ /* nodes for speed-up(default match) */
201
+ case NODE_MATCH:
202
+ /* result = rb_reg_match2(node->nd_lit); */
203
+ break;
204
+
205
+ /* nodes for speed-up(literal match) */
206
+ case NODE_MATCH2:
207
+ /* l = */ ln_eval(self, node->nd_recv, ary);
208
+ /* r = */ ln_eval(self, node->nd_value, ary);
209
+ /*** result = rb_reg_match(l, r); ***/
210
+ break;
211
+
212
+ /* nodes for speed-up(literal match) */
213
+ case NODE_MATCH3: /* z =~ /"#{var}"/ for example */
214
+ /* r = */ ln_eval(self, node->nd_recv, ary);
215
+ /* l = */ ln_eval(self, node->nd_value, ary);
216
+ /***
217
+ if (TYPE(l) == T_STRING) {
218
+ result = rb_reg_match(r, l);
219
+ }
220
+ else {
221
+ // It is possible that value can be a function call which
222
+ // can trigger an call event. So to be conservative,
223
+ // we have to add a line number here.
224
+ result = rb_funcall(l, match, 1, r);
225
+ }
226
+ ****/
227
+ EVENT_CALL(node);
228
+ break;
229
+
230
+ /* node for speed-up(top-level loop for -n/-p) */
231
+ case NODE_OPT_N:
232
+ /* Lots of ugliness in eval.c. */
233
+ ln_eval(self, node->nd_body, ary);
234
+ break;
235
+
236
+ /* These nodes are empty. */
237
+ case NODE_SELF:
238
+ case NODE_NIL:
239
+ case NODE_TRUE:
240
+ case NODE_FALSE:
241
+ RETURN /* (something) */;
242
+
243
+ case NODE_IF:
244
+ EVENT_LINE(node);
245
+ ln_eval(self, node->nd_cond, ary);
246
+ if (node->nd_body) {
247
+ if (!node->nd_else) {
248
+ node = node->nd_body;
249
+ goto again;
250
+ }
251
+ ln_eval(self, node->nd_body, ary);
252
+ }
253
+ if (node->nd_else) {
254
+ node = node->nd_else;
255
+ goto again;
256
+ }
257
+ break;
258
+
259
+ case NODE_WHEN:
260
+ {
261
+ NODE *orig_node = node;
262
+ while (node) {
263
+ NODE *tag;
264
+
265
+ if (nd_type(node) != NODE_WHEN) goto again;
266
+ tag = node->nd_head;
267
+ while (tag) {
268
+ EVENT_LINE(tag);
269
+ if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
270
+ ln_eval(self, tag->nd_head->nd_head, ary);
271
+ }
272
+ tag = tag->nd_next;
273
+ }
274
+ node = node->nd_next;
275
+ }
276
+ if (orig_node->nd_body) {
277
+ ln_eval(self, orig_node->nd_body, ary); /* body */
278
+ }
279
+ RETURN /***(Qnil)***/ ;
280
+ }
281
+
282
+ case NODE_CASE:
283
+ ln_eval(self, node->nd_head, ary); /* expr */
284
+ node = node->nd_body;
285
+ while (node) {
286
+ NODE *tag;
287
+ if (nd_type(node) != NODE_WHEN) {
288
+ goto again;
289
+ }
290
+ tag = node->nd_head;
291
+ while (tag) {
292
+ EVENT_LINE(tag);
293
+ if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
294
+ ln_eval(self, tag->nd_head->nd_head, ary);
295
+ tag = tag->nd_next;
296
+ continue;
297
+ }
298
+ ln_eval(self, tag->nd_head, ary);
299
+ tag = tag->nd_next;
300
+ }
301
+ ln_eval(self, node->nd_body, ary);
302
+ node = node->nd_next;
303
+ }
304
+ RETURN /***(Qnil)***/;
305
+
306
+ case NODE_WHILE:
307
+ case NODE_UNTIL:
308
+ /* Doesn't follow eval.c */
309
+ ln_eval(self, node->nd_cond, ary);
310
+ if (node->nd_body) {
311
+ ln_eval(self, node->nd_body, ary);
312
+ }
313
+ break;
314
+
315
+ case NODE_BLOCK_PASS:
316
+ /*** result = block_pass(self, node); ***/
317
+ ln_eval(self, node->nd_body, ary);
318
+ ln_eval(self, node->nd_iter, ary);
319
+ break;
320
+
321
+ case NODE_ITER:
322
+ case NODE_FOR:
323
+ ln_eval(self, node->nd_iter, ary);
324
+ if (node->nd_var != (NODE *)1
325
+ && node->nd_var != (NODE *)2
326
+ && node->nd_var != NULL) {
327
+ ln_eval(self, node->nd_var, ary);
328
+ }
329
+ node = node->nd_body;
330
+ goto again;
331
+
332
+ case NODE_BREAK:
333
+ /* break_jump(rb_eval(self, node->nd_stts)); */
334
+ ln_eval(self, node->nd_stts, ary);
335
+ break;
336
+
337
+ case NODE_NEXT:
338
+ /*** CHECK_INTS;
339
+ next_jump(rb_eval(self, node->nd_stts)); ***/
340
+ ln_eval(self, node->nd_stts, ary);
341
+ break;
342
+
343
+ case NODE_REDO:
344
+ /*** CHECK_INTS;
345
+ JUMP_TAG(TAG_REDO); ***/
346
+ break;
347
+
348
+ case NODE_RETRY:
349
+ /*** CHECK_INTS;
350
+ JUMP_TAG(TAG_RETRY); ***/
351
+ break;
352
+
353
+ case NODE_SPLAT:
354
+ /*** result = splat_value(rb_eval(self, node->nd_head)); ***/
355
+ ln_eval(self, node->nd_head, ary);
356
+ break;
357
+
358
+ case NODE_TO_ARY:
359
+ /*** result = rb_ary_to_ary(rb_eval(self, node->nd_head)); ***/
360
+ ln_eval(self, node->nd_head, ary);
361
+ break;
362
+
363
+ case NODE_SVALUE: /* a = b, c */
364
+ /***
365
+ result = avalue_splat(rb_eval(self, node->nd_head));
366
+ if (result == Qundef) result = Qnil; ***/
367
+ ln_eval(self, node->nd_head, ary);
368
+ break;
369
+
370
+ case NODE_YIELD:
371
+ if (node->nd_head) {
372
+ /*** result = rb_eval(self, node->nd_head);
373
+ ruby_current_node = node; else ... ***/
374
+ ln_eval(self, node->nd_head, ary);
375
+ }
376
+ break;
377
+
378
+ case NODE_RESCUE:
379
+ /* Follow ruby_parse.rb and pray for the best. */
380
+ ln_eval(self, node->nd_1st, ary);
381
+ ln_eval(self, node->nd_2nd, ary);
382
+ ln_eval(self, node->nd_3rd, ary);
383
+ break;
384
+
385
+ case NODE_ENSURE:
386
+ ln_eval(self, node->nd_head, ary);
387
+ if (node->nd_ensr) {
388
+ ln_eval(self, node->nd_ensr, ary);
389
+ }
390
+ break;
391
+
392
+ case NODE_AND:
393
+ case NODE_OR:
394
+ ln_eval(self, node->nd_1st, ary);
395
+ ln_eval(self, node->nd_2nd, ary);
396
+ break;
397
+
398
+ case NODE_NOT:
399
+ /*** if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse;
400
+ else result = Qtrue; ***/
401
+ ln_eval(self, node->nd_body, ary);
402
+ break;
403
+
404
+ case NODE_DOT2:
405
+ case NODE_DOT3:
406
+ case NODE_FLIP2:
407
+ case NODE_FLIP3:
408
+ ln_eval(self, node->nd_beg, ary);
409
+ ln_eval(self, node->nd_end, ary);
410
+ break;
411
+
412
+ case NODE_RETURN:
413
+ if (node->nd_stts)
414
+ ln_eval(self, node->nd_stts, ary);
415
+ break;
416
+
417
+ case NODE_ARGSCAT:
418
+ case NODE_ARGSPUSH:
419
+ ln_eval(self, node->nd_head, ary);
420
+ ln_eval(self, node->nd_body, ary);
421
+ break;
422
+
423
+ case NODE_ATTRASGN: /* literal.meth = y u1 u2 u3 */
424
+ /* node id node */
425
+ if (node->nd_recv == (NODE *)1) {
426
+ ln_eval(self, NEW_SELF(), ary);
427
+ } else {
428
+ ln_eval(self, node->nd_recv, ary);
429
+ }
430
+ ln_eval(self, node->nd_3rd, ary);
431
+ break;
432
+ case NODE_CALL:
433
+ case NODE_FCALL:
434
+ case NODE_VCALL:
435
+ if (nd_type(node) != NODE_FCALL)
436
+ ln_eval(self, node->nd_recv, ary);
437
+ if (node->nd_args || nd_type(node) != NODE_FCALL)
438
+ ln_eval(self, node->nd_args, ary);
439
+ break;
440
+
441
+ case NODE_SUPER:
442
+ ln_eval(self, node->nd_args, ary);
443
+ break;
444
+
445
+ case NODE_ZSUPER:
446
+ break;
447
+
448
+ case NODE_SCOPE:
449
+ ln_eval(self, node->nd_next, ary);
450
+ break;
451
+
452
+ case NODE_OP_ASGN1:
453
+ ln_eval(self, node->nd_recv, ary);
454
+ #if RUBY_VERSION_CODE < 185
455
+ ln_eval(self, node->nd_args->nd_next, ary);
456
+ #else
457
+ ln_eval(self, node->nd_args->nd_2nd, ary);
458
+ #endif
459
+ ln_eval(self, node->nd_args->nd_head, ary);
460
+ break;
461
+
462
+ case NODE_OP_ASGN2:
463
+ ln_eval(self, node->nd_recv, ary);
464
+ ln_eval(self, node->nd_value, ary);
465
+ break;
466
+
467
+ case NODE_OP_ASGN_AND:
468
+ case NODE_OP_ASGN_OR:
469
+ ln_eval(self, node->nd_head, ary);
470
+ ln_eval(self, node->nd_value, ary);
471
+ break;
472
+
473
+ case NODE_MASGN:
474
+ ln_eval(self, node->nd_head, ary);
475
+ if (node->nd_args) {
476
+ if (node->nd_args != (NODE *)-1) {
477
+ ln_eval(self, node->nd_args, ary);
478
+ }
479
+ }
480
+ ln_eval(self, node->nd_value, ary);
481
+ break;
482
+
483
+ case NODE_LASGN:
484
+ case NODE_DASGN:
485
+ case NODE_DASGN_CURR:
486
+ case NODE_GASGN:
487
+ case NODE_IASGN:
488
+ case NODE_CDECL:
489
+ case NODE_CVDECL:
490
+ case NODE_CVASGN:
491
+ ln_eval(self, node->nd_value, ary);
492
+ break;
493
+
494
+ case NODE_LVAR:
495
+ case NODE_DVAR:
496
+ case NODE_GVAR:
497
+ case NODE_IVAR:
498
+ case NODE_CONST:
499
+ case NODE_CVAR:
500
+ break;
501
+
502
+ case NODE_BLOCK_ARG: /* u1 u3 (def x(&b) */
503
+ break;
504
+
505
+ case NODE_COLON2:
506
+ ln_eval(self, node->nd_head, ary);
507
+ break;
508
+
509
+ case NODE_COLON3: /* u2 (::OUTER_CONST) */
510
+ break;
511
+
512
+ case NODE_NTH_REF: /* u2 u3 ($1) - u3 is local_cnt('~') ignorable? */
513
+ break;
514
+
515
+ case NODE_BACK_REF: /* u2 u3 ($& etc) */
516
+ break;
517
+
518
+ case NODE_HASH:
519
+ {
520
+ NODE *list;
521
+ list = node->nd_head;
522
+ while (list) {
523
+ ln_eval(self, list->nd_head, ary);
524
+ list = list->nd_next;
525
+ if (list == 0)
526
+ rb_bug("odd number list for Hash");
527
+ ln_eval(self, list->nd_head, ary);
528
+ list = list->nd_next;
529
+ }
530
+ }
531
+ break;
532
+
533
+ case NODE_ZARRAY:
534
+ break;
535
+
536
+ case NODE_ARRAY:
537
+ {
538
+ long int i = node->nd_alen;
539
+ for (i=0; node; node=node->nd_next) {
540
+ ln_eval(self, node->nd_head, ary);
541
+ }
542
+ }
543
+ break;
544
+
545
+ case NODE_STR: /* u1 */
546
+ break;
547
+
548
+ case NODE_EVSTR: /* eval of a string */
549
+ ln_eval(self, node->nd_2nd, ary);
550
+ break;
551
+
552
+ case NODE_DSTR:
553
+ case NODE_DXSTR:
554
+ case NODE_DREGX:
555
+ case NODE_DREGX_ONCE:
556
+ case NODE_DSYM:
557
+ {
558
+ NODE *list = node->nd_next;
559
+ while (list) {
560
+ if (list->nd_head) {
561
+ switch (nd_type(list->nd_head)) {
562
+ case NODE_STR:
563
+ ln_eval(self, list->nd_head, ary);
564
+ break;
565
+ case NODE_EVSTR:
566
+ ln_eval(self, list->nd_head, ary);
567
+ break;
568
+ default:
569
+ ln_eval(self, list->nd_head, ary);
570
+ break;
571
+ }
572
+ }
573
+ list = list->nd_next;
574
+ }
575
+ }
576
+ break;
577
+
578
+ case NODE_XSTR: /* u1 (%x{ls}) */
579
+ /* Issues rb_funcall(self, '`'...). So I think we have to
580
+ register a call event. */
581
+ EVENT_CALL(node);
582
+ break;
583
+
584
+ case NODE_LIT:
585
+ break;
586
+
587
+ case NODE_DEFN:
588
+ ln_eval(self, node->nd_defn, ary);
589
+ break;
590
+
591
+ case NODE_DEFS:
592
+ if (node->nd_defn) {
593
+ ln_eval(self, node->nd_recv, ary);
594
+ }
595
+ ln_eval(self, node->nd_defn, ary);
596
+ break;
597
+
598
+ case NODE_UNDEF: /* u2 (undef name, ...) */
599
+ #if RUBY_VERSION_CODE >= 185
600
+ /*** ...
601
+ rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node)));
602
+ ...
603
+ ***/
604
+ ln_eval(self, node->u2.node, ary);
605
+ #endif
606
+ break;
607
+
608
+ case NODE_ALIAS: /* u1 u2 (alias :blah :blah2) */
609
+ #if RUBY_VERSION_CODE >= 185
610
+ ln_eval(self, node->nd_1st, ary);
611
+ ln_eval(self, node->nd_2nd, ary);
612
+ #endif
613
+ break;
614
+ case NODE_VALIAS: /* u1 u2 (alias $global $global2) */
615
+ break;
616
+
617
+ case NODE_CLASS:
618
+ if (node->nd_super) {
619
+ ln_eval(self, node->nd_super, ary);
620
+ }
621
+ ln_eval(self, node->nd_body, ary);
622
+ break;
623
+
624
+ case NODE_MODULE:
625
+ ln_eval(self, node->nd_body, ary);
626
+ break;
627
+
628
+ case NODE_SCLASS:
629
+ ln_eval(self, node->nd_recv, ary);
630
+ ln_eval(self, node->nd_body, ary);
631
+ break;
632
+
633
+ case NODE_DEFINED:
634
+ ln_eval(self, node->nd_head, ary);
635
+ break;
636
+
637
+ case NODE_NEWLINE:
638
+ EVENT_LINE(node);
639
+ node = node->nd_next;
640
+ goto again;
641
+
642
+ case NODE_CFUNC:
643
+ case NODE_IFUNC:
644
+ break;
645
+
646
+ #if RUBY_VERSION_CODE >= 190
647
+ case NODE_ERRINFO:
648
+ case NODE_VALUES:
649
+ case NODE_PRELUDE:
650
+ case NODE_LAMBDA:
651
+ rb_warn("Ruby 1.9 is very different. You shouldn't have gotten here.");
652
+ break;
653
+ #endif
654
+
655
+ case NODE_BMETHOD: /* define_method (or rb_mod_define_method) with a block */
656
+ {
657
+ struct BLOCK *data;
658
+ Data_Get_Struct(node->nd_cval, struct BLOCK, data);
659
+ if (!(data->var == 0 || data->var == (NODE *)1 ||
660
+ data->var == (NODE *)2)) {
661
+ /* block doesn't have args. */
662
+ ln_eval(self, data->var, ary);
663
+ }
664
+ ln_eval(self, data->body, ary);
665
+ break;
666
+ }
667
+ break;
668
+
669
+ #if RUBY_VERSION_CODE < 190
670
+ case NODE_DMETHOD:
671
+ {
672
+ struct METHOD *data;
673
+ Data_Get_Struct(node->nd_cval, struct METHOD, data);
674
+ ln_eval(self, data->body, ary);
675
+ break;
676
+ }
677
+ #endif
678
+
679
+ case NODE_METHOD:
680
+ ln_eval(self, node->nd_3rd, ary);
681
+ break;
682
+
683
+
684
+ case NODE_ARGS: {
685
+ if (node->nd_opt) {
686
+ ln_eval(self, node->nd_opt, ary);
687
+ }
688
+ } break;
689
+
690
+ case NODE_ATTRSET:
691
+ break;
692
+
693
+ /*
694
+ // rescue body:
695
+ // begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
696
+ // stmt rescue stmt
697
+ // a = b rescue c
698
+ // NODE_RESBODY doesn't appear in 1.8.6's rb_eval
699
+ */
700
+ case NODE_RESBODY:
701
+ if (node->nd_3rd) {
702
+ ln_eval(self, node->nd_3rd, ary);
703
+ }
704
+ ln_eval(self, node->nd_2nd, ary);
705
+ ln_eval(self, node->nd_1st, ary);
706
+ break;
707
+
708
+ /* Nodes we found but have yet to decypher */
709
+ /* I think these are all runtime only... not positive but... */
710
+ case NODE_MEMO: /* enum.c zip */
711
+ case NODE_CREF:
712
+ /* #defines: */
713
+ /* case NODE_LMASK: */
714
+ /* case NODE_LSHIFT: */
715
+
716
+ default:
717
+ rb_warn("Unhandled node '%s'", NODE2NAME[nd_type(node)]);
718
+ if (RNODE(node)->u1.node != NULL) rb_warning("unhandled u1 value");
719
+ if (RNODE(node)->u2.node != NULL) rb_warning("unhandled u2 value");
720
+ if (RNODE(node)->u3.node != NULL) rb_warning("unhandled u3 value");
721
+ if (RTEST(ruby_debug))
722
+ fprintf(stderr, "u1 = %p u2 = %p u3 = %p\n",
723
+ (void*)node->nd_1st, (void*)node->nd_2nd, (void*)node->nd_3rd);
724
+ break;
725
+ }
726
+ finish:
727
+ if (contnode) {
728
+ node = contnode;
729
+ contnode = 0;
730
+ goto again;
731
+ }
732
+ if (RTEST(ruby_debug)) {
733
+ char fmt[30] = { '\0', };
734
+ indent_level -= 2;
735
+ snprintf(fmt, sizeof(fmt), "%%%ds", indent_level+1);
736
+ fprintf(stderr, fmt, "]\n");
737
+ }
738
+
739
+ } /* ln_eval */
740
+ #endif /* RUBY_VERSION_1_8 */
741
+
742
+ /* Return a list of trace hook line numbers for the string in Ruby source src*/
743
+ static VALUE
744
+ lnums_for_str(VALUE self, VALUE src) {
745
+ VALUE result = rb_ary_new(); /* The returned array of line numbers. */
746
+ #ifdef RUBY_VERSION_1_8
747
+ NODE *node = NULL;
748
+ int critical;
749
+ #else
750
+ int len;
751
+ char *token;
752
+ char *disasm;
753
+ rb_thread_t *th;
754
+ VALUE iseqval;
755
+ VALUE disasm_val;
756
+ #endif
757
+
758
+ StringValue(src); /* Check that src is a string. */
759
+
760
+ if (RTEST(ruby_debug)) {
761
+ indent_level = 0;
762
+ }
763
+
764
+ #ifdef RUBY_VERSION_1_8
765
+ ruby_nerrs = 0;
766
+ critical = rb_thread_critical;
767
+ rb_thread_critical = Qtrue;
768
+
769
+ /* Making ruby_in_eval nonzero signals rb_compile_string not to save
770
+ source in SCRIPT_LINES__. */
771
+ ruby_in_eval++;
772
+ node = rb_compile_string("(numbers_for_str)", src, 1);
773
+ ruby_in_eval--;
774
+
775
+ rb_thread_critical = critical;
776
+
777
+ if (ruby_nerrs > 0) {
778
+ ruby_nerrs = 0;
779
+ ruby_eval_tree_begin = 0;
780
+ rb_exc_raise(ruby_errinfo);
781
+ }
782
+
783
+ ln_eval(self, node, result);
784
+
785
+ #else
786
+ th = GET_THREAD();
787
+
788
+ /* First compile to bytecode, using the method in eval_string_with_cref() in vm_eval.c */
789
+ th->parse_in_eval++;
790
+ th->mild_compile_error++;
791
+ iseqval = rb_iseq_compile(src, rb_str_new_cstr("(numbers_for_str)"), INT2FIX(1));
792
+ th->mild_compile_error--;
793
+ th->parse_in_eval--;
794
+
795
+ /* Disassemble the bytecode into text and parse into lines */
796
+ disasm_val = rb_iseq_disasm(iseqval);
797
+ if (disasm_val == Qnil)
798
+ return(result);
799
+
800
+ disasm = (char*)malloc(strlen(RSTRING_PTR(disasm_val))+1);
801
+ strcpy(disasm, RSTRING_PTR(disasm_val));
802
+
803
+ for (token = strtok(disasm, "\n"); token != NULL; token = strtok(NULL, "\n")) {
804
+
805
+ /* look only for lines tracing RUBY_EVENT_LINE (1) */
806
+ if (strstr(token, "trace 1 ") == NULL)
807
+ continue;
808
+ len = strlen(token) - 1;
809
+ if (token[len] != ')')
810
+ continue;
811
+ len--;
812
+ if ((token[len] == '(') || (token[len] == ' '))
813
+ continue;
814
+
815
+ for (; len > 0; len--) {
816
+ if (token[len] == ' ')
817
+ continue;
818
+ if ((token[len] >= '0') && (token[len] <= '9'))
819
+ continue;
820
+ if (token[len] == '(')
821
+ rb_ary_push(result, INT2NUM(atoi(token + len + 1))); /* trace found */
822
+
823
+ break;
824
+ }
825
+
826
+ }
827
+
828
+ free(disasm);
829
+
830
+ #endif
831
+
832
+ return result;
833
+ }
834
+
835
+ void Init_trace_nums19(void)
836
+ {
837
+ mTraceLineNumbers = rb_define_module("TraceLineNumbers");
838
+ rb_define_module_function(mTraceLineNumbers, "lnums_for_str",
839
+ lnums_for_str, 1);
840
+ }