All files / src/core/nfa compile.ts

98.28% Statements 57/58
87.5% Branches 7/8
100% Functions 15/15
98.28% Lines 57/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 109  15x 15x 15x 15x 15x 1530x 1530x 1530x 1530x 59887x 59887x 51896x 51896x 51896x 58357x   51896x     1530x   15x   17230x   17230x     17230x 858x     16372x   17230x 17230x   15x 60x 4545x 4545x     15x 30x 5156x 11155x 11155x 11155x   5156x     15x       60x   15x   30x   15x 7529x     1530x                 1530x 1530x 1530x 1530x 1530x   1530x 51896x 1530x   51896x 51896x 58357x   51896x   1530x               15x              
import Clause from "../../models/Clause";
import deref from "../../utils/deref";
import fragment from "./fragment";
 
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: any = {};
 
function evalClause( clause ) {
  clause = deref( clause );
  vaIr 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 ],
    conformFn: null,
    generateFn: null,
    opts: {}
  } );
}
 
export default function compile( 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,
  };
};