123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- /*
- 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;
|