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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/json_completer/completion_engine.rb', line 5
def complete(partial_json)
input = partial_json
input_length = input.bytesize
if @state.nil? || @state.input_length > input_length
@state = ParsingState.new
end
return input if input.empty?
return input if valid_json_primitive_or_document?(input)
if @state.input_length == input_length && !@state.output_tokens.empty?
return finalize_completion(@state.output_tokens.dup, @state.context_stack.dup, @state.incomplete_string_token)
end
output_tokens = @state.output_tokens.dup
context_stack = @state.context_stack.dup
index = @state.last_index
incomplete_string_token = @state.incomplete_string_token
if incomplete_string_token && output_tokens.last&.start_with?('"') && output_tokens.last.end_with?('"')
output_tokens.pop
end
while index < input_length
if incomplete_string_token && index == @state.last_index
index, status = Scanners.scan_string(input, index, incomplete_string_token)
break unless %i[terminated invalid_unicode].include?(status)
output_tokens << incomplete_string_token.buffer.string
incomplete_string_token = nil
next
end
byte = input.getbyte(index)
last_significant_char_in_output = get_last_significant_char(output_tokens)
case byte
when 9, 10, 13, 32
output_tokens << input.byteslice(index, 1)
index += 1
when 34
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
string_token = Scanners::CompletionStringToken.new
index, status = Scanners.scan_string(input, index + 1, string_token)
if %i[terminated invalid_unicode].include?(status)
output_tokens << string_token.buffer.string
else
incomplete_string_token = string_token
end
when 44
remove_trailing_comma(output_tokens)
output_tokens << ','
index += 1
when 45, 48..57
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
num_str, consumed = Scanners.scan_number_literal(input, index)
output_tokens << num_str
index += consumed
when 58
remove_trailing_comma(output_tokens) if last_significant_char_in_output == ','
output_tokens << ':'
index += 1
when 91
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
output_tokens << '['
context_stack << '['
index += 1
when 93
output_tokens << ']'
context_stack.pop if !context_stack.empty? && context_stack.last == '['
index += 1
when 102
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
keyword_val, consumed = Scanners.scan_keyword_literal(input, index, KEYWORD_MAP['f'])
output_tokens << keyword_val
index += consumed
when 110
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
keyword_val, consumed = Scanners.scan_keyword_literal(input, index, KEYWORD_MAP['n'])
output_tokens << keyword_val
index += consumed
when 116
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
keyword_val, consumed = Scanners.scan_keyword_literal(input, index, KEYWORD_MAP['t'])
output_tokens << keyword_val
index += consumed
when 123
ensure_comma_before_new_item(output_tokens, context_stack, last_significant_char_in_output)
ensure_colon_if_value_expected(output_tokens, context_stack, last_significant_char_in_output)
output_tokens << '{'
context_stack << '{'
index += 1
when 125
remove_trailing_comma(output_tokens)
output_tokens << '}'
context_stack.pop if !context_stack.empty? && context_stack.last == '{'
index += 1
else
index += 1
end
end
@state = ParsingState.new(
output_tokens: output_tokens,
context_stack: context_stack,
last_index: index,
input_length: input_length,
incomplete_string_token: incomplete_string_token
)
finalize_completion(output_tokens.dup, context_stack.dup, incomplete_string_token)
end
|