2017-08-30 19:44:29 +02:00
import { BitNodeMultipliers } from "./BitNode.js" ;
import { CONSTANTS } from "./Constants.js" ;
import { Player } from "./Player.js" ;
import { Environment } from "./NetscriptEnvironment.js" ;
import { WorkerScript , addWorkerScript } from "./NetscriptWorker.js" ;
import { Server } from "./Server.js" ;
import { Settings } from "./Settings.js" ;
import { Script , findRunningScript ,
RunningScript } from "./Script.js" ;
2017-09-29 17:02:33 +02:00
import { Node } from "../utils/acorn.js" ;
2017-08-30 19:44:29 +02:00
import { printArray } from "../utils/HelperFunctions.js" ;
import { isValidIPAddress } from "../utils/IPAddress.js" ;
import { isString } from "../utils/StringHelperFunctions.js" ;
2016-11-17 23:25:40 +01:00
/ * E v a l u a t o r
2017-09-05 03:03:29 +02:00
* Evaluates / Interprets the Abstract Syntax Tree generated by Acorns parser
*
* Returns a promise
2016-11-17 23:25:40 +01:00
* /
2016-11-30 00:07:24 +01:00
function evaluate ( exp , workerScript ) {
2017-06-05 06:48:37 +02:00
return new Promise ( function ( resolve , reject ) {
2017-09-29 17:02:33 +02:00
var env = workerScript . env ;
2017-06-05 06:48:37 +02:00
if ( env . stopFlag ) { return reject ( workerScript ) ; }
2017-05-01 07:39:48 +02:00
if ( exp == null ) {
2017-06-05 06:48:37 +02:00
return reject ( makeRuntimeRejectMsg ( workerScript , "Error: NULL expression" ) ) ;
2017-05-01 07:39:48 +02:00
}
2017-06-05 06:48:37 +02:00
setTimeout ( function ( ) {
if ( env . stopFlag ) { return reject ( workerScript ) ; }
switch ( exp . type ) {
2017-06-28 11:47:42 +02:00
case "BlockStatement" :
case "Program" :
var evaluateProgPromise = evaluateProg ( exp , workerScript , 0 ) ; //TODO: make every block/program use individual enviroment
evaluateProgPromise . then ( function ( w ) {
resolve ( workerScript ) ;
} , function ( e ) {
2017-09-29 17:02:33 +02:00
if ( e . constructor === Array && e . length === 2 && e [ 0 ] === "RETURNSTATEMENT" ) {
//Returning from a Player-defined function
resolve ( e [ 1 ] ) ;
} else if ( isString ( e ) ) {
2017-06-28 11:47:42 +02:00
workerScript . errorMessage = e ;
reject ( workerScript ) ;
} else if ( e instanceof WorkerScript ) {
2017-06-05 06:48:37 +02:00
reject ( e ) ;
2017-06-11 00:44:33 +02:00
} else {
2017-06-28 11:47:42 +02:00
reject ( workerScript ) ;
2017-06-11 00:44:33 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
break ;
case "Literal" :
resolve ( exp . value ) ;
break ;
case "Identifier" :
if ( ! ( exp . name in env . vars ) ) {
2017-08-30 19:44:29 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . name + " not defined" ) ) ;
2017-06-05 06:48:37 +02:00
}
2017-06-28 11:47:42 +02:00
resolve ( env . get ( exp . name ) )
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "ExpressionStatement" :
var e = evaluate ( exp . expression , workerScript ) ;
e . then ( function ( res ) {
2017-09-29 17:02:33 +02:00
resolve ( res ) ;
2017-06-28 11:47:42 +02:00
} , function ( e ) {
2017-06-05 06:48:37 +02:00
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "ArrayExpression" :
var argPromises = exp . elements . map ( function ( arg ) {
return evaluate ( arg , workerScript ) ;
} ) ;
Promise . all ( argPromises ) . then ( function ( array ) {
resolve ( array )
2017-06-05 06:48:37 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "CallExpression" :
evaluate ( exp . callee , workerScript ) . then ( function ( func ) {
var argPromises = exp . arguments . map ( function ( arg ) {
return evaluate ( arg , workerScript ) ;
} ) ;
Promise . all ( argPromises ) . then ( function ( args ) {
2017-09-29 17:02:33 +02:00
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 . env = funcEnv ;
evaluate ( func . body , funcWorkerScript ) . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
2017-10-04 03:50:13 +02:00
if ( isString ( e ) ) {
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 ( "|" ) ;
console . log ( "Printing error message from Function:" ) ;
console . log ( errorMsg ) ;
if ( errorTextArray . length === 4 ) {
errorMsg = errorTextArray [ 3 ] ;
reject ( makeRuntimeRejectMsg ( workerScript , errorMsg ) ) ;
} else {
reject ( makeRuntimeRejectMsg ( workerScript , "Error in one of your functions. Could not identify which function" ) ) ;
}
} else if ( e instanceof Error ) {
reject ( makeRuntimeRejectMsg ( workerScript , e . toString ( ) ) ) ;
}
2017-09-29 17:02:33 +02:00
} ) ;
} else if ( exp . callee . type == "MemberExpression" ) {
2017-06-28 11:47:42 +02:00
evaluate ( exp . callee . object , workerScript ) . then ( function ( object ) {
try {
2017-07-13 18:54:29 +02:00
var res = func . apply ( object , args ) ;
resolve ( res ) ;
2017-06-28 11:47:42 +02:00
} catch ( e ) {
reject ( makeRuntimeRejectMsg ( workerScript , e ) ) ;
}
} ) . catch ( function ( e ) {
2017-05-12 06:59:07 +02:00
reject ( e ) ;
} ) ;
} else {
2017-06-28 11:47:42 +02:00
try {
var out = func . apply ( null , args ) ;
if ( out instanceof Promise ) {
out . then ( function ( res ) {
resolve ( res )
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
} else {
resolve ( out ) ;
}
} catch ( e ) {
2017-07-13 18:54:29 +02:00
if ( isScriptErrorMessage ( e ) ) {
reject ( e ) ;
} else {
reject ( makeRuntimeRejectMsg ( workerScript , e ) ) ;
}
2017-06-28 11:47:42 +02:00
}
2017-05-12 06:59:07 +02:00
}
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
} ) . catch ( function ( e ) {
2017-05-12 06:59:07 +02:00
reject ( e ) ;
} ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "MemberExpression" :
var pObject = evaluate ( exp . object , workerScript ) ;
pObject . then ( function ( object ) {
if ( exp . computed ) {
var p = evaluate ( exp . property , workerScript ) ;
p . then ( function ( index ) {
2017-07-29 18:25:40 +02:00
if ( index >= object . length ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Invalid index for arrays" ) ) ;
}
2017-06-28 11:47:42 +02:00
resolve ( object [ index ] ) ;
} ) . catch ( function ( e ) {
reject ( makeRuntimeRejectMsg ( workerScript , "Invalid MemberExpression" ) ) ;
} ) ;
} else {
try {
resolve ( object [ exp . property . name ] )
} catch ( e ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Failed to get property: " + e . toString ( ) ) ) ;
}
}
2017-06-05 06:48:37 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "LogicalExpression" :
case "BinaryExpression" :
var p = evalBinary ( exp , workerScript , resolve , reject ) ;
p . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
2017-06-05 06:48:37 +02:00
reject ( e ) ;
} ) ;
break ;
2017-07-27 04:56:14 +02:00
case "UnaryExpression" :
var p = evalUnary ( exp , workerScript , resolve , reject ) ;
p . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "AssignmentExpression" :
var p = evalAssignment ( exp , workerScript ) ;
p . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
reject ( e ) ;
2017-06-05 06:48:37 +02:00
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "UpdateExpression" :
if ( exp . argument . type === "Identifier" ) {
if ( exp . argument . name in env . vars ) {
if ( exp . prefix ) {
resolve ( env . get ( exp . argument . name ) )
}
switch ( exp . operator ) {
case "++" :
env . set ( exp . argument . name , env . get ( exp . argument . name ) + 1 ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "--" :
env . set ( exp . argument . name , env . get ( exp . argument . name ) - 1 ) ;
break ;
default :
2017-09-02 20:47:14 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "Unrecognized token: " + exp . type + ". You are trying to use code that is currently unsupported" ) ) ;
2017-06-05 19:50:32 +02:00
}
2017-06-28 11:47:42 +02:00
if ( env . prefix ) {
return ;
2017-06-05 19:50:32 +02:00
}
2017-06-28 11:47:42 +02:00
resolve ( env . get ( exp . argument . name ) )
} else {
2017-08-30 19:44:29 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . argument . name + " not defined" ) ) ;
2017-06-26 01:39:17 +02:00
}
2017-06-05 06:48:37 +02:00
} else {
2017-06-28 11:47:42 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "argument must be an identifier" ) ) ;
}
break ;
case "EmptyStatement" :
resolve ( false ) ;
break ;
case "ReturnStatement" :
2017-09-29 17:02:33 +02:00
console . log ( "Evaluating Return Statement" ) ;
//var lineNum = getErrorLineNumber(exp, workerScript);
//reject(makeRuntimeRejectMsg(workerScript, "Return statements are not yet implemented in Netscript (line " + (lineNum+1) + ")"));
evaluate ( exp . argument , workerScript ) . then ( function ( res ) {
reject ( [ "RETURNSTATEMENT" , res ] ) ;
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
2017-06-28 11:47:42 +02:00
break ;
case "BreakStatement" :
2017-08-15 22:22:46 +02:00
reject ( "BREAKSTATEMENT" ) ;
2017-06-28 11:47:42 +02:00
break ;
2017-09-21 23:27:31 +02:00
case "ContinueStatement" :
reject ( "CONTINUESTATEMENT" ) ;
break ;
2017-06-28 11:47:42 +02:00
case "IfStatement" :
evaluateIf ( exp , workerScript ) . then ( function ( forLoopRes ) {
2017-09-29 17:02:33 +02:00
resolve ( forLoopRes ) ;
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
case "SwitchStatement" :
2017-09-05 03:03:29 +02:00
var lineNum = getErrorLineNumber ( exp , workerScript ) ;
reject ( makeRuntimeRejectMsg ( workerScript , "Switch statements are not yet implemented in Netscript (line " + ( lineNum + 1 ) + ")" ) ) ;
2017-06-28 11:47:42 +02:00
break ; e
case "WhileStatement" :
evaluateWhile ( exp , workerScript ) . then ( function ( forLoopRes ) {
2017-09-29 17:02:33 +02:00
resolve ( forLoopRes ) ;
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
2017-08-15 22:22:46 +02:00
if ( e == "BREAKSTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "BREAKSTATEMENT" ) ) {
return resolve ( "whileLoopBroken" ) ;
} else {
reject ( e ) ;
}
2017-06-28 11:47:42 +02:00
} ) ;
break ;
case "ForStatement" :
evaluate ( exp . init , workerScript ) . then ( function ( expInit ) {
return evaluateFor ( exp , workerScript ) ;
} ) . then ( function ( forLoopRes ) {
resolve ( "forLoopDone" ) ;
} ) . catch ( function ( e ) {
2017-08-15 22:22:46 +02:00
if ( e == "BREAKSTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "BREAKSTATEMENT" ) ) {
return resolve ( "forLoopBroken" ) ;
} else {
reject ( e ) ;
}
2017-06-28 11:47:42 +02:00
} ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-09-29 17:02:33 +02:00
case "FunctionDeclaration" :
if ( exp . id && exp . id . name ) {
env . set ( exp . id . name , exp ) ;
resolve ( true ) ;
} else {
var lineNum = getErrorLineNumber ( exp , workerScript ) ;
reject ( makeRuntimeRejectMsg ( workerScript , "Invalid function declaration at line " + lineNum + 1 ) ) ;
}
break ;
2017-06-05 06:48:37 +02:00
default :
2017-09-05 03:03:29 +02:00
var lineNum = getErrorLineNumber ( exp , workerScript ) ;
reject ( makeRuntimeRejectMsg ( workerScript , "Unrecognized token: " + exp . type + " (line " + ( lineNum + 1 ) + "). This is currently unsupported in Netscript" ) ) ;
2017-06-05 06:48:37 +02:00
break ;
} //End switch
2017-07-25 16:39:56 +02:00
} , Settings . CodeInstructionRunTime ) ; //End setTimeout, the Netscript operation run time
2017-06-05 06:48:37 +02:00
} ) ; // End Promise
2016-11-17 23:25:40 +01:00
}
2017-06-28 11:47:42 +02:00
function evalBinary ( exp , workerScript ) {
return new Promise ( function ( resolve , reject ) {
var expLeftPromise = evaluate ( exp . left , workerScript ) ;
expLeftPromise . then ( function ( expLeft ) {
2017-09-15 16:06:59 +02:00
if ( expLeft == true && exp . operator === "||" ) {
return resolve ( true ) ;
}
if ( expLeft == false && exp . operator === "&&" ) {
return resolve ( false ) ;
}
2017-06-28 11:47:42 +02:00
var expRightPromise = evaluate ( exp . right , workerScript ) ;
expRightPromise . then ( function ( expRight ) {
switch ( exp . operator ) {
case "===" :
case "==" :
resolve ( expLeft === expRight ) ;
break ;
case "!==" :
case "!=" :
resolve ( expLeft !== expRight ) ;
break ;
case "<" :
resolve ( expLeft < expRight ) ;
break ;
case "<=" :
resolve ( expLeft <= expRight ) ;
break ;
case ">" :
resolve ( expLeft > expRight ) ;
break ;
case ">=" :
resolve ( expLeft >= expRight ) ;
break ;
case "+" :
resolve ( expLeft + expRight ) ;
break ;
case "-" :
resolve ( expLeft - expRight ) ;
break ;
case "*" :
resolve ( expLeft * expRight ) ;
break ;
case "/" :
2017-08-16 02:18:04 +02:00
if ( expRight === 0 ) {
reject ( makeRuntimeRejectMsg ( workerScript , "ERROR: Divide by zero" ) ) ;
} else {
resolve ( expLeft / expRight ) ;
}
2017-06-28 11:47:42 +02:00
break ;
case "%" :
resolve ( expLeft % expRight ) ;
break ;
case "in" :
resolve ( expLeft in expRight ) ;
break ;
case "instanceof" :
resolve ( expLeft instanceof expRight ) ;
break ;
case "||" :
resolve ( expLeft || expRight ) ;
break ;
case "&&" :
resolve ( expLeft && expRight ) ;
break ;
default :
2017-09-15 16:06:59 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "Unsupported operator: " + exp . operator ) ) ;
2017-05-12 06:59:07 +02:00
}
} , function ( e ) {
reject ( e ) ;
} ) ;
2017-06-28 11:47:42 +02:00
} , function ( e ) {
reject ( e ) ;
} ) ;
} ) ;
}
function evalUnary ( exp , workerScript ) {
2017-07-27 04:56:14 +02:00
var env = workerScript . env ;
2017-06-28 11:47:42 +02:00
return new Promise ( function ( resolve , reject ) {
2017-07-27 04:56:14 +02:00
if ( env . stopFlag ) { return reject ( workerScript ) ; }
var p = evaluate ( exp . argument , workerScript ) ;
p . then ( function ( res ) {
if ( exp . operator == "!" ) {
resolve ( ! res ) ;
} else if ( exp . operator == "-" ) {
if ( isNaN ( res ) ) {
resolve ( res ) ;
} else {
resolve ( - 1 * res ) ;
}
} else {
reject ( makeRuntimeRejectMsg ( workerScript , "Unimplemented unary operator: " + exp . operator ) ) ;
2017-06-28 11:47:42 +02:00
}
2017-07-27 04:56:14 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
2017-06-28 11:47:42 +02:00
} ) ;
} ) ;
}
2017-09-15 16:06:59 +02:00
//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 ) {
return new Promise ( function ( resolve , reject ) {
var indices = [ ] ;
var iPromise = evaluate ( exp . property , workerScript ) ;
iPromise . then ( function ( idx ) {
if ( isNaN ( idx ) ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Invalid access to array. Index is not a number: " + idx ) ) ;
} else {
if ( exp . object . name === undefined && exp . object . object ) {
var recursePromise = getArrayElement ( exp . object , workerScript ) ;
recursePromise . then ( function ( res ) {
res . push ( idx ) ;
indices = res ;
return resolve ( indices ) ;
} ) . catch ( function ( e ) {
return reject ( e ) ;
} ) ;
} else {
indices . push ( idx ) ;
indices . push ( exp . object . name ) ;
return resolve ( indices ) ;
}
}
} ) . catch ( function ( e ) {
console . log ( e ) ;
console . log ( "Error getting index in getArrayElement: " + e . toString ( ) ) ;
return reject ( e ) ;
} ) ;
} ) ;
}
2017-06-28 11:47:42 +02:00
function evalAssignment ( exp , workerScript ) {
var env = workerScript . env ;
return new Promise ( function ( resolve , reject ) {
if ( env . stopFlag ) { return reject ( workerScript ) ; }
2017-07-13 18:54:29 +02:00
if ( exp . left . type != "Identifier" && exp . left . type != "MemberExpression" ) {
2017-06-28 11:47:42 +02:00
return reject ( makeRuntimeRejectMsg ( workerScript , "Cannot assign to " + JSON . stringify ( exp . left ) ) ) ;
2017-05-12 06:59:07 +02:00
}
2017-06-28 11:47:42 +02:00
if ( exp . operator !== "=" && ! ( exp . left . name in env . vars ) ) {
2017-08-30 19:44:29 +02:00
return reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . left . name + " not defined" ) ) ;
2017-06-28 11:47:42 +02:00
}
2017-07-25 16:39:56 +02:00
2017-06-28 11:47:42 +02:00
var expRightPromise = evaluate ( exp . right , workerScript ) ;
expRightPromise . then ( function ( expRight ) {
2017-07-13 18:54:29 +02:00
if ( exp . left . type == "MemberExpression" ) {
//Assign to array element
//Array object designed by exp.left.object.name
//Index designated by exp.left.property
2017-09-15 16:06:59 +02:00
var getArrayElementPromise = getArrayElement ( exp . left , workerScript ) ;
getArrayElementPromise . then ( function ( res ) {
if ( ! ( res instanceof Array ) || res . length < 2 ) {
return 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 ] ;
env . setArrayElement ( arrName , res , expRight ) ;
return resolve ( false ) ;
} ) . catch ( function ( e ) {
return reject ( e ) ;
} ) ;
/ *
2017-07-13 18:54:29 +02:00
var name = exp . left . object . name ;
if ( ! ( name in env . vars ) ) {
2017-08-30 19:44:29 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "variable " + name + " not defined" ) ) ;
2017-07-13 18:54:29 +02:00
}
var arr = env . get ( name ) ;
if ( arr . constructor === Array || arr instanceof Array ) {
var iPromise = evaluate ( exp . left . property , workerScript ) ;
iPromise . then ( function ( idx ) {
if ( isNaN ( idx ) ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Invalid access to array. Index is not a number: " + idx ) ) ;
} else if ( idx >= arr . length || idx < 0 ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Out of bounds: Invalid index in [] operator" ) ) ;
} else {
env . setArrayElement ( name , idx , expRight ) ;
}
} ) . catch ( function ( e ) {
return reject ( e ) ;
} ) ;
} else {
return reject ( makeRuntimeRejectMsg ( workerScript , "Trying to access a non-array variable using the [] operator" ) ) ;
2017-09-15 16:06:59 +02:00
} * /
2017-07-13 18:54:29 +02:00
} else {
//Other assignments
try {
switch ( exp . operator ) {
case "=" :
env . set ( exp . left . name , expRight ) ;
break ;
case "+=" :
env . set ( exp . left . name , env . get ( exp . left . name ) + expRight ) ;
break ;
case "-=" :
env . set ( exp . left . name , env . get ( exp . left . name ) - expRight ) ;
break ;
case "*=" :
env . set ( exp . left . name , env . get ( exp . left . name ) * expRight ) ;
break ;
case "/=" :
env . set ( exp . left . name , env . get ( exp . left . name ) / expRight ) ;
break ;
case "%=" :
env . set ( exp . left . name , env . get ( exp . left . name ) % expRight ) ;
break ;
default :
reject ( makeRuntimeRejectMsg ( workerScript , "Bitwise assignment is not implemented" ) ) ;
}
2017-09-15 16:06:59 +02:00
resolve ( false ) ;
2017-07-13 18:54:29 +02:00
} catch ( e ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Failed to set environment variable: " + e . toString ( ) ) ) ;
2017-06-28 11:47:42 +02:00
}
}
2017-09-15 16:06:59 +02:00
//resolve(false); //Return false so this doesnt cause conditionals to evaluate
2017-06-28 11:47:42 +02:00
} , function ( e ) {
reject ( e ) ;
} ) ;
} ) ;
}
function evaluateIf ( exp , workerScript , i ) {
var env = workerScript . env ;
return new Promise ( function ( resolve , reject ) {
evaluate ( exp . test , workerScript ) . then ( function ( condRes ) {
if ( condRes ) {
evaluate ( exp . consequent , workerScript ) . then ( function ( res ) {
resolve ( true ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} else if ( exp . alternate ) {
evaluate ( exp . alternate , workerScript ) . then ( function ( res ) {
resolve ( true ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} else {
resolve ( "endIf" )
}
} , function ( e ) {
reject ( e ) ;
} ) ;
2017-05-12 06:59:07 +02:00
} ) ;
}
2016-11-30 00:07:24 +01:00
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
function evaluateFor ( exp , workerScript ) {
2016-12-15 23:22:42 +01:00
var env = workerScript . env ;
2016-11-30 00:07:24 +01:00
return new Promise ( function ( resolve , reject ) {
2017-05-30 15:57:24 +02:00
if ( env . stopFlag ) { reject ( workerScript ) ; return ; }
2017-07-25 16:39:56 +02:00
2017-06-28 11:47:42 +02:00
var pCond = evaluate ( exp . test , workerScript ) ;
2016-11-30 00:07:24 +01:00
pCond . then ( function ( resCond ) {
if ( resCond ) {
//Run the for loop code
2017-06-28 11:47:42 +02:00
var pBody = evaluate ( exp . body , workerScript ) ;
2016-11-30 00:07:24 +01:00
//After the code executes make a recursive call
2017-06-28 11:47:42 +02:00
pBody . then ( function ( resCode ) {
var pUpdate = evaluate ( exp . update , workerScript ) ;
pUpdate . then ( function ( resPostloop ) {
2016-11-30 00:07:24 +01:00
var recursiveCall = evaluateFor ( exp , workerScript ) ;
recursiveCall . then ( function ( foo ) {
resolve ( "endForLoop" ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-09-21 23:27:31 +02:00
if ( e == "CONTINUESTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "CONTINUESTATEMENT" ) ) {
//Continue statement, recurse to next iteration
var pUpdate = evaluate ( exp . update , workerScript ) ;
pUpdate . then ( function ( resPostloop ) {
var recursiveCall = evaluateFor ( exp , workerScript ) ;
recursiveCall . then ( function ( foo ) {
resolve ( "endForLoop" ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} else {
reject ( e ) ;
}
2016-11-30 00:07:24 +01:00
} ) ;
} else {
resolve ( "endForLoop" ) ; //Doesn't need to resolve to any particular value
}
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-08-15 22:22:46 +02:00
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} ) ;
}
function evaluateWhile ( exp , workerScript ) {
2016-12-15 23:22:42 +01:00
var env = workerScript . env ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
return new Promise ( function ( resolve , reject ) {
2017-05-30 15:57:24 +02:00
if ( env . stopFlag ) { reject ( workerScript ) ; return ; }
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
var pCond = new Promise ( function ( resolve , reject ) {
setTimeout ( function ( ) {
2017-06-28 11:47:42 +02:00
var evaluatePromise = evaluate ( exp . test , workerScript ) ;
2016-11-30 00:07:24 +01:00
evaluatePromise . then ( function ( resCond ) {
resolve ( resCond ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-07-25 16:39:56 +02:00
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} , CONSTANTS . CodeInstructionRunTime ) ;
} ) ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
pCond . then ( function ( resCond ) {
if ( resCond ) {
//Run the while loop code
var pCode = new Promise ( function ( resolve , reject ) {
setTimeout ( function ( ) {
2017-06-28 11:47:42 +02:00
var evaluatePromise = evaluate ( exp . body , workerScript ) ;
2016-11-30 00:07:24 +01:00
evaluatePromise . then ( function ( resCode ) {
resolve ( resCode ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-09-21 23:27:31 +02:00
if ( e == "CONTINUESTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "CONTINUESTATEMENT" ) ) {
//Continue statement, recurse
var recursiveCall = evaluateWhile ( exp , workerScript ) ;
recursiveCall . then ( function ( foo ) {
resolve ( "endWhileLoop" ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} else {
reject ( e ) ;
}
2016-11-30 00:07:24 +01:00
} ) ;
} , CONSTANTS . CodeInstructionRunTime ) ;
} ) ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
//After the code executes make a recursive call
pCode . then ( function ( resCode ) {
var recursiveCall = evaluateWhile ( exp , workerScript ) ;
recursiveCall . then ( function ( foo ) {
resolve ( "endWhileLoop" ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} else {
2017-08-15 22:22:46 +02:00
resolve ( "endWhileLoop" ) ; //Doesn't need to resolve to any particular value
2016-11-30 00:07:24 +01:00
}
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} ) ;
}
function evaluateProg ( exp , workerScript , index ) {
2016-12-15 23:22:42 +01:00
var env = workerScript . env ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
return new Promise ( function ( resolve , reject ) {
2017-05-30 15:57:24 +02:00
if ( env . stopFlag ) { reject ( workerScript ) ; return ; }
2017-07-25 16:39:56 +02:00
2017-06-28 11:47:42 +02:00
if ( index >= exp . body . length ) {
2016-11-30 00:07:24 +01:00
resolve ( "progFinished" ) ;
} else {
//Evaluate this line of code in the prog
var code = new Promise ( function ( resolve , reject ) {
setTimeout ( function ( ) {
2017-06-28 11:47:42 +02:00
var evaluatePromise = evaluate ( exp . body [ index ] , workerScript ) ;
2016-11-30 00:07:24 +01:00
evaluatePromise . then ( function ( evalRes ) {
resolve ( evalRes ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} , CONSTANTS . CodeInstructionRunTime ) ;
} ) ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
//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 ) {
2016-12-06 17:59:20 +01:00
resolve ( workerScript ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
}
} ) ;
}
2017-09-15 16:06:59 +02:00
function netscriptDelay ( time , workerScript ) {
2017-07-25 16:39:56 +02:00
return new Promise ( function ( resolve ) {
2017-09-15 16:06:59 +02:00
var delay = setTimeout ( resolve , time ) ;
workerScript . killTrigger = function ( ) {
clearTimeout ( delay ) ;
resolve ( ) ;
} ;
2017-06-05 06:48:37 +02:00
} ) ;
}
2017-05-25 14:18:34 +02:00
function makeRuntimeRejectMsg ( workerScript , msg ) {
return "|" + workerScript . serverIp + "|" + workerScript . name + "|" + msg ;
}
2017-09-15 16:06:59 +02:00
/ *
2016-11-17 23:25:40 +01:00
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 ) {
2017-05-23 20:17:37 +02:00
case "+" : return a + b ;
2016-11-17 23:25:40 +01:00
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 ) ;
2017-05-15 08:35:09 +02:00
}
2017-09-15 16:06:59 +02:00
* /
2017-05-15 08:35:09 +02:00
//Run a script from inside a script using run() command
2017-06-17 04:53:57 +02:00
function runScriptFromScript ( server , scriptname , args , workerScript , threads = 1 ) {
2017-07-13 18:54:29 +02:00
//Check if the script is already running
var runningScriptObj = findRunningScript ( scriptname , args , server ) ;
if ( runningScriptObj != null ) {
workerScript . scriptRef . log ( scriptname + " is already running on " + server . hostname ) ;
return Promise . resolve ( false ) ;
}
2017-06-28 11:47:42 +02:00
2017-07-13 18:54:29 +02:00
//Check if the script exists and if it does run it
for ( var i = 0 ; i < server . scripts . length ; ++ i ) {
if ( server . scripts [ i ] . filename == scriptname ) {
//Check for admin rights and that there is enough RAM availble to run
var script = server . scripts [ i ] ;
var ramUsage = script . ramUsage ;
2017-09-13 16:22:22 +02:00
threads = Math . round ( Number ( threads ) ) ; //Convert to number and round
2017-07-13 18:54:29 +02:00
ramUsage = ramUsage * threads * Math . pow ( CONSTANTS . MultithreadingRAMCost , threads - 1 ) ;
var ramAvailable = server . maxRam - server . ramUsed ;
2017-06-28 11:47:42 +02:00
2017-07-13 18:54:29 +02:00
if ( server . hasAdminRights == false ) {
workerScript . scriptRef . log ( "Cannot run script " + scriptname + " on " + server . hostname + " because you do not have root access!" ) ;
return Promise . resolve ( false ) ;
} else if ( ramUsage > ramAvailable ) {
workerScript . scriptRef . log ( "Cannot run script " + scriptname + "(t=" + threads + ") on " + server . hostname + " because there is not enough available RAM!" ) ;
return Promise . resolve ( false ) ;
} else {
//Able to run script
workerScript . scriptRef . log ( "Running script: " + scriptname + " on " + server . hostname + " with " + threads + " threads and args: " + printArray ( args ) + ". May take a few seconds to start up..." ) ;
var runningScriptObj = new RunningScript ( script , args ) ;
runningScriptObj . threads = threads ;
server . runningScripts . push ( runningScriptObj ) ; //Push onto runningScripts
addWorkerScript ( runningScriptObj , server ) ;
return Promise . resolve ( true ) ;
2017-05-15 08:35:09 +02:00
}
2017-06-28 11:47:42 +02:00
}
2017-07-13 18:54:29 +02:00
}
workerScript . scriptRef . log ( "Could not find script " + scriptname + " on " + server . hostname ) ;
return Promise . resolve ( false ) ;
2017-05-15 08:35:09 +02:00
}
2016-12-14 00:52:32 +01:00
2017-09-05 03:03:29 +02:00
//Takes in a
function getErrorLineNumber ( exp , workerScript ) {
var code = workerScript . scriptRef . scriptRef . code ;
//Split code up to the start of the node
code = code . substring ( 0 , exp . start ) ;
return ( code . match ( /\n/g ) || [ ] ) . length ;
}
2017-05-01 07:39:48 +02:00
function isScriptErrorMessage ( msg ) {
2017-08-30 19:44:29 +02:00
if ( ! isString ( msg ) ) { return false ; }
let splitMsg = msg . split ( "|" ) ;
2017-05-01 07:39:48 +02:00
if ( splitMsg . length != 4 ) {
return false ;
}
var ip = splitMsg [ 1 ] ;
if ( ! isValidIPAddress ( ip ) ) {
return false ;
}
return true ;
}
2016-12-14 00:52:32 +01:00
//The same as Player's calculateHackingChance() function but takes in the server as an argument
function scriptCalculateHackingChance ( server ) {
var difficultyMult = ( 100 - server . hackDifficulty ) / 100 ;
2017-09-15 16:06:59 +02:00
var skillMult = ( 1.75 * Player . hacking _skill ) + ( 0.2 * Player . intelligence ) ;
2016-12-14 00:52:32 +01:00
var skillChance = ( skillMult - server . requiredHackingSkill ) / skillMult ;
2017-05-24 15:49:52 +02:00
var chance = skillChance * difficultyMult * Player . hacking _chance _mult ;
2017-07-22 00:54:55 +02:00
if ( chance > 1 ) { return 1 ; }
2017-04-17 14:26:54 +02:00
if ( chance < 0 ) { return 0 ; }
else { return chance ; }
2016-12-14 00:52:32 +01:00
}
//The same as Player's calculateHackingTime() function but takes in the server as an argument
function scriptCalculateHackingTime ( server ) {
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
2017-09-15 16:06:59 +02:00
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 + ( 0.1 * Player . intelligence ) ) ;
2017-06-18 06:36:16 +02:00
var hackingTime = 5 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
2016-12-14 21:29:40 +01:00
return hackingTime ;
2016-12-14 00:52:32 +01:00
}
2017-07-25 16:39:56 +02:00
//The same as Player's calculateExpGain() function but takes in the server as an argument
2016-12-14 00:52:32 +01:00
function scriptCalculateExpGain ( server ) {
2017-06-15 03:19:52 +02:00
if ( server . baseDifficulty == null ) {
server . baseDifficulty = server . hackDifficulty ;
}
2017-08-30 19:44:29 +02:00
return ( server . baseDifficulty * Player . hacking _exp _mult * 0.3 + 3 ) * BitNodeMultipliers . HackExpGain ;
2016-12-14 00:52:32 +01:00
}
//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 ;
2017-07-22 00:54:55 +02:00
var percentMoneyHacked = difficultyMult * skillMult * Player . hacking _money _mult / 240 ;
2017-04-18 06:32:17 +02:00
if ( percentMoneyHacked < 0 ) { return 0 ; }
if ( percentMoneyHacked > 1 ) { return 1 ; }
2017-08-30 19:44:29 +02:00
return percentMoneyHacked * BitNodeMultipliers . ScriptHackMoney ;
2017-05-24 15:49:52 +02:00
}
2017-05-31 19:37:32 +02:00
//Amount of time to execute grow() in milliseconds
2017-05-24 15:49:52 +02:00
function scriptCalculateGrowTime ( server ) {
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
2017-09-15 16:06:59 +02:00
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 + ( 0.1 * Player . intelligence ) ) ;
2017-06-21 19:19:08 +02:00
var growTime = 16 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
2017-05-24 15:49:52 +02:00
return growTime * 1000 ;
2017-05-31 19:37:32 +02:00
}
//Amount of time to execute weaken() in milliseconds
function scriptCalculateWeakenTime ( server ) {
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
2017-09-15 16:06:59 +02:00
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 + ( 0.1 * Player . intelligence ) ) ;
2017-07-22 00:54:55 +02:00
var weakenTime = 20 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
2017-05-31 19:37:32 +02:00
return weakenTime * 1000 ;
2017-07-25 16:39:56 +02:00
}
2017-08-30 19:44:29 +02:00
export { makeRuntimeRejectMsg , netscriptDelay , runScriptFromScript ,
scriptCalculateHackingChance , scriptCalculateHackingTime ,
scriptCalculateExpGain , scriptCalculatePercentMoneyHacked ,
scriptCalculateGrowTime , scriptCalculateWeakenTime , evaluate ,
isScriptErrorMessage } ;