Slide 51
Slide 51 text
case @state
when :start_document
case ch
when LEFT_BRACE
@state = :start_object
@stack.push(:object)
notify_start_document
notify_start_object
when LEFT_BRACKET
@state = :start_array
@stack.push(:array)
notify_start_document
notify_start_array
when WS
# ignore
else
error("Expected object or array start")
end
when :start_object
case ch
when RIGHT_BRACE
end_container(:object)
when QUOTE
@state = :start_string
@stack.push(:key)
when WS
# ignore
else
error("Expected object key start")
end
when :start_string
case ch
when QUOTE
if @stack.pop == :string
@state = :end_value
notify_value(@buf)
else # :key
@state = :end_key
notify_key(@buf)
end
@buf = ""
when BACKSLASH
@state = :start_escape
when CONTROL
error('Control characters must be escaped')
else
@buf << ch
end
when :start_escape
case ch
when QUOTE, BACKSLASH, SLASH
@buf << ch
@state = :start_string
when B
@buf << "\b"
@state = :start_string
when F
@buf << "\f"
@state = :start_string
when N
@buf << "\n"
@state = :start_string
when R
@buf << "\r"
@state = :start_string
when T
@buf << "\t"
@state = :start_string
when U
@state = :unicode_escape
else
error("Expected escaped character")
end
when :unicode_escape
case ch
when HEX
@unicode << ch
if @unicode.size == 4
codepoint = @unicode.slice!(0, 4).hex
if codepoint >= 0xD800 && codepoint <=
0xDBFF
error('Expected low surrogate pair half')
if @stack[-1].is_a?(Fixnum)
@state = :start_surrogate_pair
@stack.push(codepoint)
elsif codepoint >= 0xDC00 && codepoint <=
0xDFFF
high = @stack.pop
error('Expected high surrogate pair
half') unless high.is_a?(Fixnum)
pair = ((high - 0xD800) * 0x400) +
(codepoint - 0xDC00) + 0x10000
@buf << pair
@state = :start_string
else
@buf << codepoint
@state = :start_string
end
end
else
error('Expected unicode escape hex digit')
end
when :start_surrogate_pair
case ch
when BACKSLASH
@state = :start_surrogate_pair_u
else
error('Expected low surrogate pair half')
end
when :start_surrogate_pair_u
case ch
when U
@state = :unicode_escape
else
error('Expected low surrogate pair half')
end
when :start_negative_number
case ch
when ZERO
@state = :start_zero
@buf << ch
when DIGIT_1_9
@state = :start_int
@buf << ch
else
error('Expected 0-9 digit')
end
when :start_zero
case ch
when POINT
@state = :start_float
@buf << ch
when EXPONENT
@state = :start_exponent
@buf << ch
else
@state = :end_value
notify_value(@buf.to_i)
@buf = ""
@pos -= 1
redo
end
when :start_float
case ch
when DIGIT
@state = :in_float
@buf << ch
else
error('Expected 0-9 digit')
end
when :in_float
case ch
when DIGIT
@buf << ch
when EXPONENT
@state = :start_exponent
@buf << ch
else
@state = :end_value
notify_value(@buf.to_f)
@buf = ""
@pos -= 1
redo
end
when :start_exponent
case ch
when MINUS, PLUS, DIGIT
@state = :in_exponent
@buf << ch
else
error('Expected +, -, or 0-9 digit')
end
when :in_exponent
case ch
when DIGIT
@buf << ch
else
error('Expected 0-9 digit') unless @buf =~
DIGIT_END
@state = :end_value
num = @buf.include?('.') ? @buf.to_f :
@buf.to_i
notify_value(num)
@buf = ""
@pos -= 1
redo
end
when :start_int
case ch
when DIGIT
@buf << ch
when POINT
@state = :start_float
@buf << ch
when EXPONENT
@state = :start_exponent
@buf << ch
else
@state = :end_value
notify_value(@buf.to_i)
@buf = ""
@pos -= 1
redo
end
when :start_true
keyword(TRUE_KEYWORD, true, TRUE_RE, ch)
when :start_false
keyword(FALSE_KEYWORD, false, FALSE_RE, ch)
when :start_null
keyword(NULL_KEYWORD, nil, NULL_RE, ch)