diff options
Diffstat (limited to 'lib/coderay/scanners/json2.rb')
-rw-r--r-- | lib/coderay/scanners/json2.rb | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/lib/coderay/scanners/json2.rb b/lib/coderay/scanners/json2.rb new file mode 100644 index 0000000..51df782 --- /dev/null +++ b/lib/coderay/scanners/json2.rb @@ -0,0 +1,131 @@ +module CodeRay +module Scanners + + class JSON2RuleBasedScanner < Scanner + class << self + attr_accessor :states + + def state *names, &block + @@states ||= {} + + @@rules = [] + + instance_eval(&block) + + for name in names + @@states[name] = @@rules + end + + @@rules = nil + end + + def token pattern, *actions + @@rules << [pattern, *actions] + end + + def push_group name + [:begin_group, name] + end + + def pop_group + [:end_group] + end + end + end + + # Scanner for JSON (JavaScript Object Notation). + class JSON2 < JSON2RuleBasedScanner + + register_for :json2 + file_extension 'json' + + KINDS_NOT_LOC = [ + :float, :char, :content, :delimiter, + :error, :integer, :operator, :value, + ] # :nodoc: + + ESCAPE = / [bfnrt\\"\/] /x # :nodoc: + UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # :nodoc: + KEY = / (?> (?: [^\\"]+ | \\. )* ) " \s* : /mx + + state :initial do + token %r/ \s+ /x, :space + + token %r/ " (?=#{KEY}) /x, push_group(:key), :delimiter + token %r/ " /x, push_group(:string), :delimiter + + token %r/ [:,\[{\]}] /x, :operator + + token %r/ true | false | null /x, :value + token %r/ -? (?: 0 | [1-9]\d* ) (?: \.\d+ (?: [eE][-+]? \d+ )? | [eE][-+]? \d+ ) /x, :float + token %r/ -? (?: 0 | [1-9]\d* ) /x, :integer + end + + state :string, :key do + token %r/ [^\\"]+ /x, :content + + token %r/ " /x, :delimiter, pop_group + + token %r/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /x, :char + token %r/ \\. /mx, :content + token %r/ \\ /x, pop_group, :error + + # token %r/$/, end_group + end + + protected + + def setup + @state = :initial + end + + # See http://json.org/ for a definition of the JSON lexic/grammar. + def scan_tokens encoder, options + state = options[:state] || @state + + if [:string, :key].include? state + encoder.begin_group state + end + + states = [state] + + until eos? + for pattern, *actions in @@states[state] + if match = scan(pattern) + for action in actions + case action + when Symbol + encoder.text_token match, action + when Array + case action.first + when :begin_group + encoder.begin_group action.last + state = action.last + states << state + when :end_group + encoder.end_group states.pop + state = states.last + end + end + end + + break + end + end && encoder.text_token(getch, :error) + end + + if options[:keep_state] + @state = state + end + + if [:string, :key].include? state + encoder.end_group state + end + + encoder + end + + end + +end +end |