/
string_based.cr
88 lines (74 loc) · 1.96 KB
/
string_based.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# :nodoc:
class JSON::Lexer::StringBased < JSON::Lexer
def initialize(string : String)
super()
@string = string
@pos = 0
@number_start = 0
end
# Consumes a string by remembering the start position of it and then
# doing a substring of the original string.
# If we find an escape sequence (\) we can't do that anymore so we
# go through a slow path where we accumulate everything in a buffer
# to build the resulting string.
private def consume_string
start_pos = current_pos
while true
case next_char
when '\0'
raise "Unterminated string"
when '\\'
return consume_string_slow_path start_pos
when '"'
next_char
break
else
if 0 <= current_char.ord < 32
unexpected_char
end
end
end
if @expects_object_key
start_pos += 1
end_pos = current_pos - 1
@token.string_value = @string_pool.get(@string.to_unsafe + start_pos, end_pos - start_pos)
else
@token.string_value = string_range(start_pos + 1, current_pos - 1)
end
end
private def consume_string_slow_path(start_pos)
consume_string_with_buffer do
@buffer.write slice_range(start_pos + 1, current_pos)
@buffer << consume_string_escape_sequence
end
end
private def current_pos
@pos
end
def string_range(start_pos, end_pos) : String
@string.byte_slice(start_pos, end_pos - start_pos)
end
def slice_range(start_pos, end_pos) : Bytes
@string.to_slice[start_pos, end_pos - start_pos]
end
private def next_char_no_column_increment
@pos += 1
char = current_char
if char == '\0' && @pos != @string.bytesize
unexpected_char
end
char
end
private def current_char
@string.to_unsafe[@pos].chr
end
private def number_start
@number_start = current_pos
end
private def append_number_char
# Nothing
end
private def number_string
string_range(@number_start, current_pos)
end
end