class Lex::Linter

A class responsible for checking lexer definitions

@api public

Constants

Failure

Failure raised by complain

IDENTIFIER_RE

Public Instance Methods

lint(lexer) click to toggle source

Run linting of lexer

@param [Lex::Lexer]

@raise [Lex::Linter::Failure]

@api public

# File lib/lex/linter.rb, line 20
def lint(lexer)
  validate_tokens(lexer)
  validate_states(lexer)
  validate_rules(lexer)
end

Private Instance Methods

complain(*args) click to toggle source

Raise a failure if validation of a lexer fails

@raise [Lex::Linter::Failure]

@api private

# File lib/lex/linter.rb, line 110
def complain(*args)
  raise Failure, *args
end
identifier?(value) click to toggle source

Check if token has valid name

@param [Symbol,String] value

token to check

@return [Boolean]

@api private

# File lib/lex/linter.rb, line 36
def identifier?(value)
  value =~ IDENTIFIER_RE
end
validate_rules(lexer) click to toggle source

Validate rules

@api private

# File lib/lex/linter.rb, line 93
def validate_rules(lexer)
  if lexer.state_re.empty?
    complain("No rules of the form rule(name, pattern) are defined")
  end

  lexer.state_info.each do |state_name, state_type|
    if !lexer.state_re.key?(state_name.to_sym)
      complain("No rules defined for state '#{state_name}'")
    end
  end
end
validate_states(lexer) click to toggle source

Validate provided state names

@api private

# File lib/lex/linter.rb, line 66
def validate_states(lexer)
  if !lexer.state_info.respond_to?(:each_pair)
    complain("States must be defined as a hash")
  end

  lexer.state_info.each do |state_name, state_type|
    if ![:inclusive, :exclusive].include?(state_type)
      complain("State type for state #{state_name}" \
               " must be :inclusive or :exclusive")
    end

    if state_type == :exclusive
      if !lexer.state_error.key?(state_name)
        lexer.logger.warn("No error rule is defined " \
                          "for exclusive state '#{state_name}'")
      end
      if !lexer.state_ignore.key?(state_name)
        lexer.logger.warn("No ignore rule is defined " \
                          "for exclusive state '#{state_name}'")
      end
    end
  end
end
validate_tokens(lexer) click to toggle source

Validate provided tokens

@api private

# File lib/lex/linter.rb, line 43
def validate_tokens(lexer)
  if lexer.lex_tokens.empty?
    complain("No token list defined")
  end
  if !lexer.lex_tokens.respond_to?(:to_ary)
    complain("Tokens must be a list or enumerable")
  end

  terminals = []
  lexer.lex_tokens.each do |token|
    if !identifier?(token)
      complain("Bad token name `#{token}`")
    end
    if terminals.include?(token)
      complain("Token `#{token}` already defined")
    end
    terminals << token
  end
end