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.
Files changed (181) hide show
  1. data/.gitignore +4 -0
  2. data/ChangeLog +1279 -235
  3. data/Makefile +13 -0
  4. data/NEWS +30 -0
  5. data/Rakefile +50 -14
  6. data/app/.gitignore +1 -0
  7. data/app/breakpoint.rb +7 -2
  8. data/app/brkptmgr.rb +12 -0
  9. data/app/cmd_parse.citrus +167 -0
  10. data/app/cmd_parse.kpeg +221 -0
  11. data/app/cmd_parse.rb +201 -0
  12. data/app/cmd_parser.rb +1914 -0
  13. data/app/complete.rb +79 -0
  14. data/app/condition.rb +1 -1
  15. data/app/core.rb +7 -11
  16. data/app/default.rb +1 -1
  17. data/app/disassemble.rb +3 -2
  18. data/app/file.rb +12 -36
  19. data/app/frame.rb +3 -2
  20. data/app/irb.rb +9 -5
  21. data/app/iseq.rb +46 -0
  22. data/app/options.rb +6 -30
  23. data/app/run.rb +5 -2
  24. data/app/util.rb +1 -2
  25. data/app/yarv.rb +11 -1
  26. data/bin/.gitignore +1 -0
  27. data/bin/trepan +6 -6
  28. data/data/.gitignore +1 -0
  29. data/interface/.gitignore +1 -0
  30. data/interface/base_intf.rb +9 -5
  31. data/interface/comcodes.rb +10 -8
  32. data/interface/user.rb +76 -17
  33. data/io/.gitignore +1 -0
  34. data/io/input.rb +39 -15
  35. data/io/tcpclient.rb +7 -1
  36. data/io/tcpfns.rb +5 -3
  37. data/io/tcpserver.rb +13 -10
  38. data/lib/.gitignore +1 -0
  39. data/lib/trepanning.rb +50 -13
  40. data/processor/.gitignore +1 -0
  41. data/processor/Makefile +7 -0
  42. data/processor/breakpoint.rb +7 -2
  43. data/processor/command/.gitignore +1 -0
  44. data/processor/command/Makefile +7 -0
  45. data/processor/command/alias.rb +2 -2
  46. data/processor/command/backtrace.rb +4 -0
  47. data/processor/command/base/cmd.rb +45 -2
  48. data/processor/command/base/subcmd.rb +4 -2
  49. data/processor/command/base/submgr.rb +23 -19
  50. data/processor/command/base/subsubcmd.rb +23 -1
  51. data/processor/command/base/subsubmgr.rb +13 -0
  52. data/processor/command/break.rb +34 -29
  53. data/processor/command/complete.rb +37 -0
  54. data/processor/command/condition.rb +2 -0
  55. data/processor/command/continue.rb +15 -18
  56. data/processor/command/disassemble.rb +5 -0
  57. data/processor/command/down.rb +1 -1
  58. data/processor/command/eval.rb +70 -0
  59. data/processor/command/exit.rb +4 -1
  60. data/processor/command/finish.rb +6 -4
  61. data/processor/command/frame.rb +6 -3
  62. data/processor/command/help.rb +97 -54
  63. data/processor/command/help/.gitignore +1 -0
  64. data/processor/command/help/README +10 -0
  65. data/processor/command/help/command.txt +48 -0
  66. data/processor/command/help/filename.txt +40 -0
  67. data/processor/command/help/location.txt +37 -0
  68. data/processor/command/info_subcmd/.gitignore +1 -0
  69. data/processor/command/info_subcmd/breakpoints.rb +9 -9
  70. data/processor/command/info_subcmd/{file.rb → files.rb} +92 -27
  71. data/processor/command/info_subcmd/frame.rb +41 -15
  72. data/processor/command/info_subcmd/iseq.rb +39 -17
  73. data/processor/command/info_subcmd/program.rb +2 -8
  74. data/processor/command/info_subcmd/registers.rb +12 -10
  75. data/processor/command/info_subcmd/registers_subcmd/.gitignore +1 -0
  76. data/processor/command/info_subcmd/ruby.rb +60 -0
  77. data/processor/command/irb.rb +26 -3
  78. data/processor/command/kill.rb +21 -10
  79. data/processor/command/list.rb +1 -1
  80. data/processor/command/macro.rb +37 -23
  81. data/processor/command/pr.rb +1 -1
  82. data/processor/command/reload.rb +4 -0
  83. data/processor/command/reload_subcmd/.gitignore +1 -0
  84. data/processor/command/restart.rb +9 -9
  85. data/processor/command/save.rb +29 -36
  86. data/processor/command/set_subcmd/.gitignore +1 -0
  87. data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
  88. data/processor/command/set_subcmd/confirm.rb +23 -0
  89. data/processor/command/set_subcmd/debug_subcmd/.gitignore +1 -0
  90. data/processor/command/set_subcmd/different.rb +2 -0
  91. data/processor/command/set_subcmd/events.rb +2 -0
  92. data/processor/command/set_subcmd/max.rb +9 -12
  93. data/processor/command/set_subcmd/max_subcmd/.gitignore +1 -0
  94. data/processor/command/set_subcmd/substitute_subcmd/.gitignore +1 -0
  95. data/processor/command/set_subcmd/trace.rb +7 -13
  96. data/processor/command/set_subcmd/trace_subcmd/.gitignore +1 -0
  97. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +12 -27
  98. data/processor/command/set_subcmd/trace_subcmd/print.rb +10 -8
  99. data/processor/command/set_subcmd/trace_subcmd/var.rb +6 -10
  100. data/processor/command/show.rb +12 -1
  101. data/processor/command/show_subcmd/.gitignore +1 -0
  102. data/processor/command/show_subcmd/alias.rb +11 -15
  103. data/processor/command/show_subcmd/auto_subcmd/.gitignore +1 -0
  104. data/processor/command/show_subcmd/basename.rb +1 -9
  105. data/processor/command/show_subcmd/confirm.rb +25 -0
  106. data/processor/command/show_subcmd/debug_subcmd/.gitignore +1 -0
  107. data/processor/command/show_subcmd/macro.rb +32 -14
  108. data/processor/command/show_subcmd/max_subcmd/.gitignore +1 -0
  109. data/processor/command/show_subcmd/trace_subcmd/.gitignore +1 -0
  110. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +11 -31
  111. data/processor/command/show_subcmd/trace_subcmd/print.rb +4 -20
  112. data/processor/command/source.rb +7 -1
  113. data/processor/command/up.rb +7 -4
  114. data/processor/default.rb +3 -1
  115. data/processor/eval.rb +13 -0
  116. data/processor/eventbuf.rb +3 -2
  117. data/processor/frame.rb +19 -0
  118. data/processor/help.rb +20 -0
  119. data/processor/load_cmds.rb +143 -24
  120. data/processor/location.rb +61 -10
  121. data/processor/main.rb +30 -11
  122. data/processor/mock.rb +5 -3
  123. data/processor/msg.rb +17 -0
  124. data/processor/running.rb +1 -1
  125. data/processor/subcmd.rb +3 -2
  126. data/processor/validate.rb +173 -185
  127. data/sample/.gitignore +1 -0
  128. data/sample/list-terminal-colors.rb +139 -0
  129. data/sample/rocky-dot-trepanrc +14 -0
  130. data/sample/rocky-trepan-colors.rb +47 -0
  131. data/test/Makefile +7 -0
  132. data/test/data/.gitignore +1 -0
  133. data/test/data/debugger-stop.cmd +3 -0
  134. data/test/data/debugger-stop.right +5 -0
  135. data/test/data/fname-with-blank.right +0 -3
  136. data/test/data/quit.right +0 -1
  137. data/test/data/quit2.cmd +6 -0
  138. data/test/data/quit2.right +3 -0
  139. data/test/data/testing.cmd +1 -0
  140. data/test/example/.gitignore +1 -0
  141. data/test/example/debugger-stop.rb +14 -0
  142. data/test/functional/.gitignore +2 -0
  143. data/test/functional/fn_helper.rb +7 -9
  144. data/test/functional/test-break-long.rb +7 -7
  145. data/test/functional/test-break.rb +7 -7
  146. data/test/functional/test-condition.rb +4 -4
  147. data/test/functional/test-delete.rb +6 -5
  148. data/test/functional/test-eval.rb +115 -0
  149. data/test/functional/test-raise.rb +1 -1
  150. data/test/functional/test-return.rb +1 -1
  151. data/test/integration/.gitignore +2 -0
  152. data/test/integration/helper.rb +6 -3
  153. data/test/integration/test-debugger-stop.rb +22 -0
  154. data/test/integration/test-quit.rb +8 -0
  155. data/test/unit/.gitignore +1 -0
  156. data/test/unit/Makefile +7 -0
  157. data/test/unit/test-app-brkpt.rb +0 -1
  158. data/test/unit/test-app-cmd_parse.rb +107 -0
  159. data/test/unit/test-app-cmd_parser.rb +22 -0
  160. data/test/unit/test-app-complete.rb +38 -0
  161. data/test/unit/test-app-condition.rb +20 -0
  162. data/test/unit/test-app-iseq.rb +31 -0
  163. data/test/unit/test-app-options.rb +9 -1
  164. data/test/unit/test-app-util.rb +0 -1
  165. data/test/unit/test-base-cmd.rb +46 -0
  166. data/test/unit/test-base-subcmd.rb +11 -2
  167. data/test/unit/test-base-submgr.rb +23 -0
  168. data/test/unit/test-base-subsubcmd.rb +20 -0
  169. data/test/unit/test-cmd-break.rb +22 -23
  170. data/test/unit/test-cmd-help.rb +4 -0
  171. data/test/unit/test-completion.rb +43 -0
  172. data/test/unit/test-io-tcpclient.rb +3 -2
  173. data/test/unit/test-proc-load_cmds.rb +10 -1
  174. data/test/unit/test-proc-location.rb +39 -0
  175. data/test/unit/test-proc-main.rb +1 -1
  176. data/test/unit/test-proc-validate.rb +47 -31
  177. data/trepanning.gemspec +45 -0
  178. metadata +247 -179
  179. data/app/core.rb-consider +0 -198
  180. data/test/functional/tmp/b3.rb +0 -5
  181. data/test/functional/tmp/immediate-bug1.rb +0 -9
data/Makefile ADDED
@@ -0,0 +1,13 @@
1
+ # I'll admit it -- I'm an absent-minded old-timer who has trouble
2
+ # learning new tricks.
3
+ .PHONY: all test
4
+
5
+ all: test
6
+
7
+ check:
8
+ rake test
9
+ test:
10
+ rake test
11
+
12
+ %:
13
+ rake $@
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('.gemspec'), binding, '.gemspec')
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 .gemspec"
18
+ sh "gem build #{Gemspec_filename}"
18
19
  FileUtils.mkdir_p 'pkg'
19
- FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", 'pkg'
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.name}-#{gemspec.version}}
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 ('*' * 10) + ' ' + directory + ' ' + ('*' * 10)
57
+ puts(('*' * 10) + ' ' + directory + ' ' + ('*' * 10))
55
58
  Dir.chdir(directory) do
56
59
  Dir.glob('*.rb').each do |ruby_file|
57
- puts ('-' * 20) + ' ' + ruby_file + ' ' + ('-' * 20)
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.verbose = true
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.verbose = true
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.verbose = true
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 library Ruby file in standalone mode."
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('lib/*.rb', 'app/*.rb', 'bin/trepan')
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
- set
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
@@ -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
+ }