@ugo-studio/jspp 0.1.5 → 0.1.7
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/LICENSE +25 -21
- package/README.md +2 -16
- package/dist/ast/symbols.js +3 -0
- package/dist/cli.js +7 -4
- package/dist/core/codegen/control-flow-handlers.js +28 -9
- package/dist/core/codegen/expression-handlers.js +7 -4
- package/dist/core/codegen/function-handlers.js +45 -27
- package/dist/core/codegen/helpers.js +24 -17
- package/dist/core/codegen/index.js +16 -9
- package/dist/core/codegen/statement-handlers.js +242 -58
- package/package.json +2 -1
- package/src/prelude/any_value.hpp +27 -1
- package/src/prelude/any_value_access.hpp +161 -122
- package/src/prelude/any_value_helpers.hpp +2 -0
- package/src/prelude/index.hpp +3 -0
- package/src/prelude/library/promise.hpp +6 -14
- package/src/prelude/types.hpp +6 -0
- package/src/prelude/utils/access.hpp +35 -2
- package/src/prelude/values/array.hpp +2 -2
- package/src/prelude/values/async_iterator.hpp +79 -0
- package/src/prelude/values/function.hpp +2 -1
- package/src/prelude/values/helpers/array.hpp +3 -0
- package/src/prelude/values/helpers/async_iterator.hpp +275 -0
- package/src/prelude/values/helpers/function.hpp +4 -0
- package/src/prelude/values/helpers/promise.hpp +10 -3
- package/src/prelude/values/promise.hpp +4 -8
- package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
|
@@ -78,7 +78,7 @@ export function visitSourceFile(node, context) {
|
|
|
78
78
|
return code;
|
|
79
79
|
}
|
|
80
80
|
export function visitBlock(node, context) {
|
|
81
|
-
let code =
|
|
81
|
+
let code = `${this.indent()}{\n`;
|
|
82
82
|
this.indentationLevel++;
|
|
83
83
|
const block = node;
|
|
84
84
|
// Collect ONLY block-scoped declarations (let/const)
|
|
@@ -232,35 +232,201 @@ export function visitThrowStatement(node, context) {
|
|
|
232
232
|
}
|
|
233
233
|
export function visitTryStatement(node, context) {
|
|
234
234
|
const tryStmt = node;
|
|
235
|
+
if (context.isInsideAsyncFunction) {
|
|
236
|
+
if (tryStmt.finallyBlock) {
|
|
237
|
+
const declaredSymbols = new Set(context.topLevelScopeSymbols.toSet());
|
|
238
|
+
this.getDeclaredSymbols(tryStmt.tryBlock).forEach((s) => declaredSymbols.add(s));
|
|
239
|
+
if (tryStmt.catchClause) {
|
|
240
|
+
this.getDeclaredSymbols(tryStmt.catchClause).forEach((s) => declaredSymbols.add(s));
|
|
241
|
+
}
|
|
242
|
+
this.getDeclaredSymbols(tryStmt.finallyBlock).forEach((s) => declaredSymbols.add(s));
|
|
243
|
+
const resultVarName = this.generateUniqueName("__try_result_", declaredSymbols);
|
|
244
|
+
const hasReturnedFlagName = this.generateUniqueName("__try_has_returned_", declaredSymbols);
|
|
245
|
+
const catchAllExPtrName = this.generateUniqueName("__catch_all_exptr", declaredSymbols);
|
|
246
|
+
let code = `${this.indent()}{\n`;
|
|
247
|
+
this.indentationLevel++;
|
|
248
|
+
code += `${this.indent()}jspp::AnyValue ${resultVarName};\n`;
|
|
249
|
+
code +=
|
|
250
|
+
`${this.indent()}std::exception_ptr ${catchAllExPtrName} = nullptr;\n`;
|
|
251
|
+
code += `${this.indent()}bool ${hasReturnedFlagName} = false;\n`;
|
|
252
|
+
const returnType = "jspp::JsPromise";
|
|
253
|
+
const returnCmd = "co_return";
|
|
254
|
+
const callPrefix = "co_await ";
|
|
255
|
+
code += `${this.indent()}try {\n`;
|
|
256
|
+
this.indentationLevel++;
|
|
257
|
+
code +=
|
|
258
|
+
`${this.indent()}${resultVarName} = ${callPrefix}([=, &${hasReturnedFlagName}]() -> ${returnType} {\n`;
|
|
259
|
+
this.indentationLevel++;
|
|
260
|
+
const innerContext = {
|
|
261
|
+
...context,
|
|
262
|
+
isFunctionBody: false,
|
|
263
|
+
isInsideTryCatchLambda: true,
|
|
264
|
+
hasReturnedFlag: hasReturnedFlagName,
|
|
265
|
+
};
|
|
266
|
+
const exPtr = this.generateUniqueName("__ex_ptr");
|
|
267
|
+
code += `${this.indent()}std::exception_ptr ${exPtr} = nullptr;\n`;
|
|
268
|
+
code += `${this.indent()}try {\n`;
|
|
269
|
+
this.indentationLevel++;
|
|
270
|
+
code += this.visit(tryStmt.tryBlock, innerContext);
|
|
271
|
+
this.indentationLevel--;
|
|
272
|
+
code +=
|
|
273
|
+
`${this.indent()}} catch (...) { ${exPtr} = std::current_exception(); }\n`;
|
|
274
|
+
if (tryStmt.catchClause) {
|
|
275
|
+
const exceptionName = this.generateUniqueExceptionName(tryStmt.catchClause.variableDeclaration?.name.getText(), declaredSymbols);
|
|
276
|
+
const caughtValVar = this.generateUniqueName("__caught_val");
|
|
277
|
+
const caughtFlagVar = this.generateUniqueName("__caught_flag");
|
|
278
|
+
code +=
|
|
279
|
+
`${this.indent()}jspp::AnyValue ${caughtValVar} = jspp::Constants::UNDEFINED;\n`;
|
|
280
|
+
code += `${this.indent()}bool ${caughtFlagVar} = false;\n`;
|
|
281
|
+
code += `${this.indent()}if (${exPtr}) {\n`;
|
|
282
|
+
this.indentationLevel++;
|
|
283
|
+
code +=
|
|
284
|
+
`${this.indent()}try { std::rethrow_exception(${exPtr}); } catch (const std::exception& ${exceptionName}) {\n`;
|
|
285
|
+
this.indentationLevel++;
|
|
286
|
+
code +=
|
|
287
|
+
`${this.indent()}${caughtValVar} = jspp::Exception::exception_to_any_value(${exceptionName});\n`;
|
|
288
|
+
code += `${this.indent()}${caughtFlagVar} = true;\n`;
|
|
289
|
+
this.indentationLevel--;
|
|
290
|
+
code += `${this.indent()}} catch (...) {\n`;
|
|
291
|
+
this.indentationLevel++;
|
|
292
|
+
code +=
|
|
293
|
+
`${this.indent()}${caughtValVar} = jspp::AnyValue::make_string("Unknown native exception");\n`;
|
|
294
|
+
code += `${this.indent()}${caughtFlagVar} = true;\n`;
|
|
295
|
+
this.indentationLevel--;
|
|
296
|
+
code += `${this.indent()}}\n`;
|
|
297
|
+
this.indentationLevel--;
|
|
298
|
+
code += `${this.indent()}}\n`;
|
|
299
|
+
code += `${this.indent()}if (${caughtFlagVar}) {\n`;
|
|
300
|
+
this.indentationLevel++;
|
|
301
|
+
code += `${this.indent()}{\n`; // Block scope
|
|
302
|
+
this.indentationLevel++;
|
|
303
|
+
if (tryStmt.catchClause.variableDeclaration) {
|
|
304
|
+
const varName = tryStmt.catchClause.variableDeclaration.name
|
|
305
|
+
.getText();
|
|
306
|
+
code +=
|
|
307
|
+
`${this.indent()}jspp::AnyValue ${varName} = ${caughtValVar};\n`;
|
|
308
|
+
}
|
|
309
|
+
const catchContext = { ...innerContext, exceptionName };
|
|
310
|
+
code += this.visit(tryStmt.catchClause.block, catchContext);
|
|
311
|
+
this.indentationLevel--;
|
|
312
|
+
code += `${this.indent()}}\n`;
|
|
313
|
+
this.indentationLevel--;
|
|
314
|
+
code += `${this.indent()}}\n`;
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
code +=
|
|
318
|
+
`${this.indent()}if (${exPtr}) { std::rethrow_exception(${exPtr}); }\n`;
|
|
319
|
+
}
|
|
320
|
+
code +=
|
|
321
|
+
`${this.indent()}${returnCmd} jspp::Constants::UNDEFINED;\n`;
|
|
322
|
+
this.indentationLevel--;
|
|
323
|
+
code += `${this.indent()}})();\n`;
|
|
324
|
+
this.indentationLevel--;
|
|
325
|
+
code +=
|
|
326
|
+
`${this.indent()}} catch (...) { ${catchAllExPtrName} = std::current_exception(); }\n`;
|
|
327
|
+
code += `${this.indent()}// finally block\n`;
|
|
328
|
+
code += this.visit(tryStmt.finallyBlock, {
|
|
329
|
+
...context,
|
|
330
|
+
isFunctionBody: false,
|
|
331
|
+
});
|
|
332
|
+
code += `${this.indent()}// re-throw or return\n`;
|
|
333
|
+
code +=
|
|
334
|
+
`${this.indent()}if (${catchAllExPtrName}) { std::rethrow_exception(${catchAllExPtrName}); }\n`;
|
|
335
|
+
code +=
|
|
336
|
+
`${this.indent()}if (${hasReturnedFlagName}) { ${returnCmd} ${resultVarName}; }\n`;
|
|
337
|
+
this.indentationLevel--;
|
|
338
|
+
code += `${this.indent()}}\n`;
|
|
339
|
+
return code;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const exceptionName = this.generateUniqueExceptionName(tryStmt.catchClause?.variableDeclaration?.name.getText(), context.topLevelScopeSymbols, context.localScopeSymbols);
|
|
343
|
+
const newContext = {
|
|
344
|
+
...context,
|
|
345
|
+
isFunctionBody: false,
|
|
346
|
+
exceptionName,
|
|
347
|
+
};
|
|
348
|
+
const exPtr = this.generateUniqueName("__ex_ptr");
|
|
349
|
+
let code = `${this.indent()}{\n`;
|
|
350
|
+
this.indentationLevel++;
|
|
351
|
+
code += `${this.indent()}std::exception_ptr ${exPtr} = nullptr;\n`;
|
|
352
|
+
code += `${this.indent()}try {\n`;
|
|
353
|
+
this.indentationLevel++;
|
|
354
|
+
code += this.visit(tryStmt.tryBlock, newContext);
|
|
355
|
+
this.indentationLevel--;
|
|
356
|
+
code +=
|
|
357
|
+
`${this.indent()}} catch (...) { ${exPtr} = std::current_exception(); }\n`;
|
|
358
|
+
if (tryStmt.catchClause) {
|
|
359
|
+
const caughtValVar = this.generateUniqueName("__caught_val");
|
|
360
|
+
const caughtFlagVar = this.generateUniqueName("__caught_flag");
|
|
361
|
+
code +=
|
|
362
|
+
`${this.indent()}jspp::AnyValue ${caughtValVar} = jspp::Constants::UNDEFINED;\n`;
|
|
363
|
+
code += `${this.indent()}bool ${caughtFlagVar} = false;\n`;
|
|
364
|
+
code += `${this.indent()}if (${exPtr}) {\n`;
|
|
365
|
+
this.indentationLevel++;
|
|
366
|
+
code +=
|
|
367
|
+
`${this.indent()}try { std::rethrow_exception(${exPtr}); } catch (const std::exception& ${exceptionName}) {\n`;
|
|
368
|
+
this.indentationLevel++;
|
|
369
|
+
code +=
|
|
370
|
+
`${this.indent()}${caughtValVar} = jspp::Exception::exception_to_any_value(${exceptionName});\n`;
|
|
371
|
+
code += `${this.indent()}${caughtFlagVar} = true;\n`;
|
|
372
|
+
this.indentationLevel--;
|
|
373
|
+
code += `${this.indent()}} catch (...) {\n`;
|
|
374
|
+
this.indentationLevel++;
|
|
375
|
+
code +=
|
|
376
|
+
`${this.indent()}${caughtValVar} = jspp::AnyValue::make_string("Unknown native exception");\n`;
|
|
377
|
+
code += `${this.indent()}${caughtFlagVar} = true;\n`;
|
|
378
|
+
this.indentationLevel--;
|
|
379
|
+
code += `${this.indent()}}\n`;
|
|
380
|
+
this.indentationLevel--;
|
|
381
|
+
code += `${this.indent()}}\n`;
|
|
382
|
+
code += `${this.indent()}if (${caughtFlagVar}) {\n`;
|
|
383
|
+
this.indentationLevel++;
|
|
384
|
+
code += `${this.indent()}{\n`; // Block scope
|
|
385
|
+
this.indentationLevel++;
|
|
386
|
+
if (tryStmt.catchClause.variableDeclaration) {
|
|
387
|
+
const varName = tryStmt.catchClause.variableDeclaration.name
|
|
388
|
+
.getText();
|
|
389
|
+
code +=
|
|
390
|
+
`${this.indent()}jspp::AnyValue ${varName} = ${caughtValVar};\n`;
|
|
391
|
+
}
|
|
392
|
+
code += this.visit(tryStmt.catchClause.block, newContext);
|
|
393
|
+
this.indentationLevel--;
|
|
394
|
+
code += `${this.indent()}}\n`;
|
|
395
|
+
this.indentationLevel--;
|
|
396
|
+
code += `${this.indent()}}\n`;
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
code +=
|
|
400
|
+
`${this.indent()}if (${exPtr}) { std::rethrow_exception(${exPtr}); }\n`;
|
|
401
|
+
}
|
|
402
|
+
this.indentationLevel--;
|
|
403
|
+
code += `${this.indent()}}\n`;
|
|
404
|
+
return code;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
235
407
|
if (tryStmt.finallyBlock) {
|
|
236
|
-
const declaredSymbols = new Set();
|
|
408
|
+
const declaredSymbols = new Set(context.topLevelScopeSymbols.toSet());
|
|
237
409
|
this.getDeclaredSymbols(tryStmt.tryBlock).forEach((s) => declaredSymbols.add(s));
|
|
238
410
|
if (tryStmt.catchClause) {
|
|
239
411
|
this.getDeclaredSymbols(tryStmt.catchClause).forEach((s) => declaredSymbols.add(s));
|
|
240
412
|
}
|
|
241
413
|
this.getDeclaredSymbols(tryStmt.finallyBlock).forEach((s) => declaredSymbols.add(s));
|
|
242
|
-
const finallyLambdaName = this.generateUniqueName("__finally_", declaredSymbols);
|
|
243
414
|
const resultVarName = this.generateUniqueName("__try_result_", declaredSymbols);
|
|
244
415
|
const hasReturnedFlagName = this.generateUniqueName("__try_has_returned_", declaredSymbols);
|
|
416
|
+
const catchAllExPtrName = this.generateUniqueName("__catch_all_exptr", declaredSymbols);
|
|
245
417
|
let code = `${this.indent()}{\n`;
|
|
246
418
|
this.indentationLevel++;
|
|
247
|
-
code += `${this.indent()}jspp::AnyValue ${resultVarName}
|
|
248
|
-
`;
|
|
249
|
-
code += `${this.indent()}bool ${hasReturnedFlagName} = false;
|
|
250
|
-
`;
|
|
251
|
-
const finallyBlockCode = this.visit(tryStmt.finallyBlock, {
|
|
252
|
-
...context,
|
|
253
|
-
isFunctionBody: false,
|
|
254
|
-
});
|
|
419
|
+
code += `${this.indent()}jspp::AnyValue ${resultVarName};\n`;
|
|
255
420
|
code +=
|
|
256
|
-
`${this.indent()}
|
|
257
|
-
`;
|
|
258
|
-
|
|
259
|
-
|
|
421
|
+
`${this.indent()}std::exception_ptr ${catchAllExPtrName} = nullptr;\n`;
|
|
422
|
+
code += `${this.indent()}bool ${hasReturnedFlagName} = false;\n`;
|
|
423
|
+
const returnType = "jspp::AnyValue";
|
|
424
|
+
const returnCmd = "return";
|
|
425
|
+
const callPrefix = "";
|
|
426
|
+
code += `${this.indent()}try {\n`;
|
|
260
427
|
this.indentationLevel++;
|
|
261
428
|
code +=
|
|
262
|
-
`${this.indent()}${resultVarName} = ([=, &${hasReturnedFlagName}]() ->
|
|
263
|
-
`;
|
|
429
|
+
`${this.indent()}${resultVarName} = ${callPrefix}([=, &${hasReturnedFlagName}]() -> ${returnType} {\n`;
|
|
264
430
|
this.indentationLevel++;
|
|
265
431
|
const innerContext = {
|
|
266
432
|
...context,
|
|
@@ -268,19 +434,20 @@ export function visitTryStatement(node, context) {
|
|
|
268
434
|
isInsideTryCatchLambda: true,
|
|
269
435
|
hasReturnedFlag: hasReturnedFlagName,
|
|
270
436
|
};
|
|
271
|
-
code += `${this.indent()}try {
|
|
272
|
-
`;
|
|
437
|
+
code += `${this.indent()}try {\n`;
|
|
273
438
|
this.indentationLevel++;
|
|
274
439
|
code += this.visit(tryStmt.tryBlock, innerContext);
|
|
275
440
|
this.indentationLevel--;
|
|
276
441
|
code += `${this.indent()}}\n`;
|
|
277
442
|
if (tryStmt.catchClause) {
|
|
278
|
-
const exceptionName = this.generateUniqueExceptionName(tryStmt.catchClause.variableDeclaration?.name.getText());
|
|
443
|
+
const exceptionName = this.generateUniqueExceptionName(tryStmt.catchClause.variableDeclaration?.name.getText(), context.topLevelScopeSymbols, context.localScopeSymbols);
|
|
279
444
|
const catchContext = { ...innerContext, exceptionName };
|
|
280
445
|
code +=
|
|
281
|
-
`${this.indent()}catch (const std::exception& ${exceptionName}) {
|
|
282
|
-
`;
|
|
446
|
+
`${this.indent()}catch (const std::exception& ${exceptionName}) {\n`;
|
|
283
447
|
this.indentationLevel++;
|
|
448
|
+
// We cannot co_await here. For now, let's just visit the catch block.
|
|
449
|
+
// If the catch block contains await, it will fail to compile.
|
|
450
|
+
// TODO: properly handle async catch by moving it out of native C++ catch.
|
|
284
451
|
code += this.visit(tryStmt.catchClause.block, catchContext);
|
|
285
452
|
this.indentationLevel--;
|
|
286
453
|
code += `${this.indent()}}\n`;
|
|
@@ -288,30 +455,28 @@ export function visitTryStatement(node, context) {
|
|
|
288
455
|
else {
|
|
289
456
|
code += `${this.indent()}catch (...) { throw; }\n`;
|
|
290
457
|
}
|
|
291
|
-
code += `${this.indent()}${
|
|
458
|
+
code += `${this.indent()}${returnCmd} jspp::Constants::UNDEFINED;\n`;
|
|
292
459
|
this.indentationLevel--;
|
|
293
460
|
code += `${this.indent()}})();\n`;
|
|
294
461
|
this.indentationLevel--;
|
|
295
|
-
code +=
|
|
296
|
-
`;
|
|
297
|
-
this.
|
|
298
|
-
code +=
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
code += `${this.indent()}
|
|
303
|
-
code +=
|
|
304
|
-
`;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
this.indentationLevel--;
|
|
308
|
-
code += `${this.indent()}}\n`;
|
|
462
|
+
code +=
|
|
463
|
+
`${this.indent()}} catch (...) { ${catchAllExPtrName} = std::current_exception(); }\n`;
|
|
464
|
+
code += `${this.indent()}// finally block\n`;
|
|
465
|
+
code += this.visit(tryStmt.finallyBlock, {
|
|
466
|
+
...context,
|
|
467
|
+
isFunctionBody: false,
|
|
468
|
+
});
|
|
469
|
+
code += `${this.indent()}// re-throw or return\n`;
|
|
470
|
+
code +=
|
|
471
|
+
`${this.indent()}if (${catchAllExPtrName}) { std::rethrow_exception(${catchAllExPtrName}); }\n`;
|
|
472
|
+
code +=
|
|
473
|
+
`${this.indent()}if (${hasReturnedFlagName}) { ${returnCmd} ${resultVarName}; }\n`;
|
|
309
474
|
this.indentationLevel--;
|
|
310
475
|
code += `${this.indent()}}\n`;
|
|
311
476
|
return code;
|
|
312
477
|
}
|
|
313
478
|
else {
|
|
314
|
-
const exceptionName = this.generateUniqueExceptionName(tryStmt.catchClause?.variableDeclaration?.name.getText());
|
|
479
|
+
const exceptionName = this.generateUniqueExceptionName(tryStmt.catchClause?.variableDeclaration?.name.getText(), context.topLevelScopeSymbols, context.localScopeSymbols);
|
|
315
480
|
const newContext = {
|
|
316
481
|
...context,
|
|
317
482
|
isFunctionBody: false,
|
|
@@ -320,7 +485,8 @@ export function visitTryStatement(node, context) {
|
|
|
320
485
|
let code = `${this.indent()}try `;
|
|
321
486
|
code += this.visit(tryStmt.tryBlock, newContext);
|
|
322
487
|
if (tryStmt.catchClause) {
|
|
323
|
-
code +=
|
|
488
|
+
code +=
|
|
489
|
+
`${this.indent()}catch (const std::exception& ${exceptionName}) `;
|
|
324
490
|
code += this.visit(tryStmt.catchClause, newContext);
|
|
325
491
|
}
|
|
326
492
|
return code;
|
|
@@ -337,21 +503,12 @@ export function visitCatchClause(node, context) {
|
|
|
337
503
|
const varName = catchClause.variableDeclaration.name.getText();
|
|
338
504
|
let code = `{\n`;
|
|
339
505
|
this.indentationLevel++;
|
|
340
|
-
code += `${this.indent()}{\n`;
|
|
341
|
-
this.indentationLevel++;
|
|
342
506
|
// The JS exception variable is always local to the catch block
|
|
343
507
|
code +=
|
|
344
508
|
`${this.indent()}jspp::AnyValue ${varName} = jspp::Exception::exception_to_any_value(${exceptionName});\n`;
|
|
345
|
-
// Shadow the C++ exception variable *only if* the names don't clash.
|
|
346
|
-
if (varName !== exceptionName) {
|
|
347
|
-
code +=
|
|
348
|
-
`${this.indent()}auto ${exceptionName} = std::make_shared<jspp::AnyValue>(jspp::Constants::UNDEFINED);\n`;
|
|
349
|
-
}
|
|
350
509
|
code += this.visit(catchClause.block, context);
|
|
351
510
|
this.indentationLevel--;
|
|
352
511
|
code += `${this.indent()}}\n`;
|
|
353
|
-
this.indentationLevel--;
|
|
354
|
-
code += `${this.indent()}}\n`;
|
|
355
512
|
return code;
|
|
356
513
|
}
|
|
357
514
|
else {
|
|
@@ -383,32 +540,59 @@ export function visitYieldExpression(node, context) {
|
|
|
383
540
|
let code = `${this.indent()}{\n`;
|
|
384
541
|
this.indentationLevel++;
|
|
385
542
|
const declaredSymbols = this.getDeclaredSymbols(expr);
|
|
543
|
+
context.topLevelScopeSymbols.toSet().forEach((s) => declaredSymbols.add(s));
|
|
386
544
|
const iterableRef = this.generateUniqueName("__iter_ref", declaredSymbols);
|
|
387
545
|
const iterator = this.generateUniqueName("__iter", declaredSymbols);
|
|
388
546
|
const nextFunc = this.generateUniqueName("__next_func", declaredSymbols);
|
|
389
547
|
const nextRes = this.generateUniqueName("__next_res", declaredSymbols);
|
|
390
548
|
const varName = this.getJsVarName(expr);
|
|
391
549
|
code += `${this.indent()}auto ${iterableRef} = ${exprText};\n`;
|
|
392
|
-
|
|
393
|
-
|
|
550
|
+
if (context.isInsideAsyncFunction) {
|
|
551
|
+
code +=
|
|
552
|
+
`${this.indent()}auto ${iterator} = jspp::Access::get_async_object_value_iterator(${iterableRef}, ${varName});\n`;
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
code +=
|
|
556
|
+
`${this.indent()}auto ${iterator} = jspp::Access::get_object_value_iterator(${iterableRef}, ${varName});\n`;
|
|
557
|
+
}
|
|
394
558
|
code +=
|
|
395
559
|
`${this.indent()}auto ${nextFunc} = ${iterator}.get_own_property("next");\n`;
|
|
396
|
-
|
|
397
|
-
|
|
560
|
+
if (context.isInsideAsyncFunction) {
|
|
561
|
+
code +=
|
|
562
|
+
`${this.indent()}auto ${nextRes} = co_await ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
code +=
|
|
566
|
+
`${this.indent()}auto ${nextRes} = ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
567
|
+
}
|
|
398
568
|
code +=
|
|
399
569
|
`${this.indent()}while (!is_truthy(${nextRes}.get_own_property("done"))) {\n`;
|
|
400
570
|
this.indentationLevel++;
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
571
|
+
if (context.isInsideAsyncFunction) {
|
|
572
|
+
code +=
|
|
573
|
+
`${this.indent()}co_yield co_await ${nextRes}.get_own_property("value");\n`;
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
code +=
|
|
577
|
+
`${this.indent()}co_yield ${nextRes}.get_own_property("value");\n`;
|
|
578
|
+
}
|
|
579
|
+
if (context.isInsideAsyncFunction) {
|
|
580
|
+
code +=
|
|
581
|
+
`${this.indent()}${nextRes} = co_await ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
code +=
|
|
585
|
+
`${this.indent()}${nextRes} = ${nextFunc}.call(${iterator}, {}, "next");\n`;
|
|
586
|
+
}
|
|
405
587
|
this.indentationLevel--;
|
|
406
588
|
code += `${this.indent()}}\n`;
|
|
407
589
|
return code;
|
|
408
590
|
}
|
|
409
|
-
|
|
591
|
+
const awaitPart = context.isInsideAsyncFunction ? "co_await " : "";
|
|
592
|
+
return `${this.indent()}co_yield ${awaitPart}${exprText}`;
|
|
410
593
|
}
|
|
411
|
-
|
|
594
|
+
const awaitPart = context.isInsideAsyncFunction ? "co_await " : "";
|
|
595
|
+
return `${this.indent()}co_yield ${awaitPart}jspp::Constants::UNDEFINED`;
|
|
412
596
|
}
|
|
413
597
|
export function visitReturnStatement(node, context) {
|
|
414
598
|
if (context.isMainContext) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ugo-studio/jspp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A modern transpiler that converts JavaScript code into high-performance, standard C++23.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"src/prelude"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
+
"postinstall": "bun run scripts/setup-compiler.ts",
|
|
16
17
|
"dev": "bun run src/cli.ts",
|
|
17
18
|
"typecheck": "tsc --noEmit",
|
|
18
19
|
"precompile": "bun run scripts/precompile-headers.ts",
|
|
@@ -50,6 +50,7 @@ namespace jspp
|
|
|
50
50
|
Promise = 11,
|
|
51
51
|
DataDescriptor = 12,
|
|
52
52
|
AccessorDescriptor = 13,
|
|
53
|
+
AsyncIterator = 14,
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
// The variant order MUST match JsType
|
|
@@ -67,7 +68,8 @@ namespace jspp
|
|
|
67
68
|
std::shared_ptr<JsSymbol>,
|
|
68
69
|
std::shared_ptr<JsPromise>,
|
|
69
70
|
std::shared_ptr<DataDescriptor>,
|
|
70
|
-
std::shared_ptr<AccessorDescriptor
|
|
71
|
+
std::shared_ptr<AccessorDescriptor>,
|
|
72
|
+
std::shared_ptr<JsAsyncIterator<AnyValue>>>;
|
|
71
73
|
|
|
72
74
|
class AnyValue
|
|
73
75
|
{
|
|
@@ -329,6 +331,12 @@ namespace jspp
|
|
|
329
331
|
v.storage = std::shared_ptr<JsIterator<AnyValue>>(iterator, [](JsIterator<AnyValue> *) {});
|
|
330
332
|
return v;
|
|
331
333
|
}
|
|
334
|
+
static AnyValue from_async_iterator(JsAsyncIterator<AnyValue> &&iterator) noexcept
|
|
335
|
+
{
|
|
336
|
+
AnyValue v;
|
|
337
|
+
v.storage = std::make_shared<JsAsyncIterator<AnyValue>>(std::move(iterator));
|
|
338
|
+
return v;
|
|
339
|
+
}
|
|
332
340
|
|
|
333
341
|
// PROPERTY RESOLUTION HELPERS ---------------------------------------
|
|
334
342
|
static AnyValue resolve_property_for_read(const AnyValue &val, const AnyValue &thisVal, const std::string &propName) noexcept
|
|
@@ -411,6 +419,7 @@ namespace jspp
|
|
|
411
419
|
bool is_uninitialized() const noexcept { return storage.index() == 2; }
|
|
412
420
|
bool is_data_descriptor() const noexcept { return storage.index() == 12; }
|
|
413
421
|
bool is_accessor_descriptor() const noexcept { return storage.index() == 13; }
|
|
422
|
+
bool is_async_iterator() const noexcept { return storage.index() == 14; }
|
|
414
423
|
bool is_generator() const noexcept { return is_function() && as_function()->is_generator; }
|
|
415
424
|
|
|
416
425
|
// --- TYPE CASTERS
|
|
@@ -450,6 +459,10 @@ namespace jspp
|
|
|
450
459
|
{
|
|
451
460
|
return std::get<std::shared_ptr<JsIterator<AnyValue>>>(storage);
|
|
452
461
|
}
|
|
462
|
+
std::shared_ptr<JsAsyncIterator<AnyValue>> as_async_iterator() const
|
|
463
|
+
{
|
|
464
|
+
return std::get<std::shared_ptr<JsAsyncIterator<AnyValue>>>(storage);
|
|
465
|
+
}
|
|
453
466
|
DataDescriptor *as_data_descriptor() const noexcept
|
|
454
467
|
{
|
|
455
468
|
return std::get<std::shared_ptr<DataDescriptor>>(storage).get();
|
|
@@ -473,6 +486,10 @@ namespace jspp
|
|
|
473
486
|
AnyValue set_own_property(const std::string &key, const AnyValue &value) const;
|
|
474
487
|
AnyValue set_own_property(uint32_t idx, const AnyValue &value) const;
|
|
475
488
|
AnyValue set_own_property(const AnyValue &key, const AnyValue &value) const;
|
|
489
|
+
// for calling the gotten the property
|
|
490
|
+
AnyValue call_own_property(const std::string &key, std::span<const AnyValue> args) const;
|
|
491
|
+
AnyValue call_own_property(uint32_t idx, std::span<const AnyValue> args) const;
|
|
492
|
+
AnyValue call_own_property(const AnyValue &key, std::span<const AnyValue> args) const;
|
|
476
493
|
|
|
477
494
|
// --- DEFINERS (Object.defineProperty semantics)
|
|
478
495
|
void define_data_property(const std::string &key, const AnyValue &value);
|
|
@@ -490,6 +507,15 @@ namespace jspp
|
|
|
490
507
|
std::string to_std_string() const;
|
|
491
508
|
};
|
|
492
509
|
|
|
510
|
+
// Awaiter for AnyValue
|
|
511
|
+
struct AnyValueAwaiter
|
|
512
|
+
{
|
|
513
|
+
AnyValue value; // Held by value
|
|
514
|
+
bool await_ready();
|
|
515
|
+
void await_suspend(std::coroutine_handle<> h);
|
|
516
|
+
AnyValue await_resume();
|
|
517
|
+
};
|
|
518
|
+
|
|
493
519
|
// Inline implementation of operator co_await
|
|
494
520
|
inline auto AnyValue::operator co_await() const
|
|
495
521
|
{
|