Chris@909: # encoding: utf-8 Chris@909: module CodeRay Chris@909: module Scanners Chris@909: Chris@909: class Ruby Chris@909: Chris@909: class StringState < Struct.new :type, :interpreted, :delim, :heredoc, Chris@909: :opening_paren, :paren_depth, :pattern, :next_state # :nodoc: all Chris@909: Chris@909: CLOSING_PAREN = Hash[ *%w[ Chris@909: ( ) Chris@909: [ ] Chris@909: < > Chris@909: { } Chris@909: ] ].each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with << Chris@909: Chris@909: STRING_PATTERN = Hash.new do |h, k| Chris@909: delim, interpreted = *k Chris@909: # delim = delim.dup # workaround for old Ruby Chris@909: delim_pattern = Regexp.escape(delim) Chris@909: if closing_paren = CLOSING_PAREN[delim] Chris@909: delim_pattern << Regexp.escape(closing_paren) Chris@909: end Chris@909: delim_pattern << '\\\\' unless delim == '\\' Chris@909: Chris@909: # special_escapes = Chris@909: # case interpreted Chris@909: # when :regexp_symbols Chris@909: # '| [|?*+(){}\[\].^$]' Chris@909: # end Chris@909: Chris@909: h[k] = Chris@909: if interpreted && delim != '#' Chris@909: / (?= [#{delim_pattern}] | \# [{$@] ) /mx Chris@909: else Chris@909: / (?= [#{delim_pattern}] ) /mx Chris@909: end Chris@909: end Chris@909: Chris@909: def initialize kind, interpreted, delim, heredoc = false Chris@909: if heredoc Chris@909: pattern = heredoc_pattern delim, interpreted, heredoc == :indented Chris@909: delim = nil Chris@909: else Chris@909: pattern = STRING_PATTERN[ [delim, interpreted] ] Chris@909: if closing_paren = CLOSING_PAREN[delim] Chris@909: opening_paren = delim Chris@909: delim = closing_paren Chris@909: paren_depth = 1 Chris@909: end Chris@909: end Chris@909: super kind, interpreted, delim, heredoc, opening_paren, paren_depth, pattern, :initial Chris@909: end Chris@909: Chris@909: def heredoc_pattern delim, interpreted, indented Chris@909: # delim = delim.dup # workaround for old Ruby Chris@909: delim_pattern = Regexp.escape(delim) Chris@909: delim_pattern = / (?:\A|\n) #{ '(?>[ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x Chris@909: if interpreted Chris@909: / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc Chris@909: else Chris@909: / (?= #{delim_pattern}() | \\ ) /mx Chris@909: end Chris@909: end Chris@909: Chris@909: end Chris@909: Chris@909: end Chris@909: Chris@909: end Chris@909: end