load("compiler.js"); var MAXINT = 4294967295; function wraparound(x) { if (!isFinite(x)) return 0; var r = Math.floor(x); while (r < 0) r = (r + MAXINT) + 1; // Don't trust the JavaScript. while (r > MAXINT) r = (r - MAXINT) - 1; return r; } function inbounds(x) { return (x>=0 && x<=MAXINT); } function variadic_math_hat(op, init) { var code = "({ state: " + init + ",\n"; code += "push: function(x) { this.state = wraparound(this.state " + op + " wraparound(x)); },\n"; code += "pop: function() { var val=this.state; this.state=" + init + "; return val; }})"; return eval(code); } function binary_math_hat(op) { var code = "({ state: [],\n"; code += "push: function(x) { this.state.push(x); },\n"; code += "pop: function() { if (this.state.length != 2) throw 'hat call with invalid number of arguments'; "; code += "else { var val = wraparound(wraparound(this.state[0]) " + op + " wraparound(this.state[1])); this.state=[]; return val; }}})"; return eval(code); } function make_standard_hats() { var standard_hats = { // Core hats. pred: { state: 0, push: function(x) { this.state = x; }, pop: function() { this.state = wraparound(this.state-1); return this.state; } }, succ: { state: 0, push: function(x) { this.state = x; }, pop: function() { this.state = wraparound(this.state+1); return this.state; } }, horn: { state: null, push: function(x) { this.state = x; }, pop: function() { if (typeof(this.state) == "number") return this.state; else throw 'horn uninitialized: ' + typeof this.state; } }, if: { state: [], push: function(x) { this.state.push(x); }, pop: function() { var val; if (this.state.length != 3) throw 'if called with an invalid number if arguments (' + this.state.length + ')'; if (this.state[0] != 0) val = this.state[1]; else val = this.state[2]; this.state = []; return val; } }, nop: { hatid: 0, push: function(x) {}, pop: function() {} }, apply: { hatid: 1, name: 'apply', push: function(x) { throw 'compiler is broken (apply hat called directly)'; }, pop: function() { throw 'compiler is broken (apply hat called directly)'; } }, // Prelude hats. equal: { state: null, push: function(x) { if (this.state==null) this.state = x; else if (this.state != x) this.state = false; }, pop: function() { var val = this.state; this.state = null; if (val==null) throw 'equal uninitialized' else if (val==false) return 0; else return 1; } }, less: { state: null, push: function(x) { if (this.state==null) this.state = x; else if (typeof(this.state) == "boolean") throw 'less with too many arguments'; else if (this.state < x) this.state = true; else this.state = false; }, pop: function() { var val = this.state; this.state = null; if (typeof(val) == "boolean") return Number(val); else throw 'less uninitialized'; } }, add: variadic_math_hat('+', 0), mul: variadic_math_hat('*', 1), div: binary_math_hat('/'), mod: binary_math_hat('%'), and: variadic_math_hat('&&', 1), or: variadic_math_hat('||', 0), neg: { state: null, push: function(x) { if (this.state==null) this.state = x; else throw 'null with too many arguments'; }, pop: function() { var val=this.state; this.state=null; if (val==null) throw 'null uninitialized'; else return wraparound(-val); } }, // I/O hats. stdio: { input_callback: null, output_callback: null, push: function(x) { this.output_callback(x); }, pop: function() { return this.input_callback(); } } } var hatid = 2; for (var h in standard_hats) { if (standard_hats[h].hatid == undefined) standard_hats[h].hatid = hatid++; } return standard_hats; }