Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1210 lines (1081 sloc) 33.721 kB
/*
Copyright © 2011, 2012 MLstate
This file is part of Opa.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/////////////////////////////////////////////////////////////////////////////
// NO LONGER SHARED BETWEEN NODE BSL AND JS BSL DUE TO FLOAT_PARSER IMPORT //
/////////////////////////////////////////////////////////////////////////////
/** @externType int32 */
/** @externType int64 */
/** @opaType outcome('a, 'b) */
// We should really use "const" here but it's not cross-browser compatible.
// Is it ok to use const in server-side only code?
// What about function myconst() { return "const"; }
var POW2_32 = 0x0000000100000000; // 2^32
var IMIN32 = -0x0000000100000000; // -2^32
var IMAX32 = 0x00000000ffffffff; // 2^32-1
var POW2_52 = 0x0010000000000000; // 2^52
var IMIN52 = -0x0010000000000000; // -2^52
var IMAX52 = 0x000fffffffffffff; // 2^52-1
var POW2_53 = 0x0020000000000000; // 2^53
var IMIN53 = -0x0020000000000000; // -2^53
var IMAX53 = 0x001fffffffffffff; // 2^53-1
var qNaNstr_be = "\x7f\xc0\x00\x00\x00\x00\x00\x00"; // quiet NaN with no payload
var qNaNstr_le = "\x00\x00\x00\x00\x00\x00\xc0\x7f";
function qNaNstr(le) { return (le) ? qNaNstr_le : qNaNstr_be; }
var qNaNarray_be = [0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; // quiet NaN with no payload as an array
var qNaNarray_le = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f];
function qNaNarray(le) { return (le) ? qNaNarray_le : qNaNarray_be; }
/** @module Int */
// Note: for bitwise ops you only get 32 bits - and they're sign extended
/** @register {int} max_int max_int */
var max_int = Math.pow(2, 53);
/**
* @register {string -> int} of_string
* @pure
*/
function int_of_string(str) {
if (str.length < 2)
return parseInt(str,10);
else {
var hex = /^0x/;
var is_hex = str.match(hex);
if (is_hex != null)
return parseInt(str,16);
else {
var oct = /^0o/;
var is_oct = str.match(oct);
if (is_oct != null) {
return parseInt(str,8);
}
else
return parseInt(str,10)
}
}
}
/**
* @register {string -> opa[option(int)]} of_string_opt
* @pure
*/
function int_of_string_opt(str) {
try {
js_some(int_of_string(str));
} catch(e) {
return js_none;
}
}
/**
* @register {float -> int} of_float
* @pure
*/
function int_of_float(a) {
if (a<0)
return Math.ceil(a); // because Math.floor(-3.1) = 4 and not 3
else
return Math.floor(a);
}
// For bitwise you get: floats -> 32-bit ints -> op -> 32-bit ints -> float
// If you try bitwise ops outside of the 32-bit range the results just don't make sense, or are imprecise
// I think it would be safer to just return NaN for values outside this range (or undefined?)
/**
* @register {int, int -> int} op_land
* @pure
*/
function int_op_land(n, m) {
if (n < IMIN32 || n > IMAX32 || m < IMIN32 || m > IMAX32) return NaN;
return n & m;
}
/**
* @register {int, int -> int} op_lor
* @pure
*/
function int_op_lor(n, m) {
if (n < IMIN32 || n > IMAX32 || m < IMIN32 || m > IMAX32) return NaN;
return n | m;
}
/**
* @register {int, int -> int} op_lxor
* @pure
*/
function int_op_lxor(n, m) {
if (n < IMIN32 || n > IMAX32 || m < IMIN32 || m > IMAX32) return NaN;
return n ^ m;
}
/**
* @register {int -> int} op_lnot
* @pure
*/
function int_op_lnot(n) {
if (n < IMIN32 || n > IMAX32) return NaN;
return ~n;
}
/**
* @register {int, int -> int} op_lsl
* @pure
*/
function int_op_lsl(n, m) {
if (m >= 32 || n < IMIN32 || n > IMAX32) return NaN;
return n << m;
}
/**
* @register {int, int -> int} op_lsr
* @pure
*/
function int_op_lsr(n, m) {
if (m >= 32) return 0;
if (n < IMIN32 || n > IMAX32) return NaN;
return n >>> m;
}
/**
* @register {int, int -> int} op_asr
* @pure
*/
function int_op_asr(n, m) {
if (n < IMIN32 || n > IMAX32) return NaN;
if (m >= 32) return (n & 0x80000000) ? -1 : 0;
return n >> m;
}
/**
* @register {int, int -> bool} leq
* @pure
*/
function int_leq(c1,c2) {
return c1 <= c2
}
/**
* @register {int, int -> bool} geq
* @pure
*/
function int_geq(c1,c2) {
return c1 >= c2
}
/**
* @register {int,int -> opa[Order.ordering]} ordering
* @pure
*/
function int_ordering(c1,c2) {
if(c1<c2) return result_lt
if(c1==c2) return result_eq
return result_gt
}
/** @endModule */
/** @module BslInt64 */
// Note these are *unsigned* int64 routines.
/* Explanation: Why do we have all these strange routines here?
* Basically because JS ints are 53 bits in accuracy but that
* bitwise operations are restricted to 32-bit *sign-extended*
* ints. That is, ~0 === -1. Since we implement int64 as:
* {h:<high 32 bits>, l:<low 32 bits>} we can't tolerate any of
* the sign extension which goes on, we need {h:0x80000000, ...}
* and not {h:-0x80000000, ...}. To prevent JS from sign extending
* we have to do our bitwise ops as:
* if (op x) has bit 31 set then ((op x) resulting in bit 31 not set)+0x80000000.
* This is greatly inconvenient and slow but seems to work.
*/
/* Debug code
function to_hex_(i) {
if (typeof i == 'undefined') return "undefind";
var s = i.toString(16);
while (s.length < 8) s = "0"+s;
return s;
}
function p(i) { return "{h:"+to_hex_(i.h)+", l:"+to_hex_(i.l)+"}"; }
function q(qr) { return "{q:"+p(qr.q)+", r:"+p(qr.r)+"}"; }
*/
// These get passed around an awful lot...
// ... so we'll prevent them from being accidentally modified.
function NAN() { return {h:NaN, l:NaN}; }
function ZERO() { return {h:0, l:0}; }
function ONE() { return {h:0, l:1}; }
function INFINITY() { return {h:Infinity, l:Infinity}; }
function MAX_INT() { return {h:0xffffffff, l:0xffffffff}; }
function is_nan(i) { return isNaN(i.h) || isNaN(i.l); }
function is_zero(i) { return i.h === 0 && i.l === 0; }
function is_one(i) { return i.h === 0 && i.l === 1; }
function is_finite(i) { return isFinite(i.h) && isFinite(i.l); }
// For debugging...
/**
* @register {( -> 'a) -> opa[outcome('a,string)]} catch
*/
function bslnumber_catch(f) {
try {
return {success:f()};
} catch (err) {
return {failure:err};
}
}
/**
* @register { -> int64} max_int
*/
function int64_max_int() {
return MAX_INT();
}
/**
* @register {int64 -> bool} is_NaN
*/
function int64_is_NaN(i) {
return is_nan(i);
}
/**
* @register {int -> int64} of_int
*/
function int64_of_int(i) {
if (i >= 0 && i <= IMAX32) { return {h:0, l:i}; };
if (i < 0 || i < IMIN53 || i > IMAX53) { return NAN(); };
var h = Math.floor(i / POW2_32);
var l = i % POW2_32;
return {h:h, l:l};
}
/**
* @register {int64 -> int} to_int
*/
function int64_to_int(i64) {
if (is_nan(i64)) return NAN();
if (i64.h > 0x1fffff) throw "Int64.to_int: int64 too big for int";
return (i64.h * 0x100000000) + i64.l;
}
/**
* @register {int64 -> int64} succ
*/
function int64_succ(i) {
if (i.l === 0xffffffff)
if (i.h === 0xffffffff)
throw "Int64.succ: overflow";
else
return {h:i.h+1, l:0};
else
return {h:i.h, l:i.l+1};
}
/**
* @register {int64 -> int64} pred
*/
function int64_pred(i) {
if (i.l === 0)
if (i.h === 0)
throw "Int64.pred: underflow";
else
return {h:i.h-1, l:0xffffffff};
else
return {h:i.h, l:i.l-1};
}
/**
* @register {int64, int64 -> int64} add
*/
function int64_add(i1,i2) {
return adde(i1, i2, "Int64.add: overflow");
}
function adde(i1, i2, err)
{
if (is_nan(i1) || is_nan(i2)) return NAN();
if (is_zero(i1)) return i2;
if (is_zero(i2)) return i1;
var ll = i1.l + i2.l;
var c = 0;
if (ll > 0xffffffff) { c = 1; ll -= 0x100000000; };
var hh = i1.h + i2.h + c;
if (hh > 0xffffffff) throw err;
return {h:hh, l:ll};
}
/**
* @register {int64, int64 -> int64} sub
*/
function int64_sub(i1,i2) {
if (is_nan(i1) || is_nan(i2)) return NAN();
if (is_zero(i2)) return i1;
var ll = i1.l - i2.l;
var b = 0;
if (ll < 0) { b = 1; ll += 0x100000000; };
var hh = i1.h - i2.h - b;
if (hh < 0) throw "Int64.sub: underflow";
return {h:hh, l:ll};
}
function mul16n(i32hh, i32hl, i32lh, i32ll, i16, n, err) {
var tmp = i32ll * i16;
var ll = tmp & 0xffff;
tmp = i32lh * i16 + (tmp >>> 16);
var lh = tmp & 0xffff;
tmp = i32hl * i16 + (tmp >>> 16);
var hl = tmp & 0xffff;
var hh = i32hh * i16 + (tmp >>> 16);
switch (n) {
case 0:
if (hh > 0xffff) throw err;
return {h:hh*0x10000+hl, l:lh*0x10000+ll};
case 16:
if (hh > 0 || hl > 0xffff) throw err;
return {h:hl*0x10000+lh, l:ll*0x10000};
case 32:
if (hh > 0 || hl > 0 || lh > 0xffff) throw err;
return {h:lh*0x10000+ll, l:0};
case 48:
if (hh > 0 || hl > 0 || lh > 0 || ll > 0xffff) throw err;
return {h:ll*0x10000, l:0};
default:
throw "Int64.mul: bad shift";
}
}
function mule(i1, i2, err) {
if (is_nan(i1) || is_nan(i2)) return NAN();
if (is_zero(i1) || is_zero(i2)) return ZERO();
if (is_one(i1)) return i2;
if (is_one(i2)) return i1;
var i1hh = i1.h >>> 16, i1hl = i1.h & 0xffff, i1lh = i1.l >>> 16, i1ll = i1.l & 0xffff;
var i2hh = i2.h >>> 16, i2hl = i2.h & 0xffff, i2lh = i2.l >>> 16, i2ll = i2.l & 0xffff;
var a = mul16n(i1hh, i1hl, i1lh, i1ll, i2ll, 0, err);
var b = mul16n(i1hh, i1hl, i1lh, i1ll, i2lh, 16, err);
var c = mul16n(i1hh, i1hl, i1lh, i1ll, i2hl, 32, err);
var d = mul16n(i1hh, i1hl, i1lh, i1ll, i2hh, 48, err);
function add(x,y) { return adde(x,y,err); }
return add(add(a,b), add(c,d));
}
/**
* @register {int64, int64 -> int64} mul
*/
function int64_mul(i1,i2) {
return mule(i1,i2,"Int64.mul: overflow");
}
var btab = [0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000];
function setb(x, msk) {
if (msk === 0x80000000) {
if (x & 0x80000000) return x;
return x + 0x80000000; // <-- this seems to be the only way of preventing JS from sign-extending bit 31
};
if (x & 0x80000000) {
return ((x & 0x7fffffff) | msk) + 0x80000000; // <-- !!!!! you've got to be kidding
};
return x | msk;
}
function shftleft(x) {
if (x & 0x40000000) return ((x & 0xbfffffff) << 1) + 0x80000000; // <-- and again
return x << 1;
}
function setbit(v, bn) {
if (bn > 63) return v;
if (bn > 31)
return {h:setb(v.h,btab[bn-32]), l:v.l};
else
return {h:v.h, l:setb(v.l,btab[bn])};
}
function shft128(x) {
var y = [0,0,0,0];
y[0] = shftleft(x[0]);
if (x[1] & 0x80000000) y[0] = setb(y[0],1);
y[1] = shftleft(x[1]);
if (x[2] & 0x80000000) y[1] = setb(y[1],1);
y[2] = shftleft(x[2]);
if (x[3] & 0x80000000) y[2] = setb(y[2],1);
y[3] = shftleft(x[3]);
return y;
}
function sub128(i1, i2)
{
var l3 = i1[3] - i2[3];
var b = 0;
if (l3 < 0) { b = 1; l3 += 0x100000000; };
var l2 = i1[2] - i2[2] - b;
b = 0;
if (l2 < 0) { b = 1; l2 += 0x100000000; };
var l1 = i1[1] - i2[1] - b;
b = 0;
if (l1 < 0) { b = 1; l1 += 0x100000000; };
var l0 = i1[0] - i2[0] - b;
if (l0 < 0) throw "Int64.sub128: underflow";
return [l0,l1,l2,l3];
}
// Naive, slow but accurate.
// Try using 53-bit division and get it to divide 64-bits without sign-extending or truncating the results.
function qr64(N, D) {
if (is_nan(N) || is_nan(D)) return {q:NAN(), r:NAN()};
if (is_zero(D)) return {q:INFINITY(), r:NAN()};
if (is_one(D)) return {q:N, r:ZERO()};
if (BslNumber_BslInt64_op_gt(D,N)) return {q:ZERO(), r:N};
var P = [0,0,N.h,N.l];
var D = [D.h,D.l,0,0];
var Q = ZERO();
for (var i = 63; i >= 0; i--) {
P = shft128(P);
if ((P[0] === D[0]) ? ((P[1] === D[1]) ? ((P[2] === D[2]) ? P[3] >= D[3] : P[2] >= D[2]) : P[1] >= D[1]) : P[0] >= D[0]) {
Q = setbit(Q, i);
P = sub128(P, D);
};
}
return {q:Q, r:{h:P[0], l:P[1]}};
}
/**
* @register {int64, int64 -> int64} div
*/
function int64_div(N, D) {
return qr64(N, D).q;
}
/**
* @register {int64, int64 -> int64} rem
*/
function int64_rem(N, D) {
return qr64(N, D).r;
}
/**
* @register {int64, int64 -> bool} op_eq
*/
function int64_op_eq(i1,i2) {
return (i1.h === i2.h) && (i1.l === i2.l);
}
/**
* @register {int64, int64 -> bool} op_ne
*/
function int64_op_ne(i1,i2) {
return (i1.h !== i2.h) || (i1.l !== i2.l);
}
/**
* @register {int64, int64 -> bool}
*/
function op_gt(i1,i2) {
return (i1.h === i2.h) ? i1.l > i2.l : i1.h > i2.h;
}
/**
* @register {int64, int64 -> bool}
*/
function op_ge(i1,i2) {
return (i1.h === i2.h) ? i1.l >= i2.l : i1.h >= i2.h;
}
/**
* @register {int64, int64 -> bool}
*/
function op_lt(i1,i2) {
return (i1.h === i2.h) ? i1.l < i2.l : i1.h < i2.h;
}
/**
* @register {int64, int64 -> bool}
*/
function op_le(i1,i2) {
return (i1.h === i2.h) ? i1.l <= i2.l : i1.h <= i2.h;
}
/**
* @register {int64, int -> string}
*/
function to_string_radix(i, radix) {
if (radix < 2 || radix > 16) throw ("Int64.to_string: bad radix "+radix);
if (is_nan(i)) return "NaN";
if (is_zero(i)) return "0";
if (is_one(i)) return "1";
if (!is_finite(i)) return "Infinity";
var strs = "0123456789abcdef";
var s = [], R={h:0, l:radix};
while (!is_zero(i)) {
qr = qr64(i, R);
if (qr.r.l >= radix) throw "Int64.to_string: bad number";
s.push(strs[qr.r.l]);
i = qr.q;
}
return s.reverse().join("");
}
/**
* @register {int64 -> string} to_string
*/
function int64_to_string(i) {
return BslNumber_BslInt64_to_string_radix(i, 10);
}
/**
* @register {string, int -> int64}
*/
function of_string_radix(s, radix) {
var tab = { '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15,
'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15 };
if (radix < 2 || radix > 16) throw ("Int64.of_string: bad radix "+radix);
var x = ZERO();
var err = "Int64.of_string: number too large for int64";
for (var i = 0; i < s.length; i++) {
var dig = tab[s[i]];
if (typeof dig == 'undefined' || dig >= radix)
throw ("Int64.of_string: bad digit "+dig);
x = adde(mule(x, {h:0, l:radix}, err), {h:0, l:dig}, err);
}
return x;
}
/**
* @register {string -> int64} of_string
*/
function int64_of_string(s) {
return BslNumber_BslInt64_of_string_radix(s, 10);
}
function land(i1,i2) {
if ((i1 & 0x80000000) && (i2 & 0x80000000)) {
return ((i1 & 0x7fffffff) & (i2 & 0x7fffffff)) + 0x80000000;
}
return i1 & i2;
}
/**
* @register {int64, int64 -> int64}
*/
function logand(i1,i2) {
return {h:land(i1.h,i2.h), l:land(i1.l,i2.l)};
}
function lor(i1,i2) {
if ((i1 & 0x80000000) || (i2 & 0x80000000)) {
return ((i1 & 0x7fffffff) | (i2 & 0x7fffffff)) + 0x80000000;
}
return i1 | i2;
}
/**
* @register {int64, int64 -> int64}
*/
function logor(i1,i2) {
return {h:lor(i1.h,i2.h), l:lor(i1.l,i2.l)};
}
function lxor(i1,i2) {
if (((i1 & 0x80000000) && !(i2 & 0x80000000)) || (!(i1 & 0x80000000) && (i2 & 0x80000000))) {
return ((i1 & 0x7fffffff) ^ (i2 & 0x7fffffff)) + 0x80000000;
}
return i1 ^ i2;
}
/**
* @register {int64, int64 -> int64}
*/
function logxor(i1,i2) {
return {h:lxor(i1.h,i2.h), l:lxor(i1.l,i2.l)};
}
function lnot(i) {
if (!(i & 0x80000000)) {
return (~(i | 0x80000000)) + 0x80000000;
}
return ~i;
}
/**
* @register {int64 -> int64}
*/
function lognot(i) {
return {h:lnot(i.h), l:lnot(i.l)};
}
function lsl(i,n) {
if (n <= 0) return {h:0, l:i};
if (n > 63) return ZERO();
if (n === 32) return {h:i, l:0};
if (n > 32) {
n = n - 32;
if (i & btab[31-n]) {
return {h:((i & lnot(btab[31-n])) << n) + 0x80000000, l:0};
}
return {h:i<<n, l:0};
}
if (i & btab[31-n]) {
return {h:i>>>(32-n), l:((i & lnot(btab[31-n])) << n) + 0x80000000};
}
return {h:i>>>(32-n), l:i<<n};
}
/**
* @register {int64, int -> int64}
*/
function shift_left(i,n) {
if (n <= 0) return i;
if (n > 63) return ZERO();
if (n === 32) return {h:i.l, l:0};
var s1 = lsl(i.h,n);
var s2 = lsl(i.l,n);
return {h:lor(s1.l,s2.h), l:s2.l};
}
function asr_(i, n) {
if (n === 0) return i;
if (n >= 32) return (i & 0x80000000) ? 0xffffffff : 0;
var msks = [0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff];
if (i & 0x80000000)
return (i >>> n) + msks[n-1];
else
return i >>> n;
}
function asr(i,n) {
if (!(i & 0x80000000)) return lsr(i, n);
if (n <= 0) return {h:i, l:0};
if (n > 63) return (i & 0x80000000) ? MAX_INT() : ZERO();
if (n === 32) return {h:(i & 0x80000000) ? 0xffffffff : 0, l:i};
if (n > 32) return {h:(i & 0x80000000) ? 0xffffffff : 0, l:asr_(i,n-32)};
if (i & btab[n-1]) {
return {h:asr_(i,n), l:((i & lnot(btab[n-1])) << (32-n)) + 0x80000000};
}
return {h:asr_(i,n), l:i<<(32-n)};
}
/**
* @register {int64, int -> int64}
*/
function shift_right(i,n) {
if (!(i.h & 0x80000000)) return shift_right_logical_(i,n);
if (n <= 0) return i;
if (n > 63) return MAX_INT();
if (n === 32) return {h:0xffffffff, l:i.h};
var s1 = asr(i.h,n);
var s2 = asr(i.l,n);
return {h:s1.h, l:lor(s1.l,s2.h)};
}
function lsr(i,n) {
if (n <= 0) return {h:i, l:0};
if (n > 63) return ZERO();
if (n === 32) return {h:0, l:i};
if (n > 32) return {h:0, l:i>>>(n-32)};
if (i & btab[n-1]) {
return {h:i>>>n, l:((i & lnot(btab[n-1])) << (32-n)) + 0x80000000};
}
return {h:i>>>n, l:i<<(32-n)};
}
/**
* @register {int64, int -> int64}
*/
function shift_right_logical(i,n) {
return shift_right_logical_(i,n);
}
function shift_right_logical_(i,n)
{
if (n <= 0) return i;
if (n > 63) return ZERO();
if (n === 32) return {h:0, l:i.h};
var s1 = lsr(i.h,n);
var s2 = lsr(i.l,n);
return {h:s1.h, l:lor(s1.l,s2.h)};
}
/** @endModule */
/** @module Float */
/**
* @register {int -> float} of_int
* @pure
*/
function float_of_int(a) {
return a;
}
/**
* @register {string -> float} of_string
* @pure
*/
function float_of_string(v) {
return parseFloat(v)
}
/**
* @register {string -> opa[option(float)]} of_string_opt
* @pure
*/
function float_of_string_opt(str) {
try {
js_some(BslNumber_Float_of_string(str));
} catch(e) {
return js_none;
}
}
// transforms the string so that it is compatible with the mlbsl
// (see the comment there)
/**
* @register {float -> string} to_string
* @pure
*/
function float_to_string(v) {
var str = ""+v;
if (str.indexOf('.') >= 0 || str.indexOf('e') >= 0 || str[0] == 'N' || str[0] == 'I' || str[1] == 'I') {
return str; //Printing corresponds to server-side printing
} else {
return str + ".0";//Printing needs to be adjusted
}
}
// should also be compatible with mlbsl
/**
* @register {bool, opa[option(int)], float -> string}
* @pure
*/
function to_formatted_string(always_dot,decimals_option,f) {
var str = ""+f;
if ('none' in decimals_option) {
if (!always_dot || (str.indexOf('.') >= 0) || str.indexOf('e') >= 0 || str[0] == 'N' || str[0] == 'I' || str[1] == 'I') {
// either js stringification already doesn't print the dot when not necessary
// or if there is already one, nothing to do
// or we have a '1e-88' kind of float and we don't add any point
// or we have NaN or Infinity or -Infinity, and we can't add a decimal point
return str;
} else {
// we want a dot, and didn't find one in str, so we add it ourselves
return str + ".0";
}
} else {
if (always_dot || str.indexOf('.') >= 0) {
// either, we want a dot, we will have it when calling toFixed
// or we have a real float (there is a dot), keep the dot, but truncate the string
return f.toFixed(decimals_option.some);
} else {
// int or special cases, or scientific notation
return str;
}
}
}
/**
* @register {float -> int} round Math.round
* @pure
*/
/**
* @register {float -> float} ceil Math.ceil
* @pure
*/
/**
* @register {float -> float} floor Math.floor
* @pure
*/
/**
* @register {float, float -> bool} leq
* @pure
*/
function float_leq(c1,c2) {
return c1 <= c2
}
/**
* @register {float, float -> bool} lt
* @pure
*/
function float_lt(c1,c2) {
return c1 < c2
}
/**
* @register {float, float -> bool} eq
* @pure
*/
function float_eq(c1,c2) {
return c1 == c2
}
/**
* @register {float, float -> bool} geq
* @pure
*/
function float_geq(c1,c2) {
return c1 >= c2
}
/**
* @register {float, float -> bool} gt
* @pure
*/
function float_gt(c1,c2) {
return c1 > c2
}
/**
* @register {float, float -> bool} neq
* @pure
*/
function float_neq(c1,c2) {
return c1 != c2
}
/**
* @register {float,float -> opa[Order.comparison]} comparison
* @pure
*/
function float_comparison(c1,c2) {
if(isNaN(c1) || isNaN(c2)) return result_neq
if(c1<c2) return result_lt
if(c1==c2) return result_eq
return result_gt
}
function code(i) {
// Ridiculous, there has to be a better way than this to prevent Javascript from casting ints to strings.
var tab =
["\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07","\x08","\x09","\x0a","\x0b","\x0c","\x0d","\x0e","\x0f",
"\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17","\x18","\x19","\x1a","\x1b","\x1c","\x1d","\x1e","\x1f",
"\x20","\x21","\x22","\x23","\x24","\x25","\x26","\x27","\x28","\x29","\x2a","\x2b","\x2c","\x2d","\x2e","\x2f",
"\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\x3a","\x3b","\x3c","\x3d","\x3e","\x3f",
"\x40","\x41","\x42","\x43","\x44","\x45","\x46","\x47","\x48","\x49","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f",
"\x50","\x51","\x52","\x53","\x54","\x55","\x56","\x57","\x58","\x59","\x5a","\x5b","\x5c","\x5d","\x5e","\x5f",
"\x60","\x61","\x62","\x63","\x64","\x65","\x66","\x67","\x68","\x69","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f",
"\x70","\x71","\x72","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a","\x7b","\x7c","\x7d","\x7e","\x7f",
"\x80","\x81","\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x8a","\x8b","\x8c","\x8d","\x8e","\x8f",
"\x90","\x91","\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\x9a","\x9b","\x9c","\x9d","\x9e","\x9f",
"\xa0","\xa1","\xa2","\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xaa","\xab","\xac","\xad","\xae","\xaf",
"\xb0","\xb1","\xb2","\xb3","\xb4","\xb5","\xb6","\xb7","\xb8","\xb9","\xba","\xbb","\xbc","\xbd","\xbe","\xbf",
"\xc0","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6","\xc7","\xc8","\xc9","\xca","\xcb","\xcc","\xcd","\xce","\xcf",
"\xd0","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6","\xd7","\xd8","\xd9","\xda","\xdb","\xdc","\xdd","\xde","\xdf",
"\xe0","\xe1","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7","\xe8","\xe9","\xea","\xeb","\xec","\xed","\xee","\xef",
"\xf0","\xf1","\xf2","\xf3","\xf4","\xf5","\xf6","\xf7","\xf8","\xf9","\xfa","\xfb","\xfc","\xfd","\xfe","\xff"
];
return tab[i];
}
function uncode(s) {
// Even more ridiculous
var tab = {
'\x00':0x00, '\x01':0x01, '\x02':0x02, '\x03':0x03, '\x04':0x04, '\x05':0x05, '\x06':0x06, '\x07':0x07,
'\x08':0x08, '\x09':0x09, '\x0a':0x0a, '\x0b':0x0b, '\x0c':0x0c, '\x0d':0x0d, '\x0e':0x0e, '\x0f':0x0f,
'\x10':0x10, '\x11':0x11, '\x12':0x12, '\x13':0x13, '\x14':0x14, '\x15':0x15, '\x16':0x16, '\x17':0x17,
'\x18':0x18, '\x19':0x19, '\x1a':0x1a, '\x1b':0x1b, '\x1c':0x1c, '\x1d':0x1d, '\x1e':0x1e, '\x1f':0x1f,
'\x20':0x20, '\x21':0x21, '\x22':0x22, '\x23':0x23, '\x24':0x24, '\x25':0x25, '\x26':0x26, '\x27':0x27,
'\x28':0x28, '\x29':0x29, '\x2a':0x2a, '\x2b':0x2b, '\x2c':0x2c, '\x2d':0x2d, '\x2e':0x2e, '\x2f':0x2f,
'\x30':0x30, '\x31':0x31, '\x32':0x32, '\x33':0x33, '\x34':0x34, '\x35':0x35, '\x36':0x36, '\x37':0x37,
'\x38':0x38, '\x39':0x39, '\x3a':0x3a, '\x3b':0x3b, '\x3c':0x3c, '\x3d':0x3d, '\x3e':0x3e, '\x3f':0x3f,
'\x40':0x40, '\x41':0x41, '\x42':0x42, '\x43':0x43, '\x44':0x44, '\x45':0x45, '\x46':0x46, '\x47':0x47,
'\x48':0x48, '\x49':0x49, '\x4a':0x4a, '\x4b':0x4b, '\x4c':0x4c, '\x4d':0x4d, '\x4e':0x4e, '\x4f':0x4f,
'\x50':0x50, '\x51':0x51, '\x52':0x52, '\x53':0x53, '\x54':0x54, '\x55':0x55, '\x56':0x56, '\x57':0x57,
'\x58':0x58, '\x59':0x59, '\x5a':0x5a, '\x5b':0x5b, '\x5c':0x5c, '\x5d':0x5d, '\x5e':0x5e, '\x5f':0x5f,
'\x60':0x60, '\x61':0x61, '\x62':0x62, '\x63':0x63, '\x64':0x64, '\x65':0x65, '\x66':0x66, '\x67':0x67,
'\x68':0x68, '\x69':0x69, '\x6a':0x6a, '\x6b':0x6b, '\x6c':0x6c, '\x6d':0x6d, '\x6e':0x6e, '\x6f':0x6f,
'\x70':0x70, '\x71':0x71, '\x72':0x72, '\x73':0x73, '\x74':0x74, '\x75':0x75, '\x76':0x76, '\x77':0x77,
'\x78':0x78, '\x79':0x79, '\x7a':0x7a, '\x7b':0x7b, '\x7c':0x7c, '\x7d':0x7d, '\x7e':0x7e, '\x7f':0x7f,
'\x80':0x80, '\x81':0x81, '\x82':0x82, '\x83':0x83, '\x84':0x84, '\x85':0x85, '\x86':0x86, '\x87':0x87,
'\x88':0x88, '\x89':0x89, '\x8a':0x8a, '\x8b':0x8b, '\x8c':0x8c, '\x8d':0x8d, '\x8e':0x8e, '\x8f':0x8f,
'\x90':0x90, '\x91':0x91, '\x92':0x92, '\x93':0x93, '\x94':0x94, '\x95':0x95, '\x96':0x96, '\x97':0x97,
'\x98':0x98, '\x99':0x99, '\x9a':0x9a, '\x9b':0x9b, '\x9c':0x9c, '\x9d':0x9d, '\x9e':0x9e, '\x9f':0x9f,
'\xa0':0xa0, '\xa1':0xa1, '\xa2':0xa2, '\xa3':0xa3, '\xa4':0xa4, '\xa5':0xa5, '\xa6':0xa6, '\xa7':0xa7,
'\xa8':0xa8, '\xa9':0xa9, '\xaa':0xaa, '\xab':0xab, '\xac':0xac, '\xad':0xad, '\xae':0xae, '\xaf':0xaf,
'\xb0':0xb0, '\xb1':0xb1, '\xb2':0xb2, '\xb3':0xb3, '\xb4':0xb4, '\xb5':0xb5, '\xb6':0xb6, '\xb7':0xb7,
'\xb8':0xb8, '\xb9':0xb9, '\xba':0xba, '\xbb':0xbb, '\xbc':0xbc, '\xbd':0xbd, '\xbe':0xbe, '\xbf':0xbf,
'\xc0':0xc0, '\xc1':0xc1, '\xc2':0xc2, '\xc3':0xc3, '\xc4':0xc4, '\xc5':0xc5, '\xc6':0xc6, '\xc7':0xc7,
'\xc8':0xc8, '\xc9':0xc9, '\xca':0xca, '\xcb':0xcb, '\xcc':0xcc, '\xcd':0xcd, '\xce':0xce, '\xcf':0xcf,
'\xd0':0xd0, '\xd1':0xd1, '\xd2':0xd2, '\xd3':0xd3, '\xd4':0xd4, '\xd5':0xd5, '\xd6':0xd6, '\xd7':0xd7,
'\xd8':0xd8, '\xd9':0xd9, '\xda':0xda, '\xdb':0xdb, '\xdc':0xdc, '\xdd':0xdd, '\xde':0xde, '\xdf':0xdf,
'\xe0':0xe0, '\xe1':0xe1, '\xe2':0xe2, '\xe3':0xe3, '\xe4':0xe4, '\xe5':0xe5, '\xe6':0xe6, '\xe7':0xe7,
'\xe8':0xe8, '\xe9':0xe9, '\xea':0xea, '\xeb':0xeb, '\xec':0xec, '\xed':0xed, '\xee':0xee, '\xef':0xef,
'\xf0':0xf0, '\xf1':0xf1, '\xf2':0xf2, '\xf3':0xf3, '\xf4':0xf4, '\xf5':0xf5, '\xf6':0xf6, '\xf7':0xf7,
'\xf8':0xf8, '\xf9':0xf9, '\xfa':0xfa, '\xfb':0xfb, '\xfc':0xfc, '\xfd':0xfd, '\xfe':0xfe, '\xff':0xff
};
return tab[s];
}
function a2s(a) {
var s = "";
for (var i = 0; i < a.length; i++) { s += code(a[i]) };
return s;
}
function s2a(s,start,length) {
start = (typeof start == 'undefined') ? 0 : start;
var end =
(typeof length == 'undefined') ? s.length :
(start + length > s.length) ? s.length : start + length;
var a = new Array(end - start - 1);
for (var i = start, j = 0; i < end; i++, j++) { a[j] = uncode(s[i]) };
return a;
}
function clen(c) {
if (c >= 0 && c <= 0xff) return 1;
if (c >= 0 && c <= 0xffff) return 2;
if (c >= 0 && c <= 0xffffffff) return 4;
return 8;
}
function slen(s,start,length) {
var size = 0, i;
start = (typeof start == 'undefined') ? 0 : start;
var end =
(typeof length == 'undefined') ? s.length :
(start + length > s.length) ? s.length : start + length;
for (i = start; i < end; size += clen(s.charCodeAt(i++)));
return size;
}
// This routine flattens out unicode characters, "\uabcd" -> <Buffer ab cd>
function s2bj(s,start,length,b,j) {
start = (typeof start == 'undefined') ? 0 : start;
var end =
(typeof length == 'undefined') ? s.length :
(start + length > s.length) ? s.length : start + length;
var i;
for (i = start; i < end; i++) {
var c = s.charCodeAt(i);
if (c >= 0 && c <= 0xff) {
b[j++] = c;
} else if (c >= 0 && c <= 0xffff) {
b[j++] = (c >> 8) & 0xff;
b[j++] = c & 0xff;
} else if (c >= 0 && c <= 0xffffffff) {
b[j++] = (c >> 24) & 0xff;
b[j++] = (c >> 16) & 0xff;
b[j++] = (c >> 8) & 0xff;
b[j++] = c & 0xff;
} else {
throw "BslNumber.s2b: bad char code";
};
};
return b;
}
function s2b(s,start,length) {
var b = new Buffer(slen(s,start,length)), j = 0;
return s2bj(s,start,length,b,j);
}
function dump(s)
{
var b = s2b(s)
var i = 0, d = "";
while (i < b.length) {
var h = "", a = "", pos = i.toString(16);
while (pos.length < 4) { pos = "0" + pos; };
for (var j = 0; i < b.length && j < 16; i++,j++) {
var ch = b[i];
var ac = (ch >= 0x20 && ch < 0x7f) ? code(b[i]) : ".";
var hx = ch.toString(16);
if (hx.length == 1) hx = "0" + hx;
var sp = (i == b.length - 1) ? "" : " ";
h += hx + sp;
a += ac;
};
while (h.length < 3*16) { h += " "; };
d += pos + " " + h + " " + a + "\n";
};
return d;
}
/* Same but for 64-bit floating point numbers. */
/**
* @register {float -> string}
*/
function embed_float_le(f) {
var b = new Buffer(8);
b.writeDoubleLE(f, 0);
return a2s(b);
}
/**
* @register {float -> string}
*/
function embed_float_be(f) {
var b = new Buffer(8);
b.writeDoubleBE(f, 0);
return a2s(b);
}
/**
* @register {string, int -> float}
*/
function unembed_float_le(s, offset) {
return (s2b(s,offset,8)).readDoubleLE(0);
}
/**
* @register {string, int -> float}
*/
function unembed_float_be(s, offset) {
return (s2b(s,offset,8)).readDoubleBE(0);
}
/** @endModule */
/** @module Math */
/**
* @register {int -> int}
* @pure
*/
function sqrt_i(n) {
return Math.floor(Math.sqrt(n));
}
/**
* @register {float -> float} log Math.log
* @pure
*/
/**
* @register {float -> float} sqrt_f Math.sqrt
* @pure
*/
/**
* @register {float -> float} exp Math.exp
* @pure
*/
/**
* @register {int -> int} abs_i Math.abs
* @pure
*/
/**
* @register {float -> float} abs_f Math.abs
* @pure
*/
/**
* @register {float -> float} ceil Math.ceil
* @pure
*/
/**
* @register {float -> float} floor Math.floor
* @pure
*/
/**
* @register {float -> float} sin Math.sin
* @pure
*/
/**
* @register {float -> float} cos Math.cos
* @pure
*/
/**
* @register {float -> float} tan Math.tan
* @pure
*/
/**
* @register {float -> float} asin Math.asin
* @pure
*/
/**
* @register {float -> float} acos Math.acos
* @pure
*/
/**
* @register {float -> float} atan Math.atan
* @pure
*/
/**
* @register {float -> bool} isNaN isNaN
* @pure
*/
/**
* @register {float -> bool}
* @pure
*/
function is_infinite(n) {
return !(isFinite(n) || isNaN(n));
}
/**
* @register {float -> bool} is_normal isFinite
* @pure
*/
/** @endModule */
/** @module Random */
/**
* @register {int -> int}
*/
function int(n) {
return Math.floor(Math.random() * n)
}
/**
* @register {float -> float}
*/
function float(n) {
return Math.random() * n
}
/**
* @register {-> void}
*/
function random_init() {
return ;
}
function makeStringFromChars(chars, len) {
var s = "";
for (var i = 0; i < len; ++i)
s += chars.charAt(Math.floor(Math.random() * chars.length));
return s;
}
/**
* @register {string, int -> string}
*/
function generic_string(chars, len) {
return (makeStringFromChars(chars, len));
}
/**
* @register {int -> string}
*/
function string(len) {
var chars = "abcdefghijklmnopqrstuvwxyz";
return makeStringFromChars(chars, len);
}
/**
* @register {int -> string} base64
*/
function bslnumber_base64(len) {
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
return makeStringFromChars(chars, len)
}
/**
* @register {int -> string}
*/
function base64_url(len) {
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
return makeStringFromChars(chars, len)
}
/** @endModule */
Jump to Line
Something went wrong with that request. Please try again.