mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
Finished implementing Netscript. Not completely tested yet. Find out how to make it multithreaded (Web Workers is the best way according to internet
This commit is contained in:
parent
a4f92f7520
commit
8d87b74eaf
28
index.html
28
index.html
@ -6,6 +6,25 @@
|
||||
<link rel="stylesheet" type="text/css" href="css/styles.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/terminal.css" />
|
||||
|
||||
<!-- We'll add in the jQuery library here - direct from
|
||||
the Google CDN (Content Delivery Network). -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
|
||||
|
||||
<script src="src/Constants.js"></script>
|
||||
<script src="src/Server.js"></script>
|
||||
<script src="src/Player.js"></script>
|
||||
<script src="src/Faction.js"></script>
|
||||
<script src="src/Company.js"></script>
|
||||
<script src="src/Terminal.js"></script>
|
||||
|
||||
<script src="src/netscript/InputStream.js"></script>
|
||||
<script src="src/netscript/Tokenizer.js"></script>
|
||||
<script src="src/netscript/Parser.js"></script>
|
||||
<script src="src/netscript/Environment.js"></script>
|
||||
<script src="src/netscript/Evaluator.js"></script>
|
||||
|
||||
<script src="src/engine.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mainmenu-container">
|
||||
@ -51,9 +70,7 @@
|
||||
<p id="character-info"> </p>
|
||||
</div> <!-- End terminal-container -->
|
||||
|
||||
<!-- We'll add in the jQuery library here - direct from
|
||||
the Google CDN (Content Delivery Network). -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
|
||||
|
||||
<!-- Always keep the terminal in focus -->
|
||||
<script type="text/javascript">
|
||||
@ -65,9 +82,6 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<script src="src/Server.js"></script>
|
||||
<script src="src/Player.js"></script>
|
||||
<script src="src/Terminal.js"></script>
|
||||
<script src="src/engine.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
122
src/Company.js
122
src/Company.js
@ -12,17 +12,17 @@ function Company() {
|
||||
|
||||
};
|
||||
|
||||
Company.prototype.init(name, salaryMult, expMult) {
|
||||
Company.prototype.init = function(name, salaryMult, expMult) {
|
||||
this.companyName = name;
|
||||
this.salaryMult = salaryMult;
|
||||
this.expMult = expMult;
|
||||
}
|
||||
|
||||
Company.prototype.addPosition(pos) {
|
||||
Company.prototype.addPosition = function(pos) {
|
||||
this.companyPositions.push(pos);
|
||||
}
|
||||
|
||||
Company.prototype.addPositions(positions) {
|
||||
Company.prototype.addPositions = function(positions) {
|
||||
for (var i = 0; i < positions.length; i++) {
|
||||
this.addPosition(positions[i]);
|
||||
}
|
||||
@ -51,7 +51,7 @@ function CompanyPosition(name, reqHack, reqStr, reqDef, reqDex, reqAgi, reqCha,
|
||||
//
|
||||
//NOTE: These parameters should total to 100, such that each parameter represents a "weighting" of how
|
||||
// important that stat/skill is for the job
|
||||
CompanyPosition.prototype.setPerformanceParameters(hackEff, strEff, defEff, dexEff, agiEff, chaEff) {
|
||||
CompanyPosition.prototype.setPerformanceParameters = function(hackEff, strEff, defEff, dexEff, agiEff, chaEff) {
|
||||
if (hackEff + strEff + defEff + dexEff + agiEff + chaEff != 100) {
|
||||
console.log("CompanyPosition.setPerformanceParameters() arguments do not total to 100");
|
||||
return;
|
||||
@ -66,7 +66,7 @@ CompanyPosition.prototype.setPerformanceParameters(hackEff, strEff, defEff, dexE
|
||||
|
||||
//Set the stat/skill experience a Player should gain for working at a CompanyPosition. The experience is per game loop (200 ms)
|
||||
//These will be constant for a single position, but is affected by a company-specific multiplier
|
||||
CompanyPosition.prototype.setExperienceGains(hack, str, def, dex, agi, cha) {
|
||||
CompanyPosition.prototype.setExperienceGains = function(hack, str, def, dex, agi, cha) {
|
||||
this.hackingExpGain = hack;
|
||||
this.strengthExpGain = str;
|
||||
this.defenseExpGain = def;
|
||||
@ -77,7 +77,7 @@ CompanyPosition.prototype.setExperienceGains(hack, str, def, dex, agi, cha) {
|
||||
|
||||
//Calculate a player's effectiveness at a certain job. Returns the amount of job reputation
|
||||
//that should be gained every game loop (200 ms)
|
||||
CompanyPosition.prototype.calculateJobPerformance(hacking, str, def, dex, agi, cha) {
|
||||
CompanyPosition.prototype.calculateJobPerformance = function(hacking, str, def, dex, agi, cha) {
|
||||
var hackRatio = this.hackingEffectiveness * hacking / CONSTANTS.MaxSkillLevel;
|
||||
var strRatio = this.strengthEffectiveness * str / CONSTANTS.MaxSkillLevel;
|
||||
var defRatio = this.defenseEffectiveness * def / CONSTANTS.MaxSkillLevel;
|
||||
@ -130,69 +130,69 @@ CompanyPositions = {
|
||||
init: function() {
|
||||
//Argument order: hack, str, def, dex, agi, cha
|
||||
//Software
|
||||
SoftwareIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
||||
SoftwareIntern.setExperienceGains(.1, 0, 0, 0, 0, .02);
|
||||
JuniorDev.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
JuniorDev.setExperienceGains(.2, 0, 0, 0, 0, .04);
|
||||
SeniorDev.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||
SeniorDev.setExperienceGains(.4, 0, 0, 0, 0, .08);
|
||||
LeadDev.setPerformanceParameters(70, 0, 0, 0, 0, 30);
|
||||
LeadDev.setExperienceGains(.5, 0, 0, 0, 0, .1);
|
||||
CompanyPositions.SoftwareIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
||||
CompanyPositions.SoftwareIntern.setExperienceGains(.1, 0, 0, 0, 0, .02);
|
||||
CompanyPositions.JuniorDev.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
CompanyPositions.JuniorDev.setExperienceGains(.2, 0, 0, 0, 0, .04);
|
||||
CompanyPositions.SeniorDev.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||
CompanyPositions.SeniorDev.setExperienceGains(.4, 0, 0, 0, 0, .08);
|
||||
CompanyPositions.LeadDev.setPerformanceParameters(70, 0, 0, 0, 0, 30);
|
||||
CompanyPositions.LeadDev.setExperienceGains(.5, 0, 0, 0, 0, .1);
|
||||
|
||||
//Security
|
||||
ITIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
||||
ITIntern.setExperienceGains(.05, 0, 0, 0, 0, .01);
|
||||
ITAnalyst.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
ITAnalyst.setExperienceGains(.15, 0, 0, 0, 0, .02);
|
||||
ITManager.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||
ITManager.setExperienceGains(.4, 0, 0, 0, 0, .1);
|
||||
SysAdmin.setPerformanceParameters(80, 0, 0, 0, 0, 20);
|
||||
SysAdmin.setExperienceGains(.5, 0, 0, 0, 0, .05);
|
||||
SecurityEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
SecurityEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
||||
NetworkEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
NetworkEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
||||
NetworkAdministrator.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||
NetworkAdministrator.setExperienceGains(0.5, 0, 0, 0, 0, .1);
|
||||
CompanyPositions.ITIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
||||
CompanyPositions.ITIntern.setExperienceGains(.05, 0, 0, 0, 0, .01);
|
||||
CompanyPositions.ITAnalyst.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
CompanyPositions.ITAnalyst.setExperienceGains(.15, 0, 0, 0, 0, .02);
|
||||
CompanyPositions.ITManager.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||
CompanyPositions.ITManager.setExperienceGains(.4, 0, 0, 0, 0, .1);
|
||||
CompanyPositions.SysAdmin.setPerformanceParameters(80, 0, 0, 0, 0, 20);
|
||||
CompanyPositions.SysAdmin.setExperienceGains(.5, 0, 0, 0, 0, .05);
|
||||
CompanyPositions.SecurityEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
CompanyPositions.SecurityEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
||||
CompanyPositions.NetworkEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||
CompanyPositions.NetworkEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
||||
CompanyPositions.NetworkAdministrator.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||
CompanyPositions.NetworkAdministrator.setExperienceGains(0.5, 0, 0, 0, 0, .1);
|
||||
|
||||
//Technology management
|
||||
HeadOfSoftware.setPerformanceParameters(65, 0, 0, 0, 0, 35);
|
||||
HeadOfSoftware.setExperienceGains(1, 0, 0, 0, 0, .5);
|
||||
HeadOfEngineering.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
||||
HeadOfEngineering.setExperienceGains(1.1, 0, 0, 0, 0, .5);
|
||||
VicePresident.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
||||
VicePresident.setExperienceGains(1.2, 0, 0, 0, 0, .6);
|
||||
CTO.setPerformanceParameters(50, 0, 0, 0, 0, 50);
|
||||
CTO.setExperienceGains(1.5, 0, 0, 0, 1);
|
||||
CompanyPositions.HeadOfSoftware.setPerformanceParameters(65, 0, 0, 0, 0, 35);
|
||||
CompanyPositions.HeadOfSoftware.setExperienceGains(1, 0, 0, 0, 0, .5);
|
||||
CompanyPositions.HeadOfEngineering.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
||||
CompanyPositions.HeadOfEngineering.setExperienceGains(1.1, 0, 0, 0, 0, .5);
|
||||
CompanyPositions.VicePresident.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
||||
CompanyPositions.VicePresident.setExperienceGains(1.2, 0, 0, 0, 0, .6);
|
||||
CompanyPositions.CTO.setPerformanceParameters(50, 0, 0, 0, 0, 50);
|
||||
CompanyPositions.CTO.setExperienceGains(1.5, 0, 0, 0, 1);
|
||||
|
||||
//Business
|
||||
BusinessIntern.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||
BusinessIntern.setExperienceGains(.01, 0, 0, 0, 0, .1);
|
||||
BusinessAnalyst.setPerformanceParameters(20, 0, 0, 0, 0, 80);
|
||||
BusinessAnalyst.setExperienceGains(.02, 0, 0, 0, 0, .2);
|
||||
BusinessManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
||||
BusinessManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
||||
OperationsManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
||||
OperationsManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
||||
CFO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||
CFO.setExperienceGains(.05, 0, 0, 0, 0, 1);
|
||||
CEO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||
CEO.setExperienceGains(.1, 0, 0, 0, 0, 1.5);
|
||||
CompanyPositions.BusinessIntern.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||
CompanyPositions.BusinessIntern.setExperienceGains(.01, 0, 0, 0, 0, .1);
|
||||
CompanyPositions.BusinessAnalyst.setPerformanceParameters(20, 0, 0, 0, 0, 80);
|
||||
CompanyPositions.BusinessAnalyst.setExperienceGains(.02, 0, 0, 0, 0, .2);
|
||||
CompanyPositions.BusinessManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
||||
CompanyPositions.BusinessManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
||||
CompanyPositions.OperationsManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
||||
CompanyPositions.OperationsManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
||||
CompanyPositions.CFO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||
CompanyPositions.CFO.setExperienceGains(.05, 0, 0, 0, 0, 1);
|
||||
CompanyPositions.CEO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||
CompanyPositions.CEO.setExperienceGains(.1, 0, 0, 0, 0, 1.5);
|
||||
|
||||
//Non-tech/management jobs
|
||||
//TODO These parameters might need to be balanced
|
||||
Waiter.setPerformanceParameters(0, 10, 0, 10, 10, 70);
|
||||
Waiter.setExperienceGains(0, .01, 0, .01, .01, .05);
|
||||
SecurityGuard.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
||||
SecurityGuard.setExperienceGains(.01, .02, .02, .02, .02, .01);
|
||||
PoliceOfficer.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
||||
PoliceOfficer.setExperienceGains(.01, .04, .04, .04, .04, .02);
|
||||
SecurityOfficer.setPerformanceParameters(10, 20, 20, 20, 20, 10);
|
||||
SecurityOfficer.setExperienceGains(.02, .06, .06, .06, .06, .04);
|
||||
SecuritySupervisor.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
||||
SecuritySupervisor.setExperienceGains(.02, .06, .06, .06, .06, .08);
|
||||
HeadOfSecurity.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
||||
HeadOfSecurity.setExperienceGains(.05, .1, .1, .1, .1, .1);
|
||||
CompanyPositions.Waiter.setPerformanceParameters(0, 10, 0, 10, 10, 70);
|
||||
CompanyPositions.Waiter.setExperienceGains(0, .01, 0, .01, .01, .05);
|
||||
CompanyPositions.SecurityGuard.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
||||
CompanyPositions.SecurityGuard.setExperienceGains(.01, .02, .02, .02, .02, .01);
|
||||
CompanyPositions.PoliceOfficer.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
||||
CompanyPositions.PoliceOfficer.setExperienceGains(.01, .04, .04, .04, .04, .02);
|
||||
CompanyPositions.SecurityOfficer.setPerformanceParameters(10, 20, 20, 20, 20, 10);
|
||||
CompanyPositions.SecurityOfficer.setExperienceGains(.02, .06, .06, .06, .06, .04);
|
||||
CompanyPositions.SecuritySupervisor.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
||||
CompanyPositions.SecuritySupervisor.setExperienceGains(.02, .06, .06, .06, .06, .08);
|
||||
CompanyPositions.HeadOfSecurity.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
||||
CompanyPositions.HeadOfSecurity.setExperienceGains(.05, .1, .1, .1, .1, .1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,7 +242,7 @@ Companies = {
|
||||
SysCoreSecurities: new Company(),
|
||||
CompuTek: new Company(),
|
||||
NetLinkTechnologies: new Company(),
|
||||
CarmichaelSecurity: new Company();
|
||||
CarmichaelSecurity: new Company(),
|
||||
|
||||
//"Low level" companies
|
||||
FoodNStuff: new Company(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
CONSTANTS = {
|
||||
//Max level for any skill. Determined by max numerical value in javascript and the skill level
|
||||
//formula in Player.js
|
||||
MaxSkillLevel: 1796;
|
||||
MaxSkillLevel: 1796,
|
||||
}
|
@ -9,11 +9,11 @@ function Faction(name) {
|
||||
};
|
||||
|
||||
//TODO
|
||||
Faction.prototype.init() {
|
||||
Faction.prototype.init = function() {
|
||||
|
||||
}
|
||||
|
||||
Faction.prototype.setAugmentations(augs) {
|
||||
Faction.prototype.setAugmentations = function(augs) {
|
||||
for (var i = 0; i < augs.length; i++) {
|
||||
this.augmentations.push(augs[i]);
|
||||
}
|
||||
@ -22,33 +22,33 @@ Faction.prototype.setAugmentations(augs) {
|
||||
Factions = {
|
||||
//TODO Saving this for later, IShima is a kinda cool name maybe use it for something
|
||||
//Endgame
|
||||
Illuminati: new Faction("Illuminati");
|
||||
Daedalus: new Faction("Daedalus");
|
||||
Covenant: new Faction("The Covenant");
|
||||
Illuminati: new Faction("Illuminati"),
|
||||
Daedalus: new Faction("Daedalus"),
|
||||
Covenant: new Faction("The Covenant"),
|
||||
|
||||
//Megacorporations, each forms its own faction
|
||||
ECorp: new Faction("ECorp");
|
||||
MegaCorp: new Faction("MegaCorp");
|
||||
BachmanAndAssociates: new Faction("Bachman & Associates");
|
||||
BladeIndustries: new Faction("Blade Industries");
|
||||
NWO: new Faction("NWO");
|
||||
ClarkeIncorporated: new Faction("Clarke Incorporated");
|
||||
OmniTekIncorporated: new Faction("OmniTek Incorporated");
|
||||
FourSigma: new Faction("Four Sigma");
|
||||
KuaiGongInternational: new Faction("KuaiGong International");
|
||||
ECorp: new Faction("ECorp"),
|
||||
MegaCorp: new Faction("MegaCorp"),
|
||||
BachmanAndAssociates: new Faction("Bachman & Associates"),
|
||||
BladeIndustries: new Faction("Blade Industries"),
|
||||
NWO: new Faction("NWO"),
|
||||
ClarkeIncorporated: new Faction("Clarke Incorporated"),
|
||||
OmniTekIncorporated: new Faction("OmniTek Incorporated"),
|
||||
FourSigma: new Faction("Four Sigma"),
|
||||
KuaiGongInternational: new Faction("KuaiGong International"),
|
||||
|
||||
//Hacker groups
|
||||
BitRunners: new Faction("BitRunners");
|
||||
BlackHand: new Faction("The Black Hand");
|
||||
NiteSec: new Faction("NiteSec");
|
||||
BitRunners: new Faction("BitRunners"),
|
||||
BlackHand: new Faction("The Black Hand"),
|
||||
NiteSec: new Faction("NiteSec"),
|
||||
|
||||
//City factions, essentially governments
|
||||
Chongqing: new Faction("Chongqing");
|
||||
Sector12: new Faction("Sector-12");
|
||||
HongKong: new Faction("New Tokyo");
|
||||
Aevum: new Faction("Aevum");
|
||||
Ishima: new Faction("Ishima");
|
||||
Volhaven: new Faction("Volhaven");
|
||||
Chongqing: new Faction("Chongqing"),
|
||||
Sector12: new Faction("Sector-12"),
|
||||
HongKong: new Faction("New Tokyo"),
|
||||
Aevum: new Faction("Aevum"),
|
||||
Ishima: new Faction("Ishima"),
|
||||
Volhaven: new Faction("Volhaven"),
|
||||
|
||||
//Criminal Organizations/Gangs
|
||||
|
||||
|
48
src/Netscript/Environment.js
Normal file
48
src/Netscript/Environment.js
Normal file
@ -0,0 +1,48 @@
|
||||
/* Environment
|
||||
* NetScript program environment
|
||||
*/
|
||||
function Environment(parent) {
|
||||
this.vars = Object.create(parent ? parent.vars : null);
|
||||
this.parent = parent;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
124
src/Netscript/Evaluator.js
Normal file
124
src/Netscript/Evaluator.js
Normal file
@ -0,0 +1,124 @@
|
||||
/* Evaluator
|
||||
* Evaluates the Abstract Syntax Tree for Netscript
|
||||
* generated by the Parser class
|
||||
*/
|
||||
|
||||
function evaluate(exp, env) {
|
||||
switch (exp.type) {
|
||||
case "num":
|
||||
case "str":
|
||||
case "bool":
|
||||
return exp.value;
|
||||
|
||||
case "var":
|
||||
return env.get(exp.value);
|
||||
|
||||
//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));
|
||||
|
||||
case "binary":
|
||||
return apply_op(exp.operator,
|
||||
evaluate(exp.left, env),
|
||||
evaluate(exp.right, env));
|
||||
|
||||
|
||||
case "if":
|
||||
var numConds = exp.cond.length;
|
||||
var numThens = exp.then.length;
|
||||
if (numConds == 0 || numThens == 0 || numConds != numThens) {
|
||||
throw new Error ("Number of conds and thens in if structure don't match (or there are none)");
|
||||
}
|
||||
|
||||
for (var i = 0; i < numConds; i++) {
|
||||
var cond = evaluate(exp.cond[i], env);
|
||||
if (cond) return evaluate(exp.then, env);
|
||||
}
|
||||
|
||||
//Evaluate else if it exists, snce none of the conditionals
|
||||
//were true
|
||||
return exp.else ? evaluate(exp.else, env) : 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 Return somethin?
|
||||
break;
|
||||
case "while":
|
||||
cond = evaluate(exp.cond, env);
|
||||
|
||||
while (cond) {
|
||||
evaluate(exp.code, env);
|
||||
cond = evaluate(exp.cond, env);
|
||||
}
|
||||
|
||||
//TODO DO i need to return anything?
|
||||
break;
|
||||
case "prog":
|
||||
var val = false;
|
||||
exp.prog.forEach(function(exp){ val = evaluate(exp, env) });
|
||||
return val;
|
||||
|
||||
/* Currently supported function calls:
|
||||
* hack()
|
||||
* sleep(N) - sleep N seconds
|
||||
* print(x) - Prints a variable or constant
|
||||
*
|
||||
*/
|
||||
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);
|
||||
//}));
|
||||
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") {
|
||||
console.log(evaluate(exp.args[0], env));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("I don't know how to evaluate " + exp.type);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
@ -6,5 +6,248 @@
|
||||
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();
|
||||
|
||||
//Body
|
||||
var then = parse_expression();
|
||||
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);
|
||||
console.log("Parsing code in for loop");
|
||||
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() {
|
||||
console.log("Parsing while token");
|
||||
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() {
|
||||
console.log("Parsing prog token");
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
@ -3,27 +3,19 @@
|
||||
* Tokens can be accessed with peek() and next().
|
||||
*
|
||||
* Token types:
|
||||
* {type: "punc", value: "(" } // punctuation: parens, comma, semicolon etc.
|
||||
* {type: "num", value: 5 } // numbers
|
||||
* {type: "str", value: "Hello World!" } // strings
|
||||
* {type: "kw", value: "lambda" } // keywords
|
||||
* {type: "var", value: "a" } // identifiers
|
||||
* {type: "op", value: "!=" } // operators
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* {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 then else true false while for ";
|
||||
var keywords = " if elif else true false while for ";
|
||||
|
||||
return {
|
||||
next : next,
|
||||
|
@ -19,6 +19,7 @@ function Server() {
|
||||
|
||||
this.scripts = [];
|
||||
this.runningScripts = []; //Scripts currently being run
|
||||
this.scriptEnvs = []; //The environment for all of the running scripts. Matched by index number
|
||||
this.programs = [];
|
||||
|
||||
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
||||
|
@ -289,6 +289,19 @@ var Terminal = {
|
||||
case "scp":
|
||||
//TODO
|
||||
break;
|
||||
|
||||
case "test":
|
||||
//TODO
|
||||
//TESTED: print, for loops
|
||||
//UNTESTED:
|
||||
|
||||
var code = "i = 0; while (i < 100000000000) {print(i); i = i+1;}";
|
||||
var ast = Parser(Tokenizer(InputStream(code)));
|
||||
console.log("Printing AST below")
|
||||
console.log(ast);
|
||||
var globalEnv = new Environment();
|
||||
evaluate(ast, globalEnv);
|
||||
break;
|
||||
default:
|
||||
post("Command not found");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user