json-as 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +18 -2
  3. package/asconfig.json +1 -2
  4. package/assembly/__benches__/abc.bench.ts +5 -5
  5. package/assembly/__benches__/large.bench.ts +5 -51
  6. package/assembly/{custom → __benches__/lib}/bench.ts +4 -0
  7. package/assembly/__benches__/medium.bench.ts +3 -3
  8. package/assembly/__benches__/small.bench.ts +1 -1
  9. package/assembly/__benches__/vec3.bench.ts +3 -49
  10. package/assembly/__tests__/custom.spec.ts +4 -3
  11. package/assembly/__tests__/hierarchy.spec.ts +55 -0
  12. package/assembly/__tests__/lib/index.ts +1 -0
  13. package/assembly/custom/util.ts +0 -4
  14. package/assembly/deserialize/simple/array/box.ts +45 -0
  15. package/assembly/deserialize/simple/array/object.ts +28 -0
  16. package/assembly/deserialize/simple/array.ts +8 -0
  17. package/assembly/index.ts +39 -41
  18. package/assembly/serialize/simd/string.ts +12 -12
  19. package/assembly/test.ts +46 -133
  20. package/assembly/util/idofd.ts +6 -0
  21. package/bench/abc.bench.ts +1 -1
  22. package/bench/large.bench.ts +3 -3
  23. package/bench/lib/bench.ts +12 -0
  24. package/bench/medium.bench.ts +1 -1
  25. package/bench/runners/assemblyscript.js +28 -0
  26. package/bench/small.bench.ts +1 -1
  27. package/bench/tsconfig.json +12 -0
  28. package/bench/vec3.bench.ts +1 -1
  29. package/package.json +3 -4
  30. package/run-bench.as.sh +44 -18
  31. package/run-bench.js.sh +32 -6
  32. package/run-tests.sh +1 -1
  33. package/transform/lib/index.js +381 -122
  34. package/transform/lib/index.js.map +1 -1
  35. package/transform/lib/types.js +1 -0
  36. package/transform/lib/types.js.map +1 -1
  37. package/transform/src/index.ts +430 -117
  38. package/transform/src/types.ts +1 -0
  39. package/assembly/__benches__/lib/index.ts +0 -26
  40. package/assembly/custom/memory.ts +0 -25
  41. package/assembly/custom/sink.ts +0 -231
  42. package/assembly/custom/types.ts +0 -5
@@ -1,4 +1,4 @@
1
- import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, NodeKind, CommonFlags, ImportStatement, Node, Tokenizer, SourceKind, NamedTypeNode, Range, FEATURE_SIMD, FunctionExpression, MethodDeclaration, Statement, Program } from "assemblyscript/dist/assemblyscript.js";
1
+ import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, NodeKind, CommonFlags, ImportStatement, Node, Tokenizer, SourceKind, NamedTypeNode, Range, FEATURE_SIMD, FunctionExpression, MethodDeclaration, Statement, Program, Feature } from "assemblyscript/dist/assemblyscript.js";
2
2
  import { Transform } from "assemblyscript/dist/transform.js";
3
3
  import { Visitor } from "./visitor.js";
4
4
  import { isStdlib, SimpleParser, toString } from "./util.js";
@@ -6,11 +6,14 @@ import * as path from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { Property, PropertyFlags, Schema } from "./types.js";
8
8
  import { getClasses, getImportedClass } from "./linker.js";
9
- import { Feature } from "types:assemblyscript/src/common";
10
9
 
11
10
  let indent = " ";
12
11
 
12
+ const DEBUG = process.env["JSON_DEBUG"];
13
+
13
14
  class JSONTransform extends Visitor {
15
+ static SN: JSONTransform = new JSONTransform();
16
+
14
17
  public program!: Program;
15
18
  public baseDir!: string;
16
19
  public parser!: Parser;
@@ -38,7 +41,14 @@ class JSONTransform extends Visitor {
38
41
  this.schema.name = node.name.text;
39
42
 
40
43
  this.schemas.push(this.schema);
41
- if (process.env["JSON_DEBUG"]) console.log("Created schema: " + this.schema.name + " in file " + node.range.source.normalizedPath);
44
+
45
+ let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
46
+ let INITIALIZE = "@inline __INITIALIZE(): this {\n";
47
+ let DESERIALIZE = "__DESERIALIZE<T>(srcStart: usize, srcEnd: usize, out: T): T {\n";
48
+ let DESERIALIZE_CUSTOM = "";
49
+ let SERIALIZE_CUSTOM = "";
50
+
51
+ if (DEBUG) console.log("Created schema: " + this.schema.name + " in file " + node.range.source.normalizedPath);
42
52
 
43
53
  const members: FieldDeclaration[] = [...(node.members.filter((v) => v.kind === NodeKind.FieldDeclaration && v.flags !== CommonFlags.Static && v.flags !== CommonFlags.Private && v.flags !== CommonFlags.Protected && !v.decorators?.some((decorator) => (<IdentifierExpression>decorator.name).text === "omit")) as FieldDeclaration[])];
44
54
  const serializers: MethodDeclaration[] = [...node.members.filter((v) => v.kind === NodeKind.MethodDeclaration && v.decorators && v.decorators.some((e) => (<IdentifierExpression>e.name).text.toLowerCase() === "serializer"))] as MethodDeclaration[];
@@ -48,6 +58,7 @@ class JSONTransform extends Visitor {
48
58
  if (deserializers.length > 1) throwError("Multiple deserializers detected for class " + node.name.text + " but schemas can only have one deserializer!", deserializers[1].range);
49
59
 
50
60
  if (serializers.length) {
61
+ this.schema.custom = true;
51
62
  const serializer = serializers[0];
52
63
  // if (!serializer.signature.parameters.length) throwError("Could not find any parameters in custom serializer for " + this.schema.name + ". Serializers must have one parameter like 'serializer(self: " + this.schema.name + "): string {}'", serializer.range);
53
64
  if (serializer.signature.parameters.length > 1) throwError("Found too many parameters in custom serializer for " + this.schema.name + ", but serializers can only accept one parameter of type '" + this.schema.name + "'!", serializer.signature.parameters[1].range);
@@ -57,22 +68,16 @@ class JSONTransform extends Visitor {
57
68
  if (!serializer.decorators.some((v) => (<IdentifierExpression>v.name).text == "inline")) {
58
69
  serializer.decorators.push(Node.createDecorator(Node.createIdentifierExpression("inline", serializer.range), null, serializer.range));
59
70
  }
60
- let SERIALIZER = "";
61
- SERIALIZER += " __SERIALIZE_CUSTOM(): void {\n";
62
- SERIALIZER += " const data = this." + serializer.name.text + "(" + (serializer.signature.parameters.length ? "this" : "") + ");\n";
63
- SERIALIZER += " const dataSize = data.length << 1;\n";
64
- SERIALIZER += " memory.copy(bs.offset, changetype<usize>(data), dataSize);\n";
65
- SERIALIZER += " bs.offset += dataSize;\n";
66
- SERIALIZER += " }\n";
67
-
68
- if (process.env["JSON_DEBUG"]) console.log(SERIALIZER);
69
-
70
- const SERIALIZER_METHOD = SimpleParser.parseClassMember(SERIALIZER, node);
71
-
72
- if (!node.members.find((v) => v.name.text == "__SERIALIZE_CUSTOM")) node.members.push(SERIALIZER_METHOD);
71
+ SERIALIZE_CUSTOM += " __SERIALIZE(ptr: usize): void {\n";
72
+ SERIALIZE_CUSTOM += " const data = this." + serializer.name.text + "(" + (serializer.signature.parameters.length ? "this" : "") + ");\n";
73
+ SERIALIZE_CUSTOM += " const dataSize = data.length << 1;\n";
74
+ SERIALIZE_CUSTOM += " memory.copy(bs.offset, changetype<usize>(data), dataSize);\n";
75
+ SERIALIZE_CUSTOM += " bs.offset += dataSize;\n";
76
+ SERIALIZE_CUSTOM += " }\n";
73
77
  }
74
78
 
75
79
  if (deserializers.length) {
80
+ this.schema.custom = true;
76
81
  const deserializer = deserializers[0];
77
82
  if (!deserializer.signature.parameters.length) throwError("Could not find any parameters in custom deserializer for " + this.schema.name + ". Deserializers must have one parameter like 'deserializer(data: string): " + this.schema.name + " {}'", deserializer.range);
78
83
  if (deserializer.signature.parameters.length > 1) throwError("Found too many parameters in custom deserializer for " + this.schema.name + ", but deserializers can only accept one parameter of type 'string'!", deserializer.signature.parameters[1].range);
@@ -82,16 +87,10 @@ class JSONTransform extends Visitor {
82
87
  if (!deserializer.decorators.some((v) => (<IdentifierExpression>v.name).text == "inline")) {
83
88
  deserializer.decorators.push(Node.createDecorator(Node.createIdentifierExpression("inline", deserializer.range), null, deserializer.range));
84
89
  }
85
- let DESERIALIZER = "";
86
- DESERIALIZER += " __DESERIALIZE_CUSTOM(data: string): this {\n";
87
- DESERIALIZER += " return this." + deserializer.name.text + "(data);\n";
88
- DESERIALIZER += " }\n";
89
-
90
- if (process.env["JSON_DEBUG"]) console.log(DESERIALIZER);
91
90
 
92
- const DESERIALIZER_METHOD = SimpleParser.parseClassMember(DESERIALIZER, node);
93
-
94
- if (!node.members.find((v) => v.name.text == "__DESERIALIZE_CUSTOM")) node.members.push(DESERIALIZER_METHOD);
91
+ DESERIALIZE_CUSTOM += " __DESERIALIZE<T>(srcStart: usize, srcEnd: usize, out: T): T {\n";
92
+ DESERIALIZE_CUSTOM += " return inline.always(this." + deserializer.name.text + "(changetype<string>(srcStart)));\n";
93
+ DESERIALIZE_CUSTOM += " }\n";
95
94
  }
96
95
 
97
96
  if (node.extendsType) {
@@ -100,7 +99,7 @@ class JSONTransform extends Visitor {
100
99
  if (!this.schema.parent) {
101
100
  const internalSearch = getClasses(node.range.source).find((v) => v.name.text == extendsName);
102
101
  if (internalSearch) {
103
- if (process.env["JSON_DEBUG"]) console.log("Found " + extendsName + " internally");
102
+ if (DEBUG) console.log("Found " + extendsName + " internally");
104
103
  this.visitClassDeclaration(internalSearch);
105
104
  this.visitClassDeclaration(node);
106
105
  return;
@@ -108,7 +107,7 @@ class JSONTransform extends Visitor {
108
107
 
109
108
  const externalSearch = getImportedClass(extendsName, node.range.source, this.parser);
110
109
  if (externalSearch) {
111
- if (process.env["JSON_DEBUG"]) console.log("Found " + extendsName + " externally");
110
+ if (DEBUG) console.log("Found " + extendsName + " externally");
112
111
  this.visitClassDeclaration(externalSearch);
113
112
  this.visitClassDeclaration(node);
114
113
  return;
@@ -187,10 +186,6 @@ class JSONTransform extends Visitor {
187
186
 
188
187
  if (!this.schema.static) this.schema.members = sortMembers(this.schema.members);
189
188
 
190
- let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
191
- let INITIALIZE = "@inline __INITIALIZE(): this {\n";
192
- let DESERIALIZE = "__DESERIALIZE(keyStart: usize, keyEnd: usize, valStart: usize, valEnd: usize, ptr: usize): void {\n switch (<u32>keyEnd - <u32>keyStart) {\n";
193
-
194
189
  indent = " ";
195
190
 
196
191
  if (this.schema.static == false) {
@@ -301,80 +296,351 @@ class JSONTransform extends Visitor {
301
296
  }
302
297
  }
303
298
 
304
- let sortedMembers: Property[][] = [];
299
+ const sortedMembers: {
300
+ string: Property[];
301
+ number: Property[];
302
+ boolean: Property[];
303
+ null: Property[];
304
+ array: Property[];
305
+ object: Property[];
306
+ } = {
307
+ string: [],
308
+ number: [],
309
+ boolean: [],
310
+ null: [],
311
+ array: [],
312
+ object: [],
313
+ };
305
314
 
306
- let len = -1;
307
- this.schema.members
308
- .slice()
309
- .sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length))
310
- .forEach((member) => {
311
- const _nameLength = member.alias?.length || member.name.length;
312
- if (_nameLength === len) {
313
- sortedMembers[sortedMembers.length - 1].push(member);
314
- } else {
315
- sortedMembers.push([member]);
316
- len = _nameLength;
317
- }
318
- });
315
+ for (const member of this.schema.members) {
316
+ if (member.type.endsWith(" | null")) sortedMembers.null.push(member);
317
+ if (isString(member.type) || member.type == "JSON.Raw") sortedMembers.string.push(member);
318
+ else if (isBoolean(member.type) || member.type.startsWith("JSON.Box<bool")) sortedMembers.boolean.push(member);
319
+ else if (isPrimitive(member.type) || member.type.startsWith("JSON.Box<")) sortedMembers.number.push(member);
320
+ else if (isArray(member.type)) sortedMembers.array.push(member);
321
+ else sortedMembers.object.push(member);
322
+ }
323
+
324
+ indent = "";
325
+ let shouldGroup = false;
326
+
327
+ // DESERIALIZE += indent + " console.log(\"data: \" + JSON.Util.ptrToStr(srcStart,srcEnd))\n";
328
+ DESERIALIZE += indent + " let keyStart: usize = 0;\n";
329
+ if (shouldGroup || DEBUG) DESERIALIZE += indent + " let keyEnd: usize = 0;\n";
330
+ DESERIALIZE += indent + " let isKey = false;\n";
331
+ if (sortedMembers.object.length || sortedMembers.array.length) DESERIALIZE += indent + " let depth: i32 = 0;\n";
332
+ DESERIALIZE += indent + " let lastIndex: usize = 0;\n\n";
333
+
334
+ DESERIALIZE += indent + " while (srcStart < srcEnd && JSON.Util.isSpace(load<u16>(srcStart))) srcStart += 2;\n";
335
+ DESERIALIZE += indent + " while (srcEnd > srcStart && JSON.Util.isSpace(load<u16>(srcEnd - 2))) srcEnd -= 2;\n";
336
+ DESERIALIZE += indent + ' if (srcStart - srcEnd == 0) throw new Error("Input string had zero length or was all whitespace");\n';
337
+ DESERIALIZE += indent + " if (load<u16>(srcStart) != 123) throw new Error(\"Expected '{' at start of object at position \" + (srcEnd - srcStart).toString());\n";
338
+ DESERIALIZE += indent + " if (load<u16>(srcEnd - 2) != 125) throw new Error(\"Expected '}' at end of object at position \" + (srcEnd - srcStart).toString());\n";
339
+ DESERIALIZE += indent + " srcStart += 2;\n\n";
340
+
341
+ DESERIALIZE += indent + " while (srcStart < srcEnd) {\n";
342
+ DESERIALIZE += indent + " let code = load<u16>(srcStart);\n";
343
+ DESERIALIZE += indent + " while (JSON.Util.isSpace(code)) code = load<u16>(srcStart += 2);\n";
344
+ DESERIALIZE += indent + " if (keyStart == 0) {\n";
345
+ DESERIALIZE += indent + " if (code == 34 && load<u16>(srcStart - 2) !== 92) {\n";
346
+ DESERIALIZE += indent + " if (isKey) {\n";
347
+ DESERIALIZE += indent + " keyStart = lastIndex;\n";
348
+ if (shouldGroup || DEBUG) DESERIALIZE += indent + " keyEnd = srcStart;\n";
349
+ DESERIALIZE += indent + " while (JSON.Util.isSpace((code = load<u16>((srcStart += 2))))) {}\n";
350
+ DESERIALIZE += indent + " if (code !== 58) throw new Error(\"Expected ':' after key at position \" + (srcEnd - srcStart).toString());\n";
351
+ DESERIALIZE += indent + " isKey = false;\n";
352
+ DESERIALIZE += indent + " } else {\n";
353
+ DESERIALIZE += indent + " isKey = true;\n";
354
+ DESERIALIZE += indent + " lastIndex = srcStart + 2;\n";
355
+ DESERIALIZE += indent + " }\n";
356
+ DESERIALIZE += indent + " }\n";
357
+ DESERIALIZE += indent + " srcStart += 2;\n";
358
+ DESERIALIZE += indent + " } else {\n";
359
+ // if (shouldGroup) DESERIALIZE += " const keySize = keyEnd - keyStart;\n";
360
+
361
+ const groupMembers = (members: Property[]) => {
362
+ let sorted: Property[][] = [];
363
+
364
+ let len = -1;
365
+ members
366
+ .slice()
367
+ .sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length))
368
+ .forEach((member) => {
369
+ const _nameLength = member.alias?.length || member.name.length;
370
+ if (_nameLength === len) {
371
+ sorted[sorted.length - 1].push(member);
372
+ } else {
373
+ sorted.push([member]);
374
+ len = _nameLength;
375
+ }
376
+ });
377
+
378
+ sorted = sorted.sort((a, b) => b.length - a.length);
379
+ return sorted;
380
+ };
381
+
382
+ const generateComparisions = (members: Property[]) => {
383
+ if (members.some((m) => (m.alias || m.name).length << 1 == 2)) {
384
+ DESERIALIZE += " const code16 = load<u16>(keyStart);\n";
385
+ }
386
+ if (members.some((m) => (m.alias || m.name).length << 1 == 4)) {
387
+ DESERIALIZE += " const code32 = load<u32>(keyStart);\n";
388
+ }
389
+ if (members.some((m) => (m.alias || m.name).length << 1 == 6)) {
390
+ DESERIALIZE += " const code48 = load<u64>(keyStart) & 0x0000FFFFFFFFFFFF;\n";
391
+ }
392
+ if (members.some((m) => (m.alias || m.name).length << 1 == 8)) {
393
+ DESERIALIZE += " const code64 = load<u64>(keyStart);\n";
394
+ }
395
+ if (members.some((m) => (m.alias || m.name).length << 1 > 8)) {
396
+ DESERIALIZE += toMemCDecl(Math.max(...members.map((m) => (m.alias || m.name).length << 1)), " ");
397
+ }
319
398
 
320
- sortedMembers = sortedMembers.sort((a, b) => b.length - a.length);
321
-
322
- indentInc();
323
- for (const memberGroup of sortedMembers) {
324
- const memberLen = (memberGroup[0].alias || memberGroup[0].name).length << 1;
325
- DESERIALIZE += `${indent}case ${memberLen}: {\n`;
326
- indentInc();
327
- if (memberLen == 2) DESERIALIZE += `${indent}switch (load<u16>(keyStart)) {\n`;
328
- else if (memberLen == 4) DESERIALIZE += `${indent}switch (load<u32>(keyStart)) {\n`;
329
- else if (memberLen == 6) DESERIALIZE += `${indent}let code = load<u64>(keyStart) & 0x0000FFFFFFFFFFFF;\n`;
330
- else if (memberLen == 8) DESERIALIZE += `${indent}let code = load<u64>(keyStart);\n`;
331
- else DESERIALIZE += toMemCDecl(memberLen, indent);
332
- for (let i = 0; i < memberGroup.length; i++) {
333
- const member = memberGroup[i];
399
+ const complex = isStruct(members[0].type) || members[0].type != "JSON.Obj" || isArray(members[0].type);
400
+ const firstMemberName = members[0].alias || members[0].name;
401
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
402
+ DESERIALIZE += indent + " store<" + members[0].type + ">(changetype<usize>(out), JSON.__deserialize<" + members[0].type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(firstMemberName) + "));\n";
403
+ if (!complex) DESERIALIZE += indent + " srcStart += 2;\n";
404
+ DESERIALIZE += indent + " keyStart = 0;\n";
405
+ DESERIALIZE += indent + " break;\n";
406
+ DESERIALIZE += indent + " }";
407
+
408
+ for (let i = 1; i < members.length; i++) {
409
+ const member = members[i];
334
410
  const memberName = member.alias || member.name;
335
- const dst = this.schemas.find((v) => v.name == member.type) ? 'load<usize>(ptr + offsetof<this>("' + member.name + '"))' : "0";
336
- if (memberLen == 2) {
337
- DESERIALIZE += `${indent} case ${memberName.charCodeAt(0)}: { // ${memberName}\n`;
338
- DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd, ${dst}), offsetof<this>(${JSON.stringify(member.name)}));\n`;
339
- DESERIALIZE += `${indent} return;\n`;
340
- DESERIALIZE += `${indent} }\n`;
341
- } else if (memberLen == 4) {
342
- DESERIALIZE += `${indent} case ${toU32(memberName)}: { // ${memberName}\n`;
343
- DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd, ${dst}), offsetof<this>(${JSON.stringify(member.name)}));\n`;
344
- DESERIALIZE += `${indent} return;\n`;
345
- DESERIALIZE += `${indent} }\n`;
346
- } else if (memberLen == 6) {
347
- DESERIALIZE += i == 0 ? indent : "";
348
- DESERIALIZE += `if (code == ${toU48(memberName)}) { // ${memberName}\n`;
349
- DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd, ${dst}), offsetof<this>(${JSON.stringify(member.name)}));\n`;
350
- DESERIALIZE += `${indent} return;\n`;
351
- DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
352
- } else if (memberLen == 8) {
353
- DESERIALIZE += i == 0 ? indent : "";
354
- DESERIALIZE += `if (code == ${toU64(memberName)}) { // ${memberName}\n`;
355
- DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd, ${dst}), offsetof<this>(${JSON.stringify(member.name)}));\n`;
356
- DESERIALIZE += `${indent} return;\n`;
357
- DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
358
- } else {
359
- DESERIALIZE += i == 0 ? indent : "";
360
- DESERIALIZE += `if (${toMemCCheck(memberName)}) { // ${memberName}\n`;
361
- DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd, ${dst}), offsetof<this>(${JSON.stringify(member.name)}));\n`;
362
- DESERIALIZE += `${indent} return;\n`;
363
- DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
364
- }
411
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
412
+ DESERIALIZE += indent + " store<" + members[0].type + ">(changetype<usize>(out), JSON.__deserialize<" + members[0].type + ">(lastIndex, srcStart), offsetof<this>(" + JSON.stringify(memberName) + "));\n";
413
+ if (isString(members[0].type)) DESERIALIZE += indent + " srcStart += 4;\n";
414
+ else if (!complex) DESERIALIZE += indent + " srcStart += 2;\n";
415
+ DESERIALIZE += indent + " keyStart = 0;\n";
416
+ DESERIALIZE += indent + " break;\n";
417
+ DESERIALIZE += indent + " }";
365
418
  }
366
- if (memberLen < 6) {
367
- DESERIALIZE += `${indent}}\n`; // Close switch
419
+
420
+ DESERIALIZE += " else {\n";
421
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
422
+ DESERIALIZE += indent + " }\n";
423
+ };
424
+
425
+ let mbElse = " ";
426
+ if (sortedMembers.string.length) {
427
+ DESERIALIZE += mbElse + "if (code == 34) {\n";
428
+ DESERIALIZE += " lastIndex = srcStart;\n";
429
+ DESERIALIZE += " srcStart += 2;\n";
430
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
431
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
432
+ DESERIALIZE += " if (code == 34 && load<u16>(srcStart - 2) !== 92) {\n";
433
+ DESERIALIZE += " srcStart += 2;\n";
434
+ generateComparisions(sortedMembers.string);
435
+ DESERIALIZE += " }\n"; // Close break char check
436
+ DESERIALIZE += " srcStart += 2;\n";
437
+ DESERIALIZE += " }\n"; // Close char scan loop
438
+ DESERIALIZE += " }\n"; // Close first char check
439
+ mbElse = " else ";
440
+ }
441
+
442
+ if (sortedMembers.number.length) {
443
+ DESERIALIZE += mbElse + "if (code - 48 <= 9 || code == 45) {\n";
444
+ DESERIALIZE += " lastIndex = srcStart;\n";
445
+ DESERIALIZE += " srcStart += 2;\n";
446
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
447
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
448
+ DESERIALIZE += " if (code == 44 || code == 125 || JSON.Util.isSpace(code)) {\n";
449
+ // DESERIALIZE += " console.log(JSON.Util.ptrToStr(keyStart,keyEnd) + \" = \" + load<u16>(keyStart).toString() + \" val \" + JSON.Util.ptrToStr(lastIndex, srcStart));\n";
450
+
451
+ generateComparisions(sortedMembers.number);
452
+ DESERIALIZE += " }\n"; // Close break char check
453
+ DESERIALIZE += " srcStart += 2;\n";
454
+ DESERIALIZE += " }\n"; // Close char scan loop
455
+ DESERIALIZE += " }"; // Close first char check
456
+ mbElse = " else ";
457
+ }
458
+
459
+ if (sortedMembers.object.length) {
460
+ DESERIALIZE += mbElse + "if (code == 123) {\n";
461
+ DESERIALIZE += " lastIndex = srcStart;\n";
462
+ DESERIALIZE += " depth++;\n";
463
+ DESERIALIZE += " srcStart += 2;\n";
464
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
465
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
466
+ DESERIALIZE += " if (code == 34) {\n";
467
+ DESERIALIZE += " srcStart += 2;\n";
468
+ DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && load<u16>(srcStart - 2) != 92)) srcStart += 2;\n";
469
+ DESERIALIZE += " } else if (code == 125) {\n";
470
+ DESERIALIZE += " if (--depth == 0) {\n";
471
+ DESERIALIZE += " srcStart += 2;\n";
472
+
473
+ indent = " ";
474
+ generateComparisions(sortedMembers.object);
475
+ indent = "";
476
+
477
+ DESERIALIZE += " }\n"; // Close break char check
478
+ DESERIALIZE += " } else if (code == 123) depth++;\n";
479
+ DESERIALIZE += " srcStart += 2;\n";
480
+ DESERIALIZE += " }\n"; // Close char scan loop
481
+ DESERIALIZE += " }"; // Close first char check
482
+ mbElse = " else ";
483
+ }
484
+ if (sortedMembers.array.length) {
485
+ DESERIALIZE += mbElse + "if (code == 91) {\n";
486
+ DESERIALIZE += " lastIndex = srcStart;\n";
487
+ DESERIALIZE += " depth++;\n";
488
+ DESERIALIZE += " srcStart += 2;\n";
489
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
490
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
491
+ DESERIALIZE += " if (code == 34) {\n";
492
+ DESERIALIZE += " srcStart += 2;\n";
493
+ DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && load<u16>(srcStart - 2) != 92)) srcStart += 2;\n";
494
+ DESERIALIZE += " } else if (code == 93) {\n";
495
+ DESERIALIZE += " if (--depth == 0) {\n";
496
+ DESERIALIZE += " srcStart += 2;\n";
497
+ // DESERIALIZE += " console.log(ptrToStr(keyStart,keyEnd) + \" = \" + (load<u64>(keyStart) & 0x0000FFFFFFFFFFFF) .toString());\n";
498
+
499
+ indent = " ";
500
+ generateComparisions(sortedMembers.array);
501
+ indent = "";
502
+
503
+ DESERIALIZE += " }\n"; // Close break char check
504
+ DESERIALIZE += " } else if (code == 91) depth++;\n";
505
+ DESERIALIZE += " srcStart += 2;\n";
506
+ DESERIALIZE += " }\n"; // Close char scan loop
507
+ DESERIALIZE += " }"; // Close first char check
508
+ mbElse = " else ";
509
+ }
510
+
511
+ if (sortedMembers.boolean.length) {
512
+ DESERIALIZE += mbElse + "if (code == 116) {\n";
513
+ DESERIALIZE += " if (load<u64>(srcStart) == 28429475166421108) {\n";
514
+ DESERIALIZE += " srcStart += 8;\n";
515
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 2)) {
516
+ DESERIALIZE += " const code16 = load<u16>(keyStart);\n";
517
+ }
518
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 4)) {
519
+ DESERIALIZE += " const code32 = load<u32>(keyStart);\n";
520
+ }
521
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 6)) {
522
+ DESERIALIZE += " const code48 = load<u64>(keyStart) & 0x0000FFFFFFFFFFFF;\n";
523
+ }
524
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 8)) {
525
+ DESERIALIZE += " const code64 = load<u64>(keyStart);\n";
526
+ }
527
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 > 8)) {
528
+ DESERIALIZE += toMemCDecl(Math.max(...sortedMembers.boolean.map((m) => (m.alias || m.name).length << 1)), " ");
529
+ }
530
+ const firstMemberName = sortedMembers.boolean[0].alias || sortedMembers.boolean[0].name;
531
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
532
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
533
+ DESERIALIZE += indent + " srcStart += 2;\n";
534
+ DESERIALIZE += indent + " keyStart = 0;\n";
535
+ DESERIALIZE += indent + " break;\n";
536
+ DESERIALIZE += indent + " }";
537
+
538
+ for (let i = 1; i < sortedMembers.boolean.length; i++) {
539
+ const member = sortedMembers.boolean[i];
540
+ const memberName = member.alias || member.name;
541
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
542
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
543
+ DESERIALIZE += indent + " srcStart += 2;\n";
544
+ DESERIALIZE += indent + " keyStart = 0;\n";
545
+ DESERIALIZE += indent + " break;\n";
546
+ DESERIALIZE += indent + " }";
368
547
  }
369
- indentDec();
370
- DESERIALIZE += `${indent} return;\n`; // Break switch
371
- DESERIALIZE += `${indent}}\n`; // Close length switch
548
+
549
+ DESERIALIZE += " else {\n";
550
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
551
+ DESERIALIZE += indent + " }\n";
552
+
553
+ DESERIALIZE += " }"; // Close first char check
554
+ mbElse = " else ";
555
+ DESERIALIZE += " else if (load<u64>(srcStart, 2) == 28429466576093281) {\n";
556
+ DESERIALIZE += " srcStart += 10;\n";
557
+
558
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
559
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
560
+ DESERIALIZE += indent + " srcStart += 2;\n";
561
+ DESERIALIZE += indent + " keyStart = 0;\n";
562
+ DESERIALIZE += indent + " break;\n";
563
+ DESERIALIZE += indent + " }";
564
+
565
+ for (let i = 1; i < sortedMembers.boolean.length; i++) {
566
+ const member = sortedMembers.boolean[i];
567
+ const memberName = member.alias || member.name;
568
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
569
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
570
+ DESERIALIZE += indent + " srcStart += 2;\n";
571
+ DESERIALIZE += indent + " keyStart = 0;\n";
572
+ DESERIALIZE += indent + " break;\n";
573
+ DESERIALIZE += indent + " }";
574
+ }
575
+
576
+ DESERIALIZE += " else {\n";
577
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
578
+ DESERIALIZE += indent + " }\n";
579
+
580
+ DESERIALIZE += " }\n"; // Close first char check
581
+ DESERIALIZE += " }"; // Close first char check
372
582
  }
373
583
 
584
+ if (sortedMembers.null.length) {
585
+ DESERIALIZE += mbElse + "if (code == 110) {\n";
586
+
587
+ DESERIALIZE += " if (load<u64>(srcStart) == 30399761348886638) {\n";
588
+ DESERIALIZE += " srcStart += 8;\n";
589
+
590
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 2)) {
591
+ DESERIALIZE += " const code16 = load<u16>(keyStart);\n";
592
+ }
593
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 4)) {
594
+ DESERIALIZE += " const code32 = load<u32>(keyStart);\n";
595
+ }
596
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 6)) {
597
+ DESERIALIZE += " const code48 = load<u64>(keyStart) & 0x0000FFFFFFFFFFFF;\n";
598
+ }
599
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 8)) {
600
+ DESERIALIZE += " const code64 = load<u64>(keyStart);\n";
601
+ }
602
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 > 8)) {
603
+ DESERIALIZE += toMemCDecl(Math.max(...sortedMembers.null.map((m) => (m.alias || m.name).length << 1)), " ");
604
+ }
605
+
606
+ const firstMemberName = sortedMembers.null[0].alias || sortedMembers.null[0].name;
607
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
608
+ DESERIALIZE += indent + " store<" + sortedMembers.null[0].type + ">(changetype<usize>(out), null, offsetof<this>(" + JSON.stringify(sortedMembers.null[0].name) + "));\n";
609
+ DESERIALIZE += indent + " srcStart += 2;\n";
610
+ DESERIALIZE += indent + " keyStart = 0;\n";
611
+ DESERIALIZE += indent + " break;\n";
612
+ DESERIALIZE += indent + " }";
613
+
614
+ for (let i = 1; i < sortedMembers.null.length; i++) {
615
+ const member = sortedMembers.null[i];
616
+ const memberName = member.alias || member.name;
617
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
618
+ DESERIALIZE += indent + " store<" + sortedMembers.null[0].type + ">(changetype<usize>(out), null, offsetof<this>(" + JSON.stringify(sortedMembers.null[0].name) + "));\n";
619
+ DESERIALIZE += indent + " srcStart += 2;\n";
620
+ DESERIALIZE += indent + " keyStart = 0;\n";
621
+ DESERIALIZE += indent + " break;\n";
622
+ DESERIALIZE += indent + " }";
623
+ }
624
+
625
+ DESERIALIZE += " else {\n";
626
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
627
+ DESERIALIZE += indent + " }\n";
628
+
629
+ DESERIALIZE += " }"; // Close first char check
630
+ DESERIALIZE += "\n }"; // Close first char check
631
+
632
+ mbElse = " else ";
633
+ }
634
+
635
+ DESERIALIZE += " else {\n";
636
+ DESERIALIZE += " srcStart += 2;\n";
637
+ DESERIALIZE += "}\n";
638
+ DESERIALIZE += "\n }\n"; // Close value portion
639
+
374
640
  indentDec();
375
- DESERIALIZE += `${indent}}\n`; // Close length switch
641
+ DESERIALIZE += ` }\n`; // Close while loop
376
642
  indentDec();
377
- DESERIALIZE += `${indent}}\n`; // Close function
643
+ DESERIALIZE += ` return out;\n}\n`; // Close function
378
644
 
379
645
  indent = " ";
380
646
 
@@ -388,15 +654,18 @@ class JSONTransform extends Visitor {
388
654
  INITIALIZE += " return this;\n";
389
655
  INITIALIZE += "}";
390
656
 
391
- if (process.env["JSON_DEBUG"]) {
392
- console.log(SERIALIZE);
657
+ // if (DESERIALIZE_CUSTOM) {
658
+ // DESERIALIZE = "__DESERIALIZE(keyStart: usize, keyEnd: usize, valStart: usize, valEnd: usize, ptr: usize): usize {\n if (isDefined(this.__DESERIALIZE_CUSTOM) return changetype<usize>(this." + deserializers[0].name + "(changetype<switch (<u32>keyEnd - <u32>keyStart) {\n"
659
+ // }
660
+ if (DEBUG) {
661
+ console.log(SERIALIZE_CUSTOM ? SERIALIZE_CUSTOM : SERIALIZE);
393
662
  console.log(INITIALIZE);
394
- console.log(DESERIALIZE);
663
+ console.log(DESERIALIZE_CUSTOM || DESERIALIZE);
395
664
  }
396
665
 
397
- const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE, node);
666
+ const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE_CUSTOM ? SERIALIZE_CUSTOM : SERIALIZE, node);
398
667
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
399
- const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
668
+ const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE_CUSTOM || DESERIALIZE, node);
400
669
 
401
670
  if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_METHOD);
402
671
  if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD);
@@ -406,9 +675,9 @@ class JSONTransform extends Visitor {
406
675
  generateEmptyMethods(node: ClassDeclaration): void {
407
676
  let SERIALIZE_EMPTY = "@inline __SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
408
677
  let INITIALIZE_EMPTY = "@inline __INITIALIZE(): this {\n return this;\n}";
409
- let DESERIALIZE_EMPTY = "@inline __DESERIALIZE(keyStart: usize, keyEnd: usize, valStart: usize, valEnd: usize, ptr: usize): void {\n return false;\n}";
678
+ let DESERIALIZE_EMPTY = "@inline __DESERIALIZE(srcStart: usize, srcEnd: usize): this {\n return this;\n}";
410
679
 
411
- if (process.env["JSON_DEBUG"]) {
680
+ if (DEBUG) {
412
681
  console.log(SERIALIZE_EMPTY);
413
682
  console.log(INITIALIZE_EMPTY);
414
683
  console.log(DESERIALIZE_EMPTY);
@@ -474,7 +743,7 @@ class JSONTransform extends Visitor {
474
743
 
475
744
  const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("bs", node.range, false), null, node.range)], Node.createStringLiteralExpression(bsPath, node.range), node.range);
476
745
  this.topStatements.push(replaceNode);
477
- if (process.env["JSON_DEBUG"]) console.log("Added as-bs import: " + toString(replaceNode) + "\n");
746
+ if (DEBUG) console.log("Added as-bs import: " + toString(replaceNode) + "\n");
478
747
  }
479
748
 
480
749
  if (!jsonImport) {
@@ -487,7 +756,7 @@ class JSONTransform extends Visitor {
487
756
  node.range,
488
757
  );
489
758
  this.topStatements.push(replaceNode);
490
- if (process.env["JSON_DEBUG"]) console.log("Added json-as import: " + toString(replaceNode) + "\n");
759
+ if (DEBUG) console.log("Added json-as import: " + toString(replaceNode) + "\n");
491
760
  }
492
761
  }
493
762
 
@@ -536,7 +805,7 @@ class JSONTransform extends Visitor {
536
805
 
537
806
  export default class Transformer extends Transform {
538
807
  afterParse(parser: Parser): void {
539
- const transformer = new JSONTransform();
808
+ const transformer = JSONTransform.SN;
540
809
  const sources = parser.sources
541
810
  .filter((source) => {
542
811
  const p = source.internalPath;
@@ -626,18 +895,18 @@ function toMemCDecl(n: number, indent: string): string {
626
895
  let offset = 0;
627
896
  let index = 0;
628
897
  while (n >= 8) {
629
- out += `${indent}const code${index++} = load<u64>(keyStart, ${offset});\n`;
898
+ out += `${indent}const codeS${(index += 8)} = load<u64>(keyStart, ${offset});\n`;
630
899
  offset += 8;
631
900
  n -= 8;
632
901
  }
633
902
 
634
903
  while (n >= 4) {
635
- out += `${indent}const code${index++} = load<u32>(keyStart, ${offset});\n`;
904
+ out += `${indent}const codeS${(index += 4)} = load<u32>(keyStart, ${offset});\n`;
636
905
  offset += 4;
637
906
  n -= 4;
638
907
  }
639
908
 
640
- if (n == 1) out += `${indent}const code${index++} = load<u16>(keyStart, ${offset});\n`;
909
+ if (n == 1) out += `${indent}const codeS${(index += 1)} = load<u16>(keyStart, ${offset});\n`;
641
910
 
642
911
  return out;
643
912
  }
@@ -648,18 +917,18 @@ function toMemCCheck(data: string): string {
648
917
  let offset = 0;
649
918
  let index = 0;
650
919
  while (n >= 8) {
651
- out += ` && code${index++} == ${toU64(data, offset >> 1)}`;
920
+ out += ` && codeS${(index += 8)} == ${toU64(data, offset >> 1)}`;
652
921
  offset += 8;
653
922
  n -= 8;
654
923
  }
655
924
 
656
925
  while (n >= 4) {
657
- out += ` && code${index++} == ${toU32(data, offset >> 1)}`;
926
+ out += ` && codeS${(index += 4)} == ${toU32(data, offset >> 1)}`;
658
927
  offset += 4;
659
928
  n -= 4;
660
929
  }
661
930
 
662
- if (n == 1) out += ` && code${index++} == ${toU16(data, offset >> 1)}`;
931
+ if (n == 1) out += ` && codeS${(index += 1)} == ${toU16(data, offset >> 1)}`;
663
932
 
664
933
  return out.slice(4);
665
934
  }
@@ -696,11 +965,6 @@ function strToNum(data: string, simd: boolean = false, offset: number = 0): stri
696
965
  return out;
697
966
  }
698
967
 
699
- function isPrimitive(type: string): boolean {
700
- const primitiveTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64", "f32", "f64", "bool", "boolean"];
701
- return primitiveTypes.some((v) => type.startsWith(v));
702
- }
703
-
704
968
  function throwError(message: string, range: Range): never {
705
969
  const err = new Error();
706
970
  err.stack = `${message}\n at ${range.source.normalizedPath}:${range.source.lineAt(range.start)}:${range.source.columnAt()}\n`;
@@ -735,3 +999,52 @@ function sizeof(type: string): number {
735
999
  else if (type == "bool" || type == "boolean") return 10;
736
1000
  else return 0;
737
1001
  }
1002
+
1003
+ function isPrimitive(type: string): boolean {
1004
+ const primitiveTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64", "f32", "f64", "bool", "boolean"];
1005
+ return primitiveTypes.some((v) => type.startsWith(v));
1006
+ }
1007
+
1008
+ function isBoolean(type: string): boolean {
1009
+ return type == "bool" || type == "boolean";
1010
+ }
1011
+
1012
+ function isStruct(type: string): boolean {
1013
+ type = stripNull(type);
1014
+ return JSONTransform.SN.schemas.some((v) => v.name == type) || JSONTransform.SN.schema.name == type;
1015
+ }
1016
+
1017
+ function isString(type: string) {
1018
+ return stripNull(type) == "string" || stripNull(type) == "String";
1019
+ }
1020
+
1021
+ function isArray(type: string): boolean {
1022
+ return type.startsWith("Array<");
1023
+ }
1024
+
1025
+ function stripNull(type: string): string {
1026
+ if (type.endsWith(" | null")) {
1027
+ return type.slice(0, type.length - 7);
1028
+ }
1029
+ return type;
1030
+ }
1031
+
1032
+ function getComparision(data: string) {
1033
+ switch (data.length << 1) {
1034
+ case 2: {
1035
+ return "code16 == " + data.charCodeAt(0);
1036
+ }
1037
+ case 4: {
1038
+ return "code32 == " + toU32(data);
1039
+ }
1040
+ case 6: {
1041
+ return "code48 == " + toU48(data);
1042
+ }
1043
+ case 8: {
1044
+ return "code64 == " + toU64(data);
1045
+ }
1046
+ default: {
1047
+ return toMemCCheck(data);
1048
+ }
1049
+ }
1050
+ }