openc3 5.5.2 → 5.6.0
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.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/openc3cli +167 -69
- data/data/config/_interfaces.yaml +1 -6
- data/data/config/interface_modifiers.yaml +55 -4
- data/data/config/microservice.yaml +30 -3
- data/ext/openc3/ext/crc/crc.c +82 -1
- data/lib/openc3/api/cmd_api.rb +19 -7
- data/lib/openc3/api/tlm_api.rb +13 -12
- data/lib/openc3/bridge/bridge_config.rb +4 -4
- data/lib/openc3/config/config_parser.rb +1 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +3 -1
- data/lib/openc3/ext/.keep +0 -0
- data/lib/openc3/interfaces/interface.rb +54 -26
- data/lib/openc3/interfaces/serial_interface.rb +4 -5
- data/lib/openc3/interfaces/simulated_target_interface.rb +4 -4
- data/lib/openc3/interfaces/stream_interface.rb +2 -2
- data/lib/openc3/interfaces/tcpip_client_interface.rb +4 -3
- data/lib/openc3/interfaces/tcpip_server_interface.rb +18 -19
- data/lib/openc3/interfaces/udp_interface.rb +10 -4
- data/lib/openc3/io/json_api.rb +72 -0
- data/lib/openc3/io/serial_driver.rb +4 -5
- data/lib/openc3/logs/buffered_packet_log_writer.rb +2 -4
- data/lib/openc3/logs/log_writer.rb +9 -8
- data/lib/openc3/logs/packet_log_reader.rb +8 -1
- data/lib/openc3/logs/packet_log_writer.rb +3 -4
- data/lib/openc3/logs/stream_log.rb +116 -0
- data/lib/openc3/logs/stream_log_pair.rb +70 -0
- data/lib/openc3/microservices/cleanup_microservice.rb +1 -1
- data/lib/openc3/microservices/decom_microservice.rb +17 -2
- data/lib/openc3/microservices/interface_decom_common.rb +42 -0
- data/lib/openc3/microservices/interface_microservice.rb +24 -17
- data/lib/openc3/microservices/router_microservice.rb +46 -4
- data/lib/openc3/migrations/20221202214600_add_target_names.rb +1 -1
- data/lib/openc3/migrations/20230319154100_log_stream.rb +40 -0
- data/lib/openc3/migrations/20230413101100_remove_log.rb +30 -0
- data/lib/openc3/models/gem_model.rb +2 -2
- data/lib/openc3/models/interface_model.rb +13 -14
- data/lib/openc3/models/metadata_model.rb +1 -1
- data/lib/openc3/models/note_model.rb +1 -1
- data/lib/openc3/models/plugin_model.rb +3 -2
- data/lib/openc3/operators/operator.rb +2 -0
- data/lib/openc3/packets/commands.rb +2 -0
- data/lib/openc3/packets/packet_config.rb +3 -2
- data/lib/openc3/packets/parsers/xtce_converter.rb +2 -1
- data/lib/openc3/script/gems.rb +125 -0
- data/lib/openc3/script/plugins.rb +186 -0
- data/lib/openc3/script/screen.rb +119 -0
- data/lib/openc3/script/script.rb +3 -0
- data/lib/openc3/script/script_runner.rb +19 -8
- data/lib/openc3/script/suite_results.rb +2 -2
- data/lib/openc3/script/web_socket_api.rb +5 -1
- data/lib/openc3/streams/serial_stream.rb +14 -11
- data/lib/openc3/streams/tcpip_client_stream.rb +5 -2
- data/lib/openc3/streams/tcpip_socket_stream.rb +37 -71
- data/lib/openc3/streams/web_socket_client_stream.rb +5 -3
- data/lib/openc3/system/system.rb +2 -0
- data/lib/openc3/topics/interface_topic.rb +13 -4
- data/lib/openc3/topics/router_topic.rb +6 -6
- data/lib/openc3/topics/telemetry_decom_topic.rb +10 -1
- data/lib/openc3/utilities/bucket_utilities.rb +12 -5
- data/lib/openc3/utilities/cli_generator.rb +56 -4
- data/lib/openc3/utilities/crc.rb +42 -7
- data/lib/openc3/utilities/process_manager.rb +3 -1
- data/lib/openc3/utilities/ruby_lex_utils.rb +265 -504
- data/lib/openc3/version.rb +6 -6
- data/templates/conversion/conversion.rb +10 -2
- data/templates/microservice/microservices/TEMPLATE/microservice.rb +1 -1
- data/templates/plugin/Rakefile +8 -1
- data/templates/widget/.browserslistrc +16 -0
- data/templates/widget/.eslintrc.js +43 -0
- data/templates/widget/.nycrc +3 -0
- data/templates/widget/.prettierrc.js +5 -0
- data/templates/widget/LICENSE.txt +20 -0
- data/templates/widget/Rakefile +24 -0
- data/templates/widget/babel.config.json +11 -0
- data/templates/widget/package.json +35 -0
- data/templates/widget/src/Widget.vue +46 -0
- data/templates/widget/vue.config.js +25 -0
- data/templates/widget/yarn.lock +8938 -0
- metadata +23 -4
- data/lib/openc3/io/raw_logger.rb +0 -170
- data/lib/openc3/io/raw_logger_pair.rb +0 -80
@@ -17,555 +17,316 @@
|
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
|
-
# This file may also be used under the terms of a commercial license
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'irb/ruby-lex'
|
24
24
|
require 'stringio'
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
26
|
+
# Clear the $VERBOSE global since we're overriding methods
|
27
|
+
old_verbose = $VERBOSE; $VERBOSE = nil
|
28
|
+
class RubyLex
|
29
|
+
attr_accessor :indent
|
30
|
+
attr_accessor :line_no
|
31
|
+
attr_accessor :exp_line_no
|
32
|
+
attr_accessor :tokens
|
33
|
+
attr_accessor :code_block_open
|
34
|
+
attr_accessor :ltype
|
35
|
+
attr_accessor :line
|
36
|
+
attr_accessor :continue
|
37
|
+
|
38
|
+
def reinitialize
|
39
|
+
@line_no = 1
|
40
|
+
@prompt = nil
|
41
|
+
initialize_input()
|
42
|
+
end
|
43
|
+
end
|
44
|
+
$VERBOSE = old_verbose
|
45
|
+
|
46
|
+
class RubyLexUtils
|
47
|
+
# Regular expression to detect blank lines
|
48
|
+
BLANK_LINE_REGEX = /^\s*$/
|
49
|
+
# Regular expression to detect lines containing only 'else'
|
50
|
+
LONELY_ELSE_REGEX = /^\s*else\s*$/
|
51
|
+
|
52
|
+
KEY_KEYWORDS = [
|
53
|
+
'class'.freeze,
|
54
|
+
'module'.freeze,
|
55
|
+
'def'.freeze,
|
56
|
+
'undef'.freeze,
|
57
|
+
'begin'.freeze,
|
58
|
+
'rescue'.freeze,
|
59
|
+
'ensure'.freeze,
|
60
|
+
'end'.freeze,
|
61
|
+
'if'.freeze,
|
62
|
+
'unless'.freeze,
|
63
|
+
'then'.freeze,
|
64
|
+
'elsif'.freeze,
|
65
|
+
'else'.freeze,
|
66
|
+
'case'.freeze,
|
67
|
+
'when'.freeze,
|
68
|
+
'while'.freeze,
|
69
|
+
'until'.freeze,
|
70
|
+
'for'.freeze,
|
71
|
+
'break'.freeze,
|
72
|
+
'next'.freeze,
|
73
|
+
'redo'.freeze,
|
74
|
+
'retry'.freeze,
|
75
|
+
'in'.freeze,
|
76
|
+
'do'.freeze,
|
77
|
+
'return'.freeze,
|
78
|
+
'alias'.freeze
|
79
|
+
]
|
80
|
+
|
81
|
+
# Create a new RubyLex and StringIO to hold the text to operate on
|
82
|
+
def initialize
|
83
|
+
@lex = RubyLex.new
|
84
|
+
@lex_io = StringIO.new('')
|
85
|
+
end
|
39
86
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
87
|
+
if RUBY_VERSION >= "3.0"
|
88
|
+
def ripper_lex_without_warning(code)
|
89
|
+
RubyLex.ripper_lex_without_warning(code)
|
90
|
+
end
|
91
|
+
else
|
92
|
+
def ripper_lex_without_warning(code)
|
93
|
+
@lex.ripper_lex_without_warning(code)
|
44
94
|
end
|
45
95
|
end
|
46
|
-
$VERBOSE = old_verbose
|
47
96
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
'
|
57
|
-
|
58
|
-
|
59
|
-
'begin'.freeze,
|
60
|
-
'rescue'.freeze,
|
61
|
-
'ensure'.freeze,
|
62
|
-
'end'.freeze,
|
63
|
-
'if'.freeze,
|
64
|
-
'unless'.freeze,
|
65
|
-
'then'.freeze,
|
66
|
-
'elsif'.freeze,
|
67
|
-
'else'.freeze,
|
68
|
-
'case'.freeze,
|
69
|
-
'when'.freeze,
|
70
|
-
'while'.freeze,
|
71
|
-
'until'.freeze,
|
72
|
-
'for'.freeze,
|
73
|
-
'break'.freeze,
|
74
|
-
'next'.freeze,
|
75
|
-
'redo'.freeze,
|
76
|
-
'retry'.freeze,
|
77
|
-
'in'.freeze,
|
78
|
-
'do'.freeze,
|
79
|
-
'return'.freeze,
|
80
|
-
'alias'.freeze
|
81
|
-
]
|
82
|
-
|
83
|
-
# Create a new RubyLex and StringIO to hold the text to operate on
|
84
|
-
def initialize
|
85
|
-
@lex = RubyLex.new
|
86
|
-
@lex_io = StringIO.new('')
|
97
|
+
# @param text [String]
|
98
|
+
# @return [Boolean] Whether the text contains the 'begin' keyword
|
99
|
+
def contains_begin?(text)
|
100
|
+
@lex.reinitialize
|
101
|
+
@lex_io.string = text
|
102
|
+
@lex.set_input(@lex_io)
|
103
|
+
tokens = ripper_lex_without_warning(text)
|
104
|
+
tokens.each do |token|
|
105
|
+
if token[1] == :on_kw and token[2] == 'begin'
|
106
|
+
return true
|
107
|
+
end
|
87
108
|
end
|
109
|
+
return false
|
110
|
+
end
|
88
111
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
112
|
+
# @param text [String]
|
113
|
+
# @return [Boolean] Whether the text contains the 'end' keyword
|
114
|
+
def contains_end?(text)
|
115
|
+
@lex.reinitialize
|
116
|
+
@lex_io.string = text
|
117
|
+
@lex.set_input(@lex_io)
|
118
|
+
tokens = ripper_lex_without_warning(text)
|
119
|
+
tokens.each do |token|
|
120
|
+
if token[1] == :on_kw and token[2] == 'end'
|
121
|
+
return true
|
96
122
|
end
|
97
123
|
end
|
124
|
+
return false
|
125
|
+
end
|
98
126
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
127
|
+
# @param text [String]
|
128
|
+
# @return [Boolean] Whether the text contains a Ruby keyword
|
129
|
+
def contains_keyword?(text)
|
130
|
+
@lex.reinitialize
|
131
|
+
@lex_io.string = text
|
132
|
+
@lex.set_input(@lex_io)
|
133
|
+
tokens = ripper_lex_without_warning(text)
|
134
|
+
tokens.each do |token|
|
135
|
+
if token[1] == :on_kw
|
136
|
+
if KEY_KEYWORDS.include?(token[2])
|
108
137
|
return true
|
109
138
|
end
|
139
|
+
elsif token[1] == :on_lbrace and !token[3].allbits?(Ripper::EXPR_BEG | Ripper::EXPR_LABEL)
|
140
|
+
return true
|
110
141
|
end
|
111
|
-
return false
|
112
142
|
end
|
143
|
+
return false
|
144
|
+
end
|
113
145
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
-
elsif token[1] == :on_lbrace and !token[3].allbits?(Ripper::EXPR_BEG | Ripper::EXPR_LABEL)
|
146
|
+
# @param text [String]
|
147
|
+
# @return [Boolean] Whether the text contains a keyword which starts a block.
|
148
|
+
# i.e. 'do', '{', or 'begin'
|
149
|
+
def contains_block_beginning?(text)
|
150
|
+
@lex.reinitialize
|
151
|
+
@lex_io.string = text
|
152
|
+
@lex.set_input(@lex_io)
|
153
|
+
tokens = ripper_lex_without_warning(text)
|
154
|
+
tokens.each do |token|
|
155
|
+
if token[1] == :on_kw
|
156
|
+
if token[2] == 'begin' || token[2] == 'do'
|
127
157
|
return true
|
128
158
|
end
|
159
|
+
elsif token[1] == :on_lbrace
|
160
|
+
return true
|
129
161
|
end
|
130
|
-
return false
|
131
162
|
end
|
163
|
+
return false
|
164
|
+
end
|
132
165
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
if token[2] == 'begin' || token[2] == 'do'
|
144
|
-
return true
|
145
|
-
end
|
146
|
-
elsif token[1] == :on_lbrace
|
147
|
-
return true
|
148
|
-
end
|
149
|
-
end
|
150
|
-
return false
|
166
|
+
def continue_block?(text)
|
167
|
+
@lex.reinitialize
|
168
|
+
@lex_io.string = text
|
169
|
+
@lex.set_input(@lex_io)
|
170
|
+
tokens = RubyLex.ripper_lex_without_warning(text)
|
171
|
+
index = tokens.length - 1
|
172
|
+
while index > 0
|
173
|
+
token = tokens[index]
|
174
|
+
return true if token[1] == :on_kw and token[2] == "do"
|
175
|
+
index -= 1
|
151
176
|
end
|
177
|
+
return false
|
178
|
+
end
|
152
179
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
end
|
180
|
+
# @param text [String]
|
181
|
+
# @param progress_dialog [OpenC3::ProgressDialog] If this is set, the overall
|
182
|
+
# progress will be set as the processing progresses
|
183
|
+
# @return [String] The text with all comments removed
|
184
|
+
def remove_comments(text, progress_dialog = nil)
|
185
|
+
@lex.reinitialize
|
186
|
+
@lex_io.string = text
|
187
|
+
@lex.set_input(@lex_io)
|
188
|
+
comments_removed = ""
|
189
|
+
token_count = 0
|
190
|
+
progress = 0.0
|
191
|
+
tokens = ripper_lex_without_warning(text)
|
192
|
+
tokens.each do |token|
|
193
|
+
token_count += 1
|
194
|
+
if token[1] != :on_comment
|
195
|
+
comments_removed << token[2]
|
196
|
+
else
|
197
|
+
newline_count = token[2].count("\n")
|
198
|
+
comments_removed << ("\n" * newline_count)
|
199
|
+
end
|
200
|
+
if progress_dialog and token_count % 10000 == 0
|
201
|
+
progress += 0.01
|
202
|
+
progress = 0.0 if progress >= 0.99
|
203
|
+
progress_dialog.set_overall_progress(progress)
|
178
204
|
end
|
179
|
-
|
180
|
-
return comments_removed
|
181
205
|
end
|
182
206
|
|
183
|
-
|
184
|
-
|
185
|
-
# @param text [String]
|
186
|
-
# @yieldparam line [String] The entire line
|
187
|
-
# @yieldparam instrumentable [Boolean] Whether the line is instrumentable
|
188
|
-
# @yieldparam inside_begin [Integer] The level of indentation
|
189
|
-
# @yieldparam line_no [Integer] The current line number
|
190
|
-
def each_lexed_segment(text)
|
191
|
-
inside_begin = false
|
192
|
-
indent = 0
|
193
|
-
lex = RubyLex.new
|
194
|
-
lex_io = StringIO.new(text)
|
195
|
-
lex.set_input(lex_io)
|
196
|
-
lex.line = ''
|
197
|
-
while lexed = lex.lex
|
198
|
-
lex.line_no += lexed.count("\n")
|
199
|
-
lex.line.concat lexed
|
200
|
-
next if lex.ltype or lex.continue
|
201
|
-
|
202
|
-
# Detect the beginning and end of begin blocks so we can not catch exceptions there
|
203
|
-
if indent == 0 and contains_begin?(lex.line)
|
204
|
-
inside_begin = true
|
205
|
-
indent = lex.indent
|
206
|
-
else
|
207
|
-
indent += lex.indent if indent > 0
|
208
|
-
end
|
209
|
-
|
210
|
-
if inside_begin and indent <= 0
|
211
|
-
indent = 0
|
212
|
-
inside_begin = false
|
213
|
-
end
|
214
|
-
|
215
|
-
loop do # loop to allow restarting for nested conditions
|
216
|
-
# Yield blank lines and lonely else lines before the actual line
|
217
|
-
while (index = lex.line.index("\n"))
|
218
|
-
line = lex.line[0..index]
|
219
|
-
if BLANK_LINE_REGEX.match?(line)
|
220
|
-
yield line, true, inside_begin, lex.exp_line_no
|
221
|
-
lex.exp_line_no += 1
|
222
|
-
lex.line = lex.line[(index + 1)..-1]
|
223
|
-
elsif LONELY_ELSE_REGEX.match?(line)
|
224
|
-
yield line, false, inside_begin, lex.exp_line_no
|
225
|
-
lex.exp_line_no += 1
|
226
|
-
lex.line = lex.line[(index + 1)..-1]
|
227
|
-
else
|
228
|
-
break
|
229
|
-
end
|
230
|
-
end
|
207
|
+
return comments_removed
|
208
|
+
end
|
231
209
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
210
|
+
# Yields each lexed segment and if the segment is instrumentable
|
211
|
+
#
|
212
|
+
# @param text [String]
|
213
|
+
# @yieldparam line [String] The entire line
|
214
|
+
# @yieldparam instrumentable [Boolean] Whether the line is instrumentable
|
215
|
+
# @yieldparam inside_begin [Integer] The level of indentation
|
216
|
+
# @yieldparam line_no [Integer] The current line number
|
217
|
+
def each_lexed_segment(text)
|
218
|
+
inside_begin = false
|
219
|
+
lex = RubyLex.new
|
220
|
+
lex_io = StringIO.new(text)
|
221
|
+
lex.set_input(lex_io)
|
222
|
+
lex.line = ''
|
223
|
+
line = ''
|
224
|
+
continue_indent = nil
|
225
|
+
begin_indent = nil
|
226
|
+
previous_indent = 0
|
227
|
+
|
228
|
+
while lexed = lex.lex
|
229
|
+
#puts "lexed = #{lexed.chomp}, indent = #{lex.indent}, continue = #{lex.continue}"
|
230
|
+
lex.line_no += lexed.count("\n")
|
231
|
+
lex.line.concat lexed
|
232
|
+
line.concat lexed
|
233
|
+
if lex.continue
|
234
|
+
if not continue_block?(lexed)
|
235
|
+
unless continue_indent
|
236
|
+
if (lex.indent - previous_indent) > 1
|
237
|
+
continue_indent = lex.indent - 1
|
256
238
|
else
|
257
|
-
|
239
|
+
continue_indent = previous_indent
|
258
240
|
end
|
259
241
|
end
|
260
|
-
|
261
|
-
lex.exp_line_no = lex.line_no
|
262
|
-
lex.indent = 0
|
263
|
-
break
|
264
|
-
end # loop do
|
265
|
-
end # while lexed
|
266
|
-
end # def each_lexed_segment
|
267
|
-
end
|
268
|
-
|
269
|
-
else
|
270
|
-
|
271
|
-
# Clear the $VERBOSE global since we're overriding methods
|
272
|
-
old_verbose = $VERBOSE; $VERBOSE = nil
|
273
|
-
class RubyLex
|
274
|
-
if self.method_defined?(:indent)
|
275
|
-
attr_writer :indent
|
276
|
-
else
|
277
|
-
attr_accessor :indent
|
278
|
-
end
|
279
|
-
# @return [Integer] The expression line number. This can differ from the
|
280
|
-
# actual line number due to white space and Ruby control keywords.
|
281
|
-
attr_accessor :exp_line_no
|
282
|
-
|
283
|
-
# Resets the RubyLex in preparation of parsing a line
|
284
|
-
def reinitialize
|
285
|
-
@seek = 0
|
286
|
-
@exp_line_no = 1
|
287
|
-
@line_no = 1
|
288
|
-
@base_char_no = 0
|
289
|
-
@char_no = 0
|
290
|
-
@rests.clear
|
291
|
-
@readed.clear
|
292
|
-
@here_readed.clear
|
293
|
-
@indent = 0
|
294
|
-
@indent_stack.clear
|
295
|
-
@lex_state = EXPR_BEG
|
296
|
-
@space_seen = false
|
297
|
-
@here_header = false
|
298
|
-
@continue = false
|
299
|
-
@line = ''
|
300
|
-
@skip_space = false
|
301
|
-
@readed_auto_clean_up = false
|
302
|
-
@exception_on_syntax_error = true
|
303
|
-
@prompt = nil
|
304
|
-
end
|
305
|
-
|
306
|
-
# Monkey patch to keep this from looping forever if the string never is closed with a right brace
|
307
|
-
def identify_string_dvar
|
308
|
-
getc
|
309
|
-
|
310
|
-
reserve_continue = @continue
|
311
|
-
reserve_ltype = @ltype
|
312
|
-
reserve_indent = @indent
|
313
|
-
reserve_indent_stack = @indent_stack
|
314
|
-
reserve_state = @lex_state
|
315
|
-
reserve_quoted = @quoted
|
316
|
-
|
317
|
-
@ltype = nil
|
318
|
-
@quoted = nil
|
319
|
-
@indent = 0
|
320
|
-
@indent_stack = []
|
321
|
-
@lex_state = EXPR_BEG
|
322
|
-
|
323
|
-
loop do
|
324
|
-
@continue = false
|
325
|
-
prompt
|
326
|
-
tk = token
|
327
|
-
break if tk.nil? # This is the patch
|
328
|
-
if @ltype or @continue or @indent >= 0
|
242
|
+
#puts "continue_indent = #{continue_indent}"
|
329
243
|
next
|
330
244
|
end
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
$VERBOSE = old_verbose
|
343
|
-
|
344
|
-
class RubyLexUtils
|
345
|
-
# Regular expression to detect blank lines
|
346
|
-
BLANK_LINE_REGEX = /^\s*$/
|
347
|
-
# Regular expression to detect lines containing only 'else'
|
348
|
-
LONELY_ELSE_REGEX = /^\s*else\s*$/
|
349
|
-
|
350
|
-
# Ruby keywords
|
351
|
-
KEYWORD_TOKENS = [RubyToken::TkCLASS,
|
352
|
-
RubyToken::TkMODULE,
|
353
|
-
RubyToken::TkDEF,
|
354
|
-
RubyToken::TkUNDEF,
|
355
|
-
RubyToken::TkBEGIN,
|
356
|
-
RubyToken::TkRESCUE,
|
357
|
-
RubyToken::TkENSURE,
|
358
|
-
RubyToken::TkEND,
|
359
|
-
RubyToken::TkIF,
|
360
|
-
RubyToken::TkUNLESS,
|
361
|
-
RubyToken::TkTHEN,
|
362
|
-
RubyToken::TkELSIF,
|
363
|
-
RubyToken::TkELSE,
|
364
|
-
RubyToken::TkCASE,
|
365
|
-
RubyToken::TkWHEN,
|
366
|
-
RubyToken::TkWHILE,
|
367
|
-
RubyToken::TkUNTIL,
|
368
|
-
RubyToken::TkFOR,
|
369
|
-
RubyToken::TkBREAK,
|
370
|
-
RubyToken::TkNEXT,
|
371
|
-
RubyToken::TkREDO,
|
372
|
-
RubyToken::TkRETRY,
|
373
|
-
RubyToken::TkIN,
|
374
|
-
RubyToken::TkDO,
|
375
|
-
RubyToken::TkRETURN,
|
376
|
-
RubyToken::TkIF_MOD,
|
377
|
-
RubyToken::TkUNLESS_MOD,
|
378
|
-
RubyToken::TkWHILE_MOD,
|
379
|
-
RubyToken::TkUNTIL_MOD,
|
380
|
-
RubyToken::TkALIAS,
|
381
|
-
RubyToken::TklBEGIN,
|
382
|
-
RubyToken::TklEND,
|
383
|
-
RubyToken::TkfLBRACE]
|
384
|
-
|
385
|
-
# Ruby keywords which define the beginning of a block: do, {, begin
|
386
|
-
BLOCK_BEGINNING_TOKENS = [RubyToken::TkDO,
|
387
|
-
RubyToken::TkfLBRACE,
|
388
|
-
RubyToken::TkBEGIN]
|
389
|
-
|
390
|
-
# Create a new RubyLex and StringIO to hold the text to operate on
|
391
|
-
def initialize
|
392
|
-
@lex = RubyLex.new
|
393
|
-
@lex_io = StringIO.new('')
|
394
|
-
end
|
395
|
-
|
396
|
-
# @param text [String]
|
397
|
-
# @return [Boolean] Whether the text contains the 'begin' keyword
|
398
|
-
def contains_begin?(text)
|
399
|
-
@lex.reinitialize
|
400
|
-
@lex.exception_on_syntax_error = false
|
401
|
-
@lex_io.string = text
|
402
|
-
@lex.set_input(@lex_io)
|
403
|
-
while token = @lex.token
|
404
|
-
if token.class == RubyToken::TkBEGIN
|
405
|
-
return true
|
406
|
-
end
|
407
|
-
end
|
408
|
-
return false
|
409
|
-
end
|
410
|
-
|
411
|
-
# @param text [String]
|
412
|
-
# @return [Boolean] Whether the text contains a Ruby keyword
|
413
|
-
def contains_keyword?(text)
|
414
|
-
@lex.reinitialize
|
415
|
-
@lex.exception_on_syntax_error = false
|
416
|
-
@lex_io.string = text
|
417
|
-
@lex.set_input(@lex_io)
|
418
|
-
while token = @lex.token
|
419
|
-
if KEYWORD_TOKENS.include?(token.class)
|
420
|
-
return true
|
421
|
-
end
|
422
|
-
end
|
423
|
-
return false
|
424
|
-
end
|
425
|
-
|
426
|
-
# @param text [String]
|
427
|
-
# @return [Boolean] Whether the text contains a keyword which starts a block.
|
428
|
-
# i.e. 'do', '{', or 'begin'
|
429
|
-
def contains_block_beginning?(text)
|
430
|
-
@lex.reinitialize
|
431
|
-
@lex.exception_on_syntax_error = false
|
432
|
-
@lex_io.string = text
|
433
|
-
@lex.set_input(@lex_io)
|
434
|
-
while token = @lex.token
|
435
|
-
if BLOCK_BEGINNING_TOKENS.include?(token.class)
|
436
|
-
return true
|
245
|
+
elsif continue_indent
|
246
|
+
if lex.indent > continue_indent
|
247
|
+
next
|
248
|
+
else
|
249
|
+
yield line, !contains_keyword?(line), inside_begin, lex.exp_line_no
|
250
|
+
line = ''
|
251
|
+
lex.exp_line_no = lex.line_no
|
252
|
+
if lex.indent == 0
|
253
|
+
lex.line = ''
|
254
|
+
end
|
255
|
+
next
|
437
256
|
end
|
438
257
|
end
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
@lex_io.string = text
|
451
|
-
@lex.set_input(@lex_io)
|
452
|
-
need_remove = nil
|
453
|
-
delete_ranges = []
|
454
|
-
token_count = 0
|
455
|
-
progress = 0.0
|
456
|
-
while token = @lex.token
|
457
|
-
token_count += 1
|
458
|
-
if need_remove
|
459
|
-
delete_ranges << (need_remove..(token.seek - 1))
|
460
|
-
need_remove = nil
|
461
|
-
end
|
462
|
-
if token.class == RubyToken::TkCOMMENT
|
463
|
-
need_remove = token.seek
|
464
|
-
end
|
465
|
-
if progress_dialog and token_count % 10000 == 0
|
466
|
-
progress += 0.01
|
467
|
-
progress = 0.0 if progress >= 0.99
|
468
|
-
progress_dialog.set_overall_progress(progress)
|
258
|
+
previous_indent = lex.indent
|
259
|
+
continue_indent = nil
|
260
|
+
|
261
|
+
# Detect the beginning and end of begin blocks so we can not catch exceptions there
|
262
|
+
if contains_begin?(line)
|
263
|
+
if contains_end?(line)
|
264
|
+
# Assume the user is being fancy with a single line begin; end;
|
265
|
+
# Ignore
|
266
|
+
else
|
267
|
+
inside_begin = true
|
268
|
+
begin_indent = lex.indent unless begin_indent # Don't restart for nested begins
|
469
269
|
end
|
470
270
|
end
|
471
271
|
|
472
|
-
if
|
473
|
-
|
474
|
-
|
272
|
+
if inside_begin and lex.indent < begin_indent
|
273
|
+
begin_indent = nil
|
274
|
+
inside_begin = false
|
475
275
|
end
|
476
276
|
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
# Yields each lexed segment and if the segment is instrumentable
|
492
|
-
#
|
493
|
-
# @param text [String]
|
494
|
-
# @yieldparam line [String] The entire line
|
495
|
-
# @yieldparam instrumentable [Boolean] Whether the line is instrumentable
|
496
|
-
# @yieldparam inside_begin [Integer] The level of indentation
|
497
|
-
# @yieldparam line_no [Integer] The current line number
|
498
|
-
def each_lexed_segment(text)
|
499
|
-
inside_begin = false
|
500
|
-
inside_indent = nil
|
501
|
-
lex = RubyLex.new
|
502
|
-
lex.exception_on_syntax_error = false
|
503
|
-
lex_io = StringIO.new(text)
|
504
|
-
lex.set_input(lex_io)
|
505
|
-
|
506
|
-
while lexed = lex.lex
|
507
|
-
line_no = lex.exp_line_no
|
508
|
-
|
509
|
-
if inside_indent.nil? and contains_begin?(lexed)
|
510
|
-
inside_indent = lex.indent - 1
|
511
|
-
inside_begin = true
|
512
|
-
end
|
513
|
-
|
514
|
-
if lex.indent == inside_indent
|
515
|
-
inside_indent = nil
|
516
|
-
inside_begin = false
|
517
|
-
end
|
518
|
-
|
519
|
-
loop do # loop to allow restarting for nested conditions
|
520
|
-
# Yield blank lines and lonely else lines before the actual line
|
521
|
-
while (index = lexed.index("\n"))
|
522
|
-
line = lexed[0..index]
|
523
|
-
if BLANK_LINE_REGEX.match?(line)
|
524
|
-
yield line, true, inside_begin, line_no
|
525
|
-
line_no += 1
|
526
|
-
lexed = lexed[(index + 1)..-1]
|
527
|
-
elsif LONELY_ELSE_REGEX.match?(line)
|
528
|
-
yield line, false, inside_begin, line_no
|
529
|
-
line_no += 1
|
530
|
-
lexed = lexed[(index + 1)..-1]
|
531
|
-
else
|
532
|
-
break
|
533
|
-
end
|
277
|
+
loop do # loop to allow restarting for nested conditions
|
278
|
+
# Yield blank lines and lonely else lines before the actual line
|
279
|
+
while (index = line.index("\n"))
|
280
|
+
one_line = line[0..index]
|
281
|
+
if BLANK_LINE_REGEX.match?(one_line)
|
282
|
+
yield one_line, true, inside_begin, lex.exp_line_no
|
283
|
+
lex.exp_line_no += 1
|
284
|
+
line = line[(index + 1)..-1]
|
285
|
+
elsif LONELY_ELSE_REGEX.match?(one_line)
|
286
|
+
yield one_line, false, inside_begin, lex.exp_line_no
|
287
|
+
lex.exp_line_no += 1
|
288
|
+
line = line[(index + 1)..-1]
|
289
|
+
else
|
290
|
+
break
|
534
291
|
end
|
292
|
+
end
|
535
293
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
end
|
545
|
-
line_no += 1
|
294
|
+
if contains_keyword?(line)
|
295
|
+
if contains_block_beginning?(line)
|
296
|
+
section = ''
|
297
|
+
line.each_line do |lexed_part|
|
298
|
+
section << lexed_part
|
299
|
+
if contains_block_beginning?(section)
|
300
|
+
yield section, false, inside_begin, lex.exp_line_no
|
301
|
+
break
|
546
302
|
end
|
547
|
-
|
548
|
-
remainder = lexed[(section.length)..-1]
|
549
|
-
lexed = remainder
|
550
|
-
next unless remainder.empty?
|
551
|
-
else
|
552
|
-
yield lexed, false, inside_begin, line_no
|
553
|
-
end
|
554
|
-
elsif !lexed.empty?
|
555
|
-
num_left_brackets = lexed.count('{')
|
556
|
-
num_right_brackets = lexed.count('}')
|
557
|
-
if num_left_brackets != num_right_brackets
|
558
|
-
# Don't instrument lines with unequal numbers of { and } brackets
|
559
|
-
yield lexed, false, inside_begin, line_no
|
560
|
-
else
|
561
|
-
yield lexed, true, inside_begin, line_no
|
303
|
+
lex.exp_line_no += 1
|
562
304
|
end
|
305
|
+
lex.exp_line_no += 1
|
306
|
+
remainder = line[(section.length)..-1]
|
307
|
+
line = remainder
|
308
|
+
next unless remainder.empty?
|
309
|
+
else
|
310
|
+
yield line, false, inside_begin, lex.exp_line_no
|
563
311
|
end
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
312
|
+
elsif !line.empty?
|
313
|
+
num_left_brackets = line.count('{')
|
314
|
+
num_right_brackets = line.count('}')
|
315
|
+
if num_left_brackets != num_right_brackets
|
316
|
+
# Don't instrument lines with unequal numbers of { and } brackets
|
317
|
+
yield line, false, inside_begin, lex.exp_line_no
|
318
|
+
else
|
319
|
+
yield line, true, inside_begin, lex.exp_line_no
|
320
|
+
end
|
321
|
+
end
|
322
|
+
line = ''
|
323
|
+
lex.exp_line_no = lex.line_no
|
324
|
+
break
|
325
|
+
end # loop do
|
570
326
|
|
571
|
-
|
327
|
+
if lex.indent == 0
|
328
|
+
lex.line = ''
|
329
|
+
end
|
330
|
+
end # while lexed
|
331
|
+
end # def each_lexed_segment
|
332
|
+
end
|