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[] = [];
+6 -4
View File
@@ -62,8 +62,8 @@ export class RunningScript {
// hostname of the server on which this script is running
server = "";
// Cached key for ByArgs lookups
scriptKey: ScriptKey = "";
// Cached key for ByArgs lookups. Will be overwritten by a correct ScriptKey in fromJSON or constructor
scriptKey = "" as ScriptKey;
// Number of threads that this script is running with
threads = 1 as PositiveInteger;
@@ -72,7 +72,7 @@ export class RunningScript {
temporary = false;
// Script urls for the current running script for translating urls back to file names in errors
dependencies: Map<ScriptURL, Script> = new Map();
dependencies = new Map<ScriptURL, Script>();
constructor(script?: Script, ramUsage?: number, args: ScriptArg[] = []) {
if (!script) return;
@@ -145,7 +145,9 @@ export class RunningScript {
// Initializes a RunningScript Object from a JSON save state
static fromJSON(value: IReviverValue): RunningScript {
return Generic_fromJSON(RunningScript, value.data, includedProperties);
const runningScript = Generic_fromJSON(RunningScript, value.data, includedProperties);
if (!runningScript.scriptKey) runningScript.scriptKey = scriptKey(runningScript.filename, runningScript.args);
return runningScript;
}
}
const includedProperties = getKeyList(RunningScript, { removedKeys: ["logs", "dependencies", "logUpd", "pid"] });
+2 -2
View File
@@ -21,13 +21,13 @@ export class Script implements ContentFile {
// Runtime data that only exists when the script has been initiated. Cleared when script or a dependency script is updated.
mod: LoadedModule | null = null;
/** Scripts that directly import this one. Stored so we can invalidate these dependent scripts when this one is invalidated. */
dependents: Set<Script> = new Set();
dependents = new Set<Script>();
/**
* Scripts that we directly or indirectly import, including ourselves.
* Stored only so RunningScript can use it, to translate urls in error messages.
* Because RunningScript uses the reference directly (to reduce object copies), it must be immutable.
*/
dependencies: Map<ScriptURL, Script> = new Map();
dependencies = new Map<ScriptURL, Script>();
get content() {
return this.code;
+2 -2
View File
@@ -29,7 +29,7 @@ export function scriptCalculateOfflineProduction(runningScript: RunningScript):
// Grow
for (const hostname of Object.keys(runningScript.dataMap)) {
if (runningScript.dataMap.hasOwnProperty(hostname)) {
if (Object.hasOwn(runningScript.dataMap, hostname)) {
if (runningScript.dataMap[hostname][2] == 0 || runningScript.dataMap[hostname][2] == null) {
continue;
}
@@ -60,7 +60,7 @@ export function scriptCalculateOfflineProduction(runningScript: RunningScript):
// Weaken
for (const hostname of Object.keys(runningScript.dataMap)) {
if (runningScript.dataMap.hasOwnProperty(hostname)) {
if (Object.hasOwn(runningScript.dataMap, hostname)) {
if (runningScript.dataMap[hostname][3] == 0 || runningScript.dataMap[hostname][3] == null) {
continue;
}