UNPKG

incr-regex-package

Version:

An incremental regular expression parser in JavaScript; useful for input validation, RegExp

711 lines (625 loc) 19.2 kB
/** * Copyright (c) 2016, Nurul Choudhury * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ "use strict"; // export function assign(object) { // if (!object) { // return object; // } // for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { // var iterable = arguments[argsIndex]; // if (typeof iterable === 'function' || (typeof iterable === 'object' && iterable !== null)) { // var index = -1, keys = Object.keys(iterable), // length = keys ? keys.length : 0, prop; // while (++index < length) { // prop = keys[index]; // object[prop] = iterable[prop]; // } // } // } // return object; // } Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.assign = assign; exports.copy = copy; exports.ID = ID; exports.flatten = flatten; exports.array_eq = array_eq; exports.arr_uniq = arr_uniq; exports.arr_find = arr_find; exports.array_match = array_match; exports.array_append = array_append; exports.sreverse = sreverse; exports.sprefix = sprefix; exports.rprefix = rprefix; exports.shead = shead; exports.stail = stail; exports.sRightMerge = sRightMerge; exports.parseMulti = parseMulti; exports.odd = odd; exports.arr_push = arr_push; exports.n_cons = n_cons; exports.n_head = n_head; exports.n_tail = n_tail; exports.n_reverse = n_reverse; exports.arrayToList = arrayToList; exports.stringToList = stringToList; exports.listToArray = listToArray; exports.listToString = listToString; exports.n_concat = n_concat; exports.n_map = n_map; exports.n_filter = n_filter; exports.n_find = n_find; exports.n_reduce = n_reduce; exports.n_removeAll = n_removeAll; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function assign() { return Object.assign.apply(Object, arguments); } function copy(obj) { return assign({}, obj); } //function has(obj,key) { return !!obj[key]; } // export function extend(protoProps, staticProps) { // var Parent = this, Child; // if (typeof Parent !== 'function') throw new Error('Parent must be a constructor function'); // if (has(protoProps, 'constructor')) { // Child = protoProps.constructor; // } else { // Child = function(){ return Parent.apply(this, arguments); }; // } // assign(Child, Parent, staticProps); // // subclass extends superclass // Child.prototype = Object.create(Parent.prototype); // if (protoProps) assign(Child.prototype, protoProps); // Child.prototype.constructor = Child; // //Child.__super__ = Parent.prototype; // return Child; // } var contract = exports.contract = function () { var call = Function.prototype.call; var getClassName = call.bind({}.toString); // A contract that allows anything var isUndef = function isUndef(x) { return x === undefined; }; var NVL = function NVL(v, dflt) { return isUndef(v) ? dflt : v; }; var any = function any(x) { return x; }; var isClassOf = function isClassOf(s) { var TYPE = "[object " + s + "]"; return function (v) { return getClassName(v) == TYPE; }; }; var classOf = function classOf(s) { var TYPE = "[object " + s + "]"; return function (v) { if (getClassName(v) !== TYPE) { throw new TypeError("Expected " + s); } return v; }; }; var isArr = isClassOf("Array"); // Manditory contract var arr = classOf("Array"); var isTypeOf = function isTypeOf(s) { return function (v) { return (typeof v === "undefined" ? "undefined" : _typeof(v)) == s; }; }; // Creates a contract for a value of type s var typeOf = function typeOf(s) { return function (v) { if ((typeof v === "undefined" ? "undefined" : _typeof(v)) !== s) { throw new TypeError("Expected a" + (s === "object" ? "n" : "") + s + "."); } return v; }; }; //Manditory contract var func = typeOf("function"); var isFunc = isTypeOf("function"); var STR = typeOf('String'); // Creates a contract for an object inheriting from ctor var instanceOf = function instanceOf(ctor) { return function (inst) { if (!(inst instanceof ctor)) { throw new TypeError("Expected an instance of " + ctor); } return inst; }; }; var int32 = function int32(n) { if ((n | 0) !== n) { throw new TypeError("Expected a 32-bit natural."); } return n; }; // Asserts int32 and nonnegative var nat32 = function nat32(n) { if ((n | 0) !== n || n < 0) { throw new TypeError("Expected a 32-bit natural."); } return n; }; return { int32: int32, nat32: nat32, func: func, isFunc: isFunc, typeOf: typeOf, isTypeOf: isTypeOf, arr: arr, isArr: isArr, classOf: classOf, isClassOf: isClassOf, instanceOf: instanceOf, isUndef: isUndef, STR: STR, any: any, NVL: NVL }; }(); function ID(x) { return x; } function flatten(anArray) { var newArray = []; return newArray.concat.apply(newArray, anArray); } function array_eq(array, another) { // if the other array is a falsy value, return if (array === another) return true; if (!array || !another) return false; // compare lengths - can save a lot of time if (another.length !== array.length) return false; for (var i = 0, l = another.length; i < l; i++) { // Check if we have nested arrays if (another[i] instanceof Array && array[i] instanceof Array) { // recurse into the nested arrays if (!array_eq(array[i], another[i])) return false; } else if (another[i] !== array[i]) { // Warning - two different object instances will never be equal: {x:20} != {x:20} return false; } } return true; } function arr_uniq(arr) { var seen = {}; var arr2 = []; for (var i = 0; i < arr.length; i++) { if (!(arr[i] in seen)) { arr2.push(arr[i]); seen[arr[i]] = true; } } return arr2; } function arr_find(fn, arr) { for (var i = 0; i < arr.length; i++) { if (fn(arr[i])) { return arr[i]; } } return undefined; } function array_match(array, subArray, at) { // if the other array is a falsy value, return if (!array || !subArray) return false; var len = array.length; var lenS = subArray.length; if (at + lenS > len) return false; // cannot match subArray too long for (var i = at, j = 0; j < lenS; i++, j++) { // Check if we have nested arrays if (subArray[j] instanceof Array && array[i] instanceof Array) { // recurse into the nested arrays if (!array_match(array[i], subArray[j], 0)) return false; } else if (array[i] !== subArray[j]) { // Warning - two different object instances will never be equal: {x:20} != {x:20} return false; } } return true; } function array_append(arr, list) { for (var i = 0; i < list.length; i++) { arr.push(list[i]); }return arr; } // Handy string utilities function sreverse(s) { var o = []; for (var i = 0, len = s.length; i <= len; i++) { o.push(s.charAt(len - i)); }return o.join(''); } // Find the prefix of two strings, // s1 = prefix + rest_of_s1; // s2 = prefix + rest_of_s2 // sprefix(s1,s2) === prefix function sprefix(s1, s2) { var i = 0; for (; i < s1.length && i < s2.length; i++) { if (s1.charAt(i) !== s2.charAt(i)) return s1.substring(0, i); } return s1.length < s2.length ? s1 : s2; } // Find the postfix of two strings, // s1 = s1_start + post; // s2 = s2_start + post; // rprefix(s1,s2) === post function rprefix(s1, s2) { return sreverse(sprefix(sreverse(s1), sreverse(s2))); } // s = head + rest_of_s // n = head.length // shead(s,n) === head function shead(s, n) { return s.length < n ? s : s.substr(0, n); } // s = start_os_s + tail // n = tail.length // stail(s,n) === tail function stail(s, n) { return s.length < n ? s : s.substr(s.length - n, n); } // s1 = start_of_s1 + end // s2 = end + rest_of_s2 // sRightMerge(s1,s2) === start_of_s1 + s2 // example s1 = "Jim hello", s2 = "hello how are you" // sRightMerge(s1,s2) === "Jim hello how are you" // where: end is the longet string that satisfies the relationship above function sRightMerge(s1, s2) { var n = Math.min(s1.length, s2.length); function match(s1, s2, n) { for (var i = s1.length - n, j = 0; j < n; i++, j++) { if (s1.charAt(i) !== s2.charAt(j)) return false; }return true; } for (var i = n; i > 0; i--) { if (match(s1, s2, i)) return s1.substr(0, s1.length - i) + s2; } return s1 + s2; } // Polyfill Object.assign if (typeof Object.assign != 'function') { (function () { Object.assign = function (target) { if (target === undefined || target === null) { throw new TypeError('Cannot convert undefined or null to object'); } var output = Object(target); for (var index = 1; index < arguments.length; index++) { var source = arguments[index]; if (source !== undefined && source !== null) { for (var nextKey in source) { if (source.hasOwnProperty(nextKey)) { output[nextKey] = source[nextKey]; } } } } return output; }; })(); } // function rxtokensOld() { // var t = "\\[(?:\\\\]|[^\\]]])*\\]"; // var meta = "[.\\]|)]|\\(\\?:|\\(|\\?\\?|\\?|\\*\\?|\\*|\\+\\?|\\+"; // var escaped = "\\\\(?:"+meta + "|" + "[dDsSbBwW\\[{}\\]])"; // var group ="\\{[0-9]+(?:,[0-9]*)?\\}"; // var nonMeta = "[^.+?{}\\]\\[|()]"; // return [ /*unicode,*/ t, group, escaped, meta, nonMeta ].join("|"); // } /* REGEXP TOKENIZER HELPERS */ var TOKINIZATION_RX = exports.TOKINIZATION_RX = makeRegexp(); function rxtokens() { function ESACPE(s) { return s.split('').map(function (a) { return "\\" + a; }).join('|'); } function OR(s) { return s.split('').join('|'); } //var charSet = "\\[(?:\\\\u|\\\\\\]|\\\\\\\\|(\\\\)?\\[|[^\\]\\[\\\\])*?\\]"; var charSet = "(?:\\[\\^\\]|\\[\\^?(?:\\\\.|[^\\]])*?(?:\\\\\\\\]|[^\\\\]]))"; // may not work //var meta = "[.\\]|)]|\\(\\?:|\\(|\\?\\?|\\?|\\*\\?|\\*|\\+\\?|\\+"; var meta1 = ESACPE(".|+*?()^$"); var meta2 = "\\(\\?:|\\?\\?|\\*\\?|\\+\\?"; var escapeTarget1 = OR("dDsSbBwW"); var escapeTarget2 = ESACPE("[]{}\\"); var escapeTarget = [meta1, escapeTarget1, escapeTarget2].join('|'); var escaped = "\\\\(?:" + escapeTarget + ")"; var group = "\\{(?:\\d+,\\d+|\\d+|\\d+,|,\\d+)\\}"; var nonMeta = "[^.+?{}\\]\\[|()\\\\]"; return [charSet, group, escaped, meta2, meta1, nonMeta].map(function (a) { return "(?:" + a + ")"; }).join("|"); } // function makeRegexp() { return new RegExp(rxtokens(), "g"); } function parseMulti(str) { var m = str.match(/\{(\d+)(,(\d*))?\}/); // handles { 3 }, { 4, }, {6, 9} var low = Number(m[1]); return { min: Number(m[1]), max: m[3] ? Number(m[3]) : m[2] ? undefined : low }; } function odd(x) { return (+x & 1) > 0; } // push element into an array, or return the element function arr_push(arr, elem) { if (arr === undefined) return elem; arr.push(elem); return arr; } // =========================== // Stack/Array with no duplicates var StackDedup = exports.StackDedup = function () { function StackDedup(v) { _classCallCheck(this, StackDedup); this.length = 0; this.data = []; v && this.push(v); this.maxLen = 0 | 0; } _createClass(StackDedup, [{ key: "forEach", value: function forEach(f) { var data = this.data; for (var i = 0; i < this.length; i++) { f(data[i], i, this); } return this; } }, { key: "reduce", value: function reduce(f, iniV) { var data = this.data; for (var i = 0; i < this.length; i++) { iniV = f(iniV, data[i], i, this); } return iniV; } }, { key: "filter", value: function filter(f) { var s = new StackDedup(); var data = this.data; s.maxLen = this.maxLen; for (var i = 0; i < this.length; i++) { if (f(data[i], i, this)) s.push(data[i]); } return s; } }, { key: "map", value: function map(f) { var s = new StackDedup(); var data = this.data; s.maxLen = this.maxLen; for (var i = 0; i < this.length; i++) { s.push(f(data[i], i, this)); } return s; } }, { key: "toArray", value: function toArray() { return this.reduce(arr_push, []); } }, { key: "reset", value: function reset() { this.length = 0 | 0; this.maxLen = 0 | 0; return this; } }, { key: "contains", value: function contains(v) { var data = this.data; var len = this.length; for (var i = 0; i < len; i++) { if (data[i] === v) { return this; } } return undefined; } }, { key: "push", value: function push(v) { if (v === undefined) return this; if (this.contains(v)) return this; this.data[this.length++] = v; if (this.length > this.maxLen) this.maxLen = this.length; return this; } }, { key: "pop", value: function pop() { if (this.length <= 0) return this; this.length--; return this; } }, { key: "top", value: function top() { if (this.length <= 0) return undefined; return this.data[this.length - 1]; } }, { key: "addAll", value: function addAll(list) { var _this = this; //console.log("ADD ALL",list); if (!list) return this; list.forEach(function (a) { return _this.push(a); }); return this; } }, { key: "clone", value: function clone() { return this.map(function (a) { return a; }); } }]); return StackDedup; }(); //============================================ // Immutable list implementation var List_n = function () { function List_n(l, r) { _classCallCheck(this, List_n); this.head = l; this.tail = r; } _createClass(List_n, [{ key: "equals", value: function equals(b) { if (b === null) return false; return this.head === b.head && this.tail === b.tail; } }, { key: "addAll", value: function addAll(aList) { if (!aList) return this; return n_reverse(aList).reduce(function (rst, head) { return n_cons(head, rst); }, this); } }, { key: "map", value: function map(f) { return n_map(f, this); } }, { key: "reduce", value: function reduce(f, base) { return n_reduce(f, this, base); } }, { key: "reverse", value: function reverse(base) { return n_reverse(this, base); } }]); return List_n; }(); function n_cons(elem, list, base) { return new List_n(elem, list); } function n_head(list) { if (!list) throw Error("n_head of empty list"); return list.head; } function n_tail(list) { if (!list) throw Error("n_tail of empty list"); return list.tail; } /* note nl is optional */ function n_reverse(list) { var nl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; //nl = nl || null; if (!list) return nl; return n_reverse(n_tail(list), n_cons(n_head(list), nl)); // simple tail recursion } function arrayToList(array) { return n_reverse(array.reduce(function (a, b) { return n_cons(b, a); }, null)); } function stringToList(str) { return arrayToList(str.split("")); } function listToArray(list) { return n_reduce(function (a, b) { a.push(b);return a; }, list, []); } function listToString(list) { return listToArray(list).join(''); } function n_concat(list1, list2) { if (!list1) return list2; return !list1 ? list2 : n_cons(n_head(list1), n_concat(n_tail(list1), list2)); } function n_map(fn, list, i) { i = i || 0; return !list ? list : n_cons(fn(n_head(list), i, list), n_map(fn, n_tail(list), i + 1)); } function n_filter(fn, list, i) { if (!list) return list; i = i || 0; if (fn(n_head(list), i, list)) return n_cons(n_head(list), n_filter(fn, n_tail(list), i + 1)); return n_filter(fn, n_tail(list), i + 1); } function n_find(fn, list, i) { i = i || 0; if (!list) return null; return fn(n_head(list), i, list) ? list : n_find(fn, n_tail(list), i + 1); } function n_reduce(fn, list, base) { return !list ? base : n_reduce(fn, n_tail(list), fn(base, n_head(list))); // simple tail recursion } function n_removeAll(eq, list, listOfItemsToRemove) { if (arguments.length === 2) { listOfItemsToRemove = list; list = eq; eq = function eq(a, b) { return a === b; }; } return n_filter(function (e) { return !n_find(function (a) { return eq(a, e); }, listOfItemsToRemove); }, list); } // POlyfill for array.find if (!Array.prototype.find) { Array.prototype.find = function (predicate) { 'use strict'; if (this == null) { throw new TypeError('Array.prototype.find called on null or undefined'); } if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } var list = Object(this); var length = list.length >>> 0; var thisArg = arguments[1]; var value; for (var i = 0; i < length; i++) { value = list[i]; if (predicate.call(thisArg, value, i, list)) { return value; } } return undefined; }; } // stringToList, listToArray, listToString, n_cons, n_head, n_tail, n_filter, n_reduce, n_map, n_concat, n_removeAll