| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/function ignoreFunction() {}function createReturningFunction(value) {	return function() {		return value;	};}function Parser(states) {	this.states = this.compileStates(states);}Parser.prototype.compileStates = function(states) {	var result = {};	Object.keys(states).forEach(function(name) {		result[name] = this.compileState(states[name], states);	}, this);	return result;};Parser.prototype.compileState = function(state, states) {	var regExps = [];	function iterator(str, value) {		regExps.push({			groups: Parser.getGroupCount(str),			regExp: str,			value: value		});	}	function processState(statePart) {		if(Array.isArray(statePart)) {			statePart.forEach(processState);		} else if(typeof statePart === "object") {			Object.keys(statePart).forEach(function(key) {				iterator(key, statePart[key]);			});		} else if(typeof statePart === "string") {			processState(states[statePart]);		} else {			throw new Error("Unexpected 'state' format");		}	}	processState(state);	var total = regExps.map(function(r) {		return "(" + r.regExp + ")";	}).join("|");	var actions = [];	var pos = 1;	regExps.forEach(function(r) {		var fn;		if(typeof r.value === "function") {			fn = r.value;		} else if(typeof r.value === "string") {			fn = createReturningFunction(r.value);		} else {			fn = ignoreFunction;		}		actions.push({			name: r.regExp,			fn: fn,			pos: pos,			pos2: pos + r.groups + 1		});		pos += r.groups + 1;	});	return {		regExp: new RegExp(total, "g"),		actions: actions	};};Parser.getGroupCount = function(regExpStr) {	return new RegExp("(" + regExpStr + ")|^$").exec("").length - 2;};Parser.prototype.parse = function(initialState, string, context) {	context = context || {};	var currentState = initialState;	var currentIndex = 0;	for(;;) {		var state = this.states[currentState];		var regExp = state.regExp;		regExp.lastIndex = currentIndex;		var match = regExp.exec(string);		if(!match) return context;		var actions = state.actions;		currentIndex = state.regExp.lastIndex;		for(var i = 0; i < actions.length; i++) {			var action = actions[i];			if(match[action.pos]) {				var ret = action.fn.apply(context, Array.prototype.slice.call(match, action.pos, action.pos2).concat([state.regExp.lastIndex - match[0].length, match[0].length]));				if(ret) {					if(!(ret in this.states))						throw new Error("State '" + ret + "' doesn't exist");					currentState = ret;				}				break;			}		}	}};module.exports = Parser;
 |