@ugo-studio/jspp 0.1.4 → 0.1.6

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 (71) hide show
  1. package/dist/analysis/scope.js +17 -0
  2. package/dist/analysis/typeAnalyzer.js +7 -1
  3. package/dist/ast/symbols.js +32 -0
  4. package/dist/ast/types.js +0 -6
  5. package/dist/cli-utils/args.js +57 -0
  6. package/dist/cli-utils/colors.js +9 -0
  7. package/dist/cli-utils/file-utils.js +20 -0
  8. package/dist/cli-utils/spinner.js +55 -0
  9. package/dist/cli.js +105 -30
  10. package/dist/core/codegen/class-handlers.js +10 -6
  11. package/dist/core/codegen/control-flow-handlers.js +57 -28
  12. package/dist/core/codegen/declaration-handlers.js +10 -6
  13. package/dist/core/codegen/expression-handlers.js +206 -61
  14. package/dist/core/codegen/function-handlers.js +203 -76
  15. package/dist/core/codegen/helpers.js +125 -28
  16. package/dist/core/codegen/index.js +23 -15
  17. package/dist/core/codegen/literal-handlers.js +15 -6
  18. package/dist/core/codegen/statement-handlers.js +282 -84
  19. package/dist/core/codegen/visitor.js +3 -1
  20. package/package.json +1 -1
  21. package/src/prelude/any_value.hpp +221 -342
  22. package/src/prelude/any_value_access.hpp +168 -81
  23. package/src/prelude/any_value_defines.hpp +74 -35
  24. package/src/prelude/any_value_helpers.hpp +75 -180
  25. package/src/prelude/exception.hpp +1 -0
  26. package/src/prelude/exception_helpers.hpp +4 -4
  27. package/src/prelude/index.hpp +12 -2
  28. package/src/prelude/library/array.hpp +190 -0
  29. package/src/prelude/library/console.hpp +6 -5
  30. package/src/prelude/library/error.hpp +10 -8
  31. package/src/prelude/library/function.hpp +10 -0
  32. package/src/prelude/library/global.hpp +20 -0
  33. package/src/prelude/library/math.hpp +308 -0
  34. package/src/prelude/library/object.hpp +288 -0
  35. package/src/prelude/library/performance.hpp +1 -1
  36. package/src/prelude/library/process.hpp +39 -0
  37. package/src/prelude/library/promise.hpp +57 -55
  38. package/src/prelude/library/symbol.hpp +45 -57
  39. package/src/prelude/library/timer.hpp +6 -6
  40. package/src/prelude/types.hpp +54 -0
  41. package/src/prelude/utils/access.hpp +215 -11
  42. package/src/prelude/utils/assignment_operators.hpp +99 -0
  43. package/src/prelude/utils/log_any_value/array.hpp +8 -8
  44. package/src/prelude/utils/log_any_value/function.hpp +6 -4
  45. package/src/prelude/utils/log_any_value/object.hpp +41 -24
  46. package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
  47. package/src/prelude/utils/operators.hpp +750 -274
  48. package/src/prelude/utils/well_known_symbols.hpp +12 -0
  49. package/src/prelude/values/array.hpp +8 -6
  50. package/src/prelude/values/async_iterator.hpp +79 -0
  51. package/src/prelude/values/descriptors.hpp +2 -2
  52. package/src/prelude/values/function.hpp +72 -62
  53. package/src/prelude/values/helpers/array.hpp +64 -28
  54. package/src/prelude/values/helpers/async_iterator.hpp +275 -0
  55. package/src/prelude/values/helpers/function.hpp +81 -92
  56. package/src/prelude/values/helpers/iterator.hpp +3 -3
  57. package/src/prelude/values/helpers/object.hpp +54 -9
  58. package/src/prelude/values/helpers/promise.hpp +13 -6
  59. package/src/prelude/values/iterator.hpp +1 -1
  60. package/src/prelude/values/object.hpp +10 -3
  61. package/src/prelude/values/promise.hpp +7 -11
  62. package/src/prelude/values/prototypes/array.hpp +851 -12
  63. package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
  64. package/src/prelude/values/prototypes/function.hpp +2 -2
  65. package/src/prelude/values/prototypes/iterator.hpp +5 -5
  66. package/src/prelude/values/prototypes/number.hpp +153 -0
  67. package/src/prelude/values/prototypes/object.hpp +2 -2
  68. package/src/prelude/values/prototypes/promise.hpp +40 -30
  69. package/src/prelude/values/prototypes/string.hpp +28 -28
  70. package/src/prelude/values/prototypes/symbol.hpp +20 -3
  71. package/src/prelude/values/shape.hpp +52 -0
@@ -1,4 +1,5 @@
1
1
  import ts from "typescript";
2
+ import { DeclaredSymbols, DeclaredSymbolType } from "../../ast/symbols";
2
3
  import { CodeGenerator } from "./";
3
4
  export function visitForStatement(node, context) {
4
5
  const forStmt = node;
@@ -10,6 +11,10 @@ export function visitForStatement(node, context) {
10
11
  this.indentationLevel++; // Enter a new scope for the for loop
11
12
  // Handle initializer
12
13
  let initializerCode = "";
14
+ let conditionContext = {
15
+ ...context,
16
+ topLevelScopeSymbols: this.prepareScopeSymbolsForVisit(context.topLevelScopeSymbols, context.localScopeSymbols),
17
+ };
13
18
  if (forStmt.initializer) {
14
19
  if (ts.isVariableDeclarationList(forStmt.initializer)) {
15
20
  const varDeclList = forStmt.initializer;
@@ -22,10 +27,15 @@ export function visitForStatement(node, context) {
22
27
  const name = decl.name.getText();
23
28
  const initValue = decl.initializer
24
29
  ? this.visit(decl.initializer, context)
25
- : "jspp::AnyValue::make_undefined()";
30
+ : "jspp::Constants::UNDEFINED";
26
31
  const scope = this.getScopeForNode(decl);
27
32
  const typeInfo = this.typeAnalyzer.scopeManager
28
33
  .lookupFromScope(name, scope);
34
+ conditionContext.localScopeSymbols = new DeclaredSymbols();
35
+ conditionContext.localScopeSymbols.set(name, {
36
+ type: DeclaredSymbolType.letOrConst,
37
+ checkedIfUninitialized: true,
38
+ });
29
39
  if (typeInfo.needsHeapAllocation) {
30
40
  initializerCode =
31
41
  `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
@@ -49,7 +59,7 @@ export function visitForStatement(node, context) {
49
59
  }
50
60
  code += `${this.indent()}for (${initializerCode}; `;
51
61
  if (forStmt.condition) {
52
- code += `(${this.visit(forStmt.condition, context)}).is_truthy()`;
62
+ code += `is_truthy(${this.visit(forStmt.condition, conditionContext)})`;
53
63
  }
54
64
  code += "; ";
55
65
  if (forStmt.incrementor) {
@@ -60,7 +70,7 @@ export function visitForStatement(node, context) {
60
70
  ...context,
61
71
  currentLabel: undefined,
62
72
  isFunctionBody: false,
63
- });
73
+ }).trim();
64
74
  if (ts.isBlock(node.statement)) {
65
75
  let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
66
76
  if (context.currentLabel) {
@@ -105,12 +115,12 @@ export function visitForInStatement(node, context) {
105
115
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(varName, scope);
106
116
  if (typeInfo.needsHeapAllocation) {
107
117
  code +=
108
- `${this.indent()}auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
118
+ `${this.indent()}auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::Constants::UNDEFINED);\n`;
109
119
  assignmentTarget = `*${varName}`;
110
120
  }
111
121
  else {
112
122
  code +=
113
- `${this.indent()}jspp::AnyValue ${varName} = jspp::AnyValue::make_undefined();\n`;
123
+ `${this.indent()}jspp::AnyValue ${varName} = jspp::Constants::UNDEFINED;\n`;
114
124
  assignmentTarget = varName;
115
125
  }
116
126
  }
@@ -129,7 +139,7 @@ export function visitForInStatement(node, context) {
129
139
  if (ts.isIdentifier(expr)) {
130
140
  const scope = this.getScopeForNode(expr);
131
141
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.getText(), scope);
132
- derefExpr = this.getDerefCode(exprText, this.getJsVarName(expr), typeInfo);
142
+ derefExpr = this.getDerefCode(exprText, this.getJsVarName(expr), context, typeInfo);
133
143
  }
134
144
  const keysVar = this.generateUniqueName("__keys_", new Set([varName]));
135
145
  code +=
@@ -177,12 +187,12 @@ export function visitForOfStatement(node, context) {
177
187
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(elemName, scope);
178
188
  if (typeInfo.needsHeapAllocation) {
179
189
  code +=
180
- `${this.indent()}auto ${elemName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
190
+ `${this.indent()}auto ${elemName} = std::make_shared<jspp::AnyValue>(jspp::Constants::UNDEFINED);\n`;
181
191
  assignmentTarget = `*${elemName}`;
182
192
  }
183
193
  else {
184
194
  code +=
185
- `${this.indent()}jspp::AnyValue ${elemName} = jspp::AnyValue::make_undefined();\n`;
195
+ `${this.indent()}jspp::AnyValue ${elemName} = jspp::Constants::UNDEFINED;\n`;
186
196
  assignmentTarget = elemName;
187
197
  }
188
198
  }
@@ -201,23 +211,36 @@ export function visitForOfStatement(node, context) {
201
211
  const scope = this.getScopeForNode(forOf.expression);
202
212
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(forOf.expression.getText(), scope);
203
213
  const varName = this.getJsVarName(forOf.expression);
204
- derefIterable = this.getDerefCode(iterableExpr, varName, typeInfo);
214
+ derefIterable = this.getDerefCode(iterableExpr, varName, context, typeInfo);
205
215
  }
206
216
  const declaredSymbols = this.getDeclaredSymbols(forOf.statement);
207
217
  const iterableRef = this.generateUniqueName("__iter_ref", declaredSymbols);
208
218
  const iterator = this.generateUniqueName("__iter", declaredSymbols);
209
219
  const nextFunc = this.generateUniqueName("__next_func", declaredSymbols);
210
220
  const nextRes = this.generateUniqueName("__next_res", declaredSymbols);
221
+ const isAwait = forOf.awaitModifier !== undefined;
211
222
  const varName = this.getJsVarName(forOf.expression);
212
223
  code += `${this.indent()}auto ${iterableRef} = ${derefIterable};\n`;
224
+ if (isAwait) {
225
+ code +=
226
+ `${this.indent()}auto ${iterator} = jspp::Access::get_async_object_value_iterator(${iterableRef}, ${varName});\n`;
227
+ }
228
+ else {
229
+ code +=
230
+ `${this.indent()}auto ${iterator} = jspp::Access::get_object_value_iterator(${iterableRef}, ${varName});\n`;
231
+ }
213
232
  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`;
233
+ `${this.indent()}auto ${nextFunc} = ${iterator}.get_own_property("next");\n`;
234
+ if (isAwait) {
235
+ code +=
236
+ `${this.indent()}auto ${nextRes} = co_await ${nextFunc}.call(${iterator}, {}, "next");\n`;
237
+ }
238
+ else {
239
+ code +=
240
+ `${this.indent()}auto ${nextRes} = ${nextFunc}.call(${iterator}, {}, "next");\n`;
241
+ }
219
242
  code +=
220
- `${this.indent()}while (!${nextRes}.get_own_property("done").is_truthy()) {\n`;
243
+ `${this.indent()}while (!is_truthy(${nextRes}.get_own_property("done"))) {\n`;
221
244
  this.indentationLevel++;
222
245
  code +=
223
246
  `${this.indent()}${assignmentTarget} = ${nextRes}.get_own_property("value");\n`;
@@ -229,8 +252,14 @@ export function visitForOfStatement(node, context) {
229
252
  if (context.currentLabel) {
230
253
  code += `${this.indent()}${context.currentLabel}_continue:;\n`;
231
254
  }
232
- code +=
233
- `${this.indent()}${nextRes} = ${nextFunc}->call(${iterator}, {});\n`;
255
+ if (isAwait) {
256
+ code +=
257
+ `${this.indent()}${nextRes} = co_await ${nextFunc}.call(${iterator}, {}, "next");\n`;
258
+ }
259
+ else {
260
+ code +=
261
+ `${this.indent()}${nextRes} = ${nextFunc}.call(${iterator}, {}, "next");\n`;
262
+ }
234
263
  this.indentationLevel--;
235
264
  code += `${this.indent()}}\n`;
236
265
  this.indentationLevel--; // Exit the scope for the for-of loop
@@ -248,7 +277,7 @@ export function visitWhileStatement(node, context) {
248
277
  const conditionText = condition.kind === ts.SyntaxKind.TrueKeyword ||
249
278
  condition.kind === ts.SyntaxKind.FalseKeyword
250
279
  ? condition.getText()
251
- : `(${this.visit(condition, context)}).is_truthy()`;
280
+ : `is_truthy(${this.visit(condition, context)})`;
252
281
  let code = "";
253
282
  if (context.currentLabel) {
254
283
  code += `${this.indent()}${context.currentLabel}: {\n`;
@@ -259,7 +288,7 @@ export function visitWhileStatement(node, context) {
259
288
  ...context,
260
289
  currentLabel: undefined,
261
290
  isFunctionBody: false,
262
- });
291
+ }).trim();
263
292
  if (ts.isBlock(node.statement)) {
264
293
  let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
265
294
  if (context.currentLabel) {
@@ -288,7 +317,7 @@ export function visitWhileStatement(node, context) {
288
317
  }
289
318
  export function visitDoStatement(node, context) {
290
319
  const condition = node.expression;
291
- const conditionText = `(${this.visit(condition, context)}).is_truthy()`;
320
+ const conditionText = `is_truthy(${this.visit(condition, context)})`;
292
321
  let code = "";
293
322
  if (context.currentLabel) {
294
323
  code += `${this.indent()}${context.currentLabel}: {\n`;
@@ -299,7 +328,7 @@ export function visitDoStatement(node, context) {
299
328
  ...context,
300
329
  currentLabel: undefined,
301
330
  isFunctionBody: false,
302
- });
331
+ }).trim();
303
332
  if (ts.isBlock(node.statement)) {
304
333
  let blockContent = statementCode.substring(1, statementCode.length - 2); // remove curly braces
305
334
  if (context.currentLabel) {
@@ -346,7 +375,7 @@ export function visitSwitchStatement(node, context) {
346
375
  `${this.indent()}const jspp::AnyValue ${switchValueVar} = ${expressionCode};\n`;
347
376
  code += `${this.indent()}bool ${fallthroughVar} = false;\n`;
348
377
  // Hoist variable declarations
349
- const hoistedSymbols = new Map();
378
+ const hoistedSymbols = new DeclaredSymbols();
350
379
  for (const clause of switchStmt.caseBlock.clauses) {
351
380
  if (ts.isCaseClause(clause) || ts.isDefaultClause(clause)) {
352
381
  for (const stmt of clause.statements) {
@@ -363,7 +392,7 @@ export function visitSwitchStatement(node, context) {
363
392
  }
364
393
  }
365
394
  // Prepare scope symbols for the switch block
366
- const topLevelScopeSymbols = this.prepareScopeSymbolsForVisit(context.topLevelScopeSymbols, context.currentScopeSymbols);
395
+ const topLevelScopeSymbols = this.prepareScopeSymbolsForVisit(context.topLevelScopeSymbols, context.localScopeSymbols);
367
396
  let firstIf = true;
368
397
  for (const clause of switchStmt.caseBlock.clauses) {
369
398
  if (ts.isCaseClause(clause)) {
@@ -374,13 +403,13 @@ export function visitSwitchStatement(node, context) {
374
403
  let condition = "";
375
404
  if (firstIf) {
376
405
  condition =
377
- `(${fallthroughVar} || ${switchValueVar}.is_strictly_equal_to_primitive(${caseExprCode}))`;
406
+ `(${fallthroughVar} || jspp::is_strictly_equal_to_primitive(${switchValueVar}, ${caseExprCode}))`;
378
407
  code += `${this.indent()}if ${condition} {\n`;
379
408
  firstIf = false;
380
409
  }
381
410
  else {
382
411
  condition =
383
- `(${fallthroughVar} || ${switchValueVar}.is_strictly_equal_to_primitive(${caseExprCode}))`;
412
+ `(${fallthroughVar} || jspp::is_strictly_equal_to_primitive(${switchValueVar}, ${caseExprCode}))`;
384
413
  code += `${this.indent()}if ${condition} {\n`;
385
414
  }
386
415
  this.indentationLevel++;
@@ -392,7 +421,7 @@ export function visitSwitchStatement(node, context) {
392
421
  const contextForFunction = {
393
422
  ...context,
394
423
  topLevelScopeSymbols,
395
- currentScopeSymbols: hoistedSymbols,
424
+ localScopeSymbols: hoistedSymbols,
396
425
  };
397
426
  const lambda = this.generateLambda(stmt, contextForFunction, { isAssignment: true });
398
427
  code += `${this.indent()}*${funcName} = ${lambda};\n`;
@@ -404,7 +433,7 @@ export function visitSwitchStatement(node, context) {
404
433
  switchBreakLabel,
405
434
  currentLabel: undefined, // Clear currentLabel for nested visits
406
435
  topLevelScopeSymbols,
407
- currentScopeSymbols: hoistedSymbols,
436
+ localScopeSymbols: hoistedSymbols,
408
437
  derefBeforeAssignment: true,
409
438
  isAssignmentOnly: ts.isVariableStatement(stmt),
410
439
  });
@@ -431,7 +460,7 @@ export function visitSwitchStatement(node, context) {
431
460
  switchBreakLabel,
432
461
  currentLabel: undefined, // Clear currentLabel for nested visits
433
462
  topLevelScopeSymbols,
434
- currentScopeSymbols: hoistedSymbols,
463
+ localScopeSymbols: hoistedSymbols,
435
464
  derefBeforeAssignment: true,
436
465
  isAssignmentOnly: ts.isVariableStatement(stmt),
437
466
  });
@@ -11,6 +11,8 @@ export function visitVariableDeclaration(node, context) {
11
11
  const name = varDecl.name.getText();
12
12
  const scope = this.getScopeForNode(varDecl);
13
13
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
14
+ // Mark the symbol as checked
15
+ this.markSymbolAsChecked(name, context.topLevelScopeSymbols, context.localScopeSymbols);
14
16
  let initializer = "";
15
17
  if (varDecl.initializer) {
16
18
  const initExpr = varDecl.initializer;
@@ -18,7 +20,9 @@ export function visitVariableDeclaration(node, context) {
18
20
  ...context,
19
21
  lambdaName: ts.isArrowFunction(initExpr) ? name : undefined, // Pass the variable name for arrow functions
20
22
  };
21
- let initText = this.visit(initExpr, initContext);
23
+ let initText = ts.isNumericLiteral(initExpr)
24
+ ? initExpr.getText()
25
+ : this.visit(initExpr, initContext);
22
26
  if (ts.isIdentifier(initExpr)) {
23
27
  const initScope = this.getScopeForNode(initExpr);
24
28
  const initTypeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(initExpr.text, initScope);
@@ -26,21 +30,21 @@ export function visitVariableDeclaration(node, context) {
26
30
  if (initTypeInfo &&
27
31
  !initTypeInfo.isParameter &&
28
32
  !initTypeInfo.isBuiltin) {
29
- initText = this.getDerefCode(initText, varName, initTypeInfo);
33
+ initText = this.getDerefCode(initText, varName, initContext, initTypeInfo);
30
34
  }
31
35
  }
32
36
  initializer = " = " + initText;
33
37
  }
34
38
  const isLetOrConst = (varDecl.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
35
39
  const shouldDeref = context.derefBeforeAssignment &&
36
- (!context.currentScopeSymbols.has(name));
40
+ (!context.localScopeSymbols.has(name));
37
41
  const assignmentTarget = shouldDeref
38
- ? this.getDerefCode(name, name, typeInfo)
42
+ ? this.getDerefCode(name, name, context, typeInfo)
39
43
  : (typeInfo.needsHeapAllocation ? `*${name}` : name);
40
44
  if (isLetOrConst) {
41
45
  // If there's no initializer, it should be assigned undefined.
42
46
  if (!initializer) {
43
- return `${assignmentTarget} = jspp::AnyValue::make_undefined()`;
47
+ return `${assignmentTarget} = jspp::Constants::UNDEFINED`;
44
48
  }
45
49
  return `${assignmentTarget}${initializer}`;
46
50
  }
@@ -55,7 +59,7 @@ export function visitVariableDeclaration(node, context) {
55
59
  // but is kept for safety.
56
60
  const initValue = initializer
57
61
  ? initializer.substring(3)
58
- : "jspp::AnyValue::make_undefined()";
62
+ : "jspp::Constants::UNDEFINED";
59
63
  if (typeInfo.needsHeapAllocation) {
60
64
  return `auto ${name} = std::make_shared<jspp::AnyValue>(${initValue})`;
61
65
  }