mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-23 14:42:28 +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/styles.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/terminal.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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mainmenu-container">
|
<div id="mainmenu-container">
|
||||||
@ -51,9 +70,7 @@
|
|||||||
<p id="character-info"> </p>
|
<p id="character-info"> </p>
|
||||||
</div> <!-- End terminal-container -->
|
</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 -->
|
<!-- Always keep the terminal in focus -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -65,9 +82,6 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</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>
|
</body>
|
||||||
</html>
|
</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.companyName = name;
|
||||||
this.salaryMult = salaryMult;
|
this.salaryMult = salaryMult;
|
||||||
this.expMult = expMult;
|
this.expMult = expMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
Company.prototype.addPosition(pos) {
|
Company.prototype.addPosition = function(pos) {
|
||||||
this.companyPositions.push(pos);
|
this.companyPositions.push(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Company.prototype.addPositions(positions) {
|
Company.prototype.addPositions = function(positions) {
|
||||||
for (var i = 0; i < positions.length; i++) {
|
for (var i = 0; i < positions.length; i++) {
|
||||||
this.addPosition(positions[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
|
//NOTE: These parameters should total to 100, such that each parameter represents a "weighting" of how
|
||||||
// important that stat/skill is for the job
|
// 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) {
|
if (hackEff + strEff + defEff + dexEff + agiEff + chaEff != 100) {
|
||||||
console.log("CompanyPosition.setPerformanceParameters() arguments do not total to 100");
|
console.log("CompanyPosition.setPerformanceParameters() arguments do not total to 100");
|
||||||
return;
|
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)
|
//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
|
//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.hackingExpGain = hack;
|
||||||
this.strengthExpGain = str;
|
this.strengthExpGain = str;
|
||||||
this.defenseExpGain = def;
|
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
|
//Calculate a player's effectiveness at a certain job. Returns the amount of job reputation
|
||||||
//that should be gained every game loop (200 ms)
|
//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 hackRatio = this.hackingEffectiveness * hacking / CONSTANTS.MaxSkillLevel;
|
||||||
var strRatio = this.strengthEffectiveness * str / CONSTANTS.MaxSkillLevel;
|
var strRatio = this.strengthEffectiveness * str / CONSTANTS.MaxSkillLevel;
|
||||||
var defRatio = this.defenseEffectiveness * def / CONSTANTS.MaxSkillLevel;
|
var defRatio = this.defenseEffectiveness * def / CONSTANTS.MaxSkillLevel;
|
||||||
@ -130,69 +130,69 @@ CompanyPositions = {
|
|||||||
init: function() {
|
init: function() {
|
||||||
//Argument order: hack, str, def, dex, agi, cha
|
//Argument order: hack, str, def, dex, agi, cha
|
||||||
//Software
|
//Software
|
||||||
SoftwareIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
CompanyPositions.SoftwareIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
||||||
SoftwareIntern.setExperienceGains(.1, 0, 0, 0, 0, .02);
|
CompanyPositions.SoftwareIntern.setExperienceGains(.1, 0, 0, 0, 0, .02);
|
||||||
JuniorDev.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
CompanyPositions.JuniorDev.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||||
JuniorDev.setExperienceGains(.2, 0, 0, 0, 0, .04);
|
CompanyPositions.JuniorDev.setExperienceGains(.2, 0, 0, 0, 0, .04);
|
||||||
SeniorDev.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
CompanyPositions.SeniorDev.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||||
SeniorDev.setExperienceGains(.4, 0, 0, 0, 0, .08);
|
CompanyPositions.SeniorDev.setExperienceGains(.4, 0, 0, 0, 0, .08);
|
||||||
LeadDev.setPerformanceParameters(70, 0, 0, 0, 0, 30);
|
CompanyPositions.LeadDev.setPerformanceParameters(70, 0, 0, 0, 0, 30);
|
||||||
LeadDev.setExperienceGains(.5, 0, 0, 0, 0, .1);
|
CompanyPositions.LeadDev.setExperienceGains(.5, 0, 0, 0, 0, .1);
|
||||||
|
|
||||||
//Security
|
//Security
|
||||||
ITIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
CompanyPositions.ITIntern.setPerformanceParameters(90, 0, 0, 0, 0, 10);
|
||||||
ITIntern.setExperienceGains(.05, 0, 0, 0, 0, .01);
|
CompanyPositions.ITIntern.setExperienceGains(.05, 0, 0, 0, 0, .01);
|
||||||
ITAnalyst.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
CompanyPositions.ITAnalyst.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||||
ITAnalyst.setExperienceGains(.15, 0, 0, 0, 0, .02);
|
CompanyPositions.ITAnalyst.setExperienceGains(.15, 0, 0, 0, 0, .02);
|
||||||
ITManager.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
CompanyPositions.ITManager.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||||
ITManager.setExperienceGains(.4, 0, 0, 0, 0, .1);
|
CompanyPositions.ITManager.setExperienceGains(.4, 0, 0, 0, 0, .1);
|
||||||
SysAdmin.setPerformanceParameters(80, 0, 0, 0, 0, 20);
|
CompanyPositions.SysAdmin.setPerformanceParameters(80, 0, 0, 0, 0, 20);
|
||||||
SysAdmin.setExperienceGains(.5, 0, 0, 0, 0, .05);
|
CompanyPositions.SysAdmin.setExperienceGains(.5, 0, 0, 0, 0, .05);
|
||||||
SecurityEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
CompanyPositions.SecurityEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||||
SecurityEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
CompanyPositions.SecurityEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
||||||
NetworkEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
CompanyPositions.NetworkEngineer.setPerformanceParameters(85, 0, 0, 0, 0, 15);
|
||||||
NetworkEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
CompanyPositions.NetworkEngineer.setExperienceGains(0.4, 0, 0, 0, 0, .05);
|
||||||
NetworkAdministrator.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
CompanyPositions.NetworkAdministrator.setPerformanceParameters(75, 0, 0, 0, 0, 25);
|
||||||
NetworkAdministrator.setExperienceGains(0.5, 0, 0, 0, 0, .1);
|
CompanyPositions.NetworkAdministrator.setExperienceGains(0.5, 0, 0, 0, 0, .1);
|
||||||
|
|
||||||
//Technology management
|
//Technology management
|
||||||
HeadOfSoftware.setPerformanceParameters(65, 0, 0, 0, 0, 35);
|
CompanyPositions.HeadOfSoftware.setPerformanceParameters(65, 0, 0, 0, 0, 35);
|
||||||
HeadOfSoftware.setExperienceGains(1, 0, 0, 0, 0, .5);
|
CompanyPositions.HeadOfSoftware.setExperienceGains(1, 0, 0, 0, 0, .5);
|
||||||
HeadOfEngineering.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
CompanyPositions.HeadOfEngineering.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
||||||
HeadOfEngineering.setExperienceGains(1.1, 0, 0, 0, 0, .5);
|
CompanyPositions.HeadOfEngineering.setExperienceGains(1.1, 0, 0, 0, 0, .5);
|
||||||
VicePresident.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
CompanyPositions.VicePresident.setPerformanceParameters(60, 0, 0, 0, 0, 40);
|
||||||
VicePresident.setExperienceGains(1.2, 0, 0, 0, 0, .6);
|
CompanyPositions.VicePresident.setExperienceGains(1.2, 0, 0, 0, 0, .6);
|
||||||
CTO.setPerformanceParameters(50, 0, 0, 0, 0, 50);
|
CompanyPositions.CTO.setPerformanceParameters(50, 0, 0, 0, 0, 50);
|
||||||
CTO.setExperienceGains(1.5, 0, 0, 0, 1);
|
CompanyPositions.CTO.setExperienceGains(1.5, 0, 0, 0, 1);
|
||||||
|
|
||||||
//Business
|
//Business
|
||||||
BusinessIntern.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
CompanyPositions.BusinessIntern.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||||
BusinessIntern.setExperienceGains(.01, 0, 0, 0, 0, .1);
|
CompanyPositions.BusinessIntern.setExperienceGains(.01, 0, 0, 0, 0, .1);
|
||||||
BusinessAnalyst.setPerformanceParameters(20, 0, 0, 0, 0, 80);
|
CompanyPositions.BusinessAnalyst.setPerformanceParameters(20, 0, 0, 0, 0, 80);
|
||||||
BusinessAnalyst.setExperienceGains(.02, 0, 0, 0, 0, .2);
|
CompanyPositions.BusinessAnalyst.setExperienceGains(.02, 0, 0, 0, 0, .2);
|
||||||
BusinessManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
CompanyPositions.BusinessManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
||||||
BusinessManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
CompanyPositions.BusinessManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
||||||
OperationsManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
CompanyPositions.OperationsManager.setPerformanceParameters(15, 0, 0, 0, 0, 85);
|
||||||
OperationsManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
CompanyPositions.OperationsManager.setExperienceGains(.02, 0, 0, 0, 0, .4);
|
||||||
CFO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
CompanyPositions.CFO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||||
CFO.setExperienceGains(.05, 0, 0, 0, 0, 1);
|
CompanyPositions.CFO.setExperienceGains(.05, 0, 0, 0, 0, 1);
|
||||||
CEO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
CompanyPositions.CEO.setPerformanceParameters(10, 0, 0, 0, 0, 90);
|
||||||
CEO.setExperienceGains(.1, 0, 0, 0, 0, 1.5);
|
CompanyPositions.CEO.setExperienceGains(.1, 0, 0, 0, 0, 1.5);
|
||||||
|
|
||||||
//Non-tech/management jobs
|
//Non-tech/management jobs
|
||||||
//TODO These parameters might need to be balanced
|
//TODO These parameters might need to be balanced
|
||||||
Waiter.setPerformanceParameters(0, 10, 0, 10, 10, 70);
|
CompanyPositions.Waiter.setPerformanceParameters(0, 10, 0, 10, 10, 70);
|
||||||
Waiter.setExperienceGains(0, .01, 0, .01, .01, .05);
|
CompanyPositions.Waiter.setExperienceGains(0, .01, 0, .01, .01, .05);
|
||||||
SecurityGuard.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
CompanyPositions.SecurityGuard.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
||||||
SecurityGuard.setExperienceGains(.01, .02, .02, .02, .02, .01);
|
CompanyPositions.SecurityGuard.setExperienceGains(.01, .02, .02, .02, .02, .01);
|
||||||
PoliceOfficer.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
CompanyPositions.PoliceOfficer.setPerformanceParameters(5, 20, 20, 20, 20, 15);
|
||||||
PoliceOfficer.setExperienceGains(.01, .04, .04, .04, .04, .02);
|
CompanyPositions.PoliceOfficer.setExperienceGains(.01, .04, .04, .04, .04, .02);
|
||||||
SecurityOfficer.setPerformanceParameters(10, 20, 20, 20, 20, 10);
|
CompanyPositions.SecurityOfficer.setPerformanceParameters(10, 20, 20, 20, 20, 10);
|
||||||
SecurityOfficer.setExperienceGains(.02, .06, .06, .06, .06, .04);
|
CompanyPositions.SecurityOfficer.setExperienceGains(.02, .06, .06, .06, .06, .04);
|
||||||
SecuritySupervisor.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
CompanyPositions.SecuritySupervisor.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
||||||
SecuritySupervisor.setExperienceGains(.02, .06, .06, .06, .06, .08);
|
CompanyPositions.SecuritySupervisor.setExperienceGains(.02, .06, .06, .06, .06, .08);
|
||||||
HeadOfSecurity.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
CompanyPositions.HeadOfSecurity.setPerformanceParameters(10, 15, 15, 15, 15, 30);
|
||||||
HeadOfSecurity.setExperienceGains(.05, .1, .1, .1, .1, .1);
|
CompanyPositions.HeadOfSecurity.setExperienceGains(.05, .1, .1, .1, .1, .1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ Companies = {
|
|||||||
SysCoreSecurities: new Company(),
|
SysCoreSecurities: new Company(),
|
||||||
CompuTek: new Company(),
|
CompuTek: new Company(),
|
||||||
NetLinkTechnologies: new Company(),
|
NetLinkTechnologies: new Company(),
|
||||||
CarmichaelSecurity: new Company();
|
CarmichaelSecurity: new Company(),
|
||||||
|
|
||||||
//"Low level" companies
|
//"Low level" companies
|
||||||
FoodNStuff: new Company(),
|
FoodNStuff: new Company(),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CONSTANTS = {
|
CONSTANTS = {
|
||||||
//Max level for any skill. Determined by max numerical value in javascript and the skill level
|
//Max level for any skill. Determined by max numerical value in javascript and the skill level
|
||||||
//formula in Player.js
|
//formula in Player.js
|
||||||
MaxSkillLevel: 1796;
|
MaxSkillLevel: 1796,
|
||||||
}
|
}
|
@ -9,11 +9,11 @@ function Faction(name) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//TODO
|
//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++) {
|
for (var i = 0; i < augs.length; i++) {
|
||||||
this.augmentations.push(augs[i]);
|
this.augmentations.push(augs[i]);
|
||||||
}
|
}
|
||||||
@ -22,33 +22,33 @@ Faction.prototype.setAugmentations(augs) {
|
|||||||
Factions = {
|
Factions = {
|
||||||
//TODO Saving this for later, IShima is a kinda cool name maybe use it for something
|
//TODO Saving this for later, IShima is a kinda cool name maybe use it for something
|
||||||
//Endgame
|
//Endgame
|
||||||
Illuminati: new Faction("Illuminati");
|
Illuminati: new Faction("Illuminati"),
|
||||||
Daedalus: new Faction("Daedalus");
|
Daedalus: new Faction("Daedalus"),
|
||||||
Covenant: new Faction("The Covenant");
|
Covenant: new Faction("The Covenant"),
|
||||||
|
|
||||||
//Megacorporations, each forms its own faction
|
//Megacorporations, each forms its own faction
|
||||||
ECorp: new Faction("ECorp");
|
ECorp: new Faction("ECorp"),
|
||||||
MegaCorp: new Faction("MegaCorp");
|
MegaCorp: new Faction("MegaCorp"),
|
||||||
BachmanAndAssociates: new Faction("Bachman & Associates");
|
BachmanAndAssociates: new Faction("Bachman & Associates"),
|
||||||
BladeIndustries: new Faction("Blade Industries");
|
BladeIndustries: new Faction("Blade Industries"),
|
||||||
NWO: new Faction("NWO");
|
NWO: new Faction("NWO"),
|
||||||
ClarkeIncorporated: new Faction("Clarke Incorporated");
|
ClarkeIncorporated: new Faction("Clarke Incorporated"),
|
||||||
OmniTekIncorporated: new Faction("OmniTek Incorporated");
|
OmniTekIncorporated: new Faction("OmniTek Incorporated"),
|
||||||
FourSigma: new Faction("Four Sigma");
|
FourSigma: new Faction("Four Sigma"),
|
||||||
KuaiGongInternational: new Faction("KuaiGong International");
|
KuaiGongInternational: new Faction("KuaiGong International"),
|
||||||
|
|
||||||
//Hacker groups
|
//Hacker groups
|
||||||
BitRunners: new Faction("BitRunners");
|
BitRunners: new Faction("BitRunners"),
|
||||||
BlackHand: new Faction("The Black Hand");
|
BlackHand: new Faction("The Black Hand"),
|
||||||
NiteSec: new Faction("NiteSec");
|
NiteSec: new Faction("NiteSec"),
|
||||||
|
|
||||||
//City factions, essentially governments
|
//City factions, essentially governments
|
||||||
Chongqing: new Faction("Chongqing");
|
Chongqing: new Faction("Chongqing"),
|
||||||
Sector12: new Faction("Sector-12");
|
Sector12: new Faction("Sector-12"),
|
||||||
HongKong: new Faction("New Tokyo");
|
HongKong: new Faction("New Tokyo"),
|
||||||
Aevum: new Faction("Aevum");
|
Aevum: new Faction("Aevum"),
|
||||||
Ishima: new Faction("Ishima");
|
Ishima: new Faction("Ishima"),
|
||||||
Volhaven: new Faction("Volhaven");
|
Volhaven: new Faction("Volhaven"),
|
||||||
|
|
||||||
//Criminal Organizations/Gangs
|
//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};
|
var FALSE = {type: "bool", value: false};
|
||||||
|
|
||||||
function Parser(input) {
|
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().
|
* Tokens can be accessed with peek() and next().
|
||||||
*
|
*
|
||||||
* Token types:
|
* Token types:
|
||||||
* {type: "punc", value: "(" } // punctuation: parens, comma, semicolon etc.
|
* {type: "punc", value: "(" } // punctuation: parens, comma, semicolon etc.
|
||||||
* {type: "num", value: 5 } // numbers
|
* {type: "num", value: 5 } // numbers (including floats)
|
||||||
* {type: "str", value: "Hello World!" } // strings
|
* {type: "str", value: "Hello World!" } // strings
|
||||||
* {type: "kw", value: "lambda" } // keywords
|
* {type: "kw", value: "for/if/" } // keywords, see defs below
|
||||||
* {type: "var", value: "a" } // identifiers
|
* {type: "var", value: "a" } // identifiers/variables
|
||||||
* {type: "op", value: "!=" } // operators
|
* {type: "op", value: "!=" } // operator characters
|
||||||
*
|
* {type: "bool", value: "true" } // Booleans
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Tokenizer(input) {
|
function Tokenizer(input) {
|
||||||
var current = null;
|
var current = null;
|
||||||
var keywords = " if then else true false while for ";
|
var keywords = " if elif else true false while for ";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
next : next,
|
next : next,
|
||||||
|
@ -19,6 +19,7 @@ function Server() {
|
|||||||
|
|
||||||
this.scripts = [];
|
this.scripts = [];
|
||||||
this.runningScripts = []; //Scripts currently being run
|
this.runningScripts = []; //Scripts currently being run
|
||||||
|
this.scriptEnvs = []; //The environment for all of the running scripts. Matched by index number
|
||||||
this.programs = [];
|
this.programs = [];
|
||||||
|
|
||||||
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
||||||
|
@ -289,6 +289,19 @@ var Terminal = {
|
|||||||
case "scp":
|
case "scp":
|
||||||
//TODO
|
//TODO
|
||||||
break;
|
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:
|
default:
|
||||||
post("Command not found");
|
post("Command not found");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user