diff options
author | Kornelius Kalnbach <murphy@rubychan.de> | 2016-02-14 15:11:18 +0100 |
---|---|---|
committer | Kornelius Kalnbach <murphy@rubychan.de> | 2016-02-14 15:11:18 +0100 |
commit | 9526bd86b6420e868bee1da167e40afc11ed1c0b (patch) | |
tree | cb7478701a2ca66bfa5241868bfb8e2248d99f06 | |
parent | dcf73a6b5bae19a6592f4be17105005474cec2d3 (diff) | |
download | coderay-9526bd86b6420e868bee1da167e40afc11ed1c0b.tar.gz |
generate scanner code automatically
-rw-r--r-- | lib/coderay/rule_based_scanner.rb | 87 | ||||
-rw-r--r-- | lib/coderay/scanners/lua2.rb | 36 |
2 files changed, 87 insertions, 36 deletions
diff --git a/lib/coderay/rule_based_scanner.rb b/lib/coderay/rule_based_scanner.rb index 653b43f..a22bcc3 100644 --- a/lib/coderay/rule_based_scanner.rb +++ b/lib/coderay/rule_based_scanner.rb @@ -1,3 +1,5 @@ +require 'set' + module CodeRay module Scanners class RuleBasedScanner < Scanner @@ -240,26 +242,32 @@ module CodeRay end def flag_on *flags + flags.each { |name| variables << name } ValueSetter.new Array(flags), true end def flag_off *flags + flags.each { |name| variables << name } ValueSetter.new Array(flags), false end def set flag, value = nil, &callback + variables << flag ValueSetter.new [flag], value || callback end def unset *flags + flags.each { |name| variables << name } ValueSetter.new Array(flags), nil end def increment *counters + counters.each { |name| variables << name } Increment.new Array(counters), :+, 1 end def decrement *counters + counters.each { |name| variables << name } Increment.new Array(counters), :-, 1 end @@ -267,33 +275,96 @@ module CodeRay Continue.new end + def define_scan_tokens! + if ENV['PUTS'] + puts CodeRay.scan(scan_tokens_code, :ruby).terminal + puts "callbacks: #{callbacks.size}" + end + + class_eval scan_tokens_code + end + protected def callbacks @callbacks ||= {} end + def variables + @variables ||= Set.new + end + + def additional_variables + variables - %i(state match kind) + end + def make_callback block base_name = "__callback_line_#{block.source_location.last}" - name = base_name + callback_name = base_name counter = 'a' - while callbacks.key?(name) - name = "#{base_name}_#{counter}" + while callbacks.key?(callback_name) + callback_name = "#{base_name}_#{counter}" counter.succ! end - callbacks[name] = define_method(name, &block) + callbacks[callback_name] = define_method(callback_name, &block) - arguments = block.parameters.map(&:last) + parameters = block.parameters - if arguments.empty? - name + if parameters.empty? + callback_name else - "#{name}(#{arguments.join(', ')})" + parameter_names = parameters.map(&:last) + parameter_names.each { |name| variables << name } + "#{callback_name}(#{parameter_names.join(', ')})" end end + + def scan_tokens_code + <<-"RUBY" + def scan_tokens encoder, options + state = options[:state] || @state + +#{ restore_local_variables_code.chomp.gsub(/^/, ' ' * 3) } + + states = [state] + + until eos? + case state +#{ @code.chomp.gsub(/^/, ' ' * 4) } + else + raise_inspect 'Unknown state: %p' % [state], encoder + end end + if options[:keep_state] + @state = state + end + +#{ close_groups_code.chomp.gsub(/^/, ' ' * 3) } + + encoder + end + RUBY + end + + def restore_local_variables_code + additional_variables.sort.map { |name| "#{name} = @#{name}" }.join("\n") + end + + def close_groups_code + "close_groups(encoder, states)" + end + end + + def scan_tokens tokens, options + self.class.define_scan_tokens! + + scan_tokens tokens, options + end + + protected + def setup @state = :initial end diff --git a/lib/coderay/scanners/lua2.rb b/lib/coderay/scanners/lua2.rb index 1aba769..f48627d 100644 --- a/lib/coderay/scanners/lua2.rb +++ b/lib/coderay/scanners/lua2.rb @@ -139,38 +139,18 @@ module Scanners # encoder.text_token("\\n\n", :error) # Visually appealing error indicator--otherwise users may wonder whether the highlighter cannot highlight multine strings end - scan_tokens_code = <<-"RUBY" - def scan_tokens encoder, options#{ def_line = __LINE__; nil } - state = options[:state] || @state - brace_depth = @brace_depth - num_equals = nil - - states = [state] - - until eos? + def close_groups encoder, states + states.reverse_each do |state| case state -#{ @code.chomp.gsub(/^/, ' ') } - else - raise_inspect 'Unknown state: %p' % [state], encoder + when :long_string, :single_quoted_string, :double_quoted_string + encoder.end_group :string + when :long_comment + encoder.end_group :long_comment + when :map + encoder.end_group :map end end - - if options[:keep_state] - @state = state - end - - encoder.end_group :string if [:string, :single_quoted_string, :double_quoted_string].include? state - brace_depth.times { encoder.end_group :map } - - encoder - end - RUBY - - if ENV['PUTS'] - puts CodeRay.scan(scan_tokens_code, :ruby).terminal - puts "callbacks: #{callbacks.size}" end - class_eval scan_tokens_code, __FILE__, def_line end end |