From 79795a6baaefdd4a03e270175b16133671a516b9 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:14:23 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/com/compat.js | 1935 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1935 insertions(+) create mode 100644 js/com/compat.js diff --git a/js/com/compat.js b/js/com/compat.js new file mode 100644 index 0000000..af7f0ac --- /dev/null +++ b/js/com/compat.js @@ -0,0 +1,1935 @@ +/** + ** ============================== + ** O O O OOOO + ** O O O O O O + ** O O O O O O + ** OOOO OOOO O OOO OOOO + ** O O O O O O O + ** O O O O O O O + ** OOOO OOOO O O OOOO + ** ============================== + ** Dr. Stefan Bosse http://www.bsslab.de + ** + ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED + ** BY THE AUTHOR(S). + ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, + ** MODIFIED, OR OTHERWISE USED IN A CONTEXT + ** OUTSIDE OF THE SOFTWARE SYSTEM. + ** + ** $AUTHORS: Stefan Bosse + ** $INITIAL: (C) 2006-2021 bLAB + ** $CREATED: 30-3-15 by sbosse. + ** $VERSION: 1.24.1 + ** + ** $INFO: + ** + ** JavaScript-OCaML Compatibility Module + ** + ** $ENDOFINFO + */ +var Io = Require('com/io'); +var Path = Require('com/path'); +var Sprintf = Require('com/sprintf'); + +/******************************* +** Some global special "values" +********************************/ + +/** A matching template pattern matching any value + * + * @type {undefined} + */ +global.any = undefined; +/** A matching template pattern matching any value + * + * @type {undefined} + */ +global._ = undefined; + +/** + * + * @type {null} + */ +global.none = null; +/** + * + * @type {null} + */ +global.empty = null; + +global.NL = '\n'; + +global.int = function (v) {return v|0}; +global.div = function (a,b) {return a/b|0}; + +if (!Object.prototype.forEach) { + Object.defineProperties(Object.prototype, { + 'forEach': { + value: function (callback) { + if (this == null) { + throw new TypeError('Not an object'); + } + var obj = this; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + callback.call(obj, obj[key], key, obj); + } + } + }, + writable: true + } + }); +} +/** Just transfer parent prototypes to child + * + */ +function inherit(child,parent) { + for(var p in parent.prototype) { + if (p == '__proto__') continue; + child.prototype[p]=parent.prototype[p]; + } +} + +/** Portable class inheritance and instanceOf polyfill + * + */ +// SomeObject.prototype.__proto__=SomeObject2.prototype; +// Child class inherits prototype from parent using __proto__ +function inheritPrototype(child,parent) { + var __proto__=child.__proto__; + child.prototype.__proto__=parent.prototype; + if (!__proto__) for(var p in parent.prototype) { + if (p == '__proto__') continue; + child.prototype[p]=parent.prototype[p]; + } +} +// Polyfill fir o instanceof c with inheritance check (checking __proto__) +function instanceOf(obj,cla) { + var p=obj.__proto__; + if (obj instanceof cla) return true; + while (p) { + if (p === cla.prototype) return true; + p=p.__proto__ + } + return false; +} +// Polyfill for __defineGetter__ / __defineSetter__ +function defineGetter(cla,prop,fun) { + Object.defineProperty(cla.prototype,prop,{ + configurable:true, + get:fun + }); +} +function defineSetter(cla,prop,fun) { + Object.defineProperty(cla.prototype,prop,{ + configurable:true, + set:fun + }); + +} + +Object.addProperty = function (obj,name,fun) { + if (obj.prototype[name]) return; + obj.prototype[name]=fun; + Object.defineProperty(obj.prototype, name, {enumerable: false}); +}; + +Object.updateProperty = function (obj,name,fun) { + obj.prototype[name]=fun; + Object.defineProperty(obj.prototype, name, {enumerable: false}); +}; + +Object.addProperty(Array,'contains',function (el) { return this.indexOf(el)!=-1 }); +Object.addProperty(Array,'last',function () { return this[this.length-1] }); + +global.inherit = inherit; +global.inheritPrototype = inheritPrototype; +global.instanceOf = instanceOf; +global.defineGetter = defineGetter; +global.defineSetter = defineSetter; + +/** + * + */ +var assert = function(condmsg) { + if (condmsg != true) { + Io.out('** Assertion failed: '+condmsg+' **'); + Io.stacktrace(); + throw Error(condmsg); + } +}; +global.assert=assert; + +function forof(obj,f) { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = obj[Symbol.iterator](), _step; + !(_iteratorNormalCompletion = (_step = _iterator.next()).done); + _iteratorNormalCompletion = true) { + element = _step.value; + + f(element); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } +} + + +global.forof=forof; + +/** OBJ + * + */ +var obj = { + /** Compact an object: + * [{a:b},[c:d},..] -> {a:b,c:d,..} + * {a:[b]} -> {a:b} + * + */ + compact: function (o) { + var a; + if (obj.isArray(o)) { + if (o.length==1 && obj.isObject(o[0])) return obj.compact(o[0]); + else return o; + } else if (obj.isObject(o)) for (a in o) { + var elem=o[a]; + o[a]=obj.compact(elem); + } + return o; + }, + copy: function (o) { + if (o === null || typeof o !== 'object') { + return o; + } + + var temp = (o instanceof Array) ? [] : {}; + for (var key in o) { + temp[key] = obj.copy(o[key]); + } + + return temp; + }, + equal: function (o1,o2) { + if (!o1 || !o2) return false; + for(var i in o1) if (o1[i]!=o2[i]) return false; + for(var i in o2) if (o1[i]!=o2[i]) return false; + return true; + }, + extend: function (o1,o2) { + for(var i in o2) o1[i]=o2[i]; + return o1; + }, + find: function(obj,fun) { + var p; + for(p in obj) { + if (fun(obj[p],p)) return obj[p]; + } + }, + + hasProperty: function (o,p) { + return o[p]!=undefined || (p in o); + }, + head:function(o) { + for (var p in o) return p; + return undefined; + }, + // transfer src attributes to dst recusively (no object overwrite) + inherit: function (dst,src) { + for(var i in src) { + if (typeof dst[i] == 'object' && typeof src[i] == 'object') + inherit(dst[i],src[i]); + else if (typeof dst[i] == 'undefined') + dst[i]=src[i]; + } + return dst; + }, + isArray:function (o) { + if (o==_ || o ==null) return false; + else return typeof o == "array" || (typeof o == "object" && o.constructor === Array); + }, + isMatrix:function (o) { + if (o==_ || o ==null) return false; + else return obj.isArray(o) && + obj.isArray(o[0]); + }, + isEmpty: function (o) { + for(var prop in o) { + if (o[prop]!=undefined) return false; + } + return true; + }, + isError: function (o) { + return o instanceof Error + }, + isFunction: function (o) { + return typeof o == "function"; + }, + isObj:function (o) { + return typeof o == "object"; + }, + isObject:function (o) { + return typeof o == "object"; + }, + isRegex: function (o) { + return o instanceof RegExp; + }, + isString: function (o) { + return typeof o == "string" || (typeof o == "object" && o.constructor === String); + }, + isNumber: function (o) { + return typeof o == "number" || (typeof o == "object" && o.constructor === Number); + }, + + + iter: function(obj,fun) { + var p; + for(p in obj) { + fun(obj[p],p) + } + } +}; + +/** ARRAY + * + */ +var array = { + /** Evaluate a function returning a boolean value for each member of the array and + * compute the boolean conjunction. + * + * @param {* []} array + * @param {function(*,number)} fun + */ + and: function(array,fun) { + var res=true; + var i=0; + var len=array.length; + for(i=0;i|string|Blob|ArrayBuffer} + */ + copy: function(src,dst) { + var i; + if (dst) { + for(i in src) dst[i]=src[i]; + } else return src.slice(); + }, + /** Create a new array with initial element values. + * + * @param length + * @param init + * @returns {Array} + */ + create : function(length,init) { + var arr = [], i = length; + while (i--) { + arr[i] = init; + } + return arr; + }, + /** Create a matrix (array of array) with initial element values. + * + */ + create_matrix : function(rows,cols,init) { + var m = []; + var r = []; + var i,j; + for (i = 0; i < rows; i++) { + r=[]; + for(j=0;j=0;i--) { + fun(array[i],i) + } + }, + /** Return last element of array. + * + */ + last : function(array) { + var len=array.length; + if (len==0) return none; + else return array[len-1]; + }, + + length : function(array) { + return array.length; + }, + /** + * + * @param {* []} array1 + * @param {* []} array2 + * @param {function(*,*,number)} fun + * @returns {* []} + */ + map2: function(array1,array2,fun) { + var i=0; + assert((array1.length == array2.length)||('Array.map2: arrays of different lengths')); + var len=array1.length; + var res=[]; + for(i=0;i1) { + var hd = this.head(array); + var tl = this.tail(array); + fun_hdtl(hd,tl); + } else fun_hdtl(this.head(array),[]); + }, + /** + * + * @param {* []} array + * @param {Function} fun_hd1hd2 - function(hd1,hd2) + * @param {Function} [fun_hdtl] - function(hd,tl) + * @param {Function} [fun_empty] - function() + */ + match2: function(array,fun_hd1hd2,fun_hdtl,fun_empty) { + if (array.length == 0 && fun_empty) + fun_empty(); + else if (array.length == 2) { + var hd1 = this.head(array); + var hd2 = this.second(array); + fun_hd1hd2(hd1,hd2); + } + else if (array.length>1 && fun_hdtl) { + var hd = this.head(array); + var tl = this.tail(array); + fun_hdtl(hd,tl); + } else if (fun_hdtl) fun_hdtl(this.head(array),[]); + }, + /** Return the maximum element of an array applying + * an optional mapping function. + * + * @param {* []} array + * @param [fun] + * @returns {number|undefined} + */ + max : function (array,fun) { + var res,max,num; + for(var i in array) { + if (fun) num=fun(array[i]); else num=array[i]; + if (max==undefined) { max=num; res=array[i] } + else if (num > max) { max=num; res=array[i] } + } + return res; + }, + /** Return the minimum element of an array applying + * an optional mapping function. + * + * @param {* []} array + * @param [fun] + * @returns {number|undefined} + */ + min : function (array,fun) { + var res,min,num; + for(var i in array) { + if (fun) num=fun(array[i]); else num=array[i]; + if (min==undefined) { min=num; res=array[i] } + else if (num < min) { min=num; res=array[i] } + } + return res; + }, + /** Check for an element in the array. + * + * @param {(number|string|boolean) []} array + * @param {number|string|boolean} element + * @returns {boolean} + */ + member: function(array,element) { + var i,exist; + var len=array.length; + exist=false; + loop: for(i=0;i ['barney', 'fred'] + */ + pluck: function(collection, key) { + return collection.map(function(object) { + return object == null ? undefined : object[key]; + }); + }, + /* + ** Push/pop head elements (Stack behaviour) + */ + /** Remove and return top element of array. + * + * @param array + * @returns {*} + */ + pop : function(array) { + var element=array[0]; + array.shift(); + return element; + }, + print: function(array) { + var i; + var len=array.length; + var str='['; + for(i=0;i [1,2,6] + * @param {* []} array + * @returns {* []} + */ + remove: function(array,begin,end) { + var i,a; + if (end==undefined) end=begin+1; + if (begin<0 || end >= array.length) return []; + a=array.slice(0,begin); + for(i=end;i use remove!!! split should return two arrays!! + * + * @param array + * @param pos + * @param [len] + * @param element + */ + split: function(array,pos,len) { + if (pos==0) return array.slice((len||1)); + else { + var a1=array.slice(0,pos); + var a2=array.slice(pos+(len||1)); + return a1.concat(a2); + } + }, + /** Return the sum number of an array applying + * an optional mapping function. + * + * @param {* []} array + * @param [fun] + * @returns {number|undefined} + */ + sum : function (array,fun) { + var res=0; + for(var i in array) { + var num=0; + if (fun) num=fun(array[i]); else num=array[i]; + if (!obj.isNumber(num)) return undefined; + res += num; + } + return res; + }, + /** Return a new array w/o the head element (or optional + * w/o the first top elements). + * + */ + tail : function(array,top) { + var array2=array.slice(); + array2.shift(); + if (top) for(;top>1;top--) array2.shift(); + return array2; + }, + /** Return union of two sets (== conjunction set) + * + * @param {* []} set1 + * @param {* []} set2 + * @param {function} [fun] Equality test + * @returns {* []} + */ + union : function(set1,set2,fun) { + var i,j,res = []; + for (i in set1) { + for (j in set2) { + if (fun != undefined && fun(set1[i],set2[j])) res.push(set1[i]); + else if (fun == undefined && set1[i]==set2[j]) res.push(set1[i]); + } + } + return res; + }, + + /** + * Creates a duplicate-free version of an array + */ + unique: function(array) { + var length = array ? array.length : 0; + function baseUniq(array) { + var index = -1, + length = array.length, + seen, + result = []; + + seen = result; + outer: + while (++index < length) { + var value = array[index]; + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === value) { + continue outer; + } + } + result.push(value); + } + return result; + } + if (!length) { + return []; + } + return baseUniq(array); + }, + + /** + * Creates an array excluding all provided values + * without([1, 2, 1, 3], 1, 2); + * // => [3] + */ + without: function () { + var array, + values=[]; + for(var i in arguments) { + if (i==0) array=arguments[0]; + else values.push(arguments[i]); + } + return array.filter(function (e) { + return values.indexOf(e) == -1; + }); + }, + /** Test for zero elements {0, '', false, undefined, ..} + */ + zero: function (array) { + for(var i in array) if (!!array[i]) return false; + return true; + }, +}; + +/** STRING + * + */ +var string = { + /** Is pattern conatined in template? + * + */ + contains: function (template,pattern) { + return template.indexOf(pattern)>-1; + }, + copy: function(src) { + var i; + var dst=''; + for(i=0;i>4) & 0xf).toString(16))+ + ((n&0xf).toString(16)); + case 4: return (((n>>12) & 0xf).toString(16)+ + ((n>>8) & 0xf).toString(16)+ + ((n>>4) & 0xf).toString(16)+ + (n&0xf).toString(16)); + case 6: return (((n>>20) & 0xf).toString(16)+ + ((n>>16) & 0xf).toString(16)+ + ((n>>12) & 0xf).toString(16)+ + ((n>>8) & 0xf).toString(16)+ + ((n>>4) & 0xf).toString(16)+ + (n&0xf).toString(16)); + case 8: return (((n>>28) & 0xf).toString(16)+ + ((n>>24) & 0xf).toString(16)+ + ((n>>20) & 0xf).toString(16)+ + ((n>>16) & 0xf).toString(16)+ + ((n>>12) & 0xf).toString(16)+ + ((n>>8) & 0xf).toString(16)+ + ((n>>4) & 0xf).toString(16)+ + (n&0xf).toString(16)); + default: return 'format_hex??'; + } + }, + /** + * + * @param {string} str + * @param {number} index + * @returns {string} + */ + get: function (str,index) { + assert((str != undefined && index < str.length && index >= 0)||('string.get ('+str.length+')')); + return str.charAt(index); + }, + isBoolean: function (str) { + return (str=='true' || str=='false') + }, + isNumeric: function (str) { + return !isNaN(parseFloat(str)) && isFinite(str); + }, + isText: function (s) { + var is_text=true; + string.iter(s,function (ch,i) { + string.match(ch,[ + ['a','z',function () {}], + ['A','Z',function () {}], + ['0','9',function () {if (i==0) is_text=false;}], + function () {is_text=false;} + ]); + }); + return is_text; + }, + /** + * + * @param {string} str + * @param {function(string,number)} fun + */ + iter: function(str,fun) { + var i; + var len=str.length; + for (i = 0; i < len; i++) { + var c = str.charAt(i); + fun(c,i); + } + }, + /** + * + * @param str + * @returns {*} + */ + length: function(str) { + if (str!=undefined) return str.length; + else return 0; + }, + /** + * + * @param str + * @returns {string} + */ + lowercase : function (str) { + return str.toLowerCase(); + }, + /** + * + * @param {number} size + * @param {string} init + * @returns {string} + */ + make: function(size,init) + { + var i; + var s=''; + for(i=0;i,,..],fun] | [:string,:string,fun] | fun) [] + */ + match: function(str,cases) { + var i,j; + var cas,cex,cv; + for(i in cases) { + cas=cases[i]; + if (obj.isArray(cas)) { + switch (cas.length) { + case 2: + // Multi-value-case + cex=cas[0]; + if (!obj.isArray(cex)) { + if (this.equal(str,cex)) { + cas[1](); + return; + } + } else { + for(j in cex) { + cv=cex[j]; + if (this.equal(str,cv)) { + cas[1](); + return; + } + } + } + break; + case 3: + // Character range check + try { + j=pervasives.int_of_char(str); + if (j>= pervasives.int_of_char(cas[0]) && j<=pervasives.int_of_char(cas[1])) { + cas[2](str); + return; + } + } catch(e) { + return + }; + break; + case 1: + cas[0](str); // Default case - obsolete + return; + default: + throw 'String.match #args'; + } + } else if (obj.isFunction(cas)) { + // Default case + cas(str); + return; + } + } + }, + /** Pad a string on the left (pre-str.length) if pre>0, + * right (post-str.length) if post>0, or centered (pre>0&post>0). + * + */ + + pad: function (str,pre,post,char) { + var len = str.length; + if (pre>0 && post==0) return string.make(len-pre,char||' ')+str; + else if (post>0 && pre==0) return str+string.make(post-len,char||' '); + else return string.make(len-pre/2,char||' ')+str+string.make(len-post/2,char||' '); + }, + /** + * + * @param str + * @param pos + * @param len + * @returns {Number} + */ + parse_hex: function (str,pos,len) { + // parse a hexadecimal number in string 'str' starting at position 'pos' with 'len' figures. + return parseInt(this.sub(str,pos,len),16); + }, + /** Return the sub-string after a point in the source string ('.' or optional point string). + * If there is no splitting point, the original string is returned. + * + * @param str + * @param [point] + * @returns {string} + */ + postfix: function (str,point) { + var n = str.indexOf(point||'.'); + if (n <= 0) return str; + else return str.substr(n+1); + }, + /** Return the sub-string before a point in the source string ('.' or optional point string) + * If there is no splitting point, the original string is returned. + * + * @param str + * @param [point] + * @returns {string} + */ + prefix: function (str,point) { + var n = str.indexOf(point||'.'); + if (n <= 0) return str; + else return str.substr(0,n); + }, + replace_first: function (pat,repl,str) { + return str.replace(pat,repl); + }, + replace_all: function (pat,repl,str) { + return str.replace('/'+pat+'/g',repl); + }, + /** + * + * @param str + * @param index + * @param char + * @returns {string} + */ + set: function (str,index,char) { + assert((str != undefined && index < str.length && index >= 0)||'string.get'); + return str.substr(0, index) + char + str.substr(index+1) + }, + /** + * + * @param delim + * @param str + * @returns {*|Array} + */ + split: function (delim,str) { + return str.split(delim); + }, + startsWith : function (str,head) { + return !str.indexOf(head); + }, + /** Return a sub-string. + * + * @param str + * @param off + * @param [len] If not give, return a sub-string from off to end + * @returns {string} + */ + sub: function (str,off,len) { + if (len) + return str.substr(off,len); + else + return str.substr(off); + }, + /** Remove leading and trailing characters from string + * + * @param str + * @param {number} pref number of head characters to remove + * @param {number} post number of tail characters to remove + * @returns {*} + */ + trim: function (str,pref,post) { + if (str.length==0 || + pref>str.length || + post>str.length || + pref < 0 || post < 0 || + (pref==0 && post==0) + ) return str; + return str.substr(pref,str.length-pref-post); + }, + /** Return a string with all characters converted to uppercase letters. + * + * @param str + * @returns {string} + */ + uppercase : function (str) { + return str.toUpperCase(); + }, + /** Return a string with first character converted to uppercase letter. + * + * @param str + * @returns {string} + */ + Uppercase : function (str) { + var len = str.length; + if (len > 1) { + var head = str.substr(0,1); + var tail = str.substr(1,len-1); + return head.toUpperCase()+tail.toLowerCase() + } if (len==1) return str.toUpperCase(); + else return ''; + } +}; + +/** RANDOM + * + */ +var rnd = Math.random; +/* Antti Syk\E4ri's algorithm adapted from Wikipedia MWC +** Returns a random generator function [0.0,1.0| with seed initialization +*/ +var seeder = function(s) { + var m_w = s; + var m_z = 987654321; + var mask = 0xffffffff; + + return function() { + m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; + m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; + + var result = ((m_z << 16) + m_w) & mask; + result /= 4294967296; + + return result + 0.5; + } +} + +var random = { + float: function(max) { + return rnd()*max + }, + int: function(max) { + return Math.floor(rnd()*max+0) + }, + // integer + interval: function(min,max) { + return Math.round(min+rnd()*(max-min)) + }, + // float + range: function(min,max) { + return min+rnd()*(max-min) + }, + seed: function (s) { + // Create a new initialized random generator + rnd=seeder(s); + } +}; + +/** PRINTF + * + */ +var printf = { + /** Trim string(s). + * + * @param str + * @param indent + * @param [width] + * @param {string} [tab] + * @returns {string} + */ + align: function (str,indent,width,tab) { + var lines = string.split('\n',str); + var form = ''; + var sp = printf.spaces(indent); + var spbreak = sp; + + array.iter(lines,function(line){ + var rest; + function breakit(spbreak,str) { + if (width < (str.length + spbreak.length)) { + return spbreak+string.sub(str,0,width-spbreak.length)+'\n'+ + breakit(spbreak,string.sub(str,width-spbreak.length,str.length-width+spbreak.length)); + } else return spbreak+str+'\n'; + } + if (width && width < (line.length + indent)) { + if (tab) { + var pos = string.find(tab,line); + if (pos > 0 && pos < width) spbreak=printf.spaces(pos+indent+1); + else spbreak=sp; + } + form=form+sp+string.sub(line,0,width-indent)+'\n'; + rest=string.sub(line,width-indent,line.length-width+indent); + form=form+breakit(spbreak,rest); + } + else + form=form+sp+line+'\n'; + }); + return form; + }, + /** Format a list of array elements using the (optional) mapping + * function and the separator (optional, too, default is ','). + * + */ + list: function (array,fun,sep) { + var i, str=''; + if (sep==undefined) sep=','; + if (fun==undefined) fun=function (s) {return s;}; + if (!obj.isArray(array)) array=[array]; + for (i in array) { + if (str==='') str=fun(array[i]); + else str=str+sep+fun(array[i]); + } + return str; + }, + /** + * + * @param n + * @returns {string} + */ + spaces: function (n){ + return string.make(n,' '); + }, + /** Formatted printer (simplified) + * + * @param {* []} args (['%format',arg]|string) [] format=%s,%d,%f,%c,%x,%#d,%#s,.. + * @returns {string} + */ + sprintf2: function(args) { + var str=''; + array.iter(args,function(fmtarg) { + var len, n,fs; + if (obj.isArray(fmtarg)) { + if (fmtarg.length==2) { + var fmt=fmtarg[0]; + var arg=fmtarg[1]; + var fc=''; + var fn=0; + string.iter(fmt,function(c) { + if (c=='s' || c=='d' || c=='f' || c=='x') { + fc=c; + } else if (c!='%') { + fn=fn*10; + n=parseInt(c); + if (!isNaN(n)) fn=fn+n; + } + }); + if (fc=='s' && obj.isString(arg)) { + str=str+arg; + if (fn!=0) { + len=arg.length; + if (len 0 && path[0] == '/'); + }, + /** + * + * @param pathl + * @param absolute + * @returns {string} + */ + join: function (pathl,absolute) { + var path=(absolute?'/':''); + array.iter(pathl,function (name,index) { + if (index>0) { + path=path+'/'+name; + } + else { + path=path+name; + } + }); + return path; + }, + /** + * + * @param path + * @returns {string} + */ + normalize : function (path) { + return Path.normalize(path) + }, + /** + * + * @param path + * @returns {*} + */ + path_absolute: function (path) { + if (this.is_relative(path)) { + var workdir = Io.workdir(); + return this.path_normalize(workdir + '/' + path); + } else return this.path_normalize(path); + }, + /** Duplicate of Path.normalize!? + * + * @param path + * @returns {string} + */ + path_normalize: function (path) { + var i; + if (string.equal(path, '')) path = '/'; + var relpath = !(string.get(path, 0) == '/'); + var pathlist = path.split('/'); + var pathlist2 = pathlist.filter(function (s) { + return (!string.equal(s, '') && !string.equal(s, '.')) + }); + var pathlist3 = []; + array.iter(pathlist2, function (pe) { + if (!string.equal(pe, '..')) { + array.push(pathlist3, pe) + } else { + if (pathlist3.length == 0) return ''; + else + pathlist3 = array.tail(pathlist3); + } + }); + var path2 = ''; + i = 0; + array.iter(pathlist3, function (pe) { + var sep; + if (i == 0) sep = ''; else sep = '/'; + path2 = pe + sep + path2; + i++; + }); + if (relpath) return path2; else return '/' + path2; + }, + removeext: function (path) { + return path.substr(0, path.lastIndexOf('.')); + } +}; + +/** PERVASIVES + * + * + */ +var pervasives = { + assert:assert, + char_of_int: function (i) {return String.fromCharCode(i)}, + div: function(a,b) {return a/b|0;}, + failwith: function(msg) {Io.err(msg);}, + float_of_string: function(s) {var num=parseFloat(s); if (isNaN(num)) throw 'NaN'; else return num;}, + int_of_char: function(c) {return c.charCodeAt()}, + int_of_float: function(f) {return f|0;}, + int_of_string: function(s) { + var num=parseInt(s); if (isNaN(num)) throw 'NaN'; else return num; + }, + + /** Try to find a value in a search list and return a mapping value. + * + * @param {*} value + * @param {* []} mapping [testval,mapval] [] + * @returns {*} + */ + map: function(value,mapping) { + function eq(v1,v2) { + if (v1==v2) return true; + if (obj.isString(v1) && obj.isString(v2)) return string.equal(v1,v2); + return false; + } + if (!array.empty(mapping)) { + var hd=array.head(mapping); + var tl=array.tail(mapping); + if (eq(hd[0],value)) return hd[1]; + else return pervasives.map(value,tl); + } else return undefined; + }, + /** Apply a matcher function to a list of cases with case handler functions. + * A case is matched if the matcher function returns a value/object. + * + * The result of the matcher function is passed as an argument ot the case handler function. + * The return value of the case handler fucntion is finally returned by this match function + * or undefined if there was no matching case. + * + * @param {function(*,*):*} matcher function(expr,pat) + * @param {*} expr + * @param {*[]} cases (pattern,handler function | handler function) [] + * @returns {*|undefined} + */ + match: function (matcher,expr,cases) { + var ret = undefined; + array.iter_break(cases, function (match) { + var quit, succ, pat, fun; + + if (match.length == 2) { + /* + ** Pattern, Function + */ + pat = match[0]; + fun = match[1]; + succ = matcher(expr, pat); + if (succ) ret = fun(succ); + quit = succ!=undefined; + } else if (match.length == 1) { + /* + ** Default case, Function + */ + fun = match[0]; + ret = fun(); + quit= true; + } + return quit; + }); + return ret; + }, + mtime: function () {var time = new Date(); return time.getTime();}, + min: function(a,b) { return (ab)?a:b}, + string_of_float: function(f) {return f.toString()}, + string_of_int: function(i) {return i.toString()}, + string_of_int64: function(i) {return i.toString()}, + time: function () {var time = new Date(); return (time.getTime()/1000)|0;} +}; + +/** BIT + * + */ +var bit = { + get: function (v,b) {return (v >> b) && 1;}, + isSet: function (v,b) {return ((v >> b) && 1)==1;}, + set: function (v,b) {return v & (1 << b);} +}; + +/** ARGS + * + */ +var args = { + /** Parse process or command line arguments (array argv). The first offset [1] arguments are + ** ignored. The numarg pattern '*' consumes all remaining arguments. + * + * @param {string []} argv + * @param {*[]} map [,,]|[] [] + * @param {number} [offset] + */ + parse: function(argv,map,offset) { + var shift=undefined, + in_shift=0, + shift_args=[], + names, + mapfun, + numarg, + len=argv.length; + + if (offset==undefined) offset=1; + + argv.forEach(function (val, index) { + var last=index==(len-1); + if(index>=offset) { + if (in_shift==0) { + array.check(map,function (onemap) { + assert(onemap!=undefined||'map'); + if (onemap.length==3) { + names = onemap[0]; + numarg = onemap[1]; + mapfun = onemap[2]; + if (!obj.isArray(names)) names=[names]; + var found = array.find(names,function (name) { + if (string.equal(val, name)) return name; else _; + }); + if (found) { + if (numarg==0) mapfun(found); + else { + in_shift=numarg; + shift_args=[]; + shift=mapfun; + } + return true; + } + } else if (obj.isFunction(onemap)) { + onemap(val); + return true; + } else if (onemap.length==1) { + mapfun = onemap[0]; + mapfun(val); + return true; + } + return false; + }); + } else { + shift_args.push(val); + if (in_shift!='*') in_shift--; + if (in_shift==0 && shift!=undefined) { + numarg=shift_args.length; + switch (numarg) { + case 0: shift(val);break; + case 1: shift(shift_args[0],val); break; + case 2: shift(shift_args[0],shift_args[1],val); break; + case 3: shift(shift_args[0],shift_args[1],shift_args[2],val); break; + default: break; + } + shift=undefined; + } else if (in_shift=='*' && last) shift(shift_args); + } + } + }); + } + +}; + +/** HASHTBL + * + */ +var hashtbl = { + add: function(hash,key,data) { + hash[key]=data; + }, + create: function(initial) { + return []; + }, + empty: function(hash) { + for (var key in hash) return false; + return true; + }, + find: function(hash,key) { + return hash[key]; + }, + invalidate: function(hash,key) { + hash[key]=undefined; + }, + iter: function(hash,fun) { + for (var key in hash) { + if (hash[key]!=undefined) fun(key,hash[key]); + } + }, + mem: function(hash,key) { + return hash[key] != undefined; + }, + remove: function(hash,key) { + // TODO: check, its wrong! + if (!hash.hasOwnProperty(key)) + return; + if (isNaN(parseInt(key)) || !(hash instanceof Array)) + delete hash[key]; + else + hash.splice(key, 1) + } +}; + +var types = []; +/** + * + * @param name + * @returns {number} + */ +function register_type(name) { + var typoff = 1000+types.length*1000; + if (array.member(types,name)) throw('[COMP] register_type: type '+name+' exists already.'); + types.push(name); + return typoff; +} + +/** + * + * @typedef {{v1:*, v2:*, v3:*, v4:*, v5:*, v6:*, v7:*, v8:*, v9:* }} tuple + */ +/** + * + * @typedef {{t:number, v1:*, v2:*, v3:*, v4:*, v5:*, v6:*, v7:*, v8:*, v9:* }} tagged_tuple + */ + +module.exports = { + args:args, + assert: assert, + array:array, + bit:bit, + copy:obj.copy, + div:pervasives.div, + filename:filename, + hashtbl:hashtbl, + isNodeJS: function () { + return (typeof global !== "undefined" && + {}.toString.call(global) == '[object global]'); + }, + obj:obj, + pervasives:pervasives, + printf:printf, + random:random, + string:string, + isArray: obj.isArray, + isString: obj.isString, + isNumber: obj.isNumber, + + register_type:register_type, + /** + * + * @param tag + * @param [val1] + * @param [val2] + * @param [val3] + * @returns {(tagged_tuple)} + */ + Tuple: function (tag,val1,val2,val3) { + if(val3) return {t:tag,v1:val1,v2:val2,v3:val3}; + else if (val2) return {t:tag,v1:val1,v2:val2}; + else if (val1) return {t:tag,v1:val1}; + else return {t:tag}; + } +};