Support white-space between tokens

This commit is contained in:
Vladimir Grichina 2019-01-06 02:59:36 -08:00
parent e4757490a7
commit a4a11af1a8
2 changed files with 42 additions and 15 deletions

View File

@ -49,7 +49,7 @@ export class ThrowingJSONHandler extends JSONHandler {
} }
setBoolean(name: string, value: bool): void { setBoolean(name: string, value: bool): void {
assert(false, 'Unexpected boolean field ' + name + ' : ' + (value ? 'true' : 'false')); assert(false, 'Unexpected bool field ' + name + ' : ' + (value ? 'true' : 'false'));
} }
setNull(name: string): void { setNull(name: string): void {
@ -97,6 +97,7 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
this.lastKey = null this.lastKey = null
assert(this.parseValue(), "Cannot parse JSON"); assert(this.parseValue(), "Cannot parse JSON");
// TODO: Error if input left
} }
private peekChar(): i32 { private peekChar(): i32 {
@ -108,22 +109,25 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
return this.buffer[this.readIndex++]; return this.buffer[this.readIndex++];
} }
private parseValue(): boolean { private parseValue(): bool {
return this.parseObject() this.skipWhitespace();
let result = this.parseObject()
|| this.parseArray() || this.parseArray()
|| this.parseString() || this.parseString()
|| this.parseBoolean() || this.parseBoolean()
|| this.parseNumber() || this.parseNumber()
|| this.parseNull() || this.parseNull()
// TODO: Error if input left this.skipWhitespace();
return result;
} }
private parseObject(): boolean { private parseObject(): bool {
if (this.peekChar() != "{".charCodeAt(0)) { if (this.peekChar() != "{".charCodeAt(0)) {
return false; return false;
} }
this.handler.pushObject(this.lastKey); this.handler.pushObject(this.lastKey);
this.readChar(); this.readChar();
this.skipWhitespace();
let firstItem = true; let firstItem = true;
while (this.peekChar() != "}".charCodeAt(0)) { while (this.peekChar() != "}".charCodeAt(0)) {
@ -141,16 +145,18 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
} }
private parseKey(): void { private parseKey(): void {
this.skipWhitespace();
this.lastKey = this.readString(); this.lastKey = this.readString();
this.skipWhitespace();
assert(this.readChar() == ":".charCodeAt(0), "Expected ':'"); assert(this.readChar() == ":".charCodeAt(0), "Expected ':'");
} }
private parseArray(): boolean { private parseArray(): bool {
// TODO // TODO
return false; return false;
} }
private parseString(): boolean { private parseString(): bool {
if (this.peekChar() != '"'.charCodeAt(0)) { if (this.peekChar() != '"'.charCodeAt(0)) {
return false; return false;
} }
@ -158,7 +164,7 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
return true; return true;
} }
private readString(): String { private readString(): string {
assert(this.readChar() == '"'.charCodeAt(0), "Expected double-quoted string"); assert(this.readChar() == '"'.charCodeAt(0), "Expected double-quoted string");
let savedIndex = this.readIndex; let savedIndex = this.readIndex;
for (;;) { for (;;) {
@ -183,7 +189,7 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
return ""; return "";
} }
private parseNumber(): boolean { private parseNumber(): bool {
// TODO: Parse floats // TODO: Parse floats
let number: i32 = 0; let number: i32 = 0;
let sign: i32 = 1; let sign: i32 = 1;
@ -205,7 +211,7 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
return false; return false;
} }
private parseBoolean(): boolean { private parseBoolean(): bool {
if (this.peekChar() == FALSE_STR.charCodeAt(0)) { if (this.peekChar() == FALSE_STR.charCodeAt(0)) {
this.readAndAssert(FALSE_STR); this.readAndAssert(FALSE_STR);
this.handler.setBoolean(this.lastKey, false); this.handler.setBoolean(this.lastKey, false);
@ -220,7 +226,7 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
return false; return false;
} }
private parseNull(): boolean { private parseNull(): bool {
if (this.peekChar() == NULL_STR.charCodeAt(0)) { if (this.peekChar() == NULL_STR.charCodeAt(0)) {
this.readAndAssert(NULL_STR); this.readAndAssert(NULL_STR);
this.handler.setNull(this.lastKey); this.handler.setNull(this.lastKey);
@ -234,4 +240,14 @@ export class JSONDecoder<JSONHandlerT extends JSONHandler> {
assert(str.charCodeAt(i) == this.readChar(), "Expected '" + str + "'"); assert(str.charCodeAt(i) == this.readChar(), "Expected '" + str + "'");
} }
} }
private skipWhitespace(): void {
while (this.isWhitespace(this.peekChar())) {
this.readChar();
}
}
private isWhitespace(charCode: i32): bool {
return charCode == 0x9 || charCode == 0xa || charCode == 0xd || charCode == 0x20;
}
} }

View File

@ -108,6 +108,10 @@ export class StringConversionTests {
return this.roundripTest("{}"); return this.roundripTest("{}");
} }
static shouldHandleEmptyObjectWithWhitespace(): bool {
return this.roundripTest("{ }", "{}");
}
static shouldHandleInt32(): bool { static shouldHandleInt32(): bool {
return this.roundripTest('{"int":4660}'); return this.roundripTest('{"int":4660}');
} }
@ -140,8 +144,15 @@ export class StringConversionTests {
return this.roundripTest('{"str":"foo","obj":{"a":1,"b":-123456}}'); return this.roundripTest('{"str":"foo","obj":{"a":1,"b":-123456}}');
} }
private static roundripTest(jsonString: string): bool { static shouldHandleWhitespace(): bool {
logStr("----------------- " + jsonString); return this.roundripTest(
' { "str":"foo","obj": {"a":1, "b" :\n -123456} } ',
'{"str":"foo","obj":{"a":1,"b":-123456}}');
}
private static roundripTest(jsonString: string, expectedString: string = null): bool {
expectedString = expectedString || jsonString;
logStr("----------------- " + jsonString );
let buffer: Uint8Array = new Uint8Array(jsonString.lengthUTF8); let buffer: Uint8Array = new Uint8Array(jsonString.lengthUTF8);
let utf8ptr = jsonString.toUTF8(); let utf8ptr = jsonString.toUTF8();
// TODO: std should expose memcpy? // TODO: std should expose memcpy?
@ -149,8 +160,8 @@ export class StringConversionTests {
buffer[i] = load<u8>(utf8ptr + i); buffer[i] = load<u8>(utf8ptr + i);
} }
this.createDecoder().deserialize(buffer); this.createDecoder().deserialize(buffer);
assert(this.handler.result == jsonString, assert(this.handler.result == expectedString,
"Expected:\n" + jsonString + "\n" + "Actual:\n" + this.handler.result); "Expected:\n" + expectedString + "\n" + "Actual:\n" + this.handler.result);
return true; return true;
} }
} }