Class: IOSParser::PureLexer
- Inherits:
-
Object
- Object
- IOSParser::PureLexer
- Defined in:
- lib/ios_parser/lexer.rb
Constant Summary collapse
- LexError =
IOSParser::LexError
- ROOT_TRANSITIONS =
[ :space, :banner_begin, :certificate_begin, :newline, :comment, :integer, :quoted_string, :word ].freeze
Instance Attribute Summary collapse
-
#char ⇒ Object
Returns the value of attribute char.
-
#indent ⇒ Object
Returns the value of attribute indent.
-
#indents ⇒ Object
Returns the value of attribute indents.
-
#line ⇒ Object
Returns the value of attribute line.
-
#start_of_line ⇒ Object
Returns the value of attribute start_of_line.
-
#state ⇒ Object
Returns the value of attribute state.
-
#string_terminator ⇒ Object
Returns the value of attribute string_terminator.
-
#token ⇒ Object
Returns the value of attribute token.
-
#token_line ⇒ Object
Returns the value of attribute token_line.
-
#tokens ⇒ Object
Returns the value of attribute tokens.
Instance Method Summary collapse
- #banner ⇒ Object
- #banner_begin ⇒ Object
- #banner_begin? ⇒ Boolean
- #banner_end_char ⇒ Object
- #banner_end_char? ⇒ Boolean
- #banner_end_clean_token ⇒ Object
- #banner_end_string ⇒ Object
- #banner_end_string? ⇒ Boolean
- #banner_garbage?(pos) ⇒ Boolean
- #call(input_text) ⇒ Object
- #certificate ⇒ Object
- #certificate_begin ⇒ Object
- #certificate_begin? ⇒ Boolean
- #certificate_end ⇒ Object
-
#certificate_end_tokens ⇒ Object
rubocop: disable AbcSize.
-
#certificate_token_value ⇒ Object
rubocop: enable AbcSize.
- #comment ⇒ Object
- #comment? ⇒ Boolean
- #comment_newline ⇒ Object
- #decimal ⇒ Object
- #decimal? ⇒ Boolean
- #decimal_token ⇒ Object
- #delimit ⇒ Object
- #digit? ⇒ Boolean (also: #integer?)
- #dot? ⇒ Boolean
- #finalize ⇒ Object
- #find_start_of_line(from: @this_char) ⇒ Object
-
#initialize ⇒ PureLexer
constructor
A new instance of PureLexer.
- #integer ⇒ Object
- #integer_token ⇒ Object
- #lead_comment? ⇒ Boolean
- #line_start ⇒ Object
- #make_token(value, pos: nil, col: nil) ⇒ Object
- #newline ⇒ Object
- #newline? ⇒ Boolean
- #pop_dedent ⇒ Object
- #push_indent ⇒ Object
- #quoted_string ⇒ Object
- #quoted_string? ⇒ Boolean
- #quoted_string_token ⇒ Object
- #root ⇒ Object
- #root_line_start ⇒ Object
- #scrub_banner_garbage ⇒ Object
- #space ⇒ Object
- #space? ⇒ Boolean
- #update_indentation ⇒ Object
- #word ⇒ Object
- #word? ⇒ Boolean
- #word_token ⇒ Object
Constructor Details
#initialize ⇒ PureLexer
Returns a new instance of PureLexer.
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/ios_parser/lexer.rb', line 9 def initialize @text = '' @token = '' @tokens = [] @indent = 0 @indents = [0] @state = :root @this_char = -1 @line = 1 @start_of_line = 0 @token_line = 0 end |
Instance Attribute Details
#char ⇒ Object
Returns the value of attribute char.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def char @char end |
#indent ⇒ Object
Returns the value of attribute indent.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def indent @indent end |
#indents ⇒ Object
Returns the value of attribute indents.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def indents @indents end |
#line ⇒ Object
Returns the value of attribute line.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def line @line end |
#start_of_line ⇒ Object
Returns the value of attribute start_of_line.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def start_of_line @start_of_line end |
#state ⇒ Object
Returns the value of attribute state.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def state @state end |
#string_terminator ⇒ Object
Returns the value of attribute string_terminator.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def string_terminator @string_terminator end |
#token ⇒ Object
Returns the value of attribute token.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def token @token end |
#token_line ⇒ Object
Returns the value of attribute token_line.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def token_line @token_line end |
#tokens ⇒ Object
Returns the value of attribute tokens.
5 6 7 |
# File 'lib/ios_parser/lexer.rb', line 5 def tokens @tokens end |
Instance Method Details
#banner ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/ios_parser/lexer.rb', line 122 def self.token_line += 1 if newline? if elsif else token << char end end |
#banner_begin ⇒ Object
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/ios_parser/lexer.rb', line 104 def self.state = :banner self.token_line = 0 tokens << make_token(:BANNER_BEGIN) @token_start = @this_char + 2 @banner_delimiter = char == "\n" ? 'EOF' : char return unless @text[@this_char + 1] == "\n" self.token_line -= 1 self.line += 1 end |
#banner_begin? ⇒ Boolean
115 116 117 118 119 120 |
# File 'lib/ios_parser/lexer.rb', line 115 def tokens[-2] && ( tokens[-2].value == 'banner' || tokens[-2..-1].map(&:value) == %w[authentication banner] ) end |
#banner_end_char ⇒ Object
148 149 150 151 152 153 154 155 156 |
# File 'lib/ios_parser/lexer.rb', line 148 def self.state = :root tokens << make_token(token) self.line += token_line find_start_of_line tokens << make_token(:BANNER_END) self.token = '' end |
#banner_end_char? ⇒ Boolean
158 159 160 161 |
# File 'lib/ios_parser/lexer.rb', line 158 def char == @banner_delimiter && (@text[@this_char - 1] == "\n" || @text[@this_char + 1] == "\n") end |
#banner_end_clean_token ⇒ Object
163 164 165 166 |
# File 'lib/ios_parser/lexer.rb', line 163 def token.slice!(0) if token[0] == 'C' token.slice!(0) if ["\n", ' '].include?(token[0]) end |
#banner_end_string ⇒ Object
134 135 136 137 138 139 140 141 142 |
# File 'lib/ios_parser/lexer.rb', line 134 def self.state = :root token.chomp!(@banner_delimiter[0..-2]) tokens << make_token(token) self.line += token_line find_start_of_line tokens << make_token(:BANNER_END) self.token = '' end |
#banner_end_string? ⇒ Boolean
144 145 146 |
# File 'lib/ios_parser/lexer.rb', line 144 def @banner_delimiter.size > 1 && (token + char).end_with?(@banner_delimiter) end |
#banner_garbage?(pos) ⇒ Boolean
175 176 177 |
# File 'lib/ios_parser/lexer.rb', line 175 def (pos) tokens[pos].value == :BANNER_END && tokens[pos + 1].value == 'C' end |
#call(input_text) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/ios_parser/lexer.rb', line 22 def call(input_text) @text = input_text input_text.each_char.with_index do |c, i| @this_char = i self.char = c send(state) end finalize end |
#certificate ⇒ Object
192 193 194 195 196 197 198 199 |
# File 'lib/ios_parser/lexer.rb', line 192 def certificate if token.end_with?("quit\n") certificate_end else self.token_line += 1 if char == "\n" token << char end end |
#certificate_begin ⇒ Object
184 185 186 187 188 189 190 |
# File 'lib/ios_parser/lexer.rb', line 184 def certificate_begin self.state = :certificate indents.pop tokens[-2..-1] = [make_token(:CERTIFICATE_BEGIN, pos: tokens[-1].pos)] self.token_line = 0 certificate end |
#certificate_begin? ⇒ Boolean
179 180 181 182 |
# File 'lib/ios_parser/lexer.rb', line 179 def certificate_begin? tokens[-6] && tokens[-6].value == :INDENT && tokens[-5] && tokens[-5].value == 'certificate' end |
#certificate_end ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/ios_parser/lexer.rb', line 201 def certificate_end tokens.concat certificate_end_tokens self.line += 1 update_indentation @token_start = @this_char @token = '' self.state = :line_start self.indent = 0 self.line += 1 root end |
#certificate_end_tokens ⇒ Object
rubocop: disable AbcSize
215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/ios_parser/lexer.rb', line 215 def certificate_end_tokens cluster = [] cluster << make_token(certificate_token_value, pos: tokens[-1].pos) self.line += self.token_line - 1 cluster << make_token(:CERTIFICATE_END, pos: @this_char, col: 1) find_start_of_line(from: @this_char - 2) cluster << make_token(:EOL, pos: @this_char, col: @this_char - start_of_line) cluster end |
#certificate_token_value ⇒ Object
rubocop: enable AbcSize
228 229 230 |
# File 'lib/ios_parser/lexer.rb', line 228 def certificate_token_value token[0..-6].gsub!(/\s+/, ' ').strip end |
#comment ⇒ Object
81 82 83 84 85 86 |
# File 'lib/ios_parser/lexer.rb', line 81 def comment self.state = :comment tokens << make_token(:EOL) if tokens.last && !tokens.last.value.is_a?(Symbol) comment_newline if newline? end |
#comment? ⇒ Boolean
96 97 98 |
# File 'lib/ios_parser/lexer.rb', line 96 def comment? char == '!' end |
#comment_newline ⇒ Object
88 89 90 91 92 93 94 |
# File 'lib/ios_parser/lexer.rb', line 88 def comment_newline delimit self.start_of_line = @this_char + 1 self.state = :line_start self.indent = 0 self.line += 1 end |
#decimal ⇒ Object
254 255 256 257 258 259 260 261 |
# File 'lib/ios_parser/lexer.rb', line 254 def decimal self.state = :decimal if digit? then token << char elsif dot? then token << char elsif word? then word else root end end |
#decimal? ⇒ Boolean
271 272 273 |
# File 'lib/ios_parser/lexer.rb', line 271 def decimal? dot? || digit? end |
#decimal_token ⇒ Object
263 264 265 266 267 268 269 |
# File 'lib/ios_parser/lexer.rb', line 263 def decimal_token if token.count('.') > 1 || token[-1] == '.' word_token else make_token(Float(token)) end end |
#delimit ⇒ Object
344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/ios_parser/lexer.rb', line 344 def delimit return if token.empty? unless respond_to?(:"#{state}_token") pos = @token_start || @this_char raise LexError, "Unterminated #{state} starting at #{pos}: "\ "#{@text[pos..pos + 20].inspect}" end tokens << send(:"#{state}_token") self.state = :root self.token = '' end |
#digit? ⇒ Boolean Also known as: integer?
245 246 247 |
# File 'lib/ios_parser/lexer.rb', line 245 def digit? ('0'..'9').cover? char end |
#dot? ⇒ Boolean
250 251 252 |
# File 'lib/ios_parser/lexer.rb', line 250 def dot? char == '.' end |
#finalize ⇒ Object
381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'lib/ios_parser/lexer.rb', line 381 def finalize if state == :quoted_string pos = @text.rindex(string_terminator) raise LexError, "Unterminated quoted string starting at #{pos}: "\ "#{@text[pos..pos + 20]}" end delimit self.line -= 1 update_indentation tokens end |
#find_start_of_line(from: @this_char) ⇒ Object
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/ios_parser/lexer.rb', line 70 def find_start_of_line(from: @this_char) from.downto(0) do |pos| if @text[pos] == "\n" self.start_of_line = pos + 1 return start_of_line end end self.line_start = 0 end |
#integer ⇒ Object
232 233 234 235 236 237 238 239 |
# File 'lib/ios_parser/lexer.rb', line 232 def integer self.state = :integer if dot? then decimal elsif digit? then token << char elsif word? then word else root end end |
#integer_token ⇒ Object
241 242 243 |
# File 'lib/ios_parser/lexer.rb', line 241 def integer_token token[0] == '0' ? word_token : make_token(Integer(token)) end |
#lead_comment? ⇒ Boolean
100 101 102 |
# File 'lib/ios_parser/lexer.rb', line 100 def lead_comment? char == '#' || char == '!' end |
#line_start ⇒ Object
335 336 337 338 339 340 341 342 |
# File 'lib/ios_parser/lexer.rb', line 335 def line_start if space? self.indent += 1 else update_indentation root_line_start end end |
#make_token(value, pos: nil, col: nil) ⇒ Object
63 64 65 66 67 68 |
# File 'lib/ios_parser/lexer.rb', line 63 def make_token(value, pos: nil, col: nil) pos ||= @token_start || @this_char col ||= pos - start_of_line + 1 @token_start = nil Token.new(value, pos, line, col) end |
#newline ⇒ Object
321 322 323 324 325 326 327 328 329 |
# File 'lib/ios_parser/lexer.rb', line 321 def newline delimit return if self.state = :line_start self.indent = 0 tokens << make_token(:EOL) self.start_of_line = @this_char + 1 self.line += 1 end |
#newline? ⇒ Boolean
331 332 333 |
# File 'lib/ios_parser/lexer.rb', line 331 def newline? char == "\n" end |
#pop_dedent ⇒ Object
364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/ios_parser/lexer.rb', line 364 def pop_dedent col = if tokens.last.line == line tokens.last.col else 1 end tokens << make_token(:DEDENT, col: col) indents.pop end |
#push_indent ⇒ Object
376 377 378 379 |
# File 'lib/ios_parser/lexer.rb', line 376 def push_indent tokens << make_token(:INDENT) indents.push(indent) end |
#quoted_string ⇒ Object
303 304 305 306 307 308 309 310 311 |
# File 'lib/ios_parser/lexer.rb', line 303 def quoted_string self.state = :quoted_string token << char if string_terminator.nil? self.string_terminator = char elsif char == string_terminator delimit end end |
#quoted_string? ⇒ Boolean
317 318 319 |
# File 'lib/ios_parser/lexer.rb', line 317 def quoted_string? char == '"' || char == "'" end |
#quoted_string_token ⇒ Object
313 314 315 |
# File 'lib/ios_parser/lexer.rb', line 313 def quoted_string_token make_token(token) end |
#root ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/ios_parser/lexer.rb', line 45 def root @token_start ||= @this_char ROOT_TRANSITIONS.each do |meth| return send(meth) if send(:"#{meth}?") end raise LexError, "Unknown character #{char.inspect}" end |
#root_line_start ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/ios_parser/lexer.rb', line 55 def root_line_start if lead_comment? comment else root end end |
#scrub_banner_garbage ⇒ Object
168 169 170 171 172 173 |
# File 'lib/ios_parser/lexer.rb', line 168 def tokens.each_index do |i| next unless tokens[i + 1] tokens.slice!(i + 1) if (i) end end |
#space ⇒ Object
294 295 296 297 |
# File 'lib/ios_parser/lexer.rb', line 294 def space delimit self.indent += 1 if tokens.last && tokens.last.value == :EOL end |
#space? ⇒ Boolean
299 300 301 |
# File 'lib/ios_parser/lexer.rb', line 299 def space? char == ' ' || char == "\t" || char == "\r" end |
#update_indentation ⇒ Object
358 359 360 361 362 |
# File 'lib/ios_parser/lexer.rb', line 358 def update_indentation pop_dedent while 1 < indents.size && indent <= indents[-2] push_indent if indent > indents.last self.indent = 0 end |
#word ⇒ Object
275 276 277 278 |
# File 'lib/ios_parser/lexer.rb', line 275 def word self.state = :word word? ? token << char : root end |
#word? ⇒ Boolean
284 285 286 287 288 289 290 291 292 |
# File 'lib/ios_parser/lexer.rb', line 284 def word? digit? || dot? || ('a'..'z').cover?(char) || ('A'..'Z').cover?(char) || ['-', '+', '$', ':', '/', ',', '(', ')', '|', '*', '#', '=', '<', '>', '!', '"', '&', '@', ';', '%', '~', '{', '}', "'", '?', '[', ']', '_', '^', '\\', '`'].include?(char) || /[[:graph:]]/.match(char) end |
#word_token ⇒ Object
280 281 282 |
# File 'lib/ios_parser/lexer.rb', line 280 def word_token make_token(token) end |