Skip to content

Commit 044b268

Browse files
committed
Merge pull request #27 from mpnovikova/bignum
Refactored number parsing
2 parents 62ca604 + 5245aa6 commit 044b268

File tree

2 files changed

+52
-147
lines changed

2 files changed

+52
-147
lines changed

jsonparse.js

Lines changed: 46 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,7 @@ var NULL1 = C.NULL1 = 0x41;
2727
var NULL2 = C.NULL2 = 0x42;
2828
var NULL3 = C.NULL3 = 0x43;
2929
var NUMBER1 = C.NUMBER1 = 0x51;
30-
var NUMBER2 = C.NUMBER2 = 0x52;
3130
var NUMBER3 = C.NUMBER3 = 0x53;
32-
var NUMBER4 = C.NUMBER4 = 0x54;
33-
var NUMBER5 = C.NUMBER5 = 0x55;
34-
var NUMBER6 = C.NUMBER6 = 0x56;
35-
var NUMBER7 = C.NUMBER7 = 0x57;
36-
var NUMBER8 = C.NUMBER8 = 0x58;
3731
var STRING1 = C.STRING1 = 0x61;
3832
var STRING2 = C.STRING2 = 0x62;
3933
var STRING3 = C.STRING3 = 0x63;
@@ -55,14 +49,6 @@ function Parser() {
5549
this.string = undefined; // string data
5650
this.unicode = undefined; // unicode escapes
5751

58-
// For number parsing
59-
this.negative = undefined;
60-
this.magnatude = undefined;
61-
this.position = undefined;
62-
this.exponent = undefined;
63-
this.negativeExponent = undefined;
64-
this.numberLength = 0;
65-
6652
this.key = undefined;
6753
this.mode = undefined;
6854
this.stack = [];
@@ -83,7 +69,7 @@ Parser.toknam = function (code) {
8369
if (C[key] === code) { return key; }
8470
}
8571
return code && ("0x" + code.toString(16));
86-
}
72+
};
8773

8874
var proto = Parser.prototype;
8975
proto.onError = function (err) { throw err; };
@@ -108,15 +94,14 @@ proto.write = function (buffer) {
10894
}else if(n === 0x66){ this.tState = FALSE1; // f
10995
}else if(n === 0x6e){ this.tState = NULL1; // n
11096
}else if(n === 0x22){ this.string = ""; this.tState = STRING1; // "
111-
}else if(n === 0x2d){ this.negative = true; this.tState = NUMBER1; // -
112-
}else if(n === 0x30){ this.magnatude = 0; this.tState = NUMBER2; // 0
97+
}else if(n === 0x2d){ this.string = "-"; this.tState = NUMBER1; // -
11398
}else{
114-
if (n > 0x30 && n < 0x40) { // 1-9
115-
this.magnatude = n - 0x30; this.tState = NUMBER3;
99+
if (n >= 0x30 && n < 0x40) { // 1-9
100+
this.string = String.fromCharCode(n); this.tState = NUMBER3;
116101
} else if (n === 0x20 || n === 0x09 || n === 0x0a || n === 0x0d) {
117102
// whitespace
118103
} else {
119-
return this.charError(buffer, i);
104+
return this.charError(buffer, i);
120105
}
121106
}
122107
}else if (this.tState === STRING1){ // After open quote
@@ -180,131 +165,48 @@ proto.write = function (buffer) {
180165
} else {
181166
return this.charError(buffer, i);
182167
}
183-
}else if (this.tState === NUMBER1){ // after minus
184-
n = buffer[i];
185-
this.numberLength++;
186-
if (n === 0x30) { this.magnatude = 0; this.tState = NUMBER2; }
187-
else if (n > 0x30 && n < 0x40) { this.magnatude = n - 0x30; this.tState = NUMBER3; }
188-
else {
189-
return this.charError(buffer, i);
190-
}
191-
}else if (this.tState === NUMBER2){ // * After initial zero
192-
n = buffer[i];
193-
this.numberLength++;
194-
if(n === 0x2e){ // .
195-
this.position = 0.1; this.tState = NUMBER4;
196-
}else if(n === 0x65 || n === 0x45){ // e/E
197-
this.exponent = 0; this.tState = NUMBER6;
198-
}else{
199-
this.tState = START;
200-
this.onToken(NUMBER, 0);
201-
this.offset += this.numberLength - 1;
202-
this.numberLength = 0;
203-
this.magnatude = undefined;
204-
this.negative = undefined;
205-
i--;
206-
}
207-
}else if (this.tState === NUMBER3){ // * After digit (before period)
208-
n = buffer[i];
209-
this.numberLength++;
210-
if(n === 0x2e){ // .
211-
this.position = 0.1; this.tState = NUMBER4;
212-
}else if(n === 0x65 || n === 0x45){ // e/E
213-
this.exponent = 0; this.tState = NUMBER6;
214-
}else{
215-
if (n >= 0x30 && n < 0x40) { this.magnatude = this.magnatude * 10 + n - 0x30; }
216-
else {
217-
this.tState = START;
218-
if (this.negative) {
219-
this.magnatude = -this.magnatude;
220-
this.negative = undefined;
221-
}
222-
this.onToken(NUMBER, this.magnatude);
223-
this.offset += this.numberLength - 1;
224-
this.numberLength = 0;
225-
this.magnatude = undefined;
226-
i--;
227-
}
228-
}
229-
}else if (this.tState === NUMBER4){ // After period
230-
n = buffer[i];
231-
this.numberLength++;
232-
if (n >= 0x30 && n < 0x40) { // 0-9
233-
this.magnatude += this.position * (n - 0x30);
234-
this.position /= 10;
235-
this.tState = NUMBER5;
236-
} else {
237-
return this.charError(buffer, i);
238-
}
239-
}else if (this.tState === NUMBER5){ // * After digit (after period)
240-
n = buffer[i];
241-
this.numberLength++;
242-
if (n >= 0x30 && n < 0x40) { // 0-9
243-
this.magnatude += this.position * (n - 0x30);
244-
this.position /= 10;
245-
}
246-
else if (n === 0x65 || n === 0x45) { this.exponent = 0; this.tState = NUMBER6; } // E/e
247-
else {
248-
this.tState = START;
249-
if (this.negative) {
250-
this.magnatude = -this.magnatude;
251-
this.negative = undefined;
252-
}
253-
this.onToken(NUMBER, this.negative ? -this.magnatude : this.magnatude);
254-
this.offset += this.numberLength - 1;
255-
this.numberLength = 0;
256-
this.magnatude = undefined;
257-
this.position = undefined;
258-
i--;
259-
}
260-
}else if (this.tState === NUMBER6){ // After E
261-
n = buffer[i];
262-
this.numberLength++;
263-
if (n === 0x2b || n === 0x2d) { // +/-
264-
if (n === 0x2d) { this.negativeExponent = true; }
265-
this.tState = NUMBER7;
266-
}
267-
else if (n >= 0x30 && n < 0x40) {
268-
this.exponent = this.exponent * 10 + (n - 0x30);
269-
this.tState = NUMBER8;
270-
}
271-
else {
272-
return this.charError(buffer, i);
273-
}
274-
}else if (this.tState === NUMBER7){ // After +/-
275-
n = buffer[i];
276-
this.numberLength++;
277-
if (n >= 0x30 && n < 0x40) { // 0-9
278-
this.exponent = this.exponent * 10 + (n - 0x30);
279-
this.tState = NUMBER8;
280-
}
281-
else {
282-
return this.charError(buffer, i);
283-
}
284-
}else if (this.tState === NUMBER8){ // * After digit (after +/-)
285-
n = buffer[i];
286-
this.numberLength++;
287-
if (n >= 0x30 && n < 0x40) { // 0-9
288-
this.exponent = this.exponent * 10 + (n - 0x30);
289-
}
290-
else {
291-
if (this.negativeExponent) {
292-
this.exponent = -this.exponent;
293-
this.negativeExponent = undefined;
294-
}
295-
this.magnatude *= Math.pow(10, this.exponent);
296-
this.exponent = undefined;
297-
if (this.negative) {
298-
this.magnatude = -this.magnatude;
299-
this.negative = undefined;
168+
} else if (this.tState === NUMBER1 || this.tState === NUMBER3) {
169+
n = buffer[i];
170+
171+
switch (n) {
172+
case 0x30: // 0
173+
case 0x31: // 1
174+
case 0x32: // 2
175+
case 0x33: // 3
176+
case 0x34: // 4
177+
case 0x35: // 5
178+
case 0x36: // 6
179+
case 0x37: // 7
180+
case 0x38: // 8
181+
case 0x39: // 9
182+
case 0x2e: // .
183+
case 0x65: // e
184+
case 0x45: // E
185+
case 0x2b: // +
186+
case 0x2d: // -
187+
this.string += String.fromCharCode(n);
188+
this.tState = NUMBER3;
189+
break;
190+
default:
191+
this.tState = START;
192+
var result = Number(this.string);
193+
194+
if (isNaN(result)){
195+
return this.charError(buffer, i);
196+
}
197+
198+
if ((this.string.match(/[0-9]+/) == this.string) && (result.toString() != this.string)) {
199+
// Long string of digits which is an ID string and not valid and/or safe JavaScript integer Number
200+
this.onToken(STRING, this.string);
201+
} else {
202+
this.onToken(NUMBER, result);
203+
}
204+
205+
this.offset += this.string.length - 1;
206+
this.string = undefined;
207+
i--;
208+
break;
300209
}
301-
this.tState = START;
302-
this.onToken(NUMBER, this.magnatude);
303-
this.offset += this.numberLength - 1;
304-
this.numberLength = 0;
305-
this.magnatude = undefined;
306-
i--;
307-
}
308210
}else if (this.tState === TRUE1){ // r
309211
if (buffer[i] === 0x72) { this.tState = TRUE2; }
310212
else { return this.charError(buffer, i); }

test/primitives.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ var expected = [
2323
[ [], [ -1 ] ],
2424
[ [ 0 ], -0.1 ],
2525
[ [], [ -0.1 ] ],
26-
[ [ 0 ], 6.019999999999999e+23 ],
27-
[ [], [ 6.019999999999999e+23 ] ]
26+
[ [ 0 ], 6.02e+23 ],
27+
[ [], [ 6.02e+23 ] ],
28+
[ [ 0 ], '7161093205057351174' ],
29+
[ [], [ '7161093205057351174'] ]
2830
];
2931

3032
test('primitives', function (t) {
31-
t.plan(23);
33+
t.plan(25);
3234

3335
var p = new Parser();
3436
p.onValue = function (value) {
@@ -51,4 +53,5 @@ test('primitives', function (t) {
5153
p.write('[0,1,-1]');
5254
p.write('[1.0,1.1,-1.1,-1.0][-1][-0.1]');
5355
p.write('[6.02e23]');
56+
p.write('[7161093205057351174]');
5457
});

0 commit comments

Comments
 (0)