mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
400 lines
14 KiB
JavaScript
400 lines
14 KiB
JavaScript
// standard print functions
|
|
function print(s) {
|
|
sys.print(s);
|
|
}
|
|
function println(s) {
|
|
if (s === undefined)
|
|
sys.print("\n");
|
|
else
|
|
sys.println(s);
|
|
}
|
|
function read() {
|
|
return sys.read();
|
|
}
|
|
// ncurses-like terminal control
|
|
var con = {};
|
|
con.getch = function() {
|
|
return sys.readKey();
|
|
};
|
|
con.move = function(y, x) {
|
|
print(String.fromCharCode(27,91)+y+";"+x+"H");
|
|
};
|
|
con.addch = function(c) {
|
|
graphics.putSymbol(c);
|
|
};
|
|
con.mvaddch = function(y, x, c) {
|
|
move(y, x); addch(c);
|
|
};
|
|
con.getmaxyx = function() {
|
|
return graphics.getTermDimension();
|
|
};
|
|
con.getyx = function() {
|
|
return graphics.getCursorYX();
|
|
};
|
|
con.hitterminate = function() { // ^C
|
|
sys.poke(-40, 1);
|
|
return (sys.peek(-41) == 31 && (sys.peek(-42) == 129 || sys.peek(-42) == 130));
|
|
};
|
|
con.hiteof = function() { // ^D
|
|
sys.poke(-40, 1);
|
|
return (sys.peek(-41) == 32 && (sys.peek(-42) == 129 || sys.peek(-42) == 130));
|
|
};
|
|
con.color_fore = function(n) { // 0..7; -1 for transparent
|
|
if (n < 0)
|
|
print(String.fromCharCode(27,91)+"38;5;255m");
|
|
else
|
|
print(String.fromCharCode(27,91)+((n % 8)+30)+"m");
|
|
};
|
|
con.color_back = function(n) { // 0..7; -1 for transparent
|
|
if (n < 0)
|
|
print(String.fromCharCode(27,91)+"48;5;255m");
|
|
else
|
|
print(String.fromCharCode(27,91)+((n % 8)+40)+"m");
|
|
};
|
|
con.color_pair = function(fore, back) { // 0..255
|
|
print(String.fromCharCode(27,91)+"38;5;"+fore+"m");
|
|
print(String.fromCharCode(27,91)+"48;5;"+back+"m");
|
|
};
|
|
Object.freeze(con);
|
|
// system management function
|
|
var system = {};
|
|
system.maxmem = function() {
|
|
return sys.peek(-65) | (sys.peek(-66) << 8) | (sys.peek(-67) << 16) | (sys.peek(-68) << 24);
|
|
};
|
|
system.halt = function() {
|
|
exit();
|
|
};
|
|
Object.freeze(system);
|
|
// some utilities functions
|
|
var base64 = {};
|
|
base64._lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
base64._revLookup = {"":0,"=":0,"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25,"a":26,"b":27,"c":28,"d":29,"e":30,"f":31,"g":32,"h":33,"i":34,"j":35,"k":36,"l":37,"m":38,"n":39,"o":40,"p":41,"q":42,"r":43,"s":44,"t":45,"u":46,"v":47,"w":48,"x":49,"y":50,"z":51,"0":52,"1":53,"2":54,"3":55,"4":56,"5":57,"6":58,"7":59,"8":60,"9":61,"+":62,"/":63};
|
|
base64.atobarr = function(base64str) {
|
|
var modulo = base64str.length % 4;
|
|
var ret = [];
|
|
for (var i = 0; i < base64str.length + modulo; i += 4) {
|
|
var bits = (base64._revLookup[base64str[i]] << 18) | (base64._revLookup[base64str[i+1]] << 12) | (base64._revLookup[base64str[i+2]] << 6) | (base64._revLookup[base64str[i+3]]);
|
|
var pads = (base64str[i+2] == "=") ? 2 : ((base64str[i+3] == "=") ? 1 : 0);
|
|
|
|
ret.push((bits >> 16) & 255);
|
|
if (pads <= 1) ret.push((bits >> 8) & 255);
|
|
if (pads == 0) ret.push(bits & 255);
|
|
}
|
|
return ret;
|
|
};
|
|
base64.atob = function(base64str) {
|
|
var modulo = base64str.length % 4;
|
|
var ret = "";
|
|
for (var i = 0; i < base64str.length + modulo; i += 4) {
|
|
var bits = (base64._revLookup[base64str[i]] << 18) | (base64._revLookup[base64str[i+1]] << 12) | (base64._revLookup[base64str[i+2]] << 6) | (base64._revLookup[base64str[i+3]]);
|
|
var pads = (base64str[i+2] == "=") ? 2 : ((base64str[i+3] == "=") ? 1 : 0);
|
|
|
|
ret += String.fromCharCode((bits >> 16) & 255);
|
|
if (pads <= 1) ret += String.fromCharCode((bits >> 8) & 255);
|
|
if (pads == 0) ret += String.fromCharCode(bits & 255);
|
|
}
|
|
return ret;
|
|
};
|
|
base64.btoa = function(inputString) {
|
|
var modulo = inputString.length % 3;
|
|
var outStr = "";
|
|
if (Array.isArray(inputString)) {
|
|
for (var i = 0; i < inputString.length + ((modulo == 0) ? 0 : 3 - modulo); i += 3) {
|
|
var bytes = (inputString[i] << 16) | (inputString[i+1] << 8) | inputString[i+2];
|
|
// for arrays, out-of-bounds have value of undefined;
|
|
// for strings, out-of-bounds have value of NaN -- both are casted into int 0 on bitwise operations.
|
|
|
|
outStr += base64._lookup[(bytes >> 18) & 63];
|
|
outStr += base64._lookup[(bytes >> 12) & 63];
|
|
if (i < Math.floor(inputString.length / 3) * 3 | (modulo == 2 || modulo == 0)) outStr += base64._lookup[(bytes >> 6) & 63];
|
|
if (i < Math.floor(inputString.length / 3) * 3 | modulo == 0) outStr += base64._lookup[bytes & 63];
|
|
}
|
|
// pad the output
|
|
if (modulo == 1) outStr += "==";
|
|
else if (modulo == 2) outStr += "=";
|
|
}
|
|
else if (typeof inputString == "string") {
|
|
for (var i = 0; i < inputString.length + ((modulo == 0) ? 0 : 3 - modulo); i += 3) {
|
|
var bytes = (inputString.charCodeAt(i) << 16) | (inputString.charCodeAt(i+1) << 8) | inputString.charCodeAt(i+2);
|
|
// for arrays, out-of-bounds have value of undefined;
|
|
// for strings, out-of-bounds have value of NaN -- both are casted into int 0 on bitwise operations.
|
|
|
|
outStr += base64._lookup[(bytes >> 18) & 63];
|
|
outStr += base64._lookup[(bytes >> 12) & 63];
|
|
if (i < Math.floor(inputString.length / 3) * 3 | (modulo == 2 || modulo == 0)) outStr += base64._lookup[(bytes >> 6) & 63];
|
|
if (i < Math.floor(inputString.length / 3) * 3 | modulo == 0) outStr += base64._lookup[bytes & 63];
|
|
}
|
|
// pad the output
|
|
if (modulo == 1) outStr += "==";
|
|
else if (modulo == 2) outStr += "=";
|
|
}
|
|
else {
|
|
throw "Unknown byte representation (with typeof "+typeof bytes+")";
|
|
}
|
|
|
|
return outStr;
|
|
};
|
|
Object.freeze(base64);
|
|
// Polyfilling some functions from ECMAScript6+
|
|
if (!String.prototype.repeat) {
|
|
String.prototype.repeat = function(count) {
|
|
'use strict';
|
|
if (this == null)
|
|
throw new TypeError('can\'t convert ' + this + ' to object');
|
|
|
|
var str = '' + this;
|
|
// To convert string to integer.
|
|
count = +count;
|
|
// Check NaN
|
|
if (count != count)
|
|
count = 0;
|
|
|
|
if (count < 0)
|
|
throw new RangeError('repeat count must be non-negative');
|
|
|
|
if (count == Infinity)
|
|
throw new RangeError('repeat count must be less than infinity');
|
|
|
|
count = Math.floor(count);
|
|
if (str.length == 0 || count == 0)
|
|
return '';
|
|
|
|
// Ensuring count is a 31-bit integer allows us to heavily optimize the
|
|
// main part. But anyway, most current (August 2014) browsers can't handle
|
|
// strings 1 << 28 chars or longer, so:
|
|
if (str.length * count >= 1 << 28)
|
|
throw new RangeError('repeat count must not overflow maximum string size');
|
|
|
|
var maxCount = str.length * count;
|
|
count = Math.floor(Math.log(count) / Math.log(2));
|
|
while (count) {
|
|
str += str;
|
|
count--;
|
|
}
|
|
str += str.substring(0, maxCount - str.length);
|
|
return str;
|
|
}
|
|
}
|
|
if (!Array.prototype.filter){
|
|
Array.prototype.filter = function(func, thisArg) {
|
|
'use strict';
|
|
if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
|
|
throw new TypeError();
|
|
|
|
var len = this.length >>> 0,
|
|
res = new Array(len), // preallocate array
|
|
t = this, c = 0, i = -1;
|
|
|
|
var kValue;
|
|
if (thisArg === undefined){
|
|
while (++i !== len){
|
|
// checks to see if the key was set
|
|
if (i in this){
|
|
kValue = t[i]; // in case t is changed in callback
|
|
if (func(t[i], i, t)){
|
|
res[c++] = kValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
while (++i !== len){
|
|
// checks to see if the key was set
|
|
if (i in this){
|
|
kValue = t[i];
|
|
if (func.call(thisArg, t[i], i, t)){
|
|
res[c++] = kValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
res.length = c; // shrink down array to proper size
|
|
return res;
|
|
};
|
|
}
|
|
// Production steps of ECMA-262, Edition 5, 15.4.4.19
|
|
// Reference: http://es5.github.io/#x15.4.4.19
|
|
if (!Array.prototype.map) {
|
|
|
|
Array.prototype.map = function(callback/*, thisArg*/) {
|
|
|
|
var T, A, k;
|
|
|
|
if (this == null) {
|
|
throw new TypeError('this is null or not defined');
|
|
}
|
|
|
|
// 1. Let O be the result of calling ToObject passing the |this|
|
|
// value as the argument.
|
|
var O = Object(this);
|
|
|
|
// 2. Let lenValue be the result of calling the Get internal
|
|
// method of O with the argument "length".
|
|
// 3. Let len be ToUint32(lenValue).
|
|
var len = O.length >>> 0;
|
|
|
|
// 4. If IsCallable(callback) is false, throw a TypeError exception.
|
|
// See: http://es5.github.com/#x9.11
|
|
if (typeof callback !== 'function') {
|
|
throw new TypeError(callback + ' is not a function');
|
|
}
|
|
|
|
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
|
if (arguments.length > 1) {
|
|
T = arguments[1];
|
|
}
|
|
|
|
// 6. Let A be a new array created as if by the expression new Array(len)
|
|
// where Array is the standard built-in constructor with that name and
|
|
// len is the value of len.
|
|
A = new Array(len);
|
|
|
|
// 7. Let k be 0
|
|
k = 0;
|
|
|
|
// 8. Repeat, while k < len
|
|
while (k < len) {
|
|
|
|
var kValue, mappedValue;
|
|
|
|
// a. Let Pk be ToString(k).
|
|
// This is implicit for LHS operands of the in operator
|
|
// b. Let kPresent be the result of calling the HasProperty internal
|
|
// method of O with argument Pk.
|
|
// This step can be combined with c
|
|
// c. If kPresent is true, then
|
|
if (k in O) {
|
|
|
|
// i. Let kValue be the result of calling the Get internal
|
|
// method of O with argument Pk.
|
|
kValue = O[k];
|
|
|
|
// ii. Let mappedValue be the result of calling the Call internal
|
|
// method of callback with T as the this value and argument
|
|
// list containing kValue, k, and O.
|
|
mappedValue = callback.call(T, kValue, k, O);
|
|
|
|
// iii. Call the DefineOwnProperty internal method of A with arguments
|
|
// Pk, Property Descriptor
|
|
// { Value: mappedValue,
|
|
// Writable: true,
|
|
// Enumerable: true,
|
|
// Configurable: true },
|
|
// and false.
|
|
|
|
// In browsers that support Object.defineProperty, use the following:
|
|
// Object.defineProperty(A, k, {
|
|
// value: mappedValue,
|
|
// writable: true,
|
|
// enumerable: true,
|
|
// configurable: true
|
|
// });
|
|
|
|
// For best browser support, use the following:
|
|
A[k] = mappedValue;
|
|
}
|
|
// d. Increase k by 1.
|
|
k++;
|
|
}
|
|
|
|
// 9. return A
|
|
return A;
|
|
};
|
|
}
|
|
// Production steps of ECMA-262, Edition 5, 15.4.4.21
|
|
// Reference: http://es5.github.io/#x15.4.4.21
|
|
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
|
|
if (!Array.prototype.reduce) {
|
|
Object.defineProperty(Array.prototype, 'reduce', {
|
|
value: function(callback /*, initialValue*/) {
|
|
if (this === null) {
|
|
throw new TypeError( 'Array.prototype.reduce ' +
|
|
'called on null or undefined' );
|
|
}
|
|
if (typeof callback !== 'function') {
|
|
throw new TypeError( callback +
|
|
' is not a function');
|
|
}
|
|
|
|
// 1. Let O be ? ToObject(this value).
|
|
var o = Object(this);
|
|
|
|
// 2. Let len be ? ToLength(? Get(O, "length")).
|
|
var len = o.length >>> 0;
|
|
|
|
// Steps 3, 4, 5, 6, 7
|
|
var k = 0;
|
|
var value;
|
|
|
|
if (arguments.length >= 2) {
|
|
value = arguments[1];
|
|
} else {
|
|
while (k < len && !(k in o)) {
|
|
k++;
|
|
}
|
|
|
|
// 3. If len is 0 and initialValue is not present,
|
|
// throw a TypeError exception.
|
|
if (k >= len) {
|
|
throw new TypeError( 'Reduce of empty array ' +
|
|
'with no initial value' );
|
|
}
|
|
value = o[k++];
|
|
}
|
|
|
|
// 8. Repeat, while k < len
|
|
while (k < len) {
|
|
// a. Let Pk be ! ToString(k).
|
|
// b. Let kPresent be ? HasProperty(O, Pk).
|
|
// c. If kPresent is true, then
|
|
// i. Let kValue be ? Get(O, Pk).
|
|
// ii. Let accumulator be ? Call(
|
|
// callbackfn, undefined,
|
|
// « accumulator, kValue, k, O »).
|
|
if (k in o) {
|
|
value = callback(value, o[k], k, o);
|
|
}
|
|
|
|
// d. Increase k by 1.
|
|
k++;
|
|
}
|
|
|
|
// 9. Return accumulator.
|
|
return value;
|
|
}
|
|
});
|
|
}
|
|
// Production steps of ECMA-262, Edition 5, 15.4.4.22
|
|
// Reference: http://es5.github.io/#x15.4.4.22
|
|
if ('function' !== typeof Array.prototype.reduceRight) {
|
|
Array.prototype.reduceRight = function(callback /*, initialValue*/) {
|
|
'use strict';
|
|
if (null === this || 'undefined' === typeof this) {
|
|
throw new TypeError('Array.prototype.reduce called on null or undefined');
|
|
}
|
|
if ('function' !== typeof callback) {
|
|
throw new TypeError(callback + ' is not a function');
|
|
}
|
|
var t = Object(this), len = t.length >>> 0, k = len - 1, value;
|
|
if (arguments.length >= 2) {
|
|
value = arguments[1];
|
|
} else {
|
|
while (k >= 0 && !(k in t)) {
|
|
k--;
|
|
}
|
|
if (k < 0) {
|
|
throw new TypeError('Reduce of empty array with no initial value');
|
|
}
|
|
value = t[k--];
|
|
}
|
|
for (; k >= 0; k--) {
|
|
if (k in t) {
|
|
value = callback(value, t[k], k, t);
|
|
}
|
|
}
|
|
return value;
|
|
};
|
|
}
|
|
|