summaryrefslogtreecommitdiff
path: root/rts/js/string.js
diff options
context:
space:
mode:
Diffstat (limited to 'rts/js/string.js')
-rw-r--r--rts/js/string.js791
1 files changed, 791 insertions, 0 deletions
diff --git a/rts/js/string.js b/rts/js/string.js
new file mode 100644
index 0000000000..da5e0c610e
--- /dev/null
+++ b/rts/js/string.js
@@ -0,0 +1,791 @@
+//#OPTIONS: CPP
+
+// encode a string constant
+function h$str(s) {
+ var enc = null;
+ return function() {
+ if(enc === null) {
+ enc = h$encodeModifiedUtf8(s);
+ }
+ return enc;
+ }
+}
+
+// encode a packed string
+// since \0 is used to separate strings (and a common occurrence)
+// we add the following mapping:
+// - \0 -> \cz\0
+// - \cz -> \cz\cz
+//
+// decoding to bytes, the following is produced:
+// - \cz\0 -> C0 80
+// - \cz\cz -> 1A
+//
+// additionally, for dealing with raw binary data we have an escape sequence
+// to pack base64 encoded runs:
+//
+// - \cz\xNN -> followed by NN-0x1f (31 decimal) bytes of base64 encoded
+// data. supported range: 0x20 .. 0x9f (1-128 bytes data)
+//
+
+function h$pstr(s) {
+ var enc = null;
+ return function() {
+ if(enc === null) {
+ enc = h$encodePackedUtf8(s);
+ }
+ return enc;
+ }
+}
+// encode a raw string from bytes
+function h$rstr(d) {
+ var enc = null;
+ return function() {
+ if(enc === null) {
+ enc = h$rawStringData(d);
+ }
+ return enc;
+ }
+}
+
+// these aren't added to the CAFs, so the list stays in mem indefinitely, is that a problem?
+#ifdef GHCJS_PROF
+function h$strt(str, cc) { return MK_LAZY_CC(function() { return h$toHsString(str, cc); }, cc); }
+function h$strta(str, cc) { return MK_LAZY_CC(function() { return h$toHsStringA(str, cc); }, cc); }
+function h$strtb(arr, cc) { return MK_LAZY_CC(function() { return h$toHsStringMU8(arr, cc); }, cc); }
+#else
+function h$strt(str) { return MK_LAZY(function() { return h$toHsString(str); }); }
+function h$strta(str) { return MK_LAZY(function() { return h$toHsStringA(str); }); }
+function h$strtb(arr) { return MK_LAZY(function() { return h$toHsStringMU8(arr); }); }
+#endif
+
+// unpack strings without thunks
+#ifdef GHCJS_PROF
+function h$ustra(str, cc) { return h$toHsStringA(str, cc); }
+function h$ustr(str, cc) { return h$toHsString(str, cc); } // utf8 string, string argument
+function h$urstra(arr, cc) { return h$toHsList(arr, cc); } // ascii string, array of codepoints argument
+function h$urstr(arr, cc) { return h$toHsStringMU8(arr, cc); } // utf8 string, array of bytes argumnt
+#else
+function h$ustra(str) { return h$toHsStringA(str); }
+function h$ustr(str) { return h$toHsString(str); }
+function h$urstra(arr) { return h$toHsList(arr); }
+function h$urstr(arr) { return h$toHsStringMU8(arr); }
+#endif
+
+function h$caseMapping(x) {
+ return (x%2)?-((x+1)>>1):(x>>1);
+}
+
+var h$toUpper = null;
+function h$u_towupper(ch) {
+ if(h$toUpper == null) { h$toUpper = h$decodeMapping(h$toUpperMapping, h$caseMapping); }
+ return ch+(h$toUpper[ch]|0);
+}
+
+var h$toLower = null;
+function h$u_towlower(ch) {
+ if(h$toLower == null) { h$toLower = h$decodeMapping(h$toLowerMapping, h$caseMapping); }
+ return ch+(h$toLower[ch]|0);
+}
+
+var h$toTitle = null;
+function h$u_towtitle(ch) {
+ if(h$toTitle == null) { h$toTitle = h$decodeMapping(h$toTitleMapping, h$caseMapping); }
+ return ch+(h$toTitle[ch]|0);
+}
+
+var h$alpha = null;
+function h$u_iswalpha(a) {
+ if(h$alpha == null) { h$alpha = h$decodeRLE(h$alphaRanges); }
+ return h$alpha[a]|0;
+}
+
+var h$alnum = null;
+function h$u_iswalnum(a) {
+ if(h$alnum == null) { h$alnum = h$decodeRLE(h$alnumRanges); }
+ return h$alnum[a] == 1 ? 1 : 0;
+}
+
+// var h$spaceChars = [9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288];
+function h$isSpace(a) {
+ if(a<5760) return a===32||(a>=9&&a<=13)||a===160;
+ return (a>=8192&&a<=8202)||a===5760||a===8239||a===8287||a===12288;
+}
+
+function h$u_iswspace(a) {
+ return h$isSpace(a)?1:0;
+}
+
+var h$lower = null;
+function h$u_iswlower(a) {
+ if(h$lower == null) { h$lower = h$decodeRLE(h$lowerRanges); }
+ if(a < 0x30000) return h$lower[a]|0;
+ if(a < 0xE0000) return 0;
+ return h$lower[a-0xB0000]|0;
+}
+
+var h$upper = null;
+function h$u_iswupper(a) {
+ if(h$upper == null) { h$upper = h$decodeRLE(h$upperRanges); }
+ if(a < 0x30000) return h$upper[a]|0;
+ if(a < 0xE0000) return 0;
+ return h$upper[a-0xB0000]|0;
+}
+
+
+var h$cntrlChars = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159];
+var h$cntrl = null;
+function h$u_iswcntrl(a) {
+ if(h$cntrl === null) {
+ h$cntrl = [];
+ for(var i=0;i<=159;i++) h$cntrl[i] = (h$cntrlChars.indexOf(i) !== -1) ? 1 : 0;
+ }
+ return a <= 159 ? h$cntrl[a] : 0;
+}
+
+var h$print = null;
+function h$u_iswprint(a) {
+ if(h$print == null) { h$print = h$decodeRLE(h$printRanges); }
+ if(a < 0x30000) return h$print[a]|0;
+ if(a < 0xE0000) return 0;
+ return h$print[a-0xB0000]|0;
+}
+
+// decode a packed string (Compactor encoding method) to an array of numbers
+function h$decodePacked(s) {
+ function f(o) {
+ var c = s.charCodeAt(o);
+ return c<34?c-32:c<92?c-33:c-34;
+ }
+ var r=[], i=0;
+ while(i < s.length) {
+ var c = s.charCodeAt(i);
+ if(c < 124) r.push(f(i++));
+ else if(c === 124) {
+ i += 3; r.push(90+90*f(i-2)+f(i-1));
+ } else if(c === 125) {
+ i += 4;
+ r.push(8190+8100*f(i-3)+90*f(i-2)+f(i-1));
+ } else throw ("h$decodePacked: invalid: " + c);
+ }
+ return r;
+}
+
+// decode string with encoded character ranges
+function h$decodeRLE(str) {
+ var r = [], x = 0, i = 0, j = 0, v, k, a = h$decodePacked(str);
+ while(i < a.length) {
+ v = a[i++];
+ if(v === 0) { // alternating
+ k = a[i++];
+ while(k--) {
+ r[j++] = x;
+ r[j++] = 1-x;
+ }
+ } else {
+ if(v <= 2) {
+ k = (a[i]<<16)+a[i+1];
+ i+=2;
+ } else k = (v-1)>>1;
+ if(v%2) {
+ r[j++] = x;
+ x = 1-x;
+ }
+ while(k--) r[j++] = x;
+ x = 1-x;
+ }
+ }
+ r.shift();
+ return r;
+}
+
+function h$decodeMapping(str, f) {
+ var r = [], i = 0, j = 0, k, v, v2, a = h$decodePacked(str);
+ while(i < a.length) {
+ v = a[i++];
+ if(v === 0) { // alternating
+ k = a[i];
+ v = f(a[i+1]);
+ v2 = f(a[i+2]);
+ while(k--) {
+ r[j++] = v;
+ r[j++] = v2;
+ }
+ i+=3;
+ } else {
+ if(v === 2) {
+ k = (a[i] << 16) + a[i+1];
+ v = a[i+2];
+ i += 3;
+ } else if(v%2) {
+ k = 1;
+ v = v>>1;
+ } else {
+ k = (v>>1)-1;
+ v = a[i++];
+ }
+ v = f(v);
+ while(k--) r[j++] = v;
+ }
+ }
+ return r;
+}
+
+var h$unicodeCat = null;
+function h$u_gencat(a) {
+ if(h$unicodeCat == null) h$unicodeCat = h$decodeMapping(h$catMapping, function(x) { return x; });
+ // private use
+ if(a >= 0xE000 && a <= 0xF8FF || a >= 0xF0000 & a <= 0xFFFFD || a >= 0x100000 && a <= 0x10FFFD) return 28;
+ var c = a < 0x30000 ? (h$unicodeCat[a]|0) :
+ (a < 0xE0000 ? 0 : (h$unicodeCat[a-0xB0000]|0));
+ return c?c-1:29;
+}
+
+function h$localeEncoding() {
+ // h$log("### localeEncoding");
+ RETURN_UBX_TUP2(h$encodeUtf8("UTF-8"), 0); // offset 0
+}
+
+function h$wcwidth(wch) {
+ return 1; // XXX: add real implementation
+}
+
+function h$rawStringData(str) {
+ var v = h$newByteArray(str.length+1);
+ var u8 = v.u8;
+ for(var i=0;i<str.length;i++) {
+ u8[i] = str[i];
+ }
+ u8[str.length] = 0;
+ return v;
+}
+
+// encode a javascript string to a zero terminated utf8 byte array
+function h$encodeUtf8(str) {
+ return h$encodeUtf8Internal(str, false, false);
+}
+
+function h$encodeModifiedUtf8(str) {
+ return h$encodeUtf8Internal(str, true, false);
+}
+
+function h$encodePackedUtf8(str) {
+ return h$encodeUtf8Internal(str, false, true);
+}
+
+// modified: encode \0 -> 192 128
+// packed: encode \cz\cz -> 26
+// \cz\0 -> 192 128
+function h$encodeUtf8Internal(str, modified, packed) {
+ var i, j, c, low, b64bytes, b64chars;
+ function base64val(cc) {
+ if(cc >= 65 && cc <= 90) return cc - 65; // A-Z
+ if(cc >= 97 && cc <= 122) return cc - 71; // a-z
+ if(cc >= 48 && cc <= 57) return cc + 4; // 0-9
+ if(cc === 43) return 62; // +
+ if(cc === 47) return 63; // /
+ if(cc === 61) return 0; // = (treat padding as zero)
+ throw new Error("invalid base64 value: " + cc);
+ }
+ var n = 0;
+ var czescape = false;
+ for(i=0;i<str.length;i++) {
+ // non-BMP encoded as surrogate pair in JavaScript string, get actual codepoint
+ var c = str.charCodeAt(i);
+ if (0xD800 <= c && c <= 0xDBFF) {
+ low = str.charCodeAt(i+1);
+ c = ((c - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
+ i++;
+ }
+ if(czescape) {
+ if(c === 26) { // \cz\cz -> 26
+ n+=1;
+ } else if(c === 0) { // \cz\0 -> 192 128
+ n+=2
+ } else if(c >= 0x20 && c <= 0x9f) {
+ b64bytes = c - 0x1f; // number of bytes in base64 encoded run
+ b64chars = ((b64bytes + 2) / 3) << 2;
+ n += b64bytes;
+ i += b64chars;
+ } else {
+ throw new Error("invalid cz escaped character: " + c);
+ }
+ czescape = false;
+ } else {
+ if(c === 26 && packed) {
+ czescape = true;
+ } else if(c === 0 && modified) {
+ n+=2;
+ } else if(c <= 0x7F) {
+ n++;
+ } else if(c <= 0x7FF) {
+ n+=2;
+ } else if(c <= 0xFFFF) {
+ n+=3;
+ } else if(c <= 0x1FFFFF) {
+ n+=4;
+ } else if(c <= 0x3FFFFFF) {
+ n+=5;
+ } else {
+ n+=6;
+ }
+ }
+ }
+ var v = h$newByteArray(n+1);
+ var u8 = v.u8;
+ n = 0;
+ for(i=0;i<str.length;i++) {
+ c = str.charCodeAt(i);
+ // non-BMP encoded as surrogate pair in JavaScript string, get actual codepoint
+ if (0xD800 <= c && c <= 0xDBFF) {
+ low = str.charCodeAt(i+1);
+ c = ((c - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
+ i++;
+ }
+// h$log("### encoding char " + c + " to UTF-8: " + String.fromCodePoint(c));
+ if(packed && !czescape && c === 26) {
+ czescape = true;
+ } else if(c === 0 && (modified || czescape)) {
+ u8[n] = 192;
+ u8[n+1] = 128;
+ n+=2;
+ czescape = false;
+ } else if(czescape) {
+ if(c >= 0x20 && c <= 0x9f) {
+ b64bytes = c - 0x1f;
+ while(b64bytes > 0) {
+ var c1 = base64val(str.charCodeAt(i+1)),
+ c2 = base64val(str.charCodeAt(i+2)),
+ c3 = base64val(str.charCodeAt(i+3)),
+ c4 = base64val(str.charCodeAt(i+4));
+ i+=4;
+ u8[n] = (c1<<2)|(c2>>4);
+ n++;
+ if(b64bytes >= 2) {
+ u8[n] = ((c2&0xf)<<4)|(c3 >> 2);
+ n++;
+ }
+ if(b64bytes >= 3) {
+ u8[n] = ((c3&0x3)<<6)|c4;
+ n++;
+ }
+ b64bytes -= 3;
+ }
+ } else {
+ u8[n] = c;
+ n++;
+ }
+ czescape = false;
+ } else if(c <= 0x7F) {
+ u8[n] = c;
+ n++;
+ } else if(c <= 0x7FF) {
+ u8[n] = (c >> 6) | 0xC0;
+ u8[n+1] = (c & 0x3F) | 0x80;
+ n+=2;
+ } else if(c <= 0xFFFF) {
+ u8[n] = (c >> 12) | 0xE0;
+ u8[n+1] = ((c >> 6) & 0x3F) | 0x80;
+ u8[n+2] = (c & 0x3F) | 0x80;
+ n+=3;
+ } else if(c <= 0x1FFFFF) {
+ u8[n] = (c >> 18) | 0xF0;
+ u8[n+1] = ((c >> 12) & 0x3F) | 0x80;
+ u8[n+2] = ((c >> 6) & 0x3F) | 0x80;
+ u8[n+3] = (c & 0x3F) | 0x80;
+ n+=4;
+ } else if(c <= 0x3FFFFFF) {
+ u8[n] = (c >> 24) | 0xF8;
+ u8[n+1] = ((c >> 18) & 0x3F) | 0x80;
+ u8[n+2] = ((c >> 12) & 0x3F) | 0x80;
+ u8[n+3] = ((c >> 6) & 0x3F) | 0x80;
+ u8[n+4] = (c & 0x3F) | 0x80;
+ n+=5;
+ } else {
+ u8[n] = (c >>> 30) | 0xFC;
+ u8[n+1] = ((c >> 24) & 0x3F) | 0x80;
+ u8[n+2] = ((c >> 18) & 0x3F) | 0x80;
+ u8[n+3] = ((c >> 12) & 0x3F) | 0x80;
+ u8[n+4] = ((c >> 6) & 0x3F) | 0x80;
+ u8[n+5] = (c & 0x3F) | 0x80;
+ n+=6;
+ }
+ }
+ u8[v.len-1] = 0; // terminator
+// h$log("### encodeUtf8: " + str);
+// h$log(v);
+ return v;
+}
+
+
+// encode a javascript string to a zero terminated utf16 byte array
+function h$encodeUtf16(str) {
+ var n = 0;
+ var i;
+ for(i=0;i<str.length;i++) {
+ var c = str.charCodeAt(i);
+ if(c <= 0xFFFF) {
+ n += 2;
+ } else {
+ n += 4;
+ }
+ }
+ var v = h$newByteArray(n+1);
+ var dv = v.dv;
+ n = 0;
+ for(i=0;i<str.length;i++) {
+ var c = str.charCodeAt(i);
+ if(c <= 0xFFFF) {
+ dv.setUint16(n, c, true);
+ n+=2;
+ } else {
+ var c0 = c - 0x10000;
+ dv.setUint16(n, c0 >> 10, true);
+ dv.setUint16(n+2, c0 & 0x3FF, true);
+ n+=4;
+ }
+ }
+ dv.setUint8(v.len-1,0); // terminator
+ return v;
+}
+
+
+/*
+function h$encodeUtf16(str) {
+ var b = new DataView(new ArrayBuffer(str.length * 2));
+ for(var i=str.length-1;i>=0;i--) {
+ b.setUint16(i<<1, str.charCodeAt(i));
+ }
+ h$ret1 = 0;
+ return b;
+}
+var h$eU16 = h$encodeUtf16;
+
+function h$decodeUtf16(v,start) {
+ return h$decodeUtf16(v, v.byteLength - start, start);
+}
+
+function h$decodeUtf16z(v,start) {
+ var len = v.byteLength - start;
+ for(var i=start;i<l;i+=2) {
+ if(v.getUint16(i) === 0) {
+ len = i;
+ break;
+ }
+ }
+ return h$decodeUtf16l(v,l,start)
+}
+*/
+
+function h$decodeUtf16l(v, byteLen, start) {
+ // perhaps we can apply it with an Uint16Array view, but that might give us endianness problems
+ var a = [];
+ for(var i=0;i<byteLen;i+=2) {
+ a[i>>1] = v.dv.getUint16(i+start,true);
+ }
+ return h$charCodeArrayToString(arr);
+}
+var h$dU16 = h$decodeUtf16;
+
+// decode a buffer with UTF-8 chars to a JS string
+// stop at the first zero
+function h$decodeUtf8z(v,start) {
+ var n = start;
+ var max = v.len;
+ while(n < max) {
+ if(v.u8[n] === 0) { break; }
+ n++;
+ }
+ return h$decodeUtf8(v,n,start);
+}
+
+// decode a buffer with Utf8 chars to a JS string
+// invalid characters are ignored
+function h$decodeUtf8(v,n0,start) {
+// h$log("### decodeUtf8");
+// h$log(v);
+ var n = n0 || v.len;
+ var arr = [];
+ var i = start || 0;
+ var code;
+ var u8 = v.u8;
+// h$log("### decoding, starting at: " + i);
+ while(i < n) {
+ var c = u8[i];
+ while((c & 0xC0) === 0x80) {
+ c = u8[++i];
+ }
+// h$log("### lead char: " + c);
+ if((c & 0x80) === 0) {
+ code = (c & 0x7F);
+ i++;
+ } else if((c & 0xE0) === 0xC0) {
+ code = ( ((c & 0x1F) << 6)
+ | (u8[i+1] & 0x3F)
+ );
+ i+=2;
+ } else if((c & 0xF0) === 0xE0) {
+ code = ( ((c & 0x0F) << 12)
+ | ((u8[i+1] & 0x3F) << 6)
+ | (u8[i+2] & 0x3F)
+ );
+ i+=3;
+ } else if ((c & 0xF8) === 0xF0) {
+ code = ( ((c & 0x07) << 18)
+ | ((u8[i+1] & 0x3F) << 12)
+ | ((u8[i+2] & 0x3F) << 6)
+ | (u8[i+3] & 0x3F)
+ );
+ i+=4;
+ } else if((c & 0xFC) === 0xF8) {
+ code = ( ((c & 0x03) << 24)
+ | ((u8[i+1] & 0x3F) << 18)
+ | ((u8[i+2] & 0x3F) << 12)
+ | ((u8[i+3] & 0x3F) << 6)
+ | (u8[i+4] & 0x3F)
+ );
+ i+=5;
+ } else {
+ code = ( ((c & 0x01) << 30)
+ | ((u8[i+1] & 0x3F) << 24)
+ | ((u8[i+2] & 0x3F) << 18)
+ | ((u8[i+3] & 0x3F) << 12)
+ | ((u8[i+4] & 0x3F) << 6)
+ | (u8[i+5] & 0x3F)
+ );
+ i+=6;
+ }
+ // h$log("### decoded codePoint: " + code + " - " + String.fromCharCode(code)); // String.fromCodePoint(code));
+ // need to deal with surrogate pairs
+ if(code > 0xFFFF) {
+ var offset = code - 0x10000;
+ arr.push(0xD800 + (offset >> 10), 0xDC00 + (offset & 0x3FF));
+ } else {
+ arr.push(code);
+ }
+ }
+ return h$charCodeArrayToString(arr);
+}
+
+// fixme what if terminator, then we read past end
+function h$decodeUtf16(v) {
+ var n = v.len;
+ var arr = [];
+ var dv = v.dv;
+ for(var i=0;i<n;i+=2) {
+ arr.push(dv.getUint16(i,true));
+ }
+ return h$charCodeArrayToString(arr);
+}
+
+function h$charCodeArrayToString(arr) {
+ if(arr.length <= 60000) {
+ return String.fromCharCode.apply(this, arr);
+ }
+ var r = '';
+ for(var i=0;i<arr.length;i+=60000) {
+ r += String.fromCharCode.apply(this, arr.slice(i, i+60000));
+ }
+ return r;
+}
+
+function h$hs_iconv_open(to,to_off,from,from_off) {
+ h$errno = h$EINVAL; // no encodings supported
+ return -1;
+// var fromStr = decodeUtf8(from, from_off);
+// var toStr = decodeUtf8(to, to_off);
+// h$log("#### hs_iconv_open: " + fromStr + " -> " + toStr);
+// return 1; // fixme?
+}
+
+function h$hs_iconv_close(iconv) {
+ return 0;
+}
+
+// ptr* -> ptr (array)
+function h$derefPtrA(ptr, ptr_off) {
+ return ptr.arr[ptr_off][0];
+}
+// ptr* -> ptr (offset)
+function h$derefPtrO(ptr, ptr_off) {
+ return ptr.arr[ptr_off][1];
+}
+
+// word** -> word ptr[x][y]
+function h$readPtrPtrU32(ptr, ptr_off, x, y) {
+ x = x || 0;
+ y = y || 0;
+ var arr = ptr.arr[ptr_off + 4 * x];
+ return arr[0].dv.getInt32(arr[1] + 4 * y, true);
+}
+
+// char** -> char ptr[x][y]
+function h$readPtrPtrU8(ptr, ptr_off, x, y) {
+ x = x || 0;
+ y = y || 0;
+ var arr = ptr.arr[ptr_off + 4 * x];
+ return arr[0].dv.getUint8(arr[1] + y);
+}
+
+// word** ptr[x][y] = v
+function h$writePtrPtrU32(ptr, ptr_off, v, x, y) {
+ x = x || 0;
+ y = y || 0;
+ var arr = ptr.arr[ptr_off + 4 * x];
+ arr[0].dv.putInt32(arr[1] + y, v);
+}
+
+// unsigned char** ptr[x][y] = v
+function h$writePtrPtrU8(ptr, ptr_off, v, x, y) {
+ x = x || 0;
+ y = y || 0;
+ var arr = ptr.arr[ptr_off+ 4 * x];
+ arr[0].dv.putUint8(arr[1] + y, v);
+}
+
+// convert JavaScript String to a Haskell String
+#ifdef GHCJS_PROF
+function h$toHsString(str, cc) {
+#else
+function h$toHsString(str) {
+#endif
+ if(typeof str !== 'string') return HS_NIL;
+ var i = str.length - 1;
+ var r = HS_NIL;
+ while(i>=0) {
+ var cp = str.charCodeAt(i);
+ if(cp >= 0xDC00 && cp <= 0xDFFF && i > 0) {
+ --i;
+ cp = (cp - 0xDC00) + (str.charCodeAt(i) - 0xD800) * 1024 + 0x10000;
+ }
+ r = MK_CONS_CC(cp, r, cc);
+ --i;
+ }
+ return r;
+}
+
+// string must have been completely forced first
+function h$fromHsString(str) {
+ var xs = '';
+ while(IS_CONS(str)) {
+ var h = CONS_HEAD(str);
+ xs += String.fromCharCode(UNWRAP_NUMBER(h));
+ str = CONS_TAIL(str);
+ }
+ return xs;
+}
+
+// list of JSVal to array, list must have been completely forced first
+function h$fromHsListJSVal(xs) {
+ var arr = [];
+ while(IS_CONS(xs)) {
+ arr.push(JSVAL_VAL(CONS_HEAD(xs)));
+ xs = CONS_TAIL(xs);
+ }
+ return arr;
+}
+
+// ascii only version of the above
+#ifdef GHCJS_PROF
+function h$toHsStringA(str, cc) {
+#else
+function h$toHsStringA(str) {
+#endif
+ if(typeof str !== 'string') return HS_NIL;
+ var i = str.length - 1;
+ var r = HS_NIL;
+ while(i>=0) {
+ r = MK_CONS_CC(str.charCodeAt(i), r, cc);
+ --i;
+ }
+ return r;
+}
+
+// convert array with modified UTF-8 encoded text
+#ifdef GHCJS_PROF
+function h$toHsStringMU8(arr, cc) {
+#else
+function h$toHsStringMU8(arr) {
+#endif
+ var i = arr.length - 1, accept = false, b, n = 0, cp = 0, r = HS_NIL;
+ while(i >= 0) {
+ b = arr[i];
+ if(!(b & 128)) {
+ cp = b;
+ accept = true;
+ } else if((b & 192) === 128) {
+ cp += (b & 32) * Math.pow(64, n)
+ } else {
+ cp += (b&((1<<(6-n))-1)) * Math.pow(64, n);
+ accept = true;
+ }
+ if(accept) {
+ r = MK_CONS_CC(cp, r, cc);
+ cp = 0
+ n = 0;
+ } else {
+ n++;
+ }
+ accept = false;
+ i--;
+ }
+ return r;
+}
+
+#ifdef GHCJS_PROF
+function h$toHsList(arr, cc) {
+#else
+function h$toHsList(arr) {
+#endif
+ var r = HS_NIL;
+ for(var i=arr.length-1;i>=0;i--) {
+ r = MK_CONS_CC(arr[i], r, cc);
+ }
+ return r;
+}
+
+// array of JS values to Haskell list of JSVal
+#ifdef GHCJS_PROF
+function h$toHsListJSVal(arr, cc) {
+#else
+function h$toHsListJSVal(arr) {
+#endif
+ var r = HS_NIL;
+ for(var i=arr.length-1;i>=0;i--) {
+ r = MK_CONS_CC(MK_JSVAL(arr[i]), r, cc);
+ }
+ return r;
+}
+
+// unpack ascii string, append to existing Haskell string
+#ifdef GHCJS_PROF
+function h$appendToHsStringA(str, appendTo, cc) {
+#else
+function h$appendToHsStringA(str, appendTo) {
+#endif
+ var i = str.length - 1;
+ var r = appendTo;
+ while(i>=0) {
+ r = MK_CONS_CC(str.charCodeAt(i), r, cc);
+ --i;
+ }
+ return r;
+}
+
+// throw e wrapped in a GHCJS.Prim.JSException in the current thread
+function h$throwJSException(e) {
+ // create a JSException object and wrap it in a SomeException
+ // adding the Exception dictionary
+ var strVal;
+ if(typeof e === 'string') {
+ strVal = e;
+ } else if(e instanceof Error) {
+ strVal = e.toString() + '\n' + Array.prototype.join.call(e.stack, '\n');
+ } else {
+ strVal = "" + e;
+ }
+ var someE = MK_SOMEEXCEPTION(HS_JSEXCEPTION_EXCEPTION,
+ MK_JSEXCEPTION(MK_JSVAL(e), h$toHsString(strVal))
+ );
+ return h$throw(someE, true);
+}