CODEBASE: Expand lint rules, and Aliases are stored as maps (#501)

This commit is contained in:
Snarling
2023-05-05 03:55:59 -04:00
committed by GitHub
parent d25254caf1
commit ebae35b1fb
202 changed files with 905 additions and 1110 deletions
+37 -45
View File
@@ -36,47 +36,51 @@ const specialReferenceWHILE = "__SPECIAL_referenceWhile";
// The global scope of a script is registered under this key during parsing.
const memCheckGlobalKey = ".__GLOBAL__";
/** Function for getting a function's ram cost, either from the ramcost function (singularity) or the static cost */
function getNumericCost(cost: number | (() => number)): number {
return typeof cost === "function" ? cost() : cost;
}
/**
* Parses code into an AST and walks through it recursively to calculate
* RAM usage. Also accounts for imported modules.
* @param otherScripts - All other scripts on the server. Used to account for imported scripts
* @param code - The code being parsed */
function parseOnlyRamCalculate(otherScripts: Map<ScriptFilePath, Script>, code: string, ns1?: boolean): RamCalculation {
try {
/**
* Maps dependent identifiers to their dependencies.
*
* The initial identifier is __SPECIAL_INITIAL_MODULE__.__GLOBAL__.
* It depends on all the functions declared in the module, all the global scopes
* of its imports, and any identifiers referenced in this global scope. Each
* function depends on all the identifiers referenced internally.
* We walk the dependency graph to calculate RAM usage, given that some identifiers
* reference Netscript functions which have a RAM cost.
*/
let dependencyMap: { [key: string]: string[] } = {};
/**
* Maps dependent identifiers to their dependencies.
*
* The initial identifier is __SPECIAL_INITIAL_MODULE__.__GLOBAL__.
* It depends on all the functions declared in the module, all the global scopes
* of its imports, and any identifiers referenced in this global scope. Each
* function depends on all the identifiers referenced internally.
* We walk the dependency graph to calculate RAM usage, given that some identifiers
* reference Netscript functions which have a RAM cost.
*/
let dependencyMap: Record<string, string[]> = {};
// Scripts we've parsed.
const completedParses = new Set();
// Scripts we've parsed.
const completedParses = new Set();
// Scripts we've discovered that need to be parsed.
const parseQueue: string[] = [];
// Scripts we've discovered that need to be parsed.
const parseQueue: string[] = [];
// Parses a chunk of code with a given module name, and updates parseQueue and dependencyMap.
function parseCode(code: string, moduleName: string): void {
const result = parseOnlyCalculateDeps(code, moduleName);
completedParses.add(moduleName);
// Parses a chunk of code with a given module name, and updates parseQueue and dependencyMap.
function parseCode(code: string, moduleName: string): void {
const result = parseOnlyCalculateDeps(code, moduleName);
completedParses.add(moduleName);
// Add any additional modules to the parse queue;
for (let i = 0; i < result.additionalModules.length; ++i) {
if (!completedParses.has(result.additionalModules[i])) {
parseQueue.push(result.additionalModules[i]);
}
// Add any additional modules to the parse queue;
for (let i = 0; i < result.additionalModules.length; ++i) {
if (!completedParses.has(result.additionalModules[i])) {
parseQueue.push(result.additionalModules[i]);
}
// Splice all the references in
dependencyMap = Object.assign(dependencyMap, result.dependencyMap);
}
// Splice all the references in
dependencyMap = Object.assign(dependencyMap, result.dependencyMap);
}
try {
// Parse the initial module, which is the "main" script that is being run
const initialModule = "__SPECIAL_INITIAL_MODULE__";
parseCode(code, initialModule);
@@ -141,16 +145,6 @@ function parseOnlyRamCalculate(otherScripts: Map<ScriptFilePath, Script>, code:
// Check if this identifier is a function in the workerScript environment.
// If it is, then we need to get its RAM cost.
try {
function applyFuncRam(cost: number | (() => number)): number {
if (typeof cost === "number") {
return cost;
} else if (typeof cost === "function") {
return cost();
} else {
return 0;
}
}
// Only count each function once
if (loadedFns[ref]) {
continue;
@@ -176,7 +170,7 @@ function parseOnlyRamCalculate(otherScripts: Map<ScriptFilePath, Script>, code:
};
const details = findFunc("", RamCosts, ref);
const fnRam = applyFuncRam(details?.func ?? 0);
const fnRam = getNumericCost(details?.func ?? 0);
ram += fnRam;
detailedCosts.push({ type: "fn", name: details?.refDetail ?? "", cost: fnRam });
} catch (error) {
@@ -237,9 +231,7 @@ export function checkInfiniteLoop(code: string): number {
}
interface ParseDepsResult {
dependencyMap: {
[key: string]: Set<string> | undefined;
};
dependencyMap: Record<string, Set<string> | undefined>;
additionalModules: string[];
}
@@ -254,12 +246,12 @@ function parseOnlyCalculateDeps(code: string, currentModule: string): ParseDepsR
// Everything from the global scope goes in ".". Everything else goes in ".function", where only
// the outermost layer of functions counts.
const globalKey = currentModule + memCheckGlobalKey;
const dependencyMap: { [key: string]: Set<string> | undefined } = {};
const dependencyMap: Record<string, Set<string> | undefined> = {};
dependencyMap[globalKey] = new Set<string>();
// If we reference this internal name, we're really referencing that external name.
// Filled when we import names from other modules.
const internalToExternal: { [key: string]: string | undefined } = {};
const internalToExternal: Record<string, string | undefined> = {};
const additionalModules: string[] = [];