jstanks: check for empty stack, display errors

This commit is contained in:
Alyssa Milburn 2014-07-30 15:17:18 +02:00
parent 01226a77c5
commit 013bca13cf
1 changed files with 51 additions and 27 deletions

View File

@ -73,22 +73,20 @@ var SPACING = 150;
var MEMORY_SIZE = 10; var MEMORY_SIZE = 10;
var Forf = function() { var Forf = function() {
this.datastack = [];
this.cmdstack = [];
this.mem = new Object(); this.mem = new Object();
this.builtins = new Object(); this.builtins = new Object();
this.builtins["debug!"] = function(myforf) { document.getElementById('debug').innerHTML = myforf.datastack.pop(); }; this.builtins["debug!"] = function(myforf) { document.getElementById('debug').innerHTML = myforf.popData(); };
var unfunc = function(func) { var unfunc = function(func) {
return function(myforf) { return function(myforf) {
var a = myforf.datastack.pop(); var a = myforf.popData();
myforf.datastack.push(~~func(a)); // truncate, FIXME myforf.datastack.push(~~func(a)); // truncate, FIXME
}; };
}; };
var binfunc = function(func) { var binfunc = function(func) {
return function(myforf) { return function(myforf) {
var a = myforf.datastack.pop(); var a = myforf.popData();
var b = myforf.datastack.pop(); var b = myforf.popData();
myforf.datastack.push(~~func(b,a)); // truncate?, FIXME myforf.datastack.push(~~func(b,a)); // truncate?, FIXME
}; };
}; };
@ -119,22 +117,22 @@ var Forf = function() {
this.builtins["abs"] = unfunc(function(a) { return Math.abs(a); }); this.builtins["abs"] = unfunc(function(a) { return Math.abs(a); });
// FIXME: the three following functions can only manipulate numbers in cforf // FIXME: the three following functions can only manipulate numbers in cforf
this.builtins["dup"] = function(myforf) { this.builtins["dup"] = function(myforf) {
var val = myforf.datastack.pop(); var val = myforf.popData();
myforf.datastack.push(val); myforf.datastack.push(val);
myforf.datastack.push(val); myforf.datastack.push(val);
}; };
this.builtins["pop"] = function(myforf) { this.builtins["pop"] = function(myforf) {
myforf.datastack.pop(); myforf.popData();
}; };
this.builtins["exch"] = function(myforf) { this.builtins["exch"] = function(myforf) {
var a = myforf.datastack.pop(); var a = myforf.popData();
var b = myforf.datastack.pop(); var b = myforf.popData();
myforf.datastack.push(a); myforf.datastack.push(a);
myforf.datastack.push(b); myforf.datastack.push(b);
}; };
this.builtins["if"] = function(myforf) { this.builtins["if"] = function(myforf) {
var ifclause = myforf.datastack.pop(); var ifclause = myforf.popData();
var cond = myforf.datastack.pop(); var cond = myforf.popData();
if (cond) { if (cond) {
// TODO: make sure ifclause is a list // TODO: make sure ifclause is a list
for (var i = 0; i < ifclause.length; i++) { for (var i = 0; i < ifclause.length; i++) {
@ -143,9 +141,9 @@ var Forf = function() {
} }
}; };
this.builtins["ifelse"] = function(myforf) { this.builtins["ifelse"] = function(myforf) {
var elseclause = myforf.datastack.pop(); var elseclause = myforf.popData();
var ifclause = myforf.datastack.pop(); var ifclause = myforf.popData();
var cond = myforf.datastack.pop(); var cond = myforf.popData();
if (!cond) { if (!cond) {
ifclause = elseclause; ifclause = elseclause;
} }
@ -155,15 +153,15 @@ var Forf = function() {
} }
}; };
this.builtins["mset"] = function(myforf) { this.builtins["mset"] = function(myforf) {
var pos = myforf.datastack.pop(); var pos = myforf.popData();
var a = myforf.datastack.pop(); var a = myforf.popData();
if (pos < 0 || pos >= MEMORY_SIZE) { if (pos < 0 || pos >= MEMORY_SIZE) {
throw "invalid memory location"; throw "invalid memory location";
} }
myforf.mem[pos] = a; myforf.mem[pos] = a;
}; };
this.builtins["mget"] = function(myforf) { this.builtins["mget"] = function(myforf) {
var pos = myforf.datastack.pop(); var pos = myforf.popData();
if (pos < 0 || pos >= MEMORY_SIZE) { if (pos < 0 || pos >= MEMORY_SIZE) {
throw "invalid memory location"; throw "invalid memory location";
} }
@ -171,11 +169,20 @@ var Forf = function() {
}; };
}; };
Forf.prototype.popData = function() {
if (this.datastack.length === 0) {
throw "tried to pop from empty stack";
}
return this.datastack.pop();
};
Forf.prototype.init = function(code) { Forf.prototype.init = function(code) {
this.code = code; this.code = code;
}; };
Forf.prototype.parse = function() { Forf.prototype.parse = function() {
this.cmdstack = [];
// 'parse' the input // 'parse' the input
this.code = this.code.replace(/\([^)]*\)/g, ""); this.code = this.code.replace(/\([^)]*\)/g, "");
var splitCode = this.code.split(/([{}])/).join(" "); var splitCode = this.code.split(/([{}])/).join(" ");
@ -214,6 +221,8 @@ Forf.prototype.parse = function() {
}; };
Forf.prototype.run = function() { Forf.prototype.run = function() {
this.datastack = [];
var running = true; var running = true;
while (running && this.cmdstack.length) { while (running && this.cmdstack.length) {
var val = this.cmdstack.pop(); var val = this.cmdstack.pop();
@ -222,7 +231,7 @@ Forf.prototype.run = function() {
if (val in this.builtins) { if (val in this.builtins) {
func(this); func(this);
} else { } else {
throw "no such function " + val; throw "no such function '" + val + "'";
} }
} else { } else {
this.datastack.push(val); this.datastack.push(val);
@ -258,12 +267,12 @@ var ForfTank = function() {
myforf.fire(); myforf.fire();
}; };
this.builtins["set-speed!"] = function(myforf) { this.builtins["set-speed!"] = function(myforf) {
var right = myforf.datastack.pop(); var right = myforf.popData();
var left = myforf.datastack.pop(); var left = myforf.popData();
myforf.setSpeed(left, right); myforf.setSpeed(left, right);
}; };
this.builtins["set-turret!"] = function(myforf) { this.builtins["set-turret!"] = function(myforf) {
var angle = myforf.datastack.pop(); var angle = myforf.popData();
myforf.setTurret(deg2rad(angle)); myforf.setTurret(deg2rad(angle));
}; };
this.builtins["get-turret"] = function(myforf) { this.builtins["get-turret"] = function(myforf) {
@ -271,15 +280,15 @@ var ForfTank = function() {
myforf.datastack.push(rad2deg(angle)); myforf.datastack.push(rad2deg(angle));
}; };
this.builtins["sensor?"] = function(myforf) { this.builtins["sensor?"] = function(myforf) {
var sensor_num = myforf.datastack.pop(); var sensor_num = myforf.popData();
myforf.datastack.push(myforf.getSensor(sensor_num)); myforf.datastack.push(myforf.getSensor(sensor_num));
}; };
this.builtins["set-led!"] = function(myforf) { this.builtins["set-led!"] = function(myforf) {
var active = myforf.datastack.pop(); var active = myforf.popData();
myforf.setLed(active); myforf.setLed(active);
}; };
this.builtins["random"] = function(myforf) { this.builtins["random"] = function(myforf) {
var max = myforf.datastack.pop(); var max = myforf.popData();
if (max < 1) { if (max < 1) {
myforf.datastack.push(0); myforf.datastack.push(0);
return; return;
@ -658,12 +667,25 @@ var updateTanks = function(tanks) {
} }
/* Run programs */ /* Run programs */
var errors = [];
for (var i = 0; i < tanks.length; i++) { for (var i = 0; i < tanks.length; i++) {
if (tanks[i].killer) { if (tanks[i].killer) {
continue; continue;
} }
tanks[i].parse(tanks[i].code); try {
tanks[i].run(); tanks[i].parse(tanks[i].code);
tanks[i].run();
} catch (e) {
errors.push(e);
}
}
if (errors.length) {
if (interval) {
clearInterval(interval);
}
document.getElementById('debug').innerHTML = "Error: " + errors.join();
return;
} }
/* Fire cannons and check for crashes */ /* Fire cannons and check for crashes */
@ -696,6 +718,8 @@ var resetTanks = function() {
clearInterval(interval); clearInterval(interval);
} }
document.getElementById('debug').innerHTML = "&nbsp;";
tanks = []; tanks = [];
ftanks = []; ftanks = [];
var tank; var tank;