json-as 0.9.29 → 1.0.0-alpha.2
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/.gitmodules +0 -0
- package/.prettierrc.json +3 -2
- package/CHANGELOG +24 -0
- package/LICENSE +1 -1
- package/README.md +23 -7
- package/as-test.config.json +1 -1
- package/asconfig.json +2 -2
- package/assembly/__benches__/misc.bench.ts +0 -34
- 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 +158 -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 +261 -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 +36 -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/as-bs/LICENSE +21 -0
- package/modules/as-bs/README.md +95 -0
- package/modules/as-bs/assembly/index.ts +166 -0
- package/modules/as-bs/assembly/tsconfig.json +97 -0
- package/modules/as-bs/index.ts +1 -0
- package/modules/as-bs/package.json +32 -0
- package/package.json +41 -48
- package/transform/lib/builder.js +1275 -0
- package/transform/lib/builder.js.map +1 -0
- package/transform/lib/index.js +548 -443
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/linker.js +16 -0
- package/transform/lib/linker.js.map +1 -0
- package/transform/lib/types.js +26 -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 +510 -430
- package/transform/lib/visitor.js.map +1 -0
- package/transform/package.json +1 -33
- package/transform/src/builder.ts +1371 -0
- package/transform/src/index.ts +574 -340
- package/transform/src/linker.ts +21 -0
- package/transform/src/types.ts +28 -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,483 @@
|
|
|
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 (<u32>keyEnd - <u32>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
|
-
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) {
|
|
169
|
-
SERIALIZE_RAW += schema.members[0]?.serialize;
|
|
170
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize;
|
|
171
|
-
} else {
|
|
172
|
-
SERIALIZE_RAW += schema.members[0]?.serialize + ",";
|
|
173
|
-
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n";
|
|
174
|
-
found = true;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n";
|
|
178
|
-
|
|
179
|
-
for (let i = 1; i < schema.members.length; i++) {
|
|
180
|
-
const member = schema.members[i]!;
|
|
181
|
-
if (member.initialize) INITIALIZE += " " + member.initialize + ";\n";
|
|
182
|
-
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) {
|
|
183
|
-
SERIALIZE_RAW += member.serialize;
|
|
184
|
-
SERIALIZE_PRETTY += member.serialize;
|
|
185
|
-
} else {
|
|
186
|
-
SERIALIZE_RAW += member.serialize + ",";
|
|
187
|
-
SERIALIZE_PRETTY += indent + member.serialize + ",\\n";
|
|
188
|
-
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";
|
|
189
148
|
}
|
|
149
|
+
this.schema.byteSize += 2;
|
|
150
|
+
SERIALIZE += indent + "store<u16>(bs.offset, 123, 0); // {\n";
|
|
151
|
+
SERIALIZE += indent + "bs.offset += 2;\n";
|
|
190
152
|
}
|
|
191
153
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
154
|
+
for (const member of this.schema.members) {
|
|
155
|
+
const nonNullType = member.type.replace(" | null", "");
|
|
156
|
+
if (!isPrimitive(nonNullType)) {
|
|
157
|
+
const schema = this.schemas.find((v) => v.name == nonNullType);
|
|
158
|
+
if (schema && !this.schema.deps.includes(schema)) {
|
|
159
|
+
this.schema.deps.push(schema);
|
|
160
|
+
this.schema.byteSize += schema.byteSize;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
198
163
|
}
|
|
199
164
|
|
|
200
|
-
|
|
165
|
+
let isPure = this.schema.static;
|
|
166
|
+
let isRegular = isPure;
|
|
167
|
+
let isFirst = true;
|
|
168
|
+
|
|
169
|
+
for (let i = 0; i < this.schema.members.length; i++) {
|
|
170
|
+
const member = this.schema.members[i];
|
|
171
|
+
const aliasName = JSON.stringify(member.alias || member.name);
|
|
172
|
+
const realName = member.name;
|
|
173
|
+
const isLast = i == this.schema.members.length - 1;
|
|
174
|
+
const nonNullType = member.type.replace(" | null", "");
|
|
175
|
+
|
|
176
|
+
if (member.value) {
|
|
177
|
+
INITIALIZE += ` this.${member.name} = ${member.value};\n`;
|
|
178
|
+
} else if (this.schemas.find((v) => nonNullType == v.name)) {
|
|
179
|
+
INITIALIZE += ` this.${member.name} = changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())).__INITIALIZE();\n`;
|
|
180
|
+
} else if (member.type.startsWith("Array<") || member.type.startsWith("Map<")) {
|
|
181
|
+
INITIALIZE += ` this.${member.name} = [];\n`;
|
|
182
|
+
} else if (member.type == "string" || member.type == "String" || member.type == "JSON.Raw") {
|
|
183
|
+
INITIALIZE += ` this.${member.name} = "";\n`;
|
|
184
|
+
}
|
|
201
185
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
186
|
+
if (!isRegular && !member.flags.has(PropertyFlags.OmitIf) && !member.flags.has(PropertyFlags.OmitNull)) isRegular = true;
|
|
187
|
+
if (isRegular && isPure) {
|
|
188
|
+
const keyPart = (isFirst ? "{" : ",") + aliasName + ":";
|
|
189
|
+
this.schema.byteSize += keyPart.length << 1;
|
|
190
|
+
SERIALIZE += this.getStores(keyPart)
|
|
191
|
+
.map((v) => indent + v + "\n")
|
|
192
|
+
.join("");
|
|
193
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
194
|
+
if (isFirst) isFirst = false;
|
|
195
|
+
} else if (isRegular && !isPure) {
|
|
196
|
+
const keyPart = (isFirst ? "" : ",") + 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
|
+
if (isFirst) isFirst = false;
|
|
211
203
|
} else {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
204
|
+
if (member.flags.has(PropertyFlags.OmitNull)) {
|
|
205
|
+
SERIALIZE += indent + `if ((block = load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))) !== 0) {\n`;
|
|
206
|
+
indentInc();
|
|
207
|
+
const keyPart = aliasName + ":";
|
|
208
|
+
this.schema.byteSize += keyPart.length << 1;
|
|
209
|
+
SERIALIZE += this.getStores(keyPart)
|
|
210
|
+
.map((v) => indent + v + "\n")
|
|
211
|
+
.join("");
|
|
212
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
213
|
+
|
|
214
|
+
if (!isLast) {
|
|
215
|
+
this.schema.byteSize += 2;
|
|
216
|
+
SERIALIZE += indent + `store<u16>(bs.offset, 44, 0); // ,\n`;
|
|
217
|
+
SERIALIZE += indent + `bs.offset += 2;\n`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
indentDec();
|
|
221
|
+
this.schema.byteSize += 2;
|
|
222
|
+
SERIALIZE += indent + `}\n`;
|
|
223
|
+
} else if (member.flags.has(PropertyFlags.OmitIf)) {
|
|
224
|
+
if (member.flags.get(PropertyFlags.OmitIf).kind == NodeKind.Function) {
|
|
225
|
+
const arg = member.flags.get(PropertyFlags.OmitIf) as FunctionExpression;
|
|
226
|
+
// @ts-ignore: type
|
|
227
|
+
arg.declaration.signature.returnType.name = Node.createSimpleTypeName("boolean", arg.declaration.signature.returnType.name.range);
|
|
228
|
+
SERIALIZE += indent + `if (!(${toString(member.flags.get(PropertyFlags.OmitIf))})(this)) {\n`;
|
|
229
|
+
} else {
|
|
230
|
+
SERIALIZE += indent + `if (${toString(member.flags.get(PropertyFlags.OmitIf))}) {\n`;
|
|
231
|
+
}
|
|
232
|
+
indentInc();
|
|
233
|
+
SERIALIZE += this.getStores(aliasName + ":")
|
|
234
|
+
.map((v) => indent + v + "\n")
|
|
235
|
+
.join("");
|
|
236
|
+
SERIALIZE += indent + `JSON.__serialize<${member.type}>(load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
237
|
+
|
|
238
|
+
if (!isLast) {
|
|
239
|
+
this.schema.byteSize += 2;
|
|
240
|
+
SERIALIZE += indent + `store<u16>(bs.offset, 44, 0); // ,\n`;
|
|
241
|
+
SERIALIZE += indent + `bs.offset += 2;\n`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
indentDec();
|
|
245
|
+
SERIALIZE += indent + `}\n`;
|
|
246
|
+
}
|
|
215
247
|
}
|
|
216
248
|
}
|
|
217
249
|
|
|
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;
|
|
250
|
+
let sortedMembers: Property[][] = [];
|
|
251
|
+
|
|
252
|
+
let len = -1;
|
|
253
|
+
this.schema.members
|
|
254
|
+
.slice()
|
|
255
|
+
.sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length))
|
|
256
|
+
.forEach((member) => {
|
|
257
|
+
const _nameLength = member.alias?.length || member.name.length;
|
|
258
|
+
if (_nameLength === len) {
|
|
259
|
+
sortedMembers[sortedMembers.length - 1].push(member);
|
|
240
260
|
} else {
|
|
241
|
-
|
|
261
|
+
sortedMembers.push([member]);
|
|
262
|
+
len = _nameLength;
|
|
242
263
|
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
sortedMembers = sortedMembers.sort((a, b) => b.length - a.length);
|
|
267
|
+
|
|
268
|
+
indentInc();
|
|
269
|
+
for (const memberGroup of sortedMembers) {
|
|
270
|
+
const memberLen = (memberGroup[0].alias || memberGroup[0].name).length << 1;
|
|
271
|
+
DESERIALIZE += `${indent}case ${memberLen}: {\n`;
|
|
272
|
+
indentInc();
|
|
273
|
+
if (memberLen == 2) DESERIALIZE += `${indent}switch (load<u16>(keyStart)) {\n`;
|
|
274
|
+
else if (memberLen == 4) DESERIALIZE += `${indent}switch (load<u32>(keyStart)) {\n`;
|
|
275
|
+
else if (memberLen == 6) DESERIALIZE += `${indent}let code = (<u64>load<u32>(keyStart) << 16) | <u64>load<u16>(keyStart, 4);\n`;
|
|
276
|
+
else DESERIALIZE += toMemCDecl(memberLen, indent);
|
|
277
|
+
for (let i = 0; i < memberGroup.length; i++) {
|
|
278
|
+
const member = memberGroup[i];
|
|
279
|
+
const memberName = member.alias || member.name;
|
|
280
|
+
if (memberLen == 2) {
|
|
281
|
+
DESERIALIZE += `${indent} case ${memberName.charCodeAt(0)}: { // ${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} }\n`;
|
|
285
|
+
} else if (memberLen == 4) {
|
|
286
|
+
DESERIALIZE += `${indent} case ${toU32(memberName)}: { // ${memberName}\n`;
|
|
287
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
288
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
289
|
+
DESERIALIZE += `${indent} }\n`;
|
|
290
|
+
} else if (memberLen == 6) {
|
|
291
|
+
DESERIALIZE += i == 0 ? indent : "";
|
|
292
|
+
DESERIALIZE += `if (code == ${toU48(memberName)}) { // ${memberName}\n`;
|
|
293
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
294
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
295
|
+
DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
|
|
247
296
|
} else {
|
|
248
|
-
DESERIALIZE +=
|
|
297
|
+
DESERIALIZE += i == 0 ? indent : "";
|
|
298
|
+
DESERIALIZE += `if (${toMemCCheck(memberName)}) { // ${memberName}\n`;
|
|
299
|
+
DESERIALIZE += `${indent} store<${member.type}>(ptr, JSON.__deserialize<${member.type}>(valStart, valEnd), offsetof<this>(${JSON.stringify(member.name)}));\n`;
|
|
300
|
+
DESERIALIZE += `${indent} return;\n`;
|
|
301
|
+
DESERIALIZE += `${indent}}${i < memberGroup.length - 1 ? " else " : "\n"}`;
|
|
249
302
|
}
|
|
250
303
|
}
|
|
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
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (_name.length < 3) {
|
|
277
|
-
DESERIALIZE += ` default: {\n return false;\n }\n }\n`;
|
|
278
|
-
} else if (_name.length == 4) {
|
|
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`;
|
|
304
|
+
if (memberLen < 6) {
|
|
305
|
+
DESERIALIZE += `${indent}}\n`; // Close switch
|
|
282
306
|
}
|
|
283
|
-
|
|
307
|
+
indentDec();
|
|
308
|
+
DESERIALIZE += `${indent} return;\n`; // Break switch
|
|
309
|
+
DESERIALIZE += `${indent}}\n`; // Close length switch
|
|
284
310
|
}
|
|
285
311
|
|
|
286
|
-
|
|
312
|
+
indentDec();
|
|
313
|
+
DESERIALIZE += `${indent}}\n`; // Close length switch
|
|
314
|
+
indentDec();
|
|
315
|
+
DESERIALIZE += `${indent}}\n`; // Close function
|
|
316
|
+
|
|
317
|
+
indent = " ";
|
|
318
|
+
|
|
319
|
+
this.schema.byteSize += 2;
|
|
320
|
+
SERIALIZE += indent + "store<u16>(bs.offset, 125, 0); // }\n";
|
|
321
|
+
SERIALIZE += indent + "bs.offset += 2;\n";
|
|
322
|
+
SERIALIZE += "}";
|
|
323
|
+
|
|
324
|
+
ALLOCATE += indent + "bs.ensureSize(" + this.schema.byteSize + ");\n";
|
|
325
|
+
ALLOCATE += "}";
|
|
287
326
|
|
|
288
|
-
|
|
327
|
+
INITIALIZE += " return this;\n";
|
|
328
|
+
INITIALIZE += "}";
|
|
289
329
|
|
|
290
330
|
if (process.env["JSON_DEBUG"]) {
|
|
291
|
-
console.log(
|
|
292
|
-
//console.log(SERIALIZE_PRETTY);
|
|
331
|
+
console.log(SERIALIZE);
|
|
293
332
|
console.log(INITIALIZE);
|
|
294
333
|
console.log(DESERIALIZE);
|
|
334
|
+
console.log(ALLOCATE);
|
|
295
335
|
}
|
|
296
336
|
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
const DESERIALIZE_SAFE = DESERIALIZE.replaceAll("__DESERIALIZE", "__DESERIALIZE_SAFE");
|
|
300
|
-
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node);
|
|
337
|
+
const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE, node);
|
|
301
338
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
302
339
|
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node);
|
|
303
|
-
const
|
|
340
|
+
const ALLOCATE_METHOD = SimpleParser.parseClassMember(ALLOCATE, node);
|
|
304
341
|
|
|
305
|
-
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(
|
|
342
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_METHOD);
|
|
306
343
|
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD);
|
|
307
344
|
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD);
|
|
308
|
-
if (!node.members.find((v) => v.name.text == "
|
|
345
|
+
if (!node.members.find((v) => v.name.text == "__ALLOCATE")) node.members.push(ALLOCATE_METHOD);
|
|
346
|
+
super.visitClassDeclaration(node);
|
|
347
|
+
}
|
|
348
|
+
generateEmptyMethods(node: ClassDeclaration): void {
|
|
349
|
+
let SERIALIZE_RAW_EMPTY = '@inline __SERIALIZE(ptr: usize = changetype<usize>(this)): string {\n return "{}";\n}';
|
|
350
|
+
let SERIALIZE_BS_EMPTY = "@inline __SERIALIZE(ptr: usize: bool): void {\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
|
|
351
|
+
let INITIALIZE_EMPTY = "@inline __INITIALIZE(): this {\n return this;\n}";
|
|
352
|
+
let DESERIALIZE_EMPTY = "@inline __DESERIALIZE(keyStart: usize, keyEnd: usize, valStart: usize, valEnd: usize, ptr: usize): void {\n return false;\n}";
|
|
353
|
+
let ALLOCATE_EMPTY = "@inline __ALLOCATE(): void {\n bs.ensureSize(4);\n}";
|
|
354
|
+
|
|
355
|
+
if (process.env["JSON_DEBUG"]) {
|
|
356
|
+
console.log(SERIALIZE_RAW_EMPTY);
|
|
357
|
+
console.log(SERIALIZE_BS_EMPTY);
|
|
358
|
+
console.log(INITIALIZE_EMPTY);
|
|
359
|
+
console.log(DESERIALIZE_EMPTY);
|
|
360
|
+
console.log(ALLOCATE_EMPTY);
|
|
361
|
+
}
|
|
309
362
|
|
|
310
|
-
|
|
363
|
+
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node);
|
|
364
|
+
const SERIALIZE_BS_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_BS_EMPTY, node);
|
|
365
|
+
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node);
|
|
366
|
+
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node);
|
|
367
|
+
const ALLOCATE_METHOD_EMPTY = SimpleParser.parseClassMember(ALLOCATE_EMPTY, node);
|
|
368
|
+
|
|
369
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY);
|
|
370
|
+
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_BS_METHOD_EMPTY);
|
|
371
|
+
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY);
|
|
372
|
+
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY);
|
|
373
|
+
if (!node.members.find((v) => v.name.text == "__ALLOCATE")) node.members.push(ALLOCATE_METHOD_EMPTY);
|
|
374
|
+
}
|
|
375
|
+
// visitCallExpression(node: CallExpression, ref: Node): void {
|
|
376
|
+
// super.visitCallExpression(node, ref);
|
|
377
|
+
// 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;
|
|
378
|
+
|
|
379
|
+
// const source = node.range.source;
|
|
380
|
+
|
|
381
|
+
// if (ref.kind == NodeKind.Call) {
|
|
382
|
+
// const newNode = Node.createBinaryExpression(Token.Equals, node.args[1], node, node.range);
|
|
383
|
+
|
|
384
|
+
// (<CallExpression>ref).args[(<CallExpression>ref).args.indexOf(node)] = newNode;
|
|
385
|
+
// } else {
|
|
386
|
+
// const newNode = Node.createExpressionStatement(Node.createBinaryExpression(Token.Equals, node.args[1], node, node.range));
|
|
387
|
+
|
|
388
|
+
// const nodeIndex = source.statements.findIndex((n: Node) => {
|
|
389
|
+
// if (n == node) return true;
|
|
390
|
+
// if (n.kind == NodeKind.Expression && (<ExpressionStatement>n).expression == node) return true;
|
|
391
|
+
// return false;
|
|
392
|
+
// });
|
|
393
|
+
|
|
394
|
+
// if (nodeIndex > 0) source.statements[nodeIndex] = newNode;
|
|
395
|
+
// }
|
|
396
|
+
// }
|
|
397
|
+
// visitBinaryExpression(node: BinaryExpression, ref?: Node | null): void {
|
|
398
|
+
// // if (node.right.kind == NodeKind.Call && (<CallExpression>node).)
|
|
399
|
+
// }
|
|
400
|
+
visitImportStatement(node: ImportStatement): void {
|
|
401
|
+
super.visitImportStatement(node);
|
|
402
|
+
const source = this.parser.sources.find((src) => src.internalPath == node.internalPath);
|
|
403
|
+
if (!source) return;
|
|
404
|
+
|
|
405
|
+
if (source.statements.some((stmt) => stmt.kind === NodeKind.NamespaceDeclaration && (stmt as NamespaceDeclaration).name.text === "JSON")) this.imports.push(node);
|
|
311
406
|
}
|
|
312
407
|
visitSource(node: Source): void {
|
|
408
|
+
this.imports = [];
|
|
313
409
|
super.visitSource(node);
|
|
410
|
+
}
|
|
411
|
+
addRequiredImports(node: ClassDeclaration): void {
|
|
412
|
+
// if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "bs"))) {
|
|
413
|
+
// if (!this.bsImport) {
|
|
414
|
+
// this.bsImport = "import { bs } from \"as-bs\"";
|
|
415
|
+
// if (process.env["JSON_DEBUG"]) console.log("Added as-bs import: " + this.bsImport + "\n");
|
|
416
|
+
// }
|
|
417
|
+
// }
|
|
418
|
+
if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "bs"))) {
|
|
419
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
420
|
+
const __dirname = path.dirname(__filename);
|
|
421
|
+
|
|
422
|
+
let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../modules/as-bs/"));
|
|
423
|
+
|
|
424
|
+
if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) relativePath = "./" + relativePath;
|
|
425
|
+
// if (!existsSync(relativePath)) {
|
|
426
|
+
// 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 + "!");
|
|
427
|
+
// }
|
|
428
|
+
|
|
429
|
+
const txt = `import { bs } from "${relativePath}";`;
|
|
430
|
+
if (!this.bsImport) {
|
|
431
|
+
this.bsImport = txt;
|
|
432
|
+
if (process.env["JSON_DEBUG"]) console.log("Added as-bs import: " + txt + "\n");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
314
435
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
436
|
+
if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "JSON"))) {
|
|
437
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
438
|
+
const __dirname = path.dirname(__filename);
|
|
439
|
+
|
|
440
|
+
let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../assembly/index.ts"));
|
|
441
|
+
|
|
442
|
+
if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) relativePath = "./" + relativePath;
|
|
443
|
+
// if (!existsSync(relativePath)) {
|
|
444
|
+
// 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 + "!");
|
|
445
|
+
// }
|
|
446
|
+
|
|
447
|
+
const txt = `import { JSON } from "${relativePath}";`;
|
|
448
|
+
if (!this.jsonImport) {
|
|
449
|
+
this.jsonImport = txt;
|
|
450
|
+
if (process.env["JSON_DEBUG"]) console.log("Added json-as import: " + txt + "\n");
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
getStores(data: string, simd: boolean = false): string[] {
|
|
456
|
+
const out: string[] = [];
|
|
457
|
+
const sizes = strToNum(data, simd);
|
|
458
|
+
let offset = 0;
|
|
459
|
+
for (const [size, num] of sizes) {
|
|
460
|
+
if (size == "v128") {
|
|
461
|
+
// This could be put in its own file
|
|
462
|
+
let index = this.newStmts.simd.findIndex((v) => v.includes(num));
|
|
463
|
+
let name = "SIMD_" + (index == -1 ? this.newStmts.simd.length : index);
|
|
464
|
+
if (index && !this.newStmts.simd.includes(`const ${name} = ${num};`)) this.newStmts.simd.push(`const ${name} = ${num};`);
|
|
465
|
+
out.push("store<v128>(bs.offset, " + name + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 8));
|
|
466
|
+
offset += 16;
|
|
467
|
+
}
|
|
468
|
+
if (size == "u64") {
|
|
469
|
+
out.push("store<u64>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 4));
|
|
470
|
+
offset += 8;
|
|
471
|
+
} else if (size == "u32") {
|
|
472
|
+
out.push("store<u32>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 2));
|
|
473
|
+
offset += 4;
|
|
474
|
+
} else if (size == "u16") {
|
|
475
|
+
out.push("store<u16>(bs.offset, " + num + ", " + offset + "); // " + data.slice(offset >> 1, (offset >> 1) + 1));
|
|
476
|
+
offset += 2;
|
|
477
|
+
}
|
|
318
478
|
}
|
|
479
|
+
out.push("bs.offset += " + offset + ";");
|
|
480
|
+
return out;
|
|
319
481
|
}
|
|
320
482
|
}
|
|
321
483
|
|
|
@@ -326,159 +488,231 @@ export default class Transformer extends Transform {
|
|
|
326
488
|
const transformer = new JSONTransform();
|
|
327
489
|
|
|
328
490
|
// 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
|
-
});
|
|
491
|
+
const sources = parser.sources.sort((_a, _b) => {
|
|
492
|
+
const a = _a.internalPath;
|
|
493
|
+
const b = _b.internalPath;
|
|
494
|
+
if (a[0] == "~" && b[0] !== "~") {
|
|
495
|
+
return -1;
|
|
496
|
+
} else if (a[0] !== "~" && b[0] == "~") {
|
|
497
|
+
return 1;
|
|
498
|
+
} else {
|
|
499
|
+
return 0;
|
|
500
|
+
}
|
|
501
|
+
});
|
|
342
502
|
|
|
503
|
+
transformer.parser = parser;
|
|
343
504
|
// Loop over every source
|
|
344
505
|
for (const source of sources) {
|
|
506
|
+
transformer.imports = [];
|
|
507
|
+
transformer.currentSource = source;
|
|
345
508
|
// Ignore all lib and std. Visit everything else.
|
|
346
|
-
|
|
347
|
-
|
|
509
|
+
transformer.visit(source);
|
|
510
|
+
|
|
511
|
+
if (transformer.newStmts.simd) {
|
|
512
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.newStmts.simd.join("\n")));
|
|
513
|
+
parser.currentSource = tokenizer.source;
|
|
514
|
+
for (let i = 0; i < transformer.newStmts.simd.length; i++) source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!);
|
|
515
|
+
parser.currentSource = source;
|
|
516
|
+
transformer.newStmts.simd = [];
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (transformer.jsonImport) {
|
|
520
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.jsonImport));
|
|
521
|
+
parser.currentSource = tokenizer.source;
|
|
522
|
+
source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!);
|
|
523
|
+
parser.currentSource = source;
|
|
524
|
+
transformer.jsonImport = null;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (transformer.bsImport) {
|
|
528
|
+
const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.bsImport));
|
|
529
|
+
parser.currentSource = tokenizer.source;
|
|
530
|
+
source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!);
|
|
531
|
+
parser.currentSource = source;
|
|
532
|
+
transformer.bsImport = null;
|
|
348
533
|
}
|
|
349
534
|
}
|
|
350
535
|
// Check that every parent and child class is hooked up correctly
|
|
351
|
-
const schemas = transformer.
|
|
536
|
+
const schemas = transformer.schemas;
|
|
352
537
|
for (const schema of schemas) {
|
|
353
538
|
if (schema.parent) {
|
|
354
|
-
const parent = schemas.find((v) => v.name
|
|
355
|
-
if (!parent)
|
|
539
|
+
const parent = schemas.find((v) => v.name == schema.parent?.name);
|
|
540
|
+
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
541
|
}
|
|
357
542
|
}
|
|
358
543
|
}
|
|
359
544
|
}
|
|
360
545
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
546
|
+
function sortMembers(members: Property[]): Property[] {
|
|
547
|
+
return members.sort((a, b) => {
|
|
548
|
+
const aMove = a.flags.has(PropertyFlags.OmitIf) || a.flags.has(PropertyFlags.OmitNull);
|
|
549
|
+
const bMove = b.flags.has(PropertyFlags.OmitIf) || b.flags.has(PropertyFlags.OmitNull);
|
|
550
|
+
|
|
551
|
+
if (aMove && !bMove) {
|
|
552
|
+
return -1;
|
|
553
|
+
} else if (!aMove && bMove) {
|
|
554
|
+
return 1;
|
|
555
|
+
} else {
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
});
|
|
368
559
|
}
|
|
369
560
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
561
|
+
function getArgs(args: Expression[] | null): string[] {
|
|
562
|
+
if (!args) return [];
|
|
563
|
+
let out: string[] = [];
|
|
564
|
+
for (const arg of args) {
|
|
565
|
+
if (arg instanceof StringLiteralExpression) {
|
|
566
|
+
out.push(arg.value);
|
|
567
|
+
} else if (arg instanceof IntegerLiteralExpression) {
|
|
568
|
+
out.push(i64_to_string(arg.value));
|
|
569
|
+
} else if (arg instanceof FloatLiteralExpression) {
|
|
570
|
+
out.push(arg.value.toString());
|
|
571
|
+
} else if (arg instanceof NullExpression) {
|
|
572
|
+
out.push(arg.text);
|
|
573
|
+
} else if (arg instanceof TrueExpression) {
|
|
574
|
+
out.push(arg.text);
|
|
575
|
+
} else if (arg instanceof FalseExpression) {
|
|
576
|
+
out.push(arg.text);
|
|
577
|
+
} else if (arg instanceof IdentifierExpression) {
|
|
578
|
+
out.push(arg.text);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return out;
|
|
582
|
+
}
|
|
376
583
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
584
|
+
function toU16(data: string, offset: number = 0): string {
|
|
585
|
+
return data.charCodeAt(offset + 0).toString();
|
|
586
|
+
}
|
|
380
587
|
|
|
381
|
-
|
|
588
|
+
function toU32(data: string, offset: number = 0): string {
|
|
589
|
+
return ((data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset + 0)).toString();
|
|
590
|
+
}
|
|
382
591
|
|
|
383
|
-
|
|
384
|
-
|
|
592
|
+
function toU48(data: string, offset: number = 0): string {
|
|
593
|
+
return ((BigInt(data.charCodeAt(offset + 2)) << 32n) | (BigInt(data.charCodeAt(offset + 1)) << 16n) | BigInt(data.charCodeAt(offset + 0))).toString();
|
|
594
|
+
}
|
|
385
595
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const type = this.type;
|
|
390
|
-
if (this.flags.has(PropertyFlags.Omit)) return;
|
|
596
|
+
function toU64(data: string, offset: number = 0): string {
|
|
597
|
+
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();
|
|
598
|
+
}
|
|
391
599
|
|
|
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
|
-
}
|
|
600
|
+
function toMemCDecl(n: number, indent: string): string {
|
|
601
|
+
let out = "";
|
|
602
|
+
let offset = 0;
|
|
603
|
+
let index = 0;
|
|
604
|
+
while (n >= 8) {
|
|
605
|
+
out += `${indent}const code${index++} = load<u64>(keyStart, ${offset});\n`;
|
|
606
|
+
offset += 8;
|
|
607
|
+
n -= 8;
|
|
608
|
+
}
|
|
404
609
|
|
|
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
|
-
}
|
|
610
|
+
while (n >= 4) {
|
|
611
|
+
out += `${indent}const code${index++} = load<u32>(keyStart, ${offset});\n`;
|
|
612
|
+
offset += 4;
|
|
613
|
+
n -= 4;
|
|
417
614
|
}
|
|
418
|
-
}
|
|
419
615
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
public parent: SchemaData | null = null;
|
|
424
|
-
public node!: ClassDeclaration;
|
|
616
|
+
if (n == 1) out += `${indent}const code${index++} = load<u16>(keyStart, ${offset});\n`;
|
|
617
|
+
|
|
618
|
+
return out;
|
|
425
619
|
}
|
|
426
620
|
|
|
427
|
-
function
|
|
428
|
-
|
|
621
|
+
function toMemCCheck(data: string): string {
|
|
622
|
+
let n = data.length << 1;
|
|
623
|
+
let out = "";
|
|
624
|
+
let offset = 0;
|
|
625
|
+
let index = 0;
|
|
626
|
+
while (n >= 8) {
|
|
627
|
+
out += ` && code${index++} == ${toU64(data, offset >> 1)}`;
|
|
628
|
+
offset += 8;
|
|
629
|
+
n -= 8;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
while (n >= 4) {
|
|
633
|
+
out += ` && code${index++} == ${toU32(data, offset >> 1)}`;
|
|
634
|
+
offset += 4;
|
|
635
|
+
n -= 4;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (n == 1) out += ` && code${index++} == ${toU16(data, offset >> 1)}`;
|
|
639
|
+
|
|
640
|
+
return out.slice(4);
|
|
429
641
|
}
|
|
430
642
|
|
|
431
|
-
function
|
|
432
|
-
|
|
433
|
-
|
|
643
|
+
function strToNum(data: string, simd: boolean = false, offset: number = 0): string[][] {
|
|
644
|
+
const out: string[][] = [];
|
|
645
|
+
let n = data.length;
|
|
646
|
+
|
|
647
|
+
while (n >= 8 && simd) {
|
|
648
|
+
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) + ")"]);
|
|
649
|
+
|
|
650
|
+
offset += 8;
|
|
651
|
+
n -= 8;
|
|
434
652
|
}
|
|
435
653
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
654
|
+
while (n >= 4) {
|
|
655
|
+
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));
|
|
656
|
+
out.push(["u64", value.toString()]);
|
|
657
|
+
offset += 4;
|
|
658
|
+
n -= 4;
|
|
659
|
+
}
|
|
440
660
|
|
|
441
|
-
|
|
661
|
+
while (n >= 2) {
|
|
662
|
+
const value = (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset + 0);
|
|
663
|
+
out.push(["u32", value.toString()]);
|
|
664
|
+
offset += 2;
|
|
665
|
+
n -= 2;
|
|
666
|
+
}
|
|
442
667
|
|
|
443
|
-
|
|
668
|
+
if (n === 1) {
|
|
669
|
+
const value = data.charCodeAt(offset + 0);
|
|
670
|
+
out.push(["u16", value.toString()]);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return out;
|
|
444
674
|
}
|
|
445
675
|
|
|
446
|
-
function
|
|
447
|
-
const
|
|
448
|
-
return
|
|
676
|
+
function isPrimitive(type: string): boolean {
|
|
677
|
+
const primitiveTypes = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64", "f32", "f64", "bool", "boolean"];
|
|
678
|
+
return primitiveTypes.some((v) => type.includes(v));
|
|
449
679
|
}
|
|
450
680
|
|
|
451
|
-
function
|
|
452
|
-
|
|
681
|
+
function throwError(message: string, range: Range): never {
|
|
682
|
+
const err = new Error();
|
|
683
|
+
err.stack = `${message}\n at ${range.source.normalizedPath}:${range.source.lineAt(range.start)}:${range.source.columnAt()}\n`;
|
|
684
|
+
throw err;
|
|
453
685
|
}
|
|
454
686
|
|
|
455
|
-
function
|
|
456
|
-
|
|
687
|
+
function indentInc(): void {
|
|
688
|
+
indent += " ";
|
|
457
689
|
}
|
|
458
690
|
|
|
459
|
-
function
|
|
460
|
-
|
|
691
|
+
function indentDec(): void {
|
|
692
|
+
indent = indent.slice(0, Math.max(0, indent.length - 2));
|
|
461
693
|
}
|
|
462
694
|
|
|
463
|
-
function
|
|
464
|
-
if (
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
695
|
+
function sizeof(type: string): number {
|
|
696
|
+
if (type == "u8")
|
|
697
|
+
return 6; // -127
|
|
698
|
+
else if (type == "i8")
|
|
699
|
+
return 8; // 255
|
|
700
|
+
else if (type == "u16")
|
|
701
|
+
return 10; // 65536
|
|
702
|
+
else if (type == "i16")
|
|
703
|
+
return 12; // -32767
|
|
704
|
+
else if (type == "u32")
|
|
705
|
+
return 20; // 4294967295
|
|
706
|
+
else if (type == "i32")
|
|
707
|
+
return 22; // -2147483647
|
|
708
|
+
else if (type == "u64")
|
|
709
|
+
return 40; // 18446744073709551615
|
|
710
|
+
else if (type == "i64")
|
|
711
|
+
return 40; // -9223372036854775807
|
|
712
|
+
else if (type == "bool" || type == "boolean") return 10;
|
|
713
|
+
else return 0;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function allPrimitive(schema: Schema): boolean {
|
|
717
|
+
return !schema.members.some((p) => p.byteSize == 0);
|
|
484
718
|
}
|