summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKornelius Kalnbach <murphy@rubychan.de>2016-02-14 15:11:18 +0100
committerKornelius Kalnbach <murphy@rubychan.de>2016-02-14 15:11:18 +0100
commit9526bd86b6420e868bee1da167e40afc11ed1c0b (patch)
treecb7478701a2ca66bfa5241868bfb8e2248d99f06
parentdcf73a6b5bae19a6592f4be17105005474cec2d3 (diff)
downloadcoderay-9526bd86b6420e868bee1da167e40afc11ed1c0b.tar.gz
generate scanner code automatically
-rw-r--r--lib/coderay/rule_based_scanner.rb87
-rw-r--r--lib/coderay/scanners/lua2.rb36
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