naider 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +209 -8
- package/SPEC.naide +152 -0
- package/lsp/server.js +55 -0
- package/package.json +22 -3
- package/src/generator-c.js +1014 -0
- package/src/generator-cpp.js +1211 -0
- package/src/generator-csharp.js +1633 -0
- package/src/generator-dart.js +1569 -0
- package/src/generator-go.js +1781 -0
- package/src/generator-java.js +1814 -0
- package/src/generator-kotlin.js +1819 -0
- package/src/generator-php.js +1576 -0
- package/src/generator-python.js +291 -0
- package/src/generator-ruby.js +1530 -0
- package/src/generator-rust.js +1887 -0
- package/src/generator-swift.js +1735 -0
- package/src/generator-typescript.js +126 -0
- package/src/generator.js +296 -0
- package/src/index.js +55 -0
- package/src/parser.js +308 -3
- package/src/tokens.js +27 -0
- package/vscode-naide/syntaxes/naide.tmLanguage.json +7 -3
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
export class CppGenerator {
|
|
2
|
+
constructor(options = {}) {
|
|
3
|
+
this.indent = 0;
|
|
4
|
+
this.output = [];
|
|
5
|
+
this.models = new Map();
|
|
6
|
+
this.schemas = new Map();
|
|
7
|
+
this.includes = new Set();
|
|
8
|
+
this.sourceMap = [];
|
|
9
|
+
this.currentSourceLine = 0;
|
|
10
|
+
this.sourceFile = options.sourceFile || null;
|
|
11
|
+
this.inFunction = false;
|
|
12
|
+
this.preamble = [];
|
|
13
|
+
this.classDefs = [];
|
|
14
|
+
this.functionDefs = [];
|
|
15
|
+
this.mainBody = [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
generate(ast) {
|
|
19
|
+
this.includes.add('<iostream>');
|
|
20
|
+
|
|
21
|
+
this.visitProgram(ast);
|
|
22
|
+
|
|
23
|
+
const out = [];
|
|
24
|
+
|
|
25
|
+
// Preamble: #includes
|
|
26
|
+
for (const inc of [...this.includes].sort()) {
|
|
27
|
+
out.push(`#include ${inc}`);
|
|
28
|
+
}
|
|
29
|
+
out.push('');
|
|
30
|
+
out.push('using namespace std;');
|
|
31
|
+
out.push('');
|
|
32
|
+
|
|
33
|
+
// Class / struct definitions
|
|
34
|
+
if (this.classDefs.length > 0) {
|
|
35
|
+
out.push(...this.classDefs);
|
|
36
|
+
out.push('');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Function definitions
|
|
40
|
+
if (this.functionDefs.length > 0) {
|
|
41
|
+
out.push(...this.functionDefs);
|
|
42
|
+
out.push('');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Main function wrapping top-level statements
|
|
46
|
+
if (this.mainBody.length > 0) {
|
|
47
|
+
out.push('int main() {');
|
|
48
|
+
out.push(...this.mainBody);
|
|
49
|
+
out.push(' return 0;');
|
|
50
|
+
out.push('}');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return out.join('\n');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
emit(line) {
|
|
57
|
+
const indented = ' '.repeat(this.indent) + line;
|
|
58
|
+
if (this.inFunction) {
|
|
59
|
+
this.functionDefs.push(indented);
|
|
60
|
+
} else {
|
|
61
|
+
this.mainBody.push(indented);
|
|
62
|
+
}
|
|
63
|
+
this.sourceMap.push(this.currentSourceLine);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
emitRaw(line) {
|
|
67
|
+
if (this.inFunction) {
|
|
68
|
+
this.functionDefs.push(line);
|
|
69
|
+
} else {
|
|
70
|
+
this.mainBody.push(line);
|
|
71
|
+
}
|
|
72
|
+
this.sourceMap.push(this.currentSourceLine);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
emitClass(line) {
|
|
76
|
+
this.classDefs.push(line);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
visitProgram(node) {
|
|
80
|
+
for (const stmt of node.body) {
|
|
81
|
+
this.visitStatement(stmt);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ===== Type mapping =====
|
|
86
|
+
|
|
87
|
+
mapType(naideType) {
|
|
88
|
+
const map = {
|
|
89
|
+
'str': 'string',
|
|
90
|
+
'string': 'string',
|
|
91
|
+
'int': 'int',
|
|
92
|
+
'integer': 'int',
|
|
93
|
+
'num': 'double',
|
|
94
|
+
'number': 'double',
|
|
95
|
+
'float': 'double',
|
|
96
|
+
'bool': 'bool',
|
|
97
|
+
'boolean': 'bool',
|
|
98
|
+
'list': 'vector<any>',
|
|
99
|
+
'map': 'map<string, any>',
|
|
100
|
+
'any': 'any',
|
|
101
|
+
'void': 'void',
|
|
102
|
+
'json': 'string',
|
|
103
|
+
'auto': 'int',
|
|
104
|
+
'timestamp': 'long long',
|
|
105
|
+
};
|
|
106
|
+
return map[naideType] || 'auto';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ===== Statement dispatcher =====
|
|
110
|
+
|
|
111
|
+
visitStatement(node) {
|
|
112
|
+
if (node._line) this.currentSourceLine = node._line;
|
|
113
|
+
switch (node.type) {
|
|
114
|
+
case 'Use': return this.visitUse(node);
|
|
115
|
+
case 'UseDestructured': return this.visitUseDestructured(node);
|
|
116
|
+
case 'Function': return this.visitFunction(node);
|
|
117
|
+
case 'Return': return this.visitReturn(node);
|
|
118
|
+
case 'ReturnStatus': return this.visitReturnStatus(node);
|
|
119
|
+
case 'ReturnMethod': return this.visitReturnMethod(node);
|
|
120
|
+
case 'TypedVar': return this.visitTypedVar(node);
|
|
121
|
+
case 'If': return this.visitIf(node);
|
|
122
|
+
case 'Each': return this.visitEach(node);
|
|
123
|
+
case 'For': return this.visitFor(node);
|
|
124
|
+
case 'While': return this.visitWhile(node);
|
|
125
|
+
case 'Match': return this.visitMatch(node);
|
|
126
|
+
case 'Try': return this.visitTry(node);
|
|
127
|
+
case 'Server': return this.visitServer(node);
|
|
128
|
+
case 'Bot': return this.visitBot(node);
|
|
129
|
+
case 'Model': return this.visitModel(node);
|
|
130
|
+
case 'On': return this.visitOn(node);
|
|
131
|
+
case 'Log': return this.visitLog(node);
|
|
132
|
+
case 'Throw': return this.visitThrow(node);
|
|
133
|
+
case 'Break': this.emit('break;'); return;
|
|
134
|
+
case 'Continue': this.emit('continue;'); return;
|
|
135
|
+
case 'Assignment': return this.visitAssignment(node);
|
|
136
|
+
case 'CompoundAssign': return this.visitCompoundAssign(node);
|
|
137
|
+
case 'ExprStatement': this.emit(this.expr(node.expression) + ';'); return;
|
|
138
|
+
case 'DbConnect': return this.visitDbConnect(node);
|
|
139
|
+
case 'DbDir': return this.visitDbDir(node);
|
|
140
|
+
case 'DbSql': return this.visitDbSql(node);
|
|
141
|
+
case 'AwaitAll': return this.visitAwaitAll(node);
|
|
142
|
+
case 'SchemaDecl': return this.visitSchema(node);
|
|
143
|
+
case 'CrudDecl': return this.visitCrud(node);
|
|
144
|
+
case 'AuthDecl': return this.visitAuth(node);
|
|
145
|
+
case 'CorsDecl': return this.visitCors(node);
|
|
146
|
+
case 'LimitDecl': return this.visitLimit(node);
|
|
147
|
+
case 'EnvDecl': return this.visitEnv(node);
|
|
148
|
+
case 'EveryDecl': return this.visitEvery(node);
|
|
149
|
+
case 'WatchDecl': return this.visitWatch(node);
|
|
150
|
+
case 'StaticDecl': return this.visitStatic(node);
|
|
151
|
+
case 'WsDecl': return this.visitWs(node);
|
|
152
|
+
case 'GroupDecl': return this.visitGroup(node);
|
|
153
|
+
case 'ErrorHandler': return this.visitErrorHandler(node);
|
|
154
|
+
case 'CookieDecl': return this.visitCookie(node);
|
|
155
|
+
case 'UploadDecl': return this.visitUpload(node);
|
|
156
|
+
case 'SessionDecl': return this.visitSession(node);
|
|
157
|
+
case 'ViewDecl': return this.visitView(node);
|
|
158
|
+
case 'SseDecl': return this.visitSse(node);
|
|
159
|
+
case 'CacheDecl': return this.visitCache(node);
|
|
160
|
+
case 'MiddlewareRef': return this.visitMiddlewareRef(node);
|
|
161
|
+
case 'ReturnRender': return this.visitReturnRender(node);
|
|
162
|
+
case 'ValidateDecl': return this.visitValidate(node);
|
|
163
|
+
case 'TestDecl': return this.visitTest(node);
|
|
164
|
+
case 'AssertStmt': return this.visitAssert(node);
|
|
165
|
+
case 'QueueDecl': return this.visitQueue(node);
|
|
166
|
+
case 'OpenapiDecl': return this.visitOpenapi(node);
|
|
167
|
+
case 'ReturnRedirect': return this.visitReturnRedirect(node);
|
|
168
|
+
case 'ReturnDownload': return this.visitReturnDownload(node);
|
|
169
|
+
case 'PromptDecl': return this.visitPrompt(node);
|
|
170
|
+
case 'Page': return this.visitPage(node);
|
|
171
|
+
case 'CliApp': return this.visitCli(node);
|
|
172
|
+
case 'MailConfig': return this.visitMail(node);
|
|
173
|
+
case 'DesktopApp': return this.visitDesktop(node);
|
|
174
|
+
case 'Screen': return this.visitScreen(node);
|
|
175
|
+
case 'OauthDecl': return this.visitOauth(node);
|
|
176
|
+
case 'PayDecl': return this.visitPay(node);
|
|
177
|
+
case 'StorageDecl': return this.visitStorage(node);
|
|
178
|
+
case 'PdfDecl': return this.visitPdf(node);
|
|
179
|
+
case 'I18nDecl': return this.visitI18n(node);
|
|
180
|
+
case 'PushDecl': return this.visitPush(node);
|
|
181
|
+
case 'SearchDecl': return this.visitSearch(node);
|
|
182
|
+
case 'ImageDecl': return this.visitImage(node);
|
|
183
|
+
case 'CsvDecl': return this.visitCsv(node);
|
|
184
|
+
case 'LoggingDecl': return this.visitLogging(node);
|
|
185
|
+
case 'MigrateDecl': return this.visitMigrate(node);
|
|
186
|
+
case 'GrpcDecl': return this.visitGrpc(node);
|
|
187
|
+
case 'WebrtcDecl': return this.visitWebrtc(node);
|
|
188
|
+
case 'BlockchainDecl': return this.visitBlockchain(node);
|
|
189
|
+
default:
|
|
190
|
+
this.emit(`/* unknown: ${node.type} */`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ===== Imports / Use =====
|
|
195
|
+
|
|
196
|
+
visitUse(node) {
|
|
197
|
+
const raw = node.source ? this.rawString(node.source) : node.name;
|
|
198
|
+
this.emit(`/* use ${raw} */`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
visitUseDestructured(node) {
|
|
202
|
+
const raw = this.rawString(node.source);
|
|
203
|
+
const names = node.names.map(n => n.name).join(', ');
|
|
204
|
+
this.emit(`/* use { ${names} } from ${raw} */`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ===== Functions =====
|
|
208
|
+
|
|
209
|
+
visitFunction(node) {
|
|
210
|
+
const retType = node.returnType ? this.mapType(node.returnType) : 'auto';
|
|
211
|
+
const params = node.params.map(p => {
|
|
212
|
+
const type = p.type ? this.mapType(p.type) : 'auto';
|
|
213
|
+
let s = '';
|
|
214
|
+
if (p.spread) s += '/* variadic */ ';
|
|
215
|
+
s += `${type} ${p.name}`;
|
|
216
|
+
if (p.defaultValue) s += ` = ${this.expr(p.defaultValue)}`;
|
|
217
|
+
return s;
|
|
218
|
+
}).join(', ');
|
|
219
|
+
|
|
220
|
+
const savedInFunction = this.inFunction;
|
|
221
|
+
this.inFunction = true;
|
|
222
|
+
|
|
223
|
+
// Use void if no return type and function doesn't return values
|
|
224
|
+
const actualRetType = retType === 'auto' ? 'void' : retType;
|
|
225
|
+
this.emit(`${actualRetType} ${node.name}(${params}) {`);
|
|
226
|
+
this.indent++;
|
|
227
|
+
for (const stmt of node.body) {
|
|
228
|
+
this.visitStatement(stmt);
|
|
229
|
+
}
|
|
230
|
+
this.indent--;
|
|
231
|
+
this.emit('}');
|
|
232
|
+
this.emitRaw('');
|
|
233
|
+
|
|
234
|
+
this.inFunction = savedInFunction;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
visitReturn(node) {
|
|
238
|
+
if (node.value === null) {
|
|
239
|
+
this.emit('return;');
|
|
240
|
+
} else {
|
|
241
|
+
this.emit(`return ${this.expr(node.value)};`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
visitReturnStatus(node) {
|
|
246
|
+
this.emit(`/* return status ${this.expr(node.statusCode)} */`);
|
|
247
|
+
this.includes.add('<iostream>');
|
|
248
|
+
this.emit(`cout << ${this.expr(node.body)} << endl;`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
visitReturnMethod(node) {
|
|
252
|
+
this.emit(`/* return ${node.method}: ${this.expr(node.value)} */`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ===== Variables =====
|
|
256
|
+
|
|
257
|
+
visitTypedVar(node) {
|
|
258
|
+
const type = node.varType ? this.mapType(node.varType) : 'auto';
|
|
259
|
+
this.emit(`${type} ${node.name} = ${this.expr(node.value)};`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
visitAssignment(node) {
|
|
263
|
+
const value = this.expr(node.value);
|
|
264
|
+
if (node.target.type === 'Array') {
|
|
265
|
+
// C++17 structured bindings
|
|
266
|
+
const names = node.target.elements.map(e => this.expr(e)).join(', ');
|
|
267
|
+
this.emit(`auto [${names}] = ${value};`);
|
|
268
|
+
} else if (node.target.type === 'Object') {
|
|
269
|
+
// No direct object destructuring in C++
|
|
270
|
+
this.emit(`/* object destructuring */`);
|
|
271
|
+
this.emit(`auto __d = ${value};`);
|
|
272
|
+
for (const p of node.target.properties) {
|
|
273
|
+
const key = p.type === 'shorthand' ? p.key : p.key;
|
|
274
|
+
const varName = p.type === 'shorthand' ? p.key : this.expr(p.value);
|
|
275
|
+
this.emit(`auto ${varName} = __d["${key}"];`);
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
this.emit(`${this.expr(node.target)} = ${value};`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
visitCompoundAssign(node) {
|
|
283
|
+
this.emit(`${this.expr(node.target)} ${node.op} ${this.expr(node.value)};`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ===== Control flow =====
|
|
287
|
+
|
|
288
|
+
visitIf(node) {
|
|
289
|
+
this.emit(`if (${this.expr(node.condition)}) {`);
|
|
290
|
+
this.indent++;
|
|
291
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
292
|
+
this.indent--;
|
|
293
|
+
|
|
294
|
+
for (const elif of node.elifs) {
|
|
295
|
+
this.emit(`} else if (${this.expr(elif.condition)}) {`);
|
|
296
|
+
this.indent++;
|
|
297
|
+
for (const stmt of elif.body) this.visitStatement(stmt);
|
|
298
|
+
this.indent--;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (node.elseBody) {
|
|
302
|
+
this.emit('} else {');
|
|
303
|
+
this.indent++;
|
|
304
|
+
for (const stmt of node.elseBody) this.visitStatement(stmt);
|
|
305
|
+
this.indent--;
|
|
306
|
+
}
|
|
307
|
+
this.emit('}');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
visitEach(node) {
|
|
311
|
+
const collection = this.expr(node.collection);
|
|
312
|
+
if (node.key) {
|
|
313
|
+
this.emit(`/* key-value iteration */`);
|
|
314
|
+
this.emit(`for (auto& [${node.key}, ${node.value}] : ${collection}) {`);
|
|
315
|
+
} else {
|
|
316
|
+
this.emit(`for (auto& ${node.value} : ${collection}) {`);
|
|
317
|
+
}
|
|
318
|
+
this.indent++;
|
|
319
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
320
|
+
this.indent--;
|
|
321
|
+
this.emit('}');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
visitFor(node) {
|
|
325
|
+
const varName = node.varName;
|
|
326
|
+
const start = this.expr(node.start);
|
|
327
|
+
const end = this.expr(node.end);
|
|
328
|
+
this.emit(`for (int ${varName} = ${start}; ${varName} < ${end}; ${varName}++) {`);
|
|
329
|
+
this.indent++;
|
|
330
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
331
|
+
this.indent--;
|
|
332
|
+
this.emit('}');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
visitWhile(node) {
|
|
336
|
+
this.emit(`while (${this.expr(node.condition)}) {`);
|
|
337
|
+
this.indent++;
|
|
338
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
339
|
+
this.indent--;
|
|
340
|
+
this.emit('}');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
visitMatch(node) {
|
|
344
|
+
this.emit(`switch (${this.expr(node.value)}) {`);
|
|
345
|
+
this.indent++;
|
|
346
|
+
for (const c of node.cases) {
|
|
347
|
+
if (c.pattern.type === 'DefaultPattern') {
|
|
348
|
+
this.emit('default: {');
|
|
349
|
+
} else {
|
|
350
|
+
this.emit(`case ${this.expr(c.pattern)}: {`);
|
|
351
|
+
}
|
|
352
|
+
this.indent++;
|
|
353
|
+
for (const stmt of c.body) this.visitStatement(stmt);
|
|
354
|
+
this.emit('break;');
|
|
355
|
+
this.indent--;
|
|
356
|
+
this.emit('}');
|
|
357
|
+
}
|
|
358
|
+
this.indent--;
|
|
359
|
+
this.emit('}');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
visitTry(node) {
|
|
363
|
+
this.includes.add('<stdexcept>');
|
|
364
|
+
this.emit('try {');
|
|
365
|
+
this.indent++;
|
|
366
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
367
|
+
this.indent--;
|
|
368
|
+
if (node.catchBody) {
|
|
369
|
+
const catchParam = node.catchVar || 'e';
|
|
370
|
+
this.emit(`} catch (const exception& ${catchParam}) {`);
|
|
371
|
+
this.indent++;
|
|
372
|
+
for (const stmt of node.catchBody) this.visitStatement(stmt);
|
|
373
|
+
this.indent--;
|
|
374
|
+
}
|
|
375
|
+
if (node.ensureBody) {
|
|
376
|
+
// C++ has no finally; use RAII or scope guard pattern
|
|
377
|
+
this.emit('} /* finally */ {');
|
|
378
|
+
this.indent++;
|
|
379
|
+
for (const stmt of node.ensureBody) this.visitStatement(stmt);
|
|
380
|
+
this.indent--;
|
|
381
|
+
}
|
|
382
|
+
this.emit('}');
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ===== Model (class) =====
|
|
386
|
+
|
|
387
|
+
visitModel(node) {
|
|
388
|
+
this.models.set(node.name, node);
|
|
389
|
+
|
|
390
|
+
const ext = node.parent ? ` : public ${node.parent}` : '';
|
|
391
|
+
let classDef = `class ${node.name}${ext} {\npublic:\n`;
|
|
392
|
+
|
|
393
|
+
// Fields
|
|
394
|
+
for (const f of node.fields) {
|
|
395
|
+
const type = f.type ? this.mapType(f.type) : 'auto';
|
|
396
|
+
classDef += ` ${type} ${f.name};\n`;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Constructor
|
|
400
|
+
if (node.fields.length > 0 || node.parent) {
|
|
401
|
+
const parentModel = node.parent ? this.models.get(node.parent) : null;
|
|
402
|
+
const parentFields = parentModel ? parentModel.fields : [];
|
|
403
|
+
const allFields = [...parentFields, ...node.fields];
|
|
404
|
+
|
|
405
|
+
const ctorParams = allFields.map(f => {
|
|
406
|
+
const type = f.type ? this.mapType(f.type) : 'auto';
|
|
407
|
+
if (f.defaultValue) return `${type} ${f.name} = ${this.expr(f.defaultValue)}`;
|
|
408
|
+
return `${type} ${f.name}`;
|
|
409
|
+
}).join(', ');
|
|
410
|
+
|
|
411
|
+
classDef += `\n ${node.name}(${ctorParams})`;
|
|
412
|
+
if (node.parent) {
|
|
413
|
+
const superArgs = parentFields.map(f => f.name).join(', ');
|
|
414
|
+
classDef += ` : ${node.parent}(${superArgs})`;
|
|
415
|
+
if (node.fields.length > 0) {
|
|
416
|
+
classDef += ', ' + node.fields.map(f => `${f.name}(${f.name})`).join(', ');
|
|
417
|
+
}
|
|
418
|
+
} else if (node.fields.length > 0) {
|
|
419
|
+
classDef += ' : ' + node.fields.map(f => `${f.name}(${f.name})`).join(', ');
|
|
420
|
+
}
|
|
421
|
+
classDef += ' {}\n';
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Methods
|
|
425
|
+
for (const method of node.methods) {
|
|
426
|
+
const retType = method.returnType ? this.mapType(method.returnType) : 'void';
|
|
427
|
+
const params = method.params.map(p => {
|
|
428
|
+
const type = p.type ? this.mapType(p.type) : 'auto';
|
|
429
|
+
let s = `${type} ${p.name}`;
|
|
430
|
+
if (p.defaultValue) s += ` = ${this.expr(p.defaultValue)}`;
|
|
431
|
+
return s;
|
|
432
|
+
}).join(', ');
|
|
433
|
+
|
|
434
|
+
classDef += `\n ${retType} ${method.name}(${params}) {\n`;
|
|
435
|
+
// Generate method body
|
|
436
|
+
const bodyLines = this.generateBodyLines(method.body);
|
|
437
|
+
for (const line of bodyLines) {
|
|
438
|
+
classDef += ` ${line}\n`;
|
|
439
|
+
}
|
|
440
|
+
classDef += ' }\n';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
classDef += '};';
|
|
444
|
+
this.emitClass(classDef);
|
|
445
|
+
this.emitClass('');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
generateBodyLines(body) {
|
|
449
|
+
const savedInFunction = this.inFunction;
|
|
450
|
+
const savedFunctions = this.functionDefs;
|
|
451
|
+
const savedMain = this.mainBody;
|
|
452
|
+
const savedIndent = this.indent;
|
|
453
|
+
this.functionDefs = [];
|
|
454
|
+
this.mainBody = [];
|
|
455
|
+
this.indent = 0;
|
|
456
|
+
this.inFunction = false;
|
|
457
|
+
for (const stmt of body) this.visitStatement(stmt);
|
|
458
|
+
const lines = this.mainBody.map(l => l.trim());
|
|
459
|
+
this.functionDefs = savedFunctions;
|
|
460
|
+
this.mainBody = savedMain;
|
|
461
|
+
this.indent = savedIndent;
|
|
462
|
+
this.inFunction = savedInFunction;
|
|
463
|
+
return lines;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ===== Log =====
|
|
467
|
+
|
|
468
|
+
visitLog(node) {
|
|
469
|
+
this.includes.add('<iostream>');
|
|
470
|
+
const args = node.args.map(a => this.expr(a));
|
|
471
|
+
if (args.length === 1) {
|
|
472
|
+
this.emit(`cout << ${args[0]} << endl;`);
|
|
473
|
+
} else {
|
|
474
|
+
const chain = args.join(' << " " << ');
|
|
475
|
+
this.emit(`cout << ${chain} << endl;`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
visitThrow(node) {
|
|
480
|
+
this.includes.add('<stdexcept>');
|
|
481
|
+
const value = this.expr(node.value);
|
|
482
|
+
if (node.value.type === 'String') {
|
|
483
|
+
this.emit(`throw runtime_error(${value});`);
|
|
484
|
+
} else {
|
|
485
|
+
this.emit(`throw ${value};`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// ===== Events =====
|
|
490
|
+
|
|
491
|
+
visitOn(node) {
|
|
492
|
+
this.emit(`/* on event: ${this.expr(node.event)} */`);
|
|
493
|
+
this.emit(`/* C++ has no built-in event system - use std::function callbacks or signals2 */`);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ===== Server =====
|
|
497
|
+
|
|
498
|
+
visitServer(node) {
|
|
499
|
+
this.emit('/* HTTP server: use cpp-httplib or Crow */');
|
|
500
|
+
this.emit(`/* server "${node.name}" */`);
|
|
501
|
+
const port = node.port ? this.expr(node.port) : '3000';
|
|
502
|
+
this.emit(`/* port: ${port} */`);
|
|
503
|
+
|
|
504
|
+
for (const child of node.routes) {
|
|
505
|
+
if (child.type === 'Route') {
|
|
506
|
+
const method = child.method.toUpperCase();
|
|
507
|
+
const path = this.rawString(child.path);
|
|
508
|
+
this.emit(`/* ${method} ${path} */`);
|
|
509
|
+
this.emit(`/* { */`);
|
|
510
|
+
this.indent++;
|
|
511
|
+
for (const stmt of child.body) this.visitStatement(stmt);
|
|
512
|
+
this.indent--;
|
|
513
|
+
this.emit(`/* } */`);
|
|
514
|
+
this.emitRaw('');
|
|
515
|
+
} else {
|
|
516
|
+
this.visitStatement(child);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
this.emit(`cout << "Server ${node.name} would run on port ${port}" << endl;`);
|
|
521
|
+
this.emitRaw('');
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// ===== Bot =====
|
|
525
|
+
|
|
526
|
+
visitBot(node) {
|
|
527
|
+
this.emit('/* Bot: use D++ (DPP) for Discord, or libcurl for API-based bots */');
|
|
528
|
+
this.emit(`/* TODO: bot "${node.name}" */`);
|
|
529
|
+
this.emitRaw('');
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ===== Database =====
|
|
533
|
+
|
|
534
|
+
visitDbConnect(node) {
|
|
535
|
+
this.emit(`/* db connect: ${this.expr(node.connectionString)} */`);
|
|
536
|
+
this.emit('/* TODO: use libpqxx (PostgreSQL), sqlite3 C++ wrapper, or SOCI */');
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
visitDbDir(node) {
|
|
540
|
+
const raw = node.path.raw || node.path.parts?.map(p => p.value).join('') || 'data/';
|
|
541
|
+
this.emit(`/* db dir: ${raw} */`);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
visitDbSql(node) {
|
|
545
|
+
this.emit('/* db sql: use SQLite C++ wrapper or SOCI */');
|
|
546
|
+
this.emit('/* #include <sqlite3.h> */');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
visitAwaitAll(node) {
|
|
550
|
+
this.includes.add('<future>');
|
|
551
|
+
this.emit('/* async: use std::async and std::future */');
|
|
552
|
+
for (const e of node.expressions) {
|
|
553
|
+
this.emit(`auto __f = std::async(std::launch::async, [&]() { return ${this.expr(e)}; });`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// ===== Domain features (comment stubs) =====
|
|
558
|
+
|
|
559
|
+
visitSchema(node) {
|
|
560
|
+
this.schemas.set(node.name, node);
|
|
561
|
+
let classDef = `struct ${node.name} {\n`;
|
|
562
|
+
for (const f of node.fields) {
|
|
563
|
+
const type = this.mapType(f.type);
|
|
564
|
+
classDef += ` ${type} ${f.name};\n`;
|
|
565
|
+
}
|
|
566
|
+
classDef += '};';
|
|
567
|
+
this.emitClass(classDef);
|
|
568
|
+
this.emitClass('');
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
visitCrud(node) {
|
|
572
|
+
this.emit(`/* TODO: CRUD for "${node.schemaName}" - use cpp-httplib or Crow */`);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
visitAuth(node) {
|
|
576
|
+
this.emit('/* TODO: auth - use jwt-cpp library */');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
visitCors(node) {
|
|
580
|
+
this.emit('/* TODO: CORS - set headers in HTTP response */');
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
visitLimit(node) {
|
|
584
|
+
this.emit('/* TODO: rate limiting - implement with token bucket algorithm */');
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
visitEnv(node) {
|
|
588
|
+
this.includes.add('<cstdlib>');
|
|
589
|
+
for (const v of node.vars) {
|
|
590
|
+
this.includes.add('<string>');
|
|
591
|
+
this.emit(`const char* __${v.name}_raw = getenv("${v.name}");`);
|
|
592
|
+
if (v.type === 'int') {
|
|
593
|
+
this.emit(`int ${v.name} = __${v.name}_raw ? atoi(__${v.name}_raw) : 0;`);
|
|
594
|
+
} else if (v.type === 'num') {
|
|
595
|
+
this.emit(`double ${v.name} = __${v.name}_raw ? atof(__${v.name}_raw) : 0.0;`);
|
|
596
|
+
} else if (v.type === 'bool') {
|
|
597
|
+
this.includes.add('<cstring>');
|
|
598
|
+
this.emit(`bool ${v.name} = __${v.name}_raw ? (strcmp(__${v.name}_raw, "true") == 0 || strcmp(__${v.name}_raw, "1") == 0) : false;`);
|
|
599
|
+
} else {
|
|
600
|
+
this.emit(`string ${v.name} = __${v.name}_raw ? string(__${v.name}_raw) : "";`);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
this.emitRaw('');
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
visitEvery(node) {
|
|
607
|
+
this.emit('/* TODO: scheduled task - use std::thread + std::chrono::sleep_for */');
|
|
608
|
+
this.includes.add('<thread>');
|
|
609
|
+
this.includes.add('<chrono>');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
visitWatch(node) {
|
|
613
|
+
this.emit(`/* TODO: watch event "${node.eventName}" - use std::function callback pattern */`);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
visitStatic(node) {
|
|
617
|
+
this.emit('/* TODO: static files - use cpp-httplib to serve files */');
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
visitWs(node) {
|
|
621
|
+
this.emit('/* TODO: WebSocket - use websocketpp or Boost.Beast */');
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
visitGroup(node) {
|
|
625
|
+
this.emit('/* TODO: route group - implement with HTTP library */');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
visitErrorHandler(node) {
|
|
629
|
+
this.emit('/* TODO: error handler - use try/catch */');
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
visitCookie(node) {
|
|
633
|
+
this.emit('/* TODO: cookies - set via HTTP headers */');
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
visitUpload(node) {
|
|
637
|
+
this.emit('/* TODO: file upload - use multipart form parser */');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
visitSession(node) {
|
|
641
|
+
this.emit('/* TODO: sessions - use std::unordered_map for session storage */');
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
visitView(node) {
|
|
645
|
+
this.emit('/* TODO: view engine - use inja (Jinja2-like C++ template engine) */');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
visitSse(node) {
|
|
649
|
+
this.emit('/* TODO: Server-Sent Events - use chunked HTTP response */');
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
visitCache(node) {
|
|
653
|
+
this.emit('/* TODO: caching - use std::unordered_map with TTL */');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
visitMiddlewareRef(node) {
|
|
657
|
+
this.emit(`/* TODO: middleware "${node.name}" */`);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
visitReturnRender(node) {
|
|
661
|
+
this.emit(`/* TODO: render template ${this.expr(node.template)} */`);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
visitValidate(node) {
|
|
665
|
+
this.emit('/* TODO: validation - implement manually */');
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
visitTest(node) {
|
|
669
|
+
this.includes.add('<cassert>');
|
|
670
|
+
const name = this.rawString(node.name);
|
|
671
|
+
const funcName = `test_${name.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
672
|
+
|
|
673
|
+
const savedInFunction = this.inFunction;
|
|
674
|
+
this.inFunction = true;
|
|
675
|
+
|
|
676
|
+
this.emit(`void ${funcName}() {`);
|
|
677
|
+
this.indent++;
|
|
678
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
679
|
+
this.indent--;
|
|
680
|
+
this.emit('}');
|
|
681
|
+
this.emitRaw('');
|
|
682
|
+
|
|
683
|
+
this.inFunction = savedInFunction;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
visitAssert(node) {
|
|
687
|
+
this.includes.add('<cassert>');
|
|
688
|
+
const exprNode = node.expr;
|
|
689
|
+
if (exprNode.type === 'Binary' && (exprNode.op === '===' || exprNode.op === '==')) {
|
|
690
|
+
this.emit(`assert(${this.expr(exprNode.left)} == ${this.expr(exprNode.right)});`);
|
|
691
|
+
} else if (exprNode.type === 'Binary' && (exprNode.op === '!==' || exprNode.op === '!=')) {
|
|
692
|
+
this.emit(`assert(${this.expr(exprNode.left)} != ${this.expr(exprNode.right)});`);
|
|
693
|
+
} else {
|
|
694
|
+
this.emit(`assert(${this.expr(exprNode)});`);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
visitQueue(node) {
|
|
699
|
+
this.includes.add('<queue>');
|
|
700
|
+
this.includes.add('<functional>');
|
|
701
|
+
this.emit(`/* TODO: queue "${node.name}" - use std::queue + std::thread */`);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
visitOpenapi(node) {
|
|
705
|
+
this.emit('/* TODO: OpenAPI spec - generate JSON with nlohmann/json */');
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
visitReturnRedirect(node) {
|
|
709
|
+
this.emit(`/* TODO: redirect to ${this.expr(node.url)} */`);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
visitReturnDownload(node) {
|
|
713
|
+
this.emit(`/* TODO: download file ${this.expr(node.filePath)} */`);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
visitPrompt(node) {
|
|
717
|
+
this.emit(`/* TODO: prompt template "${node.name}" - use string replacement */`);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
visitPage(node) {
|
|
721
|
+
this.includes.add('<fstream>');
|
|
722
|
+
this.emit('/* TODO: page generation - use std::ofstream to write HTML */');
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
visitCli(node) {
|
|
726
|
+
this.includes.add('<string>');
|
|
727
|
+
this.includes.add('<cstring>');
|
|
728
|
+
this.emit('/* CLI argument parsing */');
|
|
729
|
+
this.emit('/* argc and argv available in main() */');
|
|
730
|
+
|
|
731
|
+
for (const arg of node.args) {
|
|
732
|
+
const argName = this.rawString(arg.name);
|
|
733
|
+
this.emit(`/* --${argName}: ${arg.type} */`);
|
|
734
|
+
}
|
|
735
|
+
for (const flag of node.flags) {
|
|
736
|
+
const s = this.rawString(flag.short);
|
|
737
|
+
const l = this.rawString(flag.long);
|
|
738
|
+
this.emit(`/* -${s}, --${l} */`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
visitMail(node) {
|
|
743
|
+
this.emit('/* TODO: mail - use cpp-netlib or libcurl for SMTP */');
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
visitDesktop(node) {
|
|
747
|
+
this.emit(`/* TODO: desktop app "${node.name}" - use Qt, wxWidgets, or SDL2 */`);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
visitScreen(node) {
|
|
751
|
+
this.emit(`/* TODO: mobile screen "${node.name}" - not directly applicable in C++ */`);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
visitOauth(node) {
|
|
755
|
+
this.emit('/* TODO: OAuth - use libcurl for HTTP + jwt-cpp */');
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
visitPay(node) {
|
|
759
|
+
this.emit('/* TODO: payment - use libcurl for Stripe REST API */');
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
visitStorage(node) {
|
|
763
|
+
this.emit('/* TODO: cloud storage - use AWS SDK for C++ */');
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
visitPdf(node) {
|
|
767
|
+
this.emit('/* TODO: PDF generation - use libharu or PoDoFo */');
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
visitI18n(node) {
|
|
771
|
+
this.emit('/* TODO: i18n - use gettext or std::map-based lookup */');
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
visitPush(node) {
|
|
775
|
+
this.emit('/* TODO: push notifications - use libcurl for web push API */');
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
visitSearch(node) {
|
|
779
|
+
this.emit('/* TODO: search - use libcurl for Elasticsearch/Meilisearch API */');
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
visitImage(node) {
|
|
783
|
+
this.emit('/* TODO: image processing - use OpenCV or stb_image */');
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
visitCsv(node) {
|
|
787
|
+
this.includes.add('<fstream>');
|
|
788
|
+
this.includes.add('<sstream>');
|
|
789
|
+
this.emit('/* TODO: CSV - use std::fstream for reading/writing */');
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
visitLogging(node) {
|
|
793
|
+
this.emit('/* TODO: logging - use spdlog or custom logger */');
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
visitMigrate(node) {
|
|
797
|
+
this.emit('/* TODO: DB migration - use sqlite3 C++ wrapper */');
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
visitGrpc(node) {
|
|
801
|
+
this.emit('/* TODO: gRPC - use grpc++ (gRPC C++ library) */');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
visitWebrtc(node) {
|
|
805
|
+
this.emit('/* TODO: WebRTC - use libdatachannel or Google WebRTC C++ */');
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
visitBlockchain(node) {
|
|
809
|
+
this.emit('/* TODO: blockchain - use libcurl for JSON-RPC or web3cpp */');
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// ===== Expression generation =====
|
|
813
|
+
|
|
814
|
+
expr(node) {
|
|
815
|
+
if (!node) return 'nullptr';
|
|
816
|
+
|
|
817
|
+
switch (node.type) {
|
|
818
|
+
case 'Number': return node.value;
|
|
819
|
+
|
|
820
|
+
case 'String': return this.generateString(node.value);
|
|
821
|
+
|
|
822
|
+
case 'Bool': return node.value ? 'true' : 'false';
|
|
823
|
+
|
|
824
|
+
case 'Null': return 'nullptr';
|
|
825
|
+
|
|
826
|
+
case 'Self': return 'this';
|
|
827
|
+
|
|
828
|
+
case 'Identifier': return this.mapIdentifier(node.name);
|
|
829
|
+
|
|
830
|
+
case 'Binary': {
|
|
831
|
+
const op = this.mapBinaryOp(node.op);
|
|
832
|
+
const l = this.expr(node.left);
|
|
833
|
+
const r = this.expr(node.right);
|
|
834
|
+
const simple = node.left.type !== 'Binary' && node.right.type !== 'Binary';
|
|
835
|
+
return simple ? `${l} ${op} ${r}` : `(${l} ${op} ${r})`;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
case 'Unary':
|
|
839
|
+
return `${this.mapUnaryOp(node.op)}${this.expr(node.expr)}`;
|
|
840
|
+
|
|
841
|
+
case 'Await':
|
|
842
|
+
// C++ uses futures
|
|
843
|
+
return `/* co_await */ ${this.expr(node.expr)}`;
|
|
844
|
+
|
|
845
|
+
case 'AwaitAllExpr':
|
|
846
|
+
return `/* await all */ ${this.expr(node.expr)}`;
|
|
847
|
+
|
|
848
|
+
case 'Spread':
|
|
849
|
+
return `/* spread */ ${this.expr(node.expr)}`;
|
|
850
|
+
|
|
851
|
+
case 'New':
|
|
852
|
+
return `make_shared<${this.exprTypeName(node.expr)}>(${this.exprCallArgs(node.expr)})`;
|
|
853
|
+
|
|
854
|
+
case 'TypeOf':
|
|
855
|
+
this.includes.add('<typeinfo>');
|
|
856
|
+
return `typeid(${this.expr(node.expr)}).name()`;
|
|
857
|
+
|
|
858
|
+
case 'MemberAccess':
|
|
859
|
+
return this.generateMemberAccess(node);
|
|
860
|
+
|
|
861
|
+
case 'OptionalAccess':
|
|
862
|
+
return `${this.expr(node.object)}.${node.property}`;
|
|
863
|
+
|
|
864
|
+
case 'Call':
|
|
865
|
+
return this.generateCall(node);
|
|
866
|
+
|
|
867
|
+
case 'IndexAccess':
|
|
868
|
+
return `${this.expr(node.object)}[${this.expr(node.index)}]`;
|
|
869
|
+
|
|
870
|
+
case 'Array': {
|
|
871
|
+
this.includes.add('<vector>');
|
|
872
|
+
this.includes.add('<any>');
|
|
873
|
+
const elems = node.elements.map(e => this.expr(e)).join(', ');
|
|
874
|
+
return `vector<any>{${elems}}`;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
case 'Object': {
|
|
878
|
+
this.includes.add('<map>');
|
|
879
|
+
this.includes.add('<string>');
|
|
880
|
+
this.includes.add('<any>');
|
|
881
|
+
const props = node.properties.map(p => {
|
|
882
|
+
if (p.type === 'spread') return `/* spread: ${this.expr(p.value)} */`;
|
|
883
|
+
if (p.type === 'shorthand') return `{"${p.key}", ${p.key}}`;
|
|
884
|
+
const key = typeof p.key === 'string' ? `"${p.key}"` :
|
|
885
|
+
(p.key.type === 'String' ? this.generateString(p.key.value) :
|
|
886
|
+
`"${this.expr(p.key)}"`);
|
|
887
|
+
return `{${key}, ${this.expr(p.value)}}`;
|
|
888
|
+
}).join(', ');
|
|
889
|
+
return `map<string, any>{${props}}`;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
case 'ArrowFn': {
|
|
893
|
+
const params = node.params.map(p => `auto ${p.name}`).join(', ');
|
|
894
|
+
const body = this.expr(node.body);
|
|
895
|
+
return `[](${params}) { return ${body}; }`;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
case 'Lambda': {
|
|
899
|
+
const params = node.params.map(p => `auto ${p.name}`).join(', ');
|
|
900
|
+
const bodyLines = this.generateBodyLines(node.body);
|
|
901
|
+
return `[](${params}) { ${bodyLines.join(' ')} }`;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
case 'Ternary':
|
|
905
|
+
return `(${this.expr(node.condition)} ? ${this.expr(node.consequent)} : ${this.expr(node.alternate)})`;
|
|
906
|
+
|
|
907
|
+
case 'Pipe':
|
|
908
|
+
return this.generatePipe(node);
|
|
909
|
+
|
|
910
|
+
default:
|
|
911
|
+
return `/* expr:${node.type} */ nullptr`;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
exprTypeName(node) {
|
|
916
|
+
if (node.type === 'Call') return this.expr(node.callee);
|
|
917
|
+
return this.expr(node);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
exprCallArgs(node) {
|
|
921
|
+
if (node.type === 'Call') return node.args.map(a => this.expr(a)).join(', ');
|
|
922
|
+
return '';
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
mapIdentifier(name) {
|
|
926
|
+
const map = {
|
|
927
|
+
'null': 'nullptr',
|
|
928
|
+
'undefined': 'nullptr',
|
|
929
|
+
'true': 'true',
|
|
930
|
+
'false': 'false',
|
|
931
|
+
'this': 'this',
|
|
932
|
+
};
|
|
933
|
+
return map[name] || name;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
mapBinaryOp(op) {
|
|
937
|
+
const map = {
|
|
938
|
+
'===': '==',
|
|
939
|
+
'!==': '!=',
|
|
940
|
+
'&&': '&&',
|
|
941
|
+
'||': '||',
|
|
942
|
+
'and': '&&',
|
|
943
|
+
'or': '||',
|
|
944
|
+
};
|
|
945
|
+
return map[op] || op;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
mapUnaryOp(op) {
|
|
949
|
+
if (op === 'not' || op === '!') return '!';
|
|
950
|
+
return op;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
generateMemberAccess(node) {
|
|
954
|
+
const obj = this.expr(node.object);
|
|
955
|
+
const prop = node.property;
|
|
956
|
+
|
|
957
|
+
// Map common patterns
|
|
958
|
+
if (prop === 'length') {
|
|
959
|
+
return `${obj}.size()`;
|
|
960
|
+
}
|
|
961
|
+
if (prop === 'toString') {
|
|
962
|
+
this.includes.add('<string>');
|
|
963
|
+
return `to_string(${obj})`;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// Console methods -> cout
|
|
967
|
+
if (obj === 'console' && prop === 'log') {
|
|
968
|
+
return '/* cout << */';
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Math methods
|
|
972
|
+
if (obj === 'Math' && prop === 'PI') { this.includes.add('<cmath>'); return 'M_PI'; }
|
|
973
|
+
if (obj === 'Math' && prop === 'E') { this.includes.add('<cmath>'); return 'M_E'; }
|
|
974
|
+
|
|
975
|
+
// JSON
|
|
976
|
+
if (obj === 'JSON' && prop === 'parse') return '/* JSON parse: use nlohmann/json */';
|
|
977
|
+
if (obj === 'JSON' && prop === 'stringify') return '/* JSON stringify: use nlohmann/json */';
|
|
978
|
+
|
|
979
|
+
return `${obj}.${prop}`;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
generateCall(node) {
|
|
983
|
+
const args = node.args.map(a => this.expr(a)).join(', ');
|
|
984
|
+
|
|
985
|
+
if (node.callee.type === 'Identifier') {
|
|
986
|
+
const name = node.callee.name;
|
|
987
|
+
if (name === 'parseInt') return `stoi(${args})`;
|
|
988
|
+
if (name === 'parseFloat') return `stod(${args})`;
|
|
989
|
+
if (name === 'String') { this.includes.add('<string>'); return `to_string(${args})`; }
|
|
990
|
+
if (name === 'Number') return `stod(${args})`;
|
|
991
|
+
if (name === 'Boolean') return `static_cast<bool>(${args})`;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (node.callee.type === 'MemberAccess') {
|
|
995
|
+
const obj = this.expr(node.callee.object);
|
|
996
|
+
const prop = node.callee.property;
|
|
997
|
+
|
|
998
|
+
// Vector/list methods
|
|
999
|
+
if (prop === 'push') return `${obj}.push_back(${args})`;
|
|
1000
|
+
if (prop === 'pop') return `${obj}.pop_back()`;
|
|
1001
|
+
if (prop === 'shift') { return `/* shift: erase front */ ${obj}.erase(${obj}.begin())`; }
|
|
1002
|
+
if (prop === 'unshift') { return `${obj}.insert(${obj}.begin(), ${args})`; }
|
|
1003
|
+
if (prop === 'includes') {
|
|
1004
|
+
this.includes.add('<algorithm>');
|
|
1005
|
+
return `(find(${obj}.begin(), ${obj}.end(), ${args}) != ${obj}.end())`;
|
|
1006
|
+
}
|
|
1007
|
+
if (prop === 'indexOf') {
|
|
1008
|
+
this.includes.add('<algorithm>');
|
|
1009
|
+
return `(find(${obj}.begin(), ${obj}.end(), ${args}) - ${obj}.begin())`;
|
|
1010
|
+
}
|
|
1011
|
+
if (prop === 'join') {
|
|
1012
|
+
this.includes.add('<sstream>');
|
|
1013
|
+
return `/* join: use ostringstream */ ""`;
|
|
1014
|
+
}
|
|
1015
|
+
if (prop === 'reverse') {
|
|
1016
|
+
this.includes.add('<algorithm>');
|
|
1017
|
+
return `reverse(${obj}.begin(), ${obj}.end())`;
|
|
1018
|
+
}
|
|
1019
|
+
if (prop === 'sort') {
|
|
1020
|
+
this.includes.add('<algorithm>');
|
|
1021
|
+
return `sort(${obj}.begin(), ${obj}.end())`;
|
|
1022
|
+
}
|
|
1023
|
+
if (prop === 'map') return `/* std::transform */ ${obj}`;
|
|
1024
|
+
if (prop === 'filter') return `/* std::copy_if */ ${obj}`;
|
|
1025
|
+
if (prop === 'forEach') return `/* for (auto& x : ${obj}) */ ${obj}`;
|
|
1026
|
+
if (prop === 'find') {
|
|
1027
|
+
this.includes.add('<algorithm>');
|
|
1028
|
+
return `*find_if(${obj}.begin(), ${obj}.end(), ${args})`;
|
|
1029
|
+
}
|
|
1030
|
+
if (prop === 'some') {
|
|
1031
|
+
this.includes.add('<algorithm>');
|
|
1032
|
+
return `any_of(${obj}.begin(), ${obj}.end(), ${args})`;
|
|
1033
|
+
}
|
|
1034
|
+
if (prop === 'every') {
|
|
1035
|
+
this.includes.add('<algorithm>');
|
|
1036
|
+
return `all_of(${obj}.begin(), ${obj}.end(), ${args})`;
|
|
1037
|
+
}
|
|
1038
|
+
if (prop === 'reduce') {
|
|
1039
|
+
this.includes.add('<numeric>');
|
|
1040
|
+
return `accumulate(${obj}.begin(), ${obj}.end(), 0, ${args})`;
|
|
1041
|
+
}
|
|
1042
|
+
if (prop === 'flat') return `/* flatten: manual */ ${obj}`;
|
|
1043
|
+
if (prop === 'concat') return `/* concat: insert */ ${obj}`;
|
|
1044
|
+
if (prop === 'slice') return `/* slice: use iterators */ ${obj}`;
|
|
1045
|
+
|
|
1046
|
+
// String methods
|
|
1047
|
+
if (prop === 'split') return `/* split: use istringstream */ ${obj}`;
|
|
1048
|
+
if (prop === 'trim') return `/* trim: custom implementation */ ${obj}`;
|
|
1049
|
+
if (prop === 'trimStart') return `/* trimStart: custom implementation */ ${obj}`;
|
|
1050
|
+
if (prop === 'trimEnd') return `/* trimEnd: custom implementation */ ${obj}`;
|
|
1051
|
+
if (prop === 'toUpperCase') {
|
|
1052
|
+
this.includes.add('<algorithm>');
|
|
1053
|
+
this.includes.add('<cctype>');
|
|
1054
|
+
return `/* transform to upper */ ${obj}`;
|
|
1055
|
+
}
|
|
1056
|
+
if (prop === 'toLowerCase') {
|
|
1057
|
+
this.includes.add('<algorithm>');
|
|
1058
|
+
this.includes.add('<cctype>');
|
|
1059
|
+
return `/* transform to lower */ ${obj}`;
|
|
1060
|
+
}
|
|
1061
|
+
if (prop === 'startsWith') return `${obj}.starts_with(${args})`;
|
|
1062
|
+
if (prop === 'endsWith') return `${obj}.ends_with(${args})`;
|
|
1063
|
+
if (prop === 'replace') return `/* replace: use std::regex_replace */ ${obj}`;
|
|
1064
|
+
if (prop === 'replaceAll') return `/* replaceAll: use std::regex_replace */ ${obj}`;
|
|
1065
|
+
if (prop === 'charAt') return `${obj}[${args}]`;
|
|
1066
|
+
if (prop === 'substring') return `${obj}.substr(${args})`;
|
|
1067
|
+
if (prop === 'repeat') return `/* repeat: loop append */ ${obj}`;
|
|
1068
|
+
if (prop === 'padStart') return `/* padStart: custom */ ${obj}`;
|
|
1069
|
+
if (prop === 'padEnd') return `/* padEnd: custom */ ${obj}`;
|
|
1070
|
+
|
|
1071
|
+
// Console methods
|
|
1072
|
+
if (obj === 'console' && prop === 'log') {
|
|
1073
|
+
this.includes.add('<iostream>');
|
|
1074
|
+
return `cout << ${args} << endl, 0`;
|
|
1075
|
+
}
|
|
1076
|
+
if (obj === 'console' && prop === 'error') {
|
|
1077
|
+
this.includes.add('<iostream>');
|
|
1078
|
+
return `cerr << ${args} << endl, 0`;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// Math methods
|
|
1082
|
+
if (obj === 'Math' && prop === 'floor') { this.includes.add('<cmath>'); return `floor(${args})`; }
|
|
1083
|
+
if (obj === 'Math' && prop === 'ceil') { this.includes.add('<cmath>'); return `ceil(${args})`; }
|
|
1084
|
+
if (obj === 'Math' && prop === 'round') { this.includes.add('<cmath>'); return `round(${args})`; }
|
|
1085
|
+
if (obj === 'Math' && prop === 'abs') { this.includes.add('<cmath>'); return `abs(${args})`; }
|
|
1086
|
+
if (obj === 'Math' && prop === 'sqrt') { this.includes.add('<cmath>'); return `sqrt(${args})`; }
|
|
1087
|
+
if (obj === 'Math' && prop === 'pow') { this.includes.add('<cmath>'); return `pow(${args})`; }
|
|
1088
|
+
if (obj === 'Math' && prop === 'min') { this.includes.add('<algorithm>'); return `min(${args})`; }
|
|
1089
|
+
if (obj === 'Math' && prop === 'max') { this.includes.add('<algorithm>'); return `max(${args})`; }
|
|
1090
|
+
if (obj === 'Math' && prop === 'random') {
|
|
1091
|
+
this.includes.add('<random>');
|
|
1092
|
+
return `(static_cast<double>(rand()) / RAND_MAX)`;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// Object static methods
|
|
1096
|
+
if (obj === 'Object' && prop === 'keys') return `/* keys: iterate map */ ${args}`;
|
|
1097
|
+
if (obj === 'Object' && prop === 'values') return `/* values: iterate map */ ${args}`;
|
|
1098
|
+
if (obj === 'Object' && prop === 'entries') return `/* entries: iterate map */ ${args}`;
|
|
1099
|
+
|
|
1100
|
+
// Array static
|
|
1101
|
+
if (obj === 'Array' && prop === 'isArray') return `/* isArray */ true`;
|
|
1102
|
+
|
|
1103
|
+
// Date
|
|
1104
|
+
if (obj === 'Date' && prop === 'now') {
|
|
1105
|
+
this.includes.add('<chrono>');
|
|
1106
|
+
return `chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count()`;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
// Promise
|
|
1110
|
+
if (obj === 'Promise' && prop === 'all') {
|
|
1111
|
+
this.includes.add('<future>');
|
|
1112
|
+
return `/* Promise.all: use std::future */ ${args}`;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
const callee = this.expr(node.callee);
|
|
1117
|
+
return `${callee}(${args})`;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
generateString(strData) {
|
|
1121
|
+
if (!strData || !strData.parts) return '""';
|
|
1122
|
+
|
|
1123
|
+
const hasInterpolation = strData.parts.some(p => p.type === 'expr');
|
|
1124
|
+
|
|
1125
|
+
if (!hasInterpolation) {
|
|
1126
|
+
const raw = strData.parts.map(p => p.value).join('');
|
|
1127
|
+
this.includes.add('<string>');
|
|
1128
|
+
return `string(${JSON.stringify(raw)})`;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// C++ string concatenation for interpolation
|
|
1132
|
+
this.includes.add('<string>');
|
|
1133
|
+
let parts = [];
|
|
1134
|
+
for (const part of strData.parts) {
|
|
1135
|
+
if (part.type === 'text') {
|
|
1136
|
+
if (part.value) {
|
|
1137
|
+
parts.push(`string(${JSON.stringify(part.value)})`);
|
|
1138
|
+
}
|
|
1139
|
+
} else {
|
|
1140
|
+
parts.push(`to_string(${part.value})`);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
if (parts.length === 0) return '""';
|
|
1145
|
+
if (parts.length === 1) return parts[0];
|
|
1146
|
+
return parts.join(' + ');
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
generatePipe(node) {
|
|
1150
|
+
const steps = [];
|
|
1151
|
+
let current = node;
|
|
1152
|
+
while (current.type === 'Pipe') {
|
|
1153
|
+
steps.unshift(current.right);
|
|
1154
|
+
current = current.left;
|
|
1155
|
+
}
|
|
1156
|
+
steps.unshift(current);
|
|
1157
|
+
|
|
1158
|
+
let result = this.expr(steps[0]);
|
|
1159
|
+
for (let i = 1; i < steps.length; i++) {
|
|
1160
|
+
const step = steps[i];
|
|
1161
|
+
if (step.type === 'Call') {
|
|
1162
|
+
const callee = this.expr(step.callee);
|
|
1163
|
+
const args = step.args.map(a => this.expr(a)).join(', ');
|
|
1164
|
+
result = `${callee}(${result}${args ? ', ' + args : ''})`;
|
|
1165
|
+
} else if (step.type === 'Identifier') {
|
|
1166
|
+
result = `${step.name}(${result})`;
|
|
1167
|
+
} else {
|
|
1168
|
+
result = `/* pipe */ ${this.expr(step)}`;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return result;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
rawString(strData) {
|
|
1175
|
+
if (!strData) return '';
|
|
1176
|
+
if (strData.raw !== null && strData.raw !== undefined) return strData.raw;
|
|
1177
|
+
if (strData.parts) return strData.parts.map(p => p.value).join('');
|
|
1178
|
+
return '';
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
bodyUsesAwait(body) {
|
|
1182
|
+
for (const stmt of body) {
|
|
1183
|
+
if (this.stmtUsesAwait(stmt)) return true;
|
|
1184
|
+
}
|
|
1185
|
+
return false;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
stmtUsesAwait(node) {
|
|
1189
|
+
if (!node) return false;
|
|
1190
|
+
const json = JSON.stringify(node);
|
|
1191
|
+
return json.includes('"Await"') || json.includes('"AwaitAll"');
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
statementToString(stmt) {
|
|
1195
|
+
const saved = this.inFunction;
|
|
1196
|
+
const savedFunctions = this.functionDefs;
|
|
1197
|
+
const savedMain = this.mainBody;
|
|
1198
|
+
const savedIndent = this.indent;
|
|
1199
|
+
this.functionDefs = [];
|
|
1200
|
+
this.mainBody = [];
|
|
1201
|
+
this.indent = 0;
|
|
1202
|
+
this.inFunction = false;
|
|
1203
|
+
this.visitStatement(stmt);
|
|
1204
|
+
const result = this.mainBody.join('\n');
|
|
1205
|
+
this.functionDefs = savedFunctions;
|
|
1206
|
+
this.mainBody = savedMain;
|
|
1207
|
+
this.indent = savedIndent;
|
|
1208
|
+
this.inFunction = saved;
|
|
1209
|
+
return result;
|
|
1210
|
+
}
|
|
1211
|
+
}
|