class AdLint::Cpp::Lexer

Constants

GROUP_DIRECTIVE_RE

Attributes

content[R]

Public Class Methods

new(src, traits) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 40
def initialize(src, traits)
  src.on_cr_at_eol_found += lambda { |loc|
    on_cr_at_eol_found.invoke(loc)
  }
  src.on_eof_mark_at_eof_found += lambda { |loc|
    on_eof_mark_at_eof_found.invoke(loc)
  }
  src.on_eof_newline_not_found += method(:notify_eof_newline_not_found)

  tab_width  = traits.of_project.coding_style.tab_width
  @content   = SourceContent.lazy_new(src, tab_width)
  @state     = Initial.new(self)
  @top_token = nil
end

Public Instance Methods

discard_heading_comments() click to toggle source
# File lib/adlint/cpp/lexer.rb, line 105
def discard_heading_comments
  case
  when @content.check(/\/\*/)
    loc = @content.location
    comment = scan_block_comment(@content)
    unless comment.empty?
      notify_block_comment_found(comment, loc)
      return true
    end
  when @content.check(/\/\//)
    loc = @content.location
    comment = scan_line_comment(@content)
    unless comment.empty?
      notify_line_comment_found(comment, loc)
      return true
    end
  end
  false
end
next_token() click to toggle source
# File lib/adlint/cpp/lexer.rb, line 69
def next_token
  if @top_token
    tok = @top_token
    @top_token = nil
    return tok
  end
  @state.next_token
end
notify_block_comment_found(comment, loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 129
def notify_block_comment_found(comment, loc)
  on_block_comment_found.invoke(comment, loc)
end
notify_eof_newline_not_found(loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 145
def notify_eof_newline_not_found(loc)
  on_eof_newline_not_found.invoke(loc)
end
notify_illformed_newline_escape_found(loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 153
def notify_illformed_newline_escape_found(loc)
  on_illformed_newline_escape_found.invoke(loc)
end
notify_line_comment_found(comment, loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 133
def notify_line_comment_found(comment, loc)
  on_line_comment_found.invoke(comment, loc)
end
notify_nested_block_comment_found(loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 137
def notify_nested_block_comment_found(loc)
  on_nested_block_comment_found.invoke(loc)
end
notify_unlexable_char_found(char, loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 149
def notify_unlexable_char_found(char, loc)
  on_unlexable_char_found.invoke(char, loc)
end
notify_unterminated_block_comment(loc) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 141
def notify_unterminated_block_comment(loc)
  on_unterminated_block_comment.invoke(loc)
end
skip_group() click to toggle source
# File lib/adlint/cpp/lexer.rb, line 82
def skip_group
  group_depth = 1
  until @content.empty?
    scan_until_next_directive_or_comment(@content)

    case
    when @content.check(/\/\*|\/\//)
      discard_heading_comments
    when @content.check(/[ \t]*#[ \t]*(?:if|ifdef|ifndef|asm)\b/)
      group_depth += 1
      @content.scan(/.*?\n/)
    when @content.check(/[ \t]*#[ \t]*(?:else|elif)\b/)
      return true if group_depth == 1
      @content.scan(/.*?\n/)
    when @content.check(/[ \t]*#[ \t]*(?:endif|endasm)\b/)
      group_depth -= 1
      return true if group_depth == 0
      @content.scan(/.*?\n/)
    end
  end
  false
end
top_token() click to toggle source
# File lib/adlint/cpp/lexer.rb, line 78
def top_token
  @top_token ? @top_token : (@top_token = self.next_token)
end
transit(next_state) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 125
def transit(next_state)
  @state = next_state
end

Private Instance Methods

scan_block_comment(cont) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 176
def scan_block_comment(cont)
  comment = ""
  nest_depth = 0
  until cont.empty?
    loc = cont.location
    case
    when nest_depth == 0 && cont.scan(/\/\*/)
      nest_depth = 1
      comment += "/*"
    when nest_depth > 0 && cont.check(/\/\*\//)
      comment += cont.scan(/\//)
    when nest_depth > 0 && cont.check(/\/\*/)
      nest_depth += 1
      comment += cont.scan(/\/\*/)
      notify_nested_block_comment_found(loc)
    when cont.scan(/\*\//)
      comment += "*/"
      break
    when nest_depth == 0
      return nil
    else
      if scanned = cont.scan(/.*?(?=\/\*|\*\/)/m)
        comment += scanned
      else
        notify_unterminated_block_comment(loc)
      end
    end
  end
  comment
end
scan_line_comment(cont) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 207
def scan_line_comment(cont)
  cont.scan(/\/\/.*?(?=\n)/)
end
scan_until_next_directive_or_comment(cont) click to toggle source
# File lib/adlint/cpp/lexer.rb, line 162
def scan_until_next_directive_or_comment(cont)
  until cont.empty?
    cont.scan(/.*?(?=#{GROUP_DIRECTIVE_RE}|"|'|\/\*|\/\/)/m)
    case
    when cont.check(/"/)
      Language::C::scan_string_literal(cont)
    when cont.check(/'/)
      Language::C::scan_char_constant(cont)
    else
      break
    end
  end
end