Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
json
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
json
Commits
50ee0a62
Unverified
Commit
50ee0a62
authored
Mar 31, 2017
by
Niels Lohmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
🔨
replaced lookup-tables by switches
parent
4c821c9e
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
912 additions
and
386 deletions
+912
-386
src/json.hpp
src/json.hpp
+911
-385
test/src/unit-class_parser.cpp
test/src/unit-class_parser.cpp
+1
-1
No files found.
src/json.hpp
View file @
50ee0a62
...
@@ -10552,7 +10552,7 @@ class basic_json
...
@@ -10552,7 +10552,7 @@ class basic_json
}
}
explicit
lexer
(
std
::
istream
&
i
)
explicit
lexer
(
std
::
istream
&
i
)
:
ia
(
new
cached_input_stream_adapter
(
i
,
1
024
*
102
4
)),
:
ia
(
new
cached_input_stream_adapter
(
i
,
1
638
4
)),
decimal_point_char
(
get_decimal_point
())
decimal_point_char
(
get_decimal_point
())
{}
{}
...
@@ -10591,29 +10591,243 @@ class basic_json
...
@@ -10591,29 +10591,243 @@ class basic_json
// must be called after \u was read; returns following xxxx as hex or -1 when error
// must be called after \u was read; returns following xxxx as hex or -1 when error
int
get_codepoint
()
int
get_codepoint
()
{
{
// a mapping to discover hex numbers
assert
(
current
==
'u'
);
static
int8_t
ascii_to_hex
[
256
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
10
,
11
,
12
,
13
,
14
,
15
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
10
,
11
,
12
,
13
,
14
,
15
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
int
codepoint
=
0
;
int
codepoint
=
0
;
// check the next 4 bytes
switch
(
get
())
for
(
size_t
i
=
0
;
i
<
4
;
++
i
)
{
const
int8_t
digit
=
ascii_to_hex
[
static_cast
<
unsigned
char
>
(
get
())];
if
(
JSON_UNLIKELY
(
digit
==
-
1
))
{
{
case
'0'
:
break
;
case
'1'
:
codepoint
+=
0x1000
;
break
;
case
'2'
:
codepoint
+=
0x2000
;
break
;
case
'3'
:
codepoint
+=
0x3000
;
break
;
case
'4'
:
codepoint
+=
0x4000
;
break
;
case
'5'
:
codepoint
+=
0x5000
;
break
;
case
'6'
:
codepoint
+=
0x6000
;
break
;
case
'7'
:
codepoint
+=
0x7000
;
break
;
case
'8'
:
codepoint
+=
0x8000
;
break
;
case
'9'
:
codepoint
+=
0x9000
;
break
;
case
'A'
:
case
'a'
:
codepoint
+=
0xa000
;
break
;
case
'B'
:
case
'b'
:
codepoint
+=
0xb000
;
break
;
case
'C'
:
case
'c'
:
codepoint
+=
0xc000
;
break
;
case
'D'
:
case
'd'
:
codepoint
+=
0xd000
;
break
;
case
'E'
:
case
'e'
:
codepoint
+=
0xe000
;
break
;
case
'F'
:
case
'f'
:
codepoint
+=
0xf000
;
break
;
default:
return
-
1
;
return
-
1
;
}
}
else
switch
(
get
())
{
{
codepoint
+=
digit
;
case
'0'
:
break
;
case
'1'
:
codepoint
+=
0x0100
;
break
;
case
'2'
:
codepoint
+=
0x0200
;
break
;
case
'3'
:
codepoint
+=
0x0300
;
break
;
case
'4'
:
codepoint
+=
0x0400
;
break
;
case
'5'
:
codepoint
+=
0x0500
;
break
;
case
'6'
:
codepoint
+=
0x0600
;
break
;
case
'7'
:
codepoint
+=
0x0700
;
break
;
case
'8'
:
codepoint
+=
0x0800
;
break
;
case
'9'
:
codepoint
+=
0x0900
;
break
;
case
'A'
:
case
'a'
:
codepoint
+=
0x0a00
;
break
;
case
'B'
:
case
'b'
:
codepoint
+=
0x0b00
;
break
;
case
'C'
:
case
'c'
:
codepoint
+=
0x0c00
;
break
;
case
'D'
:
case
'd'
:
codepoint
+=
0x0d00
;
break
;
case
'E'
:
case
'e'
:
codepoint
+=
0x0e00
;
break
;
case
'F'
:
case
'f'
:
codepoint
+=
0x0f00
;
break
;
default:
return
-
1
;
}
}
// except the last byte, result must be multiplied by 16
switch
(
get
())
if
(
i
!=
3
)
{
{
codepoint
<<=
4
;
case
'0'
:
break
;
case
'1'
:
codepoint
+=
0x0010
;
break
;
case
'2'
:
codepoint
+=
0x0020
;
break
;
case
'3'
:
codepoint
+=
0x0030
;
break
;
case
'4'
:
codepoint
+=
0x0040
;
break
;
case
'5'
:
codepoint
+=
0x0050
;
break
;
case
'6'
:
codepoint
+=
0x0060
;
break
;
case
'7'
:
codepoint
+=
0x0070
;
break
;
case
'8'
:
codepoint
+=
0x0080
;
break
;
case
'9'
:
codepoint
+=
0x0090
;
break
;
case
'A'
:
case
'a'
:
codepoint
+=
0x00a0
;
break
;
case
'B'
:
case
'b'
:
codepoint
+=
0x00b0
;
break
;
case
'C'
:
case
'c'
:
codepoint
+=
0x00c0
;
break
;
case
'D'
:
case
'd'
:
codepoint
+=
0x00d0
;
break
;
case
'E'
:
case
'e'
:
codepoint
+=
0x00e0
;
break
;
case
'F'
:
case
'f'
:
codepoint
+=
0x00f0
;
break
;
default:
return
-
1
;
}
}
switch
(
get
())
{
case
'0'
:
break
;
case
'1'
:
codepoint
+=
0x0001
;
break
;
case
'2'
:
codepoint
+=
0x0002
;
break
;
case
'3'
:
codepoint
+=
0x0003
;
break
;
case
'4'
:
codepoint
+=
0x0004
;
break
;
case
'5'
:
codepoint
+=
0x0005
;
break
;
case
'6'
:
codepoint
+=
0x0006
;
break
;
case
'7'
:
codepoint
+=
0x0007
;
break
;
case
'8'
:
codepoint
+=
0x0008
;
break
;
case
'9'
:
codepoint
+=
0x0009
;
break
;
case
'A'
:
case
'a'
:
codepoint
+=
0x000a
;
break
;
case
'B'
:
case
'b'
:
codepoint
+=
0x000b
;
break
;
case
'C'
:
case
'c'
:
codepoint
+=
0x000c
;
break
;
case
'D'
:
case
'd'
:
codepoint
+=
0x000d
;
break
;
case
'E'
:
case
'e'
:
codepoint
+=
0x000e
;
break
;
case
'F'
:
case
'f'
:
codepoint
+=
0x000f
;
break
;
default:
return
-
1
;
}
}
return
codepoint
;
return
codepoint
;
...
@@ -10627,514 +10841,828 @@ class basic_json
...
@@ -10627,514 +10841,828 @@ class basic_json
// we entered the function by reading an open quote
// we entered the function by reading an open quote
assert
(
current
==
'\"'
);
assert
(
current
==
'\"'
);
static
unsigned
char
next
[
256
]
=
{
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
17
,
0
,
0
,
16
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
15
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
4
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
5
,
2
,
2
,
6
,
3
,
3
,
3
,
7
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
,
18
};
// state variable
int
state
=
-
1
;
// whether the state is already set
bool
state_set
=
false
;
while
(
true
)
while
(
true
)
{
{
// get next character
// get next character
get
();
get
();
switch
(
current
)
{
// end of file while parsing string
// end of file while parsing string
if
(
JSON_UNLIKELY
(
current
==
std
::
char_traits
<
char
>::
eof
()))
case
std
:
:
char_traits
<
char
>::
eof
()
:
{
{
error_message
=
"invalid string: missing closing quote"
;
error_message
=
"invalid string: missing closing quote"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
// after coping with EOF, we only cope with bytes
// closing quote
//assert(0 <= current and current <= 255);
case
'\"'
:
unsigned
char
ch
=
static_cast
<
unsigned
char
>
(
current
);
// get next state
state
=
state_set
?
state
:
next
[
ch
];
// reset variable
state_set
=
false
;
// 'add': 0,
// 'add_check1': 1,
// 'add_check2': 2,
// 'add_check3': 3,
// 'add_check_e0': 4,
// 'add_check_ed': 5,
// 'add_check_f0': 6,
// 'add_check_f4': 7,
// 'check1': 8,
// 'check2': 9,
// 'check3': 10,
// 'check_e0': 11,
// 'check_ed': 12,
// 'check_f0': 13,
// 'check_f4': 14,
// 'escape': 15,
// 'end': 16,
// 'error_invalid': 17,
// 'error_utf8': 18
assert
(
0
<=
state
and
state
<=
18
);
switch
(
state
)
{
// add
case
0
:
{
{
add
(
current
);
// terminate yytext
break
;
add
(
'\0'
);
--
yylen
;
return
token_type
::
value_string
;
}
}
//
add_check1
//
escapes
case
1
:
case
'\\'
:
{
{
add
(
current
);
switch
(
get
())
// next state is check1
{
state
=
8
;
// quotation mark
state_set
=
true
;
case
'\"'
:
add
(
'\"'
);
break
;
// reverse solidus
case
'\\'
:
add
(
'\\'
);
break
;
// solidus
case
'/'
:
add
(
'/'
);
break
;
// backspace
case
'b'
:
add
(
'\b'
);
break
;
// form feed
case
'f'
:
add
(
'\f'
);
break
;
// line feed
case
'n'
:
add
(
'\n'
);
break
;
break
;
// carriage return
case
'r'
:
add
(
'\r'
);
break
;
// tab
case
't'
:
add
(
'\t'
);
break
;
// unicode escapes
case
'u'
:
{
int
codepoint
;
int
codepoint1
=
get_codepoint
();
if
(
JSON_UNLIKELY
(
codepoint1
==
-
1
))
{
error_message
=
"invalid string: '
\\
u' must be followed by 4 hex digits"
;
return
token_type
::
parse_error
;
}
}
// add_check2
// check if code point is a high surrogate
case
2
:
if
(
0xD800
<=
codepoint1
and
codepoint1
<=
0xDBFF
)
{
{
add
(
current
);
// expect next \uxxxx entry
// next state is check2
if
(
JSON_LIKELY
(
get
()
==
'\\'
and
get
()
==
'u'
))
state
=
9
;
{
state_set
=
true
;
const
int
codepoint2
=
get_codepoint
();
break
;
if
(
JSON_UNLIKELY
(
codepoint2
==
-
1
))
{
error_message
=
"invalid string: '
\\
u' must be followed by 4 hex digits"
;
return
token_type
::
parse_error
;
}
}
// add_check3
// check if codepoint2 is a low surrogate
case
3
:
if
(
JSON_LIKELY
(
0xDC00
<=
codepoint2
and
codepoint2
<=
0xDFFF
))
{
{
add
(
current
);
codepoint
=
// next state is check3
// high surrogate occupies the most significant 22 bits
state
=
10
;
(
codepoint1
<<
10
)
state_set
=
true
;
// low surrogate occupies the least significant 15 bits
break
;
+
codepoint2
// there is still the 0xD800, 0xDC00 and 0x10000 noise
// in the result so we have to subtract with:
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
-
0x35FDC00
;
}
else
{
error_message
=
"invalid string: invalid low surrogate"
;
return
token_type
::
parse_error
;
}
}
else
{
error_message
=
"invalid string: missing low surrogate"
;
return
token_type
::
parse_error
;
}
}
else
{
if
(
JSON_UNLIKELY
(
0xDC00
<=
codepoint1
and
codepoint1
<=
0xDFFF
))
{
error_message
=
"invalid string: missing high surrogate"
;
return
token_type
::
parse_error
;
}
}
// add_check_e0
// only work with first code point
case
4
:
codepoint
=
codepoint1
;
}
// translate code point to bytes
if
(
codepoint
<
0x80
)
{
{
add
(
current
);
// 1-byte characters: 0xxxxxxx (ASCII)
// next state is check_e0
add
(
codepoint
);
state
=
11
;
}
state_set
=
true
;
else
if
(
codepoint
<=
0x7ff
)
{
// 2-byte characters: 110xxxxx 10xxxxxx
add
(
0xC0
|
(
codepoint
>>
6
));
add
(
0x80
|
(
codepoint
&
0x3F
));
}
else
if
(
codepoint
<=
0xffff
)
{
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
add
(
0xE0
|
(
codepoint
>>
12
));
add
(
0x80
|
((
codepoint
>>
6
)
&
0x3F
));
add
(
0x80
|
(
codepoint
&
0x3F
));
}
else
if
(
codepoint
<=
0x10ffff
)
{
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
add
(
0xF0
|
(
codepoint
>>
18
));
add
(
0x80
|
((
codepoint
>>
12
)
&
0x3F
));
add
(
0x80
|
((
codepoint
>>
6
)
&
0x3F
));
add
(
0x80
|
(
codepoint
&
0x3F
));
}
else
{
error_message
=
"invalid string: code points above U+10FFFF are invalid"
;
return
token_type
::
parse_error
;
}
break
;
break
;
}
}
// add_check_ed
// other characters after escape
case
5
:
default:
{
error_message
=
"invalid string: forbidden character after backspace"
;
add
(
current
);
return
token_type
::
parse_error
;
// next state is check_ed
}
state
=
12
;
state_set
=
true
;
break
;
break
;
}
}
// add_check_f0
// invalid control characters
case
6
:
case
'\x00'
:
case
'\x01'
:
case
'\x02'
:
case
'\x03'
:
case
'\x04'
:
case
'\x05'
:
case
'\x06'
:
case
'\x07'
:
case
'\x08'
:
case
'\x09'
:
case
'\x0a'
:
case
'\x0b'
:
case
'\x0c'
:
case
'\x0d'
:
case
'\x0e'
:
case
'\x0f'
:
case
'\x10'
:
case
'\x11'
:
case
'\x12'
:
case
'\x13'
:
case
'\x14'
:
case
'\x15'
:
case
'\x16'
:
case
'\x17'
:
case
'\x18'
:
case
'\x19'
:
case
'\x1a'
:
case
'\x1b'
:
case
'\x1c'
:
case
'\x1d'
:
case
'\x1e'
:
case
'\x1f'
:
{
{
add
(
current
);
error_message
=
"invalid string: control characters (U+0000 through U+001f) must be escaped"
;
// next state is check_f0
return
token_type
::
parse_error
;
state
=
13
;
state_set
=
true
;
break
;
}
}
// add_check_f4
// U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
case
7
:
case
'\x20'
:
case
'\x21'
:
case
'\x23'
:
case
'\x24'
:
case
'\x25'
:
case
'\x26'
:
case
'\x27'
:
case
'\x28'
:
case
'\x29'
:
case
'\x2a'
:
case
'\x2b'
:
case
'\x2c'
:
case
'\x2d'
:
case
'\x2e'
:
case
'\x2f'
:
case
'\x30'
:
case
'\x31'
:
case
'\x32'
:
case
'\x33'
:
case
'\x34'
:
case
'\x35'
:
case
'\x36'
:
case
'\x37'
:
case
'\x38'
:
case
'\x39'
:
case
'\x3a'
:
case
'\x3b'
:
case
'\x3c'
:
case
'\x3d'
:
case
'\x3e'
:
case
'\x3f'
:
case
'\x40'
:
case
'\x41'
:
case
'\x42'
:
case
'\x43'
:
case
'\x44'
:
case
'\x45'
:
case
'\x46'
:
case
'\x47'
:
case
'\x48'
:
case
'\x49'
:
case
'\x4a'
:
case
'\x4b'
:
case
'\x4c'
:
case
'\x4d'
:
case
'\x4e'
:
case
'\x4f'
:
case
'\x50'
:
case
'\x51'
:
case
'\x52'
:
case
'\x53'
:
case
'\x54'
:
case
'\x55'
:
case
'\x56'
:
case
'\x57'
:
case
'\x58'
:
case
'\x59'
:
case
'\x5a'
:
case
'\x5b'
:
case
'\x5d'
:
case
'\x5e'
:
case
'\x5f'
:
case
'\x60'
:
case
'\x61'
:
case
'\x62'
:
case
'\x63'
:
case
'\x64'
:
case
'\x65'
:
case
'\x66'
:
case
'\x67'
:
case
'\x68'
:
case
'\x69'
:
case
'\x6a'
:
case
'\x6b'
:
case
'\x6c'
:
case
'\x6d'
:
case
'\x6e'
:
case
'\x6f'
:
case
'\x70'
:
case
'\x71'
:
case
'\x72'
:
case
'\x73'
:
case
'\x74'
:
case
'\x75'
:
case
'\x76'
:
case
'\x77'
:
case
'\x78'
:
case
'\x79'
:
case
'\x7a'
:
case
'\x7b'
:
case
'\x7c'
:
case
'\x7d'
:
case
'\x7e'
:
case
'\x7f'
:
{
{
add
(
current
);
add
(
current
);
// next state is check_f4
state
=
14
;
state_set
=
true
;
break
;
break
;
}
}
// check1
// U+0080..U+07FF: bytes C2..DF 80..BF
case
8
:
case
'\xc2'
:
case
'\xc3'
:
case
'\xc4'
:
case
'\xc5'
:
case
'\xc6'
:
case
'\xc7'
:
case
'\xc8'
:
case
'\xc9'
:
case
'\xca'
:
case
'\xcb'
:
case
'\xcc'
:
case
'\xcd'
:
case
'\xce'
:
case
'\xcf'
:
case
'\xd0'
:
case
'\xd1'
:
case
'\xd2'
:
case
'\xd3'
:
case
'\xd4'
:
case
'\xd5'
:
case
'\xd6'
:
case
'\xd7'
:
case
'\xd8'
:
case
'\xd9'
:
case
'\xda'
:
case
'\xdb'
:
case
'\xdc'
:
case
'\xdd'
:
case
'\xde'
:
case
'\xdf'
:
{
{
if
(
JSON_LIKELY
(
0x80
<=
ch
and
ch
<=
0xBF
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
{
{
add
(
current
);
add
(
current
);
break
;
continue
;
}
}
else
{
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
//
check2
//
U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case
9
:
case
'\xe0'
:
{
{
if
(
JSON_LIKELY
(
0x80
<=
ch
and
ch
<=
0xBF
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\xa0'
<=
current
and
current
<=
'\xbf'
))
{
{
add
(
current
);
add
(
current
);
// next state is check1
get
();
state
=
8
;
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
state_set
=
true
;
break
;
}
else
{
{
add
(
current
);
continue
;
}
}
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
// check3
// U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
case
10
:
// U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
case
'\xe1'
:
case
'\xe2'
:
case
'\xe3'
:
case
'\xe4'
:
case
'\xe5'
:
case
'\xe6'
:
case
'\xe7'
:
case
'\xe8'
:
case
'\xe9'
:
case
'\xea'
:
case
'\xeb'
:
case
'\xec'
:
case
'\xee'
:
case
'\xef'
:
{
{
if
(
JSON_LIKELY
(
0x80
<=
ch
and
ch
<=
0xBF
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
{
{
add
(
current
);
add
(
current
);
// next state is check2
get
();
state
=
9
;
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
state_set
=
true
;
break
;
}
else
{
{
add
(
current
);
continue
;
}
}
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
//
check_e0
//
U+D000..U+D7FF: bytes ED 80..9F 80..BF
case
11
:
case
'\xed'
:
{
{
if
(
JSON_LIKELY
(
0xA0
<=
ch
and
ch
<=
0xBF
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\x9f'
))
{
{
add
(
current
);
add
(
current
);
// next state is check1
get
();
state
=
8
;
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
state_set
=
true
;
break
;
}
else
{
{
add
(
current
);
continue
;
}
}
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
//
check_ed
//
U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case
12
:
case
'\xf0'
:
{
{
if
(
JSON_LIKELY
(
0x80
<=
ch
and
ch
<=
0x9F
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x90'
<=
current
and
current
<=
'\xbf'
))
{
{
add
(
current
);
add
(
current
);
// next state is check1
get
();
state
=
8
;
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
state_set
=
true
;
break
;
}
else
{
{
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
{
add
(
current
);
continue
;
}
}
}
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
// check_f0
// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
case
13
:
case
'\xf1'
:
case
'\xf2'
:
case
'\xf3'
:
{
{
if
(
JSON_LIKELY
(
0x90
<=
ch
and
ch
<=
0xBF
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
{
{
add
(
current
);
add
(
current
);
// next state is check2
get
();
state
=
9
;
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
state_set
=
true
;
break
;
}
else
{
{
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
{
add
(
current
);
continue
;
}
}
}
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
//
check_f4
//
U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case
14
:
case
'\xf4'
:
{
{
if
(
JSON_LIKELY
(
0x80
<=
ch
and
ch
<=
0x8F
))
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\x8f'
))
{
{
add
(
current
);
add
(
current
);
// next state is check2
get
();
state
=
9
;
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
state_set
=
true
;
{
break
;
add
(
current
);
get
();
if
(
JSON_LIKELY
(
'\x80'
<=
current
and
current
<=
'\xbf'
))
{
add
(
current
);
continue
;
}
}
else
}
}
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
}
// remaining bytes (80..C1 and F5..FF) are not well-formed
default:
{
{
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
}
}
}
// escape
static
void
strtof
(
float
&
f
,
const
char
*
str
,
char
**
endptr
)
noexcept
case
15
:
{
{
switch
(
get
())
f
=
std
::
strtof
(
str
,
endptr
);
}
static
void
strtof
(
double
&
f
,
const
char
*
str
,
char
**
endptr
)
noexcept
{
{
// quotation mark
f
=
std
::
strtod
(
str
,
endptr
);
case
'\"'
:
}
add
(
'\"'
);
break
;
// reverse solidus
case
'\\'
:
add
(
'\\'
);
break
;
// solidus
case
'/'
:
add
(
'/'
);
break
;
// backspace
case
'b'
:
add
(
'\b'
);
break
;
// form feed
case
'f'
:
add
(
'\f'
);
break
;
// line feed
case
'n'
:
add
(
'\n'
);
break
;
// carriage return
case
'r'
:
add
(
'\r'
);
break
;
// tab
case
't'
:
add
(
'\t'
);
break
;
// unicode escapes
static
void
strtof
(
long
double
&
f
,
const
char
*
str
,
char
**
endptr
)
noexcept
case
'u'
:
{
{
int
codepoint
;
f
=
std
::
strtold
(
str
,
endptr
)
;
int
codepoint1
=
get_codepoint
();
}
if
(
JSON_UNLIKELY
(
codepoint1
==
-
1
))
/*!
state | 0 | 1-9 | e E | + | - | . | anything
---------|----------|----------|----------|---------|---------|----------|-----------
init | zero | any1 | [error] | [error] | minus | [error] | [error]
minus | zero | any1 | [error] | [error] | [error] | [error] | [error]
zero | done | done | exponent | done | done | decimal1 | done
any1 | any1 | any1 | exponent | done | done | decimal1 | done
decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error]
decimal2 | decimal2 | decimal2 | exponent | done | done | done | done
exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
any2 | any2 | any2 | done | done | done | done | done
*/
token_type
scan_number
()
{
{
error_message
=
"invalid string: '
\\
u' must be followed by 4 hex digits"
;
reset
();
return
token_type
::
parse_error
;
// the type of the parsed number; initially set to unsigned; will
// be changed if minus sign, decimal point or exponent is read
token_type
number_type
=
token_type
::
value_unsigned
;
// state: we just found out we need to scan a number
switch
(
current
)
{
case
'-'
:
{
add
(
current
);
goto
scan_number_minus
;
}
}
// check if code point is a high surrogate
case
'0'
:
if
(
0xD800
<=
codepoint1
and
codepoint1
<=
0xDBFF
)
{
{
// expect next \uxxxx entry
add
(
current
);
if
(
JSON_LIKELY
(
get
()
==
'\\'
and
get
()
==
'u'
))
goto
scan_number_zero
;
}
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
{
int
codepoint2
=
get_codepoint
();
add
(
current
);
goto
scan_number_any1
;
}
if
(
JSON_UNLIKELY
(
codepoint2
==
-
1
))
default:
{
{
error_message
=
"invalid string: '
\\
u' must be followed by 4 hex digits"
;
// all other characters are rejected outside scan_number()
return
token_type
::
parse_error
;
assert
(
false
);
// LCOV_EXCL_LINE
}
}
}
// check if codepoint2 is a low surrogate
scan_number_minus:
if
(
JSON_LIKELY
(
0xDC00
<=
codepoint2
and
codepoint2
<=
0xDFFF
))
// state: we just parsed a leading minus sign
number_type
=
token_type
::
value_integer
;
switch
(
get
())
{
{
codepoint
=
case
'0'
:
// high surrogate occupies the most significant 22 bits
{
(
codepoint1
<<
10
)
add
(
current
);
// low surrogate occupies the least significant 15 bits
goto
scan_number_zero
;
+
codepoint2
// there is still the 0xD800, 0xDC00 and 0x10000 noise
// in the result so we have to subtract with:
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
-
0x35FDC00
;
}
}
else
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
{
error_message
=
"invalid string: invalid low surrogate"
;
add
(
current
);
return
token_type
::
parse_error
;
goto
scan_number_any1
;
}
}
}
else
default:
{
{
error_message
=
"invalid string: missing low surrogate
"
;
error_message
=
"invalid number; expected digit after '-'
"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
}
else
scan_number_zero:
// state: we just parse a zero (maybe with a leading minus sign)
switch
(
get
())
{
{
if
(
JSON_UNLIKELY
(
0xDC00
<=
codepoint1
and
codepoint1
<=
0xDFFF
))
case
'.'
:
{
{
error_message
=
"invalid string: missing high surrogate"
;
add
(
decimal_point_char
)
;
return
token_type
::
parse_error
;
goto
scan_number_decimal1
;
}
}
// only work with first code point
case
'e'
:
codepoint
=
codepoint1
;
case
'E'
:
{
add
(
current
);
goto
scan_number_exponent
;
}
}
// translate code point to bytes
default:
if
(
codepoint
<
0x80
)
{
{
// 1-byte characters: 0xxxxxxx (ASCII)
goto
scan_number_done
;
add
(
codepoint
);
}
}
else
if
(
codepoint
<=
0x7ff
)
{
// 2-byte characters: 110xxxxx 10xxxxxx
add
(
0xC0
|
(
codepoint
>>
6
));
add
(
0x80
|
(
codepoint
&
0x3F
));
}
}
else
if
(
codepoint
<=
0xffff
)
scan_number_any1:
// state: we just parsed a number 0-9 (maybe with a leading minus sign)
switch
(
get
())
{
{
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
case
'0'
:
add
(
0xE0
|
(
codepoint
>>
12
));
case
'1'
:
add
(
0x80
|
((
codepoint
>>
6
)
&
0x3F
));
case
'2'
:
add
(
0x80
|
(
codepoint
&
0x3F
));
case
'3'
:
}
case
'4'
:
else
if
(
codepoint
<=
0x10ffff
)
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
{
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
add
(
current
);
add
(
0xF0
|
(
codepoint
>>
18
));
goto
scan_number_any1
;
add
(
0x80
|
((
codepoint
>>
12
)
&
0x3F
));
add
(
0x80
|
((
codepoint
>>
6
)
&
0x3F
));
add
(
0x80
|
(
codepoint
&
0x3F
));
}
}
else
case
'.'
:
{
{
error_message
=
"invalid string: code points above U+10FFFF are invalid"
;
add
(
decimal_point_char
)
;
return
token_type
::
parse_error
;
goto
scan_number_decimal1
;
}
}
break
;
case
'e'
:
case
'E'
:
{
add
(
current
);
goto
scan_number_exponent
;
}
}
// other characters after escape
default:
default:
error_message
=
"invalid string: forbidden character after backspace"
;
{
return
token_type
::
parse_error
;
goto
scan_number_done
;
}
}
break
;
}
}
// end
scan_number_decimal1:
case
16
:
// state: we just parsed a decimal point
number_type
=
token_type
::
value_float
;
switch
(
get
())
{
{
// terminate yytext
case
'0'
:
add
(
'\0'
);
case
'1'
:
--
yylen
;
case
'2'
:
return
token_type
::
value_string
;
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
add
(
current
);
goto
scan_number_decimal2
;
}
}
// error_invalid
default:
case
17
:
{
{
error_message
=
"invalid string: control characters (U+0000 through U+001f) must be escaped
"
;
error_message
=
"invalid number; expected digit after '.'
"
;
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
// error_utf8
scan_number_decimal2:
case
18
:
// we just parsed at least one number after a decimal point
switch
(
get
())
{
{
error_message
=
"invalid string: not well-formed UTF-8 byte"
;
case
'0'
:
return
token_type
::
parse_error
;
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
add
(
current
);
goto
scan_number_decimal2
;
}
}
default:
case
'e'
:
case
'E'
:
{
{
assert
(
false
);
// LCOV_EXCL_LINE
add
(
current
);
}
goto
scan_number_exponent
;
}
}
default:
{
goto
scan_number_done
;
}
}
}
}
static
void
strtof
(
float
&
f
,
const
char
*
str
,
char
**
endptr
)
noexcept
scan_number_exponent:
// we just parsed an exponent
number_type
=
token_type
::
value_float
;
switch
(
get
())
{
{
f
=
std
::
strtof
(
str
,
endptr
);
case
'+'
:
case
'-'
:
{
add
(
current
);
goto
scan_number_sign
;
}
}
static
void
strtof
(
double
&
f
,
const
char
*
str
,
char
**
endptr
)
noexcept
case
'0'
:
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
{
f
=
std
::
strtod
(
str
,
endptr
);
add
(
current
);
goto
scan_number_any2
;
}
}
static
void
strtof
(
long
double
&
f
,
const
char
*
str
,
char
**
endptr
)
noexcept
default:
{
{
f
=
std
::
strtold
(
str
,
endptr
);
error_message
=
"invalid number; expected '+', '-', or digit after exponent"
;
return
token_type
::
parse_error
;
}
}
}
token_type
scan_number
()
scan_number_sign:
// we just parsed an exponent sign
switch
(
get
())
{
{
static
unsigned
char
lookup
[
9
][
256
]
=
case
'0'
:
{
case
'1'
:
{
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
1
,
10
,
10
,
3
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
},
case
'2'
:
{
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
3
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
},
case
'3'
:
{
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
4
,
9
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
5
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
5
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
},
case
'4'
:
{
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
4
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
5
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
5
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
},
case
'5'
:
{
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
},
case
'6'
:
{
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
8
,
10
,
8
,
10
,
10
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
},
case
'7'
:
{
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
6
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
5
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
5
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
},
case
'8'
:
{
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
},
case
'9'
:
{
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
7
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
,
10
}
};
reset
();
bool
has_sign
=
false
;
bool
has_exp
=
false
;
bool
has_point
=
false
;
int
state
=
lookup
[
0
][
static_cast
<
unsigned
char
>
(
current
)];
int
old_state
=
0
;
while
(
state
!=
9
)
{
{
has_sign
=
has_sign
or
(
state
==
1
);
add
(
current
);
has_point
=
has_point
or
(
state
==
4
)
;
goto
scan_number_any2
;
has_exp
=
has_exp
or
(
state
==
5
);
}
if
(
JSON_UNLIKELY
(
state
==
10
))
default:
{
// create error message based on previous state
switch
(
old_state
)
{
{
case
0
:
error_message
=
"invalid number; expected '-' or digit"
;
break
;
case
1
:
error_message
=
"invalid number; expected digit after '-'"
;
break
;
case
4
:
error_message
=
"invalid number; expected digit after '.'"
;
break
;
case
5
:
error_message
=
"invalid number; expected '+', '-', or digit after exponent"
;
break
;
case
8
:
error_message
=
"invalid number; expected digit after exponent sign"
;
error_message
=
"invalid number; expected digit after exponent sign"
;
break
;
default:
assert
(
false
);
// no error in the other states
break
;
}
return
token_type
::
parse_error
;
return
token_type
::
parse_error
;
}
}
}
// add current character and fix decimal point
scan_number_any2:
add
((
state
==
4
)
?
decimal_point_char
:
current
);
// we just parsed a number after the exponent or exponent sign
get
();
switch
(
get
())
old_state
=
state
;
{
state
=
lookup
[
state
][
static_cast
<
unsigned
char
>
(
current
)];
case
'0'
:
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
add
(
current
);
goto
scan_number_any2
;
}
default:
{
goto
scan_number_done
;
}
}
}
scan_number_done:
// unget the character after the number
// unget the character after the number
unget
();
unget
();
...
@@ -11143,27 +11671,39 @@ class basic_json
...
@@ -11143,27 +11671,39 @@ class basic_json
--
yylen
;
--
yylen
;
// try to parse integers first and fall back to floats
// try to parse integers first and fall back to floats
if
(
n
ot
has_exp
and
not
has_point
)
if
(
n
umber_type
==
token_type
::
value_unsigned
)
{
{
char
*
endptr
=
nullptr
;
errno
=
0
;
errno
=
0
;
if
(
has_sign
)
const
auto
x
=
std
::
strtoull
(
yytext
.
data
(),
&
endptr
,
10
);
// we checked the number format before
assert
(
endptr
==
yytext
.
data
()
+
yylen
);
if
(
errno
==
0
)
{
{
char
*
endptr
=
nullptr
;
value_unsigned
=
static_cast
<
number_unsigned_t
>
(
x
);
const
auto
x
=
std
::
strtoll
(
yytext
.
data
(),
&
endptr
,
10
);
if
(
value_unsigned
==
x
)
value_integer
=
static_cast
<
number_integer_t
>
(
x
);
if
(
errno
==
0
and
endptr
==
yytext
.
data
()
+
yylen
and
value_integer
==
x
)
{
{
return
token_type
::
value_
integer
;
return
token_type
::
value_
unsigned
;
}
}
}
}
else
}
else
if
(
number_type
==
token_type
::
value_integer
)
{
{
char
*
endptr
=
nullptr
;
char
*
endptr
=
nullptr
;
const
auto
x
=
std
::
strtoull
(
yytext
.
data
(),
&
endptr
,
10
);
errno
=
0
;
value_unsigned
=
static_cast
<
number_unsigned_t
>
(
x
);
const
auto
x
=
std
::
strtoll
(
yytext
.
data
(),
&
endptr
,
10
);
if
(
errno
==
0
and
endptr
==
yytext
.
data
()
+
yylen
and
value_unsigned
==
x
)
// we checked the number format before
assert
(
endptr
==
yytext
.
data
()
+
yylen
);
if
(
errno
==
0
)
{
{
return
token_type
::
value_unsigned
;
value_integer
=
static_cast
<
number_integer_t
>
(
x
);
if
(
value_integer
==
x
)
{
return
token_type
::
value_integer
;
}
}
}
}
}
}
...
@@ -11223,17 +11763,9 @@ class basic_json
...
@@ -11223,17 +11763,9 @@ class basic_json
int
get
()
int
get
()
{
{
++
chars_read
;
++
chars_read
;
return
next_unget
if
(
JSON_UNLIKELY
(
next_unget
))
?
(
next_unget
=
false
,
current
)
{
:
(
current
=
ia
->
get_character
());
next_unget
=
false
;
}
else
{
current
=
ia
->
get_character
();
}
return
current
;
}
}
/// unget a character to the input
/// unget a character to the input
...
@@ -11317,7 +11849,6 @@ class basic_json
...
@@ -11317,7 +11849,6 @@ class basic_json
}
}
else
else
{
{
// add character as is
// add character as is
ss
<<
c
;
ss
<<
c
;
}
}
...
@@ -11441,8 +11972,7 @@ class basic_json
...
@@ -11441,8 +11972,7 @@ class basic_json
public:
public:
/// a parser reading from a string literal
/// a parser reading from a string literal
parser
(
const
char
*
buff
,
const
parser_callback_t
cb
=
nullptr
)
parser
(
const
char
*
buff
,
const
parser_callback_t
cb
=
nullptr
)
:
callback
(
cb
),
:
callback
(
cb
),
m_lexer
(
buff
,
std
::
strlen
(
buff
))
m_lexer
(
buff
,
std
::
strlen
(
buff
))
{}
{}
/*!
/*!
...
@@ -11528,22 +12058,11 @@ class basic_json
...
@@ -11528,22 +12058,11 @@ class basic_json
return
result
;
return
result
;
}
}
// no comma is expected here
// parse values
unexpect
(
lexer
::
token_type
::
value_separator
);
while
(
true
)
// otherwise: parse key-value pairs
do
{
// ugly, but could be fixed with loop reorganization
if
(
last_token
==
lexer
::
token_type
::
value_separator
)
{
{
get_token
();
}
// store key
// store key
expect
(
lexer
::
token_type
::
value_string
);
expect
(
lexer
::
token_type
::
value_string
);
// FIXME get_string returns const char*; maybe we can
// avoid this copy in the future
const
auto
key
=
m_lexer
.
get_string
();
const
auto
key
=
m_lexer
.
get_string
();
bool
keep_tag
=
false
;
bool
keep_tag
=
false
;
...
@@ -11571,12 +12090,20 @@ class basic_json
...
@@ -11571,12 +12090,20 @@ class basic_json
{
{
result
[
key
]
=
std
::
move
(
value
);
result
[
key
]
=
std
::
move
(
value
);
}
}
// comma -> next value
if
(
last_token
==
lexer
::
token_type
::
value_separator
)
{
get_token
();
continue
;
}
}
while
(
last_token
==
lexer
::
token_type
::
value_separator
);
// closing }
// closing }
expect
(
lexer
::
token_type
::
end_object
);
expect
(
lexer
::
token_type
::
end_object
);
get_token
();
get_token
();
break
;
}
if
(
keep
and
callback
and
not
callback
(
--
depth
,
parse_event_t
::
object_end
,
result
))
if
(
keep
and
callback
and
not
callback
(
--
depth
,
parse_event_t
::
object_end
,
result
))
{
{
result
=
basic_json
(
value_t
::
discarded
);
result
=
basic_json
(
value_t
::
discarded
);
...
@@ -11609,30 +12136,29 @@ class basic_json
...
@@ -11609,30 +12136,29 @@ class basic_json
return
result
;
return
result
;
}
}
// no comma is expected here
// parse values
unexpect
(
lexer
::
token_type
::
value_separator
);
while
(
true
)
// otherwise: parse values
do
{
// ugly, but could be fixed with loop reorganization
if
(
last_token
==
lexer
::
token_type
::
value_separator
)
{
{
get_token
();
}
// parse value
// parse value
auto
value
=
parse_internal
(
keep
);
auto
value
=
parse_internal
(
keep
);
if
(
keep
and
not
value
.
is_discarded
())
if
(
keep
and
not
value
.
is_discarded
())
{
{
result
.
push_back
(
std
::
move
(
value
));
result
.
push_back
(
std
::
move
(
value
));
}
}
// comma -> next value
if
(
last_token
==
lexer
::
token_type
::
value_separator
)
{
get_token
();
continue
;
}
}
while
(
last_token
==
lexer
::
token_type
::
value_separator
);
// closing ]
// closing ]
expect
(
lexer
::
token_type
::
end_array
);
expect
(
lexer
::
token_type
::
end_array
);
get_token
();
get_token
();
break
;
}
if
(
keep
and
callback
and
not
callback
(
--
depth
,
parse_event_t
::
array_end
,
result
))
if
(
keep
and
callback
and
not
callback
(
--
depth
,
parse_event_t
::
array_end
,
result
))
{
{
result
=
basic_json
(
value_t
::
discarded
);
result
=
basic_json
(
value_t
::
discarded
);
...
@@ -11728,7 +12254,7 @@ class basic_json
...
@@ -11728,7 +12254,7 @@ class basic_json
*/
*/
void
expect
(
typename
lexer
::
token_type
t
)
const
void
expect
(
typename
lexer
::
token_type
t
)
const
{
{
if
(
t
!=
last_token
)
if
(
JSON_UNLIKELY
(
t
!=
last_token
)
)
{
{
std
::
string
error_msg
=
"syntax error - "
;
std
::
string
error_msg
=
"syntax error - "
;
if
(
last_token
==
lexer
::
token_type
::
parse_error
)
if
(
last_token
==
lexer
::
token_type
::
parse_error
)
...
@@ -11750,7 +12276,7 @@ class basic_json
...
@@ -11750,7 +12276,7 @@ class basic_json
*/
*/
void
unexpect
(
typename
lexer
::
token_type
t
)
const
void
unexpect
(
typename
lexer
::
token_type
t
)
const
{
{
if
(
t
==
last_token
)
if
(
JSON_UNLIKELY
(
t
==
last_token
)
)
{
{
std
::
string
error_msg
=
"syntax error - "
;
std
::
string
error_msg
=
"syntax error - "
;
if
(
last_token
==
lexer
::
token_type
::
parse_error
)
if
(
last_token
==
lexer
::
token_type
::
parse_error
)
...
...
test/src/unit-class_parser.cpp
View file @
50ee0a62
...
@@ -659,7 +659,7 @@ TEST_CASE("parser class")
...
@@ -659,7 +659,7 @@ TEST_CASE("parser class")
// test case to make sure no comma preceeds the first key
// test case to make sure no comma preceeds the first key
CHECK_THROWS_AS
(
json
::
parser
(
"{,
\"
key
\"
: false}"
).
parse
(),
json
::
parse_error
);
CHECK_THROWS_AS
(
json
::
parser
(
"{,
\"
key
\"
: false}"
).
parse
(),
json
::
parse_error
);
CHECK_THROWS_WITH
(
json
::
parser
(
"{,
\"
key
\"
: false}"
).
parse
(),
CHECK_THROWS_WITH
(
json
::
parser
(
"{,
\"
key
\"
: false}"
).
parse
(),
"[json.exception.parse_error.101] parse error at 2: syntax error - unexpected ','"
);
"[json.exception.parse_error.101] parse error at 2: syntax error - unexpected ','
; expected string literal
"
);
// test case to make sure an object is properly closed
// test case to make sure an object is properly closed
CHECK_THROWS_AS
(
json
::
parser
(
"[{
\"
key
\"
: false true]"
).
parse
(),
json
::
parse_error
);
CHECK_THROWS_AS
(
json
::
parser
(
"[{
\"
key
\"
: false true]"
).
parse
(),
json
::
parse_error
);
CHECK_THROWS_WITH
(
json
::
parser
(
"[{
\"
key
\"
: false true]"
).
parse
(),
CHECK_THROWS_WITH
(
json
::
parser
(
"[{
\"
key
\"
: false true]"
).
parse
(),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment