2017-12-30 05:11:58 +01:00
|
|
|
const enum Token {
|
|
|
|
ZERO = 0x00,
|
|
|
|
MAX = 0xEF,
|
|
|
|
NULL = 0xf0,
|
|
|
|
TRUE = 0xf1,
|
|
|
|
FALSE = 0xf2,
|
|
|
|
EOBJECT = 0xf3,
|
|
|
|
EARRAY = 0xf4,
|
|
|
|
ESTRING = 0xf5,
|
|
|
|
OBJECT = 0xf6,
|
|
|
|
ARRAY = 0xf7,
|
|
|
|
INTEGER = 0xf8,
|
|
|
|
LONG = 0xf9,
|
|
|
|
FLOAT = 0xfa,
|
|
|
|
DOUBLE = 0xfb,
|
|
|
|
STRING = 0xfc,
|
|
|
|
STRING_ADD = 0xfd,
|
|
|
|
STRING_GET = 0xfe,
|
|
|
|
BINARY = 0xff
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace pson {
|
|
|
|
export declare function onNull(): void;
|
|
|
|
export declare function onTrue(): void;
|
|
|
|
export declare function onFalse(): void;
|
|
|
|
export declare function onEObject(): void;
|
|
|
|
export declare function onEArray(): void;
|
|
|
|
export declare function onEString(): void;
|
|
|
|
export declare function onObject(size: u32): void;
|
|
|
|
export declare function onArray(size: u32): void;
|
|
|
|
export declare function onInteger(value: i32): void;
|
|
|
|
export declare function onLong(valueLow: i32, valueHigh: i32): void;
|
|
|
|
export declare function onFloat(value: f32): void;
|
|
|
|
export declare function onDouble(value: f64): void;
|
|
|
|
export declare function onString(offset: usize, length: u32): void;
|
|
|
|
export declare function onBinary(offset: usize, length: u32): void;
|
|
|
|
}
|
|
|
|
|
|
|
|
var offset: usize = 0;
|
|
|
|
|
|
|
|
export function decode(length: usize): void {
|
|
|
|
offset = 0;
|
2018-05-06 01:32:58 +02:00
|
|
|
while (offset < length) decodeValue();
|
|
|
|
if (offset != length) unreachable();
|
2017-12-30 05:11:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function decodeValue(): void {
|
|
|
|
var token: u32 = load<u8>(offset++);
|
|
|
|
var size: u32;
|
|
|
|
var long: u64;
|
|
|
|
switch (token) {
|
2018-05-06 01:32:58 +02:00
|
|
|
case Token.NULL: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onNull();
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.TRUE: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onTrue();
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.FALSE: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onFalse();
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.EOBJECT: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onEObject();
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.EARRAY: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onEArray();
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.ESTRING: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onEString();
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.OBJECT: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onObject(size = readVarint32());
|
|
|
|
while (size--) {
|
|
|
|
decodeValue();
|
|
|
|
decodeValue();
|
|
|
|
}
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.ARRAY: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onArray(size = readVarint32());
|
2018-05-06 01:32:58 +02:00
|
|
|
while (size--) decodeValue();
|
2017-12-30 05:11:58 +01:00
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.INTEGER: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onInteger(((size = readVarint32()) >> 1) ^ -(size & 1));
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.LONG: {
|
2017-12-30 05:11:58 +01:00
|
|
|
long = ((long = readVarint64()) >> 1) ^ -(long & 1);
|
|
|
|
pson.onLong(<i32>long, <i32>(long >>> 32));
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.FLOAT: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onFloat(load<f32>(offset));
|
|
|
|
offset += 4;
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.DOUBLE: {
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onDouble(load<f64>(offset));
|
|
|
|
offset += 8;
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
case Token.STRING: {
|
2017-12-30 05:11:58 +01:00
|
|
|
size = readVarint32();
|
|
|
|
pson.onString(offset, size);
|
|
|
|
offset += size;
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
2017-12-30 05:11:58 +01:00
|
|
|
case Token.STRING_ADD:
|
2018-05-06 01:32:58 +02:00
|
|
|
case Token.STRING_GET: {
|
2017-12-30 05:11:58 +01:00
|
|
|
// could be implemented via imports as well, but isn't necessary for this example
|
2018-05-06 01:32:58 +02:00
|
|
|
unreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Token.BINARY: {
|
2017-12-30 05:11:58 +01:00
|
|
|
size = readVarint32();
|
|
|
|
pson.onBinary(offset, size);
|
|
|
|
offset += size;
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
|
|
|
default: { // small integer?
|
|
|
|
if (token > <u32>Token.MAX) unreachable();
|
2017-12-30 05:11:58 +01:00
|
|
|
pson.onInteger((token >> 1) ^ -(token & 1));
|
|
|
|
break;
|
2018-05-06 01:32:58 +02:00
|
|
|
}
|
2017-12-30 05:11:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function readVarint32(): u32 {
|
|
|
|
var value: u32 = 0;
|
|
|
|
var shift: u32 = 0;
|
2018-05-06 01:32:58 +02:00
|
|
|
var b: u8;
|
2017-12-30 05:11:58 +01:00
|
|
|
do {
|
2018-05-06 01:32:58 +02:00
|
|
|
b = load<u8>(offset++);
|
2017-12-30 05:11:58 +01:00
|
|
|
value |= <u32>(b & 0x7f) << (7 * shift++);
|
|
|
|
} while (b & 0x80);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function readVarint64(): u64 {
|
|
|
|
var value: u64 = 0;
|
|
|
|
var shift: u64 = 0;
|
2018-05-06 01:32:58 +02:00
|
|
|
var b: u8;
|
2017-12-30 05:11:58 +01:00
|
|
|
do {
|
2018-05-06 01:32:58 +02:00
|
|
|
b = load<u8>(offset++);
|
2017-12-30 05:11:58 +01:00
|
|
|
value |= <u64>(b & 0x7f) << (7 * shift++);
|
|
|
|
} while (b & 0x80);
|
|
|
|
return value;
|
|
|
|
}
|