@ugo-studio/jspp 0.1.3 → 0.1.4

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.
Files changed (69) hide show
  1. package/README.md +2 -2
  2. package/dist/analysis/scope.js +16 -4
  3. package/dist/analysis/typeAnalyzer.js +253 -20
  4. package/dist/ast/types.js +6 -0
  5. package/dist/cli.js +1 -2
  6. package/dist/core/codegen/class-handlers.js +127 -0
  7. package/dist/core/codegen/control-flow-handlers.js +464 -0
  8. package/dist/core/codegen/declaration-handlers.js +31 -14
  9. package/dist/core/codegen/expression-handlers.js +429 -117
  10. package/dist/core/codegen/function-handlers.js +91 -15
  11. package/dist/core/codegen/helpers.js +66 -2
  12. package/dist/core/codegen/index.js +17 -6
  13. package/dist/core/codegen/literal-handlers.js +3 -0
  14. package/dist/core/codegen/statement-handlers.js +133 -204
  15. package/dist/core/codegen/visitor.js +29 -3
  16. package/package.json +3 -3
  17. package/src/prelude/any_value.hpp +658 -634
  18. package/src/prelude/any_value_access.hpp +103 -0
  19. package/src/prelude/any_value_defines.hpp +151 -0
  20. package/src/prelude/any_value_helpers.hpp +246 -225
  21. package/src/prelude/exception.hpp +31 -0
  22. package/src/prelude/exception_helpers.hpp +49 -0
  23. package/src/prelude/index.hpp +18 -9
  24. package/src/prelude/library/console.hpp +13 -13
  25. package/src/prelude/library/error.hpp +111 -0
  26. package/src/prelude/library/global.hpp +15 -4
  27. package/src/prelude/library/performance.hpp +2 -2
  28. package/src/prelude/library/promise.hpp +121 -0
  29. package/src/prelude/library/symbol.hpp +3 -4
  30. package/src/prelude/library/timer.hpp +92 -0
  31. package/src/prelude/scheduler.hpp +145 -0
  32. package/src/prelude/types.hpp +10 -1
  33. package/src/prelude/utils/access.hpp +174 -0
  34. package/src/prelude/utils/log_any_value/array.hpp +245 -0
  35. package/src/prelude/utils/log_any_value/config.hpp +32 -0
  36. package/src/prelude/utils/log_any_value/function.hpp +37 -0
  37. package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
  38. package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
  39. package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
  40. package/src/prelude/utils/log_any_value/object.hpp +119 -0
  41. package/src/prelude/utils/log_any_value/primitives.hpp +41 -0
  42. package/src/prelude/{operators.hpp → utils/operators.hpp} +29 -10
  43. package/src/prelude/{well_known_symbols.hpp → utils/well_known_symbols.hpp} +0 -1
  44. package/src/prelude/values/array.hpp +3 -2
  45. package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
  46. package/src/prelude/values/function.hpp +76 -51
  47. package/src/prelude/values/helpers/array.hpp +20 -11
  48. package/src/prelude/values/helpers/function.hpp +125 -77
  49. package/src/prelude/values/helpers/iterator.hpp +13 -7
  50. package/src/prelude/values/helpers/object.hpp +36 -6
  51. package/src/prelude/values/helpers/promise.hpp +181 -0
  52. package/src/prelude/values/helpers/string.hpp +3 -3
  53. package/src/prelude/values/helpers/symbol.hpp +2 -2
  54. package/src/prelude/values/iterator.hpp +13 -5
  55. package/src/prelude/values/object.hpp +6 -2
  56. package/src/prelude/values/promise.hpp +73 -0
  57. package/src/prelude/values/prototypes/array.hpp +16 -16
  58. package/src/prelude/values/prototypes/function.hpp +4 -4
  59. package/src/prelude/values/prototypes/iterator.hpp +11 -10
  60. package/src/prelude/values/prototypes/object.hpp +26 -0
  61. package/src/prelude/values/prototypes/promise.hpp +124 -0
  62. package/src/prelude/values/prototypes/string.hpp +26 -26
  63. package/src/prelude/values/prototypes/symbol.hpp +5 -3
  64. package/src/prelude/values/string.hpp +1 -1
  65. package/src/prelude/values/symbol.hpp +1 -1
  66. package/src/prelude/access.hpp +0 -91
  67. package/src/prelude/error.hpp +0 -31
  68. package/src/prelude/error_helpers.hpp +0 -59
  69. package/src/prelude/log_string.hpp +0 -407
@@ -0,0 +1,464 @@
1
+ import ts from "typescript";
2
+ import { CodeGenerator } from "./";
3
+ export function visitForStatement(node, context) {
4
+ const forStmt = node;
5
+ let code = "";
6
+ if (context.currentLabel) {
7
+ code += `${this.indent()}${context.currentLabel}: {\n`;
8
+ this.indentationLevel++;
9
+ }
10
+ this.indentationLevel++; // Enter a new scope for the for loop
11
+ // Handle initializer
12
+ let initializerCode = "";
13
+ if (forStmt.initializer) {
14
+ if (ts.isVariableDeclarationList(forStmt.initializer)) {
15
+ const varDeclList = forStmt.initializer;
16
+ const isLetOrConst = (varDeclList.flags &
17
+ (ts.NodeFlags.Let | ts.NodeFlags.Const)) !==
18
+ 0;
19
+ if (isLetOrConst) {
20
+ const decl = varDeclList.declarations[0];
21
+ if (decl) {
22
+ const name = decl.name.getText();
23
+ const initValue = decl.initializer
24
+ ? this.visit(decl.initializer, context)
25
+ : "jspp::AnyValue::make_undefined()";
26
+ const scope = this.getScopeForNode(decl);
27
+ const typeInfo = this.typeAnalyzer.scopeManager
28
+ .lookupFromScope(name, scope);
29
+ if (typeInfo.needsHeapAllocation) {
30
+ initializerCode =
31
+ `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
32
+ }
33
+ else {
34
+ initializerCode =
35
+ `jspp::AnyValue ${name} = ${initValue}`;
36
+ }
37
+ }
38
+ }
39
+ else {
40
+ initializerCode = this.visit(forStmt.initializer, {
41
+ ...context,
42
+ isAssignmentOnly: true,
43
+ });
44
+ }
45
+ }
46
+ else {
47
+ initializerCode = this.visit(forStmt.initializer, context);
48
+ }
49
+ }
50
+ code += `${this.indent()}for (${initializerCode}; `;
51
+ if (forStmt.condition) {
52
+ code += `(${this.visit(forStmt.condition, context)}).is_truthy()`;
53
+ }
54
+ code += "; ";
55
+ if (forStmt.incrementor) {
56
+ code += this.visit(forStmt.incrementor, context);
57
+ }
58
+ code += ") ";
59
+ const statementCode = this.visit(forStmt.statement, {
60
+ ...context,
61
+ currentLabel: undefined,
62
+ isFunctionBody: false,
63
+ });
64
+ if (ts.isBlock(node.statement)) {
65
+ let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
66
+ if (context.currentLabel) {
67
+ blockContent +=
68
+ `${this.indent()}${context.currentLabel}_continue:;\n`;
69
+ }
70
+ code += `{\n${blockContent}}\n`;
71
+ }
72
+ else {
73
+ code += `{\n`;
74
+ code += statementCode;
75
+ if (context.currentLabel) {
76
+ code += `${this.indent()}${context.currentLabel}_continue:;\n`;
77
+ }
78
+ code += `${this.indent()}}\n`;
79
+ }
80
+ this.indentationLevel--; // Exit the scope for the for loop
81
+ if (context.currentLabel) {
82
+ this.indentationLevel--;
83
+ code += `${this.indent()}}\n`;
84
+ code +=
85
+ `${this.indent()}${context.currentLabel}_break:; // break target\n`;
86
+ }
87
+ return code;
88
+ }
89
+ export function visitForInStatement(node, context) {
90
+ const forIn = node;
91
+ let code = "";
92
+ if (context.currentLabel) {
93
+ code += `${this.indent()}${context.currentLabel}: {\n`;
94
+ this.indentationLevel++;
95
+ }
96
+ code += `${this.indent()}{\n`;
97
+ this.indentationLevel++; // Enter a new scope for the for-in loop
98
+ let varName = "";
99
+ let assignmentTarget = "";
100
+ if (ts.isVariableDeclarationList(forIn.initializer)) {
101
+ const decl = forIn.initializer.declarations[0];
102
+ if (decl) {
103
+ varName = decl.name.getText();
104
+ const scope = this.getScopeForNode(decl);
105
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(varName, scope);
106
+ if (typeInfo.needsHeapAllocation) {
107
+ code +=
108
+ `${this.indent()}auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
109
+ assignmentTarget = `*${varName}`;
110
+ }
111
+ else {
112
+ code +=
113
+ `${this.indent()}jspp::AnyValue ${varName} = jspp::AnyValue::make_undefined();\n`;
114
+ assignmentTarget = varName;
115
+ }
116
+ }
117
+ }
118
+ else if (ts.isIdentifier(forIn.initializer)) {
119
+ varName = forIn.initializer.getText();
120
+ const scope = this.getScopeForNode(forIn.initializer);
121
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(varName, scope);
122
+ assignmentTarget = typeInfo.needsHeapAllocation
123
+ ? `*${varName}`
124
+ : varName;
125
+ }
126
+ const expr = forIn.expression;
127
+ const exprText = this.visit(expr, context);
128
+ let derefExpr = exprText;
129
+ if (ts.isIdentifier(expr)) {
130
+ const scope = this.getScopeForNode(expr);
131
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.getText(), scope);
132
+ derefExpr = this.getDerefCode(exprText, this.getJsVarName(expr), typeInfo);
133
+ }
134
+ const keysVar = this.generateUniqueName("__keys_", new Set([varName]));
135
+ code +=
136
+ `${this.indent()}std::vector<std::string> ${keysVar} = jspp::Access::get_object_keys(${derefExpr});\n`;
137
+ code += `${this.indent()}for (const auto& ${varName}_str : ${keysVar}) {\n`;
138
+ this.indentationLevel++;
139
+ code +=
140
+ `${this.indent()}${assignmentTarget} = jspp::AnyValue::make_string(${varName}_str);\n`;
141
+ code += this.visit(forIn.statement, {
142
+ ...context,
143
+ currentLabel: undefined,
144
+ isFunctionBody: false,
145
+ });
146
+ this.indentationLevel--;
147
+ if (context.currentLabel) {
148
+ code += `${this.indent()}${context.currentLabel}_continue:;\n`;
149
+ }
150
+ code += `${this.indent()}}\n`;
151
+ this.indentationLevel--; // Exit the scope for the for-in loop
152
+ code += `${this.indent()}}\n`;
153
+ if (context.currentLabel) {
154
+ this.indentationLevel--;
155
+ code += `${this.indent()}}\n`;
156
+ code +=
157
+ `${this.indent()}${context.currentLabel}_break:; // break target\n`;
158
+ }
159
+ return code;
160
+ }
161
+ export function visitForOfStatement(node, context) {
162
+ const forOf = node;
163
+ let code = "";
164
+ if (context.currentLabel) {
165
+ code += `${this.indent()}${context.currentLabel}: {\n`;
166
+ this.indentationLevel++;
167
+ }
168
+ this.indentationLevel++; // Enter a new scope for the for-of loop
169
+ let elemName = "";
170
+ let assignmentTarget = "";
171
+ code += `${this.indent()}{\n`;
172
+ if (ts.isVariableDeclarationList(forOf.initializer)) {
173
+ const decl = forOf.initializer.declarations[0];
174
+ if (decl) {
175
+ elemName = decl.name.getText();
176
+ const scope = this.getScopeForNode(decl);
177
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemName, scope);
178
+ if (typeInfo.needsHeapAllocation) {
179
+ code +=
180
+ `${this.indent()}auto ${elemName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
181
+ assignmentTarget = `*${elemName}`;
182
+ }
183
+ else {
184
+ code +=
185
+ `${this.indent()}jspp::AnyValue ${elemName} = jspp::AnyValue::make_undefined();\n`;
186
+ assignmentTarget = elemName;
187
+ }
188
+ }
189
+ }
190
+ else if (ts.isIdentifier(forOf.initializer)) {
191
+ elemName = forOf.initializer.getText();
192
+ const scope = this.getScopeForNode(forOf.initializer);
193
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemName, scope);
194
+ assignmentTarget = typeInfo.needsHeapAllocation
195
+ ? `*${elemName}`
196
+ : elemName;
197
+ }
198
+ const iterableExpr = this.visit(forOf.expression, context);
199
+ let derefIterable = iterableExpr;
200
+ if (ts.isIdentifier(forOf.expression)) {
201
+ const scope = this.getScopeForNode(forOf.expression);
202
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(forOf.expression.getText(), scope);
203
+ const varName = this.getJsVarName(forOf.expression);
204
+ derefIterable = this.getDerefCode(iterableExpr, varName, typeInfo);
205
+ }
206
+ const declaredSymbols = this.getDeclaredSymbols(forOf.statement);
207
+ const iterableRef = this.generateUniqueName("__iter_ref", declaredSymbols);
208
+ const iterator = this.generateUniqueName("__iter", declaredSymbols);
209
+ const nextFunc = this.generateUniqueName("__next_func", declaredSymbols);
210
+ const nextRes = this.generateUniqueName("__next_res", declaredSymbols);
211
+ const varName = this.getJsVarName(forOf.expression);
212
+ code += `${this.indent()}auto ${iterableRef} = ${derefIterable};\n`;
213
+ code +=
214
+ `${this.indent()}auto ${iterator} = jspp::Access::get_object_value_iterator(${iterableRef}, ${varName});\n`;
215
+ code +=
216
+ `${this.indent()}auto ${nextFunc} = ${iterator}.get_own_property("next").as_function();\n`;
217
+ code +=
218
+ `${this.indent()}auto ${nextRes} = ${nextFunc}->call(${iterator}, {});\n`;
219
+ code +=
220
+ `${this.indent()}while (!${nextRes}.get_own_property("done").is_truthy()) {\n`;
221
+ this.indentationLevel++;
222
+ code +=
223
+ `${this.indent()}${assignmentTarget} = ${nextRes}.get_own_property("value");\n`;
224
+ code += this.visit(forOf.statement, {
225
+ ...context,
226
+ currentLabel: undefined,
227
+ isFunctionBody: false,
228
+ });
229
+ if (context.currentLabel) {
230
+ code += `${this.indent()}${context.currentLabel}_continue:;\n`;
231
+ }
232
+ code +=
233
+ `${this.indent()}${nextRes} = ${nextFunc}->call(${iterator}, {});\n`;
234
+ this.indentationLevel--;
235
+ code += `${this.indent()}}\n`;
236
+ this.indentationLevel--; // Exit the scope for the for-of loop
237
+ code += `${this.indent()}}\n`;
238
+ if (context.currentLabel) {
239
+ this.indentationLevel--;
240
+ code += `${this.indent()}}\n`;
241
+ code +=
242
+ `${this.indent()}${context.currentLabel}_break:; // break target\n`;
243
+ }
244
+ return code;
245
+ }
246
+ export function visitWhileStatement(node, context) {
247
+ const condition = node.expression;
248
+ const conditionText = condition.kind === ts.SyntaxKind.TrueKeyword ||
249
+ condition.kind === ts.SyntaxKind.FalseKeyword
250
+ ? condition.getText()
251
+ : `(${this.visit(condition, context)}).is_truthy()`;
252
+ let code = "";
253
+ if (context.currentLabel) {
254
+ code += `${this.indent()}${context.currentLabel}: {\n`;
255
+ this.indentationLevel++;
256
+ }
257
+ code += `${this.indent()}while (${conditionText}) `;
258
+ const statementCode = this.visit(node.statement, {
259
+ ...context,
260
+ currentLabel: undefined,
261
+ isFunctionBody: false,
262
+ });
263
+ if (ts.isBlock(node.statement)) {
264
+ let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
265
+ if (context.currentLabel) {
266
+ blockContent +=
267
+ `${this.indent()}${context.currentLabel}_continue:;\n`;
268
+ }
269
+ code += `{\n${blockContent}}\n`;
270
+ }
271
+ else {
272
+ code += `{\n`;
273
+ this.indentationLevel++;
274
+ code += statementCode;
275
+ if (context.currentLabel) {
276
+ code += `${this.indent()}${context.currentLabel}_continue:;\n`;
277
+ }
278
+ this.indentationLevel--;
279
+ code += `${this.indent()}}\n`;
280
+ }
281
+ if (context.currentLabel) {
282
+ this.indentationLevel--;
283
+ code += `${this.indent()}}\n`;
284
+ code +=
285
+ `${this.indent()}${context.currentLabel}_break:; // break target\n`;
286
+ }
287
+ return code;
288
+ }
289
+ export function visitDoStatement(node, context) {
290
+ const condition = node.expression;
291
+ const conditionText = `(${this.visit(condition, context)}).is_truthy()`;
292
+ let code = "";
293
+ if (context.currentLabel) {
294
+ code += `${this.indent()}${context.currentLabel}: {\n`;
295
+ this.indentationLevel++;
296
+ }
297
+ code += `${this.indent()}do `;
298
+ const statementCode = this.visit(node.statement, {
299
+ ...context,
300
+ currentLabel: undefined,
301
+ isFunctionBody: false,
302
+ });
303
+ if (ts.isBlock(node.statement)) {
304
+ let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
305
+ if (context.currentLabel) {
306
+ blockContent +=
307
+ `${this.indent()}${context.currentLabel}_continue:;\n`;
308
+ }
309
+ code += `{\n${blockContent}}`;
310
+ }
311
+ else {
312
+ code += `{\n`;
313
+ this.indentationLevel++;
314
+ code += statementCode;
315
+ if (context.currentLabel) {
316
+ code += `${this.indent()}${context.currentLabel}_continue:;\n`;
317
+ }
318
+ this.indentationLevel--;
319
+ code += `${this.indent()}}`;
320
+ }
321
+ code += ` while (${conditionText});\n`;
322
+ if (context.currentLabel) {
323
+ this.indentationLevel--;
324
+ code += `${this.indent()}}\n`;
325
+ code +=
326
+ `${this.indent()}${context.currentLabel}_break:; // break target\n`;
327
+ }
328
+ return code;
329
+ }
330
+ export function visitSwitchStatement(node, context) {
331
+ const switchStmt = node;
332
+ let code = "";
333
+ const declaredSymbols = this.getDeclaredSymbols(switchStmt.caseBlock);
334
+ const switchBreakLabel = this.generateUniqueName("__switch_break_", declaredSymbols);
335
+ const fallthroughVar = this.generateUniqueName("__switch_fallthrough_", declaredSymbols);
336
+ if (context.currentLabel) {
337
+ code += `${this.indent()}${context.currentLabel}: {\n`;
338
+ this.indentationLevel++;
339
+ }
340
+ code += `${this.indent()}{\n`; // Wrap the entire switch logic in a block
341
+ this.indentationLevel++;
342
+ // Evaluate the switch expression once
343
+ const expressionCode = this.visit(switchStmt.expression, context);
344
+ const switchValueVar = this.generateUniqueName("__switch_value_", declaredSymbols);
345
+ code +=
346
+ `${this.indent()}const jspp::AnyValue ${switchValueVar} = ${expressionCode};\n`;
347
+ code += `${this.indent()}bool ${fallthroughVar} = false;\n`;
348
+ // Hoist variable declarations
349
+ const hoistedSymbols = new Map();
350
+ for (const clause of switchStmt.caseBlock.clauses) {
351
+ if (ts.isCaseClause(clause) || ts.isDefaultClause(clause)) {
352
+ for (const stmt of clause.statements) {
353
+ if (ts.isVariableStatement(stmt)) {
354
+ const varDecls = stmt.declarationList.declarations;
355
+ for (const decl of varDecls) {
356
+ code += this.hoistDeclaration(decl, hoistedSymbols);
357
+ }
358
+ }
359
+ else if (ts.isFunctionDeclaration(stmt)) {
360
+ code += this.hoistDeclaration(stmt, hoistedSymbols);
361
+ }
362
+ }
363
+ }
364
+ }
365
+ // Prepare scope symbols for the switch block
366
+ const topLevelScopeSymbols = this.prepareScopeSymbolsForVisit(context.topLevelScopeSymbols, context.currentScopeSymbols);
367
+ let firstIf = true;
368
+ for (const clause of switchStmt.caseBlock.clauses) {
369
+ if (ts.isCaseClause(clause)) {
370
+ const caseExprCode = this.visit(clause.expression, {
371
+ ...context,
372
+ currentLabel: undefined, // Clear currentLabel for nested visits
373
+ });
374
+ let condition = "";
375
+ if (firstIf) {
376
+ condition =
377
+ `(${fallthroughVar} || ${switchValueVar}.is_strictly_equal_to_primitive(${caseExprCode}))`;
378
+ code += `${this.indent()}if ${condition} {\n`;
379
+ firstIf = false;
380
+ }
381
+ else {
382
+ condition =
383
+ `(${fallthroughVar} || ${switchValueVar}.is_strictly_equal_to_primitive(${caseExprCode}))`;
384
+ code += `${this.indent()}if ${condition} {\n`;
385
+ }
386
+ this.indentationLevel++;
387
+ code += `${this.indent()}${fallthroughVar} = true;\n`;
388
+ for (const stmt of clause.statements) {
389
+ if (ts.isFunctionDeclaration(stmt)) {
390
+ const funcName = stmt.name?.getText();
391
+ if (funcName) {
392
+ const contextForFunction = {
393
+ ...context,
394
+ topLevelScopeSymbols,
395
+ currentScopeSymbols: hoistedSymbols,
396
+ };
397
+ const lambda = this.generateLambda(stmt, contextForFunction, { isAssignment: true });
398
+ code += `${this.indent()}*${funcName} = ${lambda};\n`;
399
+ }
400
+ }
401
+ else {
402
+ code += this.visit(stmt, {
403
+ ...context,
404
+ switchBreakLabel,
405
+ currentLabel: undefined, // Clear currentLabel for nested visits
406
+ topLevelScopeSymbols,
407
+ currentScopeSymbols: hoistedSymbols,
408
+ derefBeforeAssignment: true,
409
+ isAssignmentOnly: ts.isVariableStatement(stmt),
410
+ });
411
+ }
412
+ }
413
+ this.indentationLevel--;
414
+ code += `${this.indent()}}\n`;
415
+ }
416
+ else if (ts.isDefaultClause(clause)) {
417
+ // Default clause
418
+ code +=
419
+ `${this.indent()}if (!${fallthroughVar}) ${fallthroughVar} = true;\n`;
420
+ if (firstIf) {
421
+ code += `${this.indent()}if (true) {\n`; // Always execute if no prior cases match and it's the first clause
422
+ firstIf = false;
423
+ }
424
+ else {
425
+ code += `${this.indent()}if (${fallthroughVar}) {\n`; // Only execute if no prior case (or default) has matched and caused fallthrough
426
+ }
427
+ this.indentationLevel++;
428
+ for (const stmt of clause.statements) {
429
+ code += this.visit(stmt, {
430
+ ...context,
431
+ switchBreakLabel,
432
+ currentLabel: undefined, // Clear currentLabel for nested visits
433
+ topLevelScopeSymbols,
434
+ currentScopeSymbols: hoistedSymbols,
435
+ derefBeforeAssignment: true,
436
+ isAssignmentOnly: ts.isVariableStatement(stmt),
437
+ });
438
+ }
439
+ this.indentationLevel--;
440
+ code += `${this.indent()}}\n`;
441
+ }
442
+ }
443
+ this.indentationLevel--;
444
+ code += `${this.indent()}}\n`; // End of the switch block
445
+ code +=
446
+ `${this.indent()}${switchBreakLabel}:; // break target for switch\n`;
447
+ if (context.currentLabel) {
448
+ this.indentationLevel--;
449
+ code += `${this.indent()}}\n`;
450
+ code +=
451
+ `${this.indent()}${context.currentLabel}_break:; // break target for labeled switch\n`;
452
+ }
453
+ return code;
454
+ }
455
+ export function visitCaseClause(node, context) {
456
+ // Case clauses are handled inline by visitSwitchStatement, not generated directly
457
+ // This function will likely not be called, or can return an empty string
458
+ return "";
459
+ }
460
+ export function visitDefaultClause(node, context) {
461
+ // Default clauses are handled inline by visitSwitchStatement, not generated directly
462
+ // This function will likely not be called, or can return an empty string
463
+ return "";
464
+ }
@@ -9,41 +9,58 @@ export function visitVariableDeclarationList(node, context) {
9
9
  export function visitVariableDeclaration(node, context) {
10
10
  const varDecl = node;
11
11
  const name = varDecl.name.getText();
12
+ const scope = this.getScopeForNode(varDecl);
13
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
12
14
  let initializer = "";
13
15
  if (varDecl.initializer) {
14
16
  const initExpr = varDecl.initializer;
15
- let initText = this.visit(initExpr, context);
17
+ const initContext = {
18
+ ...context,
19
+ lambdaName: ts.isArrowFunction(initExpr) ? name : undefined, // Pass the variable name for arrow functions
20
+ };
21
+ let initText = this.visit(initExpr, initContext);
16
22
  if (ts.isIdentifier(initExpr)) {
17
- const scope = this.getScopeForNode(initExpr);
18
- const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(initExpr.text, scope);
23
+ const initScope = this.getScopeForNode(initExpr);
24
+ const initTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(initExpr.text, initScope);
19
25
  const varName = this.getJsVarName(initExpr);
20
- if (typeInfo && !typeInfo.isParameter && !typeInfo.isBuiltin) {
21
- initText = `jspp::Access::deref(${initText}, ${varName})`;
26
+ if (initTypeInfo &&
27
+ !initTypeInfo.isParameter &&
28
+ !initTypeInfo.isBuiltin) {
29
+ initText = this.getDerefCode(initText, varName, initTypeInfo);
22
30
  }
23
31
  }
24
32
  initializer = " = " + initText;
25
33
  }
26
34
  const isLetOrConst = (varDecl.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
35
+ const shouldDeref = context.derefBeforeAssignment &&
36
+ (!context.currentScopeSymbols.has(name));
37
+ const assignmentTarget = shouldDeref
38
+ ? this.getDerefCode(name, name, typeInfo)
39
+ : (typeInfo.needsHeapAllocation ? `*${name}` : name);
27
40
  if (isLetOrConst) {
28
41
  // If there's no initializer, it should be assigned undefined.
29
- if (!initializer)
30
- return `*${name} = jspp::AnyValue::make_undefined()`;
31
- return `*${name}${initializer}`;
42
+ if (!initializer) {
43
+ return `${assignmentTarget} = jspp::AnyValue::make_undefined()`;
44
+ }
45
+ return `${assignmentTarget}${initializer}`;
32
46
  }
33
47
  // For 'var', it's a bit more complex.
34
- // If we are in a non-function-body block, 'var' is hoisted, so it's an assignment.
35
- // If we are at the top level or in a function body, it's a declaration if not already hoisted.
36
- // The current logic hoists at the function level, so we need to decide if this is the *hoisting* declaration or a later assignment.
37
- // The `isAssignmentOnly` flag helps here.
38
48
  if (context.isAssignmentOnly) {
39
49
  if (!initializer)
40
50
  return "";
41
- return `*${name}${initializer}`;
51
+ return `${assignmentTarget}${initializer}`;
42
52
  }
43
53
  else {
54
+ // This case should not be hit with the new hoisting logic,
55
+ // but is kept for safety.
44
56
  const initValue = initializer
45
57
  ? initializer.substring(3)
46
58
  : "jspp::AnyValue::make_undefined()";
47
- return `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
59
+ if (typeInfo.needsHeapAllocation) {
60
+ return `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
61
+ }
62
+ else {
63
+ return `jspp::AnyValue ${name} = ${initValue}`;
64
+ }
48
65
  }
49
66
  }