JsonPrimitive ReadNumericLiteral ()
{
bool negative = false;
if (PeekChar () == '-') {
negative = true;
ReadChar ();
if (PeekChar () < 0)
throw JsonError ("Invalid JSON numeric literal; extra negation");
}
int c;
decimal val = 0;
int x = 0;
bool zeroStart = PeekChar () == '0';
for (; ; x++) {
c = PeekChar ();
if (c < '0' || '9' < c)
break;
val = val * 10 + (c - '0');
ReadChar ();
if (zeroStart && x == 1 && c == '0')
throw JsonError ("leading multiple zeros are not allowed");
}
// fraction
bool hasFrac = false;
decimal frac = 0;
int fdigits = 0;
if (PeekChar () == '.') {
hasFrac = true;
ReadChar ();
if (PeekChar () < 0)
throw JsonError ("Invalid JSON numeric literal; extra dot");
decimal d = 10;
while (true) {
c = PeekChar ();
if (c < '0' || '9' < c)
break;
ReadChar ();
frac += (c - '0') / d;
d *= 10;
fdigits++;
}
if (fdigits == 0)
throw JsonError ("Invalid JSON numeric literal; extra dot");
}
frac = Decimal.Round (frac, fdigits);
c = PeekChar ();
if (c != 'e' && c != 'E') {
if (!hasFrac) {
if (negative && int.MinValue <= -val ||
!negative && val <= int.MaxValue)
return new JsonPrimitive ((int) (negative ? -val : val));
if (negative && long.MinValue <= -val ||
!negative && val <= long.MaxValue)
return new JsonPrimitive ((long) (negative ? -val : val));
}
var v = val + frac;
return new JsonPrimitive (negative ? -v : v);
}
// exponent
ReadChar ();
int exp = 0;
if (PeekChar () < 0)
throw new ArgumentException ("Invalid JSON numeric literal; incomplete exponent");
bool negexp = false;
c = PeekChar ();
if (c == '-') {
ReadChar ();
negexp = true;
}
else if (c == '+')
ReadChar ();
if (PeekChar () < 0)
throw JsonError ("Invalid JSON numeric literal; incomplete exponent");
while (true) {
c = PeekChar ();
if (c < '0' || '9' < c)
break;
exp = exp * 10 + (c - '0');
ReadChar ();
}
// it is messy to handle exponent, so I just use Decimal.Parse() with assured JSON format.
int [] bits = Decimal.GetBits (val + frac);
return new JsonPrimitive (new Decimal (bits [0], bits [1], bits [2], negative, (byte) exp));
}