@ugo-studio/jspp 0.2.6 → 0.2.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.
Files changed (42) hide show
  1. package/dist/analysis/typeAnalyzer.js +56 -24
  2. package/dist/ast/symbols.js +28 -19
  3. package/dist/cli/index.js +1 -1
  4. package/dist/core/codegen/class-handlers.js +8 -8
  5. package/dist/core/codegen/control-flow-handlers.js +17 -7
  6. package/dist/core/codegen/declaration-handlers.js +21 -9
  7. package/dist/core/codegen/expression-handlers.js +558 -126
  8. package/dist/core/codegen/function-handlers.js +101 -108
  9. package/dist/core/codegen/helpers.js +28 -7
  10. package/dist/core/codegen/index.js +6 -4
  11. package/dist/core/codegen/literal-handlers.js +4 -2
  12. package/dist/core/codegen/statement-handlers.js +39 -19
  13. package/package.json +1 -1
  14. package/src/prelude/any_value.hpp +89 -59
  15. package/src/prelude/any_value_access.hpp +1 -1
  16. package/src/prelude/any_value_helpers.hpp +85 -43
  17. package/src/prelude/index.hpp +1 -0
  18. package/src/prelude/library/array.hpp +3 -2
  19. package/src/prelude/types.hpp +8 -8
  20. package/src/prelude/utils/access.hpp +62 -6
  21. package/src/prelude/utils/assignment_operators.hpp +14 -14
  22. package/src/prelude/utils/log_any_value/array.hpp +0 -15
  23. package/src/prelude/utils/log_any_value/primitives.hpp +2 -0
  24. package/src/prelude/utils/operators.hpp +117 -474
  25. package/src/prelude/utils/operators_primitive.hpp +337 -0
  26. package/src/prelude/values/helpers/array.hpp +4 -4
  27. package/src/prelude/values/helpers/async_iterator.hpp +2 -2
  28. package/src/prelude/values/helpers/function.hpp +3 -3
  29. package/src/prelude/values/helpers/iterator.hpp +2 -2
  30. package/src/prelude/values/helpers/object.hpp +3 -3
  31. package/src/prelude/values/helpers/promise.hpp +1 -1
  32. package/src/prelude/values/helpers/string.hpp +1 -1
  33. package/src/prelude/values/helpers/symbol.hpp +1 -1
  34. package/src/prelude/values/prototypes/array.hpp +1125 -853
  35. package/src/prelude/values/prototypes/async_iterator.hpp +32 -14
  36. package/src/prelude/values/prototypes/function.hpp +30 -18
  37. package/src/prelude/values/prototypes/iterator.hpp +40 -17
  38. package/src/prelude/values/prototypes/number.hpp +119 -62
  39. package/src/prelude/values/prototypes/object.hpp +10 -4
  40. package/src/prelude/values/prototypes/promise.hpp +167 -109
  41. package/src/prelude/values/prototypes/string.hpp +407 -231
  42. package/src/prelude/values/prototypes/symbol.hpp +45 -23
@@ -1,16 +1,14 @@
1
1
  import ts from "typescript";
2
2
  import { DeclarationType, DeclaredSymbols } from "../../ast/symbols.js";
3
- import { CompilerError } from "../error.js";
4
3
  import { collectFunctionScopedDeclarations } from "./helpers.js";
5
4
  import { CodeGenerator } from "./index.js";
6
- export function generateLambda(node, context, options) {
7
- const capture = options?.capture || "[=]";
8
- const nativeName = options?.nativeName;
5
+ export function generateLambdaComponents(node, context, options) {
9
6
  const declaredSymbols = this.getDeclaredSymbols(node);
10
7
  const argsName = this.generateUniqueName("__args_", declaredSymbols, context.globalScopeSymbols, context.localScopeSymbols);
11
8
  const isInsideGeneratorFunction = this.isGeneratorFunction(node);
12
9
  const isInsideAsyncFunction = this.isAsyncFunction(node);
13
- const returnCmd = this.getReturnCommand({
10
+ const isArrow = ts.isArrowFunction(node);
11
+ const returnCommand = this.getReturnCommand({
14
12
  isInsideGeneratorFunction: isInsideGeneratorFunction,
15
13
  isInsideAsyncFunction: isInsideAsyncFunction,
16
14
  });
@@ -19,17 +17,10 @@ export function generateLambda(node, context, options) {
19
17
  : (isInsideGeneratorFunction
20
18
  ? "jspp::JsIterator<jspp::AnyValue>"
21
19
  : (isInsideAsyncFunction ? "jspp::JsPromise" : "jspp::AnyValue"));
22
- const isArrow = ts.isArrowFunction(node);
23
20
  // Lambda arguments are ALWAYS const references/spans to avoid copy overhead for normal functions.
24
21
  // For generators/async, we manually copy them inside the body.
25
22
  const paramThisType = "const jspp::AnyValue&";
26
23
  const paramArgsType = "std::span<const jspp::AnyValue>";
27
- const selfParamPart = nativeName ? `this auto&& ${nativeName}, ` : "";
28
- const mutablePart = nativeName ? "" : "mutable ";
29
- const thisArgParam = isArrow
30
- ? "const jspp::AnyValue&" // Arrow functions use captured 'this' or are never generators in this parser context
31
- : `${paramThisType} ${this.globalThisVar}`;
32
- let lambda = `${capture}(${selfParamPart}${thisArgParam}, ${paramArgsType} ${argsName}) ${mutablePart}-> ${funcReturnType} `;
33
24
  const globalScopeSymbols = this.prepareScopeSymbolsForVisit(context.globalScopeSymbols, context.localScopeSymbols);
34
25
  const visitContext = {
35
26
  currentScopeNode: context.currentScopeNode,
@@ -43,18 +34,6 @@ export function generateLambda(node, context, options) {
43
34
  isInsideGeneratorFunction: isInsideGeneratorFunction,
44
35
  isInsideAsyncFunction: isInsideAsyncFunction,
45
36
  };
46
- // Preamble to copy arguments for coroutines
47
- let preamble = "";
48
- if (isInsideGeneratorFunction || isInsideAsyncFunction) {
49
- const thisCopy = this.generateUniqueName("__this_copy", declaredSymbols);
50
- const argsCopy = this.generateUniqueName("__args_copy", declaredSymbols);
51
- if (!isArrow) {
52
- preamble +=
53
- `${this.indent()}jspp::AnyValue ${thisCopy} = ${this.globalThisVar};\n`;
54
- }
55
- preamble +=
56
- `${this.indent()}std::vector<jspp::AnyValue> ${argsCopy}(${argsName}.begin(), ${argsName}.end());\n`;
57
- }
58
37
  // Adjust parameter names for generator/async to allow shadowing/copying
59
38
  let finalThisParamName = isArrow ? "" : this.globalThisVar;
60
39
  let finalArgsParamName = argsName;
@@ -64,37 +43,44 @@ export function generateLambda(node, context, options) {
64
43
  }
65
44
  finalArgsParamName = this.generateUniqueName("__args_ref", declaredSymbols);
66
45
  }
67
- const thisArgParamFinal = isArrow
68
- ? "const jspp::AnyValue&"
46
+ const thisArgParam = isArrow
47
+ ? "const jspp::AnyValue&" // Arrow functions use captured 'this' or are never generators in this parser context
69
48
  : `${paramThisType} ${finalThisParamName}`;
70
- // Re-construct lambda header with potentially new param names
71
- lambda =
72
- `${capture}(${selfParamPart}${thisArgParamFinal}, ${paramArgsType} ${finalArgsParamName}) ${mutablePart}-> ${funcReturnType} `;
73
- // Regenerate preamble
74
- preamble = "";
49
+ const funcArgs = `${paramArgsType} ${finalArgsParamName}`;
50
+ // Preamble to copy arguments for coroutines
51
+ let preamble = "";
52
+ let nativePreamble = "";
75
53
  if (isInsideGeneratorFunction || isInsideAsyncFunction) {
76
54
  if (!isArrow) {
77
55
  preamble +=
78
56
  `${this.indent()}jspp::AnyValue ${this.globalThisVar} = ${finalThisParamName};\n`;
57
+ nativePreamble +=
58
+ `${this.indent()}jspp::AnyValue ${this.globalThisVar} = ${finalThisParamName};\n`;
79
59
  }
60
+ // Note: Do not add argument copy to native lambda
80
61
  preamble +=
81
62
  `${this.indent()}std::vector<jspp::AnyValue> ${argsName}(${finalArgsParamName}.begin(), ${finalArgsParamName}.end());\n`;
82
63
  }
83
- // Now 'argsName' refers to the vector (if copied) or the span (if not).
84
- // And 'this.globalThisVar' refers to the copy (if copied) or the param (if not).
85
- // So subsequent code using `argsName` and `visit` (using `globalThisVar`) works correctly.
86
- const paramExtractor = (parameters) => {
87
- let code = "";
88
- parameters.filter((p) => this.isTypescript && p.name.getText() === "this" ? false : true // Ignore "this" parameters
89
- ).forEach((p, i) => {
64
+ // Native function arguments for native lambda
65
+ let nativeFuncArgs = "";
66
+ let nativeParamsContent = "";
67
+ this.validateFunctionParams(node.parameters).forEach((p, i) => {
68
+ const name = p.name.getText();
69
+ const defaultValue = p.initializer
70
+ ? this.visit(p.initializer, visitContext)
71
+ : !!p.dotDotDotToken
72
+ ? "jspp::AnyValue::make_array(std::vector<jspp::AnyValue>{})"
73
+ : "jspp::Constants::UNDEFINED";
74
+ nativeFuncArgs += `, const jspp::AnyValue& ${name} = ${defaultValue}`;
75
+ });
76
+ // Extract lambda parameters from arguments span/vector
77
+ const generateParamsBuilder = () => {
78
+ let paramsCode = "";
79
+ this.validateFunctionParams(node.parameters).forEach((p, i) => {
90
80
  const name = p.name.getText();
91
81
  const defaultValue = p.initializer
92
82
  ? this.visit(p.initializer, visitContext)
93
83
  : "jspp::Constants::UNDEFINED";
94
- // Catch invalid parameters
95
- if (name === "this") {
96
- throw new CompilerError(`Cannot use '${name}' as a parameter name.`, p, "SyntaxError");
97
- }
98
84
  // Add paramerter to local context
99
85
  visitContext.localScopeSymbols.add(name, {
100
86
  type: DeclarationType.let,
@@ -104,108 +90,114 @@ export function generateLambda(node, context, options) {
104
90
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
105
91
  // Handle rest parameters
106
92
  if (!!p.dotDotDotToken) {
107
- if (parameters.length - 1 !== i) {
108
- throw new CompilerError("Rest parameter must be last formal parameter.", p, "SyntaxError");
109
- }
93
+ const initValue = `jspp::AnyValue::make_array(${argsName}.subspan(${i}))`;
110
94
  if (typeInfo.needsHeapAllocation) {
111
- code +=
112
- `${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(jspp::Constants::UNDEFINED);\n`;
95
+ paramsCode +=
96
+ `${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
113
97
  }
114
98
  else {
115
- code +=
116
- `${this.indent()}jspp::AnyValue ${name} = jspp::Constants::UNDEFINED;\n`;
99
+ paramsCode +=
100
+ `${this.indent()}jspp::AnyValue ${name} = ${initValue};\n`;
117
101
  }
118
- // Extract rest parameters
119
- const tempName = `temp_${name}`;
120
- code += `${this.indent()}{\n`;
121
- this.indentationLevel++;
122
- code +=
123
- `${this.indent()}std::vector<std::optional<jspp::AnyValue>> ${tempName};\n`;
124
- code += `${this.indent()}if (${argsName}.size() > ${i}) {\n`;
125
- this.indentationLevel++;
126
- code +=
127
- `${this.indent()}${tempName}.reserve(${argsName}.size() - ${i});\n`;
128
- this.indentationLevel--;
129
- code += `${this.indent()}}\n`;
130
- code +=
131
- `${this.indent()}for (size_t j = ${i}; j < ${argsName}.size(); j++) {\n`;
132
- this.indentationLevel++;
133
- code +=
134
- `${this.indent()}${tempName}.push_back(${argsName}[j]);\n`;
135
- this.indentationLevel--;
136
- code += `${this.indent()}}\n`;
137
- code += `${this.indent()}${typeInfo.needsHeapAllocation ? "*" : ""}${name} = jspp::AnyValue::make_array(std::move(${tempName}));\n`;
138
- this.indentationLevel--;
139
- code += `${this.indent()}}\n`;
140
102
  return;
141
103
  }
142
104
  // Normal parameter
143
105
  const initValue = `${argsName}.size() > ${i} ? ${argsName}[${i}] : ${defaultValue}`;
144
106
  if (typeInfo && typeInfo.needsHeapAllocation) {
145
- code +=
107
+ paramsCode +=
146
108
  `${this.indent()}auto ${name} = std::make_shared<jspp::AnyValue>(${initValue});\n`;
147
109
  }
148
110
  else {
149
- code +=
111
+ paramsCode +=
150
112
  `${this.indent()}jspp::AnyValue ${name} = ${initValue};\n`;
151
113
  }
152
114
  });
153
- return code;
115
+ return paramsCode;
154
116
  };
117
+ // Generate params and function body
118
+ let paramsContent = "";
119
+ let blockContentWithoutOpeningBrace = "";
155
120
  if (node.body) {
156
121
  if (ts.isBlock(node.body)) {
157
122
  // Hoist var declarations in the function body
158
123
  const varDecls = collectFunctionScopedDeclarations(node.body);
159
124
  varDecls.forEach((decl) => {
160
- preamble += this.hoistDeclaration(decl, visitContext.localScopeSymbols, node.body);
125
+ const hoistCode = this.hoistDeclaration(decl, visitContext.localScopeSymbols, node.body);
126
+ preamble += hoistCode;
127
+ nativePreamble += hoistCode;
161
128
  });
162
129
  this.indentationLevel++;
163
- const paramExtraction = paramExtractor(node.parameters);
130
+ paramsContent = generateParamsBuilder();
164
131
  this.indentationLevel--;
165
- const blockContent = this.visit(node.body, {
132
+ // The block visitor already adds braces, so we need to remove the opening brace to inject the preamble and param extraction.
133
+ blockContentWithoutOpeningBrace = this.visit(node.body, {
166
134
  ...visitContext,
167
135
  isMainContext: false,
168
136
  isInsideFunction: true,
169
137
  isFunctionBody: true,
170
138
  isInsideGeneratorFunction: isInsideGeneratorFunction,
171
139
  isInsideAsyncFunction: isInsideAsyncFunction,
172
- });
173
- // The block visitor already adds braces, so we need to inject the preamble and param extraction.
174
- lambda += "{\n" + preamble + paramExtraction +
175
- blockContent.trimStart().substring(2);
140
+ }).trimStart().substring(2);
176
141
  }
177
142
  else {
178
- lambda += "{\n";
179
143
  this.indentationLevel++;
180
- lambda += preamble;
181
- lambda += paramExtractor(node.parameters);
182
- lambda += `${this.indent()}${returnCmd} ${this.visit(node.body, {
183
- ...visitContext,
184
- isMainContext: false,
185
- isInsideFunction: true,
186
- isFunctionBody: false,
187
- isInsideGeneratorFunction: isInsideGeneratorFunction,
188
- isInsideAsyncFunction: isInsideAsyncFunction,
189
- })};\n`;
144
+ paramsContent = generateParamsBuilder();
145
+ blockContentWithoutOpeningBrace =
146
+ `${this.indent()}${returnCommand} ${this.visit(node.body, {
147
+ ...visitContext,
148
+ isMainContext: false,
149
+ isInsideFunction: true,
150
+ isFunctionBody: false,
151
+ isInsideGeneratorFunction: isInsideGeneratorFunction,
152
+ isInsideAsyncFunction: isInsideAsyncFunction,
153
+ })};\n`;
190
154
  this.indentationLevel--;
191
- lambda += `${this.indent()}}`;
155
+ blockContentWithoutOpeningBrace += `${this.indent()}}`;
192
156
  }
193
157
  }
194
158
  else {
195
- lambda += `{ ${preamble} ${returnCmd} jspp::Constants::UNDEFINED; }\n`;
196
- }
197
- // Return only lambda if required
198
- if (options?.generateOnlyLambda) {
199
- return lambda.trimEnd();
159
+ blockContentWithoutOpeningBrace =
160
+ `${returnCommand} jspp::Constants::UNDEFINED; }\n`;
200
161
  }
201
- return this.generateFullLambdaExpression(node, context, lambda, options);
162
+ return {
163
+ node,
164
+ context,
165
+ options,
166
+ visitContext,
167
+ thisArgParam,
168
+ funcArgs,
169
+ nativeFuncArgs,
170
+ funcReturnType,
171
+ preamble,
172
+ nativePreamble,
173
+ paramsContent,
174
+ nativeParamsContent,
175
+ blockContentWithoutOpeningBrace,
176
+ isInsideGeneratorFunction,
177
+ isInsideAsyncFunction,
178
+ };
202
179
  }
203
- export function generateFullLambdaExpression(node, context, lambda, options) {
180
+ export function generateNativeLambda(comps) {
181
+ const { options, thisArgParam, nativeFuncArgs, funcReturnType, nativePreamble, nativeParamsContent, blockContentWithoutOpeningBrace, } = comps;
182
+ const capture = options?.capture || "[=]";
183
+ const nativeName = options?.nativeName;
184
+ const selfParam = nativeName ? `this auto&& ${nativeName}, ` : "";
185
+ const mutableLabel = nativeName ? "" : "mutable ";
186
+ let lambda = `${capture}(${selfParam}${thisArgParam}${nativeFuncArgs}) ${mutableLabel}-> ${funcReturnType} {\n`;
187
+ lambda += nativePreamble;
188
+ lambda += nativeParamsContent;
189
+ lambda += blockContentWithoutOpeningBrace;
190
+ return lambda;
191
+ }
192
+ export function generateWrappedLambda(comps) {
193
+ const { node, context, options, thisArgParam, funcArgs, funcReturnType, preamble, paramsContent, blockContentWithoutOpeningBrace, isInsideGeneratorFunction, isInsideAsyncFunction, } = comps;
194
+ const capture = options?.capture || "[=]";
204
195
  const isAssignment = options?.isAssignment || false;
205
196
  const noTypeSignature = options?.noTypeSignature || false;
206
- const isInsideGeneratorFunction = this.isGeneratorFunction(node);
207
- const isInsideAsyncFunction = this.isAsyncFunction(node);
208
- const isArrow = ts.isArrowFunction(node);
197
+ let lambda = `${capture}(${thisArgParam}, ${funcArgs}) mutable -> ${funcReturnType} {\n`;
198
+ lambda += preamble;
199
+ lambda += paramsContent;
200
+ lambda += blockContentWithoutOpeningBrace;
209
201
  let callable = lambda;
210
202
  let method = "";
211
203
  // Handle generator function
@@ -247,6 +239,7 @@ export function generateFullLambdaExpression(node, context, lambda, options) {
247
239
  const funcName = context?.lambdaName || node.name?.getText();
248
240
  const hasName = !!funcName && funcName.length > 0;
249
241
  let args = callable;
242
+ const isArrow = ts.isArrowFunction(node);
250
243
  const isMethod = ts.isMethodDeclaration(node);
251
244
  const isAccessor = ts.isGetAccessor(node) || ts.isSetAccessor(node);
252
245
  const isConstructor = !isArrow && !isMethod && !isAccessor;
@@ -280,12 +273,12 @@ export function visitFunctionDeclaration(node, context) {
280
273
  // This will now be handled by the Block visitor for hoisting.
281
274
  // However, we still need to generate the lambda for assignment.
282
275
  // The block visitor will wrap this in an assignment.
283
- return this.generateLambda(node, context);
276
+ return this.generateWrappedLambda(this.generateLambdaComponents(node, context));
284
277
  }
285
278
  return "";
286
279
  }
287
280
  export function visitArrowFunction(node, context) {
288
- return this.generateLambda(node, context);
281
+ return this.generateWrappedLambda(this.generateLambdaComponents(node, context));
289
282
  }
290
283
  export function visitFunctionExpression(node, context) {
291
284
  const funcExpr = node;
@@ -295,18 +288,18 @@ export function visitFunctionExpression(node, context) {
295
288
  this.indentationLevel++;
296
289
  code +=
297
290
  `${this.indent()}auto ${funcName} = std::make_shared<jspp::AnyValue>();\n`;
298
- const lambda = this.generateLambda(funcExpr, {
291
+ const lambda = this.generateWrappedLambda(this.generateLambdaComponents(funcExpr, {
299
292
  ...context,
300
293
  lambdaName: funcName,
301
294
  }, {
302
295
  isAssignment: true,
303
296
  capture: "[=]",
304
- });
297
+ }));
305
298
  code += `${this.indent()}*${funcName} = ${lambda};\n`;
306
299
  code += `${this.indent()}return *${funcName};\n`;
307
300
  this.indentationLevel--;
308
301
  code += `${this.indent()}})()`;
309
302
  return code;
310
303
  }
311
- return this.generateLambda(node, context);
304
+ return this.generateWrappedLambda(this.generateLambdaComponents(node, context));
312
305
  }
@@ -167,7 +167,7 @@ export function hoistDeclaration(decl, hoistedSymbols, scopeNode) {
167
167
  const isGenerator = this.isGeneratorFunction(decl);
168
168
  hoistedSymbols.add(name, {
169
169
  type: declType,
170
- func: { isAsync, isGenerator },
170
+ features: { isAsync, isGenerator },
171
171
  });
172
172
  // Don't hoist functions not used as a variable
173
173
  // they will be called with their native lambdas
@@ -293,14 +293,14 @@ export function collectBlockScopedDeclarations(statements) {
293
293
  return decls;
294
294
  }
295
295
  export function isFunctionUsedAsValue(decl, root) {
296
- const funcName = decl.name?.getText();
297
- if (!funcName)
296
+ const name = decl.name?.getText();
297
+ if (!name)
298
298
  return false;
299
299
  let isUsed = false;
300
300
  const visitor = (node) => {
301
301
  if (isUsed)
302
302
  return;
303
- if (ts.isIdentifier(node) && node.text === funcName) {
303
+ if (ts.isIdentifier(node) && node.text === name) {
304
304
  const scope = this.getScopeForNode(node);
305
305
  const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(node.text, scope);
306
306
  if (typeInfo?.declaration === decl) {
@@ -336,14 +336,14 @@ export function isFunctionUsedAsValue(decl, root) {
336
336
  ts.forEachChild(root, visitor);
337
337
  return isUsed;
338
338
  }
339
- export function isFunctionUsedBeforeDeclaration(funcName, root) {
339
+ export function isFunctionUsedBeforeDeclaration(name, root) {
340
340
  let declPos = -1;
341
341
  let foundDecl = false;
342
342
  // Helper to find the function declaration position
343
343
  function findDecl(node) {
344
344
  if (foundDecl)
345
345
  return;
346
- if (ts.isFunctionDeclaration(node) && node.name?.text === funcName) {
346
+ if (ts.isFunctionDeclaration(node) && node.name?.text === name) {
347
347
  declPos = node.getStart();
348
348
  foundDecl = true;
349
349
  }
@@ -359,7 +359,7 @@ export function isFunctionUsedBeforeDeclaration(funcName, root) {
359
359
  function visit(node) {
360
360
  if (isUsedBefore)
361
361
  return;
362
- if (ts.isIdentifier(node) && node.text === funcName) {
362
+ if (ts.isIdentifier(node) && node.text === name) {
363
363
  const parent = node.parent;
364
364
  // Ignore declarations where the identifier is the name being declared
365
365
  if ((ts.isFunctionDeclaration(parent) ||
@@ -410,3 +410,24 @@ export function isFunctionUsedBeforeDeclaration(funcName, root) {
410
410
  visit(root);
411
411
  return isUsedBefore;
412
412
  }
413
+ export function validateFunctionParams(parameters) {
414
+ return parameters.filter((p) => {
415
+ if (p.name.getText() === "this") {
416
+ if (!this.isTypescript) {
417
+ // Throw error for "this" parameters in javascript files
418
+ throw new CompilerError('Cannot use "this" as a parameter name.', p, "SyntaxError");
419
+ }
420
+ else
421
+ return false; // Ignore "this" parameters in typescript files
422
+ }
423
+ else
424
+ return true;
425
+ }).map((p, i, parameters) => {
426
+ if (!!p.dotDotDotToken) {
427
+ if (parameters.length - 1 !== i) {
428
+ throw new CompilerError("Rest parameter must be last formal parameter.", p, "SyntaxError");
429
+ }
430
+ }
431
+ return p;
432
+ }) || [];
433
+ }
@@ -1,6 +1,6 @@
1
1
  import { DeclaredSymbols } from "../../ast/symbols.js";
2
- import { generateFullLambdaExpression, generateLambda, } from "./function-handlers.js";
3
- import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isFunctionUsedAsValue, isFunctionUsedBeforeDeclaration, isGeneratorFunction, markSymbolAsInitialized, prepareScopeSymbolsForVisit, } from "./helpers.js";
2
+ import { generateLambdaComponents, generateNativeLambda, generateWrappedLambda, } from "./function-handlers.js";
3
+ import { escapeString, generateUniqueExceptionName, generateUniqueName, getDeclaredSymbols, getDerefCode, getJsVarName, getReturnCommand, getScopeForNode, hoistDeclaration, indent, isAsyncFunction, isBuiltinObject, isFunctionUsedAsValue, isFunctionUsedBeforeDeclaration, isGeneratorFunction, markSymbolAsInitialized, prepareScopeSymbolsForVisit, validateFunctionParams, } from "./helpers.js";
4
4
  import { visit } from "./visitor.js";
5
5
  const MODULE_NAME = "__entry_point__";
6
6
  export class CodeGenerator {
@@ -29,9 +29,11 @@ export class CodeGenerator {
29
29
  markSymbolAsInitialized = markSymbolAsInitialized;
30
30
  isFunctionUsedAsValue = isFunctionUsedAsValue;
31
31
  isFunctionUsedBeforeDeclaration = isFunctionUsedBeforeDeclaration;
32
+ validateFunctionParams = validateFunctionParams;
32
33
  // function handlers
33
- generateLambda = generateLambda;
34
- generateFullLambdaExpression = generateFullLambdaExpression;
34
+ generateLambdaComponents = generateLambdaComponents;
35
+ generateNativeLambda = generateNativeLambda;
36
+ generateWrappedLambda = generateWrappedLambda;
35
37
  /**
36
38
  * Main entry point for the code generation process.
37
39
  */
@@ -11,9 +11,11 @@ export function visitIdentifier(node) {
11
11
  return node.text;
12
12
  }
13
13
  export function visitNumericLiteral(node) {
14
- if (node.text === "0")
14
+ if (node.text === "0" || (node.text.startsWith("0.") &&
15
+ !node.text.substring(2).split("").some((c) => c !== "0")))
15
16
  return "jspp::Constants::ZERO";
16
- if (node.text === "1")
17
+ if (node.text === "1" || (node.text.startsWith("1.") &&
18
+ !node.text.substring(2).split("").some((c) => c !== "0")))
17
19
  return "jspp::Constants::ONE";
18
20
  return `jspp::AnyValue::make_number(${this.escapeString(node.text)})`;
19
21
  }
@@ -52,21 +52,31 @@ export function visitSourceFile(node, context) {
52
52
  // Mark before further visits
53
53
  this.markSymbolAsInitialized(funcName, contextForFunctions.globalScopeSymbols, contextForFunctions.localScopeSymbols);
54
54
  this.markSymbolAsInitialized(funcName, globalScopeSymbols, localScopeSymbols);
55
- // Generate and update self name
55
+ // Update features in the symbol registry
56
56
  const nativeName = this.generateUniqueName(`__${funcName}_native_`, hoistedSymbols);
57
- hoistedSymbols.update(funcName, { func: { nativeName } });
58
- // Generate lambda
59
- const lambda = this.generateLambda(stmt, contextForFunctions, {
57
+ hoistedSymbols.update(funcName, {
58
+ features: {
59
+ native: {
60
+ type: "lambda",
61
+ name: nativeName,
62
+ parameters: this.validateFunctionParams(stmt.parameters),
63
+ },
64
+ },
65
+ });
66
+ // Generate lambda components
67
+ const lambdaComps = this.generateLambdaComponents(stmt, contextForFunctions, {
60
68
  isAssignment: true,
61
- generateOnlyLambda: true,
62
69
  nativeName,
70
+ noTypeSignature: true,
63
71
  });
64
- code += `${this.indent()}auto ${nativeName} = ${lambda};\n`;
65
- // Generate AnyValue wrapper
72
+ // Generate native lambda
73
+ const nativeLambda = this.generateNativeLambda(lambdaComps);
74
+ code += `${this.indent()}auto ${nativeName} = ${nativeLambda};\n`;
75
+ // Generate AnyValue wrapped lamda
66
76
  if (this.isFunctionUsedAsValue(stmt, node) ||
67
77
  this.isFunctionUsedBeforeDeclaration(funcName, node)) {
68
- const fullExpression = this.generateFullLambdaExpression(stmt, contextForFunctions, nativeName, { isAssignment: true, noTypeSignature: true });
69
- code += `${this.indent()}*${funcName} = ${fullExpression};\n`;
78
+ const wrappedLambda = this.generateWrappedLambda(lambdaComps);
79
+ code += `${this.indent()}*${funcName} = ${wrappedLambda};\n`;
70
80
  }
71
81
  });
72
82
  // 3. Process other statements
@@ -137,21 +147,31 @@ export function visitBlock(node, context) {
137
147
  // Mark before further visits
138
148
  this.markSymbolAsInitialized(funcName, contextForFunctions.globalScopeSymbols, contextForFunctions.localScopeSymbols);
139
149
  this.markSymbolAsInitialized(funcName, globalScopeSymbols, localScopeSymbols);
140
- // Generate and update self name
150
+ // Update features in the symbol registry
141
151
  const nativeName = this.generateUniqueName(`__${funcName}_native_`, hoistedSymbols);
142
- hoistedSymbols.update(funcName, { func: { nativeName } });
143
- // Generate lambda
144
- const lambda = this.generateLambda(stmt, contextForFunctions, {
152
+ hoistedSymbols.update(funcName, {
153
+ features: {
154
+ native: {
155
+ type: "lambda",
156
+ name: nativeName,
157
+ parameters: this.validateFunctionParams(stmt.parameters),
158
+ },
159
+ },
160
+ });
161
+ // Generate lambda components
162
+ const lambdaComps = this.generateLambdaComponents(stmt, contextForFunctions, {
145
163
  isAssignment: true,
146
- generateOnlyLambda: true,
147
164
  nativeName,
165
+ noTypeSignature: true,
148
166
  });
149
- code += `${this.indent()}auto ${nativeName} = ${lambda};\n`;
150
- // Generate AnyValue wrapper
167
+ // Generate native lambda
168
+ const nativeLambda = this.generateNativeLambda(lambdaComps);
169
+ code += `${this.indent()}auto ${nativeName} = ${nativeLambda};\n`;
170
+ // Generate AnyValue wrapped lamda
151
171
  if (this.isFunctionUsedAsValue(stmt, node) ||
152
172
  this.isFunctionUsedBeforeDeclaration(funcName, node)) {
153
- const fullExpression = this.generateFullLambdaExpression(stmt, contextForFunctions, nativeName, { isAssignment: true, noTypeSignature: true });
154
- code += `${this.indent()}*${funcName} = ${fullExpression};\n`;
173
+ const wrappedLambda = this.generateWrappedLambda(lambdaComps);
174
+ code += `${this.indent()}*${funcName} = ${wrappedLambda};\n`;
155
175
  }
156
176
  });
157
177
  // 3. Process other statements
@@ -242,7 +262,7 @@ export function visitEnumDeclaration(node, context) {
242
262
  }
243
263
  else {
244
264
  // Auto-increment
245
- valueCode = `lastVal + 1`;
265
+ valueCode = `jspp::add(lastVal, 1)`;
246
266
  }
247
267
  code += `${this.indent()}lastVal = ${valueCode};\n`;
248
268
  code +=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ugo-studio/jspp",
3
- "version": "0.2.6",
3
+ "version": "0.2.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",