Source: regex.js

/*
	This is the general, platform-independent part of every parser driver;
	Input-/Output and Feature-Functions are done by the particular drivers
	created for the particular platform.
*/

(function(root, factory) {
    /* istanbul ignore next */
	if (typeof define === 'function' && define.amd) {
		define(['require', './global', './log/log', './classes/Param', './classes/Nfa', './enums/EDGE'], factory);
	} else if (typeof module === 'object' && module.exports) {
		module.exports = factory(require);
	} else {
		root.jsccregex = factory(function(mod) {
		    return root["jscc" + mod.split("/").pop()];
		});
	}
}(this,
  /**
   * @param {reqParameter} require
   * @param {...*} others
   * @returns {function(string, number, boolean, number)}
   */
  function(require, others) {
var first_nfa;
var last_nfa;
//>>excludeStart("closure", pragmas.closure);
var has = /** @type {hasObject} */ (require("./localHas"));
//>>excludeEnd("closure");

var log, global = /** @type {jscc.global} */ (require("./global")),
    Param = /** @type {function(new:jscc.classes.Param, number=, number=)} */ (require("./classes/Param")),
    Nfa = /** @type {function(new:jscc.classes.Nfa, ?NfaOptions=)} */ (require("./classes/Nfa")),
    EDGE = require("./enums/EDGE");

/**
 * @suppress {uselessCode}
 */
(function() {
    if (has("node")) {
        log = /** @type {jscc.log} */ (require("./log/logNode"));
    } else {
        log = /** @type {jscc.log} */ (require("./log/log"));
    }
})();


var __parse=(function(/** number */ eof, /** number */ whitespace, /** number */ error_token){
	
/// there was "continue" in code, we must to replace it
var Continue = function(){throw Continue;};

	/**
	 * @template T
	 * @param {T} value
	 * @constructor
	 * @extends {Error}
     */
	var ReturnValue = function(value) {
		Error.call(this);
		this._value = value;
	};
	ReturnValue.prototype = Object.create(Error.prototype);
	ReturnValue.prototype.constructor = ReturnValue;
	/**
	 * @type {T}
	 * @private
     */
	ReturnValue.prototype._value = null;
	/**
	 * @returns {T}
     */
	ReturnValue.prototype.valueOf = function() {
		return this._value;
	};

	///can return value from any place of callback
	function Return(value){
		throw new ReturnValue(value);
	}

	var TERMINAL_ACTIONS = (function(){
		function emptyFn(PCB){return PCB.att;}
		var actions = ({

})
		return function(/** @type {!PcbClass} */ PCB, match){
			try{
				return (actions[match] || emptyFn)(PCB);
			}catch(e){
				if(e instanceof ReturnValue)return e.valueOf();
				if(e == Continue)return Continue;
				throw e;
			}
		}
	})();
	/**
	 * @constructor
     */
	var DfaLex = function() {
		this._dfaData = [{line:[[[[1,
	[[1,
	[[[2,
	3],
	[4,
	5]],
	[1,
	[6,
	1]]]],
	[1,
	[1,
	[1,
	[1,
	7]]]]]],
	[[1,
	[1,
	[[1,
	[1,
	8]],
	[[13,
	9],
	1]]]],
	[1,
	[1,
	[1,
	[[10,
	1],
	1]]]]]],
	[1,
	[1,
	[1,
	[1,
	[1,
	[1,
	[1,
	null]]]]]]]]],
	accept:-1},
	{line:[],
	accept:13},
	{line:[],
	accept:6},
	{line:[],
	accept:7},
	{line:[],
	accept:3},
	{line:[],
	accept:4},
	{line:[],
	accept:10},
	{line:[],
	accept:5},
	{line:[],
	accept:8},
	{line:[],
	accept:9},
	{line:[],
	accept:2},
	{line:[],
	accept:12},
	{line:[[[[null,
	[null,
	[12,
	[[12,
	null],
	null]]]],
	null],
	null]],
	accept:11},
	{line:[[[[11,
	[11,
	[12,
	[[12,
	11],
	11]]]],
	11],
	[11,
	[11,
	[11,
	[11,
	[11,
	[11,
	[11,
	null]]]]]]]]],
	accept:13}];
	};
	/**
	 * @type {!Array<!{line: !Array, accept: !number}>}
	 * @private
     */
	DfaLex.prototype._dfaData = [];
	/**
	 * @type {number}
     */
	DfaLex.prototype.match_pos = 0;
	/**
	 * @type {?number}
     */
	DfaLex.prototype.state = 0;
	/**
	 * @type {?number}
     */
	DfaLex.prototype.match = null;
	/**
	 * @param {number} chr
	 * @param {number} pos
     */
	DfaLex.prototype.exec = function(chr, pos) {
		if (this.state !== null) {
		    if ((typeof this.state !== "number") || this.state >= this._dfaData.length) {
		        this.state = null;
		        throw new Error("Invalid value for DfaLex.state at chr " + chr + " and pos " + pos);
		    }
			var line = this._dfaData[this.state].line;
			if (typeof line === "undefined" || line === null) {
			    var badState = this.state;
			    this.state = null;
			    throw new Error("At chr " + chr + " and pos " + pos +
			                    ", DfaLex._dfaData[" + badState +
			                    "] appears to exist, but its line property is " +
			                    (typeof line === "undefined" ? "undefined." : "null."));
			}
			var p, st;
			for (p = 1 << 8, st = line; p; p >>= 1) {
				if ((chr & p) !== 0) {
					st = st[1];
				} else {
					st = st[0];
				}
				if (typeof st === "undefined") {
				    st = null;
				}
				if (st === null)break;
				if (Array.isArray(st))continue;
				break;
			}
			var ac = this._dfaData[this.state].accept;
			this.state = /** @type {?number} */ (st);
			if (ac !== -1) {
				this.match = /** @type{number} */ (ac);
				this.match_pos = pos;
			}
		}
	};

var pop_tab =[[0,1],[15,1],[14,3],[14,1],[16,2],[16,1],[17,2],[17,2],[17,2],[17,1],[18,1],[18,1],[18,3],[20,3],[20,1],[21,2],[21,0],[19,1],[19,1],[19,1]];

/** @type {!Array<!Array<number>>} */
var act_tab =[[6,8,11,9,12,10,13,11,8,12,10,13],[],[2,14],[6,8,11,9,12,10,13,11,8,12,10,13],[],[5,16,4,17,3,18],[],[],[6,8,11,9,12,10,13,11,8,12,10,13],[],[],[],[],[],[6,8,11,9,12,10,13,11,8,12,10,13],[],[],[],[],[7,22,2,14],[9,24,11,9,12,10,13,11],[6,8,11,9,12,10,13,11,8,12,10,13],[],[],[]];

var goto_tab =[[15,1,14,2,16,3,17,4,18,5,19,6,20,7],[],[],[17,15,18,5,19,6,20,7],[],[],[],[],[14,19,16,3,17,4,18,5,19,6,20,7],[],[],[],[21,20],[],[16,21,17,4,18,5,19,6,20,7],[],[],[],[],[],[19,23],[17,15,18,5,19,6,20,7],[],[],[]];

var defact_tab =[-1,0,1,3,5,9,10,11,-1,17,18,19,16,14,-1,4,8,7,6,-1,-1,2,12,15,13];

var labels = [{"label":"RegEx'","kind":{},"prods":[0],"nullable":0,"id":0,"code":"","level":0,"special":{},"defined":true,"first":[6,11,12,13,8,10]},{"label":"ERROR_RESYNC","kind":{},"prods":[],"nullable":false,"id":1,"code":"","level":0,"special":{},"defined":true,"first":[1]},{"label":"|","kind":{},"prods":[],"nullable":false,"id":2,"code":"","level":0,"special":{},"defined":false,"first":[2]},{"label":"*","kind":{},"prods":[],"nullable":false,"id":3,"code":"","level":0,"special":{},"defined":false,"first":[3]},{"label":"+","kind":{},"prods":[],"nullable":false,"id":4,"code":"","level":0,"special":{},"defined":false,"first":[4]},{"label":"?","kind":{},"prods":[],"nullable":false,"id":5,"code":"","level":0,"special":{},"defined":false,"first":[5]},{"label":"(","kind":{},"prods":[],"nullable":false,"id":6,"code":"","level":0,"special":{},"defined":false,"first":[6]},{"label":")","kind":{},"prods":[],"nullable":false,"id":7,"code":"","level":0,"special":{},"defined":false,"first":[7]},{"label":"[","kind":{},"prods":[],"nullable":false,"id":8,"code":"","level":0,"special":{},"defined":false,"first":[8]},{"label":"]","kind":{},"prods":[],"nullable":false,"id":9,"code":"","level":0,"special":{},"defined":false,"first":[9]},{"label":"ANY_CHAR","kind":{},"prods":[],"nullable":false,"id":10,"code":"","level":0,"special":{},"defined":false,"first":[10]},{"label":"ASCII_CODE","kind":{},"prods":[],"nullable":false,"id":11,"code":"","level":0,"special":{},"defined":false,"first":[11]},{"label":"ESCAPED_CHAR","kind":{},"prods":[],"nullable":false,"id":12,"code":"","level":0,"special":{},"defined":false,"first":[12]},{"label":"ANY","kind":{},"prods":[],"nullable":false,"id":13,"code":"","level":0,"special":{},"defined":false,"first":[13]},{"label":"Expression","kind":{},"prods":[2,3],"nullable":0,"id":14,"code":"","level":0,"special":{},"defined":true,"first":[6,11,12,13,8,10]},{"label":"RegEx","kind":{},"prods":[1],"nullable":0,"id":15,"code":"","level":0,"special":{},"defined":true,"first":[6,11,12,13,8,10]},{"label":"Catenation","kind":{},"prods":[4,5],"nullable":0,"id":16,"code":"","level":0,"special":{},"defined":true,"first":[6,11,12,13,8,10]},{"label":"Factor","kind":{},"prods":[6,7,8,9],"nullable":0,"id":17,"code":"","level":0,"special":{},"defined":true,"first":[6,11,12,13,8,10]},{"label":"Term","kind":{},"prods":[10,11,12],"nullable":0,"id":18,"code":"","level":0,"special":{},"defined":true,"first":[6,11,12,13,8,10]},{"label":"Character","kind":{},"prods":[17,18,19],"nullable":0,"id":19,"code":"","level":0,"special":{},"defined":true,"first":[11,12,13]},{"label":"CharacterSet","kind":{},"prods":[13,14],"nullable":0,"id":20,"code":"","level":0,"special":{},"defined":true,"first":[8,10]},{"label":"CharClass","kind":{},"prods":[15,16],"nullable":1,"id":21,"code":"","level":0,"special":{},"defined":true,"first":[11,12,13]},{"label":"$","kind":{},"prods":[],"nullable":false,"id":22,"code":"","level":0,"special":{},"defined":false,"first":[22]}];


	var ACTIONS = (function(){
		var PCB = {};
		var actions = [		function(){
var rval;rval =  arguments[0] ;
return rval;},
		function(){
var rval;	rval = new Param();
													global.nfa_states.value[ first_nfa ].follow =  arguments[0] .start;
													last_nfa =  arguments[0] .end;
												
return rval;},
		function(){
var rval;
													rval = new Param(global.nfa_states.create(), global.nfa_states.create());
													global.nfa_states.value[rval.start].follow =  arguments[2] .start;
													global.nfa_states.value[rval.start].follow2 =  arguments[0] .start;

													global.nfa_states.value[ arguments[2] .end].follow = rval.end;
													global.nfa_states.value[ arguments[0] .end].follow = rval.end;
												
return rval;},
		function(){
var rval;rval =  arguments[0] ;
return rval;},
		function(){
var rval;
													var weight=global.nfa_states.value[ arguments[1] .end].weight;///SV: if weight unused - delete this
													global.nfa_states.value[ arguments[1] .end]=new Nfa(global.nfa_states.value[ arguments[0] .start]);
													global.nfa_states.value[ arguments[1] .end].weight=weight;///SV: if weight unused - delete this
													global.nfa_states.value[ arguments[0] .start].edge = EDGE.FREE;

													 arguments[1] .end =  arguments[0] .end;

													rval =  arguments[1] ;
												
return rval;},
		function(){
var rval;rval =  arguments[0] ;
return rval;},
		function(){
var rval;
													rval = new Param(global.nfa_states.create(), global.nfa_states.create());
													global.nfa_states.value[rval.start].follow =  arguments[1] .start;
													global.nfa_states.value[ arguments[1] .end].follow = rval.end;

													global.nfa_states.value[rval.start].follow2 = rval.end;
													global.nfa_states.value[ arguments[1] .end].follow2 =  arguments[1] .start;
												
return rval;},
		function(){
var rval;
													rval = new Param(global.nfa_states.create(), global.nfa_states.create());
													global.nfa_states.value[rval.start].follow =  arguments[1] .start;
													global.nfa_states.value[ arguments[1] .end].follow = rval.end;

													global.nfa_states.value[ arguments[1] .end].follow2 =  arguments[1] .start;
												
return rval;},
		function(){
var rval;
													rval = new Param(global.nfa_states.create(), global.nfa_states.create());
													global.nfa_states.value[rval.start].follow =  arguments[1] .start;
													global.nfa_states.value[rval.start].follow2 = rval.end;
													global.nfa_states.value[ arguments[1] .end].follow = rval.end;
												
return rval;},
		function(){
var rval;rval =  arguments[0] ;
return rval;},
		function(){
var rval;	rval = new Param();
													rval.start = global.nfa_states.create();
													rval.end = global.nfa_states.value[rval.start].follow
														= global.nfa_states.create();
													global.nfa_states.value[rval.start].edge = EDGE.CHAR;

													global.nfa_states.value[rval.start].ccl.set( arguments[0] .charCodeAt( 0 ), true );
												
return rval;},
		function(){
var rval;rval =  arguments[0] ;
return rval;},
		function(){
var rval;	rval =  arguments[1] ; 
return rval;},
		function(){
var rval;	var negate = false;
													var i = 0, j, start;
													rval = new Param();
													rval.start = global.nfa_states.create();
													rval.end = global.nfa_states.value[rval.start].follow
														= global.nfa_states.create();
													global.nfa_states.value[rval.start].edge = EDGE.CHAR;

													if(  arguments[1] .charAt( i ) == '^' ){
														negate = true;
														for( j = global.MIN_CHAR; j < global.MAX_CHAR; j++ )
															global.nfa_states.value[rval.start].ccl.set(j,true);
														i++;
													}
													for( ; i <  arguments[1] .length; i++ ){
														if(  arguments[1] .charAt( i+1 ) == '-'	&& i+2 <  arguments[1] .length ){
															i++;
															for( j =  arguments[1] .charCodeAt( i-1 );
																	j <  arguments[1] .charCodeAt( i+1 );
																		j++ )
																global.nfa_states.value[rval.start].ccl.set(j, !negate);
														}
														else
															global.nfa_states.value[rval.start].ccl.set( arguments[1] .charCodeAt(i), !negate);
													}
												
return rval;},
		function(){
var rval;	rval = new Param();

													rval.start = global.nfa_states.create();
													rval.end = global.nfa_states.value[rval.start].follow
														= global.nfa_states.create();
													global.nfa_states.value[rval.start].edge = EDGE.CHAR;
													for( var i = global.MIN_CHAR; i < global.MAX_CHAR; i++ )
														global.nfa_states.value[rval.start].ccl.set(i, true);
												
return rval;},
		function(){
var rval;	rval =  arguments[1]  +  arguments[0] ; 
return rval;},
		function(){
var rval;	rval = ""; 
return rval;},
		function(){
var rval;	rval = String.fromCharCode(  arguments[0] .substr( 1 ) ); 
return rval;},
		function(){
var rval;	rval = {n:'\n',r:'\r',t:'\t',a:'\a'}[ arguments[0] .substr(1)]|| arguments[0] .substr(1); 
return rval;},
		function(){
var rval;	rval =  arguments[0] ; 
return rval;},
];
		return function (/** number */ act, /** Array<*> */ vstack, /** !PcbClass */ pcb){
			try{
				PCB = pcb;
				return actions[act].apply(null,vstack);
			}catch(e){
				if(e instanceof ReturnValue)return e.valueOf();
				throw e;
			}
		}
	})();

	/**
	 * @param {number} top
	 * @param {?number} la
	 * @returns {?number}
     */
	function get_act(top, la){	
		for(var i = 0; i < act_tab[top].length; i+=2)
			if(act_tab[top][i] === la)
				return act_tab[top][i+1];
		return null;
	}
	function get_goto(top, pop){	
		for(var i = 0; i < goto_tab[top].length; i+=2)
			if(goto_tab[top][i] === pop)
				return goto_tab[top][i+1];
		return null;
	}

	/**
	 * @param {!string} src
	 * @constructor
     */
	var PcbClass = function(src) {
		this.src = src;
	};
	/**
	 * @type {number}
     */
	PcbClass.prototype.line = 1;
	/**
	 * @type {number}
     */
	PcbClass.prototype.column = 1;
	/**
	 * @type {number}
     */
	PcbClass.prototype.offset = 0;
	/**
	 * @type {number}
     */
	PcbClass.prototype.error_step = 0;
	/**
	 * @type {string}
     */
	PcbClass.prototype.src = "";
	/**
	 * @type {string}
     */
	PcbClass.prototype.att = "";
	/**
	 * @type {?number}
     */
	PcbClass.prototype.la = null;
	/**
	 * @type {?number}
     */
	PcbClass.prototype.act = null;
	/**
	 * @returns {?number}
     */
	PcbClass.prototype.lex = function() {
        var /** number */ start, /** number */ pos, /** number */ chr, actionResult;
		var dfa = new DfaLex();
		var loop = true;
		while(loop){
			dfa.match_pos = 0;
			pos = this.offset + 1;
			do{
				pos--;
				dfa.state = 0;
				dfa.match = null;
				start = pos;
				if(this.src.length <= start) {
					this.la = eof;
					return eof;
				}
				do{
					chr = this.src.charCodeAt(pos);
					dfa.exec(chr,pos);
					if(dfa.state !== null)
						this.accountChar(chr);
					pos++;
				}while(dfa.state !== null);
			}while(whitespace > -1 && dfa.match === whitespace);
			if(dfa.match !== null){
				this.att = this.src.slice(start, dfa.match_pos);
				this.offset = dfa.match_pos;
				actionResult = TERMINAL_ACTIONS(this,dfa.match);
				if(dfa.state !== null)
					this.accountChar(chr);
				if(actionResult === Continue)
					continue;
				this.att = actionResult;
			}else {
				this.att = "";
			}
			loop = false;
		}
		this.la = dfa.match;
		return this.la;
	};
	/**
	 * @param {number} chr
     */
    PcbClass.prototype.accountChar = function(chr) {
		if( chr === 10 ){
			this.line++;
			this.column = 0;
		}
		this.column++;
	};
	function parse(/** string */ src, err_off, err_la){
		/**
		 * @type {!Array<number>}
         */
		var		sstack			= [0];
		/**
		 * @type {!Array<*>}
         */
		var		vstack			= [0];
		/**
		 * @type {number}
         */
		var 	err_cnt			= 0;
		/**
		 * @type {*}
		 */
		var		rval;
		/**
		 * @type {?number}
		 */
		var		act;
		/**
		 * @type {number}
		 */
		var i = 0;

		var PCB	= new PcbClass(src);
		err_off	= err_off || [];
		err_la = err_la || [];
		PCB.lex();
		while(true){
			PCB.act = get_act(sstack[0],PCB.la);
			if(PCB.act === null && defact_tab[sstack[0]] >= 0)
				PCB.act = -defact_tab[sstack[0]];
			if(PCB.act === null){//Parse error? Try to recover!
				//Report errors only when error_step is 0, and this is not a
				//subsequent error from a previous parse
				if(PCB.error_step === 0){
					err_cnt++;
					err_off.unshift(PCB.offset - PCB.att.length);
					err_la.unshift([]);
					for(i = 0; i < act_tab[sstack[0]].length; i+=2)
						err_la[0].push(labels[act_tab[sstack[0]][i]]);
				}
				//Perform error recovery			
				while(sstack.length > 1 && PCB.act === null){
					sstack.shift();
					vstack.shift();
					//Try to shift on error token
					PCB.act = get_act(sstack[0],PCB.la);
					if(PCB.act === error_token){
						sstack.unshift(PCB.act);
						vstack.unshift("");
					}
				}
				//Is it better to leave the parser now?
				if(sstack.length > 1 && PCB.act !== null){
					//Ok, now try to shift on the next tokens
					while(PCB.la !== eof){
						PCB.act = act_tab[sstack[0]][i+1];
						if(PCB.act != null)break;
						while(PCB.lex() != null)PCB.offset++;
					}
				}
				if(PCB.act === null || PCB.la === eof){
					break;
				}
				//Try to parse the next three tokens successfully...
				PCB.error_step = 3;
			}
			if(PCB.act > 0){//Shift
				//Parse tree generation
				sstack.unshift(PCB.act);
				vstack.unshift(PCB.att);
				PCB.lex();
				//Successfull shift and right beyond error recovery?
				if(PCB.error_step > 0)
					PCB.error_step--;
			}else{	//Reduce	
				act = -PCB.act;
				//vstack.unshift(vstack);
				rval = ACTIONS(act,vstack,PCB);
				//vstack.shift();
				sstack.splice(0,pop_tab[act][1]);
				vstack.splice(0,pop_tab[act][1]);
				
				PCB.act = get_goto(sstack[0],pop_tab[act][0]);
				//Do some parse tree construction if desired
				//Goal symbol match?
				if(act === 0) break; //Don't use PCB.act here!
			
				//...and push it!
				sstack.unshift(PCB.act);
				vstack.unshift(rval);
			}
		}
		return err_cnt;
	}
	return parse;
})(22,-1,1);


/**
 * Compiles the given regex into a nondeterministic finite automata.
 * @param {string} str - The regex to compile.
 * @param {number} accept - The id of the symbol accepted.
 * @param {boolean} case_insensitive - Whether the regex is case insensitive.
 * @param {number} cur_line - The current line number being parsed.  Used in error
 * logging.
 * @module {jscc.regex} jscc/regex
 * @requires module:jscc/global
 * @requires module:jscc/log/log
 */
function compile_regex( str, accept, case_insensitive, cur_line ){
	var i, j;
	var weight = 0;
	var true_edges = 0;
	var error_offsets = [];
	var error_expects = [];
	var error_count = 0;

	if( str == "" )
		return;

	cur_line = cur_line || 0;

	//_print( "str = >" + str + "< " + case_insensitive );

	first_nfa = global.nfa_states.create();
	if( ( error_count = __parse( str, error_offsets, error_expects ) ) == 0 ){
		//If the symbol should be case-insensitive, manipulate the
		//character sets on the newly created items.
		if( case_insensitive ){
			for( i = 0; i < global.nfa_states.value.length; i++ ){
				if( global.nfa_states.value[i].edge == EDGE.CHAR ){
					for( j = global.MIN_CHAR; j < global.MAX_CHAR; j++ ){
						if( global.nfa_states.value[i].ccl.get( j ) ){
							global.nfa_states.value[i].ccl.set(String.fromCharCode( j ).toUpperCase().charCodeAt( 0 ), true );
							global.nfa_states.value[i].ccl.set(String.fromCharCode( j ).toLowerCase().charCodeAt( 0 ), true );
						}
					}
				}
			}
		}

		/*
			2008-5-9	Radim Cebis:

			I think that computing weight of the nfa_states.value is weird,
			IMHO nfa_state which accepts a symbol, should have
			weight according to the order...
		*/
		global.nfa_states.value[ last_nfa ].accept = accept;
		global.nfa_states.value[ last_nfa ].weight = global.regex_weight++;

		if( first_nfa > 0 ){
			i = 0;
			while( global.nfa_states.value[i].follow2 != -1 )
				i = global.nfa_states.value[i].follow2;

			global.nfa_states.value[i].follow2 = first_nfa;
		}
	}else{
		for( i = 0; i < error_count; i++ ){
			var spaces = '';
			for( j = 0; j < error_offsets[i]; j++ )
				spaces += " ";

			log.error( "Regular expression:\n\t" + str + "\n\t" +
			 		spaces + "^ expecting " + error_expects[i].join() + " on line " + cur_line );
		}
	}
}
return compile_regex;


//TESTING AREA ;)
//compile_regex( "[A-Z][A-Z0-9]*", 0 );
//compile_regex( "ab|c", 1 );
//compile_regex( "[0-9]+", 1 );
//print_nfa();
//var d = create_subset( nfa_states.value );
//print_dfa( d );
//d = minimize_dfa( d );
//print_dfa( d );
}));