All files / src/core/nfa compile.js

0% Statements 0/58
0% Branches 0/8
0% Functions 0/15
0% Lines 0/58
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108                                                                                                                                                                                                                       
var fragment = require( './fragment.js' );
var Clause = require( '../../models/Clause' );
var deref = require( '../../utils/deref' );
 
var indexedFragmentStates = function( fragment ) {
  var nextIndex = 0;
  var frontier = [ fragment.head ];
  var states = [];
  while ( frontier.length > 0 ) {
    var state = frontier.pop();
    if ( state.index === null ) {
      state.index = nextIndex;
      nextIndex++;
      state.transitions.forEach( ( transition ) => {
        frontier.push( transition.target );
      } );
      states.push( state );
    }
  }
  return states;
};
 
var evalFunctions = {};
 
function evalClause( clause ) {
  clause = deref( clause );
  var evalFn;
 
  if ( clause.type === null ) {
    throw 'Clause has no type: ' + clause;
  } else if ( !( clause.type in evalFunctions ) ) {
    evalFn = evalFunctions.PRED;
  } else {
    evalFn = evalFunctions[ clause.type ];
  }
  var r = evalFn( clause );
  return r;
}
 
var evalChildThen = function( wrapper ) {
  return function evalChildThenWrapped( clause ) {
    var childFrag = evalClause( clause.exprs[ 0 ] );
    return wrapper( childFrag );
  };
};
 
var evalChildrenThen = function( wrapper ) {
  return function evalChildrenThenWrapped( clause ) {
    var childFrags = clause.exprs.map( ( child ) => {
      var s = evalClause( child.expr );
      s.name = child.name;
      return s;
    } );
    return wrapper( childFrags );
  };
};
 
[ 'ROOT',
  'Z_OR_M',
  'O_OR_M',
  'Z_OR_O' ].forEach( ( fragName ) => {
    evalFunctions[ fragName ] = evalChildThen( fragment[ fragName ] );
  } );
 
[ 'OR',
  'CAT' ].forEach( ( fragName ) => {
    evalFunctions[ fragName ] = evalChildrenThen( fragment[ fragName ] );
  } );
 
evalFunctions.PRED = ( x ) => {
  return fragment[ 'PRED' ]( x );
};
 
function wrapRoot( expr ) {
  return new Clause( {
    type: 'ROOT',
    exprs: [ expr ],
  } );
}
 
var compile = function( expr ) {
  var rootedExpr = wrapRoot( expr );
  var fragment = evalClause( rootedExpr );
  var states = indexedFragmentStates( fragment );
  var numStates = states.length;
  var nfaTransitions = {};
  var finalState;
  states.forEach( ( state ) => {
    if ( state.transitions.length === 0 ) {
      finalState = state.index;
    }
    var outTrans = {};
    state.transitions.forEach( ( fragTrans ) => {
      outTrans[ fragTrans.target.index ] = fragTrans.clause;
    } );
    nfaTransitions[ state.index.toString() ] = outTrans;
  } );
  return {
    initialState: 0,
    numStates: numStates,
    finalState: finalState,
    transitions: nfaTransitions,
    expression: expr,
  };
};
 
module.exports = compile;