linecache 0.41-mswin32
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/AUTHORS +1 -0
- data/COPYING +340 -0
- data/ChangeLog +330 -0
- data/NEWS +25 -0
- data/README +38 -0
- data/Rakefile +162 -0
- data/VERSION +1 -0
- data/ext/extconf.rb +16 -0
- data/ext/trace_nums.c +716 -0
- data/ext/trace_nums.h +111 -0
- data/lib/linecache.rb +399 -0
- data/lib/trace_nums.so +0 -0
- data/lib/tracelines.rb +42 -0
- data/test/data/begin1.rb +3 -0
- data/test/data/begin2.rb +3 -0
- data/test/data/begin3.rb +6 -0
- data/test/data/block1.rb +7 -0
- data/test/data/block2.rb +4 -0
- data/test/data/case1.rb +6 -0
- data/test/data/case2.rb +5 -0
- data/test/data/case3.rb +5 -0
- data/test/data/case4.rb +4 -0
- data/test/data/case5.rb +10 -0
- data/test/data/class1.rb +5 -0
- data/test/data/comments1.rb +6 -0
- data/test/data/def1.rb +9 -0
- data/test/data/each1.rb +3 -0
- data/test/data/end.rb +3 -0
- data/test/data/for1.rb +4 -0
- data/test/data/if1.rb +4 -0
- data/test/data/if2.rb +4 -0
- data/test/data/if3.rb +9 -0
- data/test/data/if4.rb +14 -0
- data/test/data/if5.rb +7 -0
- data/test/data/if6.rb +4 -0
- data/test/data/if7.rb +8 -0
- data/test/data/match.rb +3 -0
- data/test/data/match3.rb +5 -0
- data/test/data/match3a.rb +6 -0
- data/test/data/not-lit.rb +6 -0
- data/test/lnum-diag.rb +130 -0
- data/test/parse-show.rb +14 -0
- data/test/rcov-bug.rb +10 -0
- data/test/short-file +2 -0
- data/test/test-linecache.rb +151 -0
- data/test/test-lnum.rb +36 -0
- data/test/test-tracelines.rb +41 -0
- metadata +94 -0
data/NEWS
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
0.41
|
2
|
+
- add test/data/* to gem.
|
3
|
+
|
4
|
+
0.4
|
5
|
+
- Credit Ryan Davis and ParseTree.
|
6
|
+
|
7
|
+
0.3
|
8
|
+
- Add tracelines: get line numbers that can be stopped at.
|
9
|
+
|
10
|
+
- Add routines to allow line-number
|
11
|
+
remapping and filename remapping.
|
12
|
+
|
13
|
+
- Add access methods to get the number of lines in a file.
|
14
|
+
|
15
|
+
0.2
|
16
|
+
- Make this work with ruby-debug-base. Add reload-on-change parameters.
|
17
|
+
add checkcache, cache, cached? sha1, and stat methods.
|
18
|
+
|
19
|
+
- Use SCRIPT_LINES__.
|
20
|
+
|
21
|
+
0.1
|
22
|
+
|
23
|
+
- Initial release of LineCache, a module for reading and caching lines.
|
24
|
+
|
25
|
+
$Id: NEWS 119 2008-04-10 20:06:39Z rockyb $
|
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= LineCache - Module to read and cache lines of a file
|
2
|
+
|
3
|
+
== Summary
|
4
|
+
|
5
|
+
require 'linecache'
|
6
|
+
lines = LineCache::getlines('/tmp/myruby.rb')
|
7
|
+
# The following lines have same effect as the above.
|
8
|
+
$: << '/tmp'
|
9
|
+
Dir.chdir('/tmp') {lines = LineCache::getlines('myruby.rb')
|
10
|
+
|
11
|
+
line = LineCache::getline('/tmp/myruby.rb', 6)
|
12
|
+
# Note lines[6] == line (if /tmp/myruby.rb has 6 lines)
|
13
|
+
|
14
|
+
LineCache::clear_file_cache
|
15
|
+
LineCache::clear_file_cache('/tmp/myruby.rb')
|
16
|
+
LineCache::update_cache # Check for modifications of all cached files.
|
17
|
+
|
18
|
+
== Credits
|
19
|
+
|
20
|
+
This is a port of the module of the same name from the Python distribution.
|
21
|
+
|
22
|
+
The idea for how TraceLineNumbers works, and some code was taken
|
23
|
+
from ParseTree by Ryan Davis.
|
24
|
+
|
25
|
+
== Other stuff
|
26
|
+
|
27
|
+
Author:: Rocky Bernstein <rockyb@rubyforge.net>
|
28
|
+
License:: Copyright (c) 2007, 2008 Rocky Bernstein
|
29
|
+
Released under the GNU GPL 2 license
|
30
|
+
|
31
|
+
== Warranty
|
32
|
+
|
33
|
+
This program is distributed in the hope that it will be useful,
|
34
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
35
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
36
|
+
GNU General Public License for more details.
|
37
|
+
|
38
|
+
$Id: README 63 2008-03-04 22:47:26Z rockyb $
|
data/Rakefile
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# -*- Ruby -*-
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/testtask'
|
7
|
+
|
8
|
+
SO_NAME = "trace_nums.so"
|
9
|
+
|
10
|
+
# ------- Default Package ----------
|
11
|
+
PKG_VERSION = open(File.join(File.dirname(__FILE__), 'VERSION')) do
|
12
|
+
|f| f.readlines[0].chomp
|
13
|
+
end
|
14
|
+
PKG_NAME = 'linecache'
|
15
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
16
|
+
RUBY_FORGE_PROJECT = 'rocky-hacks'
|
17
|
+
RUBY_FORGE_USER = 'rockyb'
|
18
|
+
|
19
|
+
FILES = FileList[
|
20
|
+
'AUTHORS',
|
21
|
+
'COPYING',
|
22
|
+
'ChangeLog',
|
23
|
+
'NEWS',
|
24
|
+
'README',
|
25
|
+
'Rakefile',
|
26
|
+
'VERSION',
|
27
|
+
'ext/trace_nums.*',
|
28
|
+
'ext/extconf.rb',
|
29
|
+
'lib/*.rb',
|
30
|
+
'test/*.rb',
|
31
|
+
'test/data/*.rb',
|
32
|
+
'test/short-file'
|
33
|
+
]
|
34
|
+
|
35
|
+
desc "Test everything."
|
36
|
+
test_task = task :test => :lib do
|
37
|
+
Rake::TestTask.new(:test) do |t|
|
38
|
+
t.pattern = 'test/test-*.rb'
|
39
|
+
t.verbose = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Create the core ruby-debug shared library extension"
|
44
|
+
task :lib do
|
45
|
+
Dir.chdir("ext") do
|
46
|
+
system("#{Gem.ruby} extconf.rb && make")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
desc "Test everything - same as test."
|
52
|
+
task :check => :test
|
53
|
+
|
54
|
+
desc "Create a GNU-style ChangeLog via svn2cl"
|
55
|
+
task :ChangeLog do
|
56
|
+
system("svn2cl --authors=svn2cl_usermap")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Base GEM Specification
|
60
|
+
default_spec = Gem::Specification.new do |spec|
|
61
|
+
spec.name = "linecache"
|
62
|
+
|
63
|
+
spec.homepage = "http://rubyforge.org/projects/rocky-hacks/linecache"
|
64
|
+
spec.summary = "Read file with caching"
|
65
|
+
spec.description = <<-EOF
|
66
|
+
LineCache is a module for reading and caching lines. This may be useful for
|
67
|
+
example in a debugger where the same lines are shown many times.
|
68
|
+
EOF
|
69
|
+
|
70
|
+
spec.version = PKG_VERSION
|
71
|
+
|
72
|
+
spec.author = "R. Bernstein"
|
73
|
+
spec.email = "rockyb@rubyforge.net"
|
74
|
+
spec.platform = Gem::Platform::RUBY
|
75
|
+
spec.require_path = "lib"
|
76
|
+
spec.files = FILES.to_a
|
77
|
+
|
78
|
+
spec.required_ruby_version = '>= 1.8.2'
|
79
|
+
spec.date = Time.now
|
80
|
+
spec.rubyforge_project = 'rocky-hacks'
|
81
|
+
|
82
|
+
# rdoc
|
83
|
+
spec.has_rdoc = true
|
84
|
+
spec.extra_rdoc_files = ['README', 'lib/linecache.rb', 'lib/tracelines.rb']
|
85
|
+
end
|
86
|
+
|
87
|
+
# Rake task to build the default package
|
88
|
+
Rake::GemPackageTask.new(default_spec) do |pkg|
|
89
|
+
pkg.need_tar = true
|
90
|
+
end
|
91
|
+
|
92
|
+
task :default => [:test]
|
93
|
+
|
94
|
+
# Windows specification
|
95
|
+
win_spec = default_spec.clone
|
96
|
+
win_spec.extensions = []
|
97
|
+
## win_spec.platform = Gem::Platform::WIN32 # deprecated
|
98
|
+
win_spec.platform = 'mswin32'
|
99
|
+
win_spec.files += ["lib/#{SO_NAME}"]
|
100
|
+
|
101
|
+
desc "Create Windows Gem"
|
102
|
+
task :win32_gem do
|
103
|
+
# Copy the win32 extension the top level directory.
|
104
|
+
current_dir = File.expand_path(File.dirname(__FILE__))
|
105
|
+
source = File.join(current_dir, "ext", "win32", SO_NAME)
|
106
|
+
target = File.join(current_dir, "lib", SO_NAME)
|
107
|
+
cp(source, target)
|
108
|
+
|
109
|
+
# Create the gem, then move it to pkg.
|
110
|
+
Gem::Builder.new(win_spec).build
|
111
|
+
gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
|
112
|
+
mv(gem_file, "pkg/#{gem_file}")
|
113
|
+
|
114
|
+
# Remove win extension from top level directory.
|
115
|
+
rm(target)
|
116
|
+
end
|
117
|
+
|
118
|
+
desc "Publish linecache to RubyForge."
|
119
|
+
task :publish do
|
120
|
+
require 'rake/contrib/sshpublisher'
|
121
|
+
|
122
|
+
# Get ruby-debug path.
|
123
|
+
ruby_debug_path = File.expand_path(File.dirname(__FILE__))
|
124
|
+
|
125
|
+
publisher = Rake::SshDirPublisher.new("rockyb@rubyforge.org",
|
126
|
+
"/var/www/gforge-projects/rocky-hacks/linecache", ruby_debug_path)
|
127
|
+
end
|
128
|
+
|
129
|
+
desc "Remove built files"
|
130
|
+
task :clean => [:clobber_package, :clobber_rdoc] do
|
131
|
+
cd "ext" do
|
132
|
+
if File.exists?("Makefile")
|
133
|
+
sh "make clean"
|
134
|
+
rm "Makefile"
|
135
|
+
end
|
136
|
+
derived_files = Dir.glob(".o") + Dir.glob("*.so")
|
137
|
+
rm derived_files unless derived_files.empty?
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# --------- RDoc Documentation ------
|
142
|
+
desc "Generate rdoc documentation"
|
143
|
+
Rake::RDocTask.new("rdoc") do |rdoc|
|
144
|
+
rdoc.rdoc_dir = 'doc'
|
145
|
+
rdoc.title = "linecache"
|
146
|
+
# Show source inline with line numbers
|
147
|
+
rdoc.options << "--inline-source" << "--line-numbers"
|
148
|
+
# Make the readme file the start page for the generated html
|
149
|
+
rdoc.options << '--main' << 'README'
|
150
|
+
rdoc.rdoc_files.include('ext/**/*.c',
|
151
|
+
'lib/*.rb',
|
152
|
+
'README',
|
153
|
+
'COPYING')
|
154
|
+
end
|
155
|
+
|
156
|
+
desc "Publish the release files to RubyForge."
|
157
|
+
task :rubyforge_upload do
|
158
|
+
`rubyforge login`
|
159
|
+
release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
|
160
|
+
puts release_command
|
161
|
+
system(release_command)
|
162
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.41
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
|
3
|
+
if RUBY_VERSION >= "1.9"
|
4
|
+
STDERR.print("Can't handle 1.9.x yet\n")
|
5
|
+
exit(1)
|
6
|
+
elsif RUBY_VERSION >= "1.8"
|
7
|
+
if RUBY_RELEASE_DATE < "2005-03-22"
|
8
|
+
STDERR.print("Ruby version is too old\n")
|
9
|
+
exit(1)
|
10
|
+
end
|
11
|
+
else
|
12
|
+
STDERR.print("Ruby version is too old\n")
|
13
|
+
exit(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
create_makefile("trace_nums")
|
data/ext/trace_nums.c
ADDED
@@ -0,0 +1,716 @@
|
|
1
|
+
/*
|
2
|
+
This code creates module TraceLineNumbers with one method
|
3
|
+
lnums_for_str. lnums_for_str returns an array lines for which
|
4
|
+
RUBY_EVENT_LINE can be called on. In other words, the line numbers
|
5
|
+
that can be traced (such as via Tracer) or stopped at in a
|
6
|
+
debugger (such as ruby-debug).
|
7
|
+
|
8
|
+
This code has been tested on Ruby 1.8.6; it does not work on Ruby
|
9
|
+
1.9.x. The code was created via culling from various sources.
|
10
|
+
|
11
|
+
Ruby 1.8's eval.c, and rb_eval() in particular, is the definitive
|
12
|
+
source of how the tree is evaluated. However we don't want to
|
13
|
+
actually evaluate the code, which simplifies things. In contrast,
|
14
|
+
we need lines for all branches, and not just the ones that get
|
15
|
+
executed on a given run. For example in an "if" node the "then"
|
16
|
+
part may or may not get executed, but we want to get the trace line
|
17
|
+
numbers for the "then" part regardless.
|
18
|
+
|
19
|
+
Code enclosed in the ***'s contains code from eval.c which is
|
20
|
+
included for comparison.
|
21
|
+
|
22
|
+
Also parse.y from Ruby 1.8 can shed light on how the nodes get
|
23
|
+
created.
|
24
|
+
|
25
|
+
Some legacy code in ParseTree is similar and necessarily more
|
26
|
+
complex. We would have used that gem from the outside and lived
|
27
|
+
with the additional bloat were it not broken for our purposes and
|
28
|
+
were it not for the author's lack of interest in extending it to
|
29
|
+
handle what's needed here.
|
30
|
+
|
31
|
+
Finally, node_help.txt from nodewrap contains descriptions of many
|
32
|
+
of the node types.
|
33
|
+
*/
|
34
|
+
#include <ruby.h>
|
35
|
+
#include <version.h>
|
36
|
+
#include <node.h>
|
37
|
+
#include <env.h>
|
38
|
+
#include <rubysig.h>
|
39
|
+
#include "trace_nums.h"
|
40
|
+
|
41
|
+
VALUE mTraceLineNumbers;
|
42
|
+
extern NODE *ruby_eval_tree_begin;
|
43
|
+
|
44
|
+
#define nd_3rd u3.node
|
45
|
+
|
46
|
+
struct METHOD {
|
47
|
+
VALUE klass, rklass;
|
48
|
+
VALUE recv;
|
49
|
+
ID id, oid;
|
50
|
+
#if RUBY_VERSION_CODE > 182
|
51
|
+
int safe_level;
|
52
|
+
#endif
|
53
|
+
NODE *body;
|
54
|
+
};
|
55
|
+
|
56
|
+
struct BLOCK {
|
57
|
+
NODE *var;
|
58
|
+
NODE *body;
|
59
|
+
VALUE self;
|
60
|
+
struct FRAME frame;
|
61
|
+
struct SCOPE *scope;
|
62
|
+
VALUE klass;
|
63
|
+
NODE *cref;
|
64
|
+
int iter;
|
65
|
+
int vmode;
|
66
|
+
int flags;
|
67
|
+
int uniq;
|
68
|
+
struct RVarmap *dyna_vars;
|
69
|
+
VALUE orig_thread;
|
70
|
+
VALUE wrapper;
|
71
|
+
VALUE block_obj;
|
72
|
+
struct BLOCK *outer;
|
73
|
+
struct BLOCK *prev;
|
74
|
+
};
|
75
|
+
|
76
|
+
#define RETURN \
|
77
|
+
goto finish
|
78
|
+
|
79
|
+
#define EVENT_LINE(node) \
|
80
|
+
rb_ary_push(ary, INT2NUM(nd_line(node)))
|
81
|
+
|
82
|
+
#ifdef FINISHED
|
83
|
+
#define EVENT_CALL(node) \
|
84
|
+
rb_ary_push(ary, INT2NUM(nd_line(node)))
|
85
|
+
#else
|
86
|
+
#define EVENT_CALL(node)
|
87
|
+
#endif
|
88
|
+
|
89
|
+
/* Used just in debugging. */
|
90
|
+
static indent_level = 0;
|
91
|
+
|
92
|
+
static
|
93
|
+
void ln_eval(VALUE self, NODE * n, VALUE ary) {
|
94
|
+
NODE * volatile contnode = 0;
|
95
|
+
NODE * volatile node = n;
|
96
|
+
|
97
|
+
if (RTEST(ruby_debug)) {
|
98
|
+
char fmt[30] = { '\0', };
|
99
|
+
snprintf(fmt, sizeof(fmt), "%%%ds", indent_level+1);
|
100
|
+
fprintf(stderr, fmt, "[");
|
101
|
+
indent_level += 2;
|
102
|
+
}
|
103
|
+
|
104
|
+
again:
|
105
|
+
if (!node) RETURN;
|
106
|
+
|
107
|
+
if (RTEST(ruby_debug)) {
|
108
|
+
NODE *r = RNODE(node); /* For debugging */
|
109
|
+
fprintf(stderr, "%s ", NODE2NAME[nd_type(node)]);
|
110
|
+
}
|
111
|
+
|
112
|
+
switch (nd_type(node)) {
|
113
|
+
case NODE_BLOCK:
|
114
|
+
while (node) {
|
115
|
+
ln_eval(self, node->nd_head, ary);
|
116
|
+
node = node->nd_next;
|
117
|
+
}
|
118
|
+
|
119
|
+
case NODE_POSTEXE: /* END { ... } */
|
120
|
+
/* Nothing to do here... we are in an iter block */
|
121
|
+
/***
|
122
|
+
rb_f_END();
|
123
|
+
nd_set_type(node, NODE_NIL); /+ exec just once +/
|
124
|
+
result = Qnil;
|
125
|
+
***/
|
126
|
+
break;
|
127
|
+
|
128
|
+
/* begin .. end without clauses */
|
129
|
+
case NODE_BEGIN:
|
130
|
+
/* node for speed-up(top-level loop for -n/-p) */
|
131
|
+
node = node->nd_body;
|
132
|
+
goto again;
|
133
|
+
|
134
|
+
/* nodes for speed-up(default match) */
|
135
|
+
case NODE_MATCH:
|
136
|
+
/* result = rb_reg_match2(node->nd_lit); */
|
137
|
+
break;
|
138
|
+
|
139
|
+
/* nodes for speed-up(literal match) */
|
140
|
+
case NODE_MATCH2:
|
141
|
+
/* l = */ ln_eval(self, node->nd_recv, ary);
|
142
|
+
/* r = */ ln_eval(self, node->nd_value, ary);
|
143
|
+
/*** result = rb_reg_match(l, r); ***/
|
144
|
+
break;
|
145
|
+
|
146
|
+
/* nodes for speed-up(literal match) */
|
147
|
+
case NODE_MATCH3: /* z =~ /"#{var}"/ for example */
|
148
|
+
/* r = */ ln_eval(self, node->nd_recv, ary);
|
149
|
+
/* l = */ ln_eval(self, node->nd_value, ary);
|
150
|
+
/***
|
151
|
+
if (TYPE(l) == T_STRING) {
|
152
|
+
result = rb_reg_match(r, l);
|
153
|
+
}
|
154
|
+
else {
|
155
|
+
// It is possible that value can be a function call which
|
156
|
+
// can trigger an call event. So to be conservative,
|
157
|
+
// we have to add a line number here.
|
158
|
+
result = rb_funcall(l, match, 1, r);
|
159
|
+
}
|
160
|
+
****/
|
161
|
+
EVENT_CALL(node);
|
162
|
+
break;
|
163
|
+
|
164
|
+
/* node for speed-up(top-level loop for -n/-p) */
|
165
|
+
case NODE_OPT_N:
|
166
|
+
/* Lots of ugliness in eval.c. */
|
167
|
+
ln_eval(self, node->nd_body, ary);
|
168
|
+
break;
|
169
|
+
|
170
|
+
/* These nodes are empty. */
|
171
|
+
case NODE_SELF:
|
172
|
+
case NODE_NIL:
|
173
|
+
case NODE_TRUE:
|
174
|
+
case NODE_FALSE:
|
175
|
+
RETURN /* (something) */;
|
176
|
+
|
177
|
+
case NODE_IF:
|
178
|
+
EVENT_LINE(node);
|
179
|
+
ln_eval(self, node->nd_cond, ary);
|
180
|
+
if (node->nd_body) {
|
181
|
+
if (!node->nd_else) {
|
182
|
+
node = node->nd_body;
|
183
|
+
goto again;
|
184
|
+
}
|
185
|
+
ln_eval(self, node->nd_body, ary);
|
186
|
+
}
|
187
|
+
if (node->nd_else) {
|
188
|
+
node = node->nd_else;
|
189
|
+
goto again;
|
190
|
+
}
|
191
|
+
break;
|
192
|
+
|
193
|
+
case NODE_WHEN:
|
194
|
+
{
|
195
|
+
NODE *orig_node = node;
|
196
|
+
while (node) {
|
197
|
+
NODE *tag;
|
198
|
+
|
199
|
+
if (nd_type(node) != NODE_WHEN) goto again;
|
200
|
+
tag = node->nd_head;
|
201
|
+
while (tag) {
|
202
|
+
EVENT_LINE(tag);
|
203
|
+
if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
|
204
|
+
ln_eval(self, tag->nd_head->nd_head, ary);
|
205
|
+
}
|
206
|
+
tag = tag->nd_next;
|
207
|
+
}
|
208
|
+
node = node->nd_next;
|
209
|
+
}
|
210
|
+
if (orig_node->nd_body) {
|
211
|
+
ln_eval(self, orig_node->nd_body, ary); /* body */
|
212
|
+
}
|
213
|
+
RETURN /***(Qnil)***/ ;
|
214
|
+
}
|
215
|
+
|
216
|
+
case NODE_CASE:
|
217
|
+
ln_eval(self, node->nd_head, ary); /* expr */
|
218
|
+
node = node->nd_body;
|
219
|
+
while (node) {
|
220
|
+
NODE *tag;
|
221
|
+
if (nd_type(node) != NODE_WHEN) {
|
222
|
+
goto again;
|
223
|
+
}
|
224
|
+
tag = node->nd_head;
|
225
|
+
while (tag) {
|
226
|
+
EVENT_LINE(tag);
|
227
|
+
if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) {
|
228
|
+
ln_eval(self, tag->nd_head->nd_head, ary);
|
229
|
+
tag = tag->nd_next;
|
230
|
+
continue;
|
231
|
+
}
|
232
|
+
ln_eval(self, tag->nd_head, ary);
|
233
|
+
tag = tag->nd_next;
|
234
|
+
}
|
235
|
+
ln_eval(self, node->nd_body, ary);
|
236
|
+
node = node->nd_next;
|
237
|
+
}
|
238
|
+
RETURN /***(Qnil)***/;
|
239
|
+
|
240
|
+
case NODE_WHILE:
|
241
|
+
case NODE_UNTIL:
|
242
|
+
/* Doesn't follow eval.c */
|
243
|
+
ln_eval(self, node->nd_cond, ary);
|
244
|
+
if (node->nd_body) {
|
245
|
+
ln_eval(self, node->nd_body, ary);
|
246
|
+
}
|
247
|
+
break;
|
248
|
+
|
249
|
+
case NODE_BLOCK_PASS:
|
250
|
+
/*** result = block_pass(self, node); ***/
|
251
|
+
ln_eval(self, node->nd_body, ary);
|
252
|
+
ln_eval(self, node->nd_iter, ary);
|
253
|
+
break;
|
254
|
+
|
255
|
+
case NODE_ITER:
|
256
|
+
case NODE_FOR:
|
257
|
+
ln_eval(self, node->nd_iter, ary);
|
258
|
+
if (node->nd_var != (NODE *)1
|
259
|
+
&& node->nd_var != (NODE *)2
|
260
|
+
&& node->nd_var != NULL) {
|
261
|
+
ln_eval(self, node->nd_var, ary);
|
262
|
+
}
|
263
|
+
node = node->nd_body;
|
264
|
+
goto again;
|
265
|
+
|
266
|
+
case NODE_BREAK:
|
267
|
+
/* break_jump(rb_eval(self, node->nd_stts)); */
|
268
|
+
ln_eval(self, node->nd_stts, ary);
|
269
|
+
break;
|
270
|
+
|
271
|
+
case NODE_NEXT:
|
272
|
+
/*** CHECK_INTS;
|
273
|
+
next_jump(rb_eval(self, node->nd_stts)); ***/
|
274
|
+
ln_eval(self, node->nd_stts, ary);
|
275
|
+
break;
|
276
|
+
|
277
|
+
case NODE_REDO:
|
278
|
+
/*** CHECK_INTS;
|
279
|
+
JUMP_TAG(TAG_REDO); ***/
|
280
|
+
break;
|
281
|
+
|
282
|
+
case NODE_RETRY:
|
283
|
+
/*** CHECK_INTS;
|
284
|
+
JUMP_TAG(TAG_RETRY); ***/
|
285
|
+
break;
|
286
|
+
|
287
|
+
case NODE_SPLAT:
|
288
|
+
/*** result = splat_value(rb_eval(self, node->nd_head)); ***/
|
289
|
+
ln_eval(self, node->nd_head, ary);
|
290
|
+
break;
|
291
|
+
|
292
|
+
case NODE_TO_ARY:
|
293
|
+
/*** result = rb_ary_to_ary(rb_eval(self, node->nd_head)); ***/
|
294
|
+
ln_eval(self, node->nd_head, ary);
|
295
|
+
break;
|
296
|
+
|
297
|
+
case NODE_SVALUE: /* a = b, c */
|
298
|
+
/***
|
299
|
+
result = avalue_splat(rb_eval(self, node->nd_head));
|
300
|
+
if (result == Qundef) result = Qnil; ***/
|
301
|
+
ln_eval(self, node->nd_head, ary);
|
302
|
+
break;
|
303
|
+
|
304
|
+
case NODE_YIELD:
|
305
|
+
if (node->nd_head) {
|
306
|
+
/*** result = rb_eval(self, node->nd_head);
|
307
|
+
ruby_current_node = node; else ... ***/
|
308
|
+
ln_eval(self, node->nd_head, ary);
|
309
|
+
}
|
310
|
+
break;
|
311
|
+
|
312
|
+
case NODE_RESCUE:
|
313
|
+
/* Follow ruby_parse.rb and pray for the best. */
|
314
|
+
ln_eval(self, node->nd_1st, ary);
|
315
|
+
ln_eval(self, node->nd_2nd, ary);
|
316
|
+
ln_eval(self, node->nd_3rd, ary);
|
317
|
+
break;
|
318
|
+
|
319
|
+
case NODE_ENSURE:
|
320
|
+
ln_eval(self, node->nd_head, ary);
|
321
|
+
if (node->nd_ensr) {
|
322
|
+
ln_eval(self, node->nd_ensr, ary);
|
323
|
+
}
|
324
|
+
break;
|
325
|
+
|
326
|
+
case NODE_AND:
|
327
|
+
case NODE_OR:
|
328
|
+
ln_eval(self, node->nd_1st, ary);
|
329
|
+
ln_eval(self, node->nd_2nd, ary);
|
330
|
+
break;
|
331
|
+
|
332
|
+
case NODE_NOT:
|
333
|
+
/*** if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse;
|
334
|
+
else result = Qtrue; ***/
|
335
|
+
ln_eval(self, node->nd_body, ary);
|
336
|
+
break;
|
337
|
+
|
338
|
+
case NODE_DOT2:
|
339
|
+
case NODE_DOT3:
|
340
|
+
case NODE_FLIP2:
|
341
|
+
case NODE_FLIP3:
|
342
|
+
ln_eval(self, node->nd_beg, ary);
|
343
|
+
ln_eval(self, node->nd_end, ary);
|
344
|
+
break;
|
345
|
+
|
346
|
+
case NODE_RETURN:
|
347
|
+
if (node->nd_stts)
|
348
|
+
ln_eval(self, node->nd_stts, ary);
|
349
|
+
break;
|
350
|
+
|
351
|
+
case NODE_ARGSCAT:
|
352
|
+
case NODE_ARGSPUSH:
|
353
|
+
ln_eval(self, node->nd_head, ary);
|
354
|
+
ln_eval(self, node->nd_body, ary);
|
355
|
+
break;
|
356
|
+
|
357
|
+
case NODE_ATTRASGN: /* literal.meth = y u1 u2 u3 */
|
358
|
+
/* node id node */
|
359
|
+
if (node->nd_recv == (NODE *)1) {
|
360
|
+
ln_eval(self, NEW_SELF(), ary);
|
361
|
+
} else {
|
362
|
+
ln_eval(self, node->nd_recv, ary);
|
363
|
+
}
|
364
|
+
ln_eval(self, node->nd_3rd, ary);
|
365
|
+
break;
|
366
|
+
case NODE_CALL:
|
367
|
+
case NODE_FCALL:
|
368
|
+
case NODE_VCALL:
|
369
|
+
if (nd_type(node) != NODE_FCALL)
|
370
|
+
ln_eval(self, node->nd_recv, ary);
|
371
|
+
if (node->nd_args || nd_type(node) != NODE_FCALL)
|
372
|
+
ln_eval(self, node->nd_args, ary);
|
373
|
+
break;
|
374
|
+
|
375
|
+
case NODE_SUPER:
|
376
|
+
ln_eval(self, node->nd_args, ary);
|
377
|
+
break;
|
378
|
+
|
379
|
+
case NODE_ZSUPER:
|
380
|
+
break;
|
381
|
+
|
382
|
+
case NODE_SCOPE:
|
383
|
+
ln_eval(self, node->nd_next, ary);
|
384
|
+
break;
|
385
|
+
|
386
|
+
case NODE_OP_ASGN1:
|
387
|
+
ln_eval(self, node->nd_recv, ary);
|
388
|
+
#if RUBY_VERSION_CODE < 185
|
389
|
+
ln_eval(self, node->nd_args->nd_next, ary);
|
390
|
+
#else
|
391
|
+
ln_eval(self, node->nd_args->nd_2nd, ary);
|
392
|
+
#endif
|
393
|
+
ln_eval(self, node->nd_args->nd_head, ary);
|
394
|
+
break;
|
395
|
+
|
396
|
+
case NODE_OP_ASGN2:
|
397
|
+
ln_eval(self, node->nd_recv, ary);
|
398
|
+
ln_eval(self, node->nd_value, ary);
|
399
|
+
break;
|
400
|
+
|
401
|
+
case NODE_OP_ASGN_AND:
|
402
|
+
case NODE_OP_ASGN_OR:
|
403
|
+
ln_eval(self, node->nd_head, ary);
|
404
|
+
ln_eval(self, node->nd_value, ary);
|
405
|
+
break;
|
406
|
+
|
407
|
+
case NODE_MASGN:
|
408
|
+
ln_eval(self, node->nd_head, ary);
|
409
|
+
if (node->nd_args) {
|
410
|
+
if (node->nd_args != (NODE *)-1) {
|
411
|
+
ln_eval(self, node->nd_args, ary);
|
412
|
+
}
|
413
|
+
}
|
414
|
+
ln_eval(self, node->nd_value, ary);
|
415
|
+
break;
|
416
|
+
|
417
|
+
case NODE_LASGN:
|
418
|
+
case NODE_DASGN:
|
419
|
+
case NODE_DASGN_CURR:
|
420
|
+
case NODE_GASGN:
|
421
|
+
case NODE_IASGN:
|
422
|
+
case NODE_CDECL:
|
423
|
+
case NODE_CVDECL:
|
424
|
+
case NODE_CVASGN:
|
425
|
+
ln_eval(self, node->nd_value, ary);
|
426
|
+
break;
|
427
|
+
|
428
|
+
case NODE_LVAR:
|
429
|
+
case NODE_DVAR:
|
430
|
+
case NODE_GVAR:
|
431
|
+
case NODE_IVAR:
|
432
|
+
case NODE_CONST:
|
433
|
+
case NODE_CVAR:
|
434
|
+
break;
|
435
|
+
|
436
|
+
case NODE_BLOCK_ARG: /* u1 u3 (def x(&b) */
|
437
|
+
break;
|
438
|
+
|
439
|
+
case NODE_COLON2:
|
440
|
+
ln_eval(self, node->nd_head, ary);
|
441
|
+
break;
|
442
|
+
|
443
|
+
case NODE_COLON3: /* u2 (::OUTER_CONST) */
|
444
|
+
break;
|
445
|
+
|
446
|
+
case NODE_NTH_REF: /* u2 u3 ($1) - u3 is local_cnt('~') ignorable? */
|
447
|
+
break;
|
448
|
+
|
449
|
+
case NODE_BACK_REF: /* u2 u3 ($& etc) */
|
450
|
+
break;
|
451
|
+
|
452
|
+
case NODE_HASH:
|
453
|
+
{
|
454
|
+
NODE *list;
|
455
|
+
list = node->nd_head;
|
456
|
+
while (list) {
|
457
|
+
ln_eval(self, list->nd_head, ary);
|
458
|
+
list = list->nd_next;
|
459
|
+
if (list == 0)
|
460
|
+
rb_bug("odd number list for Hash");
|
461
|
+
ln_eval(self, list->nd_head, ary);
|
462
|
+
list = list->nd_next;
|
463
|
+
}
|
464
|
+
}
|
465
|
+
break;
|
466
|
+
|
467
|
+
case NODE_ZARRAY:
|
468
|
+
break;
|
469
|
+
|
470
|
+
case NODE_ARRAY:
|
471
|
+
{
|
472
|
+
long int i = node->nd_alen;
|
473
|
+
for (i=0; node; node=node->nd_next) {
|
474
|
+
ln_eval(self, node->nd_head, ary);
|
475
|
+
}
|
476
|
+
}
|
477
|
+
break;
|
478
|
+
|
479
|
+
case NODE_STR: /* u1 */
|
480
|
+
break;
|
481
|
+
|
482
|
+
case NODE_EVSTR: /* eval of a string */
|
483
|
+
ln_eval(self, node->nd_2nd, ary);
|
484
|
+
break;
|
485
|
+
|
486
|
+
case NODE_DSTR:
|
487
|
+
case NODE_DXSTR:
|
488
|
+
case NODE_DREGX:
|
489
|
+
case NODE_DREGX_ONCE:
|
490
|
+
case NODE_DSYM:
|
491
|
+
{
|
492
|
+
NODE *list = node->nd_next;
|
493
|
+
while (list) {
|
494
|
+
if (list->nd_head) {
|
495
|
+
switch (nd_type(list->nd_head)) {
|
496
|
+
case NODE_STR:
|
497
|
+
ln_eval(self, list->nd_head, ary);
|
498
|
+
break;
|
499
|
+
case NODE_EVSTR:
|
500
|
+
ln_eval(self, list->nd_head, ary);
|
501
|
+
break;
|
502
|
+
default:
|
503
|
+
ln_eval(self, list->nd_head, ary);
|
504
|
+
break;
|
505
|
+
}
|
506
|
+
}
|
507
|
+
list = list->nd_next;
|
508
|
+
}
|
509
|
+
}
|
510
|
+
break;
|
511
|
+
|
512
|
+
case NODE_XSTR: /* u1 (%x{ls}) */
|
513
|
+
/* Issues rb_funcall(self, '`'...). So I think we have to
|
514
|
+
register a call event. */
|
515
|
+
EVENT_CALL(node);
|
516
|
+
break;
|
517
|
+
|
518
|
+
case NODE_LIT:
|
519
|
+
break;
|
520
|
+
|
521
|
+
case NODE_DEFN:
|
522
|
+
ln_eval(self, node->nd_defn, ary);
|
523
|
+
break;
|
524
|
+
|
525
|
+
case NODE_DEFS:
|
526
|
+
if (node->nd_defn) {
|
527
|
+
ln_eval(self, node->nd_recv, ary);
|
528
|
+
}
|
529
|
+
ln_eval(self, node->nd_defn, ary);
|
530
|
+
break;
|
531
|
+
|
532
|
+
case NODE_UNDEF: /* u2 (undef name, ...) */
|
533
|
+
#if RUBY_VERSION_CODE >= 185
|
534
|
+
/*** ...
|
535
|
+
rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node)));
|
536
|
+
...
|
537
|
+
***/
|
538
|
+
ln_eval(self, node->u2.node, ary);
|
539
|
+
#endif
|
540
|
+
break;
|
541
|
+
|
542
|
+
case NODE_ALIAS: /* u1 u2 (alias :blah :blah2) */
|
543
|
+
#if RUBY_VERSION_CODE >= 185
|
544
|
+
ln_eval(self, node->nd_1st, ary);
|
545
|
+
ln_eval(self, node->nd_2nd, ary);
|
546
|
+
#endif
|
547
|
+
break;
|
548
|
+
case NODE_VALIAS: /* u1 u2 (alias $global $global2) */
|
549
|
+
break;
|
550
|
+
|
551
|
+
case NODE_CLASS:
|
552
|
+
if (node->nd_super) {
|
553
|
+
ln_eval(self, node->nd_super, ary);
|
554
|
+
}
|
555
|
+
ln_eval(self, node->nd_body, ary);
|
556
|
+
break;
|
557
|
+
|
558
|
+
case NODE_MODULE:
|
559
|
+
ln_eval(self, node->nd_body, ary);
|
560
|
+
break;
|
561
|
+
|
562
|
+
case NODE_SCLASS:
|
563
|
+
ln_eval(self, node->nd_recv, ary);
|
564
|
+
ln_eval(self, node->nd_body, ary);
|
565
|
+
break;
|
566
|
+
|
567
|
+
case NODE_DEFINED:
|
568
|
+
ln_eval(self, node->nd_head, ary);
|
569
|
+
break;
|
570
|
+
|
571
|
+
case NODE_NEWLINE:
|
572
|
+
EVENT_LINE(node);
|
573
|
+
node = node->nd_next;
|
574
|
+
goto again;
|
575
|
+
|
576
|
+
case NODE_CFUNC:
|
577
|
+
case NODE_IFUNC:
|
578
|
+
break;
|
579
|
+
|
580
|
+
#if RUBY_VERSION_CODE >= 190
|
581
|
+
case NODE_ERRINFO:
|
582
|
+
case NODE_VALUES:
|
583
|
+
case NODE_PRELUDE:
|
584
|
+
case NODE_LAMBDA:
|
585
|
+
rb_warn("Ruby 1.9 is very different. You shouldn't have gotten here.");
|
586
|
+
break;
|
587
|
+
#endif
|
588
|
+
|
589
|
+
case NODE_BMETHOD: /* define_method (or rb_mod_define_method) with a block */
|
590
|
+
{
|
591
|
+
struct BLOCK *data;
|
592
|
+
Data_Get_Struct(node->nd_cval, struct BLOCK, data);
|
593
|
+
if (!(data->var == 0 || data->var == (NODE *)1 ||
|
594
|
+
data->var == (NODE *)2)) {
|
595
|
+
/* block doesn't have args. */
|
596
|
+
ln_eval(self, data->var, ary);
|
597
|
+
}
|
598
|
+
ln_eval(self, data->body, ary);
|
599
|
+
break;
|
600
|
+
}
|
601
|
+
break;
|
602
|
+
|
603
|
+
#if RUBY_VERSION_CODE < 190
|
604
|
+
case NODE_DMETHOD:
|
605
|
+
{
|
606
|
+
struct METHOD *data;
|
607
|
+
Data_Get_Struct(node->nd_cval, struct METHOD, data);
|
608
|
+
ln_eval(self, data->body, ary);
|
609
|
+
break;
|
610
|
+
}
|
611
|
+
#endif
|
612
|
+
|
613
|
+
case NODE_METHOD:
|
614
|
+
ln_eval(self, node->nd_3rd, ary);
|
615
|
+
break;
|
616
|
+
|
617
|
+
|
618
|
+
case NODE_ARGS: {
|
619
|
+
if (node->nd_opt) {
|
620
|
+
ln_eval(self, node->nd_opt, ary);
|
621
|
+
}
|
622
|
+
} break;
|
623
|
+
|
624
|
+
case NODE_ATTRSET:
|
625
|
+
break;
|
626
|
+
|
627
|
+
/*
|
628
|
+
// rescue body:
|
629
|
+
// begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
|
630
|
+
// stmt rescue stmt
|
631
|
+
// a = b rescue c
|
632
|
+
// NODE_RESBODY doesn't appear in 1.8.6's rb_eval
|
633
|
+
*/
|
634
|
+
case NODE_RESBODY:
|
635
|
+
if (node->nd_3rd) {
|
636
|
+
ln_eval(self, node->nd_3rd, ary);
|
637
|
+
}
|
638
|
+
ln_eval(self, node->nd_2nd, ary);
|
639
|
+
ln_eval(self, node->nd_1st, ary);
|
640
|
+
break;
|
641
|
+
|
642
|
+
/* Nodes we found but have yet to decypher */
|
643
|
+
/* I think these are all runtime only... not positive but... */
|
644
|
+
case NODE_MEMO: /* enum.c zip */
|
645
|
+
case NODE_CREF:
|
646
|
+
/* #defines: */
|
647
|
+
/* case NODE_LMASK: */
|
648
|
+
/* case NODE_LSHIFT: */
|
649
|
+
|
650
|
+
default:
|
651
|
+
rb_warn("Unhandled node '%s'", NODE2NAME[nd_type(node)]);
|
652
|
+
if (RNODE(node)->u1.node != NULL) rb_warning("unhandled u1 value");
|
653
|
+
if (RNODE(node)->u2.node != NULL) rb_warning("unhandled u2 value");
|
654
|
+
if (RNODE(node)->u3.node != NULL) rb_warning("unhandled u3 value");
|
655
|
+
if (RTEST(ruby_debug))
|
656
|
+
fprintf(stderr, "u1 = %p u2 = %p u3 = %p\n",
|
657
|
+
(void*)node->nd_1st, (void*)node->nd_2nd, (void*)node->nd_3rd);
|
658
|
+
break;
|
659
|
+
}
|
660
|
+
finish:
|
661
|
+
if (contnode) {
|
662
|
+
node = contnode;
|
663
|
+
contnode = 0;
|
664
|
+
goto again;
|
665
|
+
}
|
666
|
+
if (RTEST(ruby_debug)) {
|
667
|
+
char fmt[30] = { '\0', };
|
668
|
+
indent_level -= 2;
|
669
|
+
snprintf(fmt, sizeof(fmt), "%%%ds", indent_level+1);
|
670
|
+
fprintf(stderr, fmt, "]\n");
|
671
|
+
}
|
672
|
+
|
673
|
+
} /* ln_eval */
|
674
|
+
|
675
|
+
/* Return a list of trace hook line numbers for the string in Ruby source src*/
|
676
|
+
static VALUE
|
677
|
+
lnums_for_str(VALUE self, VALUE src) {
|
678
|
+
VALUE result = rb_ary_new(); /* The returned array of line numbers. */
|
679
|
+
NODE *node = NULL;
|
680
|
+
int critical;
|
681
|
+
|
682
|
+
ruby_nerrs = 0;
|
683
|
+
StringValue(src); /* Check that src is a string. */
|
684
|
+
|
685
|
+
critical = rb_thread_critical;
|
686
|
+
rb_thread_critical = Qtrue;
|
687
|
+
|
688
|
+
/* Making ruby_in_eval nonzero signals rb_compile_string not to save
|
689
|
+
source in SCRIPT_LINES__. */
|
690
|
+
ruby_in_eval++;
|
691
|
+
node = rb_compile_string("(numbers_for_str)", src, 1);
|
692
|
+
ruby_in_eval--;
|
693
|
+
|
694
|
+
rb_thread_critical = critical;
|
695
|
+
|
696
|
+
if (ruby_nerrs > 0) {
|
697
|
+
ruby_nerrs = 0;
|
698
|
+
#if RUBY_VERSION_CODE < 190
|
699
|
+
ruby_eval_tree_begin = 0;
|
700
|
+
#endif
|
701
|
+
rb_exc_raise(ruby_errinfo);
|
702
|
+
}
|
703
|
+
|
704
|
+
if (RTEST(ruby_debug)) {
|
705
|
+
indent_level = 0;
|
706
|
+
}
|
707
|
+
ln_eval(self, node, result);
|
708
|
+
return result;
|
709
|
+
}
|
710
|
+
|
711
|
+
void Init_trace_nums(void)
|
712
|
+
{
|
713
|
+
mTraceLineNumbers = rb_define_module("TraceLineNumbers");
|
714
|
+
rb_define_module_function(mTraceLineNumbers, "lnums_for_str",
|
715
|
+
lnums_for_str, 1);
|
716
|
+
}
|