@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.
- package/README.md +51 -36
- package/dist/analysis/scope.js +7 -0
- package/dist/analysis/typeAnalyzer.js +96 -43
- package/dist/ast/symbols.js +34 -24
- package/dist/cli/args.js +59 -0
- package/dist/cli/colors.js +9 -0
- package/dist/cli/file-utils.js +20 -0
- package/dist/cli/index.js +160 -0
- package/dist/cli/spinner.js +55 -0
- package/dist/core/codegen/class-handlers.js +8 -8
- package/dist/core/codegen/control-flow-handlers.js +19 -9
- package/dist/core/codegen/declaration-handlers.js +30 -10
- package/dist/core/codegen/expression-handlers.js +649 -161
- package/dist/core/codegen/function-handlers.js +107 -103
- package/dist/core/codegen/helpers.js +61 -14
- package/dist/core/codegen/index.js +13 -9
- package/dist/core/codegen/literal-handlers.js +4 -2
- package/dist/core/codegen/statement-handlers.js +147 -55
- package/dist/core/codegen/visitor.js +22 -2
- package/dist/core/constants.js +16 -0
- package/dist/core/error.js +58 -0
- package/dist/index.js +6 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +89 -59
- package/src/prelude/any_value_access.hpp +1 -1
- package/src/prelude/any_value_helpers.hpp +85 -43
- package/src/prelude/index.hpp +1 -0
- package/src/prelude/library/array.hpp +3 -2
- package/src/prelude/scheduler.hpp +144 -144
- package/src/prelude/types.hpp +8 -8
- package/src/prelude/utils/access.hpp +62 -6
- package/src/prelude/utils/assignment_operators.hpp +14 -14
- package/src/prelude/utils/log_any_value/array.hpp +0 -15
- package/src/prelude/utils/log_any_value/object.hpp +12 -10
- package/src/prelude/utils/log_any_value/primitives.hpp +2 -0
- package/src/prelude/utils/operators.hpp +117 -474
- package/src/prelude/utils/operators_primitive.hpp +337 -0
- package/src/prelude/values/helpers/array.hpp +4 -4
- package/src/prelude/values/helpers/async_iterator.hpp +2 -2
- package/src/prelude/values/helpers/function.hpp +3 -3
- package/src/prelude/values/helpers/iterator.hpp +2 -2
- package/src/prelude/values/helpers/object.hpp +3 -3
- package/src/prelude/values/helpers/promise.hpp +1 -1
- package/src/prelude/values/helpers/string.hpp +1 -1
- package/src/prelude/values/helpers/symbol.hpp +1 -1
- package/src/prelude/values/prototypes/array.hpp +1125 -853
- package/src/prelude/values/prototypes/async_iterator.hpp +32 -14
- package/src/prelude/values/prototypes/function.hpp +30 -18
- package/src/prelude/values/prototypes/iterator.hpp +40 -17
- package/src/prelude/values/prototypes/number.hpp +119 -62
- package/src/prelude/values/prototypes/object.hpp +10 -4
- package/src/prelude/values/prototypes/promise.hpp +167 -109
- package/src/prelude/values/prototypes/string.hpp +407 -231
- package/src/prelude/values/prototypes/symbol.hpp +45 -23
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import pkg from "../../package.json" with { type: "json" };
|
|
6
|
+
import { CompilerError } from "../core/error.js";
|
|
7
|
+
import { Interpreter } from "../index.js";
|
|
8
|
+
import { parseArgs } from "./args.js";
|
|
9
|
+
import { COLORS } from "./colors.js";
|
|
10
|
+
import { getLatestMtime } from "./file-utils.js";
|
|
11
|
+
import { Spinner } from "./spinner.js";
|
|
12
|
+
const pkgDir = path.dirname(path.dirname(import.meta.dirname));
|
|
13
|
+
async function main() {
|
|
14
|
+
const { jsFilePath, isRelease, keepCpp, outputExePath, scriptArgs } = parseArgs(process.argv.slice(2));
|
|
15
|
+
const ext = path.extname(jsFilePath);
|
|
16
|
+
const jsFileName = path.basename(jsFilePath, ext);
|
|
17
|
+
const sourceDir = path.dirname(jsFilePath);
|
|
18
|
+
// Intermediate C++ file goes alongside the source JS file
|
|
19
|
+
const cppFilePath = path.join(sourceDir, `${jsFileName}.cpp`);
|
|
20
|
+
// Determine output executable path
|
|
21
|
+
let exeFilePath;
|
|
22
|
+
if (outputExePath) {
|
|
23
|
+
exeFilePath = outputExePath;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
27
|
+
exeFilePath = path.join(sourceDir, `${jsFileName}${ext}`);
|
|
28
|
+
}
|
|
29
|
+
// Mode Configuration
|
|
30
|
+
const mode = isRelease ? "release" : "debug";
|
|
31
|
+
console.log(`${COLORS.bold}JSPP Compiler${COLORS.reset} ${COLORS.dim}v${pkg.version}${COLORS.reset}`);
|
|
32
|
+
console.log(`Mode: ${isRelease ? COLORS.green : COLORS.yellow}${mode.toUpperCase()}${COLORS.reset}\n`);
|
|
33
|
+
const flags = isRelease ? ["-O3", "-DNDEBUG"] : ["-O0"];
|
|
34
|
+
if (process.platform === "win32") {
|
|
35
|
+
flags.push("-Wa,-mbig-obj");
|
|
36
|
+
}
|
|
37
|
+
const pchDir = path.resolve(pkgDir, "prelude-build", mode);
|
|
38
|
+
const spinner = new Spinner("Initializing...");
|
|
39
|
+
try {
|
|
40
|
+
spinner.start();
|
|
41
|
+
// 1. Interpreter Phase
|
|
42
|
+
spinner.update(`Reading ${path.basename(jsFilePath)}...`);
|
|
43
|
+
const jsCode = await fs.readFile(jsFilePath, "utf-8");
|
|
44
|
+
spinner.update("Transpiling to C++...");
|
|
45
|
+
const interpreter = new Interpreter();
|
|
46
|
+
const { cppCode, preludePath } = interpreter.interpret(jsCode, jsFilePath);
|
|
47
|
+
// Ensure directory for cpp file exists (should exist as it's source dir, but for safety if we change logic)
|
|
48
|
+
await fs.mkdir(path.dirname(cppFilePath), { recursive: true });
|
|
49
|
+
await fs.writeFile(cppFilePath, cppCode);
|
|
50
|
+
spinner.succeed(`Generated cpp`);
|
|
51
|
+
// 2. Precompiled Header Check
|
|
52
|
+
spinner.text = "Checking precompiled headers...";
|
|
53
|
+
spinner.start();
|
|
54
|
+
const pchFile = path.join(pchDir, "index.hpp.gch");
|
|
55
|
+
let shouldRebuild = false;
|
|
56
|
+
try {
|
|
57
|
+
const pchStats = await fs.stat(pchFile);
|
|
58
|
+
const sourceMtime = await getLatestMtime(preludePath);
|
|
59
|
+
if (sourceMtime > pchStats.mtimeMs) {
|
|
60
|
+
shouldRebuild = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
shouldRebuild = true;
|
|
65
|
+
}
|
|
66
|
+
if (shouldRebuild) {
|
|
67
|
+
spinner.update("Rebuilding precompiled headers (this may take a while)...");
|
|
68
|
+
// Use spawn (async) instead of spawnSync to keep spinner alive
|
|
69
|
+
const rebuild = spawn("bun", [
|
|
70
|
+
"run",
|
|
71
|
+
"scripts/precompile-headers.ts",
|
|
72
|
+
], {
|
|
73
|
+
cwd: pkgDir,
|
|
74
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
75
|
+
});
|
|
76
|
+
const stderrChunks = [];
|
|
77
|
+
if (rebuild.stderr) {
|
|
78
|
+
rebuild.stderr.on("data", (chunk) => stderrChunks.push(chunk));
|
|
79
|
+
}
|
|
80
|
+
const exitCode = await new Promise((resolve) => {
|
|
81
|
+
rebuild.on("close", (code) => resolve(code ?? 1));
|
|
82
|
+
});
|
|
83
|
+
if (exitCode !== 0) {
|
|
84
|
+
const stderr = Buffer.concat(stderrChunks).toString();
|
|
85
|
+
spinner.fail("Failed to rebuild precompiled headers");
|
|
86
|
+
console.error(stderr);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
spinner.succeed("Precompiled headers updated");
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
spinner.succeed("Precompiled headers");
|
|
93
|
+
}
|
|
94
|
+
// 3. Compilation Phase
|
|
95
|
+
spinner.text = `Compiling binary...`;
|
|
96
|
+
spinner.start();
|
|
97
|
+
// Ensure output directory exists
|
|
98
|
+
await fs.mkdir(path.dirname(exeFilePath), { recursive: true });
|
|
99
|
+
const compile = spawn("g++", [
|
|
100
|
+
"-std=c++23",
|
|
101
|
+
...flags,
|
|
102
|
+
cppFilePath,
|
|
103
|
+
"-o",
|
|
104
|
+
exeFilePath,
|
|
105
|
+
"-I",
|
|
106
|
+
pchDir,
|
|
107
|
+
"-I",
|
|
108
|
+
preludePath,
|
|
109
|
+
], {
|
|
110
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
111
|
+
});
|
|
112
|
+
const compileStderrChunks = [];
|
|
113
|
+
if (compile.stderr) {
|
|
114
|
+
compile.stderr.on("data", (chunk) => compileStderrChunks.push(chunk));
|
|
115
|
+
}
|
|
116
|
+
const compileExitCode = await new Promise((resolve) => {
|
|
117
|
+
compile.on("close", (code) => resolve(code ?? 1));
|
|
118
|
+
});
|
|
119
|
+
if (compileExitCode !== 0) {
|
|
120
|
+
const stderr = Buffer.concat(compileStderrChunks).toString();
|
|
121
|
+
spinner.fail(`Compilation failed`);
|
|
122
|
+
console.error(stderr);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
spinner.succeed(`Compiled to ${COLORS.green}${COLORS.bold}${path.basename(exeFilePath)}${COLORS.reset}`);
|
|
126
|
+
// Clean up C++ file if not requested to keep
|
|
127
|
+
if (!keepCpp) {
|
|
128
|
+
try {
|
|
129
|
+
await fs.unlink(cppFilePath);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
// Ignore error if file cannot be deleted
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// 4. Execution Phase
|
|
136
|
+
console.log(`\n${COLORS.cyan}--- Running Output ---${COLORS.reset}`);
|
|
137
|
+
const run = spawn(exeFilePath, scriptArgs, {
|
|
138
|
+
stdio: "inherit",
|
|
139
|
+
});
|
|
140
|
+
const runExitCode = await new Promise((resolve) => {
|
|
141
|
+
run.on("close", (code) => resolve(code ?? 1));
|
|
142
|
+
});
|
|
143
|
+
console.log(`${COLORS.cyan}----------------------${COLORS.reset}\n`);
|
|
144
|
+
if (runExitCode !== 0) {
|
|
145
|
+
console.error(`${COLORS.red}Execution failed with exit code ${runExitCode}${COLORS.reset}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error instanceof CompilerError) {
|
|
151
|
+
spinner.fail("Compilation failed");
|
|
152
|
+
console.error(error.getFormattedError());
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
spinner.fail("An unexpected error occurred");
|
|
156
|
+
console.error(error);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
main();
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { COLORS } from "./colors.js";
|
|
2
|
+
export class Spinner {
|
|
3
|
+
frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
4
|
+
interval = null;
|
|
5
|
+
frameIndex = 0;
|
|
6
|
+
text;
|
|
7
|
+
constructor(text) {
|
|
8
|
+
this.text = text;
|
|
9
|
+
}
|
|
10
|
+
start() {
|
|
11
|
+
process.stdout.write("\x1b[?25l"); // Hide cursor
|
|
12
|
+
this.frameIndex = 0;
|
|
13
|
+
this.render();
|
|
14
|
+
this.interval = setInterval(() => {
|
|
15
|
+
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
16
|
+
this.render();
|
|
17
|
+
}, 80);
|
|
18
|
+
}
|
|
19
|
+
update(text) {
|
|
20
|
+
this.text = text;
|
|
21
|
+
this.render();
|
|
22
|
+
}
|
|
23
|
+
stop(symbol = "", color = COLORS.reset) {
|
|
24
|
+
if (this.interval) {
|
|
25
|
+
clearInterval(this.interval);
|
|
26
|
+
this.interval = null;
|
|
27
|
+
}
|
|
28
|
+
this.clearLine();
|
|
29
|
+
process.stdout.write(`${color}${symbol} ${COLORS.reset} ${this.text}\n`);
|
|
30
|
+
process.stdout.write("\x1b[?25h"); // Show cursor
|
|
31
|
+
}
|
|
32
|
+
succeed(text) {
|
|
33
|
+
if (text)
|
|
34
|
+
this.text = text;
|
|
35
|
+
this.stop("✔", COLORS.green);
|
|
36
|
+
}
|
|
37
|
+
fail(text) {
|
|
38
|
+
if (text)
|
|
39
|
+
this.text = text;
|
|
40
|
+
this.stop("✖", COLORS.red);
|
|
41
|
+
}
|
|
42
|
+
info(text) {
|
|
43
|
+
if (text)
|
|
44
|
+
this.text = text;
|
|
45
|
+
this.stop("ℹ", COLORS.cyan);
|
|
46
|
+
}
|
|
47
|
+
render() {
|
|
48
|
+
this.clearLine();
|
|
49
|
+
const frame = this.frames[this.frameIndex];
|
|
50
|
+
process.stdout.write(`${COLORS.cyan}${frame} ${COLORS.reset} ${this.text}`);
|
|
51
|
+
}
|
|
52
|
+
clearLine() {
|
|
53
|
+
process.stdout.write("\r\x1b[K");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -32,11 +32,11 @@ export function visitClassDeclaration(node, context) {
|
|
|
32
32
|
const constructor = node.members.find(ts.isConstructorDeclaration);
|
|
33
33
|
let constructorLambda = "";
|
|
34
34
|
if (constructor) {
|
|
35
|
-
constructorLambda = this.
|
|
35
|
+
constructorLambda = this.generateWrappedLambda(this.generateLambdaComponents(constructor, {
|
|
36
36
|
...classContext,
|
|
37
37
|
isInsideFunction: true,
|
|
38
38
|
lambdaName: className,
|
|
39
|
-
}, { isClass: true });
|
|
39
|
+
}, { isClass: true }));
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
// Default constructor
|
|
@@ -75,10 +75,10 @@ export function visitClassDeclaration(node, context) {
|
|
|
75
75
|
isObjectLiteralExpression: true, // Reuse this flag to handle computed properties
|
|
76
76
|
});
|
|
77
77
|
const isStatic = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);
|
|
78
|
-
const methodLambda = this.
|
|
78
|
+
const methodLambda = this.generateWrappedLambda(this.generateLambdaComponents(member, {
|
|
79
79
|
...classContext,
|
|
80
80
|
isInsideFunction: true,
|
|
81
|
-
});
|
|
81
|
+
}));
|
|
82
82
|
if (isStatic) {
|
|
83
83
|
code +=
|
|
84
84
|
`${this.indent()}(*${className}).set_own_property(${methodName}, ${methodLambda});\n`;
|
|
@@ -94,10 +94,10 @@ export function visitClassDeclaration(node, context) {
|
|
|
94
94
|
isObjectLiteralExpression: true,
|
|
95
95
|
});
|
|
96
96
|
const isStatic = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);
|
|
97
|
-
const lambda = this.
|
|
97
|
+
const lambda = this.generateWrappedLambda(this.generateLambdaComponents(member, {
|
|
98
98
|
...classContext,
|
|
99
99
|
isInsideFunction: true,
|
|
100
|
-
});
|
|
100
|
+
}));
|
|
101
101
|
if (isStatic) {
|
|
102
102
|
code +=
|
|
103
103
|
`${this.indent()}(*${className}).define_getter(${methodName}, ${lambda});\n`;
|
|
@@ -113,10 +113,10 @@ export function visitClassDeclaration(node, context) {
|
|
|
113
113
|
isObjectLiteralExpression: true,
|
|
114
114
|
});
|
|
115
115
|
const isStatic = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);
|
|
116
|
-
const lambda = this.
|
|
116
|
+
const lambda = this.generateWrappedLambda(this.generateLambdaComponents(member, {
|
|
117
117
|
...classContext,
|
|
118
118
|
isInsideFunction: true,
|
|
119
|
-
});
|
|
119
|
+
}));
|
|
120
120
|
if (isStatic) {
|
|
121
121
|
code +=
|
|
122
122
|
`${this.indent()}(*${className}).define_setter(${methodName}, ${lambda});\n`;
|
|
@@ -44,11 +44,11 @@ export function visitForStatement(node, context) {
|
|
|
44
44
|
: DeclarationType.const;
|
|
45
45
|
conditionContext.localScopeSymbols.add(name, {
|
|
46
46
|
type: declType,
|
|
47
|
-
|
|
47
|
+
checks: { initialized: true },
|
|
48
48
|
});
|
|
49
49
|
statementContext.localScopeSymbols.add(name, {
|
|
50
50
|
type: declType,
|
|
51
|
-
|
|
51
|
+
checks: { initialized: true },
|
|
52
52
|
});
|
|
53
53
|
if (typeInfo.needsHeapAllocation) {
|
|
54
54
|
initializerCode =
|
|
@@ -440,19 +440,29 @@ export function visitSwitchStatement(node, context) {
|
|
|
440
440
|
this.markSymbolAsInitialized(funcName, globalScopeSymbols, localScopeSymbols);
|
|
441
441
|
// Generate native name
|
|
442
442
|
const nativeName = this.generateUniqueName(`__${funcName}_native_`, hoistedSymbols);
|
|
443
|
-
hoistedSymbols.update(funcName, {
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
hoistedSymbols.update(funcName, {
|
|
444
|
+
features: {
|
|
445
|
+
native: {
|
|
446
|
+
type: "lambda",
|
|
447
|
+
name: nativeName,
|
|
448
|
+
parameters: this.validateFunctionParams(stmt.parameters),
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
// Generate lambda components
|
|
453
|
+
const lambdaComps = this.generateLambdaComponents(stmt, contextForFunctions, {
|
|
446
454
|
isAssignment: true,
|
|
447
|
-
generateOnlyLambda: true,
|
|
448
455
|
nativeName,
|
|
456
|
+
noTypeSignature: true,
|
|
449
457
|
});
|
|
450
|
-
|
|
458
|
+
// Generate native lambda
|
|
459
|
+
const nativeLambda = this.generateNativeLambda(lambdaComps);
|
|
460
|
+
code += `${this.indent()}auto ${nativeName} = ${nativeLambda};\n`;
|
|
451
461
|
// Generate AnyValue wrapper
|
|
452
462
|
if (this.isFunctionUsedAsValue(stmt, node) ||
|
|
453
463
|
this.isFunctionUsedBeforeDeclaration(funcName, node)) {
|
|
454
|
-
const
|
|
455
|
-
code += `${this.indent()}*${funcName} = ${
|
|
464
|
+
const wrappedLambda = this.generateWrappedLambda(lambdaComps);
|
|
465
|
+
code += `${this.indent()}*${funcName} = ${wrappedLambda};\n`;
|
|
456
466
|
}
|
|
457
467
|
});
|
|
458
468
|
let firstIf = true;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
+
import { CompilerError } from "../error.js";
|
|
2
3
|
import { CodeGenerator } from "./index.js";
|
|
3
4
|
export function visitVariableDeclarationList(node, context) {
|
|
4
5
|
return node.declarations
|
|
@@ -37,24 +38,34 @@ export function visitVariableDeclaration(node, context) {
|
|
|
37
38
|
initText = this.getDerefCode(initText, varName, context, initTypeInfo);
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
else if (ts.isArrowFunction(initExpr)
|
|
41
|
+
else if (ts.isArrowFunction(initExpr) ||
|
|
42
|
+
(ts.isFunctionExpression(initExpr) && !initExpr.name)) {
|
|
41
43
|
const initContext = {
|
|
42
44
|
...context,
|
|
43
45
|
lambdaName: name, // Use the variable name as function name
|
|
44
46
|
};
|
|
45
|
-
// Generate and update self name
|
|
46
47
|
const nativeName = this.generateUniqueName(`__${name}_native_`, context.localScopeSymbols, context.globalScopeSymbols);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// Mark before further visits
|
|
49
|
+
context.localScopeSymbols.update(name, {
|
|
50
|
+
features: {
|
|
51
|
+
native: {
|
|
52
|
+
type: "lambda",
|
|
53
|
+
name: nativeName,
|
|
54
|
+
parameters: this.validateFunctionParams(initExpr.parameters),
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
// Generate lambda components
|
|
59
|
+
const lambdaComps = this.generateLambdaComponents(initExpr, initContext, {
|
|
50
60
|
isAssignment: true,
|
|
51
|
-
generateOnlyLambda: true,
|
|
52
61
|
nativeName,
|
|
62
|
+
noTypeSignature: true,
|
|
53
63
|
});
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
const nativeLambda = this.generateNativeLambda(lambdaComps);
|
|
65
|
+
// Generate native lambda
|
|
66
|
+
nativeLambdaCode = `auto ${nativeName} = ${nativeLambda}`;
|
|
56
67
|
// Generate AnyValue wrapper
|
|
57
|
-
initText = this.
|
|
68
|
+
initText = this.generateWrappedLambda(lambdaComps);
|
|
58
69
|
}
|
|
59
70
|
initializer = " = " + initText;
|
|
60
71
|
}
|
|
@@ -66,10 +77,19 @@ export function visitVariableDeclaration(node, context) {
|
|
|
66
77
|
: (typeInfo.needsHeapAllocation && !shouldSkipDeref
|
|
67
78
|
? `*${name}`
|
|
68
79
|
: name);
|
|
80
|
+
if (nativeLambdaCode)
|
|
81
|
+
nativeLambdaCode += `;\n${this.indent()}`;
|
|
69
82
|
if (isLetOrConst) {
|
|
70
83
|
// If there's no initializer, it should be assigned undefined.
|
|
71
84
|
if (!initializer) {
|
|
72
|
-
|
|
85
|
+
// Constant variables must be initialized
|
|
86
|
+
const isConst = (varDecl.parent.flags & (ts.NodeFlags.Const)) !== 0;
|
|
87
|
+
if (isConst) {
|
|
88
|
+
throw new CompilerError(`The constant "${name}" must be initialized`, varDecl, "SyntaxError");
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return `${nativeLambdaCode}${assignmentTarget} = jspp::Constants::UNDEFINED`;
|
|
92
|
+
}
|
|
73
93
|
}
|
|
74
94
|
return `${nativeLambdaCode}${assignmentTarget}${initializer}`;
|
|
75
95
|
}
|