module MiniJSON
Constants
- EMPTY_BYTES
- ESCAPE_TO_VALUE
- KEY_REGEXP
- NUMBER_REGEXP
- VERSION
Public Class Methods
parse(str)
click to toggle source
# File lib/minijson.rb, line 7 def parse(str) parser(lexer(str)) end
Also aliased as: load
Private Class Methods
is_empty?(tok)
click to toggle source
# File lib/minijson.rb, line 52 def is_empty?(tok) tok.each_char.all? { |i| EMPTY_BYTES.include? i } end
lexer(str)
click to toggle source
# File lib/minijson.rb, line 30 def lexer(str) str.scan(lexer_regexp).map(&:first) end
lexer_regexp()
click to toggle source
# File lib/minijson.rb, line 15 def lexer_regexp @lexer_regexp ||= begin meaningful_characters = /[()\[\]{}",:]/ string_escapes = /\\(?:[\\\/"bfnrt]|u[0-9a-fA-F]{4})/ numbers = /-?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?/ space = /[ \r\n\t]+/ rest = /[^"\\: \r\n\t]+/ very_rest = /.+/ /(#{ [meaningful_characters, string_escapes, numbers, space, rest, very_rest].join('|') })/ end end
parser(toks)
click to toggle source
# File lib/minijson.rb, line 60 def parser(toks) state = :value # popping is cheaper than shifting toks = toks.reverse value = nil finalizers = [proc { |i| value = i }] structs = [] hash_keys = [] finalizer = proc { |i| finalizers.pop.(i) } until toks.empty? tok = toks.pop case state when :value, :top_value, :struct_value case tok when '{' structs << {} toks << ',' when '[' structs << [] toks << ',' when '}', ']' parser_error(tok) if structs.empty? parser_error(tok) if structs.last.class == Array && tok != ']' parser_error(tok) if structs.last.class == Hash && tok != '}' finalizer.(structs.pop) when ',' # warning: [,,,,] will cause a weird behavior, but will be caught case structs.last when nil parser_error(tok) when Array finalizers << proc do |i| parser_error(tok) unless structs.last structs.last << i end state = :struct_value when Hash finalizers << proc do |i| parser_error(tok) unless structs.last && hash_keys.last structs.last[hash_keys.pop] = i end state = :key end when 'true' finalizer.(true) when 'false' finalizer.(false) when 'null' finalizer.(nil) when method(:is_empty?).to_proc # nothing when '"' finalizer.(receive_string(toks)) when NUMBER_REGEXP finalizer.(receive_number(tok)) else parser_error(tok) end when :key case tok when '"' hash_keys << receive_string(toks) when method(:is_empty?).to_proc next when KEY_REGEXP hash_keys << tok else parser_error(tok) end state = :colon when :colon case tok when ':' state = :value when method(:is_empty?).to_proc # nothing else parser_error(tok) end end end parser_error("END") unless [finalizers, structs, hash_keys].all?(&:empty?) value end
parser_error(tok)
click to toggle source
# File lib/minijson.rb, line 56 def parser_error(tok) raise ParserError, "unexpected token at '#{tok}'" end
receive_number(tok)
click to toggle source
# File lib/minijson.rb, line 169 def receive_number(tok) if tok.match?(/[e.]/) tok.to_f else tok.to_i end end
receive_string(toks)
click to toggle source
# File lib/minijson.rb, line 152 def receive_string(toks) str = [] while true tok = toks.pop if tok == nil parser_error('"'+toks.join) elsif tok == '"' break elsif tok.start_with? '\\' str << ESCAPE_TO_VALUE[tok] else str << tok end end str.join end