json-as 0.9.29 → 1.0.0-alpha.1
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.
- package/.github/workflows/nodejs.yml +0 -3
- package/.prettierrc.json +3 -2
- package/CHANGELOG +13 -0
- package/LICENSE +1 -1
- package/README.md +22 -7
- package/as-test.config.json +1 -1
- package/asconfig.json +2 -2
- package/assembly/__benches__/misc.bench.ts +17 -32
- package/assembly/__tests__/bool.spec.ts +1 -1
- package/assembly/__tests__/simd/string.spec.ts +32 -0
- package/assembly/custom/memory.ts +25 -0
- package/assembly/custom/util.ts +14 -92
- package/assembly/deserialize/simd/string.ts +103 -0
- package/assembly/deserialize/simple/arbitrary.ts +17 -0
- package/assembly/deserialize/simple/array/arbitrary.ts +113 -0
- package/assembly/deserialize/simple/array/array.ts +18 -0
- package/assembly/deserialize/simple/array/bool.ts +17 -0
- package/assembly/deserialize/simple/array/float.ts +28 -0
- package/assembly/deserialize/simple/array/integer.ts +27 -0
- package/assembly/deserialize/simple/array/map.ts +18 -0
- package/assembly/deserialize/simple/array/object.ts +18 -0
- package/assembly/deserialize/simple/array/string.ts +22 -0
- package/assembly/deserialize/simple/array.ts +48 -0
- package/assembly/deserialize/simple/bool.ts +9 -0
- package/assembly/deserialize/simple/date.ts +11 -0
- package/assembly/deserialize/simple/float.ts +10 -0
- package/assembly/deserialize/simple/integer.ts +5 -0
- package/assembly/deserialize/simple/map.ts +154 -0
- package/assembly/deserialize/simple/object.ts +159 -0
- package/assembly/deserialize/simple/string.ts +48 -0
- package/assembly/globals/tables.ts +417 -0
- package/assembly/index.d.ts +9 -13
- package/assembly/index.ts +266 -146
- package/assembly/serialize/simd/string.ts +176 -0
- package/assembly/serialize/simple/arbitrary.ts +36 -0
- package/assembly/serialize/simple/array.ts +32 -0
- package/assembly/serialize/simple/bool.ts +19 -0
- package/assembly/serialize/simple/date.ts +13 -0
- package/assembly/serialize/simple/float.ts +7 -0
- package/assembly/serialize/simple/integer.ts +7 -0
- package/assembly/serialize/simple/map.ts +43 -0
- package/assembly/serialize/simple/object.ts +7 -0
- package/assembly/serialize/simple/string.ts +48 -0
- package/assembly/test.ts +41 -27
- package/assembly/tsconfig.json +2 -91
- package/assembly/types.ts +0 -0
- package/assembly/util/atoi.ts +35 -0
- package/assembly/util/bytes.ts +12 -0
- package/assembly/util/concat.ts +9 -0
- package/assembly/util/getArrayDepth.ts +17 -0
- package/assembly/util/index.ts +5 -0
- package/assembly/util/isSpace.ts +4 -0
- package/assembly/util/nextPowerOf2.ts +4 -0
- package/assembly/util/ptrToStr.ts +7 -0
- package/assembly/util/snp.ts +69 -0
- package/bench.js +5 -5
- package/modules/bs/index.ts +167 -0
- package/modules/tsconfig.json +8 -0
- package/package.json +42 -48
- package/transform/lib/builder.js +1353 -0
- package/transform/lib/builder.js.map +1 -0
- package/transform/lib/index.js +497 -332
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/index.old.js +404 -0
- package/transform/lib/index.old.js.map +1 -0
- package/transform/lib/linker.js +18 -0
- package/transform/lib/linker.js.map +1 -0
- package/transform/lib/types.js +25 -0
- package/transform/lib/types.js.map +1 -0
- package/transform/lib/util.js +47 -0
- package/transform/lib/util.js.map +1 -0
- package/transform/lib/visitor.js +529 -446
- package/transform/lib/visitor.js.map +1 -0
- package/transform/package.json +1 -34
- package/transform/src/builder.ts +1371 -0
- package/transform/src/index.ts +564 -341
- package/transform/src/linker.ts +21 -0
- package/transform/src/types.ts +27 -0
- package/transform/src/util.ts +56 -0
- package/transform/src/visitor.ts +531 -0
- package/transform/tsconfig.json +3 -1
- package/assembly/__benches__/as-tral.d.ts +0 -1
- package/assembly/__tests__/date.spec.ts +0 -12
- package/assembly/custom/bs.ts +0 -202
- package/assembly/deserialize/array/array.ts +0 -31
- package/assembly/deserialize/array/bool.ts +0 -19
- package/assembly/deserialize/array/float.ts +0 -24
- package/assembly/deserialize/array/integer.ts +0 -24
- package/assembly/deserialize/array/map.ts +0 -27
- package/assembly/deserialize/array/object.ts +0 -27
- package/assembly/deserialize/array/string.ts +0 -29
- package/assembly/deserialize/array.ts +0 -46
- package/assembly/deserialize/bool.ts +0 -34
- package/assembly/deserialize/date.ts +0 -19
- package/assembly/deserialize/float.ts +0 -21
- package/assembly/deserialize/integer.ts +0 -16
- package/assembly/deserialize/map.ts +0 -139
- package/assembly/deserialize/object.ts +0 -211
- package/assembly/deserialize/string.ts +0 -149
- package/assembly/serialize/array.ts +0 -44
- package/assembly/serialize/bool.ts +0 -10
- package/assembly/serialize/date.ts +0 -4
- package/assembly/serialize/float.ts +0 -4
- package/assembly/serialize/integer.ts +0 -5
- package/assembly/serialize/map.ts +0 -24
- package/assembly/serialize/object.ts +0 -13
- package/assembly/serialize/string.ts +0 -284
package/transform/src/index.ts
CHANGED
|
@@ -1,321 +1,472 @@
|
|
|
1
|
-
import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, NodeKind, Expression, CommonFlags, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression } from "assemblyscript/dist/assemblyscript.js";
|
|
2
|
-
|
|
3
|
-
import { toString, isStdlib } from "visitor-as/dist/utils.js";
|
|
4
|
-
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
1
|
+
import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, NodeKind, Expression, CommonFlags, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, CallExpression, ImportStatement, NamespaceDeclaration, Node, Statement, Tokenizer, SourceKind, PropertyAccessExpression, Token, CommentHandler, ExpressionStatement, BinaryExpression, NamedTypeNode, Range, FEATURE_SIMD, FunctionExpression } from "assemblyscript/dist/assemblyscript.js";
|
|
5
2
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
import { Visitor } from "./visitor.js";
|
|
4
|
+
import { SimpleParser, toString } from "./util.js";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { Property, PropertyFlags, Schema } from "./types.js";
|
|
8
|
+
import { getClasses, getImportedClass } from "./linker.js";
|
|
9
|
+
|
|
10
|
+
let indent = " ";
|
|
11
|
+
|
|
12
|
+
class JSONTransform extends Visitor {
|
|
13
|
+
public parser!: Parser;
|
|
14
|
+
public schemas: Schema[] = [];
|
|
15
|
+
public schema!: Schema;
|
|
10
16
|
public sources = new Set<Source>();
|
|
17
|
+
public imports: ImportStatement[] = [];
|
|
18
|
+
|
|
19
|
+
public jsonImport: string | null = null;
|
|
20
|
+
public bsImport: string | null = null;
|
|
21
|
+
public newStmts: {
|
|
22
|
+
simd: string[];
|
|
23
|
+
} = { simd: [] };
|
|
11
24
|
|
|
12
|
-
visitMethodDeclaration(): void {}
|
|
13
25
|
visitClassDeclaration(node: ClassDeclaration): void {
|
|
14
26
|
if (!node.decorators?.length) return;
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
if (!found) return;
|
|
28
|
+
if (
|
|
29
|
+
!node.decorators.some((decorator) => {
|
|
30
|
+
const name = (<IdentifierExpression>decorator.name).text;
|
|
31
|
+
return name === "json" || name === "serializable";
|
|
32
|
+
})
|
|
33
|
+
)
|
|
34
|
+
return;
|
|
25
35
|
|
|
26
|
-
|
|
27
|
-
schema.node = node;
|
|
28
|
-
schema.name = node.name.text;
|
|
36
|
+
this.schema = new Schema();
|
|
37
|
+
this.schema.node = node;
|
|
38
|
+
this.schema.name = node.name.text;
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
this.schemas.push(this.schema);
|
|
41
|
+
if (process.env["JSON_DEBUG"]) console.log("Created schema: " + this.schema.name);
|
|
42
|
+
|
|
43
|
+
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[])];
|
|
31
44
|
|
|
32
45
|
if (node.extendsType) {
|
|
33
|
-
|
|
46
|
+
const extendsName = node.extendsType?.name.identifier.text;
|
|
47
|
+
this.schema.parent = this.schemas.find((v) => v.name == extendsName) as Schema | null;
|
|
48
|
+
if (!this.schema.parent) {
|
|
49
|
+
const internalSearch = getClasses(node.range.source).find((v) => v.name.text == extendsName);
|
|
50
|
+
if (internalSearch) {
|
|
51
|
+
if (process.env["JSON_DEBUG"]) console.log("Found " + extendsName + " internally");
|
|
52
|
+
this.visitClassDeclaration(internalSearch);
|
|
53
|
+
this.visitClassDeclaration(node);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
34
56
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
57
|
+
const externalSearch = getImportedClass(extendsName, node.range.source, this.parser);
|
|
58
|
+
if (externalSearch) {
|
|
59
|
+
if (process.env["JSON_DEBUG"]) console.log("Found " + extendsName + " externally");
|
|
60
|
+
this.visitClassDeclaration(externalSearch);
|
|
61
|
+
this.visitClassDeclaration(node);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (this.schema.parent?.members) {
|
|
66
|
+
for (let i = this.schema.parent.members.length - 1; i >= 0; i--) {
|
|
67
|
+
const replace = this.schema.members.find((v) => v.name == this.schema.parent?.members[i]?.name);
|
|
38
68
|
if (!replace) {
|
|
39
|
-
members.unshift(schema.parent?.members[i]!.node);
|
|
69
|
+
members.unshift(this.schema.parent?.members[i]!.node);
|
|
40
70
|
}
|
|
41
71
|
}
|
|
42
72
|
}
|
|
43
73
|
}
|
|
44
74
|
|
|
45
75
|
if (!members.length) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}";
|
|
50
|
-
|
|
51
|
-
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}";
|
|
52
|
-
|
|
53
|
-
if (process.env["JSON_DEBUG"]) {
|
|
54
|
-
console.log(SERIALIZE_RAW_EMPTY);
|
|
55
|
-
//console.log(SERIALIZE_PRETTY_EMPTY);
|
|
56
|
-
console.log(INITIALIZE_EMPTY);
|
|
57
|
-
console.log(DESERIALIZE_EMPTY);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
|
|
61
|
-
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
62
|
-
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
|
|
63
|
-
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
|
|
64
|
-
|
|
65
|
-
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
|
|
66
|
-
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY);
|
|
67
|
-
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY);
|
|
68
|
-
|
|
69
|
-
this.schemasList.push(schema);
|
|
76
|
+
this.generateEmptyMethods(node);
|
|
77
|
+
return;
|
|
70
78
|
}
|
|
71
79
|
|
|
80
|
+
this.addRequiredImports(node);
|
|
81
|
+
|
|
72
82
|
for (const member of members) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (!member.type) {
|
|
76
|
-
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath);
|
|
77
|
-
}
|
|
83
|
+
if (!member.type) throwError("Fields must be strongly typed", node.range);
|
|
84
|
+
|
|
78
85
|
const type = toString(member.type!);
|
|
79
|
-
|
|
86
|
+
const name = member.name;
|
|
80
87
|
const value = member.initializer ? toString(member.initializer!) : null;
|
|
81
88
|
|
|
82
|
-
if (
|
|
83
|
-
if (member.flags === CommonFlags.Private) continue;
|
|
84
|
-
if (member.flags === CommonFlags.Protected) continue;
|
|
85
|
-
if (member.decorators && node.decorators.some((v) => (v.name as IdentifierExpression).text == "omit")) continue;
|
|
89
|
+
if (type.startsWith("(") && type.includes("=>")) continue;
|
|
86
90
|
|
|
87
91
|
const mem = new Property();
|
|
88
92
|
mem.name = name.text;
|
|
89
93
|
mem.type = type;
|
|
90
94
|
mem.value = value;
|
|
91
95
|
mem.node = member;
|
|
96
|
+
mem.byteSize = sizeof(mem.type);
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
mem.flags.set(PropertyFlags.JSON_Raw, []);
|
|
95
|
-
}
|
|
98
|
+
this.schema.byteSize += mem.byteSize;
|
|
96
99
|
|
|
97
|
-
if (
|
|
98
|
-
mem.flags.set(PropertyFlags.Null, []);
|
|
99
|
-
}
|
|
100
|
+
if (type.includes("JSON.Raw")) mem.flags.set(PropertyFlags.Raw, null);
|
|
100
101
|
|
|
101
102
|
if (member.decorators) {
|
|
102
103
|
for (const decorator of member.decorators) {
|
|
103
|
-
const decoratorName = (decorator.name as IdentifierExpression).text;
|
|
104
|
-
|
|
105
|
-
const args = getArgs(decorator.args);
|
|
106
|
-
|
|
104
|
+
const decoratorName = (decorator.name as IdentifierExpression).text.toLowerCase().trim();
|
|
107
105
|
switch (decoratorName) {
|
|
108
106
|
case "alias": {
|
|
109
|
-
|
|
107
|
+
const args = getArgs(decorator.args);
|
|
108
|
+
if (!args.length) throwError("@alias must have an argument of type string or number", member.range);
|
|
110
109
|
mem.alias = args[0]!;
|
|
111
|
-
mem.flags.set(PropertyFlags.Alias, args);
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
case "omit": {
|
|
115
|
-
mem.flags.set(PropertyFlags.Omit, args);
|
|
116
110
|
break;
|
|
117
111
|
}
|
|
118
112
|
case "omitif": {
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
let arg = decorator.args[0];
|
|
114
|
+
if (!decorator.args?.length) throwError("@omitif must have an argument or callback that resolves to type bool", member.range);
|
|
115
|
+
mem.flags.set(PropertyFlags.OmitIf, arg);
|
|
116
|
+
this.schema.static = false;
|
|
121
117
|
break;
|
|
122
118
|
}
|
|
123
119
|
case "omitnull": {
|
|
124
|
-
|
|
120
|
+
if (isPrimitive(type)) {
|
|
121
|
+
throwError("@omitnull cannot be used on primitive types!", member.range);
|
|
122
|
+
} else if (!member.type.isNullable) {
|
|
123
|
+
throwError("@omitnull cannot be used on non-nullable types!", member.range);
|
|
124
|
+
}
|
|
125
|
+
mem.flags.set(PropertyFlags.OmitNull, null);
|
|
126
|
+
this.schema.static = false;
|
|
125
127
|
break;
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (this.schemasList.find((v) => v.name == type)) {
|
|
134
|
-
mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()";
|
|
135
|
-
} else if (mem.value) {
|
|
136
|
-
mem.initialize = "this." + name.text + " = " + mem.value;
|
|
137
|
-
} else if (type === "Map") {
|
|
138
|
-
mem.initialize = "this." + name.text + " = new " + mem.type + "()";
|
|
139
|
-
} else if (type === "string") {
|
|
140
|
-
mem.initialize = "this." + name.text + ' = ""';
|
|
141
|
-
} else if (type === "Array") {
|
|
142
|
-
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()";
|
|
143
|
-
} else if (type === "bool" || type === "boolean") {
|
|
144
|
-
mem.initialize = "this." + name.text + " = false";
|
|
145
|
-
} else if (type === "JSON.Raw") {
|
|
146
|
-
mem.initialize = "this." + name.text + ' = ""';
|
|
147
|
-
} else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") {
|
|
148
|
-
mem.initialize = "this." + name.text + " = 0";
|
|
149
|
-
} else if (type === "f32" || type === "f64") {
|
|
150
|
-
mem.initialize = "this." + name.text + " = 0.0";
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
schema.members.push(mem);
|
|
133
|
+
this.schema.members.push(mem);
|
|
154
134
|
}
|
|
155
135
|
|
|
156
|
-
|
|
157
|
-
let SERIALIZE_PRETTY = "__SERIALIZE_PRETTY(): string {\n let out = `{";
|
|
136
|
+
if (!this.schema.static) this.schema.members = sortMembers(this.schema.members);
|
|
158
137
|
|
|
159
|
-
let
|
|
138
|
+
let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
|
|
139
|
+
let INITIALIZE = "@inline __INITIALIZE(): this {\n";
|
|
140
|
+
let DESERIALIZE = "__DESERIALIZE(keyStart: usize, keyEnd: usize, valStart: usize, valEnd: usize, ptr: usize): void {\n switch (keyEnd - keyStart) {\n";
|
|
141
|
+
let ALLOCATE = "@inline __ALLOCATE(): void {\n";
|
|
160
142
|
|
|
161
|
-
|
|
162
|
-
let indent = " ";
|
|
143
|
+
indent = " ";
|
|
163
144
|
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
} else {
|
|
172
|
-
SERIALIZE_RAW += schema.members[0]?.serialize + ",";
|
|
173
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
|
|
174
|
-
found = true;
|
|
145
|
+
if (this.schema.static == false) {
|
|
146
|
+
if (this.schema.members.some((v) => v.flags.has(PropertyFlags.OmitNull))) {
|
|
147
|
+
SERIALIZE += indent + "let block: usize = 0;\n";
|
|
148
|
+
}
|
|
149
|
+
this.schema.byteSize += 2;
|
|
150
|
+
SERIALIZE += indent + "store<u16>(bs.offset, 123, 0); // {\n";
|
|
151
|
+
SERIALIZE += indent + "bs.offset += 2;\n";
|
|
175
152
|
}
|
|
176
153
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
154
|
+
let isPure = this.schema.static;
|
|
155
|
+
let isRegular = isPure;
|
|
156
|
+
let isFirst = true;
|
|
157
|
+
|
|
158
|
+
for (let i = 0; i < this.schema.members.length; i++) {
|
|
159
|
+
const member = this.schema.members[i];
|
|
160
|
+
const aliasName = JSON.stringify(member.alias || member.name);
|
|
161
|
+
const realName = member.name;
|
|
162
|
+
const isLast = i == this.schema.members.length - 1;
|
|
163
|
+
const nonNullType = member.type.replace(" | null", "");
|
|
164
|
+
|
|
165
|
+
if (member.value) {
|
|
166
|
+
INITIALIZE += ` this.${member.name} = ${member.value};\n`;
|
|
167
|
+
} else if (this.schemas.find((v) => nonNullType == v.name)) {
|
|
168
|
+
INITIALIZE += ` this.${member.name} = changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())).__INITIALIZE();\n`;
|
|
169
|
+
} else if (member.type.startsWith("Array<") || member.type.startsWith("Map<")) {
|
|
170
|
+
INITIALIZE += ` this.${member.name} = [];\n`;
|
|
171
|
+
} else if (member.type == "string" || member.type == "String" || member.type == "JSON.Raw") {
|
|
172
|
+
INITIALIZE += ` this.${member.name} = "";\n`;
|
|
189
173
|
}
|
|
190
|
-
}
|
|
191
174
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
175
|
+
if (!isRegular && !member.flags.has(PropertyFlags.OmitIf) && !member.flags.has(PropertyFlags.OmitNull)) isRegular = true;
|
|
176
|
+
if (isRegular && isPure) {
|
|
177
|
+
const keyPart = (isFirst ? "{" : ",") + aliasName + ":";
|
|
178
|
+
this.schema.byteSize += keyPart.length << 1;
|
|
179
|
+
SERIALIZE += this.getStores(keyPart)
|
|
180
|
+
.map((v) => indent + v + "\n")
|
|
181
|
+
.join("");
|
|
182
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
183
|
+
if (isFirst) isFirst = false;
|
|
184
|
+
} else if (isRegular && !isPure) {
|
|
185
|
+
const keyPart = (isFirst ? "" : ",") + aliasName + ":";
|
|
186
|
+
this.schema.byteSize += keyPart.length << 1;
|
|
187
|
+
SERIALIZE += this.getStores(keyPart)
|
|
188
|
+
.map((v) => indent + v + "\n")
|
|
189
|
+
.join("");
|
|
190
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
191
|
+
if (isFirst) isFirst = false;
|
|
192
|
+
} else {
|
|
193
|
+
if (member.flags.has(PropertyFlags.OmitNull)) {
|
|
194
|
+
SERIALIZE += indent + `if ((block = load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))) !== 0) {\n`;
|
|
195
|
+
indentInc();
|
|
196
|
+
const keyPart = aliasName + ":";
|
|
197
|
+
this.schema.byteSize += keyPart.length << 1;
|
|
198
|
+
SERIALIZE += this.getStores(keyPart)
|
|
199
|
+
.map((v) => indent + v + "\n")
|
|
200
|
+
.join("");
|
|
201
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
202
|
+
|
|
203
|
+
if (!isLast) {
|
|
204
|
+
this.schema.byteSize += 2;
|
|
205
|
+
SERIALIZE += indent + `store<u16>(bs.offset, 44, 0); // ,\n`;
|
|
206
|
+
SERIALIZE += indent + `bs.offset += 2;\n`;
|
|
207
|
+
}
|
|
199
208
|
|
|
200
|
-
|
|
209
|
+
indentDec();
|
|
210
|
+
this.schema.byteSize += 2;
|
|
211
|
+
SERIALIZE += indent + `}\n`;
|
|
212
|
+
} else if (member.flags.has(PropertyFlags.OmitIf)) {
|
|
213
|
+
if (member.flags.get(PropertyFlags.OmitIf).kind == NodeKind.Function) {
|
|
214
|
+
const arg = member.flags.get(PropertyFlags.OmitIf) as FunctionExpression;
|
|
215
|
+
// @ts-ignore: type
|
|
216
|
+
arg.declaration.signature.returnType.name = Node.createSimpleTypeName("boolean", arg.declaration.signature.returnType.name.range);
|
|
217
|
+
SERIALIZE += indent + `if ((${toString(member.flags.get(PropertyFlags.OmitIf))})(this)) {\n`;
|
|
218
|
+
} else {
|
|
219
|
+
SERIALIZE += indent + `if (${toString(member.flags.get(PropertyFlags.OmitIf))}) {\n`;
|
|
220
|
+
}
|
|
221
|
+
indentInc();
|
|
222
|
+
SERIALIZE += this.getStores(aliasName + ":")
|
|
223
|
+
.map((v) => indent + v + "\n")
|
|
224
|
+
.join("");
|
|
225
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
226
|
+
|
|
227
|
+
if (!isLast) {
|
|
228
|
+
this.schema.byteSize += 2;
|
|
229
|
+
SERIALIZE += indent + `store<u16>(bs.offset, 44, 0); // ,\n`;
|
|
230
|
+
SERIALIZE += indent + `bs.offset += 2;\n`;
|
|
231
|
+
}
|
|
201
232
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
let offset = -1;
|
|
206
|
-
for (let i = 0; i < _sorted.length; i++) {
|
|
207
|
-
const member = _sorted[i]!;
|
|
208
|
-
const _name = member.alias || member.name;
|
|
209
|
-
if (_name.length === len) {
|
|
210
|
-
sortedMembers[offset]?.push(member);
|
|
211
|
-
} else {
|
|
212
|
-
sortedMembers.push([member]);
|
|
213
|
-
len = _name.length;
|
|
214
|
-
offset++;
|
|
233
|
+
indentDec();
|
|
234
|
+
SERIALIZE += indent + `}\n`;
|
|
235
|
+
}
|
|
215
236
|
}
|
|
216
237
|
}
|
|
217
238
|
|
|
218
|
-
let
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
} else if (_name.length === 2) {
|
|
230
|
-
if (first) {
|
|
231
|
-
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
232
|
-
first = false;
|
|
233
|
-
} else {
|
|
234
|
-
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n";
|
|
235
|
-
}
|
|
236
|
-
} else if (_name.length === 4) {
|
|
237
|
-
if (first) {
|
|
238
|
-
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n";
|
|
239
|
-
first = false;
|
|
239
|
+
let sortedMembers: Property[][] = [];
|
|
240
|
+
|
|
241
|
+
let len = -1;
|
|
242
|
+
this.schema.members
|
|
243
|
+
.slice()
|
|
244
|
+
.sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length))
|
|
245
|
+
.forEach((member) => {
|
|
246
|
+
const _nameLength = member.alias?.length || member.name.length;
|
|
247
|
+
if (_nameLength === len) {
|
|
248
|
+
sortedMembers[sortedMembers.length - 1].push(member);
|
|
240
249
|
} else {
|
|
241
|
-
|
|
250
|
+
sortedMembers.push([member]);
|
|
251
|
+
len = _nameLength;
|
|
242
252
|
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
sortedMembers = sortedMembers.sort((a, b) => b.length - a.length);
|
|
256
|
+
|
|
257
|
+
indentInc();
|
|
258
|
+
for (const memberGroup of sortedMembers) {
|
|
259
|
+
const memberLen = (memberGroup[0].alias || memberGroup[0].name).length << 1;
|
|
260
|
+
DESERIALIZE += `${indent}case ${memberLen}: {\n`;
|
|
261
|
+
indentInc();
|
|
262
|
+
if (memberLen == 2) DESERIALIZE += `${indent}switch (load<u16>(keyStart)) {\n`;
|
|
263
|
+
else if (memberLen == 4) DESERIALIZE += `${indent}switch (load<u32>(keyStart)) {\n`;
|
|
264
|
+
else if (memberLen == 6) DESERIALIZE += `${indent}let code = (<u64>load<u32>(keyStart) << 16) | <u64>load<u16>(keyStart, 4);\n`;
|
|
265
|
+
else DESERIALIZE += toMemCDecl(memberLen, indent);
|
|
266
|
+
for (let i = 0; i < memberGroup.length; i++) {
|
|
267
|
+
const member = memberGroup[i];
|
|
268
|
+
const memberName = member.alias || member.name;
|
|
269
|
+
if (memberLen == 2) {
|
|
270
|
+
DESERIALIZE += `${indent} case ${memberName.charCodeAt(0)}: { // ${memberName}\n`;
|
|
271
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
272
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
273
|
+
DESERIALIZE += `${indent} }\n`;
|
|
274
|
+
} else if (memberLen == 4) {
|
|
275
|
+
DESERIALIZE += `${indent} case ${toU32(memberName)}: { // ${memberName}\n`;
|
|
276
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
277
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
278
|
+
DESERIALIZE += `${indent} }\n`;
|
|
279
|
+
} else if (memberLen == 6) {
|
|
280
|
+
DESERIALIZE += i == 0 ? indent : "";
|
|
281
|
+
DESERIALIZE += `if (code == ${toU48(memberName)}) { // ${memberName}\n`;
|
|
282
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
283
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
284
|
+
DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
|
|
247
285
|
} else {
|
|
248
|
-
DESERIALIZE +=
|
|
286
|
+
DESERIALIZE += i == 0 ? indent : "";
|
|
287
|
+
DESERIALIZE += `if (${toMemCCheck(memberName)}) { // ${memberName}\n`;
|
|
288
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
289
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
290
|
+
DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
|
|
249
291
|
}
|
|
250
292
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const member = memberSet[i]!;
|
|
254
|
-
if (!member.deserialize) continue;
|
|
255
|
-
const _name = encodeKey(member.alias || member.name);
|
|
256
|
-
if (_name.length === 1) {
|
|
257
|
-
DESERIALIZE += ` case ${_name.charCodeAt(0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
258
|
-
} else if (_name.length === 2) {
|
|
259
|
-
DESERIALIZE += ` case ${charCodeAt32(_name, 0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
260
|
-
} else if (_name.length === 4) {
|
|
261
|
-
if (f) {
|
|
262
|
-
f = false;
|
|
263
|
-
DESERIALIZE += ` if (${charCodeAt64(_name, 0)} === code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
264
|
-
} else {
|
|
265
|
-
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`;
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
if (f) {
|
|
269
|
-
f = false;
|
|
270
|
-
DESERIALIZE += ` if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
271
|
-
} else {
|
|
272
|
-
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
293
|
+
if (memberLen < 6) {
|
|
294
|
+
DESERIALIZE += `${indent}}\n`; // Close switch
|
|
275
295
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
|
|
280
|
-
} else {
|
|
281
|
-
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`;
|
|
282
|
-
}
|
|
283
|
-
DESERIALIZE += " } ";
|
|
296
|
+
indentDec();
|
|
297
|
+
DESERIALIZE += `${indent} return;\n`; // Break switch
|
|
298
|
+
DESERIALIZE += `${indent}}\n`; // Close length switch
|
|
284
299
|
}
|
|
285
300
|
|
|
286
|
-
|
|
301
|
+
indentDec();
|
|
302
|
+
DESERIALIZE += `${indent}}\n`; // Close length switch
|
|
303
|
+
indentDec();
|
|
304
|
+
DESERIALIZE += `${indent}}\n`; // Close function
|
|
305
|
+
|
|
306
|
+
indent = " ";
|
|
287
307
|
|
|
288
|
-
|
|
308
|
+
this.schema.byteSize += 2;
|
|
309
|
+
SERIALIZE += indent + "store<u16>(bs.offset, 125, 0); // }\n";
|
|
310
|
+
SERIALIZE += indent + "bs.offset += 2;\n";
|
|
311
|
+
SERIALIZE += "}";
|
|
312
|
+
|
|
313
|
+
ALLOCATE += indent + "bs.ensureSize(" + this.schema.byteSize + ");\n";
|
|
314
|
+
ALLOCATE += "}";
|
|
315
|
+
|
|
316
|
+
INITIALIZE += " return this;\n";
|
|
317
|
+
INITIALIZE += "}";
|
|
289
318
|
|
|
290
319
|
if (process.env["JSON_DEBUG"]) {
|
|
291
|
-
console.log(
|
|
292
|
-
//console.log(SERIALIZE_PRETTY);
|
|
320
|
+
console.log(SERIALIZE);
|
|
293
321
|
console.log(INITIALIZE);
|
|
294
322
|
console.log(DESERIALIZE);
|
|
323
|
+
console.log(ALLOCATE);
|
|
295
324
|
}
|
|
296
325
|
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
const DESERIALIZE_SAFE = DESERIALIZE.replaceAll("__DESERIALIZE", "__DESERIALIZE_SAFE");
|
|
300
|
-
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
326
|
+
const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE, node);
|
|
301
327
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
302
328
|
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
303
|
-
const
|
|
329
|
+
const ALLOCATE_METHOD = SimpleParser.parseClassMember(ALLOCATE, node);
|
|
304
330
|
|
|
305
|
-
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(
|
|
331
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_METHOD);
|
|
306
332
|
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD);
|
|
307
333
|
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD);
|
|
308
|
-
if (!node.members.find((v) => v.name.text == "
|
|
334
|
+
if (!node.members.find((v) => v.name.text == "__ALLOCATE")) node.members.push(ALLOCATE_METHOD);
|
|
335
|
+
super.visitClassDeclaration(node);
|
|
336
|
+
}
|
|
337
|
+
generateEmptyMethods(node: ClassDeclaration): void {
|
|
338
|
+
let SERIALIZE_RAW_EMPTY = '@inline __SERIALIZE(ptr: usize = changetype<usize>(this)): string {\n return "{}";\n}';
|
|
339
|
+
let SERIALIZE_BS_EMPTY = "@inline __SERIALIZE(ptr: usize: bool): void {\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
|
|
340
|
+
let INITIALIZE_EMPTY = "@inline __INITIALIZE(): this {\n return this;\n}";
|
|
341
|
+
let DESERIALIZE_EMPTY = "@inline __DESERIALIZE(keyStart: usize, keyEnd: usize, valStart: usize, valEnd: usize, ptr: usize): void {\n return false;\n}";
|
|
342
|
+
let ALLOCATE_EMPTY = "@inline __ALLOCATE(): void {\n bs.ensureSize(4);\n}";
|
|
309
343
|
|
|
310
|
-
|
|
344
|
+
if (process.env["JSON_DEBUG"]) {
|
|
345
|
+
console.log(SERIALIZE_RAW_EMPTY);
|
|
346
|
+
console.log(SERIALIZE_BS_EMPTY);
|
|
347
|
+
console.log(INITIALIZE_EMPTY);
|
|
348
|
+
console.log(DESERIALIZE_EMPTY);
|
|
349
|
+
console.log(ALLOCATE_EMPTY);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
|
|
353
|
+
const SERIALIZE_BS_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_BS_EMPTY, node);
|
|
354
|
+
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
|
|
355
|
+
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
|
|
356
|
+
const ALLOCATE_METHOD_EMPTY = SimpleParser.parseClassMember(ALLOCATE_EMPTY, node);
|
|
357
|
+
|
|
358
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
|
|
359
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_BS_METHOD_EMPTY);
|
|
360
|
+
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY);
|
|
361
|
+
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY);
|
|
362
|
+
if (!node.members.find((v) => v.name.text == "__ALLOCATE")) node.members.push(ALLOCATE_METHOD_EMPTY);
|
|
363
|
+
}
|
|
364
|
+
// visitCallExpression(node: CallExpression, ref: Node): void {
|
|
365
|
+
// super.visitCallExpression(node, ref);
|
|
366
|
+
// if (!(node.expression.kind == NodeKind.PropertyAccess && (node.expression as PropertyAccessExpression).property.text == "stringifyTo") && !(node.expression.kind == NodeKind.Identifier && (node.expression as IdentifierExpression).text == "stringifyTo")) return;
|
|
367
|
+
|
|
368
|
+
// const source = node.range.source;
|
|
369
|
+
|
|
370
|
+
// if (ref.kind == NodeKind.Call) {
|
|
371
|
+
// const newNode = Node.createBinaryExpression(Token.Equals, node.args[1], node, node.range);
|
|
372
|
+
|
|
373
|
+
// (<CallExpression>ref).args[(<CallExpression>ref).args.indexOf(node)] = newNode;
|
|
374
|
+
// } else {
|
|
375
|
+
// const newNode = Node.createExpressionStatement(Node.createBinaryExpression(Token.Equals, node.args[1], node, node.range));
|
|
376
|
+
|
|
377
|
+
// const nodeIndex = source.statements.findIndex((n: Node) => {
|
|
378
|
+
// if (n == node) return true;
|
|
379
|
+
// if (n.kind == NodeKind.Expression && (<ExpressionStatement>n).expression == node) return true;
|
|
380
|
+
// return false;
|
|
381
|
+
// });
|
|
382
|
+
|
|
383
|
+
// if (nodeIndex > 0) source.statements[nodeIndex] = newNode;
|
|
384
|
+
// }
|
|
385
|
+
// }
|
|
386
|
+
// visitBinaryExpression(node: BinaryExpression, ref?: Node | null): void {
|
|
387
|
+
// // if (node.right.kind == NodeKind.Call && (<CallExpression>node).)
|
|
388
|
+
// }
|
|
389
|
+
visitImportStatement(node: ImportStatement): void {
|
|
390
|
+
super.visitImportStatement(node);
|
|
391
|
+
const source = this.parser.sources.find((src) => src.internalPath == node.internalPath);
|
|
392
|
+
if (!source) return;
|
|
393
|
+
|
|
394
|
+
if (source.statements.some((stmt) => stmt.kind === NodeKind.NamespaceDeclaration && (stmt as NamespaceDeclaration).name.text === "JSON")) this.imports.push(node);
|
|
311
395
|
}
|
|
312
396
|
visitSource(node: Source): void {
|
|
397
|
+
this.imports = [];
|
|
313
398
|
super.visitSource(node);
|
|
399
|
+
}
|
|
400
|
+
addRequiredImports(node: ClassDeclaration): void {
|
|
401
|
+
// if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "bs"))) {
|
|
402
|
+
// if (!this.bsImport) {
|
|
403
|
+
// this.bsImport = 'import { bs } from "as-bs"';
|
|
404
|
+
// if (process.env["JSON_DEBUG"]) console.log("Added as-bs import: " + this.bsImport + "\n");
|
|
405
|
+
// }
|
|
406
|
+
// }
|
|
407
|
+
if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "bs"))) {
|
|
408
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
409
|
+
const __dirname = path.dirname(__filename);
|
|
410
|
+
|
|
411
|
+
let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../modules/bs/index.ts"));
|
|
412
|
+
|
|
413
|
+
if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) relativePath = "./" + relativePath;
|
|
414
|
+
// if (!existsSync(relativePath)) {
|
|
415
|
+
// throw new Error("Could not find a valid json-as library to import from! Please add import { JSON } from \"path-to-json-as\"; in " + node.range.source.normalizedPath + "!");
|
|
416
|
+
// }
|
|
417
|
+
|
|
418
|
+
const txt = `import { bs } from "${relativePath}";`;
|
|
419
|
+
if (!this.jsonImport) {
|
|
420
|
+
this.jsonImport = txt;
|
|
421
|
+
if (process.env["JSON_DEBUG"]) console.log("Added bs import: " + txt + "\n");
|
|
422
|
+
}
|
|
423
|
+
}
|
|
314
424
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
425
|
+
if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "JSON"))) {
|
|
426
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
427
|
+
const __dirname = path.dirname(__filename);
|
|
428
|
+
|
|
429
|
+
let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../assembly/index.ts"));
|
|
430
|
+
|
|
431
|
+
if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) relativePath = "./" + relativePath;
|
|
432
|
+
// if (!existsSync(relativePath)) {
|
|
433
|
+
// throw new Error("Could not find a valid json-as library to import from! Please add import { JSON } from \"path-to-json-as\"; in " + node.range.source.normalizedPath + "!");
|
|
434
|
+
// }
|
|
435
|
+
|
|
436
|
+
const txt = `import { JSON } from "${relativePath}";`;
|
|
437
|
+
if (!this.jsonImport) {
|
|
438
|
+
this.jsonImport = txt;
|
|
439
|
+
if (process.env["JSON_DEBUG"]) console.log("Added json-as import: " + txt + "\n");
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
getStores(data: string, simd: boolean = true): string[] {
|
|
445
|
+
const out: string[] = [];
|
|
446
|
+
const sizes = strToNum(data, simd);
|
|
447
|
+
let offset = 0;
|
|
448
|
+
for (const [size, num] of sizes) {
|
|
449
|
+
if (size == "v128") {
|
|
450
|
+
// This could be put in its own file
|
|
451
|
+
let index = this.newStmts.simd.findIndex((v) => v.includes(num));
|
|
452
|
+
let name = "SIMD_" + (index == -1 ? this.newStmts.simd.length : index);
|
|
453
|
+
if (index && !this.newStmts.simd.includes(`const ${name} = ${num};`)) this.newStmts.simd.push(`const ${name} = ${num};`);
|
|
454
|
+
out.push("store<v128>(bs.offset, " + name + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 8));
|
|
455
|
+
offset += 16;
|
|
456
|
+
}
|
|
457
|
+
if (size == "u64") {
|
|
458
|
+
out.push("store<u64>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 4));
|
|
459
|
+
offset += 8;
|
|
460
|
+
} else if (size == "u32") {
|
|
461
|
+
out.push("store<u32>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 2));
|
|
462
|
+
offset += 4;
|
|
463
|
+
} else if (size == "u16") {
|
|
464
|
+
out.push("store<u16>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 1));
|
|
465
|
+
offset += 2;
|
|
466
|
+
}
|
|
318
467
|
}
|
|
468
|
+
out.push("bs.offset += " + offset + ";");
|
|
469
|
+
return out;
|
|
319
470
|
}
|
|
320
471
|
}
|
|
321
472
|
|
|
@@ -326,159 +477,231 @@ export default class Transformer extends Transform {
|
|
|
326
477
|
const transformer = new JSONTransform();
|
|
327
478
|
|
|
328
479
|
// Sort the sources so that user scripts are visited last
|
|
329
|
-
const sources = parser.sources
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
});
|
|
480
|
+
const sources = parser.sources.sort((_a, _b) => {
|
|
481
|
+
const a = _a.internalPath;
|
|
482
|
+
const b = _b.internalPath;
|
|
483
|
+
if (a[0] == "~" && b[0] !== "~") {
|
|
484
|
+
return -1;
|
|
485
|
+
} else if (a[0] !== "~" && b[0] == "~") {
|
|
486
|
+
return 1;
|
|
487
|
+
} else {
|
|
488
|
+
return 0;
|
|
489
|
+
}
|
|
490
|
+
});
|
|
342
491
|
|
|
492
|
+
transformer.parser = parser;
|
|
343
493
|
// Loop over every source
|
|
344
494
|
for (const source of sources) {
|
|
495
|
+
transformer.imports = [];
|
|
496
|
+
transformer.currentSource = source;
|
|
345
497
|
// Ignore all lib and std. Visit everything else.
|
|
346
|
-
|
|
347
|
-
|
|
498
|
+
transformer.visit(source);
|
|
499
|
+
|
|
500
|
+
if (transformer.newStmts.simd) {
|
|
501
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.newStmts.simd.join("\n")));
|
|
502
|
+
parser.currentSource = tokenizer.source;
|
|
503
|
+
for (let i = 0; i < transformer.newStmts.simd.length; i++) source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!);
|
|
504
|
+
parser.currentSource = source;
|
|
505
|
+
transformer.newStmts.simd = [];
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (transformer.jsonImport) {
|
|
509
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.jsonImport));
|
|
510
|
+
parser.currentSource = tokenizer.source;
|
|
511
|
+
source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!);
|
|
512
|
+
parser.currentSource = source;
|
|
513
|
+
transformer.jsonImport = null;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (transformer.bsImport) {
|
|
517
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.bsImport));
|
|
518
|
+
parser.currentSource = tokenizer.source;
|
|
519
|
+
source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!);
|
|
520
|
+
parser.currentSource = source;
|
|
521
|
+
transformer.bsImport = null;
|
|
348
522
|
}
|
|
349
523
|
}
|
|
350
524
|
// Check that every parent and child class is hooked up correctly
|
|
351
|
-
const schemas = transformer.
|
|
525
|
+
const schemas = transformer.schemas;
|
|
352
526
|
for (const schema of schemas) {
|
|
353
527
|
if (schema.parent) {
|
|
354
|
-
const parent = schemas.find((v) => v.name
|
|
355
|
-
if (!parent)
|
|
528
|
+
const parent = schemas.find((v) => v.name == schema.parent?.name);
|
|
529
|
+
if (!parent) throwError(`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator!`, schema.parent.node.range);
|
|
356
530
|
}
|
|
357
531
|
}
|
|
358
532
|
}
|
|
359
533
|
}
|
|
360
534
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
535
|
+
function sortMembers(members: Property[]): Property[] {
|
|
536
|
+
return members.sort((a, b) => {
|
|
537
|
+
const aMove = a.flags.has(PropertyFlags.OmitIf) || a.flags.has(PropertyFlags.OmitNull);
|
|
538
|
+
const bMove = b.flags.has(PropertyFlags.OmitIf) || b.flags.has(PropertyFlags.OmitNull);
|
|
539
|
+
|
|
540
|
+
if (aMove && !bMove) {
|
|
541
|
+
return -1;
|
|
542
|
+
} else if (!aMove && bMove) {
|
|
543
|
+
return 1;
|
|
544
|
+
} else {
|
|
545
|
+
return 0;
|
|
546
|
+
}
|
|
547
|
+
});
|
|
368
548
|
}
|
|
369
549
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
550
|
+
function getArgs(args: Expression[] | null): string[] {
|
|
551
|
+
if (!args) return [];
|
|
552
|
+
let out: string[] = [];
|
|
553
|
+
for (const arg of args) {
|
|
554
|
+
if (arg instanceof StringLiteralExpression) {
|
|
555
|
+
out.push(arg.value);
|
|
556
|
+
} else if (arg instanceof IntegerLiteralExpression) {
|
|
557
|
+
out.push(i64_to_string(arg.value));
|
|
558
|
+
} else if (arg instanceof FloatLiteralExpression) {
|
|
559
|
+
out.push(arg.value.toString());
|
|
560
|
+
} else if (arg instanceof NullExpression) {
|
|
561
|
+
out.push(arg.text);
|
|
562
|
+
} else if (arg instanceof TrueExpression) {
|
|
563
|
+
out.push(arg.text);
|
|
564
|
+
} else if (arg instanceof FalseExpression) {
|
|
565
|
+
out.push(arg.text);
|
|
566
|
+
} else if (arg instanceof IdentifierExpression) {
|
|
567
|
+
out.push(arg.text);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return out;
|
|
571
|
+
}
|
|
376
572
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
573
|
+
function toU16(data: string, offset: number = 0): string {
|
|
574
|
+
return data.charCodeAt(offset + 0).toString();
|
|
575
|
+
}
|
|
380
576
|
|
|
381
|
-
|
|
577
|
+
function toU32(data: string, offset: number = 0): string {
|
|
578
|
+
return ((data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset + 0)).toString();
|
|
579
|
+
}
|
|
382
580
|
|
|
383
|
-
|
|
384
|
-
|
|
581
|
+
function toU48(data: string, offset: number = 0): string {
|
|
582
|
+
return ((BigInt(data.charCodeAt(offset + 2)) << 32n) | (BigInt(data.charCodeAt(offset + 1)) << 16n) | BigInt(data.charCodeAt(offset + 0))).toString();
|
|
583
|
+
}
|
|
385
584
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const type = this.type;
|
|
390
|
-
if (this.flags.has(PropertyFlags.Omit)) return;
|
|
585
|
+
function toU64(data: string, offset: number = 0): string {
|
|
586
|
+
return ((BigInt(data.charCodeAt(offset + 3)) << 48n) | (BigInt(data.charCodeAt(offset + 2)) << 32n) | (BigInt(data.charCodeAt(offset + 1)) << 16n) | BigInt(data.charCodeAt(offset + 0))).toString();
|
|
587
|
+
}
|
|
391
588
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")";
|
|
402
|
-
this.right_d = (safe ? "__DESERIALIZE_SAFE" : "__DESERIALIZE") + "<" + type + ">(data.substring(value_start, value_end))";
|
|
403
|
-
}
|
|
589
|
+
function toMemCDecl(n: number, indent: string): string {
|
|
590
|
+
let out = "";
|
|
591
|
+
let offset = 0;
|
|
592
|
+
let index = 0;
|
|
593
|
+
while (n >= 8) {
|
|
594
|
+
out += `${indent}const code${index++} = load<u64>(keyStart, ${offset});\n`;
|
|
595
|
+
offset += 8;
|
|
596
|
+
n -= 8;
|
|
597
|
+
}
|
|
404
598
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
410
|
-
} else if (this.flags.has(PropertyFlags.OmitNull)) {
|
|
411
|
-
this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}';
|
|
412
|
-
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
413
|
-
} else {
|
|
414
|
-
this.serialize = escapedName + ":${" + this.right_s + "}";
|
|
415
|
-
this.deserialize = "this." + name + " = " + this.right_d + ";";
|
|
416
|
-
}
|
|
599
|
+
while (n >= 4) {
|
|
600
|
+
out += `${indent}const code${index++} = load<u32>(keyStart, ${offset});\n`;
|
|
601
|
+
offset += 4;
|
|
602
|
+
n -= 4;
|
|
417
603
|
}
|
|
418
|
-
}
|
|
419
604
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
public parent: SchemaData | null = null;
|
|
424
|
-
public node!: ClassDeclaration;
|
|
605
|
+
if (n == 1) out += `${indent}const code${index++} = load<u16>(keyStart, ${offset});\n`;
|
|
606
|
+
|
|
607
|
+
return out;
|
|
425
608
|
}
|
|
426
609
|
|
|
427
|
-
function
|
|
428
|
-
|
|
610
|
+
function toMemCCheck(data: string): string {
|
|
611
|
+
let n = data.length << 1;
|
|
612
|
+
let out = "";
|
|
613
|
+
let offset = 0;
|
|
614
|
+
let index = 0;
|
|
615
|
+
while (n >= 8) {
|
|
616
|
+
out += ` && code${index++} == ${toU64(data, offset >> 1)}`;
|
|
617
|
+
offset += 8;
|
|
618
|
+
n -= 8;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
while (n >= 4) {
|
|
622
|
+
out += ` && code${index++} == ${toU32(data, offset >> 1)}`;
|
|
623
|
+
offset += 4;
|
|
624
|
+
n -= 4;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (n == 1) out += ` && code${index++} == ${toU16(data, offset >> 1)}`;
|
|
628
|
+
|
|
629
|
+
return out.slice(4);
|
|
429
630
|
}
|
|
430
631
|
|
|
431
|
-
function
|
|
432
|
-
|
|
433
|
-
|
|
632
|
+
function strToNum(data: string, simd: boolean = false, offset: number = 0): string[][] {
|
|
633
|
+
const out: string[][] = [];
|
|
634
|
+
let n = data.length;
|
|
635
|
+
|
|
636
|
+
while (n >= 8 && simd) {
|
|
637
|
+
out.push(["v128", "i16x8(" + data.charCodeAt(offset + 0) + ", " + data.charCodeAt(offset + 1) + ", " + data.charCodeAt(offset + 2) + ", " + data.charCodeAt(offset + 3) + ", " + data.charCodeAt(offset + 4) + ", " + data.charCodeAt(offset + 5) + ", " + data.charCodeAt(offset + 6) + ", " + data.charCodeAt(offset + 7) + ")"]);
|
|
638
|
+
|
|
639
|
+
offset += 8;
|
|
640
|
+
n -= 8;
|
|
434
641
|
}
|
|
435
642
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
643
|
+
while (n >= 4) {
|
|
644
|
+
const value = (BigInt(data.charCodeAt(offset + 3)) << 48n) | (BigInt(data.charCodeAt(offset + 2)) << 32n) | (BigInt(data.charCodeAt(offset + 1)) << 16n) | BigInt(data.charCodeAt(offset + 0));
|
|
645
|
+
out.push(["u64", value.toString()]);
|
|
646
|
+
offset += 4;
|
|
647
|
+
n -= 4;
|
|
648
|
+
}
|
|
440
649
|
|
|
441
|
-
|
|
650
|
+
while (n >= 2) {
|
|
651
|
+
const value = (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset + 0);
|
|
652
|
+
out.push(["u32", value.toString()]);
|
|
653
|
+
offset += 2;
|
|
654
|
+
n -= 2;
|
|
655
|
+
}
|
|
442
656
|
|
|
443
|
-
|
|
657
|
+
if (n === 1) {
|
|
658
|
+
const value = data.charCodeAt(offset + 0);
|
|
659
|
+
out.push(["u16", value.toString()]);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
return out;
|
|
444
663
|
}
|
|
445
664
|
|
|
446
|
-
function
|
|
447
|
-
const
|
|
448
|
-
return
|
|
665
|
+
function isPrimitive(type: string): boolean {
|
|
666
|
+
const primitiveTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64", "f32", "f64", "bool", "boolean"];
|
|
667
|
+
return primitiveTypes.some((v) => type.includes(v));
|
|
449
668
|
}
|
|
450
669
|
|
|
451
|
-
function
|
|
452
|
-
|
|
670
|
+
function throwError(message: string, range: Range): never {
|
|
671
|
+
const err = new Error();
|
|
672
|
+
err.stack = `${message}\n at ${range.source.normalizedPath}:${range.source.lineAt(range.start)}:${range.source.columnAt()}\n`;
|
|
673
|
+
throw err;
|
|
453
674
|
}
|
|
454
675
|
|
|
455
|
-
function
|
|
456
|
-
|
|
676
|
+
function indentInc(): void {
|
|
677
|
+
indent += " ";
|
|
457
678
|
}
|
|
458
679
|
|
|
459
|
-
function
|
|
460
|
-
|
|
680
|
+
function indentDec(): void {
|
|
681
|
+
indent = indent.slice(0, Math.max(0, indent.length - 2));
|
|
461
682
|
}
|
|
462
683
|
|
|
463
|
-
function
|
|
464
|
-
if (
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
684
|
+
function sizeof(type: string): number {
|
|
685
|
+
if (type == "u8")
|
|
686
|
+
return 6; // -127
|
|
687
|
+
else if (type == "i8")
|
|
688
|
+
return 8; // 255
|
|
689
|
+
else if (type == "u16")
|
|
690
|
+
return 10; // 65536
|
|
691
|
+
else if (type == "i16")
|
|
692
|
+
return 12; // -32767
|
|
693
|
+
else if (type == "u32")
|
|
694
|
+
return 20; // 4294967295
|
|
695
|
+
else if (type == "i32")
|
|
696
|
+
return 22; // -2147483647
|
|
697
|
+
else if (type == "u64")
|
|
698
|
+
return 40; // 18446744073709551615
|
|
699
|
+
else if (type == "i64")
|
|
700
|
+
return 40; // -9223372036854775807
|
|
701
|
+
else if (type == "bool" || type == "boolean") return 10;
|
|
702
|
+
else return 0;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function allPrimitive(schema: Schema): boolean {
|
|
706
|
+
return !schema.members.some((p) => p.byteSize == 0);
|
|
484
707
|
}
|