From a9e04e1f52f6530cbf4b5251abcf6f1f82840ce9 Mon Sep 17 00:00:00 2001 From: Kornelius Kalnbach Date: Sun, 5 Nov 2017 17:59:45 +0100 Subject: fix specs, update SimpleScannerDSL --- lib/coderay/simple_scanner.rb | 2 +- lib/coderay/simple_scanner_dsl.rb | 93 +++++++++++++++++++++------------------ spec/simple_scanner_spec.rb | 33 +++++++++++--- spec/spec_helper.rb | 2 - 4 files changed, 77 insertions(+), 53 deletions(-) diff --git a/lib/coderay/simple_scanner.rb b/lib/coderay/simple_scanner.rb index 96a0e51..2ad5fe3 100644 --- a/lib/coderay/simple_scanner.rb +++ b/lib/coderay/simple_scanner.rb @@ -15,7 +15,7 @@ module CodeRay class_eval <<-RUBY def scan_tokens encoder, options -#{ scan_tokens_code.chomp.gsub(/^/, ' ' * 2) } +#{ scan_tokens_code.chomp.gsub(/^/, ' ') } end RUBY end diff --git a/lib/coderay/simple_scanner_dsl.rb b/lib/coderay/simple_scanner_dsl.rb index b3c8c57..e954ccf 100644 --- a/lib/coderay/simple_scanner_dsl.rb +++ b/lib/coderay/simple_scanner_dsl.rb @@ -3,6 +3,8 @@ require 'set' module CodeRay module Scanners module SimpleScannerDSL + NoStatesError = Class.new StandardError + Pattern = Struct.new :pattern Groups = Struct.new :token_kinds Kind = Struct.new :token_kind @@ -26,7 +28,7 @@ module CodeRay def eval @first = true - @code = "" + @code = '' instance_eval(&block) end @@ -111,115 +113,119 @@ when #{names.map(&:inspect).join(', ')} end end - @code << "#{'els' unless @first}if #{condition_expressions.join(' && ')}\n" + condition_code = "#{'els' unless @first}if #{condition_expressions.join(' && ')}\n" + action_code = '' for action in actions case action when String raise - @code << "p 'evaluate #{action.inspect}'\n" if $DEBUG - @code << "#{action}\n" + action_code << "p 'evaluate #{action.inspect}'\n" if $DEBUG + action_code << "#{action}\n" when Symbol - @code << "p 'text_token %p %p' % [match, #{action.inspect}]\n" if $DEBUG - @code << "encoder.text_token match, #{action.inspect}\n" + action_code << "p 'text_token %p %p' % [match, #{action.inspect}]\n" if $DEBUG + action_code << "encoder.text_token match, #{action.inspect}\n" when Kind case action.token_kind when Proc - @code << "encoder.text_token match, kind = #{dsl.add_callback(action.token_kind)}\n" + action_code << "encoder.text_token match, kind = #{dsl.add_callback(action.token_kind)}\n" else raise "I don't know how to evaluate this kind: %p" % [action.token_kind] end when Groups - @code << "p 'text_tokens %p in groups %p' % [match, #{action.token_kinds.inspect}]\n" if $DEBUG + action_code << "p 'text_tokens %p in groups %p' % [match, #{action.token_kinds.inspect}]\n" if $DEBUG action.token_kinds.each_with_index do |kind, i| - @code << "encoder.text_token self[#{i + 1}], #{kind.inspect} if self[#{i + 1}]\n" + action_code << "encoder.text_token self[#{i + 1}], #{kind.inspect} if self[#{i + 1}]\n" end when Push, PushState case action.state when String raise - @code << "p 'push %p' % [#{action.state}]\n" if $DEBUG - @code << "state = #{action.state}\n" - @code << "states << state\n" + action_code << "p 'push %p' % [#{action.state}]\n" if $DEBUG + action_code << "state = #{action.state}\n" + action_code << "states << state\n" when Symbol - @code << "p 'push %p' % [#{action.state.inspect}]\n" if $DEBUG - @code << "state = #{action.state.inspect}\n" - @code << "states << state\n" + action_code << "p 'push %p' % [#{action.state.inspect}]\n" if $DEBUG + action_code << "state = #{action.state.inspect}\n" + action_code << "states << state\n" when Proc - @code << "if new_state = #{dsl.add_callback(action.state)}\n" - @code << " state = new_state\n" - @code << " states << new_state\n" - @code << "end\n" + action_code << "if new_state = #{dsl.add_callback(action.state)}\n" + action_code << " state = new_state\n" + action_code << " states << new_state\n" + action_code << "end\n" else raise "I don't know how to evaluate this push state: %p" % [action.state] end if action.is_a? Push if action.state == action.group - @code << "encoder.begin_group state\n" + action_code << "encoder.begin_group state\n" else case action.state when Symbol - @code << "p 'begin group %p' % [#{action.group.inspect}]\n" if $DEBUG - @code << "encoder.begin_group #{action.group.inspect}\n" + action_code << "p 'begin group %p' % [#{action.group.inspect}]\n" if $DEBUG + action_code << "encoder.begin_group #{action.group.inspect}\n" when Proc - @code << "encoder.begin_group #{dsl.add_callback(action.group)}\n" + action_code << "encoder.begin_group #{dsl.add_callback(action.group)}\n" else raise "I don't know how to evaluate this push state: %p" % [action.state] end end end when Pop, PopState - @code << "p 'pop %p' % [states.last]\n" if $DEBUG + action_code << "p 'pop %p' % [states.last]\n" if $DEBUG if action.is_a? Pop if action.group case action.group when Symbol - @code << "encoder.end_group #{action.group.inspect}\n" + action_code << "encoder.end_group #{action.group.inspect}\n" else raise "I don't know how to evaluate this pop group: %p" % [action.group] end - @code << "states.pop\n" + action_code << "states.pop\n" else - @code << "encoder.end_group states.pop\n" + action_code << "encoder.end_group states.pop\n" end else - @code << "states.pop\n" + action_code << "states.pop\n" end - @code << "state = states.last\n" + action_code << "state = states.last\n" when ValueSetter case action.value when Proc - @code << "#{action.targets.join(' = ')} = #{dsl.add_callback(action.value)}\n" + action_code << "#{action.targets.join(' = ')} = #{dsl.add_callback(action.value)}\n" when Symbol - @code << "#{action.targets.join(' = ')} = #{action.value}\n" + action_code << "#{action.targets.join(' = ')} = #{action.value}\n" else - @code << "#{action.targets.join(' = ')} = #{action.value.inspect}\n" + action_code << "#{action.targets.join(' = ')} = #{action.value.inspect}\n" end when Increment case action.value when Proc - @code << "#{action.targets.join(' = ')} #{action.operation}= #{dsl.add_callback(action.value)}\n" + action_code << "#{action.targets.join(' = ')} #{action.operation}= #{dsl.add_callback(action.value)}\n" when Symbol - @code << "#{action.targets.join(' = ')} #{action.operation}= #{action.value}\n" + action_code << "#{action.targets.join(' = ')} #{action.operation}= #{action.value}\n" else - @code << "#{action.targets.join(' = ')} #{action.operation}= #{action.value.inspect}\n" + action_code << "#{action.targets.join(' = ')} #{action.operation}= #{action.value.inspect}\n" end when Proc - @code << "#{dsl.add_callback(action)}\n" + action_code << "#{dsl.add_callback(action)}\n" when Continue - @code << "next\n" + action_code << "next\n" else raise "I don't know how to evaluate this action: %p" % [action] end end + @code << condition_code + @code << action_code.gsub(/^/, ' ') + @first = false end @@ -347,8 +353,7 @@ when #{names.map(&:inspect).join(', ')} <<-"RUBY" state = options[:state] || @state states = [state] -#{ restore_local_variables_code.chomp } - +#{ restore_local_variables_code } until eos? case state #{ states_code.chomp.gsub(/^/, ' ') } @@ -359,7 +364,7 @@ end @state = state if options[:keep_state] -#{ close_groups_code.chomp } +close_groups(encoder, states) encoder RUBY @@ -370,11 +375,11 @@ encoder end def states_code - @states.map(&:code)[0,1].join - end + unless defined? @states + raise NoStatesError, 'no states defined for %p' % [self.class] + end - def close_groups_code - 'close_groups(encoder, states)' + @states.map(&:code).join end end end diff --git a/spec/simple_scanner_spec.rb b/spec/simple_scanner_spec.rb index 088343c..bc2aec4 100644 --- a/spec/simple_scanner_spec.rb +++ b/spec/simple_scanner_spec.rb @@ -1,17 +1,37 @@ RSpec.describe CodeRay::Scanners::SimpleScanner do - let(:scanner) { Class.new described_class } + let(:scanner) { described_class } describe '#scan_tokens_code' do subject { scanner.send :scan_tokens_code } - it 'lets you define states' do - is_expected.to eq <<-RUBY + it 'throws an error' do + expect { subject }.to raise_error(CodeRay::Scanners::SimpleScannerDSL::NoStatesError) + end + end + + describe 'with one state' do + let(:scanner) do + Class.new described_class do + state :somepony do + on %r/rainbow/, :dash + end + end + end + + describe '#scan_tokens_code' do + subject { scanner.send :scan_tokens_code } + it 'returns an scanner with one states' do + is_expected.to eq <<-RUBY state = options[:state] || @state states = [state] - until eos? case state - + when :somepony + if match = scan(/rainbow/) + encoder.text_token match, :dash + else + encoder.text_token getch, :error + end else raise_inspect 'Unknown state: %p' % [state], encoder end @@ -22,7 +42,8 @@ end close_groups(encoder, states) encoder - RUBY + RUBY + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 49b6a0e..fe4e726 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -91,6 +91,4 @@ RSpec.configure do |config| Kernel.srand config.seed end -$LOAD_PATH << 'lib/coderay' - require 'coderay' -- cgit v1.2.1