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,1014 @@
|
|
|
1
|
+
export class CGenerator {
|
|
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.typedefs = [];
|
|
9
|
+
this.functions = [];
|
|
10
|
+
this.mainBody = [];
|
|
11
|
+
this.sourceMap = [];
|
|
12
|
+
this.currentSourceLine = 0;
|
|
13
|
+
this.sourceFile = options.sourceFile || null;
|
|
14
|
+
this.inFunction = false;
|
|
15
|
+
this.inMain = false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
generate(ast) {
|
|
19
|
+
this.includes.add('<stdio.h>');
|
|
20
|
+
this.includes.add('<stdlib.h>');
|
|
21
|
+
|
|
22
|
+
this.visitProgram(ast);
|
|
23
|
+
|
|
24
|
+
const out = [];
|
|
25
|
+
|
|
26
|
+
// Preamble: #includes
|
|
27
|
+
for (const inc of [...this.includes].sort()) {
|
|
28
|
+
out.push(`#include ${inc}`);
|
|
29
|
+
}
|
|
30
|
+
out.push('');
|
|
31
|
+
|
|
32
|
+
// Typedefs / structs
|
|
33
|
+
if (this.typedefs.length > 0) {
|
|
34
|
+
out.push(...this.typedefs);
|
|
35
|
+
out.push('');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Function declarations
|
|
39
|
+
if (this.functions.length > 0) {
|
|
40
|
+
out.push(...this.functions);
|
|
41
|
+
out.push('');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Main function wrapping top-level statements
|
|
45
|
+
if (this.mainBody.length > 0) {
|
|
46
|
+
out.push('int main() {');
|
|
47
|
+
out.push(...this.mainBody);
|
|
48
|
+
out.push(' return 0;');
|
|
49
|
+
out.push('}');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return out.join('\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
emit(line) {
|
|
56
|
+
const indented = ' '.repeat(this.indent) + line;
|
|
57
|
+
if (this.inFunction) {
|
|
58
|
+
this.functions.push(indented);
|
|
59
|
+
} else {
|
|
60
|
+
this.mainBody.push(indented);
|
|
61
|
+
}
|
|
62
|
+
this.sourceMap.push(this.currentSourceLine);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
emitRaw(line) {
|
|
66
|
+
if (this.inFunction) {
|
|
67
|
+
this.functions.push(line);
|
|
68
|
+
} else {
|
|
69
|
+
this.mainBody.push(line);
|
|
70
|
+
}
|
|
71
|
+
this.sourceMap.push(this.currentSourceLine);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
emitTypedef(line) {
|
|
75
|
+
this.typedefs.push(line);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
visitProgram(node) {
|
|
79
|
+
for (const stmt of node.body) {
|
|
80
|
+
this.visitStatement(stmt);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ===== Type mapping =====
|
|
85
|
+
|
|
86
|
+
mapType(naideType) {
|
|
87
|
+
const map = {
|
|
88
|
+
'str': 'const char*',
|
|
89
|
+
'string': 'const char*',
|
|
90
|
+
'int': 'int',
|
|
91
|
+
'integer': 'int',
|
|
92
|
+
'num': 'double',
|
|
93
|
+
'number': 'double',
|
|
94
|
+
'float': 'double',
|
|
95
|
+
'bool': 'int',
|
|
96
|
+
'boolean': 'int',
|
|
97
|
+
'list': 'void**',
|
|
98
|
+
'map': '/* map */ void*',
|
|
99
|
+
'any': 'void*',
|
|
100
|
+
'void': 'void',
|
|
101
|
+
'json': 'const char*',
|
|
102
|
+
'auto': 'int',
|
|
103
|
+
'timestamp': 'long',
|
|
104
|
+
};
|
|
105
|
+
return map[naideType] || 'void*';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ===== Statement dispatcher =====
|
|
109
|
+
|
|
110
|
+
visitStatement(node) {
|
|
111
|
+
if (node._line) this.currentSourceLine = node._line;
|
|
112
|
+
switch (node.type) {
|
|
113
|
+
case 'Use': return this.visitUse(node);
|
|
114
|
+
case 'UseDestructured': return this.visitUseDestructured(node);
|
|
115
|
+
case 'Function': return this.visitFunction(node);
|
|
116
|
+
case 'Return': return this.visitReturn(node);
|
|
117
|
+
case 'ReturnStatus': return this.visitReturnStatus(node);
|
|
118
|
+
case 'ReturnMethod': return this.visitReturnMethod(node);
|
|
119
|
+
case 'TypedVar': return this.visitTypedVar(node);
|
|
120
|
+
case 'If': return this.visitIf(node);
|
|
121
|
+
case 'Each': return this.visitEach(node);
|
|
122
|
+
case 'For': return this.visitFor(node);
|
|
123
|
+
case 'While': return this.visitWhile(node);
|
|
124
|
+
case 'Match': return this.visitMatch(node);
|
|
125
|
+
case 'Try': return this.visitTry(node);
|
|
126
|
+
case 'Server': return this.visitServer(node);
|
|
127
|
+
case 'Bot': return this.visitBot(node);
|
|
128
|
+
case 'Model': return this.visitModel(node);
|
|
129
|
+
case 'On': return this.visitOn(node);
|
|
130
|
+
case 'Log': return this.visitLog(node);
|
|
131
|
+
case 'Throw': return this.visitThrow(node);
|
|
132
|
+
case 'Break': this.emit('break;'); return;
|
|
133
|
+
case 'Continue': this.emit('continue;'); return;
|
|
134
|
+
case 'Assignment': return this.visitAssignment(node);
|
|
135
|
+
case 'CompoundAssign': return this.visitCompoundAssign(node);
|
|
136
|
+
case 'ExprStatement': this.emit(this.expr(node.expression) + ';'); return;
|
|
137
|
+
case 'DbConnect': return this.visitDbConnect(node);
|
|
138
|
+
case 'DbDir': return this.visitDbDir(node);
|
|
139
|
+
case 'DbSql': return this.visitDbSql(node);
|
|
140
|
+
case 'AwaitAll': return this.visitAwaitAll(node);
|
|
141
|
+
case 'SchemaDecl': return this.visitSchema(node);
|
|
142
|
+
case 'CrudDecl': return this.visitCrud(node);
|
|
143
|
+
case 'AuthDecl': return this.visitAuth(node);
|
|
144
|
+
case 'CorsDecl': return this.visitCors(node);
|
|
145
|
+
case 'LimitDecl': return this.visitLimit(node);
|
|
146
|
+
case 'EnvDecl': return this.visitEnv(node);
|
|
147
|
+
case 'EveryDecl': return this.visitEvery(node);
|
|
148
|
+
case 'WatchDecl': return this.visitWatch(node);
|
|
149
|
+
case 'StaticDecl': return this.visitStatic(node);
|
|
150
|
+
case 'WsDecl': return this.visitWs(node);
|
|
151
|
+
case 'GroupDecl': return this.visitGroup(node);
|
|
152
|
+
case 'ErrorHandler': return this.visitErrorHandler(node);
|
|
153
|
+
case 'CookieDecl': return this.visitCookie(node);
|
|
154
|
+
case 'UploadDecl': return this.visitUpload(node);
|
|
155
|
+
case 'SessionDecl': return this.visitSession(node);
|
|
156
|
+
case 'ViewDecl': return this.visitView(node);
|
|
157
|
+
case 'SseDecl': return this.visitSse(node);
|
|
158
|
+
case 'CacheDecl': return this.visitCache(node);
|
|
159
|
+
case 'MiddlewareRef': return this.visitMiddlewareRef(node);
|
|
160
|
+
case 'ReturnRender': return this.visitReturnRender(node);
|
|
161
|
+
case 'ValidateDecl': return this.visitValidate(node);
|
|
162
|
+
case 'TestDecl': return this.visitTest(node);
|
|
163
|
+
case 'AssertStmt': return this.visitAssert(node);
|
|
164
|
+
case 'QueueDecl': return this.visitQueue(node);
|
|
165
|
+
case 'OpenapiDecl': return this.visitOpenapi(node);
|
|
166
|
+
case 'ReturnRedirect': return this.visitReturnRedirect(node);
|
|
167
|
+
case 'ReturnDownload': return this.visitReturnDownload(node);
|
|
168
|
+
case 'PromptDecl': return this.visitPrompt(node);
|
|
169
|
+
case 'Page': return this.visitPage(node);
|
|
170
|
+
case 'CliApp': return this.visitCli(node);
|
|
171
|
+
case 'MailConfig': return this.visitMail(node);
|
|
172
|
+
case 'DesktopApp': return this.visitDesktop(node);
|
|
173
|
+
case 'Screen': return this.visitScreen(node);
|
|
174
|
+
case 'OauthDecl': return this.visitOauth(node);
|
|
175
|
+
case 'PayDecl': return this.visitPay(node);
|
|
176
|
+
case 'StorageDecl': return this.visitStorage(node);
|
|
177
|
+
case 'PdfDecl': return this.visitPdf(node);
|
|
178
|
+
case 'I18nDecl': return this.visitI18n(node);
|
|
179
|
+
case 'PushDecl': return this.visitPush(node);
|
|
180
|
+
case 'SearchDecl': return this.visitSearch(node);
|
|
181
|
+
case 'ImageDecl': return this.visitImage(node);
|
|
182
|
+
case 'CsvDecl': return this.visitCsv(node);
|
|
183
|
+
case 'LoggingDecl': return this.visitLogging(node);
|
|
184
|
+
case 'MigrateDecl': return this.visitMigrate(node);
|
|
185
|
+
case 'GrpcDecl': return this.visitGrpc(node);
|
|
186
|
+
case 'WebrtcDecl': return this.visitWebrtc(node);
|
|
187
|
+
case 'BlockchainDecl': return this.visitBlockchain(node);
|
|
188
|
+
default:
|
|
189
|
+
this.emit(`/* unknown: ${node.type} */`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ===== Imports / Use =====
|
|
194
|
+
|
|
195
|
+
visitUse(node) {
|
|
196
|
+
const raw = node.source ? this.rawString(node.source) : node.name;
|
|
197
|
+
this.emit(`/* use ${raw} */`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
visitUseDestructured(node) {
|
|
201
|
+
const raw = this.rawString(node.source);
|
|
202
|
+
const names = node.names.map(n => n.name).join(', ');
|
|
203
|
+
this.emit(`/* use { ${names} } from ${raw} */`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ===== Functions =====
|
|
207
|
+
|
|
208
|
+
visitFunction(node) {
|
|
209
|
+
const retType = node.returnType ? this.mapType(node.returnType) : 'void';
|
|
210
|
+
const params = node.params.map(p => {
|
|
211
|
+
const type = p.type ? this.mapType(p.type) : 'void*';
|
|
212
|
+
return `${type} ${p.name}`;
|
|
213
|
+
}).join(', ');
|
|
214
|
+
|
|
215
|
+
const savedInFunction = this.inFunction;
|
|
216
|
+
this.inFunction = true;
|
|
217
|
+
|
|
218
|
+
this.emit(`${retType} ${node.name}(${params || 'void'}) {`);
|
|
219
|
+
this.indent++;
|
|
220
|
+
for (const stmt of node.body) {
|
|
221
|
+
this.visitStatement(stmt);
|
|
222
|
+
}
|
|
223
|
+
this.indent--;
|
|
224
|
+
this.emit('}');
|
|
225
|
+
this.emitRaw('');
|
|
226
|
+
|
|
227
|
+
this.inFunction = savedInFunction;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
visitReturn(node) {
|
|
231
|
+
if (node.value === null) {
|
|
232
|
+
this.emit('return;');
|
|
233
|
+
} else {
|
|
234
|
+
this.emit(`return ${this.expr(node.value)};`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
visitReturnStatus(node) {
|
|
239
|
+
this.emit(`/* return status ${this.expr(node.statusCode)} with body */`);
|
|
240
|
+
this.emit(`printf("Status: %s\\n", ${this.expr(node.body)});`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
visitReturnMethod(node) {
|
|
244
|
+
this.emit(`/* return ${node.method}: ${this.expr(node.value)} */`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ===== Variables =====
|
|
248
|
+
|
|
249
|
+
visitTypedVar(node) {
|
|
250
|
+
const type = node.varType ? this.mapType(node.varType) : this.inferCType(node.value);
|
|
251
|
+
this.emit(`${type} ${node.name} = ${this.expr(node.value)};`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
inferCType(valueNode) {
|
|
255
|
+
if (!valueNode) return 'void*';
|
|
256
|
+
switch (valueNode.type) {
|
|
257
|
+
case 'Number':
|
|
258
|
+
return valueNode.value.includes('.') ? 'double' : 'int';
|
|
259
|
+
case 'String': return 'const char*';
|
|
260
|
+
case 'Bool': return 'int';
|
|
261
|
+
case 'Null': return 'void*';
|
|
262
|
+
case 'Array': return 'void**';
|
|
263
|
+
default: return 'void*';
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
visitAssignment(node) {
|
|
268
|
+
const value = this.expr(node.value);
|
|
269
|
+
if (node.target.type === 'Array') {
|
|
270
|
+
this.emit(`/* destructuring not supported in C */`);
|
|
271
|
+
this.emit(`/* ${this.expr(node.target)} = ${value} */`);
|
|
272
|
+
} else if (node.target.type === 'Object') {
|
|
273
|
+
this.emit(`/* object destructuring not supported in C */`);
|
|
274
|
+
} else {
|
|
275
|
+
this.emit(`${this.expr(node.target)} = ${value};`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
visitCompoundAssign(node) {
|
|
280
|
+
this.emit(`${this.expr(node.target)} ${node.op} ${this.expr(node.value)};`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ===== Control flow =====
|
|
284
|
+
|
|
285
|
+
visitIf(node) {
|
|
286
|
+
this.emit(`if (${this.expr(node.condition)}) {`);
|
|
287
|
+
this.indent++;
|
|
288
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
289
|
+
this.indent--;
|
|
290
|
+
|
|
291
|
+
for (const elif of node.elifs) {
|
|
292
|
+
this.emit(`} else if (${this.expr(elif.condition)}) {`);
|
|
293
|
+
this.indent++;
|
|
294
|
+
for (const stmt of elif.body) this.visitStatement(stmt);
|
|
295
|
+
this.indent--;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (node.elseBody) {
|
|
299
|
+
this.emit('} else {');
|
|
300
|
+
this.indent++;
|
|
301
|
+
for (const stmt of node.elseBody) this.visitStatement(stmt);
|
|
302
|
+
this.indent--;
|
|
303
|
+
}
|
|
304
|
+
this.emit('}');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
visitEach(node) {
|
|
308
|
+
const collection = this.expr(node.collection);
|
|
309
|
+
this.emit(`/* each: iterate over ${collection} */`);
|
|
310
|
+
this.emit(`/* C requires manual iteration with known size */`);
|
|
311
|
+
this.emit(`for (int __i = 0; /* __i < length */; __i++) {`);
|
|
312
|
+
this.indent++;
|
|
313
|
+
if (node.key) {
|
|
314
|
+
this.emit(`int ${node.key} = __i;`);
|
|
315
|
+
}
|
|
316
|
+
this.emit(`void* ${node.value} = ${collection}[__i];`);
|
|
317
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
318
|
+
this.indent--;
|
|
319
|
+
this.emit('}');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
visitFor(node) {
|
|
323
|
+
const varName = node.varName;
|
|
324
|
+
const start = this.expr(node.start);
|
|
325
|
+
const end = this.expr(node.end);
|
|
326
|
+
this.emit(`for (int ${varName} = ${start}; ${varName} < ${end}; ${varName}++) {`);
|
|
327
|
+
this.indent++;
|
|
328
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
329
|
+
this.indent--;
|
|
330
|
+
this.emit('}');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
visitWhile(node) {
|
|
334
|
+
this.emit(`while (${this.expr(node.condition)}) {`);
|
|
335
|
+
this.indent++;
|
|
336
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
337
|
+
this.indent--;
|
|
338
|
+
this.emit('}');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
visitMatch(node) {
|
|
342
|
+
this.emit(`switch (${this.expr(node.value)}) {`);
|
|
343
|
+
this.indent++;
|
|
344
|
+
for (const c of node.cases) {
|
|
345
|
+
if (c.pattern.type === 'DefaultPattern') {
|
|
346
|
+
this.emit('default: {');
|
|
347
|
+
} else {
|
|
348
|
+
this.emit(`case ${this.expr(c.pattern)}: {`);
|
|
349
|
+
}
|
|
350
|
+
this.indent++;
|
|
351
|
+
for (const stmt of c.body) this.visitStatement(stmt);
|
|
352
|
+
this.emit('break;');
|
|
353
|
+
this.indent--;
|
|
354
|
+
this.emit('}');
|
|
355
|
+
}
|
|
356
|
+
this.indent--;
|
|
357
|
+
this.emit('}');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
visitTry(node) {
|
|
361
|
+
this.emit('/* C has no try/catch - use error codes or setjmp/longjmp */');
|
|
362
|
+
this.emit('/* try { */');
|
|
363
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
364
|
+
if (node.catchBody) {
|
|
365
|
+
const catchParam = node.catchVar || 'err';
|
|
366
|
+
this.emit(`/* } catch (${catchParam}) { */`);
|
|
367
|
+
for (const stmt of node.catchBody) this.visitStatement(stmt);
|
|
368
|
+
}
|
|
369
|
+
if (node.ensureBody) {
|
|
370
|
+
this.emit('/* } finally { */');
|
|
371
|
+
for (const stmt of node.ensureBody) this.visitStatement(stmt);
|
|
372
|
+
}
|
|
373
|
+
this.emit('/* } */');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ===== Model (struct) =====
|
|
377
|
+
|
|
378
|
+
visitModel(node) {
|
|
379
|
+
this.models.set(node.name, node);
|
|
380
|
+
|
|
381
|
+
let structDef = `typedef struct {\n`;
|
|
382
|
+
for (const f of node.fields) {
|
|
383
|
+
const type = f.type ? this.mapType(f.type) : 'void*';
|
|
384
|
+
structDef += ` ${type} ${f.name};\n`;
|
|
385
|
+
}
|
|
386
|
+
structDef += `} ${node.name};`;
|
|
387
|
+
this.emitTypedef(structDef);
|
|
388
|
+
this.emitTypedef('');
|
|
389
|
+
|
|
390
|
+
// Generate method stubs as standalone functions
|
|
391
|
+
for (const method of node.methods) {
|
|
392
|
+
const retType = method.returnType ? this.mapType(method.returnType) : 'void';
|
|
393
|
+
const params = method.params.map(p => {
|
|
394
|
+
const type = p.type ? this.mapType(p.type) : 'void*';
|
|
395
|
+
return `${type} ${p.name}`;
|
|
396
|
+
});
|
|
397
|
+
params.unshift(`${node.name}* self`);
|
|
398
|
+
|
|
399
|
+
const savedInFunction = this.inFunction;
|
|
400
|
+
this.inFunction = true;
|
|
401
|
+
|
|
402
|
+
this.emit(`${retType} ${node.name}_${method.name}(${params.join(', ')}) {`);
|
|
403
|
+
this.indent++;
|
|
404
|
+
for (const stmt of method.body) {
|
|
405
|
+
this.visitStatement(stmt);
|
|
406
|
+
}
|
|
407
|
+
this.indent--;
|
|
408
|
+
this.emit('}');
|
|
409
|
+
this.emitRaw('');
|
|
410
|
+
|
|
411
|
+
this.inFunction = savedInFunction;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ===== Log =====
|
|
416
|
+
|
|
417
|
+
visitLog(node) {
|
|
418
|
+
this.includes.add('<stdio.h>');
|
|
419
|
+
const args = node.args.map(a => this.expr(a));
|
|
420
|
+
if (args.length === 1) {
|
|
421
|
+
const arg = args[0];
|
|
422
|
+
if (node.args[0] && node.args[0].type === 'String') {
|
|
423
|
+
this.emit(`printf(${arg});`);
|
|
424
|
+
this.emit(`printf("\\n");`);
|
|
425
|
+
} else {
|
|
426
|
+
this.emit(`printf("%s\\n", ${arg});`);
|
|
427
|
+
}
|
|
428
|
+
} else {
|
|
429
|
+
// Multiple args: print each separated by space
|
|
430
|
+
const fmtParts = args.map(() => '%s').join(' ');
|
|
431
|
+
this.emit(`printf("${fmtParts}\\n", ${args.join(', ')});`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
visitThrow(node) {
|
|
436
|
+
this.includes.add('<stdio.h>');
|
|
437
|
+
this.includes.add('<stdlib.h>');
|
|
438
|
+
this.emit(`fprintf(stderr, "Error: %s\\n", ${this.expr(node.value)});`);
|
|
439
|
+
this.emit('exit(1);');
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// ===== Events =====
|
|
443
|
+
|
|
444
|
+
visitOn(node) {
|
|
445
|
+
this.emit(`/* on event: ${this.expr(node.event)} */`);
|
|
446
|
+
this.emit(`/* C has no built-in event system - use callbacks or signal handlers */`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// ===== Server =====
|
|
450
|
+
|
|
451
|
+
visitServer(node) {
|
|
452
|
+
this.emit('/* HTTP server: use libmicrohttpd or libevent */');
|
|
453
|
+
this.emit(`/* server "${node.name}" */`);
|
|
454
|
+
const port = node.port ? this.expr(node.port) : '3000';
|
|
455
|
+
this.emit(`/* port: ${port} */`);
|
|
456
|
+
|
|
457
|
+
for (const child of node.routes) {
|
|
458
|
+
if (child.type === 'Route') {
|
|
459
|
+
const method = child.method.toUpperCase();
|
|
460
|
+
const path = this.rawString(child.path);
|
|
461
|
+
this.emit(`/* ${method} ${path} */`);
|
|
462
|
+
this.emit(`/* { */`);
|
|
463
|
+
this.indent++;
|
|
464
|
+
for (const stmt of child.body) this.visitStatement(stmt);
|
|
465
|
+
this.indent--;
|
|
466
|
+
this.emit(`/* } */`);
|
|
467
|
+
this.emitRaw('');
|
|
468
|
+
} else {
|
|
469
|
+
this.visitStatement(child);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
this.emit(`printf("Server ${node.name} would run on port %s\\n", "${port}");`);
|
|
474
|
+
this.emitRaw('');
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// ===== Bot =====
|
|
478
|
+
|
|
479
|
+
visitBot(node) {
|
|
480
|
+
this.emit('/* Bot: C has no built-in bot framework */');
|
|
481
|
+
this.emit(`/* TODO: bot "${node.name}" - implement with libcurl for API calls */`);
|
|
482
|
+
this.emitRaw('');
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// ===== Database =====
|
|
486
|
+
|
|
487
|
+
visitDbConnect(node) {
|
|
488
|
+
this.emit(`/* db connect: ${this.expr(node.connectionString)} */`);
|
|
489
|
+
this.emit('/* TODO: use libpq (PostgreSQL) or sqlite3 C API */');
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
visitDbDir(node) {
|
|
493
|
+
const raw = node.path.raw || node.path.parts?.map(p => p.value).join('') || 'data/';
|
|
494
|
+
this.emit(`/* db dir: ${raw} */`);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
visitDbSql(node) {
|
|
498
|
+
this.emit('/* db sql: use sqlite3 C API */');
|
|
499
|
+
this.emit('/* #include <sqlite3.h> */');
|
|
500
|
+
this.emit('/* sqlite3 *__db; */');
|
|
501
|
+
this.emit('/* sqlite3_open("data.db", &__db); */');
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
visitAwaitAll(node) {
|
|
505
|
+
this.emit('/* await all: C has no async/await - use pthreads */');
|
|
506
|
+
for (const e of node.expressions) {
|
|
507
|
+
this.emit(`${this.expr(e)};`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// ===== Domain features (comment stubs) =====
|
|
512
|
+
|
|
513
|
+
visitSchema(node) {
|
|
514
|
+
this.schemas.set(node.name, node);
|
|
515
|
+
let structDef = `typedef struct {\n`;
|
|
516
|
+
for (const f of node.fields) {
|
|
517
|
+
const type = this.mapType(f.type);
|
|
518
|
+
structDef += ` ${type} ${f.name};\n`;
|
|
519
|
+
}
|
|
520
|
+
structDef += `} ${node.name};`;
|
|
521
|
+
this.emitTypedef(structDef);
|
|
522
|
+
this.emitTypedef('');
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
visitCrud(node) {
|
|
526
|
+
this.emit(`/* TODO: CRUD for "${node.schemaName}" - implement with HTTP library */`);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
visitAuth(node) {
|
|
530
|
+
this.emit('/* TODO: auth - use libcurl + JWT C library (libjwt) */');
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
visitCors(node) {
|
|
534
|
+
this.emit('/* TODO: CORS - set headers in HTTP response */');
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
visitLimit(node) {
|
|
538
|
+
this.emit('/* TODO: rate limiting - implement with token bucket algorithm */');
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
visitEnv(node) {
|
|
542
|
+
this.includes.add('<stdlib.h>');
|
|
543
|
+
for (const v of node.vars) {
|
|
544
|
+
this.emit(`const char* ${v.name} = getenv("${v.name}");`);
|
|
545
|
+
}
|
|
546
|
+
this.emitRaw('');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
visitEvery(node) {
|
|
550
|
+
this.emit('/* TODO: scheduled task - use timer_create or sleep loop */');
|
|
551
|
+
this.includes.add('<unistd.h>');
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
visitWatch(node) {
|
|
555
|
+
this.emit(`/* TODO: watch event "${node.eventName}" - use callback pattern */`);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
visitStatic(node) {
|
|
559
|
+
this.emit('/* TODO: static files - use HTTP library to serve files */');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
visitWs(node) {
|
|
563
|
+
this.emit('/* TODO: WebSocket - use libwebsockets */');
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
visitGroup(node) {
|
|
567
|
+
this.emit('/* TODO: route group - implement with HTTP library */');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
visitErrorHandler(node) {
|
|
571
|
+
this.emit('/* TODO: error handler - use errno and custom error codes */');
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
visitCookie(node) {
|
|
575
|
+
this.emit('/* TODO: cookies - set via HTTP headers */');
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
visitUpload(node) {
|
|
579
|
+
this.emit('/* TODO: file upload - use multipart form parser */');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
visitSession(node) {
|
|
583
|
+
this.emit('/* TODO: sessions - implement with in-memory hash map */');
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
visitView(node) {
|
|
587
|
+
this.emit('/* TODO: view engine - use string templates */');
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
visitSse(node) {
|
|
591
|
+
this.emit('/* TODO: Server-Sent Events - use chunked HTTP response */');
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
visitCache(node) {
|
|
595
|
+
this.emit('/* TODO: caching - use in-memory hash map or memcached C client */');
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
visitMiddlewareRef(node) {
|
|
599
|
+
this.emit(`/* TODO: middleware "${node.name}" */`);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
visitReturnRender(node) {
|
|
603
|
+
this.emit(`/* TODO: render template ${this.expr(node.template)} */`);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
visitValidate(node) {
|
|
607
|
+
this.emit('/* TODO: validation - implement manually */');
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
visitTest(node) {
|
|
611
|
+
this.includes.add('<assert.h>');
|
|
612
|
+
const name = this.rawString(node.name);
|
|
613
|
+
const funcName = `test_${name.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
614
|
+
|
|
615
|
+
const savedInFunction = this.inFunction;
|
|
616
|
+
this.inFunction = true;
|
|
617
|
+
|
|
618
|
+
this.emit(`void ${funcName}(void) {`);
|
|
619
|
+
this.indent++;
|
|
620
|
+
for (const stmt of node.body) this.visitStatement(stmt);
|
|
621
|
+
this.indent--;
|
|
622
|
+
this.emit('}');
|
|
623
|
+
this.emitRaw('');
|
|
624
|
+
|
|
625
|
+
this.inFunction = savedInFunction;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
visitAssert(node) {
|
|
629
|
+
this.includes.add('<assert.h>');
|
|
630
|
+
const exprNode = node.expr;
|
|
631
|
+
if (exprNode.type === 'Binary' && (exprNode.op === '===' || exprNode.op === '==')) {
|
|
632
|
+
this.emit(`assert(${this.expr(exprNode.left)} == ${this.expr(exprNode.right)});`);
|
|
633
|
+
} else if (exprNode.type === 'Binary' && (exprNode.op === '!==' || exprNode.op === '!=')) {
|
|
634
|
+
this.emit(`assert(${this.expr(exprNode.left)} != ${this.expr(exprNode.right)});`);
|
|
635
|
+
} else {
|
|
636
|
+
this.emit(`assert(${this.expr(exprNode)});`);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
visitQueue(node) {
|
|
641
|
+
this.emit(`/* TODO: queue "${node.name}" - use POSIX message queues or custom implementation */`);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
visitOpenapi(node) {
|
|
645
|
+
this.emit('/* TODO: OpenAPI spec - generate JSON manually */');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
visitReturnRedirect(node) {
|
|
649
|
+
this.emit(`/* TODO: redirect to ${this.expr(node.url)} */`);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
visitReturnDownload(node) {
|
|
653
|
+
this.emit(`/* TODO: download file ${this.expr(node.filePath)} */`);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
visitPrompt(node) {
|
|
657
|
+
this.emit(`/* TODO: prompt template "${node.name}" - use printf with format strings */`);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
visitPage(node) {
|
|
661
|
+
this.emit('/* TODO: page generation - use fprintf to write HTML file */');
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
visitCli(node) {
|
|
665
|
+
this.includes.add('<string.h>');
|
|
666
|
+
this.emit('/* CLI argument parsing */');
|
|
667
|
+
this.emit('/* argc and argv available in main() */');
|
|
668
|
+
|
|
669
|
+
for (const arg of node.args) {
|
|
670
|
+
const argName = this.rawString(arg.name);
|
|
671
|
+
this.emit(`/* --${argName}: ${arg.type} */`);
|
|
672
|
+
}
|
|
673
|
+
for (const flag of node.flags) {
|
|
674
|
+
const s = this.rawString(flag.short);
|
|
675
|
+
const l = this.rawString(flag.long);
|
|
676
|
+
this.emit(`/* -${s}, --${l} */`);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
visitMail(node) {
|
|
681
|
+
this.emit('/* TODO: mail - use libcurl for SMTP */');
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
visitDesktop(node) {
|
|
685
|
+
this.emit(`/* TODO: desktop app "${node.name}" - use GTK or SDL2 */`);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
visitScreen(node) {
|
|
689
|
+
this.emit(`/* TODO: mobile screen "${node.name}" - not applicable in C */`);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
visitOauth(node) {
|
|
693
|
+
this.emit('/* TODO: OAuth - use libcurl for HTTP requests + libjwt */');
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
visitPay(node) {
|
|
697
|
+
this.emit('/* TODO: payment - use libcurl for Stripe API */');
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
visitStorage(node) {
|
|
701
|
+
this.emit('/* TODO: cloud storage - use AWS SDK for C or libcurl */');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
visitPdf(node) {
|
|
705
|
+
this.emit('/* TODO: PDF generation - use libharu (libHPDF) */');
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
visitI18n(node) {
|
|
709
|
+
this.emit('/* TODO: i18n - use gettext or custom key-value lookup */');
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
visitPush(node) {
|
|
713
|
+
this.emit('/* TODO: push notifications - use libcurl for web push API */');
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
visitSearch(node) {
|
|
717
|
+
this.emit('/* TODO: search - use libcurl for Elasticsearch/Meilisearch API */');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
visitImage(node) {
|
|
721
|
+
this.emit('/* TODO: image processing - use stb_image or ImageMagick C API */');
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
visitCsv(node) {
|
|
725
|
+
this.emit('/* TODO: CSV - use fprintf for writing, custom parser for reading */');
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
visitLogging(node) {
|
|
729
|
+
this.emit('/* TODO: logging - use syslog or custom file logger */');
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
visitMigrate(node) {
|
|
733
|
+
this.emit('/* TODO: DB migration - use sqlite3 C API */');
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
visitGrpc(node) {
|
|
737
|
+
this.emit('/* TODO: gRPC - use grpc-c library */');
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
visitWebrtc(node) {
|
|
741
|
+
this.emit('/* TODO: WebRTC - use libdatachannel */');
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
visitBlockchain(node) {
|
|
745
|
+
this.emit('/* TODO: blockchain - use libcurl for JSON-RPC */');
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// ===== Expression generation =====
|
|
749
|
+
|
|
750
|
+
expr(node) {
|
|
751
|
+
if (!node) return 'NULL';
|
|
752
|
+
|
|
753
|
+
switch (node.type) {
|
|
754
|
+
case 'Number': return node.value;
|
|
755
|
+
|
|
756
|
+
case 'String': return this.generateString(node.value);
|
|
757
|
+
|
|
758
|
+
case 'Bool': return node.value ? '1' : '0';
|
|
759
|
+
|
|
760
|
+
case 'Null': return 'NULL';
|
|
761
|
+
|
|
762
|
+
case 'Self': return 'self';
|
|
763
|
+
|
|
764
|
+
case 'Identifier': return this.mapIdentifier(node.name);
|
|
765
|
+
|
|
766
|
+
case 'Binary': {
|
|
767
|
+
const op = this.mapBinaryOp(node.op);
|
|
768
|
+
const l = this.expr(node.left);
|
|
769
|
+
const r = this.expr(node.right);
|
|
770
|
+
const simple = node.left.type !== 'Binary' && node.right.type !== 'Binary';
|
|
771
|
+
return simple ? `${l} ${op} ${r}` : `(${l} ${op} ${r})`;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
case 'Unary':
|
|
775
|
+
return `${this.mapUnaryOp(node.op)}${this.expr(node.expr)}`;
|
|
776
|
+
|
|
777
|
+
case 'Await':
|
|
778
|
+
return `/* await */ ${this.expr(node.expr)}`;
|
|
779
|
+
|
|
780
|
+
case 'AwaitAllExpr':
|
|
781
|
+
return `/* await all */ ${this.expr(node.expr)}`;
|
|
782
|
+
|
|
783
|
+
case 'Spread':
|
|
784
|
+
return `/* spread */ ${this.expr(node.expr)}`;
|
|
785
|
+
|
|
786
|
+
case 'New': {
|
|
787
|
+
// In C, allocate with malloc
|
|
788
|
+
this.includes.add('<stdlib.h>');
|
|
789
|
+
return `/* new */ malloc(sizeof(${this.expr(node.expr)}))`;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
case 'TypeOf':
|
|
793
|
+
return `/* typeof */ "unknown"`;
|
|
794
|
+
|
|
795
|
+
case 'MemberAccess':
|
|
796
|
+
return this.generateMemberAccess(node);
|
|
797
|
+
|
|
798
|
+
case 'OptionalAccess':
|
|
799
|
+
return `(${this.expr(node.object)} ? ${this.expr(node.object)}->${node.property} : NULL)`;
|
|
800
|
+
|
|
801
|
+
case 'Call':
|
|
802
|
+
return this.generateCall(node);
|
|
803
|
+
|
|
804
|
+
case 'IndexAccess':
|
|
805
|
+
return `${this.expr(node.object)}[${this.expr(node.index)}]`;
|
|
806
|
+
|
|
807
|
+
case 'Array':
|
|
808
|
+
// C doesn't have array literals in expressions easily
|
|
809
|
+
return `/* array */ NULL`;
|
|
810
|
+
|
|
811
|
+
case 'Object':
|
|
812
|
+
return `/* object literal */ NULL`;
|
|
813
|
+
|
|
814
|
+
case 'ArrowFn':
|
|
815
|
+
return `/* function pointer */ NULL`;
|
|
816
|
+
|
|
817
|
+
case 'Lambda':
|
|
818
|
+
return `/* lambda */ NULL`;
|
|
819
|
+
|
|
820
|
+
case 'Ternary':
|
|
821
|
+
return `(${this.expr(node.condition)} ? ${this.expr(node.consequent)} : ${this.expr(node.alternate)})`;
|
|
822
|
+
|
|
823
|
+
case 'Pipe':
|
|
824
|
+
return this.generatePipe(node);
|
|
825
|
+
|
|
826
|
+
default:
|
|
827
|
+
return `/* expr:${node.type} */ 0`;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
mapIdentifier(name) {
|
|
832
|
+
const map = {
|
|
833
|
+
'null': 'NULL',
|
|
834
|
+
'undefined': 'NULL',
|
|
835
|
+
'true': '1',
|
|
836
|
+
'false': '0',
|
|
837
|
+
'this': 'self',
|
|
838
|
+
};
|
|
839
|
+
return map[name] || name;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
mapBinaryOp(op) {
|
|
843
|
+
const map = {
|
|
844
|
+
'===': '==',
|
|
845
|
+
'!==': '!=',
|
|
846
|
+
'&&': '&&',
|
|
847
|
+
'||': '||',
|
|
848
|
+
'and': '&&',
|
|
849
|
+
'or': '||',
|
|
850
|
+
};
|
|
851
|
+
return map[op] || op;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
mapUnaryOp(op) {
|
|
855
|
+
if (op === 'not' || op === '!') return '!';
|
|
856
|
+
return op;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
generateMemberAccess(node) {
|
|
860
|
+
const obj = this.expr(node.object);
|
|
861
|
+
const prop = node.property;
|
|
862
|
+
|
|
863
|
+
// Map common patterns
|
|
864
|
+
if (prop === 'length') {
|
|
865
|
+
this.includes.add('<string.h>');
|
|
866
|
+
return `strlen(${obj})`;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// Struct member access: use -> for pointers, . for values
|
|
870
|
+
return `${obj}.${prop}`;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
generateCall(node) {
|
|
874
|
+
const args = node.args.map(a => this.expr(a)).join(', ');
|
|
875
|
+
|
|
876
|
+
if (node.callee.type === 'Identifier') {
|
|
877
|
+
const name = node.callee.name;
|
|
878
|
+
if (name === 'parseInt') return `atoi(${args})`;
|
|
879
|
+
if (name === 'parseFloat') return `atof(${args})`;
|
|
880
|
+
if (name === 'toString') { this.includes.add('<stdio.h>'); return `/* toString */ ${args}`; }
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (node.callee.type === 'MemberAccess') {
|
|
884
|
+
const obj = this.expr(node.callee.object);
|
|
885
|
+
const prop = node.callee.property;
|
|
886
|
+
|
|
887
|
+
// String methods
|
|
888
|
+
if (prop === 'split') { this.includes.add('<string.h>'); return `strtok(${obj}, ${args})`; }
|
|
889
|
+
if (prop === 'indexOf') { this.includes.add('<string.h>'); return `strstr(${obj}, ${args})`; }
|
|
890
|
+
if (prop === 'includes') { this.includes.add('<string.h>'); return `(strstr(${obj}, ${args}) != NULL)`; }
|
|
891
|
+
if (prop === 'toUpperCase') { return `/* toUpperCase: iterate and toupper */ ${obj}`; }
|
|
892
|
+
if (prop === 'toLowerCase') { return `/* toLowerCase: iterate and tolower */ ${obj}`; }
|
|
893
|
+
if (prop === 'trim') { return `/* trim: custom implementation */ ${obj}`; }
|
|
894
|
+
if (prop === 'replace') { return `/* replace: custom implementation */ ${obj}`; }
|
|
895
|
+
if (prop === 'substring') { return `/* substring: pointer arithmetic */ ${obj}`; }
|
|
896
|
+
|
|
897
|
+
// Console methods
|
|
898
|
+
if (obj === 'console' && prop === 'log') {
|
|
899
|
+
this.includes.add('<stdio.h>');
|
|
900
|
+
return `printf("%s\\n", ${args})`;
|
|
901
|
+
}
|
|
902
|
+
if (obj === 'console' && prop === 'error') {
|
|
903
|
+
this.includes.add('<stdio.h>');
|
|
904
|
+
return `fprintf(stderr, "%s\\n", ${args})`;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// Math methods
|
|
908
|
+
if (obj === 'Math' && prop === 'floor') { this.includes.add('<math.h>'); return `floor(${args})`; }
|
|
909
|
+
if (obj === 'Math' && prop === 'ceil') { this.includes.add('<math.h>'); return `ceil(${args})`; }
|
|
910
|
+
if (obj === 'Math' && prop === 'round') { this.includes.add('<math.h>'); return `round(${args})`; }
|
|
911
|
+
if (obj === 'Math' && prop === 'abs') { this.includes.add('<stdlib.h>'); return `abs(${args})`; }
|
|
912
|
+
if (obj === 'Math' && prop === 'sqrt') { this.includes.add('<math.h>'); return `sqrt(${args})`; }
|
|
913
|
+
if (obj === 'Math' && prop === 'pow') { this.includes.add('<math.h>'); return `pow(${args})`; }
|
|
914
|
+
if (obj === 'Math' && prop === 'random') { this.includes.add('<stdlib.h>'); return `((double)rand() / RAND_MAX)`; }
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const callee = this.expr(node.callee);
|
|
918
|
+
return `${callee}(${args})`;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
generateString(strData) {
|
|
922
|
+
if (!strData || !strData.parts) return '""';
|
|
923
|
+
|
|
924
|
+
const hasInterpolation = strData.parts.some(p => p.type === 'expr');
|
|
925
|
+
|
|
926
|
+
if (!hasInterpolation) {
|
|
927
|
+
const raw = strData.parts.map(p => p.value).join('');
|
|
928
|
+
return JSON.stringify(raw);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// C has no string interpolation; emit printf-style format
|
|
932
|
+
// Return the format string part only; caller must handle arguments
|
|
933
|
+
let fmt = '"';
|
|
934
|
+
const fmtArgs = [];
|
|
935
|
+
for (const part of strData.parts) {
|
|
936
|
+
if (part.type === 'text') {
|
|
937
|
+
fmt += part.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
938
|
+
} else {
|
|
939
|
+
fmt += '%s';
|
|
940
|
+
fmtArgs.push(part.value);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
fmt += '"';
|
|
944
|
+
|
|
945
|
+
if (fmtArgs.length > 0) {
|
|
946
|
+
// Return as a comment-annotated format; for printf usage
|
|
947
|
+
return `${fmt} /* args: ${fmtArgs.join(', ')} */`;
|
|
948
|
+
}
|
|
949
|
+
return fmt;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
generatePipe(node) {
|
|
953
|
+
const steps = [];
|
|
954
|
+
let current = node;
|
|
955
|
+
while (current.type === 'Pipe') {
|
|
956
|
+
steps.unshift(current.right);
|
|
957
|
+
current = current.left;
|
|
958
|
+
}
|
|
959
|
+
steps.unshift(current);
|
|
960
|
+
|
|
961
|
+
let result = this.expr(steps[0]);
|
|
962
|
+
for (let i = 1; i < steps.length; i++) {
|
|
963
|
+
const step = steps[i];
|
|
964
|
+
if (step.type === 'Call') {
|
|
965
|
+
const callee = this.expr(step.callee);
|
|
966
|
+
const args = step.args.map(a => this.expr(a)).join(', ');
|
|
967
|
+
result = `${callee}(${result}${args ? ', ' + args : ''})`;
|
|
968
|
+
} else if (step.type === 'Identifier') {
|
|
969
|
+
result = `${step.name}(${result})`;
|
|
970
|
+
} else {
|
|
971
|
+
result = `/* pipe */ ${this.expr(step)}`;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return result;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
rawString(strData) {
|
|
978
|
+
if (!strData) return '';
|
|
979
|
+
if (strData.raw !== null && strData.raw !== undefined) return strData.raw;
|
|
980
|
+
if (strData.parts) return strData.parts.map(p => p.value).join('');
|
|
981
|
+
return '';
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
bodyUsesAwait(body) {
|
|
985
|
+
for (const stmt of body) {
|
|
986
|
+
if (this.stmtUsesAwait(stmt)) return true;
|
|
987
|
+
}
|
|
988
|
+
return false;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
stmtUsesAwait(node) {
|
|
992
|
+
if (!node) return false;
|
|
993
|
+
const json = JSON.stringify(node);
|
|
994
|
+
return json.includes('"Await"') || json.includes('"AwaitAll"');
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
statementToString(stmt) {
|
|
998
|
+
const saved = this.inFunction;
|
|
999
|
+
const savedFunctions = this.functions;
|
|
1000
|
+
const savedMain = this.mainBody;
|
|
1001
|
+
const savedIndent = this.indent;
|
|
1002
|
+
this.functions = [];
|
|
1003
|
+
this.mainBody = [];
|
|
1004
|
+
this.indent = 0;
|
|
1005
|
+
this.inFunction = false;
|
|
1006
|
+
this.visitStatement(stmt);
|
|
1007
|
+
const result = this.mainBody.join('\n');
|
|
1008
|
+
this.functions = savedFunctions;
|
|
1009
|
+
this.mainBody = savedMain;
|
|
1010
|
+
this.indent = savedIndent;
|
|
1011
|
+
this.inFunction = saved;
|
|
1012
|
+
return result;
|
|
1013
|
+
}
|
|
1014
|
+
}
|