@ugo-studio/jspp 0.2.5 → 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 (54) hide show
  1. package/README.md +51 -36
  2. package/dist/analysis/scope.js +7 -0
  3. package/dist/analysis/typeAnalyzer.js +96 -43
  4. package/dist/ast/symbols.js +34 -24
  5. package/dist/cli/args.js +59 -0
  6. package/dist/cli/colors.js +9 -0
  7. package/dist/cli/file-utils.js +20 -0
  8. package/dist/cli/index.js +160 -0
  9. package/dist/cli/spinner.js +55 -0
  10. package/dist/core/codegen/class-handlers.js +8 -8
  11. package/dist/core/codegen/control-flow-handlers.js +19 -9
  12. package/dist/core/codegen/declaration-handlers.js +30 -10
  13. package/dist/core/codegen/expression-handlers.js +649 -161
  14. package/dist/core/codegen/function-handlers.js +107 -103
  15. package/dist/core/codegen/helpers.js +61 -14
  16. package/dist/core/codegen/index.js +13 -9
  17. package/dist/core/codegen/literal-handlers.js +4 -2
  18. package/dist/core/codegen/statement-handlers.js +147 -55
  19. package/dist/core/codegen/visitor.js +22 -2
  20. package/dist/core/constants.js +16 -0
  21. package/dist/core/error.js +58 -0
  22. package/dist/index.js +6 -3
  23. package/package.json +3 -3
  24. package/src/prelude/any_value.hpp +89 -59
  25. package/src/prelude/any_value_access.hpp +1 -1
  26. package/src/prelude/any_value_helpers.hpp +85 -43
  27. package/src/prelude/index.hpp +1 -0
  28. package/src/prelude/library/array.hpp +3 -2
  29. package/src/prelude/scheduler.hpp +144 -144
  30. package/src/prelude/types.hpp +8 -8
  31. package/src/prelude/utils/access.hpp +62 -6
  32. package/src/prelude/utils/assignment_operators.hpp +14 -14
  33. package/src/prelude/utils/log_any_value/array.hpp +0 -15
  34. package/src/prelude/utils/log_any_value/object.hpp +12 -10
  35. package/src/prelude/utils/log_any_value/primitives.hpp +2 -0
  36. package/src/prelude/utils/operators.hpp +117 -474
  37. package/src/prelude/utils/operators_primitive.hpp +337 -0
  38. package/src/prelude/values/helpers/array.hpp +4 -4
  39. package/src/prelude/values/helpers/async_iterator.hpp +2 -2
  40. package/src/prelude/values/helpers/function.hpp +3 -3
  41. package/src/prelude/values/helpers/iterator.hpp +2 -2
  42. package/src/prelude/values/helpers/object.hpp +3 -3
  43. package/src/prelude/values/helpers/promise.hpp +1 -1
  44. package/src/prelude/values/helpers/string.hpp +1 -1
  45. package/src/prelude/values/helpers/symbol.hpp +1 -1
  46. package/src/prelude/values/prototypes/array.hpp +1125 -853
  47. package/src/prelude/values/prototypes/async_iterator.hpp +32 -14
  48. package/src/prelude/values/prototypes/function.hpp +30 -18
  49. package/src/prelude/values/prototypes/iterator.hpp +40 -17
  50. package/src/prelude/values/prototypes/number.hpp +119 -62
  51. package/src/prelude/values/prototypes/object.hpp +10 -4
  52. package/src/prelude/values/prototypes/promise.hpp +167 -109
  53. package/src/prelude/values/prototypes/string.hpp +407 -231
  54. package/src/prelude/values/prototypes/symbol.hpp +45 -23
@@ -1,6 +1,8 @@
1
1
  import ts from "typescript";
2
2
  import { DeclaredSymbols } from "../../ast/symbols.js";
3
- import { collectBlockScopedDeclarations, collectFunctionScopedDeclarations, } from "./helpers.js";
3
+ import { constants } from "../constants.js";
4
+ import { CompilerError } from "../error.js";
5
+ import { collectBlockScopedDeclarations, collectFunctionScopedDeclarations, shouldIgnoreStatement, } from "./helpers.js";
4
6
  import { CodeGenerator } from "./index.js";
5
7
  export function visitSourceFile(node, context) {
6
8
  const sourceFile = node;
@@ -8,8 +10,9 @@ export function visitSourceFile(node, context) {
8
10
  // 1. Collect all var declarations (recursively) + top-level let/const
9
11
  const varDecls = collectFunctionScopedDeclarations(sourceFile);
10
12
  const topLevelLetConst = collectBlockScopedDeclarations(sourceFile.statements);
11
- const funcDecls = sourceFile.statements.filter(ts.isFunctionDeclaration);
13
+ const funcDecls = sourceFile.statements.filter((s) => ts.isFunctionDeclaration(s) && !!s.body);
12
14
  const classDecls = sourceFile.statements.filter(ts.isClassDeclaration);
15
+ const enumDecls = sourceFile.statements.filter(ts.isEnumDeclaration);
13
16
  const hoistedSymbols = new DeclaredSymbols();
14
17
  // Hoist function declarations
15
18
  funcDecls.forEach((func) => {
@@ -19,6 +22,10 @@ export function visitSourceFile(node, context) {
19
22
  classDecls.forEach((cls) => {
20
23
  code += this.hoistDeclaration(cls, hoistedSymbols, node);
21
24
  });
25
+ // Hoist enum declarations
26
+ enumDecls.forEach((enm) => {
27
+ code += this.hoistDeclaration(enm, hoistedSymbols, node);
28
+ });
22
29
  // Hoist variable declarations (var)
23
30
  varDecls.forEach((decl) => {
24
31
  code += this.hoistDeclaration(decl, hoistedSymbols, node);
@@ -45,21 +52,31 @@ export function visitSourceFile(node, context) {
45
52
  // Mark before further visits
46
53
  this.markSymbolAsInitialized(funcName, contextForFunctions.globalScopeSymbols, contextForFunctions.localScopeSymbols);
47
54
  this.markSymbolAsInitialized(funcName, globalScopeSymbols, localScopeSymbols);
48
- // Generate and update self name
55
+ // Update features in the symbol registry
49
56
  const nativeName = this.generateUniqueName(`__${funcName}_native_`, hoistedSymbols);
50
- hoistedSymbols.update(funcName, { func: { nativeName } });
51
- // Generate lambda
52
- 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, {
53
68
  isAssignment: true,
54
- generateOnlyLambda: true,
55
69
  nativeName,
70
+ noTypeSignature: true,
56
71
  });
57
- code += `${this.indent()}auto ${nativeName} = ${lambda};\n`;
58
- // 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
59
76
  if (this.isFunctionUsedAsValue(stmt, node) ||
60
77
  this.isFunctionUsedBeforeDeclaration(funcName, node)) {
61
- const fullExpression = this.generateFullLambdaExpression(stmt, contextForFunctions, nativeName, { isAssignment: true, noTypeSignature: true });
62
- code += `${this.indent()}*${funcName} = ${fullExpression};\n`;
78
+ const wrappedLambda = this.generateWrappedLambda(lambdaComps);
79
+ code += `${this.indent()}*${funcName} = ${wrappedLambda};\n`;
63
80
  }
64
81
  });
65
82
  // 3. Process other statements
@@ -68,19 +85,11 @@ export function visitSourceFile(node, context) {
68
85
  // Already handled
69
86
  }
70
87
  else if (ts.isVariableStatement(stmt)) {
71
- const isLetOrConst = (stmt.declarationList.flags &
72
- (ts.NodeFlags.Let | ts.NodeFlags.Const)) !==
73
- 0;
74
- const contextForVisit = {
88
+ code += this.visit(stmt, {
75
89
  ...context,
76
90
  globalScopeSymbols,
77
91
  localScopeSymbols,
78
- isAssignmentOnly: !isLetOrConst,
79
- };
80
- const assignments = this.visit(stmt.declarationList, contextForVisit);
81
- if (assignments) {
82
- code += `${this.indent()}${assignments};\n`;
83
- }
92
+ });
84
93
  }
85
94
  else {
86
95
  code += this.visit(stmt, {
@@ -100,8 +109,9 @@ export function visitBlock(node, context) {
100
109
  const block = node;
101
110
  // Collect ONLY block-scoped declarations (let/const)
102
111
  const blockScopedDecls = collectBlockScopedDeclarations(block.statements);
103
- const funcDecls = block.statements.filter(ts.isFunctionDeclaration);
112
+ const funcDecls = block.statements.filter((s) => ts.isFunctionDeclaration(s) && !!s.body);
104
113
  const classDecls = block.statements.filter(ts.isClassDeclaration);
114
+ const enumDecls = block.statements.filter(ts.isEnumDeclaration);
105
115
  const hoistedSymbols = new DeclaredSymbols();
106
116
  // 1. Hoist all function declarations
107
117
  funcDecls.forEach((func) => {
@@ -111,6 +121,10 @@ export function visitBlock(node, context) {
111
121
  classDecls.forEach((cls) => {
112
122
  code += this.hoistDeclaration(cls, hoistedSymbols, node);
113
123
  });
124
+ // Hoist enum declarations
125
+ enumDecls.forEach((enm) => {
126
+ code += this.hoistDeclaration(enm, hoistedSymbols, node);
127
+ });
114
128
  // Hoist variable declarations (let/const only)
115
129
  blockScopedDecls.forEach((decl) => {
116
130
  code += this.hoistDeclaration(decl, hoistedSymbols, node);
@@ -133,21 +147,31 @@ export function visitBlock(node, context) {
133
147
  // Mark before further visits
134
148
  this.markSymbolAsInitialized(funcName, contextForFunctions.globalScopeSymbols, contextForFunctions.localScopeSymbols);
135
149
  this.markSymbolAsInitialized(funcName, globalScopeSymbols, localScopeSymbols);
136
- // Generate and update self name
150
+ // Update features in the symbol registry
137
151
  const nativeName = this.generateUniqueName(`__${funcName}_native_`, hoistedSymbols);
138
- hoistedSymbols.update(funcName, { func: { nativeName } });
139
- // Generate lambda
140
- 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, {
141
163
  isAssignment: true,
142
- generateOnlyLambda: true,
143
164
  nativeName,
165
+ noTypeSignature: true,
144
166
  });
145
- code += `${this.indent()}auto ${nativeName} = ${lambda};\n`;
146
- // 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
147
171
  if (this.isFunctionUsedAsValue(stmt, node) ||
148
172
  this.isFunctionUsedBeforeDeclaration(funcName, node)) {
149
- const fullExpression = this.generateFullLambdaExpression(stmt, contextForFunctions, nativeName, { isAssignment: true, noTypeSignature: true });
150
- code += `${this.indent()}*${funcName} = ${fullExpression};\n`;
173
+ const wrappedLambda = this.generateWrappedLambda(lambdaComps);
174
+ code += `${this.indent()}*${funcName} = ${wrappedLambda};\n`;
151
175
  }
152
176
  });
153
177
  // 3. Process other statements
@@ -156,19 +180,11 @@ export function visitBlock(node, context) {
156
180
  // Do nothing, already handled
157
181
  }
158
182
  else if (ts.isVariableStatement(stmt)) {
159
- const isLetOrConst = (stmt.declarationList.flags &
160
- (ts.NodeFlags.Let | ts.NodeFlags.Const)) !==
161
- 0;
162
- const contextForVisit = {
183
+ code += this.visit(stmt, {
163
184
  ...context,
164
185
  globalScopeSymbols,
165
186
  localScopeSymbols,
166
- isAssignmentOnly: !isLetOrConst,
167
- };
168
- const assignments = this.visit(stmt.declarationList, contextForVisit);
169
- if (assignments) {
170
- code += `${this.indent()}${assignments};\n`;
171
- }
187
+ });
172
188
  }
173
189
  else {
174
190
  code += this.visit(stmt, {
@@ -190,9 +206,87 @@ export function visitBlock(node, context) {
190
206
  return code;
191
207
  }
192
208
  export function visitVariableStatement(node, context) {
193
- return (this.indent() +
194
- this.visit(node.declarationList, context) +
195
- ";\n");
209
+ if (shouldIgnoreStatement(node)) {
210
+ return "";
211
+ }
212
+ const isLetOrConst = (node.declarationList.flags &
213
+ (ts.NodeFlags.Let | ts.NodeFlags.Const)) !==
214
+ 0;
215
+ const visitContext = {
216
+ ...context,
217
+ isAssignmentOnly: !isLetOrConst,
218
+ };
219
+ const assignments = this.visit(node.declarationList, visitContext);
220
+ if (assignments) {
221
+ return `${this.indent()}${assignments};\n`;
222
+ }
223
+ return "";
224
+ }
225
+ export function visitTypeAliasDeclaration(node, context) {
226
+ return "";
227
+ }
228
+ export function visitInterfaceDeclaration(node, context) {
229
+ return "";
230
+ }
231
+ export function visitEnumDeclaration(node, context) {
232
+ const name = node.name.getText();
233
+ const scope = this.getScopeForNode(node);
234
+ const typeInfo = this.typeAnalyzer.scopeManager.lookupFromScope(name, scope);
235
+ // Mark as initialized
236
+ this.markSymbolAsInitialized(name, context.globalScopeSymbols, context.localScopeSymbols);
237
+ const enumVar = typeInfo.needsHeapAllocation ? `(*${name})` : name;
238
+ let code = `${this.indent()}${enumVar} = jspp::AnyValue::make_object({});\n`;
239
+ code += `${this.indent()}{\n`;
240
+ this.indentationLevel++;
241
+ code +=
242
+ `${this.indent()}jspp::AnyValue lastVal = jspp::AnyValue::make_number(-1);\n`; // Previous value tracker
243
+ for (const member of node.members) {
244
+ const memberName = member.name.getText();
245
+ let valueCode = "";
246
+ // Handle member name (it could be a string literal or identifier)
247
+ let key = "";
248
+ if (ts.isIdentifier(member.name)) {
249
+ key = `"${memberName}"`;
250
+ }
251
+ else if (ts.isStringLiteral(member.name)) {
252
+ key = member.name.getText(); // Includes quotes
253
+ }
254
+ else {
255
+ // Computed property names or numeric literals in enums are rarer but possible
256
+ // For now assume simple enum
257
+ key = `"${memberName}"`;
258
+ }
259
+ if (member.initializer) {
260
+ // Visit initializer
261
+ valueCode = this.visit(member.initializer, context);
262
+ }
263
+ else {
264
+ // Auto-increment
265
+ valueCode = `jspp::add(lastVal, 1)`;
266
+ }
267
+ code += `${this.indent()}lastVal = ${valueCode};\n`;
268
+ code +=
269
+ `${this.indent()}${enumVar}.set_own_property(${key}, lastVal);\n`;
270
+ // Reverse mapping for numeric enums
271
+ code += `${this.indent()}if (lastVal.is_number()) {\n`;
272
+ this.indentationLevel++;
273
+ code +=
274
+ `${this.indent()}${enumVar}.set_own_property(lastVal, jspp::AnyValue::make_string(${key}));\n`;
275
+ this.indentationLevel--;
276
+ code += `${this.indent()}}\n`;
277
+ }
278
+ this.indentationLevel--;
279
+ code += `${this.indent()}}\n`;
280
+ return code;
281
+ }
282
+ export function visitModuleDeclaration(node, context) {
283
+ return "";
284
+ }
285
+ export function visitImportDeclaration(node, context) {
286
+ return "";
287
+ }
288
+ export function visitImportEqualsDeclaration(node, context) {
289
+ return "";
196
290
  }
197
291
  export function visitBreakStatement(node, context) {
198
292
  if (node.label) {
@@ -237,7 +331,12 @@ export function visitLabeledStatement(node, context) {
237
331
  }
238
332
  export function visitIfStatement(node, context) {
239
333
  const ifStmt = node;
240
- const condition = this.visit(ifStmt.expression, context);
334
+ const isBinaryExpression = ts.isBinaryExpression(ifStmt.expression) &&
335
+ constants.booleanOperators.includes(ifStmt.expression.operatorToken.kind);
336
+ const condition = this.visit(ifStmt.expression, {
337
+ ...context,
338
+ supportedNativeLiterals: isBinaryExpression ? ["boolean"] : undefined,
339
+ });
241
340
  const thenStmt = this.visit(ifStmt.thenStatement, {
242
341
  ...context,
243
342
  isFunctionBody: false,
@@ -250,15 +349,8 @@ export function visitIfStatement(node, context) {
250
349
  isFunctionBody: false,
251
350
  });
252
351
  }
253
- if (ts.isBinaryExpression(ifStmt.expression)) {
254
- const binExpr = ifStmt.expression;
255
- const op = binExpr.operatorToken.getText();
256
- const isBoolean = op === "==" || op === "!=" || op === "===" ||
257
- op === "!==" || op === "<" || op === ">" || op === "<=" ||
258
- op === ">=" || op === "instanceof" || op === "in";
259
- if (isBoolean) {
260
- return `${this.indent()}if ((${condition}).as_boolean()) ${thenStmt}${elseStmt}`;
261
- }
352
+ if (isBinaryExpression) {
353
+ return `${this.indent()}if (${condition}) ${thenStmt}${elseStmt}`;
262
354
  }
263
355
  return `${this.indent()}if (jspp::is_truthy(${condition})) ${thenStmt}${elseStmt}`;
264
356
  }
@@ -540,7 +632,7 @@ export function visitCatchClause(node, context) {
540
632
  const exceptionName = context.exceptionName;
541
633
  if (!exceptionName) {
542
634
  // This should not happen if it's coming from a TryStatement
543
- throw new Error("Compiler bug: exceptionName not found in context for CatchClause");
635
+ throw new CompilerError("exceptionName not found in context for CatchClause", node, "CompilerBug");
544
636
  }
545
637
  if (catchClause.variableDeclaration) {
546
638
  const varName = catchClause.variableDeclaration.name.getText();
@@ -2,11 +2,11 @@ import ts from "typescript";
2
2
  import { visitClassDeclaration } from "./class-handlers.js";
3
3
  import { visitCaseClause, visitDefaultClause, visitDoStatement, visitForInStatement, visitForOfStatement, visitForStatement, visitSwitchStatement, visitWhileStatement, } from "./control-flow-handlers.js";
4
4
  import { visitVariableDeclaration, visitVariableDeclarationList, } from "./declaration-handlers.js";
5
- import { visitArrayLiteralExpression, visitAwaitExpression, visitBinaryExpression, visitCallExpression, visitConditionalExpression, visitDeleteExpression, visitElementAccessExpression, visitNewExpression, visitObjectLiteralExpression, visitParenthesizedExpression, visitPostfixUnaryExpression, visitPrefixUnaryExpression, visitPropertyAccessExpression, visitTemplateExpression, visitTypeOfExpression, visitVoidExpression, } from "./expression-handlers.js";
5
+ import { visitArrayLiteralExpression, visitAsExpression, visitAwaitExpression, visitBinaryExpression, visitCallExpression, visitConditionalExpression, visitDeleteExpression, visitElementAccessExpression, visitNewExpression, visitNonNullExpression, visitObjectLiteralExpression, visitParenthesizedExpression, visitPostfixUnaryExpression, visitPrefixUnaryExpression, visitPropertyAccessExpression, visitSatisfiesExpression, visitTemplateExpression, visitTypeAssertionExpression, visitTypeOfExpression, visitVoidExpression, } from "./expression-handlers.js";
6
6
  import { visitArrowFunction, visitFunctionDeclaration, visitFunctionExpression, } from "./function-handlers.js";
7
7
  import { CodeGenerator } from "./index.js";
8
8
  import { visitFalseKeyword, visitIdentifier, visitNoSubstitutionTemplateLiteral, visitNullKeyword, visitNumericLiteral, visitStringLiteral, visitThisKeyword, visitTrueKeyword, visitUndefinedKeyword, } from "./literal-handlers.js";
9
- import { visitBlock, visitBreakStatement, visitCatchClause, visitContinueStatement, visitExpressionStatement, visitIfStatement, visitLabeledStatement, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitVariableStatement, visitYieldExpression, } from "./statement-handlers.js";
9
+ import { visitBlock, visitBreakStatement, visitCatchClause, visitContinueStatement, visitEnumDeclaration, visitExpressionStatement, visitIfStatement, visitImportDeclaration, visitImportEqualsDeclaration, visitInterfaceDeclaration, visitLabeledStatement, visitModuleDeclaration, visitReturnStatement, visitSourceFile, visitThrowStatement, visitTryStatement, visitTypeAliasDeclaration, visitVariableStatement, visitYieldExpression, } from "./statement-handlers.js";
10
10
  export function visit(node, context) {
11
11
  if (ts.isFunctionDeclaration(node)) {
12
12
  return visitFunctionDeclaration.call(this, node, context);
@@ -114,6 +114,26 @@ export function visit(node, context) {
114
114
  return visitNullKeyword.call(this);
115
115
  case ts.SyntaxKind.ThisKeyword:
116
116
  return visitThisKeyword.call(this);
117
+ case ts.SyntaxKind.AsExpression:
118
+ return visitAsExpression.call(this, node, context);
119
+ case ts.SyntaxKind.TypeAssertionExpression:
120
+ return visitTypeAssertionExpression.call(this, node, context);
121
+ case ts.SyntaxKind.NonNullExpression:
122
+ return visitNonNullExpression.call(this, node, context);
123
+ case ts.SyntaxKind.SatisfiesExpression:
124
+ return visitSatisfiesExpression.call(this, node, context);
125
+ case ts.SyntaxKind.TypeAliasDeclaration:
126
+ return visitTypeAliasDeclaration.call(this, node, context);
127
+ case ts.SyntaxKind.InterfaceDeclaration:
128
+ return visitInterfaceDeclaration.call(this, node, context);
129
+ case ts.SyntaxKind.EnumDeclaration:
130
+ return visitEnumDeclaration.call(this, node, context);
131
+ case ts.SyntaxKind.ModuleDeclaration:
132
+ return visitModuleDeclaration.call(this, node, context);
133
+ case ts.SyntaxKind.ImportDeclaration:
134
+ return visitImportDeclaration.call(this, node, context);
135
+ case ts.SyntaxKind.ImportEqualsDeclaration:
136
+ return visitImportEqualsDeclaration.call(this, node, context);
117
137
  default:
118
138
  return `/* Unhandled node: ${ts.SyntaxKind[node.kind]} */`;
119
139
  }
@@ -0,0 +1,16 @@
1
+ import ts from "typescript";
2
+ const booleanOperators = [
3
+ ts.SyntaxKind.EqualsEqualsEqualsToken,
4
+ ts.SyntaxKind.EqualsEqualsToken,
5
+ ts.SyntaxKind.ExclamationEqualsEqualsToken,
6
+ ts.SyntaxKind.ExclamationEqualsToken,
7
+ ts.SyntaxKind.InstanceOfKeyword,
8
+ ts.SyntaxKind.InKeyword,
9
+ ts.SyntaxKind.LessThanToken,
10
+ ts.SyntaxKind.LessThanEqualsToken,
11
+ ts.SyntaxKind.GreaterThanToken,
12
+ ts.SyntaxKind.GreaterThanEqualsToken,
13
+ ];
14
+ export const constants = Object.freeze({
15
+ booleanOperators,
16
+ });
@@ -0,0 +1,58 @@
1
+ import ts from "typescript";
2
+ const COLORS = {
3
+ reset: "\x1b[0m",
4
+ red: "\x1b[31m",
5
+ yellow: "\x1b[33m",
6
+ cyan: "\x1b[36m",
7
+ bold: "\x1b[1m",
8
+ dim: "\x1b[2m",
9
+ };
10
+ export class CompilerError extends Error {
11
+ node;
12
+ type;
13
+ constructor(message, node, type = "SyntaxError") {
14
+ super(message);
15
+ this.node = node;
16
+ this.type = type;
17
+ Object.setPrototypeOf(this, CompilerError.prototype);
18
+ }
19
+ getFormattedError() {
20
+ const sourceFile = this.node.getSourceFile();
21
+ if (!sourceFile) {
22
+ return `${COLORS.red}${this.type}: ${this.message}${COLORS.reset}`;
23
+ }
24
+ const start = this.node.getStart();
25
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(start);
26
+ // Get the full line content safely
27
+ const lineStartPos = sourceFile.getPositionOfLineAndCharacter(line, 0);
28
+ let lineEndPos;
29
+ try {
30
+ lineEndPos = sourceFile.getLineEndOfPosition(start);
31
+ }
32
+ catch {
33
+ lineEndPos = sourceFile.text.length;
34
+ }
35
+ const lineContent = sourceFile.text.substring(lineStartPos, lineEndPos).replace(/\r/g, ''); // Remove CR
36
+ const fileName = sourceFile.fileName;
37
+ const lineNum = line + 1;
38
+ const charNum = character + 1;
39
+ let output = `\n${COLORS.red}${COLORS.bold}${this.type}:${COLORS.reset} ${this.message}\n`;
40
+ output += ` ${COLORS.dim}at ${fileName}:${lineNum}:${charNum}${COLORS.reset}\n\n`;
41
+ // Code frame
42
+ const lineNumStr = `${lineNum} | `;
43
+ output += `${COLORS.dim}${lineNumStr}${COLORS.reset}${lineContent}\n`;
44
+ // Adjust pointer position if there are tabs
45
+ let pointerPadding = "";
46
+ for (let i = 0; i < character; i++) {
47
+ if (lineContent[i] === '\t') {
48
+ pointerPadding += "\t";
49
+ }
50
+ else {
51
+ pointerPadding += " ";
52
+ }
53
+ }
54
+ const padding = " ".repeat(lineNumStr.length) + pointerPadding;
55
+ output += `${padding}${COLORS.red}^${COLORS.reset}\n`;
56
+ return output;
57
+ }
58
+ }
package/dist/index.js CHANGED
@@ -6,10 +6,13 @@ export class Interpreter {
6
6
  parser = new Parser();
7
7
  analyzer = new TypeAnalyzer();
8
8
  generator = new CodeGenerator();
9
- interpret(jsCode, fileName) {
10
- const ast = this.parser.parse(jsCode, fileName);
9
+ interpret(code, fileName) {
10
+ const ast = this.parser.parse(code, fileName);
11
11
  this.analyzer.analyze(ast);
12
- const cppCode = this.generator.generate(ast, this.analyzer);
12
+ const isTypescript = fileName
13
+ ? path.extname(fileName) === ".ts"
14
+ : false;
15
+ const cppCode = this.generator.generate(ast, this.analyzer, isTypescript);
13
16
  const preludePath = path.resolve(import.meta.dirname, "..", "src", "prelude");
14
17
  return { cppCode, preludePath };
15
18
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ugo-studio/jspp",
3
- "version": "0.2.5",
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",
7
7
  "type": "module",
8
8
  "bin": {
9
- "jspp": "dist/cli.js"
9
+ "jspp": "dist/cli/index.js"
10
10
  },
11
11
  "files": [
12
12
  "dist",
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "scripts": {
17
17
  "postinstall": "bun run scripts/setup-compiler.ts",
18
- "dev": "bun run src/cli.ts",
18
+ "dev": "bun run src/cli/index.ts",
19
19
  "typecheck": "tsc --noEmit",
20
20
  "precompile": "bun run scripts/precompile-headers.ts",
21
21
  "test": "bun test",