@ugo-studio/jspp 0.1.1 → 0.1.3

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 (41) hide show
  1. package/README.md +3 -1
  2. package/dist/analysis/scope.js +22 -11
  3. package/dist/analysis/typeAnalyzer.js +4 -3
  4. package/dist/cli.js +7 -5
  5. package/dist/core/codegen/expression-handlers.js +10 -6
  6. package/dist/core/codegen/function-handlers.js +27 -6
  7. package/dist/core/codegen/helpers.js +12 -8
  8. package/dist/core/codegen/index.js +3 -1
  9. package/dist/core/codegen/statement-handlers.js +53 -16
  10. package/dist/core/codegen/visitor.js +7 -1
  11. package/package.json +2 -2
  12. package/src/prelude/access.hpp +8 -3
  13. package/src/prelude/any_value.hpp +141 -241
  14. package/src/prelude/any_value_helpers.hpp +225 -0
  15. package/src/prelude/error_helpers.hpp +3 -3
  16. package/src/prelude/index.hpp +17 -3
  17. package/src/prelude/library/console.hpp +7 -7
  18. package/src/prelude/library/performance.hpp +25 -0
  19. package/src/prelude/library/symbol.hpp +60 -3
  20. package/src/prelude/log_string.hpp +10 -6
  21. package/src/prelude/operators.hpp +2 -2
  22. package/src/prelude/types.hpp +24 -6
  23. package/src/prelude/values/array.hpp +2 -0
  24. package/src/prelude/values/function.hpp +33 -1
  25. package/src/prelude/values/{operators → helpers}/array.hpp +14 -7
  26. package/src/prelude/values/helpers/function.hpp +77 -0
  27. package/src/prelude/values/helpers/iterator.hpp +101 -0
  28. package/src/prelude/values/helpers/string.hpp +50 -0
  29. package/src/prelude/values/helpers/symbol.hpp +23 -0
  30. package/src/prelude/values/iterator.hpp +88 -0
  31. package/src/prelude/values/object.hpp +2 -1
  32. package/src/prelude/values/prototypes/array.hpp +18 -11
  33. package/src/prelude/values/prototypes/function.hpp +26 -0
  34. package/src/prelude/values/prototypes/iterator.hpp +57 -0
  35. package/src/prelude/values/prototypes/string.hpp +366 -357
  36. package/src/prelude/values/prototypes/symbol.hpp +39 -0
  37. package/src/prelude/values/string.hpp +25 -0
  38. package/src/prelude/values/symbol.hpp +102 -0
  39. package/src/prelude/well_known_symbols.hpp +7 -3
  40. package/src/prelude/values/operators/function.hpp +0 -34
  41. /package/src/prelude/values/{operators → helpers}/object.hpp +0 -0
package/README.md CHANGED
@@ -33,6 +33,8 @@ JSPP reserves certain keywords to avoid conflicts with the generated C++ code an
33
33
 
34
34
  - `std`: Reserved to prevent conflicts with the C++ standard library namespace.
35
35
  - `jspp`: Reserved for internal use by the JSPP transpiler.
36
+ - `co_yield`: Reserved to prevent conflicts with the c++ generator functions.
37
+ - `co_return`: Reserved to prevent conflicts with the c++ generator functions.
36
38
 
37
39
  Using these keywords as variable names will result in a `SyntaxError`.
38
40
 
@@ -45,7 +47,7 @@ The transpilation process is a classic three-stage pipeline:
45
47
  2. **Analysis:** The `TypeAnalyzer` traverses the AST. While it doesn't perform traditional static type checking, it plays a crucial role in understanding the code's structure. It identifies scopes (global, function, block) and detects when variables are "captured" by closures.
46
48
 
47
49
  3. **Code Generation:** The `CodeGenerator` performs a final traversal of the AST. It translates each node into its C++ equivalent.
48
- - All variables are declared as `std::shared_ptr<AnyValue>` (where `AnyValue` uses a [Tagged Union](https://en.wikipedia.org/wiki/Tagged_union) system for managing dynamic types like JavaScript). This approach elegantly mimics JavaScript's dynamic types and reference-based memory model.
50
+ - All variables are declared as `std::shared_ptr<AnyValue>` (where `AnyValue` uses a [Tagged Union](https://en.wikipedia.org/wiki/Tagged_union) method for managing dynamic types like JavaScript). This approach elegantly mimics JavaScript's dynamic types and reference-based memory model.
49
51
  - Closures are implemented as C++ lambdas that capture `shared_ptr`s by value, ensuring variable lifetimes are correctly extended beyond their original scope.
50
52
  - The entire script is wrapped into a single `main` function, with hoisting logic carefully replicated to ensure correct execution order.
51
53
 
@@ -1,4 +1,18 @@
1
- const RESERVED_KEYWORDS = ["std", "jspp"];
1
+ export const RESERVED_KEYWORDS = new Set([
2
+ "jspp",
3
+ "std",
4
+ "co_yield",
5
+ "co_return",
6
+ ]);
7
+ export const BUILTIN_OBJECTS = new Set([
8
+ { name: "undefined", isConst: true },
9
+ { name: "null", isConst: true },
10
+ { name: "Symbol", isConst: false },
11
+ { name: "console", isConst: false },
12
+ { name: "performance", isConst: false },
13
+ { name: "global", isConst: false },
14
+ { name: "globalThis", isConst: false },
15
+ ]);
2
16
  // Represents a single scope (e.g., a function body or a block statement)
3
17
  export class Scope {
4
18
  parent;
@@ -31,16 +45,13 @@ export class ScopeManager {
31
45
  const rootScope = new Scope(null); // The global scope
32
46
  this.currentScope = rootScope;
33
47
  this.allScopes.push(rootScope); // Add the root scope to our list
34
- this.define("undefined", {
35
- type: "undefined",
36
- isConst: true,
37
- isBuiltin: true,
38
- });
39
- this.define("null", {
40
- type: "null",
41
- isConst: true,
42
- isBuiltin: true,
43
- });
48
+ for (const { name, isConst } of BUILTIN_OBJECTS) {
49
+ this.define(name, {
50
+ type: name,
51
+ isConst: isConst,
52
+ isBuiltin: true,
53
+ });
54
+ }
44
55
  }
45
56
  // Enters a new, nested scope.
46
57
  enterScope() {
@@ -1,4 +1,5 @@
1
1
  import * as ts from "typescript";
2
+ import { isBuiltinObject } from "../core/codegen/helpers";
2
3
  import { Traverser } from "../core/traverser";
3
4
  import { Scope, ScopeManager } from "./scope";
4
5
  export class TypeAnalyzer {
@@ -55,7 +56,8 @@ export class TypeAnalyzer {
55
56
  const varDecl = forIn.initializer.declarations[0];
56
57
  if (varDecl) {
57
58
  const name = varDecl.name.getText();
58
- const isConst = (varDecl.parent.flags & ts.NodeFlags.Const) !== 0;
59
+ const isConst = (varDecl.parent.flags & ts.NodeFlags.Const) !==
60
+ 0;
59
61
  const typeInfo = {
60
62
  type: "string", // Keys are always strings
61
63
  declaration: varDecl,
@@ -186,9 +188,8 @@ export class TypeAnalyzer {
186
188
  Identifier: {
187
189
  enter: (node, parent) => {
188
190
  if (ts.isIdentifier(node)) {
189
- if (node.text === "console") {
191
+ if (isBuiltinObject.call(this, node))
190
192
  return;
191
- }
192
193
  const currentFuncNode = this.functionStack[this.functionStack.length - 1];
193
194
  if (currentFuncNode &&
194
195
  (ts.isFunctionDeclaration(currentFuncNode) ||
package/dist/cli.js CHANGED
@@ -16,20 +16,22 @@ async function main() {
16
16
  try {
17
17
  const jsCode = await fs.readFile(jsFilePath, "utf-8");
18
18
  const interpreter = new Interpreter();
19
+ console.time(`Generated C++ code ${cppFilePath}...`);
19
20
  const { cppCode, preludePath } = interpreter.interpret(jsCode);
21
+ console.timeEnd(`Generated C++ code ${cppFilePath}...`);
20
22
  await fs.mkdir(outputDir, { recursive: true });
21
23
  await fs.writeFile(cppFilePath, cppCode);
22
24
  console.log(`Compiling ${cppFilePath}...`);
23
25
  const compile = Bun.spawnSync({
24
26
  cmd: [
25
27
  "g++",
26
- "-std=c++20",
28
+ "-std=c++23",
27
29
  cppFilePath,
28
30
  "-o",
29
31
  exeFilePath,
30
32
  "-I",
31
33
  preludePath,
32
- "-O2",
34
+ "-O3",
33
35
  "-DNDEBUG",
34
36
  // "-include",
35
37
  // path.join(process.cwd(), "prelude-build", "index.hpp"),
@@ -38,7 +40,7 @@ async function main() {
38
40
  stderr: "inherit",
39
41
  });
40
42
  if (compile.exitCode !== 0) {
41
- console.error(`Compilation failed for ${jsFileName}.js`);
43
+ console.error(`Compilation failed for ${cppFilePath}`);
42
44
  process.exit(1);
43
45
  }
44
46
  console.log(`Running ${exeFilePath}...`);
@@ -50,10 +52,10 @@ async function main() {
50
52
  });
51
53
  console.log("\x1b[32m\n------end--------\x1b[0m");
52
54
  if (run.exitCode !== 0) {
53
- console.error(`Execution failed for ${jsFileName}.js`);
55
+ console.error(`Execution failed for ${exeFilePath}`);
54
56
  process.exit(1);
55
57
  }
56
- console.log(`Successfully ran ${jsFileName}.js`);
58
+ console.log(`Successfully ran ${exeFilePath}`);
57
59
  }
58
60
  catch (error) {
59
61
  console.error(`Error: ${error.message}`);
@@ -1,7 +1,10 @@
1
1
  import ts from "typescript";
2
2
  import { CodeGenerator } from "./";
3
3
  function visitObjectPropertyName(node, context) {
4
- if (ts.isStringLiteral(node)) {
4
+ if (ts.isNumericLiteral(node)) {
5
+ return node.getText();
6
+ }
7
+ else if (ts.isStringLiteral(node)) {
5
8
  return `"${node.getText().substring(1, node.getText().length - 1) // remove trailing "' from original name
6
9
  }"`;
7
10
  }
@@ -12,9 +15,12 @@ function visitObjectPropertyName(node, context) {
12
15
  name += ".to_std_string()";
13
16
  return name;
14
17
  }
15
- return context.isPropertyNameAccess
16
- ? node.getText()
17
- : `"${node.getText()}"`;
18
+ else if (context.isPropertyNameAccess) {
19
+ return this.visit(node, context);
20
+ }
21
+ else {
22
+ return `"${node.getText()}"`;
23
+ }
18
24
  }
19
25
  export function visitObjectLiteralExpression(node, context) {
20
26
  const obj = node;
@@ -86,7 +92,6 @@ export function visitPropertyAccessExpression(node, context) {
86
92
  finalExpr = exprText;
87
93
  }
88
94
  return `${finalExpr}.get_own_property("${propName}")`;
89
- // return `${finalExpr}["${propName}"]`;
90
95
  }
91
96
  export function visitElementAccessExpression(node, context) {
92
97
  const elemAccess = node;
@@ -116,7 +121,6 @@ export function visitElementAccessExpression(node, context) {
116
121
  }
117
122
  }
118
123
  return `${finalExpr}.get_own_property(${argText})`;
119
- // return `${finalExpr}[${argText}]`;
120
124
  }
121
125
  export function visitBinaryExpression(node, context) {
122
126
  const binExpr = node;
@@ -3,7 +3,14 @@ import { CodeGenerator } from "./";
3
3
  export function generateLambda(node, isAssignment = false, capture = "[=]") {
4
4
  const declaredSymbols = this.getDeclaredSymbols(node);
5
5
  const argsName = this.generateUniqueName("__args_", declaredSymbols);
6
- let lambda = `${capture}(const std::vector<jspp::AnyValue>& ${argsName}) mutable -> jspp::AnyValue `;
6
+ const isInsideGeneratorFunction = this.isGeneratorFunction(node);
7
+ const returnCmd = this.getReturnCmd({
8
+ isInsideGeneratorFunction: isInsideGeneratorFunction,
9
+ });
10
+ const funcReturnType = isInsideGeneratorFunction
11
+ ? "jspp::JsIterator<jspp::AnyValue>"
12
+ : "jspp::AnyValue";
13
+ let lambda = `${capture}(const std::vector<jspp::AnyValue>& ${argsName}) mutable -> ${funcReturnType} `;
7
14
  const visitContext = {
8
15
  isMainContext: false,
9
16
  isInsideFunction: true,
@@ -26,6 +33,7 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
26
33
  isMainContext: false,
27
34
  isInsideFunction: true,
28
35
  isFunctionBody: true,
36
+ isInsideGeneratorFunction: isInsideGeneratorFunction,
29
37
  });
30
38
  // The block visitor already adds braces, so we need to inject the param extraction.
31
39
  lambda += "{\n" + paramExtraction + blockContent.substring(2);
@@ -41,7 +49,7 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
41
49
  lambda +=
42
50
  `${this.indent()}auto ${name} = ${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue};\n`;
43
51
  });
44
- lambda += `${this.indent()}return ${this.visit(node.body, {
52
+ lambda += `${this.indent()}${returnCmd} ${this.visit(node.body, {
45
53
  isMainContext: false,
46
54
  isInsideFunction: true,
47
55
  isFunctionBody: false,
@@ -52,12 +60,25 @@ export function generateLambda(node, isAssignment = false, capture = "[=]") {
52
60
  }
53
61
  }
54
62
  else {
55
- lambda += "{ return jspp::AnyValue::make_undefined(); }\n";
63
+ lambda += `{ ${returnCmd} jspp::AnyValue::make_undefined(); }\n`;
64
+ }
65
+ let signature = "";
66
+ let callable = "";
67
+ let method = "";
68
+ // Handle generator function
69
+ if (isInsideGeneratorFunction) {
70
+ signature =
71
+ "jspp::JsIterator<jspp::AnyValue>(const std::vector<jspp::AnyValue>&)";
72
+ callable = `std::function<${signature}>(${lambda})`;
73
+ method = `jspp::AnyValue::make_function`;
74
+ } // Handle normal function
75
+ else {
76
+ signature = `jspp::AnyValue(const std::vector<jspp::AnyValue>&)`;
77
+ callable = `std::function<${signature}>(${lambda})`;
78
+ method = `jspp::AnyValue::make_function`;
56
79
  }
57
- const signature = `jspp::AnyValue(const std::vector<jspp::AnyValue>&)`;
58
- const callable = `std::function<${signature}>(${lambda})`;
59
80
  const funcName = node.name?.getText();
60
- const fullExpression = `jspp::AnyValue::make_function(${callable}, "${funcName || ""}")`;
81
+ const fullExpression = `${method}(${callable}, "${funcName || ""}")`;
61
82
  if (ts.isFunctionDeclaration(node) && !isAssignment && funcName) {
62
83
  return `${this.indent()}auto ${funcName} = ${fullExpression};\n`;
63
84
  }
@@ -1,14 +1,8 @@
1
1
  import ts from "typescript";
2
- import { Scope } from "../../analysis/scope";
2
+ import { BUILTIN_OBJECTS, Scope } from "../../analysis/scope";
3
3
  import { CodeGenerator } from "./";
4
- const BUILTIN_OBJECTS = new Set([
5
- "global",
6
- "globalThis",
7
- "console",
8
- "Symbol",
9
- ]);
10
4
  export function isBuiltinObject(node) {
11
- return BUILTIN_OBJECTS.has(node.text);
5
+ return BUILTIN_OBJECTS.values().some((obj) => obj.name === node.text);
12
6
  }
13
7
  export function getDeclaredSymbols(node) {
14
8
  const symbols = new Set();
@@ -81,3 +75,13 @@ export function escapeString(str) {
81
75
  export function getJsVarName(node) {
82
76
  return `"${node.text}"`;
83
77
  }
78
+ export function getReturnCmd(context) {
79
+ return context.isInsideGeneratorFunction ? "co_return" : "return";
80
+ }
81
+ export function isGeneratorFunction(node) {
82
+ return ((ts.isFunctionDeclaration(node) ||
83
+ ts.isFunctionExpression(node) ||
84
+ ts.isMethodDeclaration(node)) &&
85
+ !!node.asteriskToken // generator indicator
86
+ );
87
+ }
@@ -1,6 +1,6 @@
1
1
  import { TypeAnalyzer } from "../../analysis/typeAnalyzer";
2
2
  import { generateLambda } from "./function-handlers";
3
- import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getJsVarName, getScopeForNode, indent, isBuiltinObject, } from "./helpers";
3
+ import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getJsVarName, getReturnCmd, getScopeForNode, indent, isBuiltinObject, isGeneratorFunction, } from "./helpers";
4
4
  import { visit } from "./visitor";
5
5
  const CONTAINER_FUNCTION_NAME = "__container__";
6
6
  export class CodeGenerator {
@@ -17,7 +17,9 @@ export class CodeGenerator {
17
17
  indent = indent;
18
18
  escapeString = escapeString;
19
19
  getJsVarName = getJsVarName;
20
+ getReturnCmd = getReturnCmd;
20
21
  isBuiltinObject = isBuiltinObject;
22
+ isGeneratorFunction = isGeneratorFunction;
21
23
  // function handlers
22
24
  generateLambda = generateLambda;
23
25
  /**
@@ -130,8 +130,7 @@ export function visitBlock(node, context) {
130
130
  if (context.isFunctionBody) {
131
131
  const lastStatement = block.statements[block.statements.length - 1];
132
132
  if (!lastStatement || !ts.isReturnStatement(lastStatement)) {
133
- code +=
134
- `${this.indent()}return jspp::AnyValue::make_undefined();\n`;
133
+ code += `${this.indent()}${this.getReturnCmd(context)} jspp::AnyValue::make_undefined();\n`;
135
134
  }
136
135
  }
137
136
  this.indentationLevel--;
@@ -250,32 +249,49 @@ export function visitForOfStatement(node, context) {
250
249
  varName = decl.name.getText();
251
250
  // Declare the shared_ptr before the loop
252
251
  code +=
253
- `${this.indent()}auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
252
+ `${this.indent()}{ auto ${varName} = std::make_shared<jspp::AnyValue>(jspp::AnyValue::make_undefined());\n`;
254
253
  }
255
254
  }
256
255
  else if (ts.isIdentifier(forOf.initializer)) {
257
256
  varName = forOf.initializer.getText();
258
257
  // Assume it's already declared in an outer scope, just assign to it.
259
258
  // No explicit declaration here.
259
+ code += `${this.indent()}{\n`;
260
260
  }
261
261
  const iterableExpr = this.visit(forOf.expression, context);
262
- const derefIterable = `jspp::Access::deref(${iterableExpr}, ${this.getJsVarName(forOf.expression)})`;
263
- const arrayPtr = this.generateUniqueName("__array_ptr_", new Set());
262
+ const derefIterable = ts.isIdentifier(forOf.expression)
263
+ ? `jspp::Access::deref(${iterableExpr}, ${this.getJsVarName(forOf.expression)})`
264
+ : iterableExpr;
265
+ const iteratorFn = this.generateUniqueName("__iter_fn_", new Set());
266
+ const iteratorPtr = this.generateUniqueName("__iter_ptr_", new Set());
267
+ const nextRes = this.generateUniqueName("__res__", new Set());
264
268
  code +=
265
- `${this.indent()}{ auto ${arrayPtr} = std::any_cast<std::shared_ptr<jspp::JsArray>>(${derefIterable});\n`;
269
+ `${this.indent()}auto ${iteratorFn} = ${derefIterable}.get_own_property(Symbol.get_own_property("iterator"));\n`;
266
270
  code +=
267
- `${this.indent()}for (const auto& ${varName}_val : ${arrayPtr}->items) {\n`;
271
+ `${this.indent()}if (!${iteratorFn}.is_generator()) { throw jspp::RuntimeError::make_error("${iterableExpr} is not iterable", "TypeError"); }\n`;
272
+ code +=
273
+ `${this.indent()}auto ${iteratorPtr} = ${iteratorFn}.as_function()->call({}).as_iterator();\n`;
274
+ code += `${this.indent()}auto ${nextRes} = ${iteratorPtr}->next();\n`;
275
+ code += `${this.indent()}while (!${nextRes}.done) {\n`;
268
276
  this.indentationLevel++;
269
- code += `${this.indent()}*${varName} = ${varName}_val;\n`;
277
+ code +=
278
+ `${this.indent()}*${varName} = ${nextRes}.value.value_or(jspp::AnyValue::make_undefined());\n`;
270
279
  code += this.visit(forOf.statement, {
271
280
  ...context,
272
281
  isFunctionBody: false,
273
282
  });
283
+ code += `${this.indent()}${nextRes} = ${iteratorPtr}->next();\n`;
274
284
  this.indentationLevel--;
275
285
  code += `${this.indent()}}}\n`;
276
286
  this.indentationLevel--; // Exit the scope for the for-of loop
277
287
  return code;
278
288
  }
289
+ export function visitBreakStatement(node, context) {
290
+ return "break;";
291
+ }
292
+ export function visitContinueStatement(node, context) {
293
+ return "continue;";
294
+ }
279
295
  export function visitIfStatement(node, context) {
280
296
  const ifStmt = node;
281
297
  const condition = this.visit(ifStmt.expression, context);
@@ -355,7 +371,7 @@ export function visitTryStatement(node, context) {
355
371
  else {
356
372
  code += `${this.indent()}catch (...) { throw; }\n`;
357
373
  }
358
- code += `${this.indent()}return jspp::AnyValue::make_undefined();\n`;
374
+ code += `${this.indent()}${this.getReturnCmd(context)} jspp::AnyValue::make_undefined();\n`;
359
375
  this.indentationLevel--;
360
376
  code += `${this.indent()}})();\n`;
361
377
  this.indentationLevel--;
@@ -427,11 +443,32 @@ export function visitCatchClause(node, context) {
427
443
  return code;
428
444
  }
429
445
  }
446
+ export function visitYieldExpression(node, context) {
447
+ if (node.expression) {
448
+ const expr = node.expression;
449
+ const exprText = this.visit(expr, context);
450
+ if (ts.isIdentifier(expr)) {
451
+ const scope = this.getScopeForNode(expr);
452
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(expr.text, scope);
453
+ if (!typeInfo) {
454
+ return `${this.indent()}jspp::RuntimeError::throw_unresolved_reference_error(${this.getJsVarName(expr)})\n`; // THROWS, not returns
455
+ }
456
+ if (typeInfo &&
457
+ !typeInfo.isParameter &&
458
+ !typeInfo.isBuiltin) {
459
+ return `${this.indent()}co_yield jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)})`;
460
+ }
461
+ }
462
+ return `${this.indent()}co_yield ${exprText}`;
463
+ }
464
+ return `${this.indent()}co_yield jspp::AnyValue::make_undefined()`;
465
+ }
430
466
  export function visitReturnStatement(node, context) {
431
467
  if (context.isMainContext) {
432
468
  return `${this.indent()}jspp::RuntimeError::throw_invalid_return_statement_error();\n`;
433
469
  }
434
470
  const returnStmt = node;
471
+ const returnCmd = this.getReturnCmd(context);
435
472
  if (context.isInsideTryCatchLambda && context.hasReturnedFlag) {
436
473
  let returnCode = `${this.indent()}${context.hasReturnedFlag} = true;\n`;
437
474
  if (returnStmt.expression) {
@@ -448,19 +485,19 @@ export function visitReturnStatement(node, context) {
448
485
  !typeInfo.isParameter &&
449
486
  !typeInfo.isBuiltin) {
450
487
  returnCode +=
451
- `${this.indent()}return jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)});\n`;
488
+ `${this.indent()}${returnCmd} jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)});\n`;
452
489
  }
453
490
  else {
454
- returnCode += `${this.indent()}return ${exprText};\n`;
491
+ returnCode += `${this.indent()}${returnCmd} ${exprText};\n`;
455
492
  }
456
493
  }
457
494
  else {
458
- returnCode += `${this.indent()}return ${exprText};\n`;
495
+ returnCode += `${this.indent()}${returnCmd} ${exprText};\n`;
459
496
  }
460
497
  }
461
498
  else {
462
499
  returnCode +=
463
- `${this.indent()}return jspp::AnyValue::make_undefined();\n`;
500
+ `${this.indent()}${returnCmd} jspp::AnyValue::make_undefined();\n`;
464
501
  }
465
502
  return returnCode;
466
503
  }
@@ -476,10 +513,10 @@ export function visitReturnStatement(node, context) {
476
513
  if (typeInfo &&
477
514
  !typeInfo.isParameter &&
478
515
  !typeInfo.isBuiltin) {
479
- return `${this.indent()}return jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)});\n`;
516
+ return `${this.indent()}${returnCmd} jspp::Access::deref(${exprText}, ${this.getJsVarName(expr)});\n`;
480
517
  }
481
518
  }
482
- return `${this.indent()}return ${exprText};\n`;
519
+ return `${this.indent()}${returnCmd} ${exprText};\n`;
483
520
  }
484
- return `${this.indent()}return jspp::AnyValue::make_undefined();\n`;
521
+ return `${this.indent()}${returnCmd} jspp::AnyValue::make_undefined();\n`;
485
522
  }
@@ -4,7 +4,7 @@ import { visitVariableDeclaration, visitVariableDeclarationList, } from "./decla
4
4
  import { visitArrayLiteralExpression, visitBinaryExpression, visitCallExpression, visitElementAccessExpression, visitObjectLiteralExpression, visitParenthesizedExpression, visitPostfixUnaryExpression, visitPrefixUnaryExpression, visitPropertyAccessExpression, visitTemplateExpression, visitVoidExpression, } from "./expression-handlers";
5
5
  import { visitArrowFunction, visitFunctionDeclaration, visitFunctionExpression, } from "./function-handlers";
6
6
  import { visitFalseKeyword, visitIdentifier, visitNoSubstitutionTemplateLiteral, visitNullKeyword, visitNumericLiteral, visitStringLiteral, visitTrueKeyword, visitUndefinedKeyword, } from "./literal-handlers";
7
- import { visitBlock, visitCatchClause, visitExpressionStatement, visitForInStatement, visitForOfStatement, visitForStatement, visitIfStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, } from "./statement-handlers";
7
+ import { visitBlock, visitBreakStatement, visitCatchClause, visitContinueStatement, visitExpressionStatement, visitForInStatement, visitForOfStatement, visitForStatement, visitIfStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, visitYieldExpression, } from "./statement-handlers";
8
8
  export function visit(node, context) {
9
9
  if (ts.isFunctionDeclaration(node)) {
10
10
  return visitFunctionDeclaration.call(this, node, context);
@@ -34,6 +34,10 @@ export function visit(node, context) {
34
34
  return visitForInStatement.call(this, node, context);
35
35
  case ts.SyntaxKind.ForOfStatement:
36
36
  return visitForOfStatement.call(this, node, context);
37
+ case ts.SyntaxKind.BreakStatement:
38
+ return visitBreakStatement.call(this, node, context);
39
+ case ts.SyntaxKind.ContinueStatement:
40
+ return visitContinueStatement.call(this, node, context);
37
41
  case ts.SyntaxKind.IfStatement:
38
42
  return visitIfStatement.call(this, node, context);
39
43
  case ts.SyntaxKind.PrefixUnaryExpression:
@@ -58,6 +62,8 @@ export function visit(node, context) {
58
62
  return visitCatchClause.call(this, node, context);
59
63
  case ts.SyntaxKind.CallExpression:
60
64
  return visitCallExpression.call(this, node, context);
65
+ case ts.SyntaxKind.YieldExpression:
66
+ return visitYieldExpression.call(this, node, context);
61
67
  case ts.SyntaxKind.ReturnStatement:
62
68
  return visitReturnStatement.call(this, node, context);
63
69
  case ts.SyntaxKind.Identifier:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ugo-studio/jspp",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A modern, experimental transpiler that converts JavaScript code into high-performance, standard C++23.",
5
5
  "main": "dist/index.js",
6
6
  "module": "src/index.ts",
@@ -19,7 +19,7 @@
19
19
  "test": "bun run precompile && bun test",
20
20
  "build": "tsc",
21
21
  "prepack": "bun run build",
22
- "publish-package": "npm publish --access=public"
22
+ "publish:npm": "npm publish --access=public"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/bun": "latest"
@@ -1,8 +1,11 @@
1
1
  #pragma once
2
2
 
3
3
  #include "types.hpp"
4
+ #include "well_known_symbols.hpp"
4
5
  #include "values/function.hpp"
6
+ #include "values/symbol.hpp"
5
7
  #include "error.hpp"
8
+ #include "any_value.hpp"
6
9
  #include <ranges>
7
10
 
8
11
  namespace jspp
@@ -52,7 +55,8 @@ namespace jspp
52
55
  auto ptr = obj.as_object();
53
56
  for (const auto &pair : ptr->props)
54
57
  {
55
- keys.push_back(pair.first);
58
+ if (!JsSymbol::is_internal_key(pair.first))
59
+ keys.push_back(pair.first);
56
60
  }
57
61
  }
58
62
  if (obj.is_function())
@@ -60,7 +64,8 @@ namespace jspp
60
64
  auto ptr = obj.as_function();
61
65
  for (const auto &pair : ptr->props)
62
66
  {
63
- keys.push_back(pair.first);
67
+ if (!JsSymbol::is_internal_key(pair.first))
68
+ keys.push_back(pair.first);
64
69
  }
65
70
  }
66
71
  if (obj.is_array())
@@ -73,7 +78,7 @@ namespace jspp
73
78
  }
74
79
  if (obj.is_string())
75
80
  {
76
- auto len = obj.as_string()->length();
81
+ auto len = obj.as_string()->value.length();
77
82
  for (auto i = 0; i < len; ++i)
78
83
  {
79
84
  keys.push_back(std::to_string(i));