skir-cc-gen 0.0.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/README.md +335 -0
- package/client/BUILD.bazel +33 -0
- package/client/MODULE.bazel +11 -0
- package/client/MODULE.bazel.lock +225 -0
- package/client/skir.cc +2687 -0
- package/client/skir.h +2946 -0
- package/client/skir.testing.h +282 -0
- package/dist/enum_field.d.ts +33 -0
- package/dist/enum_field.d.ts.map +1 -0
- package/dist/enum_field.js +85 -0
- package/dist/enum_field.js.map +1 -0
- package/dist/enum_variant.d.ts +31 -0
- package/dist/enum_variant.d.ts.map +1 -0
- package/dist/enum_variant.js +85 -0
- package/dist/enum_variant.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1627 -0
- package/dist/index.js.map +1 -0
- package/dist/keywords.d.ts +2 -0
- package/dist/keywords.d.ts.map +1 -0
- package/dist/keywords.js +101 -0
- package/dist/keywords.js.map +1 -0
- package/dist/recursivity_resolver.d.ts +58 -0
- package/dist/recursivity_resolver.d.ts.map +1 -0
- package/dist/recursivity_resolver.js +142 -0
- package/dist/recursivity_resolver.js.map +1 -0
- package/dist/type_speller.d.ts +17 -0
- package/dist/type_speller.d.ts.map +1 -0
- package/dist/type_speller.js +87 -0
- package/dist/type_speller.js.map +1 -0
- package/package.json +55 -0
- package/src/enum_variant.ts +126 -0
- package/src/index.ts +2089 -0
- package/src/keywords.ts +100 -0
- package/src/recursivity_resolver.ts +161 -0
- package/src/type_speller.ts +100 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1627 @@
|
|
|
1
|
+
import { convertCase, encodeInt32, simpleHash, } from "skir-internal";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getEnumVariants } from "./enum_variant.js";
|
|
4
|
+
import { CC_KEYWORDS } from "./keywords.js";
|
|
5
|
+
import { RecursvityResolver } from "./recursivity_resolver.js";
|
|
6
|
+
import { TypeSpeller, getClassName, modulePathToNamespace, } from "./type_speller.js";
|
|
7
|
+
const Config = z.object({
|
|
8
|
+
writeGoogleTestHeaders: z.boolean(),
|
|
9
|
+
});
|
|
10
|
+
class CcCodeGenerator {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.id = "cc";
|
|
13
|
+
this.configType = Config;
|
|
14
|
+
this.version = "1.0.0";
|
|
15
|
+
}
|
|
16
|
+
generateCode(input) {
|
|
17
|
+
const { recordMap, config } = input;
|
|
18
|
+
const outputFiles = [];
|
|
19
|
+
for (const module of input.modules) {
|
|
20
|
+
const generator = new CcLibFilesGenerator(module, recordMap);
|
|
21
|
+
outputFiles.push({
|
|
22
|
+
path: module.path.replace(/\.skir$/, ".h"),
|
|
23
|
+
code: generator.getCode(".h"),
|
|
24
|
+
});
|
|
25
|
+
outputFiles.push({
|
|
26
|
+
path: module.path.replace(/\.skir$/, ".cc"),
|
|
27
|
+
code: generator.getCode(".cc"),
|
|
28
|
+
});
|
|
29
|
+
if (config.writeGoogleTestHeaders) {
|
|
30
|
+
outputFiles.push({
|
|
31
|
+
path: module.path.replace(/\.skir$/, ".testing.h"),
|
|
32
|
+
code: generator.getCode(".testing.h"),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { files: outputFiles };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generates the code for one C++ library, made of one .h file and one .cc
|
|
41
|
+
* file.
|
|
42
|
+
*/
|
|
43
|
+
class CcLibFilesGenerator {
|
|
44
|
+
constructor(inModule, recordMap) {
|
|
45
|
+
this.inModule = inModule;
|
|
46
|
+
this.recordMap = recordMap;
|
|
47
|
+
this.includes = new Set();
|
|
48
|
+
this.seenskiroutSymbols = new Set();
|
|
49
|
+
this.header = new FileContents(".h");
|
|
50
|
+
this.source = new FileContents(".cc");
|
|
51
|
+
this.testingHeader = new FileContents(".testing.h");
|
|
52
|
+
this.typeSpeller = new TypeSpeller(recordMap, inModule, this.includes);
|
|
53
|
+
this.recursivityResolver = RecursvityResolver.resolve(recordMap, inModule);
|
|
54
|
+
this.includes.add('"skir.h"');
|
|
55
|
+
this.namespace = modulePathToNamespace(inModule.path);
|
|
56
|
+
this.generate();
|
|
57
|
+
}
|
|
58
|
+
getCode(extension) {
|
|
59
|
+
switch (extension) {
|
|
60
|
+
case ".h":
|
|
61
|
+
return fileContentsToCode(this.header);
|
|
62
|
+
case ".cc":
|
|
63
|
+
return fileContentsToCode(this.source);
|
|
64
|
+
case ".testing.h":
|
|
65
|
+
return fileContentsToCode(this.testingHeader);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
generate() {
|
|
69
|
+
this.header.namespace = this.namespace;
|
|
70
|
+
this.source.namespace = this.namespace;
|
|
71
|
+
this.testingHeader.namespace = this.namespace;
|
|
72
|
+
for (const record of this.recursivityResolver.reorderedRecords) {
|
|
73
|
+
this.writeCodeForRecord(record);
|
|
74
|
+
}
|
|
75
|
+
for (const method of this.inModule.methods) {
|
|
76
|
+
this.writeCodeForMethod(method);
|
|
77
|
+
}
|
|
78
|
+
for (const constant of this.inModule.constants) {
|
|
79
|
+
this.writeCodeForConstant(constant);
|
|
80
|
+
}
|
|
81
|
+
this.writeIncludes();
|
|
82
|
+
}
|
|
83
|
+
writeCodeForRecord(record) {
|
|
84
|
+
const { recordType } = record.record;
|
|
85
|
+
if (recordType === "struct") {
|
|
86
|
+
this.writeCodeForStruct(record);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.writeCodeForEnum(record);
|
|
90
|
+
}
|
|
91
|
+
this.writeCodeInHeaderForAdapter(record);
|
|
92
|
+
}
|
|
93
|
+
writeCodeForStruct(struct) {
|
|
94
|
+
const { header, recordMap, source, testingHeader, typeSpeller } = this;
|
|
95
|
+
const { fields, numSlots, numSlotsInclRemovedNumbers, nestedRecords } = struct.record;
|
|
96
|
+
const fieldsByName = [...struct.record.fields].sort((a, b) => a.name.text.localeCompare(b.name.text, "en-US"));
|
|
97
|
+
const fieldsByNumber = [...struct.record.fields].sort((a, b) => a.number - b.number);
|
|
98
|
+
const className = getClassName(struct);
|
|
99
|
+
const adapterName = `${className}Adapter`;
|
|
100
|
+
const qualifiedName = `::${this.namespace}::${className}`;
|
|
101
|
+
const constRefType = `const ${qualifiedName}&`;
|
|
102
|
+
// ------------------------------
|
|
103
|
+
// - APPEND CODE IN THE .h FILE -
|
|
104
|
+
// ------------------------------
|
|
105
|
+
header.mainTop.push(`struct ${className};`);
|
|
106
|
+
for (const field of fields) {
|
|
107
|
+
const fieldName = field.name.text;
|
|
108
|
+
const escapedFieldName = maybeEscapeLowerCaseName(fieldName);
|
|
109
|
+
const structName = `get_${fieldName}`;
|
|
110
|
+
if (!this.addskiroutSymbol(structName))
|
|
111
|
+
continue;
|
|
112
|
+
header.skirout.push(`#ifndef skirout_${structName}`);
|
|
113
|
+
header.skirout.push(`#define skirout_${structName}`);
|
|
114
|
+
header.skirout.push("template <typename other = ::skir::identity>");
|
|
115
|
+
header.skirout.push(`struct ${structName} {`);
|
|
116
|
+
header.skirout.push(" using other_type = other;");
|
|
117
|
+
header.skirout.push("");
|
|
118
|
+
header.skirout.push(` static constexpr absl::string_view kFieldName = "${fieldName}";`);
|
|
119
|
+
header.skirout.push("");
|
|
120
|
+
header.skirout.push(" template <typename T>");
|
|
121
|
+
header.skirout.push(` auto& operator()(T& input) const {`);
|
|
122
|
+
header.skirout.push(` return skir_internal::get(other()(input).${escapedFieldName});`);
|
|
123
|
+
header.skirout.push(" }");
|
|
124
|
+
header.skirout.push("};");
|
|
125
|
+
header.skirout.push("#endif");
|
|
126
|
+
header.skirout.push("");
|
|
127
|
+
}
|
|
128
|
+
header.mainMiddle.push(...commentify(docToCommentText(struct.record.doc)));
|
|
129
|
+
header.mainMiddle.push(`struct ${className} {`);
|
|
130
|
+
// Declare fields in alphabetical order. It helps users who want to
|
|
131
|
+
// initialize a struct using the designated initializer syntax. See:
|
|
132
|
+
// https://abseil.io/tips/172
|
|
133
|
+
for (const field of fieldsByName) {
|
|
134
|
+
const type = field.type;
|
|
135
|
+
const fieldIsRecursive = this.recursivityResolver.isRecursive(field);
|
|
136
|
+
const ccType = typeSpeller.getCcType(type, {
|
|
137
|
+
fieldIsRecursive: fieldIsRecursive,
|
|
138
|
+
});
|
|
139
|
+
const fieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
140
|
+
// Numeric types must be initialized.
|
|
141
|
+
let assignment = "";
|
|
142
|
+
if (type.kind === "primitive") {
|
|
143
|
+
if (type.primitive === "bool") {
|
|
144
|
+
assignment = " = false";
|
|
145
|
+
}
|
|
146
|
+
else if (type.primitive.includes("int")) {
|
|
147
|
+
assignment = " = 0";
|
|
148
|
+
}
|
|
149
|
+
else if (type.primitive.includes("float")) {
|
|
150
|
+
assignment = " = 0.0";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
header.mainMiddle.push(...commentify(docToCommentText(field.doc), " "));
|
|
154
|
+
header.mainMiddle.push(` ${ccType} ${fieldName}${assignment};`);
|
|
155
|
+
}
|
|
156
|
+
header.mainMiddle.push("");
|
|
157
|
+
header.mainMiddle.push(" ::skir_internal::UnrecognizedFields<");
|
|
158
|
+
header.mainMiddle.push(` ::skir_internal::${this.namespace}::${adapterName}>`);
|
|
159
|
+
header.mainMiddle.push(" _unrecognized;");
|
|
160
|
+
header.mainMiddle.push("");
|
|
161
|
+
header.mainMiddle.push(` bool operator==(const ${className}& other) const;`);
|
|
162
|
+
header.mainMiddle.push("");
|
|
163
|
+
header.mainMiddle.push(` inline bool operator!=(const ${className}& other) const {`);
|
|
164
|
+
header.mainMiddle.push(" return !(*this == other);");
|
|
165
|
+
header.mainMiddle.push(" }");
|
|
166
|
+
header.mainMiddle.push("");
|
|
167
|
+
{
|
|
168
|
+
const commentLines = [
|
|
169
|
+
"Use this when you want to make sure you are specifying all the fields of",
|
|
170
|
+
"the struct. The compiler will error if one field is missing.",
|
|
171
|
+
];
|
|
172
|
+
if (fields.length !== 0) {
|
|
173
|
+
commentLines.push(...[
|
|
174
|
+
"",
|
|
175
|
+
"Example:",
|
|
176
|
+
"",
|
|
177
|
+
` ${className} value = ${className}::whole{`,
|
|
178
|
+
]);
|
|
179
|
+
for (const field of fieldsByName) {
|
|
180
|
+
const fieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
181
|
+
commentLines.push(` .${fieldName} = ...,`);
|
|
182
|
+
}
|
|
183
|
+
commentLines.push(" };");
|
|
184
|
+
}
|
|
185
|
+
header.mainMiddle.push(...commentify(commentLines, " "));
|
|
186
|
+
}
|
|
187
|
+
header.mainMiddle.push(" struct whole {");
|
|
188
|
+
for (const field of fieldsByName) {
|
|
189
|
+
const type = field.type;
|
|
190
|
+
const fieldIsRecursive = this.recursivityResolver.isRecursive(field);
|
|
191
|
+
const ccType = typeSpeller.getCcType(type, {
|
|
192
|
+
fieldIsRecursive: fieldIsRecursive,
|
|
193
|
+
});
|
|
194
|
+
const fieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
195
|
+
header.mainMiddle.push(...commentify(docToCommentText(field.doc), " "));
|
|
196
|
+
header.mainMiddle.push(` ::skir::must_init<${ccType}> ${fieldName};`);
|
|
197
|
+
}
|
|
198
|
+
header.mainMiddle.push("");
|
|
199
|
+
header.mainMiddle.push(` operator ${className}();`);
|
|
200
|
+
header.mainMiddle.push(" };");
|
|
201
|
+
header.mainMiddle.push("");
|
|
202
|
+
for (const nestedRecord of nestedRecords) {
|
|
203
|
+
let typeAlias = nestedRecord.name.text;
|
|
204
|
+
if (typeAlias === className) {
|
|
205
|
+
typeAlias = `${typeAlias}_`;
|
|
206
|
+
}
|
|
207
|
+
const recordLocation = recordMap.get(nestedRecord.key);
|
|
208
|
+
const nestedClassName = getClassName(recordLocation);
|
|
209
|
+
header.mainMiddle.push(` using ${typeAlias} = ${nestedClassName};`);
|
|
210
|
+
}
|
|
211
|
+
header.mainMiddle.push("};");
|
|
212
|
+
header.mainMiddle.push("");
|
|
213
|
+
header.mainBottom.push("inline std::ostream& operator<<(");
|
|
214
|
+
header.mainBottom.push(" std::ostream& os,");
|
|
215
|
+
header.mainBottom.push(` ${constRefType} input) {`);
|
|
216
|
+
header.mainBottom.push(" return os << ::skir_internal::ToDebugString(input);");
|
|
217
|
+
header.mainBottom.push("}");
|
|
218
|
+
header.mainBottom.push("");
|
|
219
|
+
{
|
|
220
|
+
header.mainBottom.push("template <typename H>");
|
|
221
|
+
header.mainBottom.push(`H AbslHashValue(H h, ${constRefType} input) {`);
|
|
222
|
+
const args = fields
|
|
223
|
+
.map((f) => `,\n input.${maybeEscapeLowerCaseName(f.name.text)}`)
|
|
224
|
+
.join("");
|
|
225
|
+
header.mainBottom.push(" return H::combine(");
|
|
226
|
+
header.mainBottom.push(` std::move(h)${args});`);
|
|
227
|
+
header.mainBottom.push("}");
|
|
228
|
+
header.mainBottom.push("");
|
|
229
|
+
}
|
|
230
|
+
// --------------------------------------
|
|
231
|
+
// - APPEND CODE IN THE .testing.h FILE -
|
|
232
|
+
// --------------------------------------
|
|
233
|
+
testingHeader.skirout.push("template <>");
|
|
234
|
+
testingHeader.skirout.push(`struct StructIs<${qualifiedName}> {`);
|
|
235
|
+
// Declare fields in alphabetical order. It helps users who want to
|
|
236
|
+
// initialize a struct using the designated initializer syntax. See:
|
|
237
|
+
// https://abseil.io/tips/172
|
|
238
|
+
for (const field of fieldsByName) {
|
|
239
|
+
const type = field.type;
|
|
240
|
+
const fieldIsRecursive = this.recursivityResolver.isRecursive(field);
|
|
241
|
+
const fieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
242
|
+
if (type.kind === "record") {
|
|
243
|
+
// Do not pass fieldIsRecursive.
|
|
244
|
+
const ccType = typeSpeller.getCcType(type, { forceNamespace: true });
|
|
245
|
+
const recordType = recordMap.get(type.key).record.recordType;
|
|
246
|
+
if (!fieldIsRecursive && recordType === "struct") {
|
|
247
|
+
testingHeader.skirout.push(` StructIs<${ccType}> ${fieldName};`);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
testingHeader.skirout.push(` Matcher<${ccType}> ${fieldName} = _;`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
const ccType = typeSpeller.getCcType(type, {
|
|
255
|
+
fieldIsRecursive: fieldIsRecursive,
|
|
256
|
+
forceNamespace: true,
|
|
257
|
+
});
|
|
258
|
+
testingHeader.skirout.push(` Matcher<${ccType}> ${fieldName} = _;`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
testingHeader.skirout.push("");
|
|
262
|
+
testingHeader.skirout.push(` Matcher<${qualifiedName}> ToMatcher() const {`);
|
|
263
|
+
if (fields.length <= 0) {
|
|
264
|
+
testingHeader.skirout.push(" return _;");
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
testingHeader.skirout.push(` return ::testing::skir_internal::StructIs<${qualifiedName}>(`);
|
|
268
|
+
for (const field of fieldsByName) {
|
|
269
|
+
const type = field.type;
|
|
270
|
+
const fieldIsRecursive = this.recursivityResolver.isRecursive(field);
|
|
271
|
+
const fieldName = field.name.text;
|
|
272
|
+
let matcherExpr = maybeEscapeLowerCaseName(fieldName);
|
|
273
|
+
if (type.kind === "record") {
|
|
274
|
+
const recordType = recordMap.get(type.key).record.recordType;
|
|
275
|
+
if (!fieldIsRecursive && recordType === "struct") {
|
|
276
|
+
matcherExpr += ".ToMatcher()";
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const end = field === fieldsByName.at(-1) ? ");" : ",";
|
|
280
|
+
const getterExpr = `::skirout::get_${fieldName}()`;
|
|
281
|
+
testingHeader.skirout.push(` std::make_pair(${getterExpr}, ${matcherExpr})${end}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
testingHeader.skirout.push(" }");
|
|
285
|
+
testingHeader.skirout.push("");
|
|
286
|
+
testingHeader.skirout.push(" template <typename T>");
|
|
287
|
+
testingHeader.skirout.push(" operator Matcher<T>() const {");
|
|
288
|
+
testingHeader.skirout.push(" return ::testing::SafeMatcherCast<T>(ToMatcher());");
|
|
289
|
+
testingHeader.skirout.push(" }");
|
|
290
|
+
testingHeader.skirout.push("");
|
|
291
|
+
testingHeader.skirout.push("};");
|
|
292
|
+
testingHeader.skirout.push("");
|
|
293
|
+
// -------------------------------
|
|
294
|
+
// - APPEND CODE IN THE .cc FILE -
|
|
295
|
+
// -------------------------------
|
|
296
|
+
{
|
|
297
|
+
// _GetArrayLength(const T&)
|
|
298
|
+
source.anonymous.push("inline ::int32_t _GetArrayLength(");
|
|
299
|
+
source.anonymous.push(` ${constRefType} input,`);
|
|
300
|
+
source.anonymous.push(" const std::shared_ptr<skir_internal::UnrecognizedFieldsData>& u,");
|
|
301
|
+
source.anonymous.push(" skir_internal::UnrecognizedFormat format) {");
|
|
302
|
+
source.anonymous.push(" if (u != nullptr && u->format == format)");
|
|
303
|
+
source.anonymous.push(" return u->array_len;");
|
|
304
|
+
for (const field of [...fieldsByNumber].reverse()) {
|
|
305
|
+
const { number, name } = field;
|
|
306
|
+
const fieldExpr = `input.${maybeEscapeLowerCaseName(name.text)}`;
|
|
307
|
+
source.anonymous.push(` if (!::skir_internal::IsDefault(${fieldExpr}))`);
|
|
308
|
+
source.anonymous.push(` return ${number + 1};`);
|
|
309
|
+
}
|
|
310
|
+
source.anonymous.push(" return 0;");
|
|
311
|
+
source.anonymous.push("}");
|
|
312
|
+
source.anonymous.push("");
|
|
313
|
+
}
|
|
314
|
+
{
|
|
315
|
+
// IsDefault(const T&)
|
|
316
|
+
source.internalMain.push(`bool ${adapterName}::IsDefault(const type& input) {`);
|
|
317
|
+
const expression = fields.length
|
|
318
|
+
? fields
|
|
319
|
+
.map((f) => {
|
|
320
|
+
const fieldName = maybeEscapeLowerCaseName(f.name.text);
|
|
321
|
+
return `::skir_internal::IsDefault(input.${fieldName})`;
|
|
322
|
+
})
|
|
323
|
+
.join("\n && ")
|
|
324
|
+
: "true";
|
|
325
|
+
source.internalMain.push(` return ${expression};`);
|
|
326
|
+
source.internalMain.push("}");
|
|
327
|
+
source.internalMain.push("");
|
|
328
|
+
}
|
|
329
|
+
{
|
|
330
|
+
// Append(const T&, DenseJson&)
|
|
331
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, DenseJson& out) {`);
|
|
332
|
+
source.internalMain.push(" const auto& unrecognized = input._unrecognized.data;");
|
|
333
|
+
source.internalMain.push(" const auto array_len = _GetArrayLength(input, unrecognized, skir_internal::UnrecognizedFormat::kDenseJson);");
|
|
334
|
+
source.internalMain.push(" if (array_len == 0) {");
|
|
335
|
+
source.internalMain.push(" out.out += {'[', ']'};");
|
|
336
|
+
source.internalMain.push(" return;");
|
|
337
|
+
source.internalMain.push(" }");
|
|
338
|
+
source.internalMain.push(" JsonArrayCloser closer(&out);");
|
|
339
|
+
let charLiterals = ["'['"];
|
|
340
|
+
let lastFieldNumber = -1;
|
|
341
|
+
for (const field of fieldsByNumber) {
|
|
342
|
+
const { number, name } = field;
|
|
343
|
+
// Append one 0 for every removed number.
|
|
344
|
+
for (let i = lastFieldNumber + 1; i < number; ++i) {
|
|
345
|
+
charLiterals.push("'0'");
|
|
346
|
+
charLiterals.push("','");
|
|
347
|
+
}
|
|
348
|
+
source.internalMain.push(` out.out += {${charLiterals.join(", ")}};`);
|
|
349
|
+
charLiterals = [];
|
|
350
|
+
const fieldExpr = `input.${maybeEscapeLowerCaseName(name.text)}`;
|
|
351
|
+
source.internalMain.push(` ::skir_internal::Append(${fieldExpr}, out);`);
|
|
352
|
+
source.internalMain.push(` if (array_len == ${number + 1}) return;`);
|
|
353
|
+
lastFieldNumber = number;
|
|
354
|
+
charLiterals.push("','");
|
|
355
|
+
}
|
|
356
|
+
for (let i = numSlots; i < numSlotsInclRemovedNumbers; ++i) {
|
|
357
|
+
charLiterals.push("'0'");
|
|
358
|
+
charLiterals.push("','");
|
|
359
|
+
}
|
|
360
|
+
source.internalMain.push(` out.out += {${charLiterals.join(", ")}};`);
|
|
361
|
+
source.internalMain.push(" unrecognized->values.AppendTo(out);");
|
|
362
|
+
source.internalMain.push("}");
|
|
363
|
+
source.internalMain.push("");
|
|
364
|
+
}
|
|
365
|
+
{
|
|
366
|
+
// Append(const T&, ReadableJson&)
|
|
367
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, ReadableJson& out) {`);
|
|
368
|
+
if (fields.length) {
|
|
369
|
+
source.internalMain.push(" JsonObjectWriter(&out)");
|
|
370
|
+
for (const field of fields) {
|
|
371
|
+
const isLastField = field === fields.at(-1);
|
|
372
|
+
const maybeSemicolon = isLastField ? ";" : "";
|
|
373
|
+
const name = field.name.text;
|
|
374
|
+
const fieldExpr = `input.${maybeEscapeLowerCaseName(name)}`;
|
|
375
|
+
source.internalMain.push(` .Write("${name}", ${fieldExpr})${maybeSemicolon}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
source.internalMain.push(" out.out += {'{', '}'};");
|
|
380
|
+
}
|
|
381
|
+
source.internalMain.push("}");
|
|
382
|
+
source.internalMain.push("");
|
|
383
|
+
}
|
|
384
|
+
{
|
|
385
|
+
// Append(const T&, DebugString&)
|
|
386
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, DebugString& out) {`);
|
|
387
|
+
if (fields.length) {
|
|
388
|
+
source.internalMain.push(" DebugObjectWriter(&out)");
|
|
389
|
+
for (const field of fields) {
|
|
390
|
+
const isLastField = field === fields.at(-1);
|
|
391
|
+
const maybeSemicolon = isLastField ? ";" : "";
|
|
392
|
+
const name = maybeEscapeLowerCaseName(field.name.text);
|
|
393
|
+
const fieldExpr = `input.${name}`;
|
|
394
|
+
source.internalMain.push(` .Write("${name}", ${fieldExpr})${maybeSemicolon}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
source.internalMain.push(" out.out += {'{', '}'};");
|
|
399
|
+
}
|
|
400
|
+
source.internalMain.push("}");
|
|
401
|
+
source.internalMain.push("");
|
|
402
|
+
}
|
|
403
|
+
{
|
|
404
|
+
// Append(const T&, ByteSink&)
|
|
405
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, ByteSink& out) {`);
|
|
406
|
+
source.internalMain.push(" const auto& unrecognized = input._unrecognized.data;");
|
|
407
|
+
source.internalMain.push(" const auto array_len = _GetArrayLength(input, unrecognized, skir_internal::UnrecognizedFormat::kBytes);");
|
|
408
|
+
source.internalMain.push(" if (array_len == 0) {");
|
|
409
|
+
source.internalMain.push(" out.Push(246);");
|
|
410
|
+
source.internalMain.push(" return;");
|
|
411
|
+
source.internalMain.push(" }");
|
|
412
|
+
source.internalMain.push(" AppendArrayPrefix(array_len, out);");
|
|
413
|
+
let lastFieldNumber = -1;
|
|
414
|
+
for (const field of fieldsByNumber) {
|
|
415
|
+
const { number, name } = field;
|
|
416
|
+
const isLastField = field === fieldsByNumber.at(-1);
|
|
417
|
+
if (lastFieldNumber < number - 1) {
|
|
418
|
+
// Append one 0 for every removed number.
|
|
419
|
+
const zeros = "0, ".repeat(number - lastFieldNumber - 1).slice(0, -2);
|
|
420
|
+
source.internalMain.push(` out.Push(${zeros});`);
|
|
421
|
+
}
|
|
422
|
+
const fieldExpr = `input.${maybeEscapeLowerCaseName(name.text)}`;
|
|
423
|
+
source.internalMain.push(` ::skir_internal::Append(${fieldExpr}, out);`);
|
|
424
|
+
if (!isLastField) {
|
|
425
|
+
source.internalMain.push(` if (array_len == ${number + 1}) return;`);
|
|
426
|
+
}
|
|
427
|
+
lastFieldNumber = number;
|
|
428
|
+
}
|
|
429
|
+
source.internalMain.push(` if (array_len == ${lastFieldNumber + 1}) return;`);
|
|
430
|
+
if (numSlots < numSlotsInclRemovedNumbers) {
|
|
431
|
+
// Append one 0 for every removed number at the end of the struct.
|
|
432
|
+
const zeros = "0, "
|
|
433
|
+
.repeat(numSlotsInclRemovedNumbers - numSlots)
|
|
434
|
+
.slice(0, -2);
|
|
435
|
+
source.internalMain.push(` out.Push(${zeros});`);
|
|
436
|
+
}
|
|
437
|
+
source.internalMain.push(" unrecognized->values.AppendTo(out);");
|
|
438
|
+
source.internalMain.push("}");
|
|
439
|
+
source.internalMain.push("");
|
|
440
|
+
}
|
|
441
|
+
{
|
|
442
|
+
// Parse(JsonTokenizer&, T&)
|
|
443
|
+
source.internalMain.push(`void ${adapterName}::Parse(`);
|
|
444
|
+
source.internalMain.push(" JsonTokenizer& tokenizer,");
|
|
445
|
+
source.internalMain.push(" type& out) {");
|
|
446
|
+
source.internalMain.push(" switch (tokenizer.state().token_type) {");
|
|
447
|
+
source.internalMain.push(" case JsonTokenType::kLeftSquareBracket: {");
|
|
448
|
+
source.internalMain.push(" JsonArrayReader array_reader(&tokenizer);");
|
|
449
|
+
let lastNumber = -1;
|
|
450
|
+
for (const field of fieldsByNumber) {
|
|
451
|
+
const ccFieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
452
|
+
source.internalMain.push(" if (!array_reader.NextElement()) break;");
|
|
453
|
+
for (let i = lastNumber + 1; i < field.number; ++i) {
|
|
454
|
+
source.internalMain.push(" SkipValue(tokenizer);");
|
|
455
|
+
source.internalMain.push(" if (!array_reader.NextElement()) break;");
|
|
456
|
+
}
|
|
457
|
+
source.internalMain.push(` ::skir_internal::Parse(tokenizer, out.${ccFieldName});`);
|
|
458
|
+
lastNumber = field.number;
|
|
459
|
+
}
|
|
460
|
+
source.internalMain.push(" if (!array_reader.NextElement()) break;");
|
|
461
|
+
source.internalMain.push(" auto& unrecognized = out._unrecognized.data;");
|
|
462
|
+
const args = [
|
|
463
|
+
"array_reader",
|
|
464
|
+
numSlots,
|
|
465
|
+
numSlotsInclRemovedNumbers,
|
|
466
|
+
"unrecognized",
|
|
467
|
+
].join(", ");
|
|
468
|
+
source.internalMain.push(` ::skir_internal::ParseUnrecognizedFields(${args});`);
|
|
469
|
+
source.internalMain.push(" break;");
|
|
470
|
+
source.internalMain.push(" }");
|
|
471
|
+
source.internalMain.push(" case JsonTokenType::kLeftCurlyBracket: {");
|
|
472
|
+
const parserExpr = "(new StructJsonObjectParser<type>())" +
|
|
473
|
+
fields
|
|
474
|
+
.map((field) => {
|
|
475
|
+
const name = field.name.text;
|
|
476
|
+
const ccFieldName = maybeEscapeLowerCaseName(name);
|
|
477
|
+
const indent = " ";
|
|
478
|
+
return `\n${indent}->AddField("${name}", &type::${ccFieldName})`;
|
|
479
|
+
})
|
|
480
|
+
.join("");
|
|
481
|
+
source.internalMain.push(" static const auto* kParser =");
|
|
482
|
+
source.internalMain.push(` ${parserExpr};`);
|
|
483
|
+
source.internalMain.push(" kParser->Parse(tokenizer, out);");
|
|
484
|
+
source.internalMain.push(" break;");
|
|
485
|
+
source.internalMain.push(" }");
|
|
486
|
+
source.internalMain.push(" case JsonTokenType::kZero:");
|
|
487
|
+
source.internalMain.push(" tokenizer.Next();");
|
|
488
|
+
source.internalMain.push(" break;");
|
|
489
|
+
source.internalMain.push(" default: {");
|
|
490
|
+
source.internalMain.push(" tokenizer.mutable_state().PushUnexpectedTokenError(\"'['\");");
|
|
491
|
+
source.internalMain.push(" }");
|
|
492
|
+
source.internalMain.push(" }");
|
|
493
|
+
source.internalMain.push("}");
|
|
494
|
+
source.internalMain.push("");
|
|
495
|
+
}
|
|
496
|
+
{
|
|
497
|
+
// Parse(ByteSource&, T&)
|
|
498
|
+
source.internalMain.push(`void ${adapterName}::Parse(ByteSource& source, type& out) {`);
|
|
499
|
+
source.internalMain.push(" ::uint32_t array_len = 0;");
|
|
500
|
+
source.internalMain.push(" ParseArrayPrefix(source, array_len);");
|
|
501
|
+
let lastNumber = -1;
|
|
502
|
+
for (const field of fieldsByNumber) {
|
|
503
|
+
const ccFieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
504
|
+
for (let i = lastNumber + 1; i < field.number; ++i) {
|
|
505
|
+
source.internalMain.push(` if (array_len == ${i}) return;`);
|
|
506
|
+
source.internalMain.push(" SkipValue(source);");
|
|
507
|
+
}
|
|
508
|
+
source.internalMain.push(` if (array_len == ${field.number}) return;`);
|
|
509
|
+
source.internalMain.push(` ::skir_internal::Parse(source, out.${ccFieldName});`);
|
|
510
|
+
lastNumber = field.number;
|
|
511
|
+
}
|
|
512
|
+
source.internalMain.push(` if (array_len == ${numSlots}) return;`);
|
|
513
|
+
source.internalMain.push(" auto& unrecognized = out._unrecognized.data;");
|
|
514
|
+
const args = [
|
|
515
|
+
"source",
|
|
516
|
+
"array_len",
|
|
517
|
+
numSlots,
|
|
518
|
+
numSlotsInclRemovedNumbers,
|
|
519
|
+
"unrecognized",
|
|
520
|
+
].join(", ");
|
|
521
|
+
source.internalMain.push(` ::skir_internal::ParseUnrecognizedFields(${args});`);
|
|
522
|
+
source.internalMain.push("}");
|
|
523
|
+
source.internalMain.push("");
|
|
524
|
+
}
|
|
525
|
+
{
|
|
526
|
+
// GetType(skir_type<T>)
|
|
527
|
+
source.internalMain.push(`skir::reflection::Type ${adapterName}::GetType(skir_type<type>) {`);
|
|
528
|
+
const recordId = getRecordId(struct);
|
|
529
|
+
source.internalMain.push(` return skir::reflection::RecordType({"${recordId}"});`);
|
|
530
|
+
source.internalMain.push("}");
|
|
531
|
+
source.internalMain.push("");
|
|
532
|
+
}
|
|
533
|
+
{
|
|
534
|
+
// RegisterRecords(skir_type<T>, RecordRegistry&)
|
|
535
|
+
const recordId = getRecordId(struct);
|
|
536
|
+
source.internalMain.push(`void ${adapterName}::RegisterRecords(`);
|
|
537
|
+
source.internalMain.push(" skir_type<type>,");
|
|
538
|
+
source.internalMain.push(" skir::reflection::RecordRegistry& registry) {");
|
|
539
|
+
source.internalMain.push(" const bool already_present =");
|
|
540
|
+
source.internalMain.push(` registry.find_or_null("${recordId}") != nullptr;`);
|
|
541
|
+
source.internalMain.push(" if (already_present) return;");
|
|
542
|
+
source.internalMain.push(" skir::reflection::Struct record = {");
|
|
543
|
+
source.internalMain.push(` "${recordId}",`);
|
|
544
|
+
source.internalMain.push(` ${JSON.stringify(struct.record.doc.text)},`);
|
|
545
|
+
source.internalMain.push(" {");
|
|
546
|
+
for (const field of fields) {
|
|
547
|
+
const ccType = typeSpeller.getCcType(field.type, {
|
|
548
|
+
forceNamespace: true,
|
|
549
|
+
});
|
|
550
|
+
source.internalMain.push(" {");
|
|
551
|
+
source.internalMain.push(` "${field.name.text}",`);
|
|
552
|
+
source.internalMain.push(` ${field.number},`);
|
|
553
|
+
source.internalMain.push(` skir_internal::GetType<${ccType}>(),`);
|
|
554
|
+
source.internalMain.push(` ${JSON.stringify(field.doc.text)},`);
|
|
555
|
+
source.internalMain.push(" },");
|
|
556
|
+
}
|
|
557
|
+
source.internalMain.push(" },");
|
|
558
|
+
const removedNumbers = struct.record.removedNumbers.join(", ");
|
|
559
|
+
source.internalMain.push(` {${removedNumbers}},`);
|
|
560
|
+
source.internalMain.push(" };");
|
|
561
|
+
source.internalMain.push(" registry.push_back(std::move(record));");
|
|
562
|
+
for (const field of fields) {
|
|
563
|
+
const ccType = typeSpeller.getCcType(field.type, {
|
|
564
|
+
forceNamespace: true,
|
|
565
|
+
});
|
|
566
|
+
source.internalMain.push(` skir_internal::RegisterRecords<${ccType}>(registry);`);
|
|
567
|
+
}
|
|
568
|
+
source.internalMain.push("}");
|
|
569
|
+
source.internalMain.push("");
|
|
570
|
+
}
|
|
571
|
+
{
|
|
572
|
+
// Struct::operator==(const T&)
|
|
573
|
+
source.mainBottom.push(`bool ${className}::operator==(${constRefType} other) const {`);
|
|
574
|
+
const expression = fields.length
|
|
575
|
+
? fields
|
|
576
|
+
.map((f) => {
|
|
577
|
+
const fieldName = maybeEscapeLowerCaseName(f.name.text);
|
|
578
|
+
return `this->${fieldName} == other.${fieldName}`;
|
|
579
|
+
})
|
|
580
|
+
.join("\n && ")
|
|
581
|
+
: "true";
|
|
582
|
+
source.mainBottom.push(` return ${expression};`);
|
|
583
|
+
source.mainBottom.push("}");
|
|
584
|
+
source.mainBottom.push("");
|
|
585
|
+
}
|
|
586
|
+
{
|
|
587
|
+
// Whole -> Struct
|
|
588
|
+
source.mainBottom.push(`${className}::whole::operator ${className}() {`);
|
|
589
|
+
source.mainBottom.push(` return ${className}{`);
|
|
590
|
+
for (const field of fieldsByName) {
|
|
591
|
+
const fieldName = maybeEscapeLowerCaseName(field.name.text);
|
|
592
|
+
source.mainBottom.push(` *std::move(${fieldName}),`);
|
|
593
|
+
}
|
|
594
|
+
source.mainBottom.push(" };");
|
|
595
|
+
source.mainBottom.push("}");
|
|
596
|
+
source.mainBottom.push("");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
writeCodeForEnum(record) {
|
|
600
|
+
const { header, recordMap, source, typeSpeller } = this;
|
|
601
|
+
const { nestedRecords } = record.record;
|
|
602
|
+
const variants = getEnumVariants(record.record.fields, typeSpeller);
|
|
603
|
+
const constVariants = variants.filter((f) => !f.valueType);
|
|
604
|
+
const wrapperVariants = variants.filter((f) => f.valueType);
|
|
605
|
+
const pointerVariants = wrapperVariants.filter((f) => f.usePointer);
|
|
606
|
+
for (const variant of constVariants) {
|
|
607
|
+
this.writeCodeForConstantVariant(variant);
|
|
608
|
+
}
|
|
609
|
+
for (const variant of wrapperVariants) {
|
|
610
|
+
this.writeCodeForWrapperVariant(variant);
|
|
611
|
+
}
|
|
612
|
+
const className = getClassName(record);
|
|
613
|
+
const adapterName = `${className}Adapter`;
|
|
614
|
+
const qualifiedName = `::${this.namespace}::${className}`;
|
|
615
|
+
const constRefType = `const ${qualifiedName}&`;
|
|
616
|
+
header.mainTop.push(`class ${className};`);
|
|
617
|
+
header.mainMiddle.push(...commentify(docToCommentText(record.record.doc)));
|
|
618
|
+
header.mainMiddle.push(`class ${className} {`);
|
|
619
|
+
header.mainMiddle.push(" public:");
|
|
620
|
+
for (const variant of wrapperVariants) {
|
|
621
|
+
const type = `::skirout::${variant.structType}<${variant.valueType}>`;
|
|
622
|
+
header.mainMiddle.push(` using ${variant.typeAlias} = ${type};`);
|
|
623
|
+
}
|
|
624
|
+
header.mainMiddle.push("");
|
|
625
|
+
header.mainMiddle.push(` // Identifies the possible variants held by a ${className}.`);
|
|
626
|
+
header.mainMiddle.push(" enum class kind_type {");
|
|
627
|
+
for (const variant of variants) {
|
|
628
|
+
header.mainMiddle.push(...commentify(variant.isUnknownVariant
|
|
629
|
+
? `Constant indicating an unknown ${className}.\n`
|
|
630
|
+
: docToCommentText(variant.doc), " "));
|
|
631
|
+
header.mainMiddle.push(` ${variant.kindEnumerator},`);
|
|
632
|
+
}
|
|
633
|
+
header.mainMiddle.push(" };");
|
|
634
|
+
header.mainMiddle.push("");
|
|
635
|
+
for (const variant of constVariants) {
|
|
636
|
+
const { identifier, isUnknownVariant, kindEnumerator, structType } = variant;
|
|
637
|
+
const assignment = isUnknownVariant ? " = ::skirout::kUnknown" : "";
|
|
638
|
+
header.mainMiddle.push(` // For example: FunctionExpecting${className}(skirout::${identifier})`);
|
|
639
|
+
header.mainMiddle.push(` ${className}(::skirout::${structType}${assignment});`);
|
|
640
|
+
const body = isUnknownVariant
|
|
641
|
+
? "{\n value_._unrecognized = nullptr;\n}"
|
|
642
|
+
: "{}";
|
|
643
|
+
source.mainMiddle.push(`${className}::${className}(::skirout::${structType}) : kind_(kind_type::${kindEnumerator}) ${body}`);
|
|
644
|
+
}
|
|
645
|
+
source.mainMiddle.push("");
|
|
646
|
+
for (const variant of wrapperVariants) {
|
|
647
|
+
const { identifier, kindEnumerator, typeAlias, usePointer, variantName } = variant;
|
|
648
|
+
header.mainMiddle.push(` // For example: FunctionExpecting${className}(skirout::${identifier}(...))`);
|
|
649
|
+
header.mainMiddle.push(` ${className}(${typeAlias});`);
|
|
650
|
+
source.mainMiddle.push(`${className}::${className}(${typeAlias} w)`);
|
|
651
|
+
source.mainMiddle.push(` : kind_(kind_type::${kindEnumerator}) {`);
|
|
652
|
+
if (usePointer) {
|
|
653
|
+
source.mainMiddle.push(` value_.${variantName}_ = new ${typeAlias}(std::move(w));`);
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
source.mainMiddle.push(` value_.${variantName}_ = w;`);
|
|
657
|
+
}
|
|
658
|
+
source.mainMiddle.push("}");
|
|
659
|
+
source.mainMiddle.push("");
|
|
660
|
+
}
|
|
661
|
+
header.mainMiddle.push("");
|
|
662
|
+
header.mainMiddle.push(` ${className}(const ${className}&);`);
|
|
663
|
+
source.mainMiddle.push(`${className}::${className}(const ${className}& other) {`);
|
|
664
|
+
source.mainMiddle.push(" copy(other);");
|
|
665
|
+
source.mainMiddle.push("}");
|
|
666
|
+
source.mainMiddle.push("");
|
|
667
|
+
header.mainMiddle.push(` ${className}(${className}&&);`);
|
|
668
|
+
header.mainMiddle.push("");
|
|
669
|
+
source.mainMiddle.push(`${className}::${className}(${className}&& other)`);
|
|
670
|
+
source.mainMiddle.push(` : kind_(other.kind_),`);
|
|
671
|
+
source.mainMiddle.push(` value_(other.value_) {`);
|
|
672
|
+
source.mainMiddle.push(" other.kind_ = kind_type::kUnknown;");
|
|
673
|
+
source.mainMiddle.push(" other.value_._unrecognized = nullptr;");
|
|
674
|
+
source.mainMiddle.push("}");
|
|
675
|
+
source.mainMiddle.push("");
|
|
676
|
+
{
|
|
677
|
+
source.mainMiddle.push(`${className}::${className}(unrecognized_variant u) : kind_(kind_type::kUnknown) {`);
|
|
678
|
+
source.mainMiddle.push(" value_._unrecognized = new unrecognized_variant(std::move(u));");
|
|
679
|
+
source.mainMiddle.push("}");
|
|
680
|
+
source.mainMiddle.push("");
|
|
681
|
+
}
|
|
682
|
+
header.mainMiddle.push("");
|
|
683
|
+
header.mainMiddle.push(` ~${className}();`);
|
|
684
|
+
header.mainMiddle.push("");
|
|
685
|
+
source.mainMiddle.push(`${className}::~${className}() {`);
|
|
686
|
+
source.mainMiddle.push(" free_value();");
|
|
687
|
+
source.mainMiddle.push("}");
|
|
688
|
+
source.mainMiddle.push("");
|
|
689
|
+
for (const variant of constVariants) {
|
|
690
|
+
const { identifier } = variant;
|
|
691
|
+
header.mainMiddle.push(` static constexpr auto ${identifier} = ::skirout::${identifier};`);
|
|
692
|
+
}
|
|
693
|
+
header.mainMiddle.push("");
|
|
694
|
+
for (const variant of wrapperVariants) {
|
|
695
|
+
const { identifier, usePointer, valueType } = variant;
|
|
696
|
+
header.mainMiddle.push(` static ${className} ${identifier}(${valueType} value);`);
|
|
697
|
+
source.mainMiddle.push(`${className} ${className}::${identifier}(${valueType} value) {`);
|
|
698
|
+
const maybeMoveValue = usePointer ? "std::move(value)" : "value";
|
|
699
|
+
const returnValue = `${className}(::skirout::${identifier}(${maybeMoveValue}))`;
|
|
700
|
+
source.mainMiddle.push(` return ${returnValue};`);
|
|
701
|
+
source.mainMiddle.push("}");
|
|
702
|
+
source.mainMiddle.push("");
|
|
703
|
+
}
|
|
704
|
+
header.mainMiddle.push("");
|
|
705
|
+
header.mainMiddle.push(` // Returns the kind of variant held by this ${className}.`);
|
|
706
|
+
header.mainMiddle.push(" kind_type kind() const { return kind_; }");
|
|
707
|
+
header.mainMiddle.push("");
|
|
708
|
+
for (const variant of wrapperVariants) {
|
|
709
|
+
const { variantName, kindEnumerator, usePointer, valueType } = variant;
|
|
710
|
+
header.mainMiddle.push(` // Returns true if this ${className} holds a ${variantName} variant.`);
|
|
711
|
+
header.mainMiddle.push(` inline bool is_${variantName}() const;`);
|
|
712
|
+
header.mainMiddle.push(` // Assuming this ${className} holds a ${variantName} variant, returns its value.`);
|
|
713
|
+
header.mainMiddle.push(` inline const ${valueType}& as_${variantName}() const;`);
|
|
714
|
+
header.mainMiddle.push(` inline ${valueType}& as_${variantName}();`);
|
|
715
|
+
header.mainMiddle.push("");
|
|
716
|
+
header.mainBottom.push(`inline bool ${className}::is_${variantName}() const {`);
|
|
717
|
+
(header.mainBottom.push(` return kind_ == kind_type::${kindEnumerator};`),
|
|
718
|
+
header.mainBottom.push("}"));
|
|
719
|
+
header.mainBottom.push("");
|
|
720
|
+
header.mainBottom.push(`inline const ${valueType}& ${className}::as_${variantName}() const {`);
|
|
721
|
+
header.mainBottom.push(` return const_cast<${className}*>(this)->as_${variantName}();`);
|
|
722
|
+
header.mainBottom.push("}");
|
|
723
|
+
header.mainBottom.push("");
|
|
724
|
+
header.mainBottom.push(`inline ${valueType}& ${className}::as_${variantName}() {`);
|
|
725
|
+
header.mainBottom.push(` ABSL_CHECK(is_${variantName}()) << "actual: " << *this;`);
|
|
726
|
+
const returnValue = usePointer
|
|
727
|
+
? `value_.${variantName}_->value`
|
|
728
|
+
: `value_.${variantName}_.value`;
|
|
729
|
+
header.mainBottom.push(` return ${returnValue};`);
|
|
730
|
+
header.mainBottom.push("}");
|
|
731
|
+
header.mainBottom.push("");
|
|
732
|
+
}
|
|
733
|
+
{
|
|
734
|
+
const commentLines = ["Example:", "", " struct visitor {"];
|
|
735
|
+
for (const variant of constVariants) {
|
|
736
|
+
const { structType } = variant;
|
|
737
|
+
commentLines.push(` void operator()(skirout::${structType}) { ... }`);
|
|
738
|
+
}
|
|
739
|
+
for (const variant of wrapperVariants) {
|
|
740
|
+
const { structType } = variant;
|
|
741
|
+
commentLines.push(` void operator()(const ${className}::${structType}& w) {`);
|
|
742
|
+
commentLines.push(" const auto& value = w.value;");
|
|
743
|
+
commentLines.push(" ...");
|
|
744
|
+
commentLines.push(" }");
|
|
745
|
+
}
|
|
746
|
+
commentLines.push(" };");
|
|
747
|
+
commentLines.push(" e.visit(visitor());");
|
|
748
|
+
header.mainMiddle.push(...commentify(commentLines, " "));
|
|
749
|
+
}
|
|
750
|
+
header.mainMiddle.push(" template <typename Visitor>");
|
|
751
|
+
header.mainMiddle.push(" decltype(auto) visit(Visitor&& visitor) const {");
|
|
752
|
+
header.mainMiddle.push(` return visit_impl(*this, std::forward<Visitor>(visitor));`);
|
|
753
|
+
header.mainMiddle.push(" }");
|
|
754
|
+
header.mainMiddle.push(" template <typename Visitor>");
|
|
755
|
+
header.mainMiddle.push(" decltype(auto) visit(Visitor&& visitor) {");
|
|
756
|
+
header.mainMiddle.push(` return visit_impl(*this, std::forward<Visitor>(visitor));`);
|
|
757
|
+
header.mainMiddle.push(" }");
|
|
758
|
+
header.mainMiddle.push("");
|
|
759
|
+
header.mainMiddle.push(` ${className}& operator=(const ${className}& other);`);
|
|
760
|
+
source.mainMiddle.push(`${className}& ${className}::operator=(const ${className}& other) {`);
|
|
761
|
+
source.mainMiddle.push(" free_value();");
|
|
762
|
+
source.mainMiddle.push(" copy(other);");
|
|
763
|
+
source.mainMiddle.push(" return *this;");
|
|
764
|
+
source.mainMiddle.push("}");
|
|
765
|
+
source.mainMiddle.push("");
|
|
766
|
+
header.mainMiddle.push(` ${className}& operator=(${className}&& other);`);
|
|
767
|
+
source.mainMiddle.push(`${className}& ${className}::operator=(${className}&& other) {`);
|
|
768
|
+
source.mainMiddle.push(" free_value();");
|
|
769
|
+
source.mainMiddle.push(" kind_ = other.kind_;");
|
|
770
|
+
source.mainMiddle.push(" value_ = other.value_;");
|
|
771
|
+
source.mainMiddle.push(" other.kind_ = kind_type::kUnknown;");
|
|
772
|
+
source.mainMiddle.push(" other.value_._unrecognized = nullptr;");
|
|
773
|
+
source.mainMiddle.push(" return *this;");
|
|
774
|
+
source.mainMiddle.push("}");
|
|
775
|
+
source.mainMiddle.push("");
|
|
776
|
+
header.mainMiddle.push("");
|
|
777
|
+
for (const variant of constVariants) {
|
|
778
|
+
const { isUnknownVariant, kindEnumerator, structType } = variant;
|
|
779
|
+
header.mainMiddle.push(` ${className}& operator=(::skirout::${structType});`);
|
|
780
|
+
source.mainMiddle.push(`${className}& ${className}::operator=(::skirout::${structType}) {`);
|
|
781
|
+
source.mainMiddle.push(" free_value();");
|
|
782
|
+
source.mainMiddle.push(` kind_ = kind_type::${kindEnumerator};`);
|
|
783
|
+
if (isUnknownVariant) {
|
|
784
|
+
source.mainMiddle.push(" value_._unrecognized = nullptr;");
|
|
785
|
+
}
|
|
786
|
+
source.mainMiddle.push(" return *this;");
|
|
787
|
+
source.mainMiddle.push("}");
|
|
788
|
+
source.mainMiddle.push("");
|
|
789
|
+
}
|
|
790
|
+
for (const variant of wrapperVariants) {
|
|
791
|
+
const { variantName, kindEnumerator, typeAlias, usePointer } = variant;
|
|
792
|
+
header.mainMiddle.push(` ${className}& operator=(${typeAlias});`);
|
|
793
|
+
source.mainMiddle.push(`${className}& ${className}::operator=(${typeAlias} w) {`);
|
|
794
|
+
source.mainMiddle.push(" free_value();");
|
|
795
|
+
source.mainMiddle.push(` kind_ = kind_type::${kindEnumerator};`);
|
|
796
|
+
if (usePointer) {
|
|
797
|
+
source.mainMiddle.push(` value_.${variantName}_ = new ${typeAlias}(std::move(w));`);
|
|
798
|
+
}
|
|
799
|
+
else {
|
|
800
|
+
source.mainMiddle.push(` value_.${variantName}_ = w;`);
|
|
801
|
+
}
|
|
802
|
+
source.mainMiddle.push(" return *this;");
|
|
803
|
+
source.mainMiddle.push("}");
|
|
804
|
+
source.mainMiddle.push("");
|
|
805
|
+
}
|
|
806
|
+
header.mainMiddle.push("");
|
|
807
|
+
if (wrapperVariants.length) {
|
|
808
|
+
header.mainMiddle.push(` bool operator==(const ${className}&) const;`);
|
|
809
|
+
source.mainMiddle.push(`bool ${className}::operator==(const ${className}& other) const {`);
|
|
810
|
+
source.mainMiddle.push(" if (other.kind_ != kind_) return false;");
|
|
811
|
+
source.mainMiddle.push(" switch (kind_) {");
|
|
812
|
+
for (const variant of wrapperVariants) {
|
|
813
|
+
const { variantName, kindEnumerator, usePointer } = variant;
|
|
814
|
+
const dotOrStar = usePointer ? "->" : ".";
|
|
815
|
+
const a = `value_.${variantName}_${dotOrStar}value`;
|
|
816
|
+
const b = `other.value_.${variantName}_${dotOrStar}value`;
|
|
817
|
+
source.mainMiddle.push(` case kind_type::${kindEnumerator}:`);
|
|
818
|
+
source.mainMiddle.push(` return ${a} == ${b};`);
|
|
819
|
+
}
|
|
820
|
+
source.mainMiddle.push(` default:`);
|
|
821
|
+
source.mainMiddle.push(" return true;");
|
|
822
|
+
source.mainMiddle.push(" }");
|
|
823
|
+
source.mainMiddle.push("}");
|
|
824
|
+
source.mainMiddle.push("");
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
header.mainMiddle.push(` inline bool operator==(const ${className}& other) const {`);
|
|
828
|
+
header.mainMiddle.push(" return other.kind_ == kind_;");
|
|
829
|
+
header.mainMiddle.push(" }");
|
|
830
|
+
}
|
|
831
|
+
header.mainMiddle.push("");
|
|
832
|
+
header.mainMiddle.push(` inline bool operator!=(const ${className}& other) const {`);
|
|
833
|
+
header.mainMiddle.push(" return !(*this == other);");
|
|
834
|
+
header.mainMiddle.push(" }");
|
|
835
|
+
header.mainMiddle.push("");
|
|
836
|
+
for (const nestedRecord of nestedRecords) {
|
|
837
|
+
let typeAlias = nestedRecord.name.text;
|
|
838
|
+
if (typeAlias === className) {
|
|
839
|
+
typeAlias = `${typeAlias}_`;
|
|
840
|
+
}
|
|
841
|
+
const recordLocation = recordMap.get(nestedRecord.key);
|
|
842
|
+
const nestedClassName = getClassName(recordLocation);
|
|
843
|
+
header.mainMiddle.push(` using ${typeAlias} = ${nestedClassName};`);
|
|
844
|
+
}
|
|
845
|
+
header.mainMiddle.push("");
|
|
846
|
+
header.mainMiddle.push(" private:");
|
|
847
|
+
header.mainMiddle.push(" using unrecognized_variant = ::skir_internal::UnrecognizedVariant;");
|
|
848
|
+
header.mainMiddle.push("");
|
|
849
|
+
header.mainMiddle.push(` ${className}(unrecognized_variant);`);
|
|
850
|
+
header.mainMiddle.push("");
|
|
851
|
+
header.mainMiddle.push(" kind_type kind_;");
|
|
852
|
+
header.mainMiddle.push("");
|
|
853
|
+
header.mainMiddle.push(" union value_wrapper {");
|
|
854
|
+
header.mainMiddle.push(" value_wrapper() {}");
|
|
855
|
+
header.mainMiddle.push(" unrecognized_variant* _unrecognized;");
|
|
856
|
+
for (const variant of wrapperVariants) {
|
|
857
|
+
const { variantName, typeAlias } = variant;
|
|
858
|
+
const maybeStar = variant.usePointer ? "*" : "";
|
|
859
|
+
header.mainMiddle.push(` ${typeAlias}${maybeStar} ${variantName}_;`);
|
|
860
|
+
}
|
|
861
|
+
header.mainMiddle.push(" };");
|
|
862
|
+
header.mainMiddle.push(" value_wrapper value_;");
|
|
863
|
+
header.mainMiddle.push("");
|
|
864
|
+
header.mainMiddle.push(` void copy(const ${className}&);`);
|
|
865
|
+
source.mainMiddle.push(`void ${className}::copy(const ${className}& other) {`);
|
|
866
|
+
source.mainMiddle.push(" kind_ = other.kind_;");
|
|
867
|
+
source.mainMiddle.push(" switch (other.kind_) {");
|
|
868
|
+
source.mainMiddle.push(" case kind_type::kUnknown: {");
|
|
869
|
+
source.mainMiddle.push(" const unrecognized_variant* u = other.value_._unrecognized;");
|
|
870
|
+
source.mainMiddle.push(" value_._unrecognized = u != nullptr ? new unrecognized_variant(*u) : nullptr;");
|
|
871
|
+
source.mainMiddle.push(" break;");
|
|
872
|
+
source.mainMiddle.push(" }");
|
|
873
|
+
for (const variant of wrapperVariants) {
|
|
874
|
+
const { variantName, kindEnumerator, typeAlias, usePointer } = variant;
|
|
875
|
+
source.mainMiddle.push(` case kind_type::${kindEnumerator}:`);
|
|
876
|
+
if (usePointer) {
|
|
877
|
+
const expr = `new ${typeAlias}(*other.value_.${variantName}_)`;
|
|
878
|
+
source.mainMiddle.push(` value_.${variantName}_ = ${expr};`);
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
source.mainMiddle.push(` value_.${variantName}_ = other.value_.${variantName}_;`);
|
|
882
|
+
}
|
|
883
|
+
source.mainMiddle.push(" break;");
|
|
884
|
+
}
|
|
885
|
+
source.mainMiddle.push(" default:");
|
|
886
|
+
source.mainMiddle.push(" break;");
|
|
887
|
+
source.mainMiddle.push(" }");
|
|
888
|
+
source.mainMiddle.push("}");
|
|
889
|
+
source.mainMiddle.push("");
|
|
890
|
+
header.mainMiddle.push(" void free_value() const;");
|
|
891
|
+
source.mainMiddle.push(`void ${className}::free_value() const {`);
|
|
892
|
+
source.mainMiddle.push(" switch (kind_) {");
|
|
893
|
+
source.mainMiddle.push(" case kind_type::kUnknown:");
|
|
894
|
+
source.mainMiddle.push(" ::std::unique_ptr<unrecognized_variant>(value_._unrecognized);");
|
|
895
|
+
source.mainMiddle.push(" break;");
|
|
896
|
+
for (const variant of pointerVariants) {
|
|
897
|
+
const { variantName, kindEnumerator, typeAlias } = variant;
|
|
898
|
+
source.mainMiddle.push(` case kind_type::${kindEnumerator}:`);
|
|
899
|
+
source.mainMiddle.push(` ::std::unique_ptr<${typeAlias}>(value_.${variantName}_);`);
|
|
900
|
+
source.mainMiddle.push(" break;");
|
|
901
|
+
}
|
|
902
|
+
source.mainMiddle.push(" default:");
|
|
903
|
+
source.mainMiddle.push(" break;");
|
|
904
|
+
source.mainMiddle.push(" }");
|
|
905
|
+
source.mainMiddle.push("}");
|
|
906
|
+
source.mainMiddle.push("");
|
|
907
|
+
header.mainMiddle.push("");
|
|
908
|
+
header.mainMiddle.push(" template <typename E, typename Visitor>");
|
|
909
|
+
header.mainMiddle.push(" static decltype(auto) visit_impl(E& e, Visitor&& visitor) {");
|
|
910
|
+
header.mainMiddle.push(" switch (e.kind_) {");
|
|
911
|
+
for (const variant of constVariants) {
|
|
912
|
+
const { kindEnumerator, structType } = variant;
|
|
913
|
+
header.mainMiddle.push(` case kind_type::${kindEnumerator}:`);
|
|
914
|
+
header.mainMiddle.push(` return std::forward<Visitor>(visitor)(::skirout::${structType}());`);
|
|
915
|
+
}
|
|
916
|
+
for (const variant of wrapperVariants) {
|
|
917
|
+
const { variantName, kindEnumerator, usePointer } = variant;
|
|
918
|
+
const maybeStar = usePointer ? "*" : "";
|
|
919
|
+
header.mainMiddle.push(` case kind_type::${kindEnumerator}:`);
|
|
920
|
+
header.mainMiddle.push(` return std::forward<Visitor>(visitor)(${maybeStar}e.value_.${variantName}_);`);
|
|
921
|
+
}
|
|
922
|
+
header.mainMiddle.push(" }");
|
|
923
|
+
header.mainMiddle.push(" ABSL_CHECK(false);");
|
|
924
|
+
header.mainMiddle.push(" }");
|
|
925
|
+
header.mainMiddle.push("");
|
|
926
|
+
header.mainMiddle.push(` friend class ::skir_internal::${this.namespace}::${adapterName};`);
|
|
927
|
+
header.mainMiddle.push("};");
|
|
928
|
+
header.mainMiddle.push("");
|
|
929
|
+
for (const variant of constVariants) {
|
|
930
|
+
const { kindEnumerator, structType } = variant;
|
|
931
|
+
header.mainBottom.push("inline bool operator==(");
|
|
932
|
+
header.mainBottom.push(` ${constRefType} a,`);
|
|
933
|
+
header.mainBottom.push(` ::skirout::${structType}) {`);
|
|
934
|
+
header.mainBottom.push(` return a.kind() == ${qualifiedName}::kind_type::${kindEnumerator};`);
|
|
935
|
+
header.mainBottom.push("}");
|
|
936
|
+
header.mainBottom.push("");
|
|
937
|
+
header.mainBottom.push("inline bool operator!=(");
|
|
938
|
+
header.mainBottom.push(` ${constRefType} a,`);
|
|
939
|
+
header.mainBottom.push(` ::skirout::${structType} b) {`);
|
|
940
|
+
header.mainBottom.push(" return !(a == b);");
|
|
941
|
+
header.mainBottom.push("}");
|
|
942
|
+
header.mainBottom.push("");
|
|
943
|
+
header.mainBottom.push("inline bool operator==(");
|
|
944
|
+
header.mainBottom.push(` ::skirout::${variant.structType},`);
|
|
945
|
+
header.mainBottom.push(` ${constRefType} b) {`);
|
|
946
|
+
header.mainBottom.push(` return ${qualifiedName}::kind_type::${kindEnumerator} == b.kind();`);
|
|
947
|
+
header.mainBottom.push("}");
|
|
948
|
+
header.mainBottom.push("");
|
|
949
|
+
header.mainBottom.push("inline bool operator!=(");
|
|
950
|
+
header.mainBottom.push(` ::skirout::${variant.structType} a,`);
|
|
951
|
+
header.mainBottom.push(` ${constRefType} b) {`);
|
|
952
|
+
header.mainBottom.push(" return !(a == b);");
|
|
953
|
+
header.mainBottom.push("}");
|
|
954
|
+
header.mainBottom.push("");
|
|
955
|
+
}
|
|
956
|
+
header.mainBottom.push("template <typename H>");
|
|
957
|
+
header.mainBottom.push(`H AbslHashValue(H h, ${constRefType} input) {`);
|
|
958
|
+
header.mainBottom.push(" struct visitor {");
|
|
959
|
+
header.mainBottom.push(" H h;");
|
|
960
|
+
for (const variant of constVariants) {
|
|
961
|
+
const { variantName, structType } = variant;
|
|
962
|
+
header.mainBottom.push(` H operator()(::skirout::${structType}) {`);
|
|
963
|
+
const hash = simpleHash(variantName);
|
|
964
|
+
header.mainBottom.push(` return H::combine(std::move(h), ${hash});`);
|
|
965
|
+
header.mainBottom.push(" }");
|
|
966
|
+
}
|
|
967
|
+
for (const variant of wrapperVariants) {
|
|
968
|
+
const { variantName, typeAlias } = variant;
|
|
969
|
+
header.mainBottom.push(` H operator()(const ${className}::${typeAlias}& w) {`);
|
|
970
|
+
const hash = simpleHash(variantName);
|
|
971
|
+
header.mainBottom.push(` return H::combine(std::move(h), ${hash}, w.value);`);
|
|
972
|
+
header.mainBottom.push(" }");
|
|
973
|
+
}
|
|
974
|
+
header.mainBottom.push(" };");
|
|
975
|
+
header.mainBottom.push(" return input.visit(visitor{std::move(h)});");
|
|
976
|
+
header.mainBottom.push("}");
|
|
977
|
+
header.mainBottom.push("");
|
|
978
|
+
header.mainMiddle.push("inline std::ostream& operator<<(");
|
|
979
|
+
header.mainMiddle.push(" std::ostream& os,");
|
|
980
|
+
header.mainMiddle.push(` ${constRefType} input) {`);
|
|
981
|
+
header.mainMiddle.push(" return os << ::skir_internal::ToDebugString(input);");
|
|
982
|
+
header.mainMiddle.push("}");
|
|
983
|
+
header.mainMiddle.push("");
|
|
984
|
+
{
|
|
985
|
+
// IsDefault(const T&)
|
|
986
|
+
source.internalMain.push(`bool ${adapterName}::IsDefault(const type& input) {`);
|
|
987
|
+
source.internalMain.push(" return input == ::skirout::kUnknown;");
|
|
988
|
+
source.internalMain.push("}");
|
|
989
|
+
source.internalMain.push("");
|
|
990
|
+
}
|
|
991
|
+
{
|
|
992
|
+
// Append(const T&, DenseJson&)
|
|
993
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, DenseJson& out) {`);
|
|
994
|
+
source.internalMain.push(" switch (input.kind_) {");
|
|
995
|
+
for (const variant of constVariants) {
|
|
996
|
+
const { variantNumber, kindEnumerator, isUnknownVariant } = variant;
|
|
997
|
+
source.internalMain.push(` case type::kind_type::${kindEnumerator}: {`);
|
|
998
|
+
if (isUnknownVariant) {
|
|
999
|
+
source.internalMain.push(" AppendUnrecognizedVariant(input.value_._unrecognized, out);");
|
|
1000
|
+
}
|
|
1001
|
+
else {
|
|
1002
|
+
source.internalMain.push(` out.out += {${numberToCharLiterals(variantNumber)}};`);
|
|
1003
|
+
}
|
|
1004
|
+
source.internalMain.push(" break;");
|
|
1005
|
+
source.internalMain.push(" }");
|
|
1006
|
+
}
|
|
1007
|
+
for (const variant of wrapperVariants) {
|
|
1008
|
+
const { variantName, variantNumber, kindEnumerator, usePointer } = variant;
|
|
1009
|
+
const dotOrArrow = usePointer ? "->" : ".";
|
|
1010
|
+
source.internalMain.push(` case type::kind_type::${kindEnumerator}: {`);
|
|
1011
|
+
source.internalMain.push(` out.out += {'[', ${numberToCharLiterals(variantNumber)}, ','};`);
|
|
1012
|
+
source.internalMain.push(` ::skir_internal::Append(input.value_.${variantName}_${dotOrArrow}value, out);`);
|
|
1013
|
+
source.internalMain.push(" out.out += ']';");
|
|
1014
|
+
source.internalMain.push(" break;");
|
|
1015
|
+
source.internalMain.push(" }");
|
|
1016
|
+
}
|
|
1017
|
+
source.internalMain.push(" }");
|
|
1018
|
+
source.internalMain.push("}");
|
|
1019
|
+
source.internalMain.push("");
|
|
1020
|
+
}
|
|
1021
|
+
{
|
|
1022
|
+
// Append(const T&, ReadableJson&)
|
|
1023
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, ReadableJson& out) {`);
|
|
1024
|
+
source.internalMain.push(" struct visitor {");
|
|
1025
|
+
source.internalMain.push(" ReadableJson& out;");
|
|
1026
|
+
for (const variant of constVariants) {
|
|
1027
|
+
const { variantName, structType } = variant;
|
|
1028
|
+
source.internalMain.push(` void operator()(::skirout::${structType}) {`);
|
|
1029
|
+
source.internalMain.push(` out.out += "\\"${variantName}\\"";`);
|
|
1030
|
+
source.internalMain.push(" }");
|
|
1031
|
+
}
|
|
1032
|
+
for (const variant of wrapperVariants) {
|
|
1033
|
+
const { variantName, typeAlias } = variant;
|
|
1034
|
+
source.internalMain.push(` void operator()(const type::${typeAlias}& w) {`);
|
|
1035
|
+
source.internalMain.push(" out.new_line.Indent();");
|
|
1036
|
+
source.internalMain.push(` absl::StrAppend(&out.out, "{", *out.new_line, "\\"kind\\": \\"${variantName}\\",",`);
|
|
1037
|
+
source.internalMain.push(' *out.new_line, "\\"value\\": ");');
|
|
1038
|
+
source.internalMain.push(" ::skir_internal::Append(w.value, out);");
|
|
1039
|
+
source.internalMain.push(' absl::StrAppend(&out.out, out.new_line.Dedent(), "}");');
|
|
1040
|
+
source.internalMain.push(" }");
|
|
1041
|
+
}
|
|
1042
|
+
source.internalMain.push(" };");
|
|
1043
|
+
source.internalMain.push(" input.visit(visitor{out});");
|
|
1044
|
+
source.internalMain.push("}");
|
|
1045
|
+
source.internalMain.push("");
|
|
1046
|
+
}
|
|
1047
|
+
{
|
|
1048
|
+
// Append(const T&, DebugString&)
|
|
1049
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, DebugString& out) {`);
|
|
1050
|
+
source.internalMain.push(" struct visitor {");
|
|
1051
|
+
source.internalMain.push(" DebugString& out;");
|
|
1052
|
+
for (const variant of constVariants) {
|
|
1053
|
+
const { identifier, structType } = variant;
|
|
1054
|
+
source.internalMain.push(` void operator()(::skirout::${structType}) {`);
|
|
1055
|
+
source.internalMain.push(` out.out += "skirout::${identifier}";`);
|
|
1056
|
+
source.internalMain.push(" }");
|
|
1057
|
+
}
|
|
1058
|
+
for (const variant of wrapperVariants) {
|
|
1059
|
+
const { identifier, typeAlias } = variant;
|
|
1060
|
+
source.internalMain.push(` void operator()(const ${qualifiedName}::${typeAlias}& w) {`);
|
|
1061
|
+
source.internalMain.push(` out.out += "::skirout::${identifier}(";`);
|
|
1062
|
+
source.internalMain.push(" ::skir_internal::Append(w.value, out);");
|
|
1063
|
+
source.internalMain.push(" out.out += ')';");
|
|
1064
|
+
source.internalMain.push(" }");
|
|
1065
|
+
}
|
|
1066
|
+
source.internalMain.push(" };");
|
|
1067
|
+
source.internalMain.push(" input.visit(visitor{out});");
|
|
1068
|
+
source.internalMain.push("}");
|
|
1069
|
+
source.internalMain.push("");
|
|
1070
|
+
}
|
|
1071
|
+
{
|
|
1072
|
+
// Append(const T&, ByteSink&)
|
|
1073
|
+
source.internalMain.push(`void ${adapterName}::Append(const type& input, ByteSink& out) {`);
|
|
1074
|
+
source.internalMain.push(" switch (input.kind_) {");
|
|
1075
|
+
for (const variant of constVariants) {
|
|
1076
|
+
const { variantNumber, isUnknownVariant, kindEnumerator } = variant;
|
|
1077
|
+
source.internalMain.push(` case type::kind_type::${kindEnumerator}: {`);
|
|
1078
|
+
if (isUnknownVariant) {
|
|
1079
|
+
source.internalMain.push(" AppendUnrecognizedVariant(input.value_._unrecognized, out);");
|
|
1080
|
+
}
|
|
1081
|
+
else {
|
|
1082
|
+
const intLiterals = bytesToIntLiterals([
|
|
1083
|
+
...encodeInt32(variantNumber),
|
|
1084
|
+
]);
|
|
1085
|
+
source.internalMain.push(` out.Push(${intLiterals});`);
|
|
1086
|
+
}
|
|
1087
|
+
source.internalMain.push(" break;");
|
|
1088
|
+
source.internalMain.push(" }");
|
|
1089
|
+
}
|
|
1090
|
+
for (const variant of wrapperVariants) {
|
|
1091
|
+
const { variantName, variantNumber, kindEnumerator, usePointer } = variant;
|
|
1092
|
+
const intLiterals = bytesToIntLiterals(1 <= variantNumber && variantNumber <= 4
|
|
1093
|
+
? [variantNumber + 250]
|
|
1094
|
+
: [248, ...encodeInt32(variantNumber)]);
|
|
1095
|
+
const dotOrArrow = usePointer ? "->" : ".";
|
|
1096
|
+
source.internalMain.push(` case type::kind_type::${kindEnumerator}: {`);
|
|
1097
|
+
source.internalMain.push(` out.Push(${intLiterals});`);
|
|
1098
|
+
source.internalMain.push(` ::skir_internal::Append(input.value_.${variantName}_${dotOrArrow}value, out);`);
|
|
1099
|
+
source.internalMain.push(" break;");
|
|
1100
|
+
source.internalMain.push(" }");
|
|
1101
|
+
}
|
|
1102
|
+
source.internalMain.push(" }");
|
|
1103
|
+
source.internalMain.push("}");
|
|
1104
|
+
source.internalMain.push("");
|
|
1105
|
+
}
|
|
1106
|
+
{
|
|
1107
|
+
// Parse(JsonTokenizer&, T&)
|
|
1108
|
+
source.internalMain.push(`void ${adapterName}::Parse(JsonTokenizer& tokenizer, type& out) {`);
|
|
1109
|
+
source.internalMain.push(" switch (tokenizer.state().token_type) {");
|
|
1110
|
+
source.internalMain.push(" case JsonTokenType::kZero:");
|
|
1111
|
+
source.internalMain.push(" tokenizer.Next();");
|
|
1112
|
+
source.internalMain.push(" break;");
|
|
1113
|
+
source.internalMain.push(" case JsonTokenType::kUnsignedInteger: {");
|
|
1114
|
+
source.internalMain.push(" const int i = tokenizer.state().uint_value;");
|
|
1115
|
+
source.internalMain.push(" switch (i) {");
|
|
1116
|
+
for (const variant of constVariants) {
|
|
1117
|
+
const { variantNumber, identifier } = variant;
|
|
1118
|
+
if (variant.variantNumber <= 0)
|
|
1119
|
+
continue;
|
|
1120
|
+
source.internalMain.push(` case ${variantNumber}:`);
|
|
1121
|
+
source.internalMain.push(` out = ::skirout::${identifier};`);
|
|
1122
|
+
source.internalMain.push(" break;");
|
|
1123
|
+
}
|
|
1124
|
+
source.internalMain.push(" default:");
|
|
1125
|
+
source.internalMain.push(" if (tokenizer.keep_unrecognized_values()) {");
|
|
1126
|
+
source.internalMain.push(" out = type(UnrecognizedVariant{::skir_internal::UnrecognizedFormat::kDenseJson, i});");
|
|
1127
|
+
source.internalMain.push(" }");
|
|
1128
|
+
source.internalMain.push(" }");
|
|
1129
|
+
source.internalMain.push(" tokenizer.Next();");
|
|
1130
|
+
source.internalMain.push(" break;");
|
|
1131
|
+
source.internalMain.push(" }");
|
|
1132
|
+
source.internalMain.push(" case JsonTokenType::kSignedInteger: {");
|
|
1133
|
+
source.internalMain.push(" tokenizer.Next();");
|
|
1134
|
+
source.internalMain.push(" break;");
|
|
1135
|
+
source.internalMain.push(" }");
|
|
1136
|
+
source.internalMain.push(" case JsonTokenType::kString: {");
|
|
1137
|
+
source.internalMain.push(" static const auto* kMap = new absl::flat_hash_map<std::string, type>({");
|
|
1138
|
+
for (const variant of constVariants) {
|
|
1139
|
+
const { variantName, identifier } = variant;
|
|
1140
|
+
source.internalMain.push(` {"${variantName}", type::${identifier}},`);
|
|
1141
|
+
}
|
|
1142
|
+
source.internalMain.push(" });");
|
|
1143
|
+
source.internalMain.push(" const auto it = kMap->find(tokenizer.state().string_value);");
|
|
1144
|
+
source.internalMain.push(" if (it == kMap->cend()) break;");
|
|
1145
|
+
source.internalMain.push(" out = it->second;");
|
|
1146
|
+
source.internalMain.push(" tokenizer.Next();");
|
|
1147
|
+
source.internalMain.push(" break;");
|
|
1148
|
+
source.internalMain.push(" }");
|
|
1149
|
+
source.internalMain.push(" case JsonTokenType::kLeftSquareBracket: {");
|
|
1150
|
+
source.internalMain.push(" EnumJsonArrayParser parser(&tokenizer);");
|
|
1151
|
+
source.internalMain.push(" const int number = parser.ReadNumber();");
|
|
1152
|
+
source.internalMain.push(" switch (number) {");
|
|
1153
|
+
for (const variant of wrapperVariants) {
|
|
1154
|
+
const { variantNumber, typeAlias } = variant;
|
|
1155
|
+
source.internalMain.push(` case ${variantNumber}: {`);
|
|
1156
|
+
source.internalMain.push(` type::${typeAlias} wrapper;`);
|
|
1157
|
+
source.internalMain.push(" ::skir_internal::Parse(tokenizer, wrapper.value);");
|
|
1158
|
+
source.internalMain.push(" out = std::move(wrapper);");
|
|
1159
|
+
source.internalMain.push(" break;");
|
|
1160
|
+
source.internalMain.push(" }");
|
|
1161
|
+
}
|
|
1162
|
+
source.internalMain.push(" default: {");
|
|
1163
|
+
source.internalMain.push(" if (tokenizer.keep_unrecognized_values()) {");
|
|
1164
|
+
source.internalMain.push(" UnrecognizedVariant unrecognized{::skir_internal::UnrecognizedFormat::kDenseJson, number};");
|
|
1165
|
+
source.internalMain.push(" unrecognized.emplace_value().ParseFrom(tokenizer);");
|
|
1166
|
+
source.internalMain.push(" out = type(std::move(unrecognized));");
|
|
1167
|
+
source.internalMain.push(" } else {");
|
|
1168
|
+
source.internalMain.push(" SkipValue(tokenizer);");
|
|
1169
|
+
source.internalMain.push(" }");
|
|
1170
|
+
source.internalMain.push(" }");
|
|
1171
|
+
source.internalMain.push(" }");
|
|
1172
|
+
source.internalMain.push(" parser.Finish();");
|
|
1173
|
+
source.internalMain.push(" break;");
|
|
1174
|
+
source.internalMain.push(" }");
|
|
1175
|
+
source.internalMain.push(" case JsonTokenType::kLeftCurlyBracket: {");
|
|
1176
|
+
const parserExpr = "(new EnumJsonObjectParser<type>())" +
|
|
1177
|
+
wrapperVariants
|
|
1178
|
+
.map((variant) => {
|
|
1179
|
+
const { variantName, typeAlias } = variant;
|
|
1180
|
+
const indent = " ";
|
|
1181
|
+
return `\n${indent}->AddVariant<type::${typeAlias}>("${variantName}")`;
|
|
1182
|
+
})
|
|
1183
|
+
.join("");
|
|
1184
|
+
source.internalMain.push(" static const auto* kParser =");
|
|
1185
|
+
source.internalMain.push(` ${parserExpr};`);
|
|
1186
|
+
source.internalMain.push(" kParser->Parse(tokenizer, out);");
|
|
1187
|
+
source.internalMain.push(" break;");
|
|
1188
|
+
source.internalMain.push(" }");
|
|
1189
|
+
source.internalMain.push(" default: {");
|
|
1190
|
+
source.internalMain.push(" tokenizer.mutable_state().PushUnexpectedTokenError(\"number or '['\");");
|
|
1191
|
+
source.internalMain.push(" }");
|
|
1192
|
+
source.internalMain.push(" }");
|
|
1193
|
+
source.internalMain.push("}");
|
|
1194
|
+
source.internalMain.push("");
|
|
1195
|
+
}
|
|
1196
|
+
{
|
|
1197
|
+
// Parse(ByteSource&, T&)
|
|
1198
|
+
source.internalMain.push(`void ${adapterName}::Parse(ByteSource& source, type& out) {`);
|
|
1199
|
+
source.internalMain.push(" const auto [has_value, number] = ParseEnumPrefix(source);");
|
|
1200
|
+
source.internalMain.push(" if (has_value) {");
|
|
1201
|
+
source.internalMain.push(" switch (number) {");
|
|
1202
|
+
for (const variant of wrapperVariants) {
|
|
1203
|
+
const { variantNumber, typeAlias } = variant;
|
|
1204
|
+
source.internalMain.push(` case ${variantNumber}: {`);
|
|
1205
|
+
source.internalMain.push(` type::${typeAlias} wrapper;`);
|
|
1206
|
+
source.internalMain.push(" ::skir_internal::Parse(source, wrapper.value);");
|
|
1207
|
+
source.internalMain.push(" out = std::move(wrapper);");
|
|
1208
|
+
source.internalMain.push(" break;");
|
|
1209
|
+
source.internalMain.push(" }");
|
|
1210
|
+
}
|
|
1211
|
+
source.internalMain.push(" default: {");
|
|
1212
|
+
source.internalMain.push(" if (source.keep_unrecognized_values) {");
|
|
1213
|
+
source.internalMain.push(" UnrecognizedVariant unrecognized{::skir_internal::UnrecognizedFormat::kBytes, number};");
|
|
1214
|
+
source.internalMain.push(" unrecognized.emplace_value().ParseFrom(source);");
|
|
1215
|
+
source.internalMain.push(" out = type(std::move(unrecognized));");
|
|
1216
|
+
source.internalMain.push(" } else {");
|
|
1217
|
+
source.internalMain.push(" SkipValue(source);");
|
|
1218
|
+
source.internalMain.push(" }");
|
|
1219
|
+
source.internalMain.push(" }");
|
|
1220
|
+
source.internalMain.push(" }");
|
|
1221
|
+
source.internalMain.push(" } else {");
|
|
1222
|
+
source.internalMain.push(" switch (number) {");
|
|
1223
|
+
source.internalMain.push(" case 0:");
|
|
1224
|
+
source.internalMain.push(" break;");
|
|
1225
|
+
for (const variant of constVariants) {
|
|
1226
|
+
const { variantNumber, identifier } = variant;
|
|
1227
|
+
if (variant.variantNumber === 0)
|
|
1228
|
+
continue;
|
|
1229
|
+
source.internalMain.push(` case ${variantNumber}:`);
|
|
1230
|
+
source.internalMain.push(` out = ::skirout::${identifier};`);
|
|
1231
|
+
source.internalMain.push(" break;");
|
|
1232
|
+
}
|
|
1233
|
+
source.internalMain.push(" default: {");
|
|
1234
|
+
source.internalMain.push(" if (source.keep_unrecognized_values) {");
|
|
1235
|
+
source.internalMain.push(" out = type(UnrecognizedVariant{::skir_internal::UnrecognizedFormat::kBytes, number});");
|
|
1236
|
+
source.internalMain.push(" }");
|
|
1237
|
+
source.internalMain.push(" }");
|
|
1238
|
+
source.internalMain.push(" }");
|
|
1239
|
+
source.internalMain.push(" }");
|
|
1240
|
+
source.internalMain.push("}");
|
|
1241
|
+
source.internalMain.push("");
|
|
1242
|
+
}
|
|
1243
|
+
{
|
|
1244
|
+
// GetType(skir_type<T>)
|
|
1245
|
+
source.internalMain.push(`skir::reflection::Type ${adapterName}::GetType(skir_type<type>) {`);
|
|
1246
|
+
const recordId = getRecordId(record);
|
|
1247
|
+
source.internalMain.push(` return skir::reflection::RecordType({"${recordId}"});`);
|
|
1248
|
+
source.internalMain.push("}");
|
|
1249
|
+
source.internalMain.push("");
|
|
1250
|
+
}
|
|
1251
|
+
{
|
|
1252
|
+
// RegisterRecords(skir_type<T>, RecordRegistry&)
|
|
1253
|
+
const recordId = getRecordId(record);
|
|
1254
|
+
source.internalMain.push(`void ${adapterName}::RegisterRecords(`);
|
|
1255
|
+
source.internalMain.push(" skir_type<type>,");
|
|
1256
|
+
source.internalMain.push(" skir::reflection::RecordRegistry& registry) {");
|
|
1257
|
+
source.internalMain.push(" const bool already_present =");
|
|
1258
|
+
source.internalMain.push(` registry.find_or_null("${recordId}") != nullptr;`);
|
|
1259
|
+
source.internalMain.push(" if (already_present) return;");
|
|
1260
|
+
source.internalMain.push(" skir::reflection::Enum record = {");
|
|
1261
|
+
source.internalMain.push(` "${recordId}",`);
|
|
1262
|
+
source.internalMain.push(` ${JSON.stringify(record.record.doc.text)},`);
|
|
1263
|
+
source.internalMain.push(" {");
|
|
1264
|
+
for (const variant of constVariants) {
|
|
1265
|
+
if (variant.isUnknownVariant) {
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
source.internalMain.push(" {");
|
|
1269
|
+
source.internalMain.push(` "${variant.variantName}",`);
|
|
1270
|
+
source.internalMain.push(` ${variant.variantNumber},`);
|
|
1271
|
+
source.internalMain.push(` absl::nullopt,`);
|
|
1272
|
+
source.internalMain.push(` ${JSON.stringify(variant.doc.text)},`);
|
|
1273
|
+
source.internalMain.push(" },");
|
|
1274
|
+
}
|
|
1275
|
+
for (const variant of wrapperVariants) {
|
|
1276
|
+
const { variantName, variantNumber, valueTypeWithNamespace } = variant;
|
|
1277
|
+
source.internalMain.push(" {");
|
|
1278
|
+
source.internalMain.push(` "${variantName}",`);
|
|
1279
|
+
source.internalMain.push(` ${variantNumber},`);
|
|
1280
|
+
source.internalMain.push(` skir_internal::GetType<${valueTypeWithNamespace}>(),`);
|
|
1281
|
+
source.internalMain.push(" },");
|
|
1282
|
+
}
|
|
1283
|
+
source.internalMain.push(" },");
|
|
1284
|
+
const removedNumbers = record.record.removedNumbers.join(", ");
|
|
1285
|
+
source.internalMain.push(` {${removedNumbers}},`);
|
|
1286
|
+
source.internalMain.push(" };");
|
|
1287
|
+
source.internalMain.push(" registry.push_back(std::move(record));");
|
|
1288
|
+
for (const variant of wrapperVariants) {
|
|
1289
|
+
const { valueTypeWithNamespace } = variant;
|
|
1290
|
+
source.internalMain.push(` skir_internal::RegisterRecords<${valueTypeWithNamespace}>(registry);`);
|
|
1291
|
+
}
|
|
1292
|
+
source.internalMain.push("}");
|
|
1293
|
+
source.internalMain.push("");
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
writeCodeInHeaderForAdapter(record) {
|
|
1297
|
+
const { header } = this;
|
|
1298
|
+
const { fields, recordType } = record.record;
|
|
1299
|
+
const className = getClassName(record);
|
|
1300
|
+
const adapterName = `${className}Adapter`;
|
|
1301
|
+
const qualifiedName = `::${this.namespace}::${className}`;
|
|
1302
|
+
header.internalMainTop.push(`class ${adapterName};`);
|
|
1303
|
+
header.internalMain.push(`class ${adapterName} {`);
|
|
1304
|
+
header.internalMain.push(" public:");
|
|
1305
|
+
header.internalMain.push(` using type = ${qualifiedName};`);
|
|
1306
|
+
const tupleName = recordType === "struct" ? "fields_tuple" : "variants_tuple";
|
|
1307
|
+
if (fields.length || recordType === "enum") {
|
|
1308
|
+
const fieldToReflectionType = (f) => {
|
|
1309
|
+
const fieldName = f.name.text;
|
|
1310
|
+
if (recordType === "struct") {
|
|
1311
|
+
return `struct_field<type, skirout::get_${fieldName}<>>`;
|
|
1312
|
+
}
|
|
1313
|
+
else if (f.type) {
|
|
1314
|
+
return `enum_wrapper_variant<type, skirout::reflection::${fieldName}_variant>`;
|
|
1315
|
+
}
|
|
1316
|
+
else {
|
|
1317
|
+
return `skir::reflection::enum_const_variant<skirout::k_${fieldName.toLowerCase()}>`;
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
const reflectionTypes = fields
|
|
1321
|
+
.map(fieldToReflectionType)
|
|
1322
|
+
.concat(recordType === "enum"
|
|
1323
|
+
? ["skir::reflection::enum_const_variant<skirout::k_unknown>"]
|
|
1324
|
+
: [])
|
|
1325
|
+
.join(",\n ");
|
|
1326
|
+
header.internalMain.push(` using ${tupleName} = std::tuple<\n ${reflectionTypes}>;`);
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
header.internalMain.push(` using ${tupleName} = std::tuple<>;`);
|
|
1330
|
+
}
|
|
1331
|
+
header.internalMain.push("");
|
|
1332
|
+
header.internalMain.push(" static bool IsDefault(const type&);");
|
|
1333
|
+
header.internalMain.push(" static void Append(const type&, DenseJson&);");
|
|
1334
|
+
header.internalMain.push(" static void Append(const type&, ReadableJson&);");
|
|
1335
|
+
header.internalMain.push(" static void Append(const type&, DebugString&);");
|
|
1336
|
+
header.internalMain.push(" static void Append(const type&, ByteSink&);");
|
|
1337
|
+
header.internalMain.push(" static void Parse(JsonTokenizer&, type&);");
|
|
1338
|
+
header.internalMain.push(" static void Parse(ByteSource&, type&);");
|
|
1339
|
+
header.internalMain.push(" static skir::reflection::Type GetType(skir_type<type>);");
|
|
1340
|
+
header.internalMain.push(" static void RegisterRecords(");
|
|
1341
|
+
header.internalMain.push(" skir_type<type>,");
|
|
1342
|
+
header.internalMain.push(" skir::reflection::RecordRegistry&);");
|
|
1343
|
+
header.internalMain.push(` static constexpr bool IsStruct() { return ${recordType === "struct"}; }`);
|
|
1344
|
+
header.internalMain.push(` static constexpr bool IsEnum() { return ${recordType === "enum"}; }`);
|
|
1345
|
+
header.internalMain.push("};");
|
|
1346
|
+
header.internalMain.push("");
|
|
1347
|
+
header.internal.push(`inline ::skir_internal::${this.namespace}::${adapterName} GetAdapter(`);
|
|
1348
|
+
header.internal.push(` ::skir_internal::skir_type<${qualifiedName}>);`);
|
|
1349
|
+
header.internal.push("");
|
|
1350
|
+
}
|
|
1351
|
+
writeCodeForConstantVariant(variant) {
|
|
1352
|
+
if (!this.addskiroutSymbol(variant.structType))
|
|
1353
|
+
return;
|
|
1354
|
+
const { skirout } = this.header;
|
|
1355
|
+
skirout.push(`#ifndef skirout_${variant.structType}`);
|
|
1356
|
+
skirout.push(`#define skirout_${variant.structType}`);
|
|
1357
|
+
skirout.push(`struct ${variant.structType} {`);
|
|
1358
|
+
skirout.push(` static constexpr absl::string_view kVariantName = "${variant.variantName}";`);
|
|
1359
|
+
skirout.push("};");
|
|
1360
|
+
skirout.push("");
|
|
1361
|
+
skirout.push(`constexpr auto ${variant.identifier} = ${variant.structType}();`);
|
|
1362
|
+
skirout.push("#endif");
|
|
1363
|
+
skirout.push("");
|
|
1364
|
+
}
|
|
1365
|
+
writeCodeForWrapperVariant(variant) {
|
|
1366
|
+
const { variantName, structType } = variant;
|
|
1367
|
+
if (!this.addskiroutSymbol(structType))
|
|
1368
|
+
return;
|
|
1369
|
+
const variantType = `${variantName}_variant`;
|
|
1370
|
+
{
|
|
1371
|
+
const { skirout } = this.header;
|
|
1372
|
+
skirout.push(`#ifndef skirout_${structType}`);
|
|
1373
|
+
skirout.push(`#define skirout_${structType}`);
|
|
1374
|
+
skirout.push("template <typename T>");
|
|
1375
|
+
skirout.push(`struct ${structType};`);
|
|
1376
|
+
skirout.push("");
|
|
1377
|
+
skirout.push("namespace reflection {");
|
|
1378
|
+
skirout.push(`struct ${variantType} {`);
|
|
1379
|
+
skirout.push(` static constexpr absl::string_view kVariantName = "${variantName}";`);
|
|
1380
|
+
skirout.push("");
|
|
1381
|
+
skirout.push(" template <typename T>");
|
|
1382
|
+
skirout.push(` static ${structType}<T> wrap(T input) {`);
|
|
1383
|
+
skirout.push(` return ${structType}(std::move(input));`);
|
|
1384
|
+
skirout.push(" }");
|
|
1385
|
+
skirout.push("");
|
|
1386
|
+
skirout.push(" template <typename Enum>");
|
|
1387
|
+
skirout.push(" static auto* get_or_null(Enum& e) {");
|
|
1388
|
+
skirout.push(` return e.is_${variantName}() ? &e.as_${variantName}() : nullptr;`);
|
|
1389
|
+
skirout.push(" }");
|
|
1390
|
+
skirout.push("};");
|
|
1391
|
+
skirout.push("} // namespace reflection");
|
|
1392
|
+
skirout.push("");
|
|
1393
|
+
skirout.push("template <typename T>");
|
|
1394
|
+
skirout.push(`struct ${structType} {`);
|
|
1395
|
+
skirout.push(" using value_type = T;");
|
|
1396
|
+
skirout.push(` using variant_type = ::skirout::reflection::${variantType};`);
|
|
1397
|
+
skirout.push("");
|
|
1398
|
+
skirout.push(" T value{};");
|
|
1399
|
+
skirout.push("");
|
|
1400
|
+
skirout.push(` ${structType}() = default;`);
|
|
1401
|
+
skirout.push(` explicit ${structType}(T value): value(std::move(value)) {}`);
|
|
1402
|
+
skirout.push("};");
|
|
1403
|
+
skirout.push("#endif");
|
|
1404
|
+
skirout.push("");
|
|
1405
|
+
}
|
|
1406
|
+
{
|
|
1407
|
+
const { skirout } = this.testingHeader;
|
|
1408
|
+
skirout.push(`#ifndef TESTING_skirout_${structType}`);
|
|
1409
|
+
skirout.push(`#define TESTING_skirout_${structType}`);
|
|
1410
|
+
skirout.push("template <typename ValueMatcher = decltype(_)>");
|
|
1411
|
+
const functionName = "Is" + convertCase(variantName, "UpperCamel");
|
|
1412
|
+
skirout.push(`auto ${functionName}(ValueMatcher matcher = _) {`);
|
|
1413
|
+
skirout.push(" using ::testing::skir_internal::EnumValueIsMatcher;");
|
|
1414
|
+
skirout.push(` using Variant = ::skirout::reflection::${variantType};`);
|
|
1415
|
+
skirout.push(" return EnumValueIsMatcher<Variant, ValueMatcher>(std::move(matcher));");
|
|
1416
|
+
skirout.push("}");
|
|
1417
|
+
skirout.push("#endif");
|
|
1418
|
+
skirout.push("");
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
writeCodeForMethod(method) {
|
|
1422
|
+
const { typeSpeller } = this;
|
|
1423
|
+
const { mainMiddle } = this.header;
|
|
1424
|
+
const methodName = method.name.text;
|
|
1425
|
+
const requestType = typeSpeller.getCcType(method.requestType);
|
|
1426
|
+
const responseType = typeSpeller.getCcType(method.responseType);
|
|
1427
|
+
const doc = method.doc.text;
|
|
1428
|
+
mainMiddle.push(...commentify(docToCommentText(method.doc)));
|
|
1429
|
+
mainMiddle.push(`struct ${methodName} {`);
|
|
1430
|
+
mainMiddle.push(` using request_type = ${requestType};`);
|
|
1431
|
+
mainMiddle.push(` using response_type = ${responseType};`);
|
|
1432
|
+
mainMiddle.push(` static constexpr absl::string_view kMethodName = "${methodName}";`);
|
|
1433
|
+
mainMiddle.push(` static constexpr uint32_t kNumber = ${method.number};`);
|
|
1434
|
+
mainMiddle.push(` static constexpr absl::string_view kDoc = ${JSON.stringify(doc)};`);
|
|
1435
|
+
mainMiddle.push("};");
|
|
1436
|
+
mainMiddle.push("");
|
|
1437
|
+
}
|
|
1438
|
+
writeCodeForConstant(constant) {
|
|
1439
|
+
const { header, source, typeSpeller } = this;
|
|
1440
|
+
const name = `k_${constant.name.text.toLowerCase()}`;
|
|
1441
|
+
const type = typeSpeller.getCcType(constant.type);
|
|
1442
|
+
const ccStringLiteral = JSON.stringify(JSON.stringify(constant.valueAsDenseJson));
|
|
1443
|
+
header.mainMiddle.push(...commentify(docToCommentText(constant.doc)));
|
|
1444
|
+
header.mainMiddle.push(`const ${type}& ${name}();`);
|
|
1445
|
+
header.mainMiddle.push("");
|
|
1446
|
+
source.mainMiddle.push(`const ${type}& ${name}() {`);
|
|
1447
|
+
source.mainMiddle.push(` static const auto* kResult = new ${type}(`);
|
|
1448
|
+
source.mainMiddle.push(` ::skir::Parse<${type}>(`);
|
|
1449
|
+
source.mainMiddle.push(` ${ccStringLiteral})`);
|
|
1450
|
+
source.mainMiddle.push(" .value());");
|
|
1451
|
+
source.mainMiddle.push(" return *kResult;");
|
|
1452
|
+
source.mainMiddle.push("}");
|
|
1453
|
+
source.mainMiddle.push("");
|
|
1454
|
+
}
|
|
1455
|
+
writeIncludes() {
|
|
1456
|
+
const { header, source, testingHeader } = this;
|
|
1457
|
+
{
|
|
1458
|
+
const headerPath = "skirout/" + this.inModule.path.replace(/\.skir$/, ".h");
|
|
1459
|
+
source.includes.push(`#include "${headerPath}"`);
|
|
1460
|
+
testingHeader.includes.push(`#include "${headerPath}"`);
|
|
1461
|
+
}
|
|
1462
|
+
for (const h of [...this.includes].sort()) {
|
|
1463
|
+
header.includes.push(`#include ${h}`);
|
|
1464
|
+
testingHeader.includes.push(`#include ${h.replace(/\.h"$/, '.testing.h"')}`);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
addskiroutSymbol(symbol) {
|
|
1468
|
+
if (this.seenskiroutSymbols.has(symbol))
|
|
1469
|
+
return false;
|
|
1470
|
+
this.seenskiroutSymbols.add(symbol);
|
|
1471
|
+
return true;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
function commentify(textOrLines, indent = "") {
|
|
1475
|
+
const text = (typeof textOrLines === "string" ? textOrLines : textOrLines.join("\n"))
|
|
1476
|
+
.replace(/^\s*\n+/g, "")
|
|
1477
|
+
.replace(/\n+\s*$/g, "")
|
|
1478
|
+
.replace(/\n{3,}/g, "\n\n");
|
|
1479
|
+
if (text.length <= 0) {
|
|
1480
|
+
return [];
|
|
1481
|
+
}
|
|
1482
|
+
return text.split("\n").map((line) => `${indent}// ${line}`);
|
|
1483
|
+
}
|
|
1484
|
+
function docToCommentText(doc) {
|
|
1485
|
+
return doc.pieces
|
|
1486
|
+
.map((p) => {
|
|
1487
|
+
switch (p.kind) {
|
|
1488
|
+
case "text":
|
|
1489
|
+
return p.text;
|
|
1490
|
+
case "reference":
|
|
1491
|
+
return `'${p.referenceRange.text.slice(1, -1)}'`;
|
|
1492
|
+
}
|
|
1493
|
+
})
|
|
1494
|
+
.join("");
|
|
1495
|
+
}
|
|
1496
|
+
class FileContents {
|
|
1497
|
+
constructor(extension) {
|
|
1498
|
+
this.extension = extension;
|
|
1499
|
+
this.namespace = "";
|
|
1500
|
+
this.includes = [];
|
|
1501
|
+
/** Group within the ::skirout namespace. */
|
|
1502
|
+
this.skirout = [];
|
|
1503
|
+
/** First group within the ::skirout_my_module namespace. */
|
|
1504
|
+
this.mainTop = [];
|
|
1505
|
+
/** Second group within the ::skirout_my_module namespace. */
|
|
1506
|
+
this.mainMiddle = [];
|
|
1507
|
+
/** Third group within the ::skirout_my_module namespace. */
|
|
1508
|
+
this.mainBottom = [];
|
|
1509
|
+
/** Group within the anonymous namespace. Only in the .cc. */
|
|
1510
|
+
this.anonymous = [];
|
|
1511
|
+
/** Group within the ::skir_internal namespace. */
|
|
1512
|
+
this.internal = [];
|
|
1513
|
+
/**
|
|
1514
|
+
* First group within the ::skir_internal_my_module namespace. Only in the
|
|
1515
|
+
* .h.
|
|
1516
|
+
*/
|
|
1517
|
+
this.internalMainTop = [];
|
|
1518
|
+
/** Group within the ::skir_internal::my::module namespace. */
|
|
1519
|
+
this.internalMain = [];
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
function fileContentsToCode(fileContents) {
|
|
1523
|
+
const { extension, namespace } = fileContents;
|
|
1524
|
+
const lines = [
|
|
1525
|
+
"// ______ _ _ _ _",
|
|
1526
|
+
"// | _ \\ | | | |(_)| |",
|
|
1527
|
+
"// | | | | ___ _ __ ___ | |_ ___ __| | _ | |_",
|
|
1528
|
+
"// | | | | / _ \\ | '_ \\ / _ \\ | __| / _ \\ / _` || || __|",
|
|
1529
|
+
"// | |/ / | (_) | | | | || (_) || |_ | __/| (_| || || |_ ",
|
|
1530
|
+
"// |___/ \\___/ |_| |_| \\___/ \\__| \\___| \\__,_||_| \\__|",
|
|
1531
|
+
"",
|
|
1532
|
+
];
|
|
1533
|
+
if (extension === ".h" || extension === ".testing.h") {
|
|
1534
|
+
const includeGuard = `${namespace}${extension.replace(/\./g, "_")}`.toUpperCase();
|
|
1535
|
+
lines.push(`#ifndef ${includeGuard}`);
|
|
1536
|
+
lines.push(`#define ${includeGuard}`);
|
|
1537
|
+
lines.push("");
|
|
1538
|
+
}
|
|
1539
|
+
fileContents.includes.forEach((l) => lines.push(l));
|
|
1540
|
+
lines.push("");
|
|
1541
|
+
if (extension === ".h") {
|
|
1542
|
+
lines.push("namespace skir_internal {");
|
|
1543
|
+
lines.push(`namespace ${namespace} {`);
|
|
1544
|
+
fileContents.internalMainTop.forEach((l) => lines.push(l));
|
|
1545
|
+
lines.push(`} // namespace ${namespace}`);
|
|
1546
|
+
lines.push("} // namespace skir_internal");
|
|
1547
|
+
lines.push("");
|
|
1548
|
+
}
|
|
1549
|
+
else if (extension === ".cc") {
|
|
1550
|
+
lines.push("namespace {");
|
|
1551
|
+
lines.push("");
|
|
1552
|
+
fileContents.anonymous.forEach((l) => lines.push(l));
|
|
1553
|
+
lines.push("");
|
|
1554
|
+
lines.push("} // namespace");
|
|
1555
|
+
lines.push("");
|
|
1556
|
+
}
|
|
1557
|
+
if (extension === ".testing.h") {
|
|
1558
|
+
lines.push("namespace testing {");
|
|
1559
|
+
}
|
|
1560
|
+
lines.push("namespace skirout {");
|
|
1561
|
+
fileContents.skirout.forEach((l) => lines.push(l));
|
|
1562
|
+
lines.push("} // namespace skirout");
|
|
1563
|
+
if (extension === ".h" || extension === ".cc") {
|
|
1564
|
+
lines.push("");
|
|
1565
|
+
lines.push(`namespace ${namespace} {`);
|
|
1566
|
+
fileContents.mainTop.forEach((l) => lines.push(l));
|
|
1567
|
+
lines.push("");
|
|
1568
|
+
fileContents.mainMiddle.forEach((l) => lines.push(l));
|
|
1569
|
+
lines.push("");
|
|
1570
|
+
fileContents.mainBottom.forEach((l) => lines.push(l));
|
|
1571
|
+
lines.push("");
|
|
1572
|
+
lines.push(`} // namespace ${namespace}`);
|
|
1573
|
+
lines.push("namespace skir_internal {");
|
|
1574
|
+
lines.push(`namespace ${namespace} {`);
|
|
1575
|
+
lines.push("");
|
|
1576
|
+
fileContents.internalMain.forEach((l) => lines.push(l));
|
|
1577
|
+
lines.push("");
|
|
1578
|
+
lines.push(`} // namespace ${namespace}`);
|
|
1579
|
+
lines.push("");
|
|
1580
|
+
fileContents.internal.forEach((l) => lines.push(l));
|
|
1581
|
+
lines.push("");
|
|
1582
|
+
lines.push("} // namespace skir_internal");
|
|
1583
|
+
lines.push("");
|
|
1584
|
+
}
|
|
1585
|
+
else {
|
|
1586
|
+
lines.push("} // namespace testing");
|
|
1587
|
+
lines.push("");
|
|
1588
|
+
}
|
|
1589
|
+
if (extension === ".h" || extension === ".testing.h") {
|
|
1590
|
+
lines.push("#endif");
|
|
1591
|
+
}
|
|
1592
|
+
return (lines
|
|
1593
|
+
.map((l) => `${l}\n`)
|
|
1594
|
+
.join("")
|
|
1595
|
+
// Remove empty line following "public" or "private".
|
|
1596
|
+
.replace(/((public:|private:)\n)\n+/g, "$1")
|
|
1597
|
+
// Remove empty line preceding a closed curly bracket.
|
|
1598
|
+
.replace(/\n(\n *\})/g, "$1")
|
|
1599
|
+
// Coalesce consecutive empty lines.
|
|
1600
|
+
.replace(/\n\n\n+/g, "\n\n")
|
|
1601
|
+
.replace(/\n\n$/g, "\n"));
|
|
1602
|
+
}
|
|
1603
|
+
export const GENERATOR = new CcCodeGenerator();
|
|
1604
|
+
function maybeEscapeLowerCaseName(name) {
|
|
1605
|
+
return CC_KEYWORDS.has(name) ? `${name}_` : name;
|
|
1606
|
+
}
|
|
1607
|
+
function numberToCharLiterals(n) {
|
|
1608
|
+
const decimal = `${n}`;
|
|
1609
|
+
let result = "";
|
|
1610
|
+
for (let i = 0; i < decimal.length; ++i) {
|
|
1611
|
+
if (i !== 0) {
|
|
1612
|
+
result += ", ";
|
|
1613
|
+
}
|
|
1614
|
+
result += `'${decimal[i]}'`;
|
|
1615
|
+
}
|
|
1616
|
+
return result;
|
|
1617
|
+
}
|
|
1618
|
+
function bytesToIntLiterals(bytes) {
|
|
1619
|
+
return bytes.map((b) => `${b}`).join(", ");
|
|
1620
|
+
}
|
|
1621
|
+
function getRecordId(record) {
|
|
1622
|
+
const qualifiedName = record.recordAncestors
|
|
1623
|
+
.map((r) => r.name.text)
|
|
1624
|
+
.join(".");
|
|
1625
|
+
return `${record.modulePath}:${qualifiedName}`;
|
|
1626
|
+
}
|
|
1627
|
+
//# sourceMappingURL=index.js.map
|