Refactored Netscript code into their respective files since it will no longer be done in Web Worker

This commit is contained in:
Daniel Xie
2016-11-29 17:07:24 -06:00
parent 77f0c31777
commit 867ae191b5
3 changed files with 257 additions and 883 deletions
+250 -45
View File
@@ -2,28 +2,78 @@
* Evaluates the Abstract Syntax Tree for Netscript
* generated by the Parser class
*/
function evaluate(exp, env) {
// 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;
switch (exp.type) {
case "num":
case "str":
case "bool":
return exp.value;
return new Promise(function(resolve, reject) {
resolve(exp.value);
});
break;
case "var":
return env.get(exp.value);
return new Promise(function(resolve, reject) {
resolve(env.get(exp.value));
});
break;
//Can currently only assign to "var"s
case "assign":
if (exp.left.type != "var")
throw new Error("Cannot assign to " + JSON.stringify(exp.left));
return env.set(exp.left.value, evaluate(exp.right, env));
console.log("Evaluating assign operation");
return new Promise(function(resolve, reject) {
if (exp.left.type != "var")
throw new Error("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);
});
}, CONSTANTS.CodeInstructionRunTime)
});
p.then(function(expRight) {
console.log("Right side of assign operation resolved with value: " + expRight);
env.set(exp.left.value, expRight);
console.log("Assign operation finished");
resolve("assignFinished");
});
});
case "binary":
return apply_op(exp.operator,
evaluate(exp.left, env),
evaluate(exp.right, env));
console.log("Binary operation called");
return new Promise(function(resolve, reject) {
var pLeft = new Promise(function(resolve, reject) {
setTimeout(function() {
var promise = evaluate(exp.left, workerScript);
promise.then(function(valLeft) {
resolve(valLeft);
});
}, 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]);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pRight.then(function(args) {
console.log("Resolving binary operation");
resolve(apply_op(exp.operator, args[0], args[1]));
});
});
});
break;
//TODO
case "if":
var numConds = exp.cond.length;
var numThens = exp.then.length;
@@ -32,40 +82,51 @@ function evaluate(exp, env) {
}
for (var i = 0; i < numConds; i++) {
var cond = evaluate(exp.cond[i], env);
if (cond) return evaluate(exp.then, env);
var cond = evaluate(exp.cond[i], workerScript);
if (cond) return evaluate(exp.then[i], workerScript);
}
//Evaluate else if it exists, snce none of the conditionals
//were true
return exp.else ? evaluate(exp.else, env) : false;
return exp.else ? evaluate(exp.else, workerScript) : false;
case "for":
evaluate(exp.init, env);
cond = evaluate(exp.cond, env);
console.log("Evaluated the conditional");
while (cond) {
evaluate(exp.code, env);
evaluate(exp.postloop, env);
cond = evaluate(exp.cond, env);
}
//TODO I don't think I need to return anything..but I might be wrong
return new Promise(function(resolve, reject) {
console.log("for loop encountered in evaluator");
var pInit = new Promise(function(resolve, reject) {
setTimeout(function() {
var resInit = evaluate(exp.init, workerScript);
resInit.then(function(foo) {
resolve(resInit);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pInit.then(function(expInit) {
var pForLoop = evaluateFor(exp, workerScript);
pForLoop.then(function(forLoopRes) {
resolve("forLoopDone");
});
});
});
break;
case "while":
cond = evaluate(exp.cond, env);
while (cond) {
evaluate(exp.code, env);
cond = evaluate(exp.cond, env);
}
//TODO I don't think I need to return anything..but I might be wrong
console.log("Evaluating while loop");
return new Promise(function(resolve, reject) {
var pEvaluateWhile = evaluateWhile(exp, workerScript);
pEvaluateWhile.then(function(whileLoopRes) {
resolve("whileLoopDone");
});
});
break;
case "prog":
var val = false;
exp.prog.forEach(function(exp){ val = evaluate(exp, env) });
return val;
return new Promise(function(resolve, reject) {
var evaluateProgPromise = evaluateProg(exp, workerScript, 0);
evaluateProgPromise.then(function(res) {
resolve(res);
});
});
break;
/* Currently supported function calls:
* hack()
@@ -79,13 +140,32 @@ function evaluate(exp, env) {
//return func.apply(null, exp.args.map(function(arg){
// return evaluate(arg, env);
//}));
if (exp.func.value == "hack") {
console.log("Execute hack()");
} else if (exp.func.value == "sleep") {
console.log("Execute sleep()");
} else if (exp.func.value == "print") {
post(evaluate(exp.args[0], env).toString());
}
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (exp.func.value == "hack") {
console.log("Execute hack()");
resolve("hackExecuted");
} else if (exp.func.value == "sleep") {
console.log("Execute sleep()");
resolve("sleepExecuted");
} else if (exp.func.value == "print") {
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.args[0], workerScript);
evaluatePromise.then(function(res) {
resolve(res);
});
}, CONSTANTS.CodeInstructionRunTime);
});
p.then(function(res) {
post(res.toString());
console.log("Print call executed");
resolve("printExecuted");
});
}
}, CONSTANTS.CodeInstructionRunTime);
});
break;
default:
@@ -93,6 +173,131 @@ function evaluate(exp, env) {
}
}
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
function evaluateFor(exp, workerScript) {
console.log("evaluateFor() called");
return new Promise(function(resolve, reject) {
var pCond = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.cond, workerScript);
evaluatePromise.then(function(resCond) {
console.log("Conditional evaluated to: " + resCond);
resolve(resCond);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pCond.then(function(resCond) {
if (resCond) {
console.log("About to evaluate an iteration of for loop code");
//Run the for loop code
var pCode = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.code, workerScript);
evaluatePromise.then(function(resCode) {
console.log("Evaluated an iteration of for loop code");
resolve(resCode);
});
}, 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) {
console.log("Evaluated for loop postloop");
resolve("postLoopFinished");
});
}, CONSTANTS.CodeInstructionRunTime);
});
pPostLoop.then(function(resPostloop) {
var recursiveCall = evaluateFor(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endForLoop");
});
});
});
} else {
console.log("Cond is false, stopping for loop");
resolve("endForLoop"); //Doesn't need to resolve to any particular value
}
});
});
}
function evaluateWhile(exp, workerScript) {
console.log("evaluateWhile() called");
return new Promise(function(resolve, reject) {
var pCond = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.cond, workerScript);
evaluatePromise.then(function(resCond) {
console.log("Conditional evaluated to: " + resCond);
resolve(resCond);
});
}, 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) {
console.log("Evaluated an iteration of while loop code");
resolve(resCode);
});
}, 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");
});
});
} else {
console.log("Cond is false, stopping while loop");
resolve("endWhileLoop"); //Doesn't need to resolve to any particular value
}
});
});
}
function evaluateProg(exp, workerScript, index) {
console.log("evaluateProg() called");
return new Promise(function(resolve, reject) {
if (index >= exp.prog.length) {
console.log("Prog done. Resolving recursively");
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);
});
}, 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("progDone");
});
});
}
});
}
function apply_op(op, a, b) {
function num(x) {
if (typeof x != "number")
@@ -120,4 +325,4 @@ function apply_op(op, a, b) {
case "!=": return a !== b;
}
throw new Error("Can't apply operator " + op);
}
}