summaryrefslogtreecommitdiffstats
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/Core/StructuredData.cpp343
-rw-r--r--lldb/source/Host/common/StringConvert.cpp142
-rw-r--r--lldb/source/Utility/JSON.cpp468
-rw-r--r--lldb/source/Utility/StringExtractor.cpp9
-rw-r--r--lldb/source/Utility/StringExtractor.h12
5 files changed, 650 insertions, 324 deletions
diff --git a/lldb/source/Core/StructuredData.cpp b/lldb/source/Core/StructuredData.cpp
index a2c440948af..efc104f1f3e 100644
--- a/lldb/source/Core/StructuredData.cpp
+++ b/lldb/source/Core/StructuredData.cpp
@@ -14,301 +14,148 @@
#include <inttypes.h>
#include "lldb/Core/StreamString.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/JSON.h"
using namespace lldb_private;
-static StructuredData::ObjectSP read_json_object (const char **ch);
-static StructuredData::ObjectSP read_json_array (const char **ch);
+//----------------------------------------------------------------------
+// Functions that use a JSONParser to parse JSON into StructuredData
+//----------------------------------------------------------------------
+static StructuredData::ObjectSP ParseJSONValue (JSONParser &json_parser);
+static StructuredData::ObjectSP ParseJSONObject (JSONParser &json_parser);
+static StructuredData::ObjectSP ParseJSONArray (JSONParser &json_parser);
static StructuredData::ObjectSP
-read_json_number (const char **ch)
+ParseJSONObject (JSONParser &json_parser)
{
- StructuredData::ObjectSP object_sp;
- while (isspace (**ch))
- (*ch)++;
- const char *start_of_number = *ch;
- bool is_integer = true;
- bool is_float = false;
- while (isdigit(**ch) || **ch == '-' || **ch == '.' || **ch == '+' || **ch == 'e' || **ch == 'E')
- {
- if (isdigit(**ch) == false && **ch != '-')
- {
- is_integer = false;
- is_float = true;
- }
- (*ch)++;
- }
- while (isspace (**ch))
- (*ch)++;
- if (**ch == ',' || **ch == ']' || **ch == '}')
+ // The "JSONParser::Token::ObjectStart" token should have already been consumed
+ // by the time this function is called
+ std::unique_ptr<StructuredData::Dictionary> dict_up(new StructuredData::Dictionary());
+
+ std::string value;
+ std::string key;
+ while (1)
{
- if (is_integer)
+ JSONParser::Token token = json_parser.GetToken(value);
+
+ if (token == JSONParser::Token::String)
{
- errno = 0;
- uint64_t val = strtoul (start_of_number, NULL, 10);
- if (errno == 0)
+ key.swap(value);
+ token = json_parser.GetToken(value);
+ if (token == JSONParser::Token::Colon)
{
- object_sp.reset(new StructuredData::Integer());
- object_sp->GetAsInteger()->SetValue (val);
+ StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
+ if (value_sp)
+ dict_up->AddItem(key, value_sp);
+ else
+ break;
}
}
- if (is_float)
+ else if (token == JSONParser::Token::ObjectEnd)
{
- char *end_of_number = NULL;
- errno = 0;
- double val = strtod (start_of_number, &end_of_number);
- if (errno == 0 && end_of_number != start_of_number && end_of_number != NULL)
- {
- object_sp.reset(new StructuredData::Float());
- object_sp->GetAsFloat()->SetValue (val);
- }
+ return StructuredData::ObjectSP(dict_up.release());
}
- }
- return object_sp;
-}
-
-static std::string
-read_json_string (const char **ch)
-{
- std::string string;
- if (**ch == '"')
- {
- (*ch)++;
- while (**ch != '\0')
+ else if (token == JSONParser::Token::Comma)
{
- if (**ch == '"')
- {
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
- break;
- }
- else if (**ch == '\\')
- {
- switch (**ch)
- {
- case '"':
- string.push_back('"');
- *ch += 2;
- break;
- case '\\':
- string.push_back('\\');
- *ch += 2;
- break;
- case '/':
- string.push_back('/');
- *ch += 2;
- break;
- case 'b':
- string.push_back('\b');
- *ch += 2;
- break;
- case 'f':
- string.push_back('\f');
- *ch += 2;
- break;
- case 'n':
- string.push_back('\n');
- *ch += 2;
- break;
- case 'r':
- string.push_back('\r');
- *ch += 2;
- break;
- case 't':
- string.push_back('\t');
- *ch += 2;
- break;
- case 'u':
- // FIXME handle four-hex-digits
- *ch += 10;
- break;
- default:
- *ch += 1;
- }
- }
- else
- {
- string.push_back (**ch);
- }
- (*ch)++;
+ continue;
+ }
+ else
+ {
+ break;
}
}
- return string;
+ return StructuredData::ObjectSP();
}
static StructuredData::ObjectSP
-read_json_value (const char **ch)
+ParseJSONArray (JSONParser &json_parser)
{
- StructuredData::ObjectSP object_sp;
- while (isspace (**ch))
- (*ch)++;
+ // The "JSONParser::Token::ObjectStart" token should have already been consumed
+ // by the time this function is called
+ std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
- if (**ch == '{')
- {
- object_sp = read_json_object (ch);
- }
- else if (**ch == '[')
+ std::string value;
+ std::string key;
+ while (1)
{
- object_sp = read_json_array (ch);
- }
- else if (**ch == '"')
- {
- std::string string = read_json_string (ch);
- object_sp.reset(new StructuredData::String());
- object_sp->GetAsString()->SetValue(string);
- }
- else
- {
- if (strncmp (*ch, "true", 4) == 0)
- {
- object_sp.reset(new StructuredData::Boolean());
- object_sp->GetAsBoolean()->SetValue(true);
- *ch += 4;
- }
- else if (strncmp (*ch, "false", 5) == 0)
+ StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
+ if (value_sp)
+ array_up->AddItem(value_sp);
+ else
+ break;
+
+ JSONParser::Token token = json_parser.GetToken(value);
+ if (token == JSONParser::Token::Comma)
{
- object_sp.reset(new StructuredData::Boolean());
- object_sp->GetAsBoolean()->SetValue(false);
- *ch += 5;
+ continue;
}
- else if (strncmp (*ch, "null", 4) == 0)
+ else if (token == JSONParser::Token::ArrayEnd)
{
- object_sp.reset(new StructuredData::Null());
- *ch += 4;
+ return StructuredData::ObjectSP(array_up.release());
}
else
{
- object_sp = read_json_number (ch);
+ break;
}
}
- return object_sp;
+ return StructuredData::ObjectSP();
}
static StructuredData::ObjectSP
-read_json_array (const char **ch)
+ParseJSONValue (JSONParser &json_parser)
{
- StructuredData::ObjectSP object_sp;
- if (**ch == '[')
+ std::string value;
+ const JSONParser::Token token = json_parser.GetToken(value);
+ switch (token)
{
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
+ case JSONParser::Token::ObjectStart:
+ return ParseJSONObject(json_parser);
- bool first_value = true;
- while (**ch != '\0' && (first_value || **ch == ','))
- {
- if (**ch == ',')
- (*ch)++;
- first_value = false;
- while (isspace (**ch))
- (*ch)++;
- lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
- if (value_sp)
+ case JSONParser::Token::ArrayStart:
+ return ParseJSONArray(json_parser);
+
+ case JSONParser::Token::Integer:
{
- if (object_sp.get() == NULL)
- {
- object_sp.reset(new StructuredData::Array());
- }
- object_sp->GetAsArray()->Push (value_sp);
+ bool success = false;
+ uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
+ if (success)
+ return StructuredData::ObjectSP(new StructuredData::Integer(uval));
}
- while (isspace (**ch))
- (*ch)++;
- }
- if (**ch == ']')
- {
- // FIXME should throw an error if we don't see a } to close out the JSON object
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
- }
- }
- return object_sp;
-}
+ break;
-static StructuredData::ObjectSP
-read_json_object (const char **ch)
-{
- StructuredData::ObjectSP object_sp;
- if (**ch == '{')
- {
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
- bool first_pair = true;
- while (**ch != '\0' && (first_pair || **ch == ','))
- {
- first_pair = false;
- if (**ch == ',')
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
- if (**ch != '"')
- break;
- std::string key_string = read_json_string (ch);
- while (isspace (**ch))
- (*ch)++;
- if (key_string.size() > 0 && **ch == ':')
+ case JSONParser::Token::Float:
{
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
- lldb_private::StructuredData::ObjectSP value_sp = read_json_value (ch);
- if (value_sp.get())
- {
- if (object_sp.get() == NULL)
- {
- object_sp.reset(new StructuredData::Dictionary());
- }
- object_sp->GetAsDictionary()->AddItem (key_string.c_str(), value_sp);
- }
+ bool success = false;
+ double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
+ if (success)
+ return StructuredData::ObjectSP(new StructuredData::Float(val));
}
- while (isspace (**ch))
- (*ch)++;
- }
- if (**ch == '}')
- {
- // FIXME should throw an error if we don't see a } to close out the JSON object
- (*ch)++;
- while (isspace (**ch))
- (*ch)++;
- }
+ break;
+
+ case JSONParser::Token::String:
+ return StructuredData::ObjectSP(new StructuredData::String(value));
+
+ case JSONParser::Token::True:
+ case JSONParser::Token::False:
+ return StructuredData::ObjectSP(new StructuredData::Boolean(token == JSONParser::Token::True));
+
+ case JSONParser::Token::Null:
+ return StructuredData::ObjectSP(new StructuredData::Null());
+
+ default:
+ break;
}
- return object_sp;
-}
+ return StructuredData::ObjectSP();
+}
StructuredData::ObjectSP
StructuredData::ParseJSON (std::string json_text)
{
- StructuredData::ObjectSP object_sp;
- const size_t json_text_size = json_text.size();
- if (json_text_size > 0)
- {
- const char *start_of_json_text = json_text.c_str();
- const char *c = json_text.c_str();
- while (*c != '\0' &&
- static_cast<size_t>(c - start_of_json_text) <= json_text_size)
- {
- while (isspace (*c) &&
- static_cast<size_t>(c - start_of_json_text) < json_text_size)
- c++;
- if (*c == '{')
- {
- object_sp = read_json_object (&c);
- }
- else if (*c == '[')
- {
- object_sp = read_json_array (&c);
- }
- else
- {
- // We have bad characters here, this is likely an illegal JSON string.
- return object_sp;
- }
- }
- }
+ JSONParser json_parser(json_text.c_str());
+ StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
return object_sp;
}
@@ -395,7 +242,7 @@ StructuredData::Integer::Dump (Stream &s) const
void
StructuredData::Float::Dump (Stream &s) const
{
- s.Printf ("%lf", m_value);
+ s.Printf ("%lg", m_value);
}
void
diff --git a/lldb/source/Host/common/StringConvert.cpp b/lldb/source/Host/common/StringConvert.cpp
index 0a8e75f4b87..c4ff67515d4 100644
--- a/lldb/source/Host/common/StringConvert.cpp
+++ b/lldb/source/Host/common/StringConvert.cpp
@@ -15,79 +15,103 @@
// Project includes
#include "lldb/Host/StringConvert.h"
-namespace lldb_private {
-
-namespace StringConvert {
-
-int32_t
-ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
+namespace lldb_private
{
- if (s && s[0])
+ namespace StringConvert
{
- char *end = nullptr;
- const long sval = ::strtol (s, &end, base);
- if (*end == '\0')
+
+ int32_t
+ ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
{
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ const long sval = ::strtol (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
+ return (int32_t)sval; // All characters were used, return the result
+ }
+ }
if (success_ptr)
- *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
- return (int32_t)sval; // All characters were used, return the result
+ *success_ptr = false;
+ return fail_value;
}
- }
- if (success_ptr) *success_ptr = false;
- return fail_value;
-}
-uint32_t
-ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
-{
- if (s && s[0])
- {
- char *end = nullptr;
- const unsigned long uval = ::strtoul (s, &end, base);
- if (*end == '\0')
+ uint32_t
+ ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
{
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ const unsigned long uval = ::strtoul (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = (uval <= UINT32_MAX);
+ return (uint32_t)uval; // All characters were used, return the result
+ }
+ }
if (success_ptr)
- *success_ptr = (uval <= UINT32_MAX);
- return (uint32_t)uval; // All characters were used, return the result
+ *success_ptr = false;
+ return fail_value;
}
- }
- if (success_ptr) *success_ptr = false;
- return fail_value;
-}
-int64_t
-ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
-{
- if (s && s[0])
- {
- char *end = nullptr;
- int64_t uval = ::strtoll (s, &end, base);
- if (*end == '\0')
+ int64_t
+ ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
{
- if (success_ptr) *success_ptr = true;
- return uval; // All characters were used, return the result
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ int64_t uval = ::strtoll (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
}
- }
- if (success_ptr) *success_ptr = false;
- return fail_value;
-}
-uint64_t
-ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
-{
- if (s && s[0])
- {
- char *end = nullptr;
- uint64_t uval = ::strtoull (s, &end, base);
- if (*end == '\0')
+ uint64_t
+ ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
{
- if (success_ptr) *success_ptr = true;
- return uval; // All characters were used, return the result
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ uint64_t uval = ::strtoull (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
}
- }
- if (success_ptr) *success_ptr = false;
- return fail_value;
-}
-}
+ double
+ ToDouble (const char *s, double fail_value, bool *success_ptr)
+ {
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ double val = strtod (s, &end);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return val; // All characters were used, return the result
+ }
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+ }
+ }
}
diff --git a/lldb/source/Utility/JSON.cpp b/lldb/source/Utility/JSON.cpp
index 0ba8cf4399c..eaf224d555f 100644
--- a/lldb/source/Utility/JSON.cpp
+++ b/lldb/source/Utility/JSON.cpp
@@ -8,6 +8,8 @@
//===----------------------------------------------------------------------===//
#include "lldb/Utility/JSON.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/StringConvert.h"
using namespace lldb_private;
@@ -33,20 +35,20 @@ JSONString::json_string_quote_metachars (const std::string &s)
}
JSONString::JSONString () :
-JSONValue(JSONValue::Kind::String),
-m_data()
+ JSONValue(JSONValue::Kind::String),
+ m_data()
{
}
JSONString::JSONString (const char* s) :
-JSONValue(JSONValue::Kind::String),
-m_data(s ? s : "")
+ JSONValue(JSONValue::Kind::String),
+ m_data(s ? s : "")
{
}
JSONString::JSONString (const std::string& s) :
-JSONValue(JSONValue::Kind::String),
-m_data(s)
+ JSONValue(JSONValue::Kind::String),
+ m_data(s)
{
}
@@ -57,25 +59,41 @@ JSONString::Write (Stream& s)
}
JSONNumber::JSONNumber () :
-JSONValue(JSONValue::Kind::Number),
-m_data(0)
+ JSONValue(JSONValue::Kind::Number),
+ m_is_integer(true),
+ m_data(0),
+ m_double(0.0)
{
}
-JSONNumber::JSONNumber (int64_t i) :
-JSONValue(JSONValue::Kind::Number),
-m_data(i)
+JSONNumber::JSONNumber (uint64_t i) :
+ JSONValue(JSONValue::Kind::Number),
+ m_is_integer(true),
+ m_data(i),
+ m_double(0.0)
+{
+}
+
+
+JSONNumber::JSONNumber (double d) :
+ JSONValue(JSONValue::Kind::Number),
+ m_is_integer(false),
+ m_data(0),
+ m_double(d)
{
}
void
JSONNumber::Write (Stream& s)
{
- s.Printf("%" PRId64, m_data);
+ if (m_is_integer)
+ s.Printf("%" PRIu64, m_data);
+ else
+ s.Printf("%g", m_double);
}
JSONTrue::JSONTrue () :
-JSONValue(JSONValue::Kind::True)
+ JSONValue(JSONValue::Kind::True)
{
}
@@ -86,7 +104,7 @@ JSONTrue::Write(Stream& s)
}
JSONFalse::JSONFalse () :
-JSONValue(JSONValue::Kind::False)
+ JSONValue(JSONValue::Kind::False)
{
}
@@ -97,7 +115,7 @@ JSONFalse::Write(Stream& s)
}
JSONNull::JSONNull () :
-JSONValue(JSONValue::Kind::Null)
+ JSONValue(JSONValue::Kind::Null)
{
}
@@ -108,7 +126,7 @@ JSONNull::Write(Stream& s)
}
JSONObject::JSONObject () :
-JSONValue(JSONValue::Kind::Object)
+ JSONValue(JSONValue::Kind::Object)
{
}
@@ -153,7 +171,7 @@ JSONObject::GetObject (const std::string& key)
}
JSONArray::JSONArray () :
-JSONValue(JSONValue::Kind::Array)
+ JSONValue(JSONValue::Kind::Array)
{
}
@@ -215,3 +233,419 @@ JSONArray::GetNumElements ()
{
return m_elements.size();
}
+
+
+JSONParser::JSONParser (const char *cstr) :
+ StringExtractor(cstr)
+{
+}
+
+JSONParser::Token
+JSONParser::GetToken (std::string &value)
+{
+ StreamString error;
+
+ value.clear();
+ SkipSpaces ();
+ const uint64_t start_index = m_index;
+ const char ch = GetChar();
+ switch (ch)
+ {
+ case '{': return Token::ObjectStart;
+ case '}': return Token::ObjectEnd;
+ case '[': return Token::ArrayStart;
+ case ']': return Token::ArrayEnd;
+ case ',': return Token::Comma;
+ case ':': return Token::Colon;
+ case '\0': return Token::EndOfFile;
+ case 't':
+ if (GetChar() == 'r')
+ if (GetChar() == 'u')
+ if (GetChar() == 'e')
+ return Token::True;
+ break;
+
+ case 'f':
+ if (GetChar() == 'a')
+ if (GetChar() == 'l')
+ if (GetChar() == 's')
+ if (GetChar() == 'e')
+ return Token::False;
+ break;
+
+ case 'n':
+ if (GetChar() == 'u')
+ if (GetChar() == 'l')
+ if (GetChar() == 'l')
+ return Token::Null;
+ break;
+
+ case '"':
+ {
+ while (1)
+ {
+ bool was_escaped = false;
+ int escaped_ch = GetEscapedChar(was_escaped);
+ if (escaped_ch == -1)
+ {
+ error.Printf("error: an error occurred getting a character from offset %" PRIu64, start_index);
+ value = std::move(error.GetString());
+ return Token::Error;
+
+ }
+ else
+ {
+ const bool is_end_quote = escaped_ch == '"';
+ const bool is_null = escaped_ch == 0;
+ if (was_escaped || (!is_end_quote && !is_null))
+ {
+ if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX)
+ {
+ value.append(1, (char)escaped_ch);
+ }
+ else
+ {
+ error.Printf("error: wide character support is needed for unicode character 0x%4.4x at offset %" PRIu64, escaped_ch, start_index);
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ }
+ else if (is_end_quote)
+ {
+ return Token::String;
+ }
+ else if (is_null)
+ {
+ value = "error: missing end quote for string";
+ return Token::Error;
+ }
+ }
+ }
+ }
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ bool done = false;
+ bool got_decimal_point = false;
+ uint64_t exp_index = 0;
+ bool got_int_digits = (ch >= '0') && (ch <= '9');
+ bool got_frac_digits = false;
+ bool got_exp_digits = false;
+ while (!done)
+ {
+ const char next_ch = PeekChar();
+ switch (next_ch)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (exp_index != 0)
+ {
+ got_exp_digits = true;
+ }
+ else if (got_decimal_point)
+ {
+ got_frac_digits = true;
+ }
+ else
+ {
+ got_int_digits = true;
+ }
+ ++m_index; // Skip this character
+ break;
+
+ case '.':
+ if (got_decimal_point)
+ {
+ error.Printf("error: extra decimal point found at offset %" PRIu64, start_index);
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ else
+ {
+ got_decimal_point = true;
+ ++m_index; // Skip this character
+ }
+ break;
+
+ case 'e':
+ case 'E':
+ if (exp_index != 0)
+ {
+ error.Printf("error: extra expenent character found at offset %" PRIu64, start_index);
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ else
+ {
+ exp_index = m_index;
+ ++m_index; // Skip this character
+ }
+ break;
+
+ case '+':
+ case '-':
+ // The '+' and '-' can only come after an exponent character...
+ if (exp_index == m_index - 1)
+ {
+ ++m_index; // Skip the exponent sign character
+ }
+ else
+ {
+ error.Printf("error: unexpected %c character at offset %" PRIu64, next_ch, start_index);
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+
+ default:
+ done = true;
+ break;
+ }
+ }
+
+ if (m_index > start_index)
+ {
+ value = m_packet.substr(start_index, m_index - start_index);
+ if (got_decimal_point)
+ {
+ if (exp_index != 0)
+ {
+ // We have an exponent, make sure we got exponent digits
+ if (got_exp_digits)
+ {
+ return Token::Float;
+ }
+ else
+ {
+ error.Printf("error: got exponent character but no exponent digits at offset in float value \"%s\"", value.c_str());
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ }
+ else
+ {
+ // No exponent, but we need at least one decimal after the decimal point
+ if (got_frac_digits)
+ {
+ return Token::Float;
+ }
+ else
+ {
+ error.Printf("error: no digits after decimal point \"%s\"", value.c_str());
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ }
+ }
+ else
+ {
+ // No decimal point
+ if (got_int_digits)
+ {
+ // We need at least some integer digits to make an integer
+ return Token::Integer;
+ }
+ else
+ {
+ error.Printf("error: no digits negate sign \"%s\"", value.c_str());
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ }
+ }
+ else
+ {
+ error.Printf("error: invalid number found at offset %" PRIu64, start_index);
+ value = std::move(error.GetString());
+ return Token::Error;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ error.Printf("error: failed to parse token at offset %" PRIu64 " (around character '%c')", start_index, ch);
+ value = std::move(error.GetString());
+ return Token::Error;
+}
+
+int
+JSONParser::GetEscapedChar(bool &was_escaped)
+{
+ was_escaped = false;
+ const char ch = GetChar();
+ if (ch == '\\')
+ {
+ was_escaped = true;
+ const char ch2 = GetChar();
+ switch (ch2)
+ {
+ case '"':
+ case '\\':
+ case '/':
+ default:
+ break;
+
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'u':
+ {
+ const int hi_byte = DecodeHexU8();
+ const int lo_byte = DecodeHexU8();
+ if (hi_byte >=0 && lo_byte >= 0)
+ return hi_byte << 8 | lo_byte;
+ return -1;
+ }
+ break;
+ }
+ return ch2;
+ }
+ return ch;
+}
+
+JSONValue::SP
+JSONParser::ParseJSONObject ()
+{
+ // The "JSONParser::Token::ObjectStart" token should have already been consumed
+ // by the time this function is called
+ std::unique_ptr<JSONObject> dict_up(new JSONObject());
+
+ std::string value;
+ std::string key;
+ while (1)
+ {
+ JSONParser::Token token = GetToken(value);
+
+ if (token == JSONParser::Token::String)
+ {
+ key.swap(value);
+ token = GetToken(value);
+ if (token == JSONParser::Token::Colon)
+ {
+ JSONValue::SP value_sp = ParseJSONValue();
+ if (value_sp)
+ dict_up->SetObject(key, value_sp);
+ else
+ break;
+ }
+ }
+ else if (token == JSONParser::Token::ObjectEnd)
+ {
+ return JSONValue::SP(dict_up.release());
+ }
+ else if (token == JSONParser::Token::Comma)
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return JSONValue::SP();
+}
+
+JSONValue::SP
+JSONParser::ParseJSONArray ()
+{
+ // The "JSONParser::Token::ObjectStart" token should have already been consumed
+ // by the time this function is called
+ std::unique_ptr<JSONArray> array_up(new JSONArray());
+
+ std::string value;
+ std::string key;
+ while (1)
+ {
+ JSONValue::SP value_sp = ParseJSONValue();
+ if (value_sp)
+ array_up->AppendObject(value_sp);
+ else
+ break;
+
+ JSONParser::Token token = GetToken(value);
+ if (token == JSONParser::Token::Comma)
+ {
+ continue;
+ }
+ else if (token == JSONParser::Token::ArrayEnd)
+ {
+ return JSONValue::SP(array_up.release());
+ }
+ else
+ {
+ break;
+ }
+ }
+ return JSONValue::SP();
+}
+
+JSONValue::SP
+JSONParser::ParseJSONValue ()
+{
+ std::string value;
+ const JSONParser::Token token = GetToken(value);
+ switch (token)
+ {
+ case JSONParser::Token::ObjectStart:
+ return ParseJSONObject();
+
+ case JSONParser::Token::ArrayStart:
+ return ParseJSONArray();
+
+ case JSONParser::Token::Integer:
+ {
+ bool success = false;
+ uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
+ if (success)
+ return JSONValue::SP(new JSONNumber(uval));
+ }
+ break;
+
+ case JSONParser::Token::Float:
+ {
+ bool success = false;
+ double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
+ if (success)
+ return JSONValue::SP(new JSONNumber(val));
+ }
+ break;
+
+ case JSONParser::Token::String:
+ return JSONValue::SP(new JSONString(value));
+
+ case JSONParser::Token::True:
+ return JSONValue::SP(new JSONTrue());
+
+ case JSONParser::Token::False:
+ return JSONValue::SP(new JSONFalse());
+
+ case JSONParser::Token::Null:
+ return JSONValue::SP(new JSONNull());
+
+ default:
+ break;
+ }
+ return JSONValue::SP();
+
+}
diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp
index e82c83dfd09..bde5e1961d8 100644
--- a/lldb/source/Utility/StringExtractor.cpp
+++ b/lldb/source/Utility/StringExtractor.cpp
@@ -476,3 +476,12 @@ StringExtractor::GetNameColonValue (std::string &name, std::string &value)
m_index = UINT64_MAX;
return false;
}
+
+void
+StringExtractor::SkipSpaces ()
+{
+ const size_t n = m_packet.size();
+ while (m_index < n && isspace(m_packet[m_index]))
+ ++m_index;
+}
+
diff --git a/lldb/source/Utility/StringExtractor.h b/lldb/source/Utility/StringExtractor.h
index 49dfe99bd35..0f2dbb166be 100644
--- a/lldb/source/Utility/StringExtractor.h
+++ b/lldb/source/Utility/StringExtractor.h
@@ -67,6 +67,9 @@ public:
m_index = 0;
}
+ void
+ SkipSpaces ();
+
std::string &
GetStringRef ()
{
@@ -96,6 +99,15 @@ public:
char
GetChar (char fail_value = '\0');
+ char
+ PeekChar (char fail_value = '\0')
+ {
+ const char *cstr = Peek();
+ if (cstr)
+ return cstr[0];
+ return fail_value;
+ }
+
int
DecodeHexU8();
OpenPOWER on IntegriCloud