Allow JSON numeric fields to be specified by a numeric data in a string.

Change-Id: I6a3fae1e71434a7384edc39b8602bd84a0432edb
Tested: on Linux.
Bug: 24140897
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index e16d3ca..17d89a4 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -470,7 +470,7 @@
                                           BaseType req, bool *destmatch);
   FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
   FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e);
-  FLATBUFFERS_CHECKED_ERROR ParseIntegerFromString(Type &type, int64_t *result);
+  FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
   StructDef *LookupCreateStruct(const std::string &name,
                                 bool create_if_new = true,
                                 bool definition = false);
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index 263f650..73dd80e 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -209,6 +209,10 @@
   return NoError();
 }
 
+bool IsIdentifierStart(char c) {
+  return isalpha(static_cast<unsigned char>(c)) || c == '_';
+}
+
 CheckedError Parser::Next() {
   doc_comment_.clear();
   bool seen_newline = false;
@@ -288,7 +292,7 @@
         }
         // fall thru
       default:
-        if (isalpha(static_cast<unsigned char>(c)) || c == '_') {
+        if (IsIdentifierStart(c)) {
           // Collect all chars of an identifier:
           const char *start = cursor_ - 1;
           while (isalnum(static_cast<unsigned char>(*cursor_)) ||
@@ -880,7 +884,7 @@
   return NoError();
 }
 
-CheckedError Parser::ParseIntegerFromString(Type &type, int64_t *result) {
+CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) {
   *result = 0;
   // Parse one or more enum identifiers, separated by spaces.
   const char *next = attribute_.c_str();
@@ -950,10 +954,22 @@
   if (e.type.base_type != BASE_TYPE_STRING &&
       e.type.base_type != BASE_TYPE_NONE &&
       (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
-    int64_t val;
-    ECHECK(ParseIntegerFromString(e.type, &val));
-    e.constant = NumToString(val);
-    NEXT();
+    if (IsIdentifierStart(attribute_[0])) {  // Enum value.
+      int64_t val;
+      ECHECK(ParseEnumFromString(e.type, &val));
+      e.constant = NumToString(val);
+      NEXT();
+    } else {  // Numeric constant in string.
+      if (IsInteger(e.type.base_type)) {
+        // TODO(wvo): do we want to check for garbage after the number?
+        e.constant = NumToString(StringToInt(attribute_.c_str()));
+      } else if (IsFloat(e.type.base_type)) {
+        e.constant = NumToString(strtod(attribute_.c_str(), nullptr));
+      } else {
+        assert(0);  // Shouldn't happen, we covered all types.
+        e.constant = "0";
+      }
+    }
   } else {
     bool match = false;
     ECHECK(TryTypedValue(kTokenIntegerConstant,
diff --git a/tests/monsterdata_test.json b/tests/monsterdata_test.json
index 12c02d2..e8e3e1d 100755
--- a/tests/monsterdata_test.json
+++ b/tests/monsterdata_test.json
@@ -1,7 +1,7 @@
 {
   pos: {
     x: 1,
-    y: 2,
+    y: "2",
     z: 3,
     test1: 3,
     test2: Green,
@@ -30,7 +30,7 @@
       b: 20
     },
     {
-      b: 40,
+      b: "40",
       a: 30
     }
   ],