🔨 using a vector<bool> for the parser hierarchy
This commit is contained in:
parent
5f723bbec6
commit
850671b9f1
2 changed files with 166 additions and 180 deletions
|
@ -162,10 +162,9 @@ class parser
|
||||||
private:
|
private:
|
||||||
bool sax_parse_internal(json_sax_t* sax)
|
bool sax_parse_internal(json_sax_t* sax)
|
||||||
{
|
{
|
||||||
// two values for the structured values
|
|
||||||
enum class parse_state_t { array_value, object_value };
|
|
||||||
// stack to remember the hieararchy of structured values we are parsing
|
// stack to remember the hieararchy of structured values we are parsing
|
||||||
std::vector<parse_state_t> states;
|
// true = array; false = object
|
||||||
|
std::vector<bool> states;
|
||||||
// value to avoid a goto (see comment where set to true)
|
// value to avoid a goto (see comment where set to true)
|
||||||
bool skip_to_state_evaluation = false;
|
bool skip_to_state_evaluation = false;
|
||||||
|
|
||||||
|
@ -221,7 +220,7 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember we are now inside an object
|
// remember we are now inside an object
|
||||||
states.push_back(parse_state_t::object_value);
|
states.push_back(false);
|
||||||
|
|
||||||
// parse values
|
// parse values
|
||||||
get_token();
|
get_token();
|
||||||
|
@ -249,7 +248,7 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember we are now inside an array
|
// remember we are now inside an array
|
||||||
states.push_back(parse_state_t::array_value);
|
states.push_back(true);
|
||||||
|
|
||||||
// parse values (no need to call get_token)
|
// parse values (no need to call get_token)
|
||||||
continue;
|
continue;
|
||||||
|
@ -359,104 +358,98 @@ class parser
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
get_token();
|
get_token();
|
||||||
switch (states.back())
|
if (states.back()) // array
|
||||||
{
|
{
|
||||||
case parse_state_t::array_value:
|
// comma -> next value
|
||||||
|
if (last_token == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// comma -> next value
|
// parse a new value
|
||||||
if (last_token == token_type::value_separator)
|
get_token();
|
||||||
{
|
continue;
|
||||||
// parse a new value
|
|
||||||
get_token();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// closing ]
|
|
||||||
if (JSON_LIKELY(last_token == token_type::end_array))
|
|
||||||
{
|
|
||||||
if (JSON_UNLIKELY(not sax->end_array()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are done with this array. Before we can parse
|
|
||||||
// a new value, we need to evaluate the new state
|
|
||||||
// first. By setting skip_to_state_evaluation to
|
|
||||||
// false, we are effectively jumping to the
|
|
||||||
// beginning of this switch.
|
|
||||||
assert(not states.empty());
|
|
||||||
states.pop_back();
|
|
||||||
skip_to_state_evaluation = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case parse_state_t::object_value:
|
// closing ]
|
||||||
|
if (JSON_LIKELY(last_token == token_type::end_array))
|
||||||
{
|
{
|
||||||
// comma -> next value
|
if (JSON_UNLIKELY(not sax->end_array()))
|
||||||
if (last_token == token_type::value_separator)
|
|
||||||
{
|
{
|
||||||
get_token();
|
return false;
|
||||||
|
|
||||||
// parse key
|
|
||||||
if (JSON_UNLIKELY(last_token != token_type::value_string))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse separator (:)
|
|
||||||
get_token();
|
|
||||||
if (JSON_UNLIKELY(last_token != token_type::name_separator))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse values
|
|
||||||
get_token();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing }
|
// We are done with this array. Before we can parse a
|
||||||
if (JSON_LIKELY(last_token == token_type::end_object))
|
// new value, we need to evaluate the new state first.
|
||||||
{
|
// By setting skip_to_state_evaluation to false, we
|
||||||
if (JSON_UNLIKELY(not sax->end_object()))
|
// are effectively jumping to the beginning of this if.
|
||||||
{
|
assert(not states.empty());
|
||||||
return false;
|
states.pop_back();
|
||||||
}
|
skip_to_state_evaluation = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // object
|
||||||
|
{
|
||||||
|
// comma -> next value
|
||||||
|
if (last_token == token_type::value_separator)
|
||||||
|
{
|
||||||
|
get_token();
|
||||||
|
|
||||||
// We are done with this object. Before we can
|
// parse key
|
||||||
// parse a new value, we need to evaluate the new
|
if (JSON_UNLIKELY(last_token != token_type::value_string))
|
||||||
// state first. By setting skip_to_state_evaluation
|
|
||||||
// to false, we are effectively jumping to the
|
|
||||||
// beginning of this switch.
|
|
||||||
assert(not states.empty());
|
|
||||||
states.pop_back();
|
|
||||||
skip_to_state_evaluation = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse separator (:)
|
||||||
|
get_token();
|
||||||
|
if (JSON_UNLIKELY(last_token != token_type::name_separator))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse values
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// closing }
|
||||||
|
if (JSON_LIKELY(last_token == token_type::end_object))
|
||||||
|
{
|
||||||
|
if (JSON_UNLIKELY(not sax->end_object()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done with this object. Before we can parse a
|
||||||
|
// new value, we need to evaluate the new state first.
|
||||||
|
// By setting skip_to_state_evaluation to false, we
|
||||||
|
// are effectively jumping to the beginning of this if.
|
||||||
|
assert(not states.empty());
|
||||||
|
states.pop_back();
|
||||||
|
skip_to_state_evaluation = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3955,10 +3955,9 @@ class parser
|
||||||
private:
|
private:
|
||||||
bool sax_parse_internal(json_sax_t* sax)
|
bool sax_parse_internal(json_sax_t* sax)
|
||||||
{
|
{
|
||||||
// two values for the structured values
|
|
||||||
enum class parse_state_t { array_value, object_value };
|
|
||||||
// stack to remember the hieararchy of structured values we are parsing
|
// stack to remember the hieararchy of structured values we are parsing
|
||||||
std::vector<parse_state_t> states;
|
// true = array; false = object
|
||||||
|
std::vector<bool> states;
|
||||||
// value to avoid a goto (see comment where set to true)
|
// value to avoid a goto (see comment where set to true)
|
||||||
bool skip_to_state_evaluation = false;
|
bool skip_to_state_evaluation = false;
|
||||||
|
|
||||||
|
@ -4014,7 +4013,7 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember we are now inside an object
|
// remember we are now inside an object
|
||||||
states.push_back(parse_state_t::object_value);
|
states.push_back(false);
|
||||||
|
|
||||||
// parse values
|
// parse values
|
||||||
get_token();
|
get_token();
|
||||||
|
@ -4042,7 +4041,7 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember we are now inside an array
|
// remember we are now inside an array
|
||||||
states.push_back(parse_state_t::array_value);
|
states.push_back(true);
|
||||||
|
|
||||||
// parse values (no need to call get_token)
|
// parse values (no need to call get_token)
|
||||||
continue;
|
continue;
|
||||||
|
@ -4152,104 +4151,98 @@ class parser
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
get_token();
|
get_token();
|
||||||
switch (states.back())
|
if (states.back()) // array
|
||||||
{
|
{
|
||||||
case parse_state_t::array_value:
|
// comma -> next value
|
||||||
|
if (last_token == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// comma -> next value
|
// parse a new value
|
||||||
if (last_token == token_type::value_separator)
|
get_token();
|
||||||
{
|
continue;
|
||||||
// parse a new value
|
|
||||||
get_token();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// closing ]
|
|
||||||
if (JSON_LIKELY(last_token == token_type::end_array))
|
|
||||||
{
|
|
||||||
if (JSON_UNLIKELY(not sax->end_array()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are done with this array. Before we can parse
|
|
||||||
// a new value, we need to evaluate the new state
|
|
||||||
// first. By setting skip_to_state_evaluation to
|
|
||||||
// false, we are effectively jumping to the
|
|
||||||
// beginning of this switch.
|
|
||||||
assert(not states.empty());
|
|
||||||
states.pop_back();
|
|
||||||
skip_to_state_evaluation = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case parse_state_t::object_value:
|
// closing ]
|
||||||
|
if (JSON_LIKELY(last_token == token_type::end_array))
|
||||||
{
|
{
|
||||||
// comma -> next value
|
if (JSON_UNLIKELY(not sax->end_array()))
|
||||||
if (last_token == token_type::value_separator)
|
|
||||||
{
|
{
|
||||||
get_token();
|
return false;
|
||||||
|
|
||||||
// parse key
|
|
||||||
if (JSON_UNLIKELY(last_token != token_type::value_string))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse separator (:)
|
|
||||||
get_token();
|
|
||||||
if (JSON_UNLIKELY(last_token != token_type::name_separator))
|
|
||||||
{
|
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
|
||||||
m_lexer.get_token_string(),
|
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse values
|
|
||||||
get_token();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// closing }
|
// We are done with this array. Before we can parse a
|
||||||
if (JSON_LIKELY(last_token == token_type::end_object))
|
// new value, we need to evaluate the new state first.
|
||||||
{
|
// By setting skip_to_state_evaluation to false, we
|
||||||
if (JSON_UNLIKELY(not sax->end_object()))
|
// are effectively jumping to the beginning of this if.
|
||||||
{
|
assert(not states.empty());
|
||||||
return false;
|
states.pop_back();
|
||||||
}
|
skip_to_state_evaluation = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // object
|
||||||
|
{
|
||||||
|
// comma -> next value
|
||||||
|
if (last_token == token_type::value_separator)
|
||||||
|
{
|
||||||
|
get_token();
|
||||||
|
|
||||||
// We are done with this object. Before we can
|
// parse key
|
||||||
// parse a new value, we need to evaluate the new
|
if (JSON_UNLIKELY(last_token != token_type::value_string))
|
||||||
// state first. By setting skip_to_state_evaluation
|
|
||||||
// to false, we are effectively jumping to the
|
|
||||||
// beginning of this switch.
|
|
||||||
assert(not states.empty());
|
|
||||||
states.pop_back();
|
|
||||||
skip_to_state_evaluation = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse separator (:)
|
||||||
|
get_token();
|
||||||
|
if (JSON_UNLIKELY(last_token != token_type::name_separator))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse values
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// closing }
|
||||||
|
if (JSON_LIKELY(last_token == token_type::end_object))
|
||||||
|
{
|
||||||
|
if (JSON_UNLIKELY(not sax->end_object()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done with this object. Before we can parse a
|
||||||
|
// new value, we need to evaluate the new state first.
|
||||||
|
// By setting skip_to_state_evaluation to false, we
|
||||||
|
// are effectively jumping to the beginning of this if.
|
||||||
|
assert(not states.empty());
|
||||||
|
states.pop_back();
|
||||||
|
skip_to_state_evaluation = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue