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.
@@ -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
+ }