# frozen_string_literal: true # encoding: UTF-8 #-- # This file is automatically generated. Do not modify it. # Generated by: oedipus_lex version 2.6.1. # Source: lib/ruby_lexer.rex #++ # # lexical scanner definition for ruby ## # The generated lexer RubyLexer class RubyLexer require 'strscan' # :stopdoc: IDENT_CHAR = /[a-zA-Z0-9_[:^ascii:]]/ ESC = /\\((?>[0-7]{1,3}|x\h{1,2}|M-[^\\]|(C-|c)[^\\]|u\h{1,4}|u\{\h+(?:\s+\h+)*\}|[^0-7xMCc]))/ SIMPLE_STRING = /((#{ESC}|\#(#{ESC}|[^\{\#\@\$\"\\])|[^\"\\\#])*)/o SSTRING = /((\\.|[^\'])*)/ INT_DEC = /[+]?(?:(?:[1-9][\d_]*|0)(?!\.\d)(ri|r|i)?\b|0d[0-9_]+)(ri|r|i)?/i INT_HEX = /[+]?0x[a-f0-9_]+(ri|r|i)?/i INT_BIN = /[+]?0b[01_]+(ri|r|i)?/i INT_OCT = /[+]?0o?[0-7_]+(ri|r|i)?|0o(ri|r|i)?/i FLOAT = /[+]?\d[\d_]*\.[\d_]+(e[+-]?[\d_]+)?(?:(ri|r|i)\b)?|[+]?[\d_]+e[+-]?[\d_]+(?:(ri|r|i)\b)?/i INT_DEC2 = /[+]?\d[0-9_]*(?![e])((ri|r|i)\b)?/i NUM_BAD = /[+]?0[xbd]\b/i INT_OCT_BAD = /[+]?0o?[0-7_]*[89]/i FLOAT_BAD = /[+]?\d[\d_]*_(e|\.)/i # :startdoc: # :stopdoc: class LexerError < StandardError ; end class ScanError < LexerError ; end # :startdoc: ## # The current line number. attr_accessor :lineno ## # The file name / path attr_accessor :filename ## # The StringScanner for this lexer. attr_accessor :ss ## # The current lexical state. attr_accessor :state alias :match :ss ## # The match groups for the current scan. def matches m = (1..9).map { |i| ss[i] } m.pop until m[-1] or m.empty? m end ## # Yields on the current action. def action yield end ## # The previous position. Only available if the :column option is on. attr_accessor :old_pos ## # The position of the start of the current line. Only available if the # :column option is on. attr_accessor :start_of_current_line_pos ## # The current column, starting at 0. Only available if the # :column option is on. def column old_pos - start_of_current_line_pos end ## # The current scanner class. Must be overridden in subclasses. def scanner_class StringScanner end unless instance_methods(false).map(&:to_s).include?("scanner_class") ## # Parse the given string. def parse str self.ss = scanner_class.new str self.lineno = 1 self.start_of_current_line_pos = 0 self.state ||= nil do_parse end ## # Read in and parse the file at +path+. def parse_file path self.filename = path open path do |f| parse f.read end end ## # The current location in the parse. def location [ (filename || ""), lineno, column, ].compact.join(":") end ## # Lex the next token. def next_token maybe_pop_stack return process_string_or_heredoc if lex_strterm self.cmd_state = self.command_start self.command_start = false self.space_seen = false # TODO: rename token_seen? self.last_state = lex_state token = nil until ss.eos? or token do if ss.check(/\n/) then self.lineno += 1 # line starts 1 position after the newline self.start_of_current_line_pos = ss.pos + 1 end self.old_pos = ss.pos token = case state when nil then case when ss.skip(/[\ \t\r\f\v]+/) then action { self.space_seen = true; next } when text = ss.scan(/\n|\#/) then process_newline_or_comment text when text = ss.scan(/[\]\)\}]/) then process_brace_close text when ss.match?(/\!/) then case when is_after_operator? && (text = ss.scan(/\!\@/)) then action { result EXPR_ARG, TOKENS[text], text } when text = ss.scan(/\![=~]?/) then action { result :arg_state, TOKENS[text], text } end # group /\!/ when ss.match?(/\./) then case when text = ss.scan(/\.\.\.?/) then process_dots text when ss.skip(/\.\d/) then action { rb_compile_error "no . floating literal anymore put 0 before dot" } when ss.skip(/\./) then action { self.lex_state = EXPR_BEG; result EXPR_DOT, :tDOT, "." } end # group /\./ when text = ss.scan(/\(/) then process_paren text when text = ss.scan(/\,/) then action { result EXPR_PAR, TOKENS[text], text } when ss.match?(/=/) then case when text = ss.scan(/\=\=\=|\=\=|\=~|\=>|\=(?!begin\b)/) then action { result arg_state, TOKENS[text], text } when bol? && (text = ss.scan(/\=begin(?=\s)/)) then process_begin text when text = ss.scan(/\=(?=begin\b)/) then action { result arg_state, TOKENS[text], text } end # group /=/ when ruby22_label? && (text = ss.scan(/\"#{SIMPLE_STRING}\":/o)) then process_label text when text = ss.scan(/\"(#{SIMPLE_STRING})\"/o) then process_simple_string text when text = ss.scan(/\"/) then action { string STR_DQUOTE, '"'; result nil, :tSTRING_BEG, text } when text = ss.scan(/\@\@?\d/) then action { rb_compile_error "`#{text}` is not allowed as a variable name" } when text = ss.scan(/\@\@?#{IDENT_CHAR}+/o) then process_ivar text when ss.match?(/:/) then case when not_end? && (text = ss.scan(/:([a-zA-Z_]#{IDENT_CHAR}*(?:[?]|[!](?!=)|=(?==>)|=(?![=>]))?)/o)) then process_symbol text when not_end? && (text = ss.scan(/\:\"(#{SIMPLE_STRING})\"/o)) then process_symbol text when not_end? && (text = ss.scan(/\:\'(#{SSTRING})\'/o)) then process_symbol text when text = ss.scan(/\:\:/) then process_colon2 text when text = ss.scan(/\:/) then process_colon1 text end # group /:/ when text = ss.scan(/->/) then action { result EXPR_ENDFN, :tLAMBDA, text } when text = ss.scan(/[+-]/) then process_plus_minus text when ss.match?(/[+\d]/) then case when ss.skip(/#{NUM_BAD}/o) then action { rb_compile_error "Invalid numeric format" } when ss.skip(/#{INT_DEC}/o) then action { int_with_base 10 } when ss.skip(/#{INT_HEX}/o) then action { int_with_base 16 } when ss.skip(/#{INT_BIN}/o) then action { int_with_base 2 } when ss.skip(/#{INT_OCT_BAD}/o) then action { rb_compile_error "Illegal octal digit." } when ss.skip(/#{INT_OCT}/o) then action { int_with_base 8 } when ss.skip(/#{FLOAT_BAD}/o) then action { rb_compile_error "Trailing '_' in number." } when text = ss.scan(/#{FLOAT}/o) then process_float text when ss.skip(/#{INT_DEC2}/o) then action { int_with_base 10 } when ss.skip(/[0-9]/) then action { rb_compile_error "Bad number format" } end # group /[+\d]/ when text = ss.scan(/\[/) then process_square_bracket text when was_label? && (text = ss.scan(/\'#{SSTRING}\':?/o)) then process_label_or_string text when text = ss.scan(/\'/) then action { string STR_SQUOTE, "'"; result nil, :tSTRING_BEG, text } when ss.match?(/\|/) then case when ss.skip(/\|\|\=/) then action { result EXPR_BEG, :tOP_ASGN, "||" } when ss.skip(/\|\|/) then action { result EXPR_BEG, :tOROP, "||" } when ss.skip(/\|\=/) then action { result EXPR_BEG, :tOP_ASGN, "|" } when ss.skip(/\|/) then action { state = is_after_operator? ? EXPR_ARG : EXPR_PAR; result state, :tPIPE, "|" } end # group /\|/ when text = ss.scan(/\{/) then process_brace_open text when ss.match?(/\*/) then case when ss.skip(/\*\*=/) then action { result EXPR_BEG, :tOP_ASGN, "**" } when ss.skip(/\*\*/) then action { result :arg_state, space_vs_beginning(:tDSTAR, :tDSTAR, :tPOW), "**" } when ss.skip(/\*\=/) then action { result EXPR_BEG, :tOP_ASGN, "*" } when ss.skip(/\*/) then action { result :arg_state, space_vs_beginning(:tSTAR, :tSTAR, :tSTAR2), "*" } end # group /\*/ when ss.match?(//) then action { result :arg_state, :tCMP, "<=>" } when ss.skip(/\<\=/) then action { result :arg_state, :tLEQ, "<=" } when ss.skip(/\<\<\=/) then action { result EXPR_BEG, :tOP_ASGN, "<<" } when text = ss.scan(/\<\/) then case when ss.skip(/\>\=/) then action { result :arg_state, :tGEQ, ">=" } when ss.skip(/\>\>=/) then action { result EXPR_BEG, :tOP_ASGN, ">>" } when ss.skip(/\>\>/) then action { result :arg_state, :tRSHFT, ">>" } when ss.skip(/\>/) then action { result :arg_state, :tGT, ">" } end # group />/ when ss.match?(/\`/) then case when expr_fname? && (ss.skip(/\`/)) then action { result EXPR_END, :tBACK_REF2, "`" } when expr_dot? && (ss.skip(/\`/)) then action { result((cmd_state ? EXPR_CMDARG : EXPR_ARG), :tBACK_REF2, "`") } when ss.skip(/\`/) then action { string STR_XQUOTE, '`'; result nil, :tXSTRING_BEG, "`" } end # group /\`/ when text = ss.scan(/\?/) then process_questionmark text when ss.match?(/&/) then case when ss.skip(/\&\&\=/) then action { result EXPR_BEG, :tOP_ASGN, "&&" } when ss.skip(/\&\&/) then action { result EXPR_BEG, :tANDOP, "&&" } when ss.skip(/\&\=/) then action { result EXPR_BEG, :tOP_ASGN, "&" } when ss.skip(/\&\./) then action { result EXPR_DOT, :tLONELY, "&." } when text = ss.scan(/\&/) then process_amper text end # group /&/ when text = ss.scan(/\//) then process_slash text when ss.match?(/\^/) then case when ss.skip(/\^=/) then action { result EXPR_BEG, :tOP_ASGN, "^" } when ss.skip(/\^/) then action { result :arg_state, :tCARET, "^" } end # group /\^/ when ss.skip(/\;/) then action { self.command_start = true; result EXPR_BEG, :tSEMI, ";" } when ss.match?(/~/) then case when is_after_operator? && (ss.skip(/\~@/)) then action { result :arg_state, :tTILDE, "~" } when ss.skip(/\~/) then action { result :arg_state, :tTILDE, "~" } end # group /~/ when ss.match?(/\\/) then case when ss.skip(/\\\r?\n/) then action { self.lineno += 1; self.space_seen = true; next } when ss.skip(/\\/) then action { rb_compile_error "bare backslash only allowed before newline" } end # group /\\/ when text = ss.scan(/\%/) then process_percent text when ss.match?(/\$/) then case when text = ss.scan(/\$_\w+/) then process_gvar text when text = ss.scan(/\$_/) then process_gvar text when text = ss.scan(/\$[~*$?!@\/\\;,.=:<>\"]|\$-\w?/) then process_gvar text when in_fname? && (text = ss.scan(/\$([\&\`\'\+])/)) then process_gvar text when text = ss.scan(/\$([\&\`\'\+])/) then process_backref text when in_fname? && (text = ss.scan(/\$([1-9]\d*)/)) then process_gvar text when text = ss.scan(/\$([1-9]\d*)/) then process_nthref text when text = ss.scan(/\$0/) then process_gvar text when text = ss.scan(/\$#{IDENT_CHAR}+/) then process_gvar text when text = ss.scan(/\$\W/) then process_gvar_oddity text end # group /\$/ when text = ss.scan(/\_/) then process_underscore text when text = ss.scan(/#{IDENT_CHAR}+/o) then process_token text when ss.skip(/\004|\032|\000|\Z/) then action { [RubyLexer::EOF, RubyLexer::EOF] } when text = ss.scan(/./) then action { rb_compile_error "Invalid char #{text.inspect} in expression" } else text = ss.string[ss.pos .. -1] raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'" end else raise ScanError, "undefined state at #{location}: '#{state}'" end # token = case state next unless token # allow functions to trigger redo w/ nil end # while raise LexerError, "bad lexical result at #{location}: #{token.inspect}" unless token.nil? || (Array === token && token.size >= 2) # auto-switch state self.state = token.last if token && token.first == :state token end # def next_token end # class