mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-23 09:42:53 +02:00
Implemented several optimizations - running scripts dont keep track of script refs or a map of ALL servers. Not completely tested yet
This commit is contained in:
+8
-696
@@ -13,692 +13,7 @@ import {arrayToString} from "../utils/helpers/arrayToString
|
||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||
import {isString} from "../utils/helpers/isString";
|
||||
|
||||
var Promise = require("bluebird");
|
||||
|
||||
Promise.config({
|
||||
warnings: false,
|
||||
longStackTraces: false,
|
||||
cancellation: true,
|
||||
monitoring: false
|
||||
});
|
||||
/* Evaluator
|
||||
* Evaluates/Interprets the Abstract Syntax Tree generated by Acorns parser
|
||||
*
|
||||
* Returns a promise
|
||||
*/
|
||||
function evaluate(exp, workerScript) {
|
||||
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
if (exp == null) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error: NULL expression", exp));
|
||||
}
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
switch (exp.type) {
|
||||
case "BlockStatement":
|
||||
case "Program":
|
||||
var evaluateProgPromise = evaluateProg(exp, workerScript, 0); //TODO: make every block/program use individual enviroment
|
||||
return evaluateProgPromise.then(function(w) {
|
||||
return Promise.resolve(workerScript);
|
||||
}).catch(function(e) {
|
||||
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
|
||||
return Promise.reject(e);
|
||||
} else if (isString(e)) {
|
||||
workerScript.errorMessage = e;
|
||||
return Promise.reject(workerScript);
|
||||
} else if (e instanceof WorkerScript) {
|
||||
return Promise.reject(e);
|
||||
} else {
|
||||
return Promise.reject(workerScript);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "Literal":
|
||||
return Promise.resolve(exp.value);
|
||||
break;
|
||||
case "Identifier":
|
||||
//Javascript constructor() method can be used as an exploit to run arbitrary code
|
||||
if (exp.name == "constructor") {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it.", exp));
|
||||
}
|
||||
|
||||
if (!(exp.name in env.vars)){
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not defined", exp));
|
||||
}
|
||||
return Promise.resolve(env.get(exp.name))
|
||||
break;
|
||||
case "ExpressionStatement":
|
||||
return evaluate(exp.expression, workerScript);
|
||||
break;
|
||||
case "ArrayExpression":
|
||||
var argPromises = exp.elements.map(function(arg) {
|
||||
return evaluate(arg, workerScript);
|
||||
});
|
||||
return Promise.all(argPromises).then(function(array) {
|
||||
return Promise.resolve(array)
|
||||
});
|
||||
break;
|
||||
case "CallExpression":
|
||||
return evaluate(exp.callee, workerScript).then(function(func) {
|
||||
return Promise.map(exp.arguments, function(arg) {
|
||||
return evaluate(arg, workerScript);
|
||||
}).then(function(args) {
|
||||
if (func instanceof Node) { //Player-defined function
|
||||
//Create new Environment for the function
|
||||
//Should be automatically garbage collected...
|
||||
var funcEnv = env.extend();
|
||||
|
||||
//Define function arguments in this new environment
|
||||
for (var i = 0; i < func.params.length; ++i) {
|
||||
var arg;
|
||||
if (i >= args.length) {
|
||||
arg = null;
|
||||
} else {
|
||||
arg = args[i];
|
||||
}
|
||||
funcEnv.def(func.params[i].name, arg);
|
||||
}
|
||||
|
||||
//Create a new WorkerScript for this function evaluation
|
||||
var funcWorkerScript = new WorkerScript(workerScript.scriptRef);
|
||||
funcWorkerScript.serverIp = workerScript.serverIp;
|
||||
funcWorkerScript.env = funcEnv;
|
||||
workerScript.fnWorker = funcWorkerScript;
|
||||
|
||||
return evaluate(func.body, funcWorkerScript).then(function(res) {
|
||||
//If the function finished successfuly, that means there
|
||||
//was no return statement since a return statement rejects. So resolve to null
|
||||
workerScript.fnWorker = null;
|
||||
return Promise.resolve(null);
|
||||
}).catch(function(e) {
|
||||
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
|
||||
//Return statement from function
|
||||
return Promise.resolve(e[1]);
|
||||
workerScript.fnWorker = null;
|
||||
} else if (isString(e)) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
|
||||
} else if (e instanceof WorkerScript) {
|
||||
//Parse out the err message from the WorkerScript and re-reject
|
||||
var errorMsg = e.errorMessage;
|
||||
var errorTextArray = errorMsg.split("|");
|
||||
if (errorTextArray.length === 4) {
|
||||
errorMsg = errorTextArray[3];
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, errorMsg));
|
||||
} else {
|
||||
if (env.stopFlag) {
|
||||
return Promise.reject(workerScript);
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error in one of your functions. Could not identify which function"));
|
||||
}
|
||||
}
|
||||
} else if (e instanceof Error) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e.toString()));
|
||||
}
|
||||
});
|
||||
} else if (exp.callee.type === "MemberExpression"){
|
||||
return evaluate(exp.callee.object, workerScript).then(function(object) {
|
||||
try {
|
||||
if (func === "NETSCRIPTFOREACH") {
|
||||
return evaluateForeach(object, args, workerScript).then(function(res) {
|
||||
return Promise.resolve(res);
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
}
|
||||
var res = func.apply(object,args);
|
||||
return Promise.resolve(res);
|
||||
} catch (e) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e, exp));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
var out = func.apply(null,args);
|
||||
if (out instanceof Promise){
|
||||
return out.then(function(res) {
|
||||
return Promise.resolve(res)
|
||||
}).catch(function(e) {
|
||||
if (isScriptErrorMessage(e)) {
|
||||
//Functions don't have line number appended in error message, so add it
|
||||
var num = getErrorLineNumber(exp, workerScript);
|
||||
e += " (Line " + num + ")";
|
||||
}
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(out);
|
||||
}
|
||||
} catch (e) {
|
||||
if (isScriptErrorMessage(e)) {
|
||||
if (isScriptErrorMessage(e)) {
|
||||
//Functions don't have line number appended in error message, so add it
|
||||
var num = getErrorLineNumber(exp, workerScript);
|
||||
e += " (Line " + num + ")";
|
||||
}
|
||||
return Promise.reject(e);
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e, exp));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
case "MemberExpression":
|
||||
return evaluate(exp.object, workerScript).then(function(object) {
|
||||
if (exp.computed){
|
||||
return evaluate(exp.property, workerScript).then(function(index) {
|
||||
if (index >= object.length) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid index for arrays", exp));
|
||||
}
|
||||
return Promise.resolve(object[index]);
|
||||
}).catch(function(e) {
|
||||
if (e instanceof WorkerScript || isScriptErrorMessage(e)) {
|
||||
return Promise.reject(e);
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid MemberExpression", exp));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (exp.property.name === "constructor") {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it.", exp));
|
||||
}
|
||||
if (object != null && object instanceof Array && exp.property.name === "forEach") {
|
||||
return "NETSCRIPTFOREACH";
|
||||
}
|
||||
try {
|
||||
return Promise.resolve(object[exp.property.name])
|
||||
} catch (e) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to get property: " + e.toString(), exp));
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "LogicalExpression":
|
||||
case "BinaryExpression":
|
||||
return evalBinary(exp, workerScript);
|
||||
break;
|
||||
case "UnaryExpression":
|
||||
return evalUnary(exp, workerScript);
|
||||
break;
|
||||
case "AssignmentExpression":
|
||||
return evalAssignment(exp, workerScript);
|
||||
break;
|
||||
case "VariableDeclaration":
|
||||
return evalVariableDeclaration(exp, workerScript);
|
||||
break;
|
||||
case "UpdateExpression":
|
||||
if (exp.argument.type==="Identifier"){
|
||||
if (exp.argument.name in env.vars){
|
||||
if (exp.operator === "++" || exp.operator === "--") {
|
||||
switch (exp.operator) {
|
||||
case "++":
|
||||
env.set(exp.argument.name,env.get(exp.argument.name)+1);
|
||||
break;
|
||||
case "--":
|
||||
env.set(exp.argument.name,env.get(exp.argument.name)-1);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return Promise.resolve(env.get(exp.argument.name));
|
||||
}
|
||||
//Not sure what prefix UpdateExpressions there would be besides ++/--
|
||||
if (exp.prefix){
|
||||
return Promise.resolve(env.get(exp.argument.name))
|
||||
}
|
||||
switch (exp.operator){
|
||||
default:
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". You are trying to use code that is currently unsupported", exp));
|
||||
}
|
||||
return Promise.resolve(env.get(exp.argument.name))
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not defined", exp));
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "argument must be an identifier", exp));
|
||||
}
|
||||
break;
|
||||
case "EmptyStatement":
|
||||
return Promise.resolve(false);
|
||||
break;
|
||||
case "ReturnStatement":
|
||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
||||
return Promise.reject(["RETURNSTATEMENT", res]);
|
||||
});
|
||||
break;
|
||||
case "BreakStatement":
|
||||
return Promise.reject("BREAKSTATEMENT");
|
||||
break;
|
||||
case "ContinueStatement":
|
||||
return Promise.reject("CONTINUESTATEMENT");
|
||||
break;
|
||||
case "IfStatement":
|
||||
return evaluateIf(exp, workerScript);
|
||||
break;
|
||||
case "SwitchStatement":
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Switch statements are not yet implemented in Netscript", exp));
|
||||
break;
|
||||
case "WhileStatement":
|
||||
return evaluateWhile(exp, workerScript).then(function(res) {
|
||||
return Promise.resolve(res);
|
||||
}).catch(function(e) {
|
||||
if (e == "BREAKSTATEMENT" ||
|
||||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
|
||||
return Promise.resolve("whileLoopBroken");
|
||||
} else {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "ForStatement":
|
||||
return evaluate(exp.init, workerScript).then(function(expInit) {
|
||||
return evaluateFor(exp, workerScript);
|
||||
}).then(function(forLoopRes) {
|
||||
return Promise.resolve("forLoopDone");
|
||||
}).catch(function(e) {
|
||||
if (e == "BREAKSTATEMENT" ||
|
||||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
|
||||
return Promise.resolve("forLoopBroken");
|
||||
} else {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "FunctionDeclaration":
|
||||
if (exp.id && exp.id.name) {
|
||||
env.set(exp.id.name, exp);
|
||||
return Promise.resolve(true);
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid function declaration", exp));
|
||||
}
|
||||
break;
|
||||
case "ImportDeclaration":
|
||||
return evaluateImport(exp, workerScript).then(function(res) {
|
||||
return Promise.resolve(res);
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
break;
|
||||
case "ThrowStatement":
|
||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, res));
|
||||
});
|
||||
break;
|
||||
default:
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". This is currently unsupported in Netscript", exp));
|
||||
break;
|
||||
} //End switch
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
}); // End Promise
|
||||
}
|
||||
|
||||
function evalBinary(exp, workerScript){
|
||||
return evaluate(exp.left, workerScript).then(function(expLeft) {
|
||||
//Short circuiting
|
||||
if (expLeft && exp.operator === "||") {
|
||||
return Promise.resolve(expLeft);
|
||||
}
|
||||
if (!expLeft && exp.operator === "&&") {
|
||||
return Promise.resolve(expLeft);
|
||||
}
|
||||
return evaluate(exp.right, workerScript).then(function(expRight) {
|
||||
switch (exp.operator){
|
||||
case "===":
|
||||
case "==":
|
||||
return Promise.resolve(expLeft===expRight);
|
||||
break;
|
||||
case "!==":
|
||||
case "!=":
|
||||
return Promise.resolve(expLeft!==expRight);
|
||||
break;
|
||||
case "<":
|
||||
return Promise.resolve(expLeft<expRight);
|
||||
break;
|
||||
case "<=":
|
||||
return Promise.resolve(expLeft<=expRight);
|
||||
break;
|
||||
case ">":
|
||||
return Promise.resolve(expLeft>expRight);
|
||||
break;
|
||||
case ">=":
|
||||
return Promise.resolve(expLeft>=expRight);
|
||||
break;
|
||||
case "+":
|
||||
return Promise.resolve(expLeft+expRight);
|
||||
break;
|
||||
case "-":
|
||||
return Promise.resolve(expLeft-expRight);
|
||||
break;
|
||||
case "*":
|
||||
return Promise.resolve(expLeft*expRight);
|
||||
break;
|
||||
case "/":
|
||||
if (expRight === 0) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "ERROR: Divide by zero"));
|
||||
} else {
|
||||
return Promise.resolve(expLeft/expRight);
|
||||
}
|
||||
break;
|
||||
case "%":
|
||||
return Promise.resolve(expLeft%expRight);
|
||||
break;
|
||||
case "in":
|
||||
return Promise.resolve(expLeft in expRight);
|
||||
break;
|
||||
case "instanceof":
|
||||
return Promise.resolve(expLeft instanceof expRight);
|
||||
break;
|
||||
case "||":
|
||||
return Promise.resolve(expLeft || expRight);
|
||||
break;
|
||||
case "&&":
|
||||
return Promise.resolve(expLeft && expRight);
|
||||
break;
|
||||
default:
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unsupported operator: " + exp.operator));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function evalUnary(exp, workerScript){
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
||||
if (exp.operator == "!") {
|
||||
return Promise.resolve(!res);
|
||||
} else if (exp.operator == "-") {
|
||||
if (isNaN(res)) {
|
||||
return Promise.resolve(res);
|
||||
} else {
|
||||
return Promise.resolve(-1 * res);
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unimplemented unary operator: " + exp.operator));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Takes in a MemberExpression that should represent a Netscript array (possible multidimensional)
|
||||
//The return value is an array of the form:
|
||||
// [0th index (leftmost), array name, 1st index, 2nd index, ...]
|
||||
function getArrayElement(exp, workerScript) {
|
||||
var indices = [];
|
||||
return evaluate(exp.property, workerScript).then(function(idx) {
|
||||
if (isNaN(idx)) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
|
||||
} else {
|
||||
if (exp.object.name === undefined && exp.object.object) {
|
||||
return getArrayElement(exp.object, workerScript).then(function(res) {
|
||||
res.push(idx);
|
||||
indices = res;
|
||||
return Promise.resolve(indices);
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
indices.push(idx);
|
||||
indices.push(exp.object.name);
|
||||
return Promise.resolve(indices);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function evalAssignment(exp, workerScript) {
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
|
||||
if (exp.left.type != "Identifier" && exp.left.type != "MemberExpression") {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
|
||||
}
|
||||
|
||||
if (exp.operator !== "=" && !(exp.left.name in env.vars)){
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not defined"));
|
||||
}
|
||||
|
||||
return evaluate(exp.right, workerScript).then(function(expRight) {
|
||||
if (exp.left.type == "MemberExpression") {
|
||||
if (!exp.left.computed) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to an object's property. This is currently unsupported in Netscript", exp));
|
||||
}
|
||||
//Assign to array element
|
||||
//Array object designed by exp.left.object.name
|
||||
//Index designated by exp.left.property
|
||||
return getArrayElement(exp.left, workerScript).then(function(res) {
|
||||
if (!(res instanceof Array) || res.length < 2) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error evaluating array assignment. This is (probably) a bug please report to game dev"));
|
||||
}
|
||||
|
||||
//The array name is the second value
|
||||
var arrName = res.splice(1, 1);
|
||||
arrName = arrName[0];
|
||||
|
||||
var res;
|
||||
try {
|
||||
res = env.setArrayElement(arrName, res, expRight);
|
||||
} catch (e) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
|
||||
}
|
||||
return Promise.resolve(res);
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
//Other assignments
|
||||
try {
|
||||
var assign;
|
||||
switch (exp.operator) {
|
||||
case "=":
|
||||
assign = expRight; break;
|
||||
case "+=":
|
||||
assign = env.get(exp.left.name) + expRight; break;
|
||||
case "-=":
|
||||
assign = env.get(exp.left.name) - expRight; break;
|
||||
case "*=":
|
||||
assign = env.get(exp.left.name) * expRight; break;
|
||||
case "/=":
|
||||
assign = env.get(exp.left.name) / expRight; break;
|
||||
case "%=":
|
||||
assign = env.get(exp.left.name) % expRight; break;
|
||||
default:
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Bitwise assignment is not implemented"));
|
||||
}
|
||||
env.set(exp.left.name, assign);
|
||||
return Promise.resolve(assign);
|
||||
} catch (e) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function evalVariableDeclaration(exp, workerScript) {
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
|
||||
if (!(exp.declarations instanceof Array)) {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Variable declarations parsed incorrectly. This may be a syntax error"));
|
||||
}
|
||||
|
||||
if (exp.kind !== "var") {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Only 'var' declarations are currently allowed (let, const, etc. are not allowed)"));
|
||||
}
|
||||
|
||||
return Promise.all(exp.declarations.map((decl)=>{
|
||||
evalVariableDeclarator(decl, workerScript);
|
||||
})).then(function(res) {
|
||||
return Promise.resolve(res);
|
||||
});
|
||||
}
|
||||
|
||||
//A Variable Declaration contains an array of Variable Declarators
|
||||
function evalVariableDeclarator(exp, workerScript) {
|
||||
var env = workerScript.env;
|
||||
if (exp.type !== "VariableDeclarator") {
|
||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid AST Node passed into evalVariableDeclarator: " + exp.type));
|
||||
}
|
||||
if (exp.init == null) {
|
||||
env.set(exp.id.name, null);
|
||||
return Promise.resolve(null);
|
||||
} else {
|
||||
return evaluate(exp.init, workerScript).then(function(initValue) {
|
||||
env.set(exp.id.name, initValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateIf(exp, workerScript, i) {
|
||||
var env = workerScript.env;
|
||||
return evaluate(exp.test, workerScript).then(function(condRes) {
|
||||
if (condRes) {
|
||||
return evaluate(exp.consequent, workerScript).then(function(res) {
|
||||
return Promise.resolve(true);
|
||||
}, function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else if (exp.alternate) {
|
||||
return evaluate(exp.alternate, workerScript).then(function(res) {
|
||||
return Promise.resolve(true);
|
||||
}, function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve("endIf");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
|
||||
function evaluateFor(exp, workerScript) {
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
return new Promise(function(resolve, reject) {
|
||||
function recurse() {
|
||||
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
|
||||
evaluate(exp.test, workerScript).then(function(resCond) {
|
||||
if (resCond) {
|
||||
return evaluate(exp.body, workerScript).then(function(res) {
|
||||
return evaluate(exp.update, workerScript);
|
||||
}).catch(function(e) {
|
||||
if (e == "CONTINUESTATEMENT" ||
|
||||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
|
||||
//Continue statement, recurse to next iteration
|
||||
return evaluate(exp.update, workerScript).then(function(resPostloop) {
|
||||
return evaluateFor(exp, workerScript);
|
||||
}).then(function(foo) {
|
||||
return Promise.resolve("endForLoop");
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}).then(recurse, reject).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}).catch(function(e) {
|
||||
reject(e);
|
||||
});
|
||||
}
|
||||
recurse();
|
||||
});
|
||||
}
|
||||
|
||||
function evaluateForeach(arr, args, workerScript) {
|
||||
console.log("evaluateForeach called");
|
||||
if (!(arr instanceof Array)) {
|
||||
return Promise.reject("Invalid array passed into forEach");
|
||||
}
|
||||
if (!(args instanceof Array) && args.length != 1) {
|
||||
return Promise.reject("Invalid argument passed into forEach");
|
||||
}
|
||||
var func = args[0];
|
||||
if (typeof func !== "function") {
|
||||
return Promise.reject("Invalid function passed into forEach");
|
||||
}
|
||||
console.log(func);
|
||||
return new Promise(function(resolve, reject) {
|
||||
//Don't return a promise so the promise chain is broken on each recursion
|
||||
function recurse(i) {
|
||||
console.log("recurse() called with i: " + i);
|
||||
if (i >= arr.length) {
|
||||
resolve();
|
||||
} else {
|
||||
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
|
||||
console.log("About to apply function");
|
||||
var res = func.apply(null, [arr[i]]);
|
||||
console.log("Applied function");
|
||||
++i;
|
||||
Promise.resolve(res).then(function(val) {
|
||||
recurse(i);
|
||||
}, reject).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
recurse(0);
|
||||
});
|
||||
}
|
||||
|
||||
function evaluateWhile(exp, workerScript) {
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
return new Promise(function (resolve, reject) {
|
||||
function recurse() {
|
||||
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
|
||||
evaluate(exp.test, workerScript).then(function(resCond) {
|
||||
if (resCond) {
|
||||
return evaluate(exp.body, workerScript).catch(function(e) {
|
||||
if (e == "CONTINUESTATEMENT" ||
|
||||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
|
||||
//Continue statement, recurse
|
||||
return evaluateWhile(exp, workerScript).then(function(foo) {
|
||||
return Promise.resolve("endWhileLoop");
|
||||
}, function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}).then(recurse, reject).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}).catch(function(e) {
|
||||
reject(e);
|
||||
});
|
||||
}
|
||||
recurse();
|
||||
});
|
||||
}
|
||||
|
||||
function evaluateProg(exp, workerScript, index) {
|
||||
var env = workerScript.env;
|
||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
||||
if (index >= exp.body.length) {
|
||||
return Promise.resolve("progFinished");
|
||||
} else {
|
||||
//Evaluate this line of code in the prog
|
||||
//After the code finishes evaluating, evaluate the next line recursively
|
||||
return evaluate(exp.body[index], workerScript).then(function(res) {
|
||||
return evaluateProg(exp, workerScript, index + 1);
|
||||
}).then(function(res) {
|
||||
return Promise.resolve(workerScript);
|
||||
}).catch(function(e) {
|
||||
return Promise.reject(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateImport(exp, workerScript, checkingRam=false) {
|
||||
export function evaluateImport(exp, workerScript, checkingRam=false) {
|
||||
//When its checking RAM, it exports an array of nodes for each imported function
|
||||
var ramCheckRes = [];
|
||||
|
||||
@@ -808,7 +123,7 @@ function evaluateImport(exp, workerScript, checkingRam=false) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
function killNetscriptDelay(workerScript) {
|
||||
export function killNetscriptDelay(workerScript) {
|
||||
if (workerScript instanceof WorkerScript) {
|
||||
if (workerScript.delay) {
|
||||
clearTimeout(workerScript.delay);
|
||||
@@ -817,7 +132,7 @@ function killNetscriptDelay(workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
function netscriptDelay(time, workerScript) {
|
||||
export function netscriptDelay(time, workerScript) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
workerScript.delay = setTimeout(()=>{
|
||||
workerScript.delay = null;
|
||||
@@ -827,7 +142,7 @@ function netscriptDelay(time, workerScript) {
|
||||
});
|
||||
}
|
||||
|
||||
function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
||||
export function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
||||
var lineNum = "";
|
||||
if (exp != null) {
|
||||
var num = getErrorLineNumber(exp, workerScript);
|
||||
@@ -837,7 +152,7 @@ function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
||||
}
|
||||
|
||||
//Run a script from inside a script using run() command
|
||||
function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
||||
export function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
||||
//Check if the script is already running
|
||||
var runningScriptObj = findRunningScript(scriptname, args, server);
|
||||
if (runningScriptObj != null) {
|
||||
@@ -887,8 +202,8 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
function getErrorLineNumber(exp, workerScript) {
|
||||
var code = workerScript.scriptRef.scriptRef.code;
|
||||
export function getErrorLineNumber(exp, workerScript) {
|
||||
var code = workerScript.scriptRef.codeCode();
|
||||
|
||||
//Split code up to the start of the node
|
||||
try {
|
||||
@@ -899,7 +214,7 @@ function getErrorLineNumber(exp, workerScript) {
|
||||
}
|
||||
}
|
||||
|
||||
function isScriptErrorMessage(msg) {
|
||||
export function isScriptErrorMessage(msg) {
|
||||
if (!isString(msg)) {return false;}
|
||||
let splitMsg = msg.split("|");
|
||||
if (splitMsg.length != 4){
|
||||
@@ -911,6 +226,3 @@ function isScriptErrorMessage(msg) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript, evaluate,
|
||||
isScriptErrorMessage, killNetscriptDelay, evaluateImport};
|
||||
|
||||
Reference in New Issue
Block a user