js-slang
Version:
Javascript-based implementations of Source, written in Typescript
88 lines • 5.48 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const typeGuards_1 = require("../../utils/ast/typeGuards");
const assert_1 = require("../../utils/assert");
const helpers_1 = require("../../utils/ast/helpers");
const utils_1 = require("../utils");
const transformProgramToFunctionDeclaration_1 = require("./transformers/transformProgramToFunctionDeclaration");
const filePaths_1 = require("./filePaths");
const contextSpecificConstructors_1 = require("./constructors/contextSpecificConstructors");
const hoistAndMergeImports_1 = require("./transformers/hoistAndMergeImports");
const removeExports_1 = require("./transformers/removeExports");
const getSourceModuleImports = (programs) => {
return Object.values(programs).flatMap(program => {
return program.body.filter((stmt) => {
if (!(0, typeGuards_1.isImportDeclaration)(stmt))
return false;
const importSource = (0, helpers_1.getModuleDeclarationSource)(stmt);
return (0, utils_1.isSourceModule)(importSource);
});
});
};
const defaultBundler = (programs, entrypointFilePath, topoOrder) => {
// We want to operate on the entrypoint program to get the eventual
// preprocessed program.
const entrypointProgram = programs[entrypointFilePath];
const entrypointDirPath = path_1.posix.resolve(entrypointFilePath, '..');
// Create variables to hold the imported statements.
const entrypointProgramModuleDeclarations = entrypointProgram.body.filter(typeGuards_1.isModuleDeclaration);
const entrypointProgramInvokedFunctionResultVariableNameToImportSpecifiersMap = (0, transformProgramToFunctionDeclaration_1.getInvokedFunctionResultVariableNameToImportSpecifiersMap)(entrypointProgramModuleDeclarations, entrypointDirPath);
const entrypointProgramAccessImportStatements = (0, transformProgramToFunctionDeclaration_1.createAccessImportStatements)(entrypointProgramInvokedFunctionResultVariableNameToImportSpecifiersMap);
// Transform all programs into their equivalent function declaration
// except for the entrypoint program.
const functionDeclarations = {};
for (const [filePath, program] of Object.entries(programs)) {
// The entrypoint program does not need to be transformed into its
// function declaration equivalent as its enclosing environment is
// simply the overall program's (constructed program's) environment.
if (filePath === entrypointFilePath) {
continue;
}
const functionDeclaration = (0, transformProgramToFunctionDeclaration_1.transformProgramToFunctionDeclaration)(program, filePath);
const functionName = functionDeclaration.id?.name;
(0, assert_1.default)(functionName !== undefined, 'A transformed function declaration is missing its name. This should never happen.');
functionDeclarations[functionName] = functionDeclaration;
}
// Invoke each of the transformed functions and store the result in a variable.
const invokedFunctionResultVariableDeclarations = [];
topoOrder.forEach((filePath) => {
// As mentioned above, the entrypoint program does not have a function
// declaration equivalent, so there is no need to process it.
if (filePath === entrypointFilePath) {
return;
}
const functionName = (0, filePaths_1.transformFilePathToValidFunctionName)(filePath);
const invokedFunctionResultVariableName = (0, filePaths_1.transformFunctionNameToInvokedFunctionResultVariableName)(functionName);
const functionDeclaration = functionDeclarations[functionName];
const functionParams = functionDeclaration.params.filter(typeGuards_1.isIdentifier);
(0, assert_1.default)(functionParams.length === functionDeclaration.params.length, 'Function declaration contains non-Identifier AST nodes as params. This should never happen.');
const invokedFunctionResultVariableDeclaration = (0, contextSpecificConstructors_1.createInvokedFunctionResultVariableDeclaration)(functionName, invokedFunctionResultVariableName, functionParams);
invokedFunctionResultVariableDeclarations.push(invokedFunctionResultVariableDeclaration);
});
// Get all Source module imports across the entrypoint program & all imported programs.
const sourceModuleImports = getSourceModuleImports(programs);
// Re-assemble the program.
const preprocessedProgram = {
...entrypointProgram,
body: [
...sourceModuleImports,
...Object.values(functionDeclarations),
...invokedFunctionResultVariableDeclarations,
...entrypointProgramAccessImportStatements,
...entrypointProgram.body
]
};
// We need to hoist all remaining imports to the top of the
// program. These imports should be source module imports since
// non-Source module imports would have already been handled. As part
// of this step, we also merge imports from the same module so as to
// import each unique name per module only once.
(0, hoistAndMergeImports_1.default)(preprocessedProgram);
// After this pre-processing step, all export-related nodes in the AST
// are no longer needed and are thus removed.
(0, removeExports_1.default)(preprocessedProgram);
return preprocessedProgram;
};
exports.default = defaultBundler;
//# sourceMappingURL=bundler.js.map