Class: Rouge::RegexLexer::StateDSL

Inherits:
Object
  • Object
show all
Defined in:
lib/rouge/regex_lexer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, &defn) ⇒ StateDSL

Returns a new instance of StateDSL.



77
78
79
80
81
82
83
# File 'lib/rouge/regex_lexer.rb', line 77

def initialize(name, &defn)
  @name = name
  @defn = defn
  @rules = []
  @loaded = false
  @closed = false
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



76
77
78
# File 'lib/rouge/regex_lexer.rb', line 76

def name
  @name
end

#rulesObject (readonly)

Returns the value of attribute rules.



76
77
78
# File 'lib/rouge/regex_lexer.rb', line 76

def rules
  @rules
end

Instance Method Details

#appended(&defn) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/rouge/regex_lexer.rb', line 101

def appended(&defn)
  parent_defn = @defn
  StateDSL.new(@name) do
    instance_eval(&parent_defn)
    instance_eval(&defn)
  end
end

#close!Object (protected)



188
189
190
# File 'lib/rouge/regex_lexer.rb', line 188

def close!
  @closed = true
end

#context_sensitive?(re) ⇒ Boolean (protected)

Returns:

  • (Boolean)


178
179
180
181
182
183
184
185
186
# File 'lib/rouge/regex_lexer.rb', line 178

def context_sensitive?(re)
  source = re.source
  return true if source =~ /[(][?]<?[!=]/

  # anchors count as lookahead/behind
  return true if source =~ /[$^]/

  false
end

#mixin(state) ⇒ Object (protected)

Mix in the rules from another state into this state. The rules from the mixed-in state will be tried in order before moving on to the rest of the rules in this state.



195
196
197
# File 'lib/rouge/regex_lexer.rb', line 195

def mixin(state)
  rules << state.to_s
end

#prepended(&defn) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/rouge/regex_lexer.rb', line 93

def prepended(&defn)
  parent_defn = @defn
  StateDSL.new(@name) do
    instance_eval(&defn)
    instance_eval(&parent_defn)
  end
end

#rule(re, token, next_state = nil) ⇒ Object (protected) #rule(re, &callback) ⇒ Object (protected)

Define a new rule for this state.

Parameters:

  • re (Regexp)

    a regular expression for this rule to test.

  • tok (String) (defaults to: nil)

    the token type to yield if re matches.

  • next_state (#to_s) (defaults to: nil)

    (optional) a state to push onto the stack if re matches. If next_state is :pop!, the state stack will be popped instead.

  • callback (Proc)

    a block that will be evaluated in the context of the lexer if re matches. This block has access to a number of lexer methods, including Rouge::RegexLexer#push, Rouge::RegexLexer#pop!, Rouge::RegexLexer#token, and Rouge::RegexLexer#delegate. The first argument can be used to access the match groups.

Raises:



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rouge/regex_lexer.rb', line 129

def rule(re, tok=nil, next_state=nil, &callback)
  raise ClosedState.new(self) if @closed

  if tok.nil? && callback.nil?
    raise "please pass `rule` a token to yield or a callback"
  end

  matches_empty = re =~ ''

  callback ||= case next_state
  when :pop!
    proc do |stream|
      puts "    yielding: #{tok.qualname}, #{stream[0].inspect}" if @debug
      @output_stream.call(tok, stream[0])
      puts "    popping stack: 1" if @debug
      @stack.pop or raise 'empty stack!'
    end
  when :push
    proc do |stream|
      puts "    yielding: #{tok.qualname}, #{stream[0].inspect}" if @debug
      @output_stream.call(tok, stream[0])
      puts "    pushing :#{@stack.last.name}" if @debug
      @stack.push(@stack.last)
    end
  when Symbol
    proc do |stream|
      puts "    yielding: #{tok.qualname}, #{stream[0].inspect}" if @debug
      @output_stream.call(tok, stream[0])
      state = @states[next_state] || self.class.get_state(next_state)
      puts "    pushing :#{state.name}" if @debug
      @stack.push(state)
    end
  when nil
    # cannot use an empty-matching regexp with no predicate
    raise InvalidRegex.new(re) if matches_empty

    proc do |stream|
      puts "    yielding: #{tok.qualname}, #{stream[0].inspect}" if @debug
      @output_stream.call(tok, stream[0])
    end
  else
    raise "invalid next state: #{next_state.inspect}"
  end

  rules << Rule.new(re, callback)

  close! if matches_empty && !context_sensitive?(re)
end

#to_state(lexer_class) ⇒ Object



85
86
87
88
89
90
91
# File 'lib/rouge/regex_lexer.rb', line 85

def to_state(lexer_class)
  load!
  rules = @rules.map do |rule|
    rule.is_a?(String) ? lexer_class.get_state(rule) : rule
  end
  State.new(@name, rules)
end