class Lex::Lexer::RuleDSL
Rules DSL
used internally by {Lexer}
@api private
Attributes
lex_tokens[R]
state_error[R]
state_ignore[R]
state_info[R]
state_lexemes[R]
state_names[R]
state_re[R]
Public Class Methods
new()
click to toggle source
@api private
# File lib/lex/lexer/rule_dsl.rb, line 18 def initialize @state_info = { initial: :inclusive } @state_ignore = { initial: '' } # Ignored characters for each state @state_error = {} # Error conditions for each state @state_re = Hash.new { |hash, name| hash[name] = {}} # Regexes for each state @state_names = {} # Symbol names for each state @state_lexemes = Hash.new { |hash, name| hash[name] = State.new(name) } @lex_tokens = [] # List of valid tokens end
Public Instance Methods
error(states = :initial, &action)
click to toggle source
Define error condition for a state
@api public
# File lib/lex/lexer/rule_dsl.rb, line 104 def error(states = :initial, &action) state_names = states.to_s.split('_').map(&:to_sym) state_names.each do |state_name| @state_error[state_name] = action end @state_info.each do |state_name, state_type| if state_name != :initial && state_type == :inclusive if !@state_error.key?(state_name) @state_error[state_name] = @state_error[:initial] end end end end
ignore(states, value = (not_set = true))
click to toggle source
Define ignore condition for a state
@param [Symbol] states
the optional state names
@param [String] value
the characters to ignore
@api public
# File lib/lex/lexer/rule_dsl.rb, line 79 def ignore(states, value = (not_set = true)) if not_set value = states state_names = [:initial] else state_names = states.to_s.split('_').map(&:to_sym) end if !value.is_a?(String) logger.error("Ignore rule '#{value}' has to be defined with a string") end state_names.each do |state_name| @state_ignore[state_name] = value end @state_info.each do |state_name, state_type| if state_name != :initial && state_type == :inclusive if !@state_ignore.key?(state_name) @state_ignore[state_name] = @state_ignore[:initial] end end end end
rule(name, pattern, &action)
click to toggle source
Specify lexing rule
@param [Symbol] name
the rule name
@param [Regex] pattern
the regex pattern
@api public
# File lib/lex/lexer/rule_dsl.rb, line 51 def rule(name, pattern, &action) state_names, token_name = *extract_state_token(name) if token_name =~ /^[[:upper:]]*$/ && !@lex_tokens.include?(token_name) complain("Rule '#{name}' defined for" \ " an unspecified token #{token_name}") end state_names.each do |state_name| state = @state_lexemes[state_name] state << Lexeme.new(token_name, pattern, &action) end update_inclusive_states state_names.each do |state_name| if @state_re[state_name].key?(token_name) complain("Rule '#{name}' redefined.") end @state_re[state_name][token_name] = pattern end end
states(value)
click to toggle source
Add states to lexer
@api public
# File lib/lex/lexer/rule_dsl.rb, line 38 def states(value) @state_info.merge!(value) end
tokens(*value)
click to toggle source
Add tokens to lexer
@api public
# File lib/lex/lexer/rule_dsl.rb, line 31 def tokens(*value) @lex_tokens = value end
Private Instance Methods
complain(*args)
click to toggle source
@api private
# File lib/lex/lexer/rule_dsl.rb, line 160 def complain(*args) raise LexerError, *args end
extract_state_token(name)
click to toggle source
Extract tuple of state names and token name
@param [Symbol] name
the rule name
@return [Array, Symbol]
returns tuples [states, token]
@api private
# File lib/lex/lexer/rule_dsl.rb, line 141 def extract_state_token(name) parts = name.to_s.split('_') state_i = 0 parts.each_with_index do |part, i| if !@state_info.keys.include?(part.to_sym) state_i = i break end end states = if state_i > 0 parts[0...state_i].map(&:to_sym) else [:initial] end token_name = parts[state_i..-1].join('_').to_sym [states, token_name] end
update_inclusive_states()
click to toggle source
For inclusive states copy over initial state rules
@api private
# File lib/lex/lexer/rule_dsl.rb, line 123 def update_inclusive_states @state_info.each do |state_name, state_type| if state_name != :initial && state_type == :inclusive initial_state = @state_lexemes[:initial] @state_lexemes[state_name].update(initial_state.lexemes) end end end