Scanner for JSON (JavaScript Object Notation).
See json.org/ for a definition of the JSON lexic/grammar.
# File lib/coderay/scanners/json.rb, line 21 def scan_tokens encoder, options state = :initial stack = [] key_expected = false until eos? case state when :initial if match = scan(%r \s+ /) encoder.text_token match, :space elsif match = scan(%r"/) state = key_expected ? :key : :string encoder.begin_group state encoder.text_token match, :delimiter elsif match = scan(%r [:,\[{\]}] /) encoder.text_token match, :operator case match when ':' then key_expected = false when ',' then key_expected = true if stack.last == :object when '{' then stack << :object; key_expected = true when '[' then stack << :array when '}', ']' then stack.pop # no error recovery, but works for valid JSON end elsif match = scan(%r true | false | null /) encoder.text_token match, :value elsif match = scan(%r -? (?: 0 | [1-9]\d* ) /) if scan(%r \.\d+ (?:[eE][-+]?\d+)? | [eE][-+]? \d+ /) match << matched encoder.text_token match, :float else encoder.text_token match, :integer end else encoder.text_token getch, :error end when :string, :key if match = scan(%r[^\\"]+/) encoder.text_token match, :content elsif match = scan(%r"/) encoder.text_token match, :delimiter encoder.end_group state state = :initial elsif match = scan(%r \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /ox) encoder.text_token match, :char elsif match = scan(%r\\./) encoder.text_token match, :content elsif match = scan(%r \\ | $ /) encoder.end_group state encoder.text_token match, :error state = :initial else raise_inspect "else case \" reached; %p not handled." % peek(1), encoder end else raise_inspect 'Unknown state: %p' % [state], encoder end end if [:string, :key].include? state encoder.end_group state end encoder end