json-as 1.0.8 → 1.1.0

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.
@@ -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<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): __JSON_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<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): __JSON_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,352 @@ 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
+ DESERIALIZE += " console.log(JSON.Util.ptrToStr(keyStart,keyEnd) + \" = \" + load<u16>(keyStart).toString() + \" val \" + JSON.Util.ptrToStr(lastIndex, srcStart));\n";
435
+ generateComparisions(sortedMembers.string);
436
+ DESERIALIZE += " }\n"; // Close break char check
437
+ DESERIALIZE += " srcStart += 2;\n";
438
+ DESERIALIZE += " }\n"; // Close char scan loop
439
+ DESERIALIZE += " }\n"; // Close first char check
440
+ mbElse = " else ";
441
+ }
442
+
443
+ if (sortedMembers.number.length) {
444
+ DESERIALIZE += mbElse + "if (code - 48 <= 9 || code == 45) {\n";
445
+ DESERIALIZE += " lastIndex = srcStart;\n";
446
+ DESERIALIZE += " srcStart += 2;\n";
447
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
448
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
449
+ DESERIALIZE += " if (code == 44 || code == 125 || JSON.Util.isSpace(code)) {\n";
450
+ // DESERIALIZE += " console.log(JSON.Util.ptrToStr(keyStart,keyEnd) + \" = \" + load<u16>(keyStart).toString() + \" val \" + JSON.Util.ptrToStr(lastIndex, srcStart));\n";
451
+
452
+ generateComparisions(sortedMembers.number);
453
+ DESERIALIZE += " }\n"; // Close break char check
454
+ DESERIALIZE += " srcStart += 2;\n";
455
+ DESERIALIZE += " }\n"; // Close char scan loop
456
+ DESERIALIZE += " }"; // Close first char check
457
+ mbElse = " else ";
458
+ }
459
+
460
+ if (sortedMembers.object.length) {
461
+ DESERIALIZE += mbElse + "if (code == 123) {\n";
462
+ DESERIALIZE += " lastIndex = srcStart;\n";
463
+ DESERIALIZE += " depth++;\n";
464
+ DESERIALIZE += " srcStart += 2;\n";
465
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
466
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
467
+ DESERIALIZE += " if (code == 34) {\n";
468
+ DESERIALIZE += " srcStart += 2;\n";
469
+ DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && load<u16>(srcStart - 2) != 92)) srcStart += 2;\n";
470
+ DESERIALIZE += " } else if (code == 125) {\n";
471
+ DESERIALIZE += " if (--depth == 0) {\n";
472
+ DESERIALIZE += " srcStart += 2;\n";
473
+
474
+ indent = " ";
475
+ generateComparisions(sortedMembers.object);
476
+ indent = "";
477
+
478
+ DESERIALIZE += " }\n"; // Close break char check
479
+ DESERIALIZE += " } else if (code == 123) depth++;\n";
480
+ DESERIALIZE += " srcStart += 2;\n";
481
+ DESERIALIZE += " }\n"; // Close char scan loop
482
+ DESERIALIZE += " }"; // Close first char check
483
+ mbElse = " else ";
484
+ }
485
+ if (sortedMembers.array.length) {
486
+ DESERIALIZE += mbElse + "if (code == 91) {\n";
487
+ DESERIALIZE += " lastIndex = srcStart;\n";
488
+ DESERIALIZE += " depth++;\n";
489
+ DESERIALIZE += " srcStart += 2;\n";
490
+ DESERIALIZE += " while (srcStart < srcEnd) {\n";
491
+ DESERIALIZE += " const code = load<u16>(srcStart);\n";
492
+ DESERIALIZE += " if (code == 34) {\n";
493
+ DESERIALIZE += " srcStart += 2;\n";
494
+ DESERIALIZE += " while (!(load<u16>(srcStart) == 34 && load<u16>(srcStart - 2) != 92)) srcStart += 2;\n";
495
+ DESERIALIZE += " } else if (code == 93) {\n";
496
+ DESERIALIZE += " if (--depth == 0) {\n";
497
+ DESERIALIZE += " srcStart += 2;\n";
498
+ // DESERIALIZE += " console.log(ptrToStr(keyStart,keyEnd) + \" = \" + (load<u64>(keyStart) & 0x0000FFFFFFFFFFFF) .toString());\n";
499
+
500
+ indent = " ";
501
+ generateComparisions(sortedMembers.array);
502
+ indent = "";
503
+
504
+ DESERIALIZE += " }\n"; // Close break char check
505
+ DESERIALIZE += " } else if (code == 91) depth++;\n";
506
+ DESERIALIZE += " srcStart += 2;\n";
507
+ DESERIALIZE += " }\n"; // Close char scan loop
508
+ DESERIALIZE += " }"; // Close first char check
509
+ mbElse = " else ";
510
+ }
511
+
512
+ if (sortedMembers.boolean.length) {
513
+ DESERIALIZE += mbElse + "if (code == 116) {\n";
514
+ DESERIALIZE += " if (load<u64>(srcStart) == 28429475166421108) {\n";
515
+ DESERIALIZE += " srcStart += 8;\n";
516
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 2)) {
517
+ DESERIALIZE += " const code16 = load<u16>(keyStart);\n";
518
+ }
519
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 4)) {
520
+ DESERIALIZE += " const code32 = load<u32>(keyStart);\n";
521
+ }
522
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 6)) {
523
+ DESERIALIZE += " const code48 = load<u64>(keyStart) & 0x0000FFFFFFFFFFFF;\n";
524
+ }
525
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 == 8)) {
526
+ DESERIALIZE += " const code64 = load<u64>(keyStart);\n";
527
+ }
528
+ if (sortedMembers.boolean.some((m) => (m.alias || m.name).length << 1 > 8)) {
529
+ DESERIALIZE += toMemCDecl(Math.max(...sortedMembers.boolean.map((m) => (m.alias || m.name).length << 1)), " ");
530
+ }
531
+ const firstMemberName = sortedMembers.boolean[0].alias || sortedMembers.boolean[0].name;
532
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
533
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
534
+ DESERIALIZE += indent + " srcStart += 2;\n";
535
+ DESERIALIZE += indent + " keyStart = 0;\n";
536
+ DESERIALIZE += indent + " break;\n";
537
+ DESERIALIZE += indent + " }";
538
+
539
+ for (let i = 1; i < sortedMembers.boolean.length; i++) {
540
+ const member = sortedMembers.boolean[i];
541
+ const memberName = member.alias || member.name;
542
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
543
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), true, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
544
+ DESERIALIZE += indent + " srcStart += 2;\n";
545
+ DESERIALIZE += indent + " keyStart = 0;\n";
546
+ DESERIALIZE += indent + " break;\n";
547
+ DESERIALIZE += indent + " }";
368
548
  }
369
- indentDec();
370
- DESERIALIZE += `${indent} return;\n`; // Break switch
371
- DESERIALIZE += `${indent}}\n`; // Close length switch
549
+
550
+ DESERIALIZE += " else {\n";
551
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
552
+ DESERIALIZE += indent + " }\n";
553
+
554
+ DESERIALIZE += " }"; // Close first char check
555
+ mbElse = " else ";
556
+ DESERIALIZE += " else if (load<u64>(srcStart, 2) == 28429466576093281) {\n";
557
+ DESERIALIZE += " srcStart += 10;\n";
558
+
559
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
560
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
561
+ DESERIALIZE += indent + " srcStart += 2;\n";
562
+ DESERIALIZE += indent + " keyStart = 0;\n";
563
+ DESERIALIZE += indent + " break;\n";
564
+ DESERIALIZE += indent + " }";
565
+
566
+ for (let i = 1; i < sortedMembers.boolean.length; i++) {
567
+ const member = sortedMembers.boolean[i];
568
+ const memberName = member.alias || member.name;
569
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
570
+ DESERIALIZE += indent + " store<" + sortedMembers.boolean[0].type + ">(changetype<usize>(out), false, offsetof<this>(" + JSON.stringify(sortedMembers.boolean[0].name) + "));\n";
571
+ DESERIALIZE += indent + " srcStart += 2;\n";
572
+ DESERIALIZE += indent + " keyStart = 0;\n";
573
+ DESERIALIZE += indent + " break;\n";
574
+ DESERIALIZE += indent + " }";
575
+ }
576
+
577
+ DESERIALIZE += " else {\n";
578
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
579
+ DESERIALIZE += indent + " }\n";
580
+
581
+ DESERIALIZE += " }\n"; // Close first char check
582
+ DESERIALIZE += " }"; // Close first char check
372
583
  }
373
584
 
585
+ if (sortedMembers.null.length) {
586
+ DESERIALIZE += mbElse + "if (code == 110) {\n";
587
+
588
+ DESERIALIZE += " if (load<u64>(srcStart) == 30399761348886638) {\n";
589
+ DESERIALIZE += " srcStart += 8;\n";
590
+
591
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 2)) {
592
+ DESERIALIZE += " const code16 = load<u16>(keyStart);\n";
593
+ }
594
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 4)) {
595
+ DESERIALIZE += " const code32 = load<u32>(keyStart);\n";
596
+ }
597
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 6)) {
598
+ DESERIALIZE += " const code48 = load<u64>(keyStart) & 0x0000FFFFFFFFFFFF;\n";
599
+ }
600
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 == 8)) {
601
+ DESERIALIZE += " const code64 = load<u64>(keyStart);\n";
602
+ }
603
+ if (sortedMembers.null.some((m) => (m.alias || m.name).length << 1 > 8)) {
604
+ DESERIALIZE += toMemCDecl(Math.max(...sortedMembers.null.map((m) => (m.alias || m.name).length << 1)), " ");
605
+ }
606
+
607
+ const firstMemberName = sortedMembers.null[0].alias || sortedMembers.null[0].name;
608
+ DESERIALIZE += indent + " if (" + getComparision(firstMemberName) + ") { // " + firstMemberName + "\n";
609
+ DESERIALIZE += indent + " store<" + sortedMembers.null[0].type + ">(changetype<usize>(out), null, offsetof<this>(" + JSON.stringify(sortedMembers.null[0].name) + "));\n";
610
+ DESERIALIZE += indent + " srcStart += 2;\n";
611
+ DESERIALIZE += indent + " keyStart = 0;\n";
612
+ DESERIALIZE += indent + " break;\n";
613
+ DESERIALIZE += indent + " }";
614
+
615
+ for (let i = 1; i < sortedMembers.null.length; i++) {
616
+ const member = sortedMembers.null[i];
617
+ const memberName = member.alias || member.name;
618
+ DESERIALIZE += indent + " else if (" + getComparision(memberName) + ") { // " + memberName + "\n";
619
+ DESERIALIZE += indent + " store<" + sortedMembers.null[0].type + ">(changetype<usize>(out), null, offsetof<this>(" + JSON.stringify(sortedMembers.null[0].name) + "));\n";
620
+ DESERIALIZE += indent + " srcStart += 2;\n";
621
+ DESERIALIZE += indent + " keyStart = 0;\n";
622
+ DESERIALIZE += indent + " break;\n";
623
+ DESERIALIZE += indent + " }";
624
+ }
625
+
626
+ DESERIALIZE += " else {\n";
627
+ DESERIALIZE += indent + ' throw new Error("Unexpected key in JSON object \'" + String.fromCharCode(load<u16>(srcStart)) + "\' at position " + (srcEnd - srcStart).toString());\n';
628
+ DESERIALIZE += indent + " }\n";
629
+
630
+ DESERIALIZE += " }"; // Close first char check
631
+ DESERIALIZE += "\n }"; // Close first char check
632
+
633
+ mbElse = " else ";
634
+ }
635
+
636
+ DESERIALIZE += " else {\n";
637
+ DESERIALIZE += " srcStart += 2;\n";
638
+ DESERIALIZE += "}\n";
639
+ DESERIALIZE += "\n }\n"; // Close value portion
640
+
374
641
  indentDec();
375
- DESERIALIZE += `${indent}}\n`; // Close length switch
642
+ DESERIALIZE += ` }\n`; // Close while loop
376
643
  indentDec();
377
- DESERIALIZE += `${indent}}\n`; // Close function
644
+ DESERIALIZE += ` return out;\n}\n`; // Close function
378
645
 
379
646
  indent = " ";
380
647
 
@@ -388,15 +655,18 @@ class JSONTransform extends Visitor {
388
655
  INITIALIZE += " return this;\n";
389
656
  INITIALIZE += "}";
390
657
 
391
- if (process.env["JSON_DEBUG"]) {
392
- console.log(SERIALIZE);
658
+ // if (DESERIALIZE_CUSTOM) {
659
+ // 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"
660
+ // }
661
+ if (DEBUG) {
662
+ console.log(SERIALIZE_CUSTOM ? SERIALIZE_CUSTOM : SERIALIZE);
393
663
  console.log(INITIALIZE);
394
- console.log(DESERIALIZE);
664
+ console.log(DESERIALIZE_CUSTOM || DESERIALIZE);
395
665
  }
396
666
 
397
- const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE, node);
667
+ const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE_CUSTOM ? SERIALIZE_CUSTOM : SERIALIZE, node);
398
668
  const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
399
- const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
669
+ const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE_CUSTOM || DESERIALIZE, node);
400
670
 
401
671
  if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_METHOD);
402
672
  if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD);
@@ -406,9 +676,9 @@ class JSONTransform extends Visitor {
406
676
  generateEmptyMethods(node: ClassDeclaration): void {
407
677
  let SERIALIZE_EMPTY = "@inline __SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
408
678
  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 {}";
679
+ let DESERIALIZE_EMPTY = "@inline __DESERIALIZE<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): __JSON_T {\n return this;\n}";
410
680
 
411
- if (process.env["JSON_DEBUG"]) {
681
+ if (DEBUG) {
412
682
  console.log(SERIALIZE_EMPTY);
413
683
  console.log(INITIALIZE_EMPTY);
414
684
  console.log(DESERIALIZE_EMPTY);
@@ -474,7 +744,7 @@ class JSONTransform extends Visitor {
474
744
 
475
745
  const replaceNode = Node.createImportStatement([Node.createImportDeclaration(Node.createIdentifierExpression("bs", node.range, false), null, node.range)], Node.createStringLiteralExpression(bsPath, node.range), node.range);
476
746
  this.topStatements.push(replaceNode);
477
- if (process.env["JSON_DEBUG"]) console.log("Added as-bs import: " + toString(replaceNode) + "\n");
747
+ if (DEBUG) console.log("Added as-bs import: " + toString(replaceNode) + "\n");
478
748
  }
479
749
 
480
750
  if (!jsonImport) {
@@ -487,7 +757,7 @@ class JSONTransform extends Visitor {
487
757
  node.range,
488
758
  );
489
759
  this.topStatements.push(replaceNode);
490
- if (process.env["JSON_DEBUG"]) console.log("Added json-as import: " + toString(replaceNode) + "\n");
760
+ if (DEBUG) console.log("Added json-as import: " + toString(replaceNode) + "\n");
491
761
  }
492
762
  }
493
763
 
@@ -536,7 +806,7 @@ class JSONTransform extends Visitor {
536
806
 
537
807
  export default class Transformer extends Transform {
538
808
  afterParse(parser: Parser): void {
539
- const transformer = new JSONTransform();
809
+ const transformer = JSONTransform.SN;
540
810
  const sources = parser.sources
541
811
  .filter((source) => {
542
812
  const p = source.internalPath;
@@ -626,18 +896,18 @@ function toMemCDecl(n: number, indent: string): string {
626
896
  let offset = 0;
627
897
  let index = 0;
628
898
  while (n >= 8) {
629
- out += `${indent}const code${index++} = load<u64>(keyStart, ${offset});\n`;
899
+ out += `${indent}const codeS${(index += 8)} = load<u64>(keyStart, ${offset});\n`;
630
900
  offset += 8;
631
901
  n -= 8;
632
902
  }
633
903
 
634
904
  while (n >= 4) {
635
- out += `${indent}const code${index++} = load<u32>(keyStart, ${offset});\n`;
905
+ out += `${indent}const codeS${(index += 4)} = load<u32>(keyStart, ${offset});\n`;
636
906
  offset += 4;
637
907
  n -= 4;
638
908
  }
639
909
 
640
- if (n == 1) out += `${indent}const code${index++} = load<u16>(keyStart, ${offset});\n`;
910
+ if (n == 1) out += `${indent}const codeS${(index += 1)} = load<u16>(keyStart, ${offset});\n`;
641
911
 
642
912
  return out;
643
913
  }
@@ -648,18 +918,18 @@ function toMemCCheck(data: string): string {
648
918
  let offset = 0;
649
919
  let index = 0;
650
920
  while (n >= 8) {
651
- out += ` && code${index++} == ${toU64(data, offset >> 1)}`;
921
+ out += ` && codeS${(index += 8)} == ${toU64(data, offset >> 1)}`;
652
922
  offset += 8;
653
923
  n -= 8;
654
924
  }
655
925
 
656
926
  while (n >= 4) {
657
- out += ` && code${index++} == ${toU32(data, offset >> 1)}`;
927
+ out += ` && codeS${(index += 4)} == ${toU32(data, offset >> 1)}`;
658
928
  offset += 4;
659
929
  n -= 4;
660
930
  }
661
931
 
662
- if (n == 1) out += ` && code${index++} == ${toU16(data, offset >> 1)}`;
932
+ if (n == 1) out += ` && codeS${(index += 1)} == ${toU16(data, offset >> 1)}`;
663
933
 
664
934
  return out.slice(4);
665
935
  }
@@ -696,11 +966,6 @@ function strToNum(data: string, simd: boolean = false, offset: number = 0): stri
696
966
  return out;
697
967
  }
698
968
 
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
969
  function throwError(message: string, range: Range): never {
705
970
  const err = new Error();
706
971
  err.stack = `${message}\n at ${range.source.normalizedPath}:${range.source.lineAt(range.start)}:${range.source.columnAt()}\n`;
@@ -735,3 +1000,52 @@ function sizeof(type: string): number {
735
1000
  else if (type == "bool" || type == "boolean") return 10;
736
1001
  else return 0;
737
1002
  }
1003
+
1004
+ function isPrimitive(type: string): boolean {
1005
+ const primitiveTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64", "f32", "f64", "bool", "boolean"];
1006
+ return primitiveTypes.some((v) => type.startsWith(v));
1007
+ }
1008
+
1009
+ function isBoolean(type: string): boolean {
1010
+ return type == "bool" || type == "boolean";
1011
+ }
1012
+
1013
+ function isStruct(type: string): boolean {
1014
+ type = stripNull(type);
1015
+ return JSONTransform.SN.schemas.some((v) => v.name == type) || JSONTransform.SN.schema.name == type;
1016
+ }
1017
+
1018
+ function isString(type: string) {
1019
+ return stripNull(type) == "string" || stripNull(type) == "String";
1020
+ }
1021
+
1022
+ function isArray(type: string): boolean {
1023
+ return type.startsWith("Array<");
1024
+ }
1025
+
1026
+ function stripNull(type: string): string {
1027
+ if (type.endsWith(" | null")) {
1028
+ return type.slice(0, type.length - 7);
1029
+ }
1030
+ return type;
1031
+ }
1032
+
1033
+ function getComparision(data: string) {
1034
+ switch (data.length << 1) {
1035
+ case 2: {
1036
+ return "code16 == " + data.charCodeAt(0);
1037
+ }
1038
+ case 4: {
1039
+ return "code32 == " + toU32(data);
1040
+ }
1041
+ case 6: {
1042
+ return "code48 == " + toU48(data);
1043
+ }
1044
+ case 8: {
1045
+ return "code64 == " + toU64(data);
1046
+ }
1047
+ default: {
1048
+ return toMemCCheck(data);
1049
+ }
1050
+ }
1051
+ }