Moved netscript files into src folder and renamed

This commit is contained in:
Daniel Xie
2017-05-13 02:42:25 -05:00
parent fb9e232957
commit 78c3d0d060
7 changed files with 6 additions and 6 deletions
-49
View File
@@ -1,49 +0,0 @@
/* Environment
* NetScript program environment
*/
function Environment(parent) {
this.vars = Object.create(parent ? parent.vars : null);
this.parent = parent;
this.stopFlag = false;
}
Environment.prototype = {
//Create a "subscope", which is a new new "sub-environment"
//The subscope is linked to this through its parent variable
extend: function() {
return new Environment(this);
},
//Finds the scope where the variable with the given name is defined
lookup: function(name) {
var scope = this;
while (scope) {
if (Object.prototype.hasOwnProperty.call(scope.vars, name))
return scope;
scope = scope.parent;
}
},
//Get the current value of a variable
get: function(name) {
if (name in this.vars)
return this.vars[name];
throw new Error("Undefined variable " + name);
},
//Sets the value of a variable in any scope
set: function(name, value) {
var scope = this.lookup(name);
// let's not allow defining globals from a nested environment
//
// If scope is null (aka existing variable with name could not be found)
// and this is NOT the global scope, throw error
if (!scope && this.parent)
throw new Error("Undefined variable " + name);
return (scope || this).vars[name] = value;
},
//Creates (or overwrites) a variable in the current scope
def: function(name, value) {
return this.vars[name] = value;
}
};
-917
View File
@@ -1,917 +0,0 @@
/* Evaluator
* Evaluates the Abstract Syntax Tree for Netscript
* generated by the Parser class
*/
// Evaluator should return a Promise, so that any call to evaluate() can just
//wait for that promise to finish before continuing
function evaluate(exp, workerScript) {
var env = workerScript.env;
if (exp == null) {
return new Promise(function(resolve, reject) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Error: NULL expression");
});
}
switch (exp.type) {
case "num":
case "str":
case "bool":
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
resolve(exp.value);
});
break;
case "var":
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
try {
resolve(env.get(exp.value));
} catch (e) {
throw new Error("|" + workerScript.serverIp + "|" + workerScript.name + "|" + e.toString());
}
});
break;
//Can currently only assign to "var"s
case "assign":
return new Promise(function(resolve, reject) {
console.log("Evaluating assign");
if (env.stopFlag) {reject(workerScript);}
if (exp.left.type != "var")
reject("|" + workerScript.serverIp + "|" + workerScript.name + "| Cannot assign to " + JSON.stringify(exp.left));
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
resolve(expRight);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime)
});
p.then(function(expRight) {
try {
env.set(exp.left.value, expRight);
} catch (e) {
console.log("here");
throw new Error("|" + workerScript.serverIp + "|" + workerScript.name + "|" + e.toString());
}
resolve(false); //Return false so this doesnt cause loops/ifs to evaluate
}, function(e) {
reject(e);
});
});
case "binary":
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
var pLeft = new Promise(function(resolve, reject) {
setTimeout(function() {
var promise = evaluate(exp.left, workerScript);
promise.then(function(valLeft) {
resolve(valLeft);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pLeft.then(function(valLeft) {
var pRight = new Promise(function(resolve, reject) {
setTimeout(function() {
var promise = evaluate(exp.right, workerScript);
promise.then(function(valRight) {
resolve([valLeft, valRight]);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pRight.then(function(args) {
try {
resolve(apply_op(exp.operator, args[0], args[1]));
} catch (e) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|" + e.toString());
}
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
});
break;
//TODO
case "if":
return new Promise(function(resolve, reject) {
console.log("Evaluating if");
var numConds = exp.cond.length;
var numThens = exp.then.length;
if (numConds == 0 || numThens == 0 || numConds != numThens) {
console.log("Number of ifs and conds dont match. Rejecting");
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Number of conds and thens in if structure don't match (or there are none)");
}
var evalIfPromise = evaluateIf(exp, workerScript, 0);
evalIfPromise.then(function(res) {
if (res) {
//One of the if/elif statements evaluated to true
console.log("done with if");
resolve("if statement done");
} else {
//None of the if/elif statements were true. Evaluate else if there is one
if (exp.else) {
var elseEval = evaluate(exp.else, workerScript);
elseEval.then(function(res) {
console.log("if statement done with else");
resolve("if statement done with else");
}, function(e) {
reject(e);
});
} else {
console.log("no else statement, resolving");
resolve("if statement done");
}
}
}, function(e) {
reject(e);
});
});
break;
case "for":
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
console.log("for loop encountered in evaluator");
workerScript.scriptRef.log("Entering for loop");
var pInit = new Promise(function(resolve, reject) {
setTimeout(function() {
var resInit = evaluate(exp.init, workerScript);
resInit.then(function(foo) {
resolve(resInit);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pInit.then(function(expInit) {
var pForLoop = evaluateFor(exp, workerScript);
pForLoop.then(function(forLoopRes) {
resolve("forLoopDone");
workerScript.scriptRef.log("Exiting for loop");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
});
break;
case "while":
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
var pEvaluateWhile = evaluateWhile(exp, workerScript);
pEvaluateWhile.then(function(whileLoopRes) {
resolve("whileLoopDone");
}, function(e) {
reject(e);
});
});
break;
case "prog":
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
var evaluateProgPromise = evaluateProg(exp, workerScript, 0);
evaluateProgPromise.then(function(w) {
resolve(workerScript);
}, function(e) {
workerScript.errorMessage = e.toString();
reject(workerScript);
});
});
break;
/* Currently supported function calls:
* hack(server)
* sleep(N) - sleep N seconds
* print(x) - Prints a variable or constant
* grow(server)
* nuke(server)
* brutessh(server)
* ftpcrack(server)
* relaysmtp(server)
* httpworm(server)
* sqlinject(server)
*/
case "call":
//Define only valid function calls here, like hack() and stuff
//var func = evaluate(exp.func, env);
//return func.apply(null, exp.args.map(function(arg){
// return evaluate(arg, env);
//}));
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (exp.func.value == "hack") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Hack() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into hack() command");
workerScript.scriptRef.log("Cannot hack(). Invalid IP or hostname passed in: " + ip + ". Stopping...");
return;
}
//Calculate the hacking time
var hackingTime = scriptCalculateHackingTime(server); //This is in seconds
//No root access or skill level too low
if (server.hasAdminRights == false) {
workerScript.scriptRef.log("Cannot hack this server (" + server.hostname + ") because user does not have root access");
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Script crashed because it did not have root access to " + server.hostname);
return;
}
if (server.requiredHackingSkill > Player.hacking_skill) {
workerScript.scriptRef.log("Cannot hack this server (" + server.hostaname + ") because user does not have root access");
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Script crashed because player's hacking skill is not high enough to hack " + server.hostname);
return;
}
workerScript.scriptRef.log("Attempting to hack " + ip + " in " + hackingTime.toFixed(3) + " seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
console.log("Hacking " + server.hostname + " after " + hackingTime.toString() + " seconds.");
setTimeout(function() {
if (env.stopFlag) {reject(workerScript);}
var hackChance = scriptCalculateHackingChance(server);
var rand = Math.random();
var expGainedOnSuccess = scriptCalculateExpGain(server);
var expGainedOnFailure = (expGainedOnSuccess / 4);
if (rand < hackChance) { //Success!
if (env.stopFlag) {reject(workerScript); return;}
var moneyGained = scriptCalculatePercentMoneyHacked(server);
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
//Safety check
if (moneyGained <= 0) {moneyGained = 0;}
server.moneyAvailable -= moneyGained;
Player.gainMoney(moneyGained);
workerScript.scriptRef.onlineMoneyMade += moneyGained;
console.log("About to add to moneystolenmap for " + server.hostname);
workerScript.scriptRef.moneyStolenMap[server.ip] += moneyGained;
Player.gainHackingExp(expGainedOnSuccess);
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
console.log("Script successfully hacked " + server.hostname + " for $" + formatNumber(moneyGained, 2) + " and " + formatNumber(expGainedOnSuccess, 4) + " exp");
workerScript.scriptRef.log("Script SUCCESSFULLY hacked " + server.hostname + " for $" + formatNumber(moneyGained, 2) + " and " + formatNumber(expGainedOnSuccess, 4) + " exp");
resolve("Hack success");
} else {
if (env.stopFlag) {reject(workerScript); return;}
//Player only gains 25% exp for failure? TODO Can change this later to balance
Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
console.log("Script unsuccessful to hack " + server.hostname + ". Gained " + formatNumber(expGainedOnFailure, 4) + " exp");
workerScript.scriptRef.log("Script FAILED to hack " + server.hostname + ". Gained " + formatNumber(expGainedOnFailure, 4) + " exp");
resolve("Hack failure");
}
}, hackingTime * 1000);
});
p.then(function(res) {
resolve("hackExecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "sleep") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|sleep() call has incorrect number of arguments. Takes 1 argument.");
}
var sleepTimePromise = evaluate(exp.args[0], workerScript);
sleepTimePromise.then(function(sleepTime) {
workerScript.scriptRef.log("Sleeping for " + sleepTime + " milliseconds");
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve("foo");
}, sleepTime);
});
p.then(function(res) {
resolve("sleepExecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e)
});
} else if (exp.func.value == "print") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|print() call has incorrect number of arguments. Takes 1 argument");
}
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.args[0], workerScript);
evaluatePromise.then(function(res) {
resolve(res);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
p.then(function(res) {
workerScript.scriptRef.log(res.toString());
resolve("printExecuted");
}, function(e) {
reject(e);
});
} else if (exp.func.value == "grow") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|grow() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into grow() command");
workerScript.scriptRef.log("Cannot grow(). Invalid IP or hostname passed in: " + ip);
return;
}
//No root access or skill level too low
if (server.hasAdminRights == false) {
workerScript.scriptRef.log("Cannot grow this server (" + server.hostname + ") because user does not have root access");
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Script crashed because it did not have root access to " + server.hostname);
return;
}
workerScript.scriptRef.log("Calling grow() on server " + server.hostname + " in 120 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
var growthPercentage = processSingleServerGrowth(server, 450);
resolve(growthPercentage);
}, 120 * 1000); //grow() takes flat 2 minutes right now
});
p.then(function(growthPercentage) {
resolve("hackExecuted");
workerScript.scriptRef.log("Using grow(), the money available on " + server.hostname + " was grown by " + (growthPercentage*100 - 100).toFixed(6) + "%. Gained 1 hacking exp");
Player.gainHackingExp(1);
workerScript.scriptRef.onlineExpGained += 1;
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "nuke") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|nuke() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into nuke() command");
workerScript.scriptRef.log("Cannot nuke(). Invalid IP or hostname passed in: " + ip);
return;
}
if (!Player.hasProgram(Programs.NukeProgram)) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Player does not have NUKE program on home computer");
return;
}
if (server.openPortCount < server.numOpenPortsRequired) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Not enough ports opened to use NUKE.exe virus");
return;
}
workerScript.scriptRef.log("Running NUKE.exe on server " + server.hostname + " in 5 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (server.hasAdminRights) {
workerScript.scriptRef.log("Already have root access to " + server.hostname);
} else {
server.hasAdminRights = true;
workerScript.scriptRef.log("Executed NUKE.exe virus on " + server.hostname + " to gain root access");
}
resolve("nuke done");
}, 5 * 1000);
});
p.then(function(res) {
resolve("nukeExecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "brutessh") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|brutessh() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into brutessh() command");
workerScript.scriptRef.log("Cannot brutessh(). Invalid IP or hostname passed in: " + ip);
return;
}
if (!Player.hasProgram(Programs.BruteSSHProgram)) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Player does not have BruteSSH.exe program on home computer");
return;
}
workerScript.scriptRef.log("Running BruteSSH.exe on server " + server.hostname + " in 10 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (!server.sshPortOpen) {
workerScript.scriptRef.log("Executed BruteSSH.exe virus on " + server.hostname + " to open SSH port (22)");
server.sshPortOpen = true;
++server.openPortCount;
} else {
workerScript.scriptRef.log("SSH Port (22) already opened on " + server.hostname);
}
resolve("brutessh done");
}, 10 * 1000);
});
p.then(function(res) {
resolve("bruteSSHExecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "ftpcrack") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|ftpcrack() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into ftpcrack() command");
workerScript.scriptRef.log("Cannot ftpcrack(). Invalid IP or hostname passed in: " + ip);
return;
}
if (!Player.hasProgram(Programs.FTPCrackProgram)) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Player does not have FTPCrack.exe program on home computer");
return;
}
workerScript.scriptRef.log("Running FTPCrack.exe on server " + server.hostname + " in 15 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (!server.ftpPortOpen) {
workerScript.scriptRef.log("Executed FTPCrack.exe virus on " + server.hostname + " to open FTP port (21)");
server.ftpPortOpen = true;
++server.openPortCount;
} else {
workerScript.scriptRef.log("FTP Port (21) already opened on " + server.hostname);
}
resolve("ftpcrack done");
}, 15 * 1000);
});
p.then(function(res) {
resolve("ftpcrackexecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "relaysmtp") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|relaysmtp() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into relaysmtp() command");
workerScript.scriptRef.log("Cannot relaysmtp(). Invalid IP or hostname passed in: " + ip);
return;
}
if (!Player.hasProgram(Programs.RelaySMTPProgram)) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Player does not have relaySMTP.exe program on home computer");
return;
}
workerScript.scriptRef.log("Running relaySMTP.exe on server " + server.hostname + " in 20 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (!server.smtpPortOpen) {
workerScript.scriptRef.log("Executed relaySMTP.exe virus on " + server.hostname + " to open SMTP port (25)");
server.smtpPortOpen = true;
++server.openPortCount;
} else {
workerScript.scriptRef.log("SMTP Port (25) already opened on " + server.hostname);
}
resolve("relaysmtp done");
}, 20 * 1000);
});
p.then(function(res) {
resolve("relaysmtpexecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "httpworm") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|httpworm() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into relaysmtp() command");
workerScript.scriptRef.log("Cannot httpworm(). Invalid IP or hostname passed in: " + ip);
return;
}
if (!Player.hasProgram(Programs.HTTPWormProgram)) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Player does not have HTTPWorm.exe program on home computer");
return;
}
workerScript.scriptRef.log("Running HTTPWorm.exe on server " + server.hostname + " in 25 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (!server.httpPortOpen) {
workerScript.scriptRef.log("Executed HTTPWorm.exe virus on " + server.hostname + " to open HTTP port (25)");
server.httpPortOpen = true;
++server.openPortCount;
} else {
workerScript.scriptRef.log("HTTP Port (80) already opened on " + server.hostname);
}
resolve("httpworm done");
}, 25 * 1000);
});
p.then(function(res) {
resolve("HTTPWormexecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else if (exp.func.value == "sqlinject") {
if (exp.args.length != 1) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|sqlinject() call has incorrect number of arguments. Takes 1 argument");
}
var ipPromise = evaluate(exp.args[0], workerScript);
ipPromise.then(function(ip) {
var server = getServer(ip);
if (server == null) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Invalid IP or hostname passed into sqlinject() command");
workerScript.scriptRef.log("Cannot sqlinject(). Invalid IP or hostname passed in: " + ip);
return;
}
if (!Player.hasProgram(Programs.SQLInjectProgram)) {
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Player does not have SQLInject.exe program on home computer");
return;
}
workerScript.scriptRef.log("Running SQLInject.exe on server " + server.hostname + " in 30 seconds");
var p = new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
setTimeout(function() {
if (!server.sqlPortOpen) {
workerScript.scriptRef.log("Executed SQLInject.exe virus on " + server.hostname + " to open SQL port (1433)");
server.sqlPortOpen = true;
++server.openPortCount;
} else {
workerScript.scriptRef.log("SQL Port (1433) already opened on " + server.hostname);
}
resolve("sqlinject done");
}, 30 * 1000);
});
p.then(function(res) {
resolve("sqlinjectexecuted");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
}
}, CONSTANTS.CodeInstructionRunTime);
});
break;
default:
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|Can't evaluate type " + exp.type);
}
}
//Returns true if any of the if statements evaluated, false otherwise. Therefore, the else statement
//should evaluate if this returns false
function evaluateIf(exp, workerScript, i) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (i >= exp.cond.length) {
//Catch out of bounds errors
resolve(false);
} else {
console.log("Evaluating cond " + i + " in if");
var cond = evaluate(exp.cond[i], workerScript);
cond.then(function(condRes) {
console.log("cond evaluated to: " + condRes);
if (condRes) {
console.log("Evaluating then: " + exp.then[i]);
var evalThen = evaluate(exp.then[i], workerScript);
evalThen.then(function(res) {
console.log("If statement done");
resolve(true);
}, function(e) {
reject(e);
});
} else {
//If this if statement isnt true, go on the next elif, or recursively resolve
if (i == exp.cond.length-1) {
resolve(false);
} else {
var recursiveCall = evaluateIf(exp, workerScript, i+1);
recursiveCall.then(function(res) {
resolve(res);
}, function(e) {
reject(e);
});
}
}
}, function(e) {
reject(e);
});
}
});
}
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
function evaluateFor(exp, workerScript) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
var pCond = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.cond, workerScript);
evaluatePromise.then(function(resCond) {
resolve(resCond);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pCond.then(function(resCond) {
if (resCond) {
//Run the for loop code
var pCode = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.code, workerScript);
evaluatePromise.then(function(resCode) {
resolve(resCode);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
//After the code executes make a recursive call
pCode.then(function(resCode) {
var pPostLoop = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.postloop, workerScript);
evaluatePromise.then(function(foo) {
resolve("postLoopFinished");
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pPostLoop.then(function(resPostloop) {
var recursiveCall = evaluateFor(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endForLoop");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else {
resolve("endForLoop"); //Doesn't need to resolve to any particular value
}
}, function(e) {
reject(e);
});
});
}
function evaluateWhile(exp, workerScript) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
var pCond = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.cond, workerScript);
evaluatePromise.then(function(resCond) {
resolve(resCond);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pCond.then(function(resCond) {
if (resCond) {
//Run the while loop code
var pCode = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.code, workerScript);
evaluatePromise.then(function(resCode) {
resolve(resCode);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
//After the code executes make a recursive call
pCode.then(function(resCode) {
var recursiveCall = evaluateWhile(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endWhileLoop");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
} else {
resolve("endWhileLoop"); //Doesn't need to resolve to any particular value
}
}, function(e) {
reject(e);
});
});
}
function evaluateProg(exp, workerScript, index) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript);}
if (index >= exp.prog.length) {
resolve("progFinished");
} else {
//Evaluate this line of code in the prog
var code = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.prog[index], workerScript);
evaluatePromise.then(function(evalRes) {
resolve(evalRes);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
//After the code finishes evaluating, evaluate the next line recursively
code.then(function(codeRes) {
var nextLine = evaluateProg(exp, workerScript, index + 1);
nextLine.then(function(nextLineRes) {
resolve(workerScript);
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
}
});
}
function apply_op(op, a, b) {
function num(x) {
if (typeof x != "number")
throw new Error("Expected number but got " + x);
return x;
}
function div(x) {
if (num(x) == 0)
throw new Error("Divide by zero");
return x;
}
switch (op) {
case "+": return num(a) + num(b);
case "-": return num(a) - num(b);
case "*": return num(a) * num(b);
case "/": return num(a) / div(b);
case "%": return num(a) % div(b);
case "&&": return a !== false && b;
case "||": return a !== false ? a : b;
case "<": return num(a) < num(b);
case ">": return num(a) > num(b);
case "<=": return num(a) <= num(b);
case ">=": return num(a) >= num(b);
case "==": return a === b;
case "!=": return a !== b;
}
throw new Error("Can't apply operator " + op);
}
function isScriptErrorMessage(msg) {
splitMsg = msg.split("|");
if (splitMsg.length != 4){
return false;
}
var ip = splitMsg[1];
if (!isValidIPAddress(ip)) {
return false;
}
return true;
}
//The same as Player's calculateHackingChance() function but takes in the server as an argument
function scriptCalculateHackingChance(server) {
var difficultyMult = (100 - server.hackDifficulty) / 100;
var skillMult = (2 * Player.hacking_chance_mult * Player.hacking_skill);
var skillChance = (skillMult - server.requiredHackingSkill) / skillMult;
var chance = skillChance * difficultyMult;
if (chance < 0) {return 0;}
else {return chance;}
}
//The same as Player's calculateHackingTime() function but takes in the server as an argument
function scriptCalculateHackingTime(server) {
var difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50);
var hackingTime = skillFactor * Player.hacking_speed_mult * 5; //This is in seconds
return hackingTime;
}
//The same as Player's calculateExpGain() function but takes in the server as an argument
function scriptCalculateExpGain(server) {
return (server.hackDifficulty * Player.hacking_exp_mult);
}
//The same as Player's calculatePercentMoneyHacked() function but takes in the server as an argument
function scriptCalculatePercentMoneyHacked(server) {
var difficultyMult = (100 - server.hackDifficulty) / 100;
var skillMult = (Player.hacking_skill - (server.requiredHackingSkill - 1)) / Player.hacking_skill;
var percentMoneyHacked = difficultyMult * skillMult * Player.hacking_money_mult / 1000;
if (percentMoneyHacked < 0) {return 0;}
if (percentMoneyHacked > 1) {return 1;}
return percentMoneyHacked;
}
-25
View File
@@ -1,25 +0,0 @@
/* InputStream class. Creates a "stream object" that provides operations to read
* from a string. */
function InputStream(input) {
var pos = 0, line = 1, col = 0;
return {
next : next,
peek : peek,
eof : eof,
croak : croak,
};
function next() {
var ch = input.charAt(pos++);
if (ch == "\n") line++, col = 0; else col++;
return ch;
}
function peek() {
return input.charAt(pos);
}
function eof() {
return peek() == "";
}
function croak(msg) {
throw new Error(msg + " (" + line + ":" + col + ")");
}
}
-164
View File
@@ -1,164 +0,0 @@
/* Worker code, contains Netscript scripts that are actually running */
//TODO Tested For and while and generic call statements. Have not tested if statements
/* Actual Worker Code */
function WorkerScript(script) {
this.name = "";
this.running = false;
this.serverIp = null;
this.code = "";
this.env = new Environment();
this.output = "";
this.ramUsage = 0;
this.scriptRef = script;
this.errorMessage = "";
}
//Returns the server on which the workerScript is running
WorkerScript.prototype.getServer = function() {
return AllServers[this.serverIp];
}
//Array containing all scripts that are running across all servers, to easily run them all
var workerScripts = [];
//Loop through workerScripts and run every script that is not currently running
function runScriptsLoop() {
//Run any scripts that haven't been started
for (var i = 0; i < workerScripts.length; i++) {
//If it isn't running, start the script
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == false) {
try {
var ast = Parser(Tokenizer(InputStream(workerScripts[i].code)));
} catch (e) {
dialogBoxCreate("Syntax ERROR in " + workerScripts[i].name + ":", e, "", "");
workerScripts[i].env.stopFlag = true;
continue;
}
workerScripts[i].running = true;
var p = evaluate(ast, workerScripts[i]);
//Once the code finishes (either resolved or rejected, doesnt matter), set its
//running status to false
p.then(function(w) {
console.log("Stopping script " + w.name + " because it finished running naturally");
w.running = false;
w.env.stopFlag = true;
}, function(w) {
if (w instanceof Error) {
//Error text format: |serverip|scriptname|error message
var errorText = w.toString();
if (Engine.Debug) {
console.log("Error in script: " + errorText);
}
var errorTextArray = errorText.split("|");
if (errorTextArray.length != 4) {
console.log("ERROR: Something wrong with Error text in evaluator...");
console.log("Error text: " + errorText);
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: ", "Server Ip: " + serverIp, "Script name: " + scriptName, errorMsg);
//Find the corresponding workerscript and set its flags to kill it
for (var i = 0; i < workerScripts.length; ++i) {
if (workerScripts[i].serverIp == serverIp && workerScripts[i].name == scriptName) {
workerScripts[i].running = false;
workerScripts[i].env.stopFlag = true;
return;
}
}
} else if (w instanceof WorkerScript) {
if (isScriptErrorMessage(w.errorMessage)) {
var errorTextArray = w.errorMessage.split("|");
if (errorTextArray.length != 4) {
console.log("ERROR: Something wrong with Error text in evaluator...");
console.log("Error text: " + errorText);
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: ", "Server Ip: " + serverIp, "Script name: " + scriptName, errorMsg);
}
w.running = false;
w.env.stopFlag = true;
}
});
}
}
//Delete any scripts that finished or have been killed. Loop backwards bc removing
//items fucks up the indexing
for (var i = workerScripts.length - 1; i >= 0; i--) {
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == true) {
console.log("Deleting script: " + workerScripts[i].name);
//Delete script from the runningScripts array on its host serverIp
var ip = workerScripts[i].serverIp;
var name = workerScripts[i].name;
for (var j = 0; j < AllServers[ip].runningScripts.length; j++) {
if (AllServers[ip].runningScripts[j] == name) {
AllServers[ip].runningScripts.splice(j, 1);
break;
}
}
//Free RAM
AllServers[ip].ramUsed -= workerScripts[i].ramUsage;
//Delete script from workerScripts
workerScripts.splice(i, 1);
//Delete script from Active Scripts
Engine.deleteActiveScriptsItem(i);
}
}
setTimeout(runScriptsLoop, 10000);
}
//Queues a script to be killed by settings its stop flag to true. Then, the code will reject
//all of its promises recursively, and when it does so it will no longer be running.
//The runScriptsLoop() will then delete the script from worker scripts
function killWorkerScript(scriptName, serverIp) {
for (var i = 0; i < workerScripts.length; i++) {
if (workerScripts[i].name == scriptName && workerScripts[i].serverIp == serverIp) {
workerScripts[i].env.stopFlag = true;
}
}
}
//Queues a script to be run
function addWorkerScript(script, server) {
var filename = script.filename;
//Update server's ram usage
server.ramUsed += script.ramUsage;
//Create the WorkerScript
var s = new WorkerScript(script);
s.name = filename;
s.code = script.code;
s.serverIp = server.ip;
s.ramUsage = script.ramUsage;
//Add the WorkerScript to the Active Scripts list
Engine.addActiveScriptsItem(s);
//Add the WorkerScript
workerScripts.push(s);
return;
}
//Updates the online running time stat of all running scripts
function updateOnlineScriptTimes(numCycles = 1) {
var time = (numCycles * Engine._idleSpeed) / 1000; //seconds
for (var i = 0; i < workerScripts.length; ++i) {
workerScripts[i].scriptRef.onlineRunningTime += time;
}
}
runScriptsLoop();
-252
View File
@@ -1,252 +0,0 @@
/* Parser
* Creates Abstract Syntax Tree Nodes
* Operates on a stream of tokens from the Tokenizer
*/
var FALSE = {type: "bool", value: false};
function Parser(input) {
var PRECEDENCE = {
"=": 1,
"||": 2,
"&&": 3,
"<": 7, ">": 7, "<=": 7, ">=": 7, "==": 7, "!=": 7,
"+": 10, "-": 10,
"*": 20, "/": 20, "%": 20,
};
return parse_toplevel();
//Returns true if the next token is a punc type with value ch
function is_punc(ch) {
var tok = input.peek();
return tok && tok.type == "punc" && (!ch || tok.value == ch) && tok;
}
//Returns true if the next token is the kw keyword
function is_kw(kw) {
var tok = input.peek();
return tok && tok.type == "kw" && (!kw || tok.value == kw) && tok;
}
//Returns true if the next token is an op type with the given op value
function is_op(op) {
var tok = input.peek();
return tok && tok.type == "op" && (!op || tok.value == op) && tok;
}
//Checks that the next character is the given punctuation character and throws
//an error if it's not. If it is, skips over it in the input
function checkPuncAndSkip(ch) {
if (is_punc(ch)) input.next();
else input.croak("Expecting punctuation: \"" + ch + "\"");
}
//Checks that the next character is the given keyword and throws an error
//if its not. If it is, skips over it in the input
function checkKeywordAndSkip(kw) {
if (is_kw(kw)) input.next();
else input.croak("Expecting keyword: \"" + kw + "\"");
}
//Checks that the next character is the given operator and throws an error
//if its not. If it is, skips over it in the input
function checkOpAndSkip(op) {
if (is_op(op)) input.next();
else input.croak("Expecting operator: \"" + op + "\"");
}
function unexpected() {
input.croak("Unexpected token: " + JSON.stringify(input.peek()));
}
function maybe_binary(left, my_prec) {
var tok = is_op();
if (tok) {
var his_prec = PRECEDENCE[tok.value];
if (his_prec > my_prec) {
input.next();
return maybe_binary({
type : tok.value == "=" ? "assign" : "binary",
operator : tok.value,
left : left,
right : maybe_binary(parse_atom(), his_prec)
}, my_prec);
}
}
return left;
}
function delimited(start, stop, separator, parser) {
var a = [], first = true;
checkPuncAndSkip(start);
while (!input.eof()) {
if (is_punc(stop)) break;
if (first) first = false; else checkPuncAndSkip(separator);
if (is_punc(stop)) break;
a.push(parser());
}
checkPuncAndSkip(stop);
return a;
}
function parse_call(func) {
return {
type: "call",
func: func,
args: delimited("(", ")", ",", parse_expression),
};
}
function parse_varname() {
var name = input.next();
if (name.type != "var") input.croak("Expecting variable name");
return name.value;
}
/* type: "if",
* cond: [ {"type": "var", "value": "cond1"}, {"type": "var", "value": "cond2"}...]
* then: [ {"type": "var", "value": "then1"}, {"type": "var", "value": "then2"}...]
* else: {"type": "var", "value": "foo"}
*/
function parse_if() {
console.log("Parsing if token");
checkKeywordAndSkip("if");
//Conditional
var cond = parse_expression();
console.log("cond: " + cond);
//Body
var then = parse_expression();
console.log("then: " + then);
var ret = {
type: "if",
cond: [],
then: [],
};
ret.cond.push(cond);
ret.then.push(then);
// Parse all elif branches
while (is_kw("elif")) {
input.next();
var cond = parse_expression();
var then = parse_expression();
ret.cond.push(cond);
ret.then.push(then);
}
// Parse else branch, if it exists
if (is_kw("else")) {
input.next();
ret.else = parse_expression();
}
return ret;
}
/* for (init, cond, postloop) {code;}
*
* type: "for",
* init: assign node,
* cond: var node,
* postloop: assign node
* code: prog node
*/
function parse_for() {
console.log("Parsing for token");
checkKeywordAndSkip("for");
splitExpressions = delimited("(", ")", ";", parse_expression);
code = parse_expression();
if (splitExpressions.length != 3) {
throw new Error("for statement has incorrect number of arugments");
}
//TODO Check type of the init, cond, and postloop nodes
return {
type: "for",
init: splitExpressions[0],
cond: splitExpressions[1],
postloop: splitExpressions[2],
code: code
}
}
/* while (cond) {}
*
* type: "while",
* cond: var node
* code: prog node
*/
function parse_while() {
checkKeywordAndSkip("while");
var cond = parse_expression();
var code = parse_expression();
return {
type: "while",
cond: cond,
code: code
}
}
function parse_bool() {
return {
type : "bool",
value : input.next().value == "true"
};
}
function maybe_call(expr) {
expr = expr();
return is_punc("(") ? parse_call(expr) : expr;
}
function parse_atom() {
return maybe_call(function(){
if (is_punc("(")) {
input.next();
var exp = parse_expression();
checkPuncAndSkip(")");
return exp;
}
if (is_punc("{")) return parse_prog();
if (is_kw("if")) return parse_if();
if (is_kw("for")) return parse_for();
if (is_kw("while")) return parse_while();
//Note, let for loops be function calls (call node types)
if (is_kw("true") || is_kw("false")) return parse_bool();
var tok = input.next();
if (tok.type == "var" || tok.type == "num" || tok.type == "str")
return tok;
unexpected();
});
}
function parse_toplevel() {
var prog = [];
while (!input.eof()) {
prog.push(parse_expression());
if (!input.eof()) checkPuncAndSkip(";");
}
//Return the top level Abstract Syntax Tree, where the top node is a "prog" node
return { type: "prog", prog: prog };
}
function parse_prog() {
var prog = delimited("{", "}", ";", parse_expression);
if (prog.length == 0) return FALSE;
if (prog.length == 1) return prog[0];
return { type: "prog", prog: prog };
}
function parse_expression() {
return maybe_call(function(){
return maybe_binary(parse_atom(), 0);
});
}
}
-168
View File
@@ -1,168 +0,0 @@
/* Tokenizer
* Acts on top of the InputStream class. Takes in a character input stream and and parses it into tokens.
* Tokens can be accessed with peek() and next().
*
* Token types:
* {type: "punc", value: "(" } // punctuation: parens, comma, semicolon etc.
* {type: "num", value: 5 } // numbers (including floats)
* {type: "str", value: "Hello World!" } // strings
* {type: "kw", value: "for/if/" } // keywords, see defs below
* {type: "var", value: "a" } // identifiers/variables
* {type: "op", value: "!=" } // operator characters
* {type: "bool", value: "true" } // Booleans
*
*/
function Tokenizer(input) {
var current = null;
var keywords = " if elif else true false while for ";
return {
next : next,
peek : peek,
eof : eof,
croak : input.croak
}
function is_keyword(x) {
return keywords.indexOf(" " + x + " ") >= 0;
}
function is_digit(ch) {
return /[0-9]/i.test(ch);
}
//An identifier can start with any letter or an underscore
function is_id_start(ch) {
return /[a-z_]/i.test(ch);
}
function is_id(ch) {
return is_id_start(ch) || "?!-<>=0123456789".indexOf(ch) >= 0;
}
function is_op_char(ch) {
return "+-*/%=&|<>!".indexOf(ch) >= 0;
}
function is_punc(ch) {
return ",;(){}[]".indexOf(ch) >= 0;
}
function is_whitespace(ch) {
return " \t\n".indexOf(ch) >= 0;
}
function read_while(predicate) {
var str = "";
while (!input.eof() && predicate(input.peek()))
str += input.next();
return str;
}
function read_number() {
var has_dot = false;
//Reads the number from the input. Checks for only a single decimal point
var number = read_while(function(ch){
if (ch == ".") {
if (has_dot) return false;
has_dot = true;
return true;
}
return is_digit(ch);
});
return { type: "num", value: parseFloat(number) };
}
//This function also checks the identifier against a list of known keywords (defined at the top)
//and will return a kw object rather than identifier if it is one
function read_ident() {
//Identifier must start with a letter or underscore..and can contain anything from ?!-<>=0123456789
var id = read_while(is_id);
return {
type : is_keyword(id) ? "kw" : "var",
value : id
};
}
function read_escaped(end) {
var escaped = false, str = "";
input.next(); //Skip the quotation mark
while (!input.eof()) {
var ch = input.next();
if (escaped) {
str += ch;
escaped = false;
} else if (ch == "\\") {
escaped = true;
} else if (ch == end) {
break;
} else {
str += ch;
}
}
return str;
}
function read_string(ch) {
if (ch == '"') {
return { type: "str", value: read_escaped('"') };
} else if (ch == '\'') {
return { type: "str", value: read_escaped('\'') };
}
}
//Only supports single-line comments right now
function skip_comment() {
read_while(function(ch){ return ch != "\n" });
input.next();
}
//Gets the next token
function read_next() {
//Skip over whitespace
read_while(is_whitespace);
if (input.eof()) return null;
//Peek the next character and decide what to do based on what that
//next character is
var ch = input.peek();
if (ch == "//") {
skip_comment();
return read_next();
}
if (ch == '"' || ch == '\'') return read_string(ch);
if (is_digit(ch)) return read_number();
if (is_id_start(ch)) return read_ident();
if (is_punc(ch)) return {
type : "punc",
value : input.next()
}
if (is_op_char(ch)) return {
type : "op",
value : read_while(is_op_char)
}
}
function peek() {
//Returns current token, unless its null in which case it grabs the next one
//and returns it
return current || (current = read_next());
}
function next() {
//The token might have been peaked already, in which case read_next() was already
//called so just return current
var tok = current;
current = null;
return tok || read_next();
}
function eof() {
return peek() == null;
}
}