trepanning 0.1.0 → 0.1.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/.gitignore +4 -0
- data/ChangeLog +1279 -235
- data/Makefile +13 -0
- data/NEWS +30 -0
- data/Rakefile +50 -14
- data/app/.gitignore +1 -0
- data/app/breakpoint.rb +7 -2
- data/app/brkptmgr.rb +12 -0
- data/app/cmd_parse.citrus +167 -0
- data/app/cmd_parse.kpeg +221 -0
- data/app/cmd_parse.rb +201 -0
- data/app/cmd_parser.rb +1914 -0
- data/app/complete.rb +79 -0
- data/app/condition.rb +1 -1
- data/app/core.rb +7 -11
- data/app/default.rb +1 -1
- data/app/disassemble.rb +3 -2
- data/app/file.rb +12 -36
- data/app/frame.rb +3 -2
- data/app/irb.rb +9 -5
- data/app/iseq.rb +46 -0
- data/app/options.rb +6 -30
- data/app/run.rb +5 -2
- data/app/util.rb +1 -2
- data/app/yarv.rb +11 -1
- data/bin/.gitignore +1 -0
- data/bin/trepan +6 -6
- data/data/.gitignore +1 -0
- data/interface/.gitignore +1 -0
- data/interface/base_intf.rb +9 -5
- data/interface/comcodes.rb +10 -8
- data/interface/user.rb +76 -17
- data/io/.gitignore +1 -0
- data/io/input.rb +39 -15
- data/io/tcpclient.rb +7 -1
- data/io/tcpfns.rb +5 -3
- data/io/tcpserver.rb +13 -10
- data/lib/.gitignore +1 -0
- data/lib/trepanning.rb +50 -13
- data/processor/.gitignore +1 -0
- data/processor/Makefile +7 -0
- data/processor/breakpoint.rb +7 -2
- data/processor/command/.gitignore +1 -0
- data/processor/command/Makefile +7 -0
- data/processor/command/alias.rb +2 -2
- data/processor/command/backtrace.rb +4 -0
- data/processor/command/base/cmd.rb +45 -2
- data/processor/command/base/subcmd.rb +4 -2
- data/processor/command/base/submgr.rb +23 -19
- data/processor/command/base/subsubcmd.rb +23 -1
- data/processor/command/base/subsubmgr.rb +13 -0
- data/processor/command/break.rb +34 -29
- data/processor/command/complete.rb +37 -0
- data/processor/command/condition.rb +2 -0
- data/processor/command/continue.rb +15 -18
- data/processor/command/disassemble.rb +5 -0
- data/processor/command/down.rb +1 -1
- data/processor/command/eval.rb +70 -0
- data/processor/command/exit.rb +4 -1
- data/processor/command/finish.rb +6 -4
- data/processor/command/frame.rb +6 -3
- data/processor/command/help.rb +97 -54
- data/processor/command/help/.gitignore +1 -0
- data/processor/command/help/README +10 -0
- data/processor/command/help/command.txt +48 -0
- data/processor/command/help/filename.txt +40 -0
- data/processor/command/help/location.txt +37 -0
- data/processor/command/info_subcmd/.gitignore +1 -0
- data/processor/command/info_subcmd/breakpoints.rb +9 -9
- data/processor/command/info_subcmd/{file.rb → files.rb} +92 -27
- data/processor/command/info_subcmd/frame.rb +41 -15
- data/processor/command/info_subcmd/iseq.rb +39 -17
- data/processor/command/info_subcmd/program.rb +2 -8
- data/processor/command/info_subcmd/registers.rb +12 -10
- data/processor/command/info_subcmd/registers_subcmd/.gitignore +1 -0
- data/processor/command/info_subcmd/ruby.rb +60 -0
- data/processor/command/irb.rb +26 -3
- data/processor/command/kill.rb +21 -10
- data/processor/command/list.rb +1 -1
- data/processor/command/macro.rb +37 -23
- data/processor/command/pr.rb +1 -1
- data/processor/command/reload.rb +4 -0
- data/processor/command/reload_subcmd/.gitignore +1 -0
- data/processor/command/restart.rb +9 -9
- data/processor/command/save.rb +29 -36
- data/processor/command/set_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/confirm.rb +23 -0
- data/processor/command/set_subcmd/debug_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/different.rb +2 -0
- data/processor/command/set_subcmd/events.rb +2 -0
- data/processor/command/set_subcmd/max.rb +9 -12
- data/processor/command/set_subcmd/max_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/substitute_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/trace.rb +7 -13
- data/processor/command/set_subcmd/trace_subcmd/.gitignore +1 -0
- data/processor/command/set_subcmd/trace_subcmd/buffer.rb +12 -27
- data/processor/command/set_subcmd/trace_subcmd/print.rb +10 -8
- data/processor/command/set_subcmd/trace_subcmd/var.rb +6 -10
- data/processor/command/show.rb +12 -1
- data/processor/command/show_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/alias.rb +11 -15
- data/processor/command/show_subcmd/auto_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/basename.rb +1 -9
- data/processor/command/show_subcmd/confirm.rb +25 -0
- data/processor/command/show_subcmd/debug_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/macro.rb +32 -14
- data/processor/command/show_subcmd/max_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/trace_subcmd/.gitignore +1 -0
- data/processor/command/show_subcmd/trace_subcmd/buffer.rb +11 -31
- data/processor/command/show_subcmd/trace_subcmd/print.rb +4 -20
- data/processor/command/source.rb +7 -1
- data/processor/command/up.rb +7 -4
- data/processor/default.rb +3 -1
- data/processor/eval.rb +13 -0
- data/processor/eventbuf.rb +3 -2
- data/processor/frame.rb +19 -0
- data/processor/help.rb +20 -0
- data/processor/load_cmds.rb +143 -24
- data/processor/location.rb +61 -10
- data/processor/main.rb +30 -11
- data/processor/mock.rb +5 -3
- data/processor/msg.rb +17 -0
- data/processor/running.rb +1 -1
- data/processor/subcmd.rb +3 -2
- data/processor/validate.rb +173 -185
- data/sample/.gitignore +1 -0
- data/sample/list-terminal-colors.rb +139 -0
- data/sample/rocky-dot-trepanrc +14 -0
- data/sample/rocky-trepan-colors.rb +47 -0
- data/test/Makefile +7 -0
- data/test/data/.gitignore +1 -0
- data/test/data/debugger-stop.cmd +3 -0
- data/test/data/debugger-stop.right +5 -0
- data/test/data/fname-with-blank.right +0 -3
- data/test/data/quit.right +0 -1
- data/test/data/quit2.cmd +6 -0
- data/test/data/quit2.right +3 -0
- data/test/data/testing.cmd +1 -0
- data/test/example/.gitignore +1 -0
- data/test/example/debugger-stop.rb +14 -0
- data/test/functional/.gitignore +2 -0
- data/test/functional/fn_helper.rb +7 -9
- data/test/functional/test-break-long.rb +7 -7
- data/test/functional/test-break.rb +7 -7
- data/test/functional/test-condition.rb +4 -4
- data/test/functional/test-delete.rb +6 -5
- data/test/functional/test-eval.rb +115 -0
- data/test/functional/test-raise.rb +1 -1
- data/test/functional/test-return.rb +1 -1
- data/test/integration/.gitignore +2 -0
- data/test/integration/helper.rb +6 -3
- data/test/integration/test-debugger-stop.rb +22 -0
- data/test/integration/test-quit.rb +8 -0
- data/test/unit/.gitignore +1 -0
- data/test/unit/Makefile +7 -0
- data/test/unit/test-app-brkpt.rb +0 -1
- data/test/unit/test-app-cmd_parse.rb +107 -0
- data/test/unit/test-app-cmd_parser.rb +22 -0
- data/test/unit/test-app-complete.rb +38 -0
- data/test/unit/test-app-condition.rb +20 -0
- data/test/unit/test-app-iseq.rb +31 -0
- data/test/unit/test-app-options.rb +9 -1
- data/test/unit/test-app-util.rb +0 -1
- data/test/unit/test-base-cmd.rb +46 -0
- data/test/unit/test-base-subcmd.rb +11 -2
- data/test/unit/test-base-submgr.rb +23 -0
- data/test/unit/test-base-subsubcmd.rb +20 -0
- data/test/unit/test-cmd-break.rb +22 -23
- data/test/unit/test-cmd-help.rb +4 -0
- data/test/unit/test-completion.rb +43 -0
- data/test/unit/test-io-tcpclient.rb +3 -2
- data/test/unit/test-proc-load_cmds.rb +10 -1
- data/test/unit/test-proc-location.rb +39 -0
- data/test/unit/test-proc-main.rb +1 -1
- data/test/unit/test-proc-validate.rb +47 -31
- data/trepanning.gemspec +45 -0
- metadata +247 -179
- data/app/core.rb-consider +0 -198
- data/test/functional/tmp/b3.rb +0 -5
- data/test/functional/tmp/immediate-bug1.rb +0 -9
data/Makefile
ADDED
data/NEWS
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
March 15, 2011 (0.0.6)
|
2
|
+
- Revise breakpoint location parsing
|
3
|
+
* Add: break <location> if/unless <condition>
|
4
|
+
* Add: step until <condition>
|
5
|
+
* VM offsets are now specified via @ rather than o or O
|
6
|
+
* Filenames can be quoted and blanks and characters inside escaped
|
7
|
+
- Document command syntax by adding it as a new category with sub help
|
8
|
+
- More controlled parsing of method names
|
9
|
+
- Add eval (no args) and eval? to run current source line or source line
|
10
|
+
eval? strips:
|
11
|
+
* leading "if", "elsif", "while", "until" "return" or "case", or "unless"
|
12
|
+
* trailing "then", "do"
|
13
|
+
- Save and restore some debugger state across a restart
|
14
|
+
- Redo command completion
|
15
|
+
|
16
|
+
Feb 15, 2011 (0.0.5)
|
17
|
+
- "disassemble" command: allow disassembly of specified line numbers
|
18
|
+
- GNU Readline:
|
19
|
+
* Start GNU readline tab (command) completion.
|
20
|
+
* Save and restore command history
|
21
|
+
* add --readline and --no-readline options to trepanx
|
22
|
+
- Macros can return more than one command now
|
23
|
+
- help
|
24
|
+
* "help macros" shows all macro names
|
25
|
+
* "help aliases" shows all alias names
|
26
|
+
* "help *" lists macros and aliases now
|
27
|
+
- start "info line"
|
28
|
+
- "info file" has/shows File::stat()'s mtime and ctime
|
29
|
+
- be able to pass --verbose to ruby to rake
|
30
|
+
|
1
31
|
Feb 1, 2011 (0.1.0)
|
2
32
|
* Add Remote debugging interface. Add options --server --port
|
3
33
|
* Add Syntax highlighting on Ruby and YARV listings and locations
|
data/Rakefile
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
|
5
5
|
ROOT_DIR = File.dirname(__FILE__)
|
6
|
+
Gemspec_filename='trepanning.gemspec'
|
6
7
|
require File.join %W(#{ROOT_DIR} app options)
|
7
8
|
|
8
9
|
def gemspec
|
9
|
-
@gemspec ||= eval(File.read(
|
10
|
+
@gemspec ||= eval(File.read(Gemspec_filename), binding, Gemspec_filename)
|
10
11
|
end
|
11
12
|
|
12
13
|
require 'rake/gempackagetask'
|
@@ -14,16 +15,16 @@ desc "Build the gem"
|
|
14
15
|
task :package=>:gem
|
15
16
|
task :gem=>:gemspec do
|
16
17
|
Dir.chdir(ROOT_DIR) do
|
17
|
-
sh "gem build
|
18
|
+
sh "gem build #{Gemspec_filename}"
|
18
19
|
FileUtils.mkdir_p 'pkg'
|
19
|
-
FileUtils.mv
|
20
|
+
FileUtils.mv gemspec.file_name, 'pkg'
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
24
|
desc "Install the gem locally"
|
24
25
|
task :install => :gem do
|
25
26
|
Dir.chdir(ROOT_DIR) do
|
26
|
-
sh %{gem install --local pkg/#{gemspec.
|
27
|
+
sh %{gem install --local pkg/#{gemspec.file_name}}
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -47,14 +48,16 @@ def run_standalone_ruby_files(list)
|
|
47
48
|
puts '*' * 40
|
48
49
|
list.each do |ruby_file|
|
49
50
|
system(RUBY_PATH, ruby_file)
|
51
|
+
p $?.exitstatus
|
52
|
+
break if $?.exitstatus != 0 && !opts[:continue]
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
53
56
|
def run_standalone_ruby_file(directory, opts={})
|
54
|
-
puts
|
57
|
+
puts(('*' * 10) + ' ' + directory + ' ' + ('*' * 10))
|
55
58
|
Dir.chdir(directory) do
|
56
59
|
Dir.glob('*.rb').each do |ruby_file|
|
57
|
-
puts
|
60
|
+
puts(('-' * 20) + ' ' + ruby_file + ' ' + ('-' * 20))
|
58
61
|
system(RUBY_PATH, ruby_file)
|
59
62
|
break if $?.exitstatus != 0 && !opts[:continue]
|
60
63
|
end
|
@@ -70,19 +73,19 @@ desc 'Test units - the smaller tests'
|
|
70
73
|
Rake::TestTask.new(:'test:unit') do |t|
|
71
74
|
t.test_files = FileList['test/unit/**/test-*.rb']
|
72
75
|
# t.pattern = 'test/**/*test-*.rb' # instead of above
|
73
|
-
t.
|
76
|
+
t.options = '--verbose' if $VERBOSE
|
74
77
|
end
|
75
78
|
|
76
79
|
desc 'Test functional - the medium-sized tests'
|
77
80
|
Rake::TestTask.new(:'test:functional') do |t|
|
78
81
|
t.test_files = FileList['test/functional/**/test-*.rb']
|
79
|
-
t.
|
82
|
+
t.options = '--verbose' if $VERBOSE
|
80
83
|
end
|
81
84
|
|
82
85
|
desc 'Test integration - end-to-end blackbox tests'
|
83
86
|
Rake::TestTask.new(:'test:integration') do |t|
|
84
87
|
t.test_files = FileList['test/integration/**/test-*.rb']
|
85
|
-
t.
|
88
|
+
t.options = '--verbose' if $VERBOSE
|
86
89
|
end
|
87
90
|
|
88
91
|
desc 'Test everything - unit tests for now.'
|
@@ -100,7 +103,7 @@ task :test do
|
|
100
103
|
raise "Test failures" unless exceptions.empty?
|
101
104
|
end
|
102
105
|
|
103
|
-
desc "Run each
|
106
|
+
desc "Run each Ruby app file in standalone mode."
|
104
107
|
task :'check:app' do
|
105
108
|
run_standalone_ruby_file(File.join(%W(#{ROOT_DIR} app)))
|
106
109
|
end
|
@@ -110,6 +113,14 @@ task :'check:commands' do
|
|
110
113
|
run_standalone_ruby_file(File.join(%W(#{ROOT_DIR} processor command)))
|
111
114
|
end
|
112
115
|
|
116
|
+
desc "Run each of the sub-sub commands in standalone mode."
|
117
|
+
task :'check:sub:commands' do
|
118
|
+
p "#{ROOT_DIR}/processor/command/*_subcmd/*_subcmd/*.rb"
|
119
|
+
Dir.glob("#{ROOT_DIR}/processor/command/*_subcmd").each do |sub_dir|
|
120
|
+
run_standalone_ruby_file(sub_dir)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
113
124
|
desc "Run each of the sub-sub commands in standalone mode."
|
114
125
|
task :'check:subsub:commands' do
|
115
126
|
subsub_files = FileList["#{ROOT_DIR}/processor/command/*_subcmd/*_subcmd/*.rb"]
|
@@ -131,10 +142,28 @@ task :'check:unit' do
|
|
131
142
|
run_standalone_ruby_file(File.join(%W(#{ROOT_DIR} test unit)))
|
132
143
|
end
|
133
144
|
|
145
|
+
desc "Run functional tests in standalone mode."
|
134
146
|
task :'check:functional' do
|
135
147
|
run_standalone_ruby_file(File.join(%W(#{ROOT_DIR} test functional)))
|
136
148
|
end
|
137
149
|
|
150
|
+
desc "Run command parser grammar."
|
151
|
+
task :'check:cmd_parse' do
|
152
|
+
sh "kpeg --test --debug #{File.join(ROOT_DIR, %w(app cmd_parse.kpeg))}"
|
153
|
+
end
|
154
|
+
|
155
|
+
desc "Generate command parser."
|
156
|
+
task :'cmd_parse' do
|
157
|
+
require 'tmpdir'
|
158
|
+
temp_file =
|
159
|
+
File.join(Dir.tmpdir,
|
160
|
+
Dir::Tmpname.make_tmpname(['cmd_parser_', '.rb'], nil))
|
161
|
+
|
162
|
+
sh("kpeg --name CmdParse --verbose --stand-alone " +
|
163
|
+
"#{File.join(ROOT_DIR, %w(app cmd_parse.kpeg))} " +
|
164
|
+
"--output #{temp_file}")
|
165
|
+
end
|
166
|
+
|
138
167
|
task :'check:integration' do
|
139
168
|
run_standalone_ruby_file(File.join(%W(#{ROOT_DIR} test integration)))
|
140
169
|
end
|
@@ -161,14 +190,15 @@ Rake::RDocTask.new("rdoc") do |rdoc|
|
|
161
190
|
rdoc.rdoc_dir = 'doc'
|
162
191
|
rdoc.title = "Trepanning #{Trepan::VERSION} Documentation"
|
163
192
|
|
164
|
-
rdoc.rdoc_files.include(
|
193
|
+
rdoc.rdoc_files.include(%w(lib/*.rb
|
194
|
+
app/*.rb intf/*.rb io/*.rb
|
195
|
+
bin/trepan
|
196
|
+
))
|
165
197
|
end
|
198
|
+
|
166
199
|
desc "Same as rdoc"
|
167
200
|
task :doc => :rdoc
|
168
201
|
|
169
|
-
desc "Remove built files"
|
170
|
-
task :clean => [:clobber_package, :clobber_rdoc]
|
171
|
-
|
172
202
|
task :clobber_package do
|
173
203
|
FileUtils.rm_rf File.join(ROOT_DIR, 'pkg')
|
174
204
|
end
|
@@ -177,3 +207,9 @@ task :clobber_rdoc do
|
|
177
207
|
FileUtils.rm_rf File.join(ROOT_DIR, 'doc')
|
178
208
|
end
|
179
209
|
|
210
|
+
task :rm_patch_residue do
|
211
|
+
FileUtils.rm_rf FileList['**/*.{rej,orig}'].to_a
|
212
|
+
end
|
213
|
+
|
214
|
+
desc "Remove built files"
|
215
|
+
task :clean => [:clobber_package, :clobber_rdoc, :rm_patch_residue]
|
data/app/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/*~
|
data/app/breakpoint.rb
CHANGED
@@ -19,6 +19,9 @@ class Trepan
|
|
19
19
|
attr_reader :offset # Fixnum. Offset into an instruction
|
20
20
|
# sequence for the location of the
|
21
21
|
# breakpoint
|
22
|
+
attr_reader :negate # Boolean. Negate sense of condition. Used in
|
23
|
+
# break if .. and break unless ..
|
24
|
+
# breakpoint
|
22
25
|
attr_reader :type # String. 'line' if breakpoint requested
|
23
26
|
# at "line" boundary or 'offset'
|
24
27
|
# requested at a specific offset
|
@@ -29,6 +32,7 @@ class Trepan
|
|
29
32
|
:enabled => 'true',
|
30
33
|
:ignore => 0,
|
31
34
|
:temp => false,
|
35
|
+
:negate => false,
|
32
36
|
:type => 'line',
|
33
37
|
} unless defined?(BRKPT_DEFAULT_SETTINGS)
|
34
38
|
|
@@ -59,11 +63,12 @@ class Trepan
|
|
59
63
|
@id = @@next_id
|
60
64
|
@@next_id += 1
|
61
65
|
end
|
62
|
-
|
66
|
+
raise RuntimeError,
|
67
|
+
"Unable to set breakpoint in #{iseq.name} at offset #{offset}" unless set
|
63
68
|
end
|
64
69
|
|
65
70
|
def condition?(bind)
|
66
|
-
if eval(@condition, bind)
|
71
|
+
if @negate != eval(@condition, bind)
|
67
72
|
if @ignore > 0
|
68
73
|
@ignore -= 1
|
69
74
|
return false
|
data/app/brkptmgr.rb
CHANGED
@@ -8,11 +8,23 @@ class Trepan
|
|
8
8
|
attr_reader :set
|
9
9
|
|
10
10
|
def initialize
|
11
|
+
clear
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear
|
11
15
|
@list = []
|
12
16
|
@next_id = 1
|
13
17
|
@set = Set.new
|
14
18
|
end
|
15
19
|
|
20
|
+
# Remove all breakpoints that we have recorded
|
21
|
+
def finalize
|
22
|
+
@list.each do |bp|
|
23
|
+
bp.remove!
|
24
|
+
end
|
25
|
+
clear
|
26
|
+
end
|
27
|
+
|
16
28
|
def <<(brkpt)
|
17
29
|
@list << brkpt
|
18
30
|
@set.add(set_key(brkpt))
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# -*- Ruby -*-
|
2
|
+
grammar MethodName
|
3
|
+
rule upcase_letter
|
4
|
+
[A-Z]
|
5
|
+
end
|
6
|
+
rule downcase_letter
|
7
|
+
[a-z]
|
8
|
+
end
|
9
|
+
rule suffix_letter
|
10
|
+
[=!?]
|
11
|
+
end
|
12
|
+
rule letter
|
13
|
+
upcase_letter | downcase_letter
|
14
|
+
end
|
15
|
+
rule id_symbol
|
16
|
+
letter | '_' | [0-9]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Examples:
|
20
|
+
# var1
|
21
|
+
# my_var?
|
22
|
+
rule variable_identifier
|
23
|
+
((downcase_letter | '_') id_symbol* suffix_letter?)
|
24
|
+
{
|
25
|
+
SymbolEntry = Struct.new(:type, :name, :chain)
|
26
|
+
def value
|
27
|
+
SymbolEntry.new(:variable, self.to_s)
|
28
|
+
end
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Examples:
|
33
|
+
# MY_CONSTANT
|
34
|
+
# MyConstant_01
|
35
|
+
rule constant_identifier
|
36
|
+
(upcase_letter id_symbol*)
|
37
|
+
{
|
38
|
+
def value
|
39
|
+
SymbolEntry.new(:constant, self.to_s)
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
# Examples:
|
45
|
+
# $global_variable
|
46
|
+
# We won't try for funny global names like $$, $? $:, $', etc
|
47
|
+
rule global_identifier
|
48
|
+
('$' (constant_identifier | variable_identifier))
|
49
|
+
{
|
50
|
+
def value
|
51
|
+
SymbolEntry.new(:global, self.to_s)
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Examples:
|
57
|
+
# Foo
|
58
|
+
# foo
|
59
|
+
rule local_identifier
|
60
|
+
(constant_identifier | variable_identifier)
|
61
|
+
{
|
62
|
+
def value
|
63
|
+
SymbolEntry.new(:instance, self.to_s)
|
64
|
+
end
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
# Example: @foo
|
69
|
+
rule instance_identifier
|
70
|
+
('@' local_identifier )
|
71
|
+
{
|
72
|
+
def value
|
73
|
+
SymbolEntry.new(:instance, self.to_s)
|
74
|
+
end
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Example: @@foo
|
80
|
+
rule classvar_identifier
|
81
|
+
('@@' local_identifier )
|
82
|
+
{
|
83
|
+
def value
|
84
|
+
SymbolEntry.new(:classvar, self.to_s)
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
rule identifier
|
89
|
+
global_identifier | instance_identifier | classvar_identifier |
|
90
|
+
local_identifier
|
91
|
+
end
|
92
|
+
|
93
|
+
# I think strict Ruby rules are that once one goes from :: to .
|
94
|
+
# There is no going back. That is, A.B::C is invalid.
|
95
|
+
#
|
96
|
+
# Also I think method names can't be constants. But such
|
97
|
+
# subtleties we'll handle in semantic analysis.
|
98
|
+
rule class_module_chain
|
99
|
+
( ( parent:(local_identifier) symbol:('::'|'.')
|
100
|
+
child:(class_module_chain) )
|
101
|
+
| (parent:(local_identifier) ) )
|
102
|
+
{
|
103
|
+
def value
|
104
|
+
let = self.to_s[0..0]
|
105
|
+
type = (let.capitalize == let) ? :constant : :variable
|
106
|
+
SymbolEntry.new(type, self.to_s, [parent, child, symbol.to_s])
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
##############################################################
|
112
|
+
# Location-specific things. This is used in conjunction with
|
113
|
+
# method-like things above.
|
114
|
+
rule sp
|
115
|
+
[ \t]+
|
116
|
+
end
|
117
|
+
|
118
|
+
rule file_pos_sep
|
119
|
+
sp | ':'
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
rule integer
|
124
|
+
[0-9]+ { to_i }
|
125
|
+
end
|
126
|
+
|
127
|
+
rule vm_offset
|
128
|
+
('@' integer)
|
129
|
+
{
|
130
|
+
Position = Struct.new(:type, :value) unless defined?(Position)
|
131
|
+
Position.new(:offset, integer.value)
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
rule line_number
|
136
|
+
([0-9]+)
|
137
|
+
{
|
138
|
+
Position = Struct.new(:type, :value) unless defined?(Position)
|
139
|
+
Position.new(:line, to_i)
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
# Examples:
|
144
|
+
# @43
|
145
|
+
# 5
|
146
|
+
rule position
|
147
|
+
(vm_offset | line_number)
|
148
|
+
end
|
149
|
+
|
150
|
+
rule location
|
151
|
+
(class_module_chain? file_pos_sep position
|
152
|
+
| position | meth2:(class_module_chain))
|
153
|
+
{
|
154
|
+
Location = Struct.new(:method_name, :position) unless defined?(Location)
|
155
|
+
pos_val = position ? position.value : nil
|
156
|
+
meth_val =
|
157
|
+
if class_module_chain
|
158
|
+
class_module_chain.value
|
159
|
+
else
|
160
|
+
# p ['++++2', meth2, meth2.class]
|
161
|
+
meth2 ? meth2.value : nil
|
162
|
+
end
|
163
|
+
Location.new(meth_val, pos_val)
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
data/app/cmd_parse.kpeg
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# -*- Ruby -*-
|
2
|
+
|
3
|
+
%% {
|
4
|
+
#####################################################
|
5
|
+
# Structure to hold composite method names
|
6
|
+
SymbolEntry = Struct.new(:type, :name, :chain)
|
7
|
+
|
8
|
+
|
9
|
+
# Structure to hold position information
|
10
|
+
Position = Struct.new(:container_type, :container,
|
11
|
+
:position_type, :position)
|
12
|
+
|
13
|
+
# Structure to hold breakpoint information
|
14
|
+
Breakpoint = Struct.new(:position, :negate, :condition)
|
15
|
+
|
16
|
+
# Structure to hold list information
|
17
|
+
List = Struct.new(:position, :num)
|
18
|
+
|
19
|
+
}
|
20
|
+
#####################################################
|
21
|
+
|
22
|
+
upcase_letter = /[A-Z]/
|
23
|
+
downcase_letter = /[a-z]/
|
24
|
+
suffix_letter = /[=!?]/
|
25
|
+
letter = upcase_letter
|
26
|
+
| downcase_letter
|
27
|
+
id_symbol = letter | "_" | [0-9]
|
28
|
+
|
29
|
+
|
30
|
+
# An variable or a method identifier
|
31
|
+
# Examples:
|
32
|
+
# var1
|
33
|
+
# my_var?
|
34
|
+
# But not: Variable or @var
|
35
|
+
vm_identifier = < (downcase_letter | "_") id_symbol* suffix_letter? >
|
36
|
+
{
|
37
|
+
SymbolEntry.new(:variable, text)
|
38
|
+
}
|
39
|
+
|
40
|
+
# Examples:
|
41
|
+
# var1
|
42
|
+
# But not: my_var?, my_var!
|
43
|
+
variable_identifier = < (downcase_letter | "_") id_symbol* >
|
44
|
+
{
|
45
|
+
SymbolEntry.new(:variable, text)
|
46
|
+
}
|
47
|
+
|
48
|
+
# Examples:
|
49
|
+
# MY_CONSTANT
|
50
|
+
# MyConstant_01
|
51
|
+
# But not:
|
52
|
+
# MyConstant_01?
|
53
|
+
constant_identifier = < upcase_letter id_symbol* >
|
54
|
+
{
|
55
|
+
SymbolEntry.new(:constant, text)
|
56
|
+
}
|
57
|
+
|
58
|
+
# Examples:
|
59
|
+
# $global_variable
|
60
|
+
# We won't try for funny global names like $$, $? $:, $', etc
|
61
|
+
global_identifier = < "$" (constant_identifier | variable_identifier) >
|
62
|
+
{
|
63
|
+
SymbolEntry.new(:global, text)
|
64
|
+
}
|
65
|
+
|
66
|
+
# Examples:
|
67
|
+
# Foo
|
68
|
+
# foo
|
69
|
+
# But not:
|
70
|
+
# foo!, @foo, Class.foo
|
71
|
+
local_internal_identifier = constant_identifier | variable_identifier
|
72
|
+
|
73
|
+
# Examples:
|
74
|
+
# Foo, foo, foo!
|
75
|
+
# foo
|
76
|
+
# But not:
|
77
|
+
# @foo, Class.foo
|
78
|
+
local_identifier = constant_identifier | vm_identifier
|
79
|
+
|
80
|
+
# Example: @foo
|
81
|
+
instance_identifier = < '@' local_identifier >
|
82
|
+
{
|
83
|
+
SymbolEntry.new(:instance, text)
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
# Example: @@foo
|
88
|
+
classvar_identifier = ('@@' local_identifier:id )
|
89
|
+
{
|
90
|
+
SymbolEntry.new(:classvar, id)
|
91
|
+
}
|
92
|
+
|
93
|
+
identifier = global_identifier
|
94
|
+
| instance_identifier
|
95
|
+
| classvar_identifier
|
96
|
+
| local_identifier
|
97
|
+
|
98
|
+
id_separator = < '::'|'.' > { text }
|
99
|
+
|
100
|
+
# Like of class_module_chain *after* the first name. So we don't
|
101
|
+
# allow sigils in the initial id. That is we don't allow:
|
102
|
+
# Class.@name1.@@name2.$name3
|
103
|
+
# But we do allow final sigils:
|
104
|
+
# class.name!, class.name=
|
105
|
+
internal_class_module_chain =
|
106
|
+
< local_internal_identifier:parent id_separator:sep
|
107
|
+
internal_class_module_chain:child >
|
108
|
+
{
|
109
|
+
SymbolEntry.new(parent.type, text, [parent, child, sep])
|
110
|
+
}
|
111
|
+
| local_identifier
|
112
|
+
|
113
|
+
|
114
|
+
# I think strict Ruby rules are that once one goes from :: to .
|
115
|
+
# There is no going back. That is, A.B::C is invalid.
|
116
|
+
#
|
117
|
+
# Also I think method names can't be constants. But such
|
118
|
+
# subtleties we'll handle when we process the final structure.
|
119
|
+
# Examples:
|
120
|
+
# Object, A::B, A.b @@foo.bar, $foo.bar.baz?
|
121
|
+
|
122
|
+
class_module_chain =
|
123
|
+
< identifier:parent id_separator:sep internal_class_module_chain:child >
|
124
|
+
{
|
125
|
+
SymbolEntry.new(parent.type, text, [parent, child, sep])
|
126
|
+
}
|
127
|
+
| identifier
|
128
|
+
|
129
|
+
##############################################################
|
130
|
+
# Location-specific things. This is used in conjunction with
|
131
|
+
# method-like things above.
|
132
|
+
sp = /[ \t]/
|
133
|
+
- = sp+
|
134
|
+
dbl_escapes = "\\\"" { '"' }
|
135
|
+
| "\\n" { "\n" }
|
136
|
+
| "\\t" { "\t" }
|
137
|
+
| "\\\\" { "\\" }
|
138
|
+
escapes = "\\\"" { '"' }
|
139
|
+
| "\\n" { "\n" }
|
140
|
+
| "\\t" { "\t" }
|
141
|
+
| "\\ " { " " }
|
142
|
+
| "\\:" { ":" }
|
143
|
+
| "\\\\" { "\\" }
|
144
|
+
dbl_seq = < /[^\\"]+/ > { text }
|
145
|
+
dbl_not_quote = (dbl_escapes | dbl_seq)+:ary { ary }
|
146
|
+
dbl_string = "\"" dbl_not_quote:ary "\"" { ary.join }
|
147
|
+
not_space_colon = escapes
|
148
|
+
| < /[^ \t\n:]/ > { text }
|
149
|
+
not_space_colons = ( not_space_colon )+:ary { ary.join }
|
150
|
+
filename = dbl_string | not_space_colons
|
151
|
+
file_pos_sep = sp+ | ':'
|
152
|
+
integer = </[0-9]+/> { text.to_i }
|
153
|
+
line_number = integer
|
154
|
+
|
155
|
+
vm_offset = '@' integer:int
|
156
|
+
{
|
157
|
+
Position.new(nil, nil, :offset, int)
|
158
|
+
}
|
159
|
+
|
160
|
+
# Examples:
|
161
|
+
# @43
|
162
|
+
# 5
|
163
|
+
position =
|
164
|
+
vm_offset
|
165
|
+
| line_number:l {
|
166
|
+
Position.new(nil, nil, :line, l)
|
167
|
+
}
|
168
|
+
|
169
|
+
# Examples:
|
170
|
+
# Myclass.fn @5 # bytecode offset 5 of fn
|
171
|
+
# Myclass.fn:@5 # same as above
|
172
|
+
# Myclass.fn 5 # line number 5 of fn
|
173
|
+
# Note: Myclass.fn could be either a filename or a method name
|
174
|
+
|
175
|
+
# The below ordering is important.
|
176
|
+
# 1. Numbers can't be method names they are first. If there's a
|
177
|
+
# file with that name, later we'll allow quoting to indicate filename.
|
178
|
+
# 2. filename:position can't also be a method so that's next
|
179
|
+
# 3. It is possible a filename can be a method name, but we
|
180
|
+
# test using File.exist? so we want to put this first.
|
181
|
+
# Later "quoting" will skip the File.exist?
|
182
|
+
# 4. Class module *with* a position is next and has to be before
|
183
|
+
# without a position, else we would stop early before handling
|
184
|
+
# the position.
|
185
|
+
|
186
|
+
location =
|
187
|
+
position
|
188
|
+
| <filename>:file &{ File.exist?(file) } file_pos_sep position:pos {
|
189
|
+
Position.new(:file, file, pos.position_type, pos.position)
|
190
|
+
}
|
191
|
+
| <filename>:file &{ File.exist?(file) } {
|
192
|
+
Position.new(:file, file, nil, nil)
|
193
|
+
}
|
194
|
+
| class_module_chain?:fn file_pos_sep position:pos {
|
195
|
+
Position.new(:fn, fn, pos.position_type, pos.position)
|
196
|
+
}
|
197
|
+
| class_module_chain?:fn {
|
198
|
+
Position.new(:fn, fn, nil, nil)
|
199
|
+
}
|
200
|
+
|
201
|
+
if_unless = <"if" | "unless"> { text }
|
202
|
+
condition = </.+/> { text}
|
203
|
+
|
204
|
+
breakpoint_stmt_no_condition = location:loc {
|
205
|
+
Breakpoint.new(loc, false, 'true')
|
206
|
+
}
|
207
|
+
|
208
|
+
# Note that the first word "break" is handled in the command.
|
209
|
+
# Also, "break" with nothing else is handled there as well
|
210
|
+
breakpoint_stmt = location:loc - if_unless:iu - condition:cond {
|
211
|
+
Breakpoint.new(loc, iu == 'unless', cond)
|
212
|
+
}
|
213
|
+
| breakpoint_stmt_no_condition
|
214
|
+
|
215
|
+
# Note that the first word "list", "list>" or handled in
|
216
|
+
# the command. Also, "list" with nothing else is
|
217
|
+
# handled there as well
|
218
|
+
list_special_targets = <'.' '-'> { text }
|
219
|
+
list_stmt = (list_special_target | location):loc - (integer:int)? {
|
220
|
+
List.new(loc, int)
|
221
|
+
}
|