Advertisement
honey_the_codewitch

visualfa.ts

Nov 1st, 2024 (edited)
720
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 252.58 KB | Source Code | 0 0
  1. "IsLetter", FACharacterClasses.isLetter);
  2.             result.set("IsDigit", FACharacterClasses.isDigit);
  3.             result.set("IsLetterOrDigit", FACharacterClasses.isLetterOrDigit);
  4.             result.set("IsWhiteSpace", FACharacterClasses.isWhiteSpace);
  5.             result.set("alnum", FACharacterClasses.alnum);
  6.             result.set("alpha", FACharacterClasses.alpha);
  7.             result.set("cntrl", FACharacterClasses.cntrl);
  8.             result.set("digit", FACharacterClasses.digit);
  9.             result.set("graph", FACharacterClasses.graph);
  10.             result.set("ascii", FACharacterClasses.ascii);
  11.             result.set("blank", FACharacterClasses.blank);
  12.             result.set("lower", FACharacterClasses.lower);
  13.             result.set("print", FACharacterClasses.print);
  14.             result.set("punct", FACharacterClasses.punct);
  15.             result.set("space", FACharacterClasses.space);
  16.             result.set("upper", FACharacterClasses.upper);
  17.             result.set("word", FACharacterClasses.word);
  18.             result.set("xdigit", FACharacterClasses.xdigit);
  19.             FACharacterClasses._known = result;
  20.         }
  21.         return FACharacterClasses._known;
  22.     }
  23. };
  24. export class FAMatch {
  25.     public symbolId: number;
  26.     public value: string;
  27.     public position: number;
  28.     public line: number;
  29.     public column: number;
  30.     constructor(symbolId:number=-1,value:string=null,position:number=0,line:number=1,column:number=1) {
  31.         this.symbolId = symbolId;
  32.         this.value = value;
  33.         this.position = position;
  34.         this.line = line;
  35.         this.column = column;
  36.     }
  37.     public toString() {
  38.         let sb: string = "";
  39.         sb+="[SymbolId: ";
  40.         sb+=this.symbolId;
  41.         sb+=", Value: ";
  42.         if (this.value !== null && this.value!==undefined)
  43.         {
  44.             sb+="\"";
  45.             sb+=this.value.replace("\r", "\\r").replace("\t", "\\t").replace("\n", "\\n").replace("\v", "\\v");
  46.             sb+="\", Position: ";
  47.         }
  48.         else
  49.         {
  50.             sb+="null, Position: ";
  51.         }
  52.         sb+=this.position;
  53.         sb+=" (";
  54.         sb+=this.line;
  55.         sb+=", ";
  56.         sb+=this.column;
  57.         sb+=")]";
  58.         return sb;
  59.     }
  60. };
  61. export abstract class FARunner implements Iterable<FAMatch> {
  62.     protected tabWidth: number = 4;
  63.     protected position: number = -1;
  64.     protected line: number = 1;
  65.     protected column: number = 1;
  66.     public abstract nextMatch() : FAMatch;
  67.     public abstract reset() : void;
  68.     public *[Symbol.iterator](): IterableIterator<FAMatch> {
  69.         let match: FAMatch = new FAMatch();
  70.         match=this.nextMatch();
  71.         while (match.symbolId!==-2) {
  72.             yield match;
  73.             match = this.nextMatch();
  74.         }
  75.     }
  76. };
  77. export abstract class FAStringRunner extends FARunner {
  78.     protected input_string: string;
  79.     public set(str: string): void {
  80.         this.input_string = str;
  81.         this.position = -1;
  82.         this.line = 1;
  83.         this.column = 1;
  84.     }
  85.     public override reset() : void {
  86.         this.position = -1;
  87.         this.line = 1;
  88.         this.column = 1;
  89.     }
  90.     protected advance(s: string, cp: number, len: number, first: boolean) : [number, number] {
  91.         if(!first) {
  92.             switch(String.fromCodePoint(cp)) {
  93.                 case '\n':
  94.                     ++this.line;
  95.                     this.column = 1;
  96.                     break;
  97.                 case '\r':
  98.                     this.column = 1;
  99.                     break;
  100.                 case '\t':
  101.                     this.column = ((this.column-1)/this.tabWidth)*(this.tabWidth+1);
  102.                     break;
  103.                 default:
  104.                     if(cp>31) {
  105.                         ++this.column;
  106.                     }
  107.                     break;
  108.             }
  109.             ++len;
  110.             if(cp>65535) {
  111.                 ++this.position;
  112.                 ++len;
  113.             }
  114.             ++this.position;
  115.         }
  116.         if(this.position<s.length) {
  117.             cp = s.codePointAt(this.position)
  118.         } else {
  119.             cp = -1;
  120.         }
  121.        
  122.         return [cp, len];
  123.     }
  124. };
  125. export class FAStringStateRunner extends FAStringRunner
  126. {
  127.     readonly _fa: FA;
  128.     readonly _blockEnds: FA[];
  129.     readonly _states: FA[];
  130.     readonly _nexts: FA[];
  131.     readonly _initial: FA[];
  132.     constructor(fa: FA, blockEnds: FA[] = null)
  133.     {
  134.         super();
  135.         if (null === fa || undefined===fa)
  136.         {
  137.             throw "fa was not valid";
  138.         }
  139.         this._fa = fa;
  140.         this._blockEnds = blockEnds;
  141.         this._states = new Array<FA>();
  142.         this._nexts = new Array<FA>();
  143.         this._initial = new Array<FA>();
  144.     }
  145.     public override nextMatch() : FAMatch
  146.     {
  147.         return this._nextImpl(this.input_string);
  148.     }
  149.     private _nextImpl(
  150.         s: string
  151.         ): FAMatch
  152.     {
  153.         let dfaState: FA = null, dfaNext: FA = null, dfaInitial: FA = null;
  154.         if (this.position == -1)
  155.         {
  156.             // first read
  157.             ++this.position;
  158.         }
  159.         let len:number = 0;
  160.         let cursor_pos: number = this.position;
  161.         let line: number = this.line;
  162.         let column: number = this.column;
  163.         let ch: number = -1;
  164.         let advr= this.advance(s, ch, len, true);ch = advr[0];len = advr[1];
  165.         if (this._fa.isDeterministic)
  166.         {
  167.             dfaState = this._fa;
  168.             dfaInitial = this._fa;
  169.         }
  170.         else
  171.         {
  172.             this._initial.length = 0;
  173.             if (this._fa.isCompact)
  174.             {
  175.                 this._initial.push(this._fa);
  176.             }
  177.             else
  178.             {
  179.                 this._fa.fillEpsilonClosure(this._initial);
  180.             }
  181.             this._states.length = 0;
  182.             this._states.push(...this._initial);
  183.         }
  184.         while (true)
  185.         {
  186.             if (dfaState != null)
  187.             {
  188.                 dfaNext = dfaState.move(ch);
  189.             }
  190.             else
  191.             {
  192.                 dfaNext = null;
  193.                 this._nexts.length = 0;
  194.                 FA.fillMove(this._states, ch, this._nexts);
  195.             }
  196.             if (dfaNext != null)
  197.             {
  198.                 advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  199.                 if (dfaNext.isDeterministic)
  200.                 {
  201.                     dfaState = dfaNext;
  202.                 }
  203.                 else
  204.                 {
  205.                     this._states.length = 0;
  206.                     if (dfaNext.isCompact)
  207.                     {
  208.                         this._states.push(dfaNext);
  209.                     }
  210.                     else
  211.                     {
  212.                         dfaNext.fillEpsilonClosure(this._states);
  213.                     }
  214.                     dfaState = null;
  215.                 }
  216.                 dfaNext = null;
  217.             }
  218.             else if (this._nexts.length > 0)
  219.             {
  220.                 advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  221.                 if (this._nexts.length === 1)
  222.                 {
  223.                     var ffa = this._nexts[0];
  224.                     // switch to deterministic mode if needed
  225.                     if (ffa.isDeterministic)
  226.                     {
  227.                         dfaState = ffa;
  228.                     }
  229.                     else
  230.                     {
  231.                         dfaNext = null;
  232.                         this._states.length = 0;
  233.                         if (!ffa.isCompact)
  234.                         {
  235.                             ffa.fillEpsilonClosure(this._states);
  236.                         }
  237.                         else
  238.                         {
  239.                             this._states.push(ffa);
  240.                         }
  241.                         dfaState = null;
  242.                     }
  243.                 }
  244.                 else
  245.                 {
  246.                     this._states.length = 0;
  247.                     FA.fillEpsilonClosureStates(this._nexts, this._states);
  248.                 }
  249.                 this._nexts.length = 0;
  250.             }
  251.             else
  252.             {
  253.                 let acc: number;
  254.                 if (dfaState !== null)
  255.                 {
  256.                     acc = dfaState.acceptSymbol;
  257.                 }
  258.                 else
  259.                 {
  260.                     acc = FA.getFirstAcceptSymbol(this._states);
  261.                 }
  262.                 if (acc > -1)
  263.                 {
  264.                     if (this._blockEnds != null && this._blockEnds.length > acc && this._blockEnds[acc] !== null)
  265.                     {
  266.                         var be = this._blockEnds[acc];
  267.                         if (be.isDeterministic)
  268.                         {
  269.                             dfaState = be;
  270.                             dfaInitial = be;
  271.                             this._states.length = 0;
  272.                         }
  273.                         else
  274.                         {
  275.                             dfaState = null;
  276.                             dfaInitial = null;
  277.                             this._initial.length = 0;
  278.                             if (be.isCompact)
  279.                             {
  280.                                 this._initial.push(be);
  281.                             }
  282.                             else
  283.                             {
  284.                                 be.fillEpsilonClosure(this._initial);
  285.                             }
  286.                             this._states.length=0;
  287.                             this._states.push(...this._initial);
  288.                         }
  289.                         while (true)
  290.                         {
  291.                             if (dfaState !== null)
  292.                             {
  293.                                 dfaNext = dfaState.move(ch);
  294.                             }
  295.                             else
  296.                             {
  297.                                 dfaNext = null;
  298.                                 this._nexts.length = 0;
  299.                                 FA.fillMove(this._states, ch, this._nexts);
  300.                             }
  301.                             if (dfaNext !== null)
  302.                             {
  303.                                 advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  304.                                 if (dfaNext.isDeterministic)
  305.                                 {
  306.                                     dfaState = dfaNext;
  307.                                 }
  308.                                 else
  309.                                 {
  310.                                     this._states.length = 0;
  311.                                     if (dfaNext.isCompact)
  312.                                     {
  313.                                         this._states.push(dfaNext);
  314.                                     }
  315.                                     else
  316.                                     {
  317.                                         dfaNext.fillEpsilonClosure(this._states);
  318.                                     }
  319.                                     dfaState = null;
  320.                                 }
  321.                                 dfaNext = null;
  322.  
  323.                             }
  324.                             else if (this._nexts.length > 0)
  325.                             {
  326.                                 advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  327.                                 if (this._nexts.length == 1)
  328.                                 {
  329.                                     const ffa: FA = this._nexts[0];
  330.                                     // switch to deterministic mode if needed
  331.                                     if (ffa.isDeterministic)
  332.                                     {
  333.                                         dfaState = ffa;
  334.                                         this._states.length = 0;
  335.                                     }
  336.                                     else
  337.                                     {
  338.                                         dfaNext = null;
  339.                                         this._states.length = 0;
  340.                                         if (!ffa.isCompact)
  341.                                         {
  342.                                             ffa.fillEpsilonClosure(this._states);
  343.                                         }
  344.                                         else
  345.                                         {
  346.                                             this._states.push(ffa);
  347.                                         }
  348.                                         dfaState = null;
  349.                                     }
  350.                                 }
  351.                                 else
  352.                                 {
  353.                                     this._states.length = 0;
  354.                                     FA.fillEpsilonClosureStates(this._nexts, this._states);
  355.                                 }
  356.                                 this._nexts.length=0;
  357.                             }
  358.                             else
  359.                             {
  360.                                 if (dfaState !== null)
  361.                                 {
  362.                                     if (dfaState.isAccepting())
  363.                                     {
  364.                                         return new FAMatch(acc,
  365.                         s.substring(cursor_pos, cursor_pos+len)
  366.                                             , cursor_pos, line, column);
  367.                                     }
  368.                                 }
  369.                                 else
  370.                                 {
  371.                                     if (-1 < FA.getFirstAcceptSymbol(this._states))
  372.                                     {
  373.                                         return new FAMatch(acc,
  374.                         s.substring(cursor_pos,cursor_pos+ len)
  375.                                             , cursor_pos, line, column);
  376.                                     }
  377.                                 }
  378.                                 advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  379.                                 if (dfaInitial !== null)
  380.                                 {
  381.                                     this._states.length = 0;
  382.                                     dfaState = dfaInitial;
  383.                                 }
  384.                                 else
  385.                                 {
  386.                                     dfaState = null;
  387.                                     this._states.length = 0;
  388.                                     this._states.push(...this._initial);
  389.                                 }
  390.                                 if (ch == -1)
  391.                                 {
  392.                                     return new FAMatch(-1,
  393.                         s.substring(cursor_pos, cursor_pos+len)
  394.                                         , cursor_pos, line, column);
  395.                                 }
  396.                             }
  397.                         }
  398.                     }
  399.                     else
  400.                     {
  401.                         return new FAMatch(acc,
  402.                         s.substring(cursor_pos, cursor_pos+len)
  403.                             , cursor_pos, line, column);
  404.                     }
  405.                 }
  406.                 else
  407.                 {
  408.                     if (dfaInitial !== null)
  409.                     {
  410.                         while (ch != -1 && dfaInitial.move(ch) === null)
  411.                         {
  412.                             advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  413.                         }
  414.                     }
  415.                     else
  416.                     {
  417.                         this._states.length = 0;
  418.                         while (ch != -1 && FA.fillMove(this._initial, ch, this._states).length === 0)
  419.                         {
  420.                             advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  421.                         }
  422.                     }
  423.                     if (len == 0)
  424.                     {
  425.                         return new FAMatch(-2, null, 0, 0, 0);
  426.                     }
  427.                     return new FAMatch(-1,
  428.                         s.substring(cursor_pos, cursor_pos+len)
  429.                         , cursor_pos, line, column);
  430.                 }
  431.             }
  432.         }
  433.     }
  434. }
  435. export class FAStringDfaTableRunner extends FAStringRunner {
  436.     private readonly _dfa : number[];
  437.     private readonly _blockEnds: number[][];
  438.     constructor(dfa: number[],blockEnds:number[][] = null) {
  439.         super();
  440.         this._dfa = dfa;
  441.         this._blockEnds = blockEnds;
  442.     }
  443.     public nextMatch(): FAMatch {
  444.         return this._nextImpl(this.input_string);
  445.     }
  446.     private _nextImpl(s: string) : FAMatch {
  447.         let tlen: number;
  448.         let tto: number;
  449.         let prlen: number;
  450.         let pmin: number;
  451.         let pmax: number;
  452.         let i: number;
  453.         let j: number;
  454.         let state: number = 0;
  455.         let acc: number;
  456.         if (this.position === -1)
  457.         {
  458.             // first read
  459.             ++this.position;
  460.         }
  461.         let len: number = 0;
  462.         let cursor_pos: number = this.position;
  463.         let line: number = this.line;
  464.         let column: number = this.column;
  465.         let ch: number = -1;
  466.         let cont: boolean = false;
  467.         let advr= this.advance(s, ch, len, true);ch = advr[0];len = advr[1];
  468.         while(true) {
  469.             // accept symbol
  470.             acc = this._dfa[state];
  471.             ++state;
  472.             // transitions count
  473.             tlen = this._dfa[state];
  474.             ++state;
  475.             for (let i: number = 0; i < tlen; ++i)
  476.             {
  477.                 // destination state
  478.                 tto = this._dfa[state];
  479.                 ++state;
  480.                 // number of ranges to check
  481.                 prlen = this._dfa[state];
  482.                 ++state;
  483.                 for (let j:number = 0; j < prlen; ++j)
  484.                 {
  485.                     pmin = this._dfa[state];
  486.                     ++state;
  487.                     pmax = this._dfa[state];
  488.                     ++state;
  489.                     if (ch < pmin)
  490.                     {
  491.                         // early out
  492.                         state += ((prlen - (j + 1)) * 2);
  493.                         j = prlen;
  494.                     }
  495.                     else if (ch <= pmax)
  496.                     {
  497.                         advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  498.                         state = tto;
  499.                         cont = true;
  500.                         i=tlen;
  501.                         break;
  502.                     }
  503.                 }
  504.             }
  505.             if(cont===true) {
  506.                 cont = false;
  507.                 continue;
  508.             }
  509.             break;
  510.         }
  511.         if (acc !== -1)
  512.         {
  513.             const sym: number = acc;
  514.             const be: number[] = (this._blockEnds !== null && this._blockEnds.length > acc) ? this._blockEnds[acc] : null;
  515.             if (be !== null)
  516.             {
  517.                 state = 0;
  518.                 while(true) {
  519.                     acc = be[state];
  520.                     ++state;
  521.                     tlen = be[state];
  522.                     ++state;
  523.                     for (let i: number = 0; i < tlen; ++i)
  524.                     {
  525.                         tto = be[state];
  526.                         ++state;
  527.                         prlen = be[state];
  528.                         ++state;
  529.                         for (let j: number = 0; j < prlen; ++j)
  530.                         {
  531.                             pmin = be[state];
  532.                             ++state;
  533.                             pmax = be[state];
  534.                             ++state;
  535.                             if (ch < pmin)
  536.                             {
  537.                                 state += ((prlen - (j + 1)) * 2);
  538.                                 j = prlen;
  539.                             }
  540.                             else if (ch <= pmax)
  541.                             {
  542.                                 advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  543.                                 state = tto;
  544.                                 i=tlen;
  545.                                 break;
  546.                             }
  547.                         }
  548.                     }
  549.                
  550.                     if (acc !== -1)
  551.                     {
  552.                         return new FAMatch(sym,
  553.                             s.substring(cursor_pos,cursor_pos+len)
  554.                             , cursor_pos, line, column);
  555.                     }
  556.                     if (ch === -1)
  557.                     {
  558.                         return new FAMatch(-1,
  559.                             s.substring(cursor_pos, cursor_pos+len)
  560.                             , cursor_pos, line, column);
  561.                     }
  562.                     advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  563.                     state = 0;
  564.                     // restart the state machine
  565.                 }
  566.             }
  567.             return new FAMatch(acc,
  568.                         s.substring(cursor_pos, cursor_pos+len)
  569.                 , cursor_pos, line, column);
  570.         }
  571.         // error. keep trying until we find a potential transition.
  572.         while (ch !== -1)
  573.         {
  574.             var moved = false;
  575.             state = 1;
  576.             tlen = this._dfa[state];
  577.             ++state;
  578.             for (let i: number = 0; i < tlen; ++i)
  579.             {
  580.                 ++state;
  581.                 prlen = this._dfa[state];
  582.                 ++state;
  583.                 for (let j: number = 0; j < prlen; ++j)
  584.                 {
  585.                     pmin = this._dfa[state];
  586.                     ++state;
  587.                     pmax = this._dfa[state];
  588.                     ++state;
  589.                     if (ch < pmin)
  590.                     {
  591.                         state += ((prlen - (j + 1)) * 2);
  592.                         j = prlen;
  593.                     }
  594.                     else if (ch <= pmax)
  595.                     {
  596.                         moved = true;
  597.                     }
  598.                 }
  599.             }
  600.             if (moved)
  601.             {
  602.                 break;
  603.             }
  604.             advr= this.advance(s, ch, len, false);ch = advr[0];len = advr[1];
  605.         }
  606.         if (len === 0)
  607.         {
  608.             return new FAMatch(-2, null, 0, 0, 0);
  609.         }
  610.         return new FAMatch(-1,
  611.                         s.substring(cursor_pos, cursor_pos+len)
  612.             , cursor_pos, line, column);
  613.     }
  614. };
  615. class _ParseContext {
  616.     public input: string;
  617.     public codepoint: number = -2;
  618.     public position: number = 0;
  619.     public line: number = 1;
  620.     public column: number = 0;
  621.     public tabWidth: number = 4;
  622.     public capture_buffer: string = "";
  623.     public constructor(input: string, tabWidth: number = 4, position: number = 0, line: number = 1, column: number = 0) {
  624.         this.input = input;
  625.         this.tabWidth = tabWidth;
  626.         this.position = position;
  627.         this.line = line;
  628.         this.column = column;
  629.     }
  630.    
  631.     public advance(): number {
  632.         if (this.position>= this.input.length) {
  633.             this.codepoint = -1;
  634.         } else {
  635.             this.codepoint = this.input.codePointAt(this.position);
  636.         }
  637.         switch (this.codepoint) {
  638.             case 10:
  639.                 ++this.line;
  640.                 this.column = 0;
  641.                 break;
  642.             case 13:
  643.                 this.column = 0;
  644.                 break;
  645.             case 9:
  646.                 this.column = (((this.column - 1) / this.tabWidth) + 1) * this.tabWidth + 1;
  647.                 break;
  648.             default:
  649.                 if (this.codepoint > 31)
  650.                     ++this.column;
  651.                 break;
  652.         }
  653.         ++this.position;
  654.         return this.codepoint;
  655.     }
  656.     public capture() : void {
  657.         this.capture_buffer+=String.fromCodePoint(this.codepoint);
  658.     }
  659.     public ensureStarted() : void {
  660.         if(this.codepoint==-2) {
  661.             this.advance();
  662.         }
  663.     }
  664.     private static _getCodepoints(values: string[]): number[] {
  665.         const result: number[] = new Array<number>(values.length);
  666.         for (let i: number = 0; i < values.length; ++i) {
  667.             result[i] = values[i].codePointAt(0);
  668.         }
  669.         return result;
  670.     }
  671.     private _getErrorMessage(expecting: number[]): string {
  672.         let sb: string = null;
  673.         switch (expecting.length) {
  674.             case 0:
  675.                 break;
  676.             case 1:
  677.                 sb = "";
  678.                 if (-1 == expecting[0])
  679.                     sb += "end of input";
  680.                 else {
  681.                     sb += "\"";
  682.                     sb += String.fromCodePoint(expecting[0]);
  683.                     sb += "\"";
  684.                 }
  685.                 break;
  686.             case 2:
  687.                 sb = "";
  688.                 if (-1 == expecting[0])
  689.                     sb += "end of input";
  690.                 else {
  691.                     sb += "\"";
  692.                     sb += String.fromCodePoint(expecting[0]);
  693.                     sb += "\"";
  694.                 }
  695.                 sb += " or ";
  696.                 if (-1 == expecting[1])
  697.                     sb += "end of input";
  698.                 else {
  699.                     sb += "\"";
  700.                     sb += String.fromCodePoint(expecting[1]);
  701.                     sb += "\"";
  702.                 }
  703.                 break;
  704.             default: // length > 2
  705.                 sb = ""
  706.                 if (-1 == expecting[0])
  707.                     sb += "end of input";
  708.                 else {
  709.                     sb += "\"";
  710.                     sb += String.fromCodePoint(expecting[0]);
  711.                     sb += "\"";
  712.                 }
  713.                 const l: number = expecting.length - 1;
  714.                 let i: number = 1;
  715.                 for (; i < l; ++i) {
  716.                     sb += ", ";
  717.                     if (-1 == expecting[i])
  718.                         sb += "end of input";
  719.                     else {
  720.                         sb += "\"";
  721.                         sb += String.fromCodePoint(expecting[1]);
  722.                         sb += "\"";
  723.                     }
  724.                 }
  725.                 sb += ", or ";
  726.                 if (-1 == expecting[i])
  727.                     sb += "end of input";
  728.                 else {
  729.                     sb += "\"";
  730.                     sb += String.fromCodePoint(expecting[i]);
  731.                     sb += "\"";
  732.                 }
  733.                 break;
  734.         }
  735.         if (-1 == this.codepoint) {
  736.             if (0 == expecting.length)
  737.                 return "Unexpected end of input";
  738.             return "Unexpected end of input. Expecting " + sb;
  739.         }
  740.         if (0 == expecting.length)
  741.             return "Unexpected character \"" + String.fromCodePoint(this.codepoint) + "\" in input";
  742.         return "Unexpected character \"" + String.fromCodePoint(this.codepoint) + "\" in input. Expecting " + sb;
  743.     }
  744.     public expecting(...values: string[]) {
  745.         const codepoints: number[] = _ParseContext._getCodepoints(values);
  746.         if (this.codepoint === -2)
  747.             throw "The cursor is before the beginning of the input at " + this.position;
  748.         switch (codepoints.length) {
  749.             case 0:
  750.                 if (this.codepoint === -1)
  751.                     throw "Unexpected end of input at " + this.position;
  752.                 break;
  753.             case 1:
  754.                 if (codepoints[0] != this.codepoint)
  755.                     throw this._getErrorMessage(codepoints) + " at " + this.position;
  756.                 break;
  757.             default:
  758.                 if (!codepoints.includes(this.codepoint))
  759.                     throw this._getErrorMessage(codepoints) + " at " + this.position;
  760.                 break;
  761.         }
  762.     }
  763.     public trySkipWhiteSpace(): boolean
  764.     {
  765.         this.ensureStarted();
  766.         if (this.codepoint==-1) {
  767.             return false;
  768.         }
  769.         if(!FACharacterClasses.space.includes(this.codepoint)) {
  770.             return false;
  771.         }
  772.         this.advance();
  773.         while (this.codepoint!=-1 && FACharacterClasses.space.includes(this.codepoint)) {
  774.             this.advance();
  775.         }
  776.         return true;
  777.     }
  778.     public tryReadDigits(): boolean
  779.     {
  780.         this.ensureStarted();
  781.         if (this.codepoint==-1) {
  782.             return false;
  783.         }
  784.         if(!FACharacterClasses.digit.includes(this.codepoint)) {
  785.             return false;
  786.         }
  787.         this.capture();
  788.         this.advance();
  789.         while (this.codepoint!=-1 && FACharacterClasses.digit.includes(this.codepoint))
  790.         {
  791.             this.capture();
  792.             this.advance();
  793.         }
  794.         return true;
  795.     }
  796.     public tryReadUntil(character: number, readCharacter: boolean = true) : boolean
  797.     {
  798.         this.ensureStarted();
  799.         if (0 > character) character = -1;
  800.         this.capture();
  801.         if (this.codepoint === character)
  802.         {
  803.             return true;
  804.         }
  805.         while (-1 != this.advance() && this.codepoint != character)
  806.             this.capture();
  807.         //
  808.         if (this.codepoint == character)
  809.         {
  810.             if (readCharacter)
  811.             {
  812.                 this.capture();
  813.                 this.advance();
  814.             }
  815.             return true;
  816.         }
  817.         return false;
  818.     }
  819. };
  820. class _ExpEdge {
  821.     public exp : string;
  822.     public from : FA;
  823.     public to : FA;
  824. };
  825. export class FADotGraphOptions {
  826.     public dpi: number = 300;
  827.     public statePrefix: string = "q";
  828.     public debugString: string = null;
  829.     public blockEnds: FA[] = null;
  830.     public debugSourceNfa: FA = null;
  831.     public debugShowNfa: boolean = false;
  832.     public hideAcceptSymbolIds: boolean = false;
  833.     public acceptSymbolNames: string[] = null;
  834.     public vertical: boolean = false;
  835. };
  836. export interface FAProgressCallbackType { (value: number): void };
  837.  
  838. export class FAProgress {
  839.     private _callback: FAProgressCallbackType = null;
  840.     public value: number = 0;
  841.     public constructor(callback: FAProgressCallbackType = null) {
  842.         this._callback = callback;
  843.     }
  844.     public report(value: number): void {
  845.         this.value = value;
  846.         if (this._callback !== null) {
  847.             this._callback(value)
  848.         }
  849.     }
  850. };
  851. export class FARange {
  852.     public min: number;
  853.     public max: number;
  854.     public constructor(min: number, max: number) {
  855.         this.min = min;
  856.         this.max = max;
  857.     }
  858.     public intersects(arg: FARange | number): boolean {
  859.         let range: FARange;
  860.         let codepoint: number;
  861.         if (typeof arg === 'number') {
  862.             codepoint = arg;
  863.             return codepoint >= this.min && codepoint <= this.max;
  864.         }
  865.         range = arg;
  866.         return (range.min >= this.min && range.min <= this.max) ||
  867.             (range.max >= this.min && range.max <= this.max);
  868.     }
  869.     public static toUnpacked(packedRanges: number[]): FARange[] {
  870.         const result: FARange[] = new Array<FARange>(packedRanges.length / 2);
  871.         for (let i: number = 0; i < result.length; ++i) {
  872.             const j: number = i * 2;
  873.             result[i] = new FARange(packedRanges[j], packedRanges[j + 1]);
  874.         }
  875.         return result;
  876.     }
  877.     public static toPacked(pairs: FARange[]): number[] {
  878.         const result: number[] = new Array<number>(pairs.length * 2);
  879.         for (let ic: number = pairs.length, i: number = 0; i < ic; ++i) {
  880.             var pair = pairs[i];
  881.             var j = i * 2;
  882.             result[j] = pair.min;
  883.             result[j + 1] = pair.max;
  884.         }
  885.         return result;
  886.     }
  887.     public static *toNotRanges(ranges: Iterable<FARange>): Iterable<FARange> {
  888.         // expects ranges to be normalized
  889.         let last: number = 0x10ffff;
  890.         const e: Iterator<FARange> = ranges[Symbol.iterator]();
  891.         let cur = e.next();
  892.         if (cur.done) {
  893.             yield new FARange(0x0, 0x10ffff);
  894.             return;
  895.         }
  896.         if (cur.value.min > 0) {
  897.             yield new FARange(0, cur.value.min - 1);
  898.             last = cur.value.max;
  899.             if (0x10ffff <= last)
  900.                 return;
  901.         }
  902.         else if (cur.value.min == 0) {
  903.             last = cur.value.max;
  904.             if (0x10ffff <= last)
  905.                 return;
  906.         }
  907.         while (!cur.done) {
  908.             if (0x10ffff <= last)
  909.                 return;
  910.             if (last + 1 < cur.value.min)
  911.                 yield new FARange(last + 1, (cur.value.min - 1));
  912.             last = cur.value.max;
  913.             cur = e.next();
  914.         }
  915.         if (0x10ffff >= last)
  916.             yield new FARange((last + 1), 0x10ffff);
  917.     }
  918. }
  919. export class FATransition {
  920.     public min: number;
  921.     public max: number;
  922.     public to: FA;
  923.     public constructor(to: FA, min: number = -1, max: number = -1) {
  924.         this.min = min;
  925.         this.max = max;
  926.         this.to = to;
  927.     }
  928.     public isEpsilon(): boolean {
  929.         return this.min == -1 || this.max == -1;
  930.     }
  931. }
  932. class _FListNode {
  933.     public state: FA = null;
  934.     public stateList: _FList = null;
  935.     public next: _FListNode = null;
  936.     public prev: _FListNode = null;
  937.     public constructor(q: FA, sl: _FList) {
  938.         this.state = q;
  939.         this.stateList = sl;
  940.         if (sl.count++ === 0) {
  941.             sl.first = this;
  942.             sl.last = this;
  943.         }
  944.         else {
  945.             sl.last.next = this;
  946.             this.prev = sl.last;
  947.             sl.last = this;
  948.         }
  949.     }
  950.     public remove(): void {
  951.         --this.stateList.count;
  952.         if (this.stateList.first === this) {
  953.             this.stateList.first = this.next;
  954.         } else {
  955.             this.prev.next = this.next;
  956.         }
  957.         if (this.stateList.last === this) {
  958.             this.stateList.last = this.prev;
  959.         } else {
  960.             this.next.prev = this.prev;
  961.         }
  962.     }
  963. };
  964. class _FList {
  965.     public count: number = 0;
  966.     public first: _FListNode = null;
  967.     public last: _FListNode = null;
  968.     public add(q: FA): _FListNode {
  969.         return new _FListNode(q, this);
  970.     }
  971. };
  972. class _FKeyPair {
  973.     public key: number;
  974.     public value: number;
  975.     constructor(key: number, value: number) {
  976.         this.key = key;
  977.         this.value = value;
  978.     }
  979. };
  980. export class FA {
  981.     public isCompact: boolean = true;
  982.     public isDeterministic: boolean = true;
  983.     public tag: number = -1;
  984.     public acceptSymbol: number = -1;
  985.     public id: number = -1;
  986.     public transitions: FATransition[] = [];
  987.     public fromStates: FA[] = null;
  988.     private _minimizationTag: number = -1;
  989.     constructor(accept: number = -1) {
  990.         this.acceptSymbol = accept;
  991.     }
  992.     public fillClosure(result: FA[] = []): FA[] {
  993.         if (result.includes(this)) {
  994.             return result;
  995.         }
  996.         // add this instance
  997.         result.push(this);
  998.         // add sub instances
  999.         for (const transition of this.transitions) {
  1000.             const state: FA = transition.to;
  1001.             state.fillClosure(result);
  1002.         }
  1003.         // Return the list of fa instances
  1004.         return result;
  1005.     }
  1006.     public fillEpsilonClosure(result: FA[] = []): FA[] {
  1007.         if (result.includes(this)) {
  1008.             return result;
  1009.         }
  1010.         // add this instance
  1011.         result.push(this);
  1012.         // add sub instances
  1013.         for (const transition of this.transitions) {
  1014.             if (transition.isEpsilon()) {
  1015.                 const state: FA = transition.to;
  1016.                 state.fillEpsilonClosure(result);
  1017.             }
  1018.         }
  1019.         // Return the list of fa instances
  1020.         return result;
  1021.     }
  1022.     public static fillEpsilonClosureStates(states: Iterable<FA>, result: FA[] = []): FA[] {
  1023.         for (let state of states) {
  1024.             state.fillEpsilonClosure(result);
  1025.         }
  1026.         return result;
  1027.     }
  1028.     public isAccepting(): boolean {
  1029.         return this.acceptSymbol > -1;
  1030.     }
  1031.     public addEpsilon(to: FA, compact: boolean = true): void {
  1032.         if (to === undefined || to === null) {
  1033.             throw "to was not set";
  1034.         }
  1035.         if (compact) {
  1036.             if (this.acceptSymbol < 0 && to.acceptSymbol > -1) {
  1037.                 this.acceptSymbol = to.acceptSymbol;
  1038.             }
  1039.             for (let i: number = 0; i < to.transitions.length; ++i) {
  1040.                 var fat = to.transitions[i];
  1041.                 if (!fat.isEpsilon()) {
  1042.                     this.addTransition(new FARange(fat.min, fat.max), fat.to);
  1043.                 }
  1044.                 else {
  1045.                     this.addEpsilon(fat.to, true);
  1046.                 }
  1047.             }
  1048.         }
  1049.         else {
  1050.             var found = false;
  1051.             let i = 0;
  1052.             for (; i < this.transitions.length; ++i) {
  1053.                 var fat = this.transitions[i];
  1054.                 if (!fat.isEpsilon()) break;
  1055.                 if (fat.to === to) {
  1056.                     found = true;
  1057.                     break;
  1058.                 }
  1059.             }
  1060.             if (!found) {
  1061.                 this.transitions.splice(i, 0, new FATransition(to));
  1062.                 this.isCompact = false;
  1063.                 this.isDeterministic = false;
  1064.             }
  1065.         }
  1066.  
  1067.     }
  1068.     public addTransition(range: FARange, to: FA, compact: boolean = true): void {
  1069.         if (to === undefined || to === null) {
  1070.             throw "to was not set";
  1071.         }
  1072.         if (range.min == -1 || range.max == -1) {
  1073.             this.addEpsilon(to, compact);
  1074.             return;
  1075.         }
  1076.         if (range.min > range.max) {
  1077.             const tmp: number = range.min;
  1078.             range.min = range.max;
  1079.             range.max = tmp;
  1080.         }
  1081.         var insert = -1;
  1082.         for (let i: number = 0; i < this.transitions.length; ++i) {
  1083.             const fat: FATransition = this.transitions[i];
  1084.             if (to === fat.to) {
  1085.                 if (range.min === fat.min &&
  1086.                     range.max == fat.max) {
  1087.                     return;
  1088.                 }
  1089.             }
  1090.             if (this.isDeterministic) {
  1091.                 if (range.intersects(
  1092.                     new FARange(fat.min, fat.max))) {
  1093.                     this.isDeterministic = false;
  1094.                 }
  1095.             }
  1096.             if (range.max > fat.max) {
  1097.                 insert = i;
  1098.             }
  1099.             if (!this.isDeterministic &&
  1100.                 range.max < fat.min) {
  1101.                 break;
  1102.             }
  1103.         }
  1104.         this.transitions.splice(insert + 1, 0, new FATransition(to, range.min, range.max));
  1105.  
  1106.     }
  1107.     private static _crackSet(str: string, closure: FA[]): FA[] {
  1108.         const result: FA[] = [];
  1109.         if (str == "") {
  1110.             return result;
  1111.         }
  1112.         const sa: string[] = str.split(" ");
  1113.         for (const s of sa) {
  1114.             result.push(closure[Number.parseInt(s, 10)]);
  1115.         }
  1116.         return result;
  1117.     }
  1118.     private static _makeSet(closure: FA[], states: Iterable<FA>): string {
  1119.         let result: string = "";
  1120.         let delim: string = "";
  1121.         let ns: number[] = [];
  1122.         for (const fa of states) {
  1123.             const idx = closure.indexOf(fa);
  1124.             ns.push(idx);
  1125.         }
  1126.         ns.sort((x, y) => x - y);
  1127.         for (const i of ns) {
  1128.             result += (delim + i.toString(10));
  1129.             delim = " ";
  1130.         }
  1131.         return result;
  1132.     }
  1133.     private static _determinize(target: FA, progress: FAProgress = null): FA {
  1134.         if (progress === null) {
  1135.             progress = new FAProgress();
  1136.         }
  1137.         let prog: number = 0;
  1138.         progress.report(0);
  1139.         const closure: FA[] = target.fillClosure();
  1140.         const p: Set<number> = new Set<number>();
  1141.         for (const ffa of closure) {
  1142.             p.add(0);
  1143.             for (const t of ffa.transitions) {
  1144.                 p.add(t.min);
  1145.                 if (t.max < 0x10ffff) {
  1146.                     p.add(t.max + 1);
  1147.                 }
  1148.             }
  1149.         }
  1150.         const points: number[] = [...p];
  1151.         points.sort((x, y) => x - y);
  1152.         ++prog; progress.report(prog);
  1153.         const sets: Map<string, Set<FA>> = new Map<string, Set<FA>>();
  1154.         const working: string[] = [];
  1155.         const dfaMap: Map<string, FA> = new Map<string, FA>();
  1156.         const initStates: FA[] = closure[0].fillEpsilonClosure();
  1157.         let initial: string = FA._makeSet(closure, initStates);
  1158.         sets.set(initial, new Set<FA>(initStates));
  1159.         working.push(initial);
  1160.         const result: FA = new FA();
  1161.         result.isDeterministic = true;
  1162.         result.fromStates = initStates;
  1163.         result.acceptSymbol = FA.getFirstAcceptSymbol(initStates);
  1164.         dfaMap.set(initial, result);
  1165.         while (working.length > 0) {
  1166.             const s: string = working[0];
  1167.             working.shift();
  1168.             const dfa: FA = dfaMap.get(s)!;
  1169.             const crackedS1: FA[] = FA._crackSet(s, closure);
  1170.             for (const q of crackedS1) {
  1171.                 if (q.isAccepting()) {
  1172.                     dfa.acceptSymbol = q.acceptSymbol;
  1173.                     break;
  1174.                 }
  1175.             }
  1176.             let i: number = 0;
  1177.             for (const pnt of points) {
  1178.                 const set: Set<FA> = new Set<FA>();
  1179.                 for (const c of crackedS1) {
  1180.                     const ecs: FA[] = c.fillEpsilonClosure();
  1181.                     for (const efa of ecs) {
  1182.                         for (let trns of efa.transitions) {
  1183.                             if (!trns.isEpsilon()) {
  1184.                                 if (trns.min <= pnt && pnt <= trns.max) {
  1185.                                     for (const eefa of trns.to.fillEpsilonClosure()) {
  1186.                                         set.add(eefa);
  1187.                                     }
  1188.                                 }
  1189.                             }
  1190.                         }
  1191.                     }
  1192.                 }
  1193.                 const skey: string = FA._makeSet(closure, set);
  1194.                 if (!sets.has(skey)) {
  1195.                     sets.set(skey, set);
  1196.                     working.push(skey);
  1197.                     let newFa: FA = new FA();
  1198.                     newFa.isDeterministic = true;
  1199.                     newFa.isCompact = true;
  1200.                     newFa.fromStates = Array.from(set.values());
  1201.                     dfaMap.set(skey, newFa);
  1202.                 }
  1203.                 const dst: FA = dfaMap.get(skey)!;
  1204.                 const first: number = pnt;
  1205.                 let last: number;
  1206.                 if (i + 1 < points.length) {
  1207.                     last = points[i + 1] - 1;
  1208.                 } else {
  1209.                     last = 0x10ffff;
  1210.                 }
  1211.                 dfa.transitions.push(new FATransition(dst, first, last));
  1212.                 ++i;
  1213.             }
  1214.             ++prog; progress.report(prog);
  1215.         }
  1216.         for (const ffa of result.fillClosure()) {
  1217.             const itrns: FATransition[] = [...ffa.transitions];
  1218.             for (const trns of itrns) {
  1219.                 const acc: FA[] = trns.to.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  1220.                 if (acc.length == 0) {
  1221.                     ffa.transitions.splice(ffa.transitions.indexOf(trns), 1);
  1222.                 }
  1223.             }
  1224.             ++prog; progress.report(prog);
  1225.         }
  1226.         ++prog; progress.report(prog);
  1227.         return result;
  1228.     }
  1229.     public isDfa(): boolean {
  1230.         for (const ffa of this.fillClosure()) {
  1231.             if (!ffa.isDeterministic) {
  1232.                 return false;
  1233.             }
  1234.         }
  1235.         return true;
  1236.     }
  1237.     public toDfa(progress: FAProgress = null): FA {
  1238.         return FA._determinize(this, progress);
  1239.     }
  1240.     public totalize(closure: FA[] = null): void {
  1241.         if (closure === null) {
  1242.             closure = this.fillClosure();
  1243.         }
  1244.         const s: FA = new FA();
  1245.         s.transitions.push(new FATransition(s, 0, 0x10ffff));
  1246.         for (const p of closure) {
  1247.             let maxi: number = 0;
  1248.             const sortedTrans: FATransition[] = [...p.transitions];
  1249.             sortedTrans.sort((x: FATransition, y: FATransition) => {
  1250.                 let c: number = x.max - y.max; if (0 != c) return c; return x.min - y.min;
  1251.             });
  1252.             for (const t of sortedTrans) {
  1253.                 if (!t.isEpsilon()) {
  1254.                     if (t.min > maxi) {
  1255.                         p.transitions.push(new FATransition(s, maxi, t.min - 1));
  1256.                     }
  1257.                     if (t.max + 1 > maxi) {
  1258.                         maxi = t.max + 1;
  1259.                     }
  1260.                 }
  1261.             }
  1262.             if (maxi <= 0x10ffff) {
  1263.                 p.transitions.push(new FATransition(s, maxi, 0x10ffff));
  1264.             }
  1265.         }
  1266.     }
  1267.     private _step(input: number): FA {
  1268.         for (let ic: number = this.transitions.length, i: number = 0; i < ic; ++i) {
  1269.             var t = this.transitions[i];
  1270.             if (input >= t.min && input <= t.max)
  1271.                 return t.to;
  1272.  
  1273.         }
  1274.         return null;
  1275.     }
  1276.     private static _minimize(a: FA, progress: FAProgress): FA {
  1277.         let prog: number = 0;
  1278.         if (progress === null) {
  1279.             progress = new FAProgress();
  1280.         }
  1281.         progress.report(prog);
  1282.         a = a.toDfa(progress);
  1283.         const tr: FATransition[] = a.transitions;
  1284.         if (tr.length == 1) {
  1285.             const t: FATransition = tr[0];
  1286.             if (t.to === a && t.min == 0 && t.max == 0x10ffff) {
  1287.                 return a;
  1288.             }
  1289.         }
  1290.         a.totalize();
  1291.         ++prog; progress.report(prog);
  1292.         const cl: FA[] = a.fillClosure();
  1293.         const states: FA[] = new Array<FA>();
  1294.         let mtag: number = 0;
  1295.         for (const q of cl) {
  1296.             q._minimizationTag = mtag;
  1297.             states.push(q);
  1298.             ++mtag;
  1299.         }
  1300.         let pp: number[] = [];
  1301.         for (let ic: number = cl.length, i = 0; i < ic; ++i) {
  1302.             const ffa: FA = cl[i];
  1303.             pp.push(0);
  1304.             for (const t of ffa.transitions) {
  1305.                 pp.push(t.min);
  1306.                 if (t.max < 0x10ffff) {
  1307.                     pp.push(t.max + 1);
  1308.                 }
  1309.             }
  1310.         }
  1311.         const sigma: number[] = new Array<number>();
  1312.         for (let i = 0; i < pp.length; ++i) {
  1313.             sigma.push(pp[i]);
  1314.         }
  1315.         sigma.sort();
  1316.  
  1317.         // initialize the data structures
  1318.         const reverse: FA[][][] = new Array<Array<Array<FA>>>();
  1319.         for (const s of states) {
  1320.             const arr: FA[][] = new Array<Array<FA>>(sigma.length);
  1321.             arr.fill(null, 0, arr.length - 1);
  1322.             reverse.push(arr);
  1323.         }
  1324.         ++prog; progress.report(prog);
  1325.         const reverseNonempty: boolean[][] = Array<Array<boolean>>();//[states.length,sigma.length];
  1326.         for (let i: number = 0; i < states.length; ++i) {
  1327.             const arr: boolean[] = new Array<boolean>(sigma.length);
  1328.             arr.fill(false, 0, arr.length - 1);
  1329.             reverseNonempty.push(arr);
  1330.         }
  1331.         const partition: FA[][] = new Array<Array<FA>>(states.length);
  1332.         partition.fill(null, 0, partition.length - 1);
  1333.         ++prog; progress.report(prog);
  1334.         const block: number[] = new Array<number>(states.length);
  1335.         const active: _FList[][] = new Array<Array<_FList>>(); // [states.length,sigma.length];
  1336.         for (let i: number = 0; i < states.length; ++i) {
  1337.             const arr: _FList[] = new Array<_FList>(sigma.length);
  1338.             arr.fill(null, 0, arr.length - 1);
  1339.             active.push(arr);
  1340.         }
  1341.         const active2: _FListNode[][] = new Array<Array<_FListNode>>()//[states.length,sigma.length];
  1342.         for (let i: number = 0; i < states.length; ++i) {
  1343.             const arr: _FListNode[] = new Array<_FListNode>(sigma.length);
  1344.             arr.fill(null, 0, arr.length - 1);
  1345.             active2.push(arr);
  1346.         }
  1347.         const pending: _FKeyPair[] = new Array<_FKeyPair>();
  1348.         const pending2: boolean[][] = Array<Array<boolean>>();//[sigma.length,states.length];
  1349.         for (let i: number = 0; i < sigma.length; ++i) {
  1350.             const arr: boolean[] = new Array<boolean>(states.length);
  1351.             arr.fill(false, 0, arr.length - 1);
  1352.             pending2.push(arr);
  1353.         }
  1354.         let split: FA[] = new Array<FA>();
  1355.         const split2: boolean[] = new Array<boolean>(states.length);
  1356.         split2.fill(false, 0, split2.length - 1);
  1357.         let refine: number[] = new Array<number>();
  1358.         const refine2: boolean[] = new Array<boolean>(states.length);
  1359.         split2.fill(false, 0, refine2.length - 1);
  1360.         const splitBlock: FA[][] = new Array<Array<FA>>(states.length);
  1361.         splitBlock.fill(null, 0, splitBlock.length - 1);
  1362.         ++prog; progress.report(prog);
  1363.         for (let q: number = 0; q < states.length; ++q) {
  1364.             splitBlock[q] = new Array<FA>();
  1365.             partition[q] = new Array<FA>();
  1366.             for (let x: number = 0; x < sigma.length; ++x) {
  1367.                 reverse[q][x] = new Array<FA>();
  1368.                 active[q][x] = new _FList();
  1369.             }
  1370.         }
  1371.         // Find the initial partition and reverse edges
  1372.         for (const qq of states) {
  1373.             const j: number = qq.isAccepting() ? 0 : 1;
  1374.             partition[j].push(qq);
  1375.             block[qq._minimizationTag] = j;
  1376.             for (let x: number = 0; x < sigma.length; ++x) {
  1377.                 const y: number = sigma[x];
  1378.                 const p: FA = qq._step(y);
  1379.                 const pn: number = p._minimizationTag;
  1380.                 if (reverse[pn] !== null && reverse[pn][x] !== null) {
  1381.                     reverse[pn][x].push(qq);
  1382.                 }
  1383.                 reverseNonempty[pn][x] = true;
  1384.             }
  1385.             ++prog; progress.report(prog);
  1386.         }
  1387.         // initialize the active sets
  1388.         for (let j: number = 0; j <= 1; ++j) {
  1389.             for (let x: number = 0; x < sigma.length; ++x) {
  1390.                 const part: FA[] = partition[j];
  1391.                 for (const qq of part) {
  1392.                     if (reverseNonempty[qq._minimizationTag][x] === true) {
  1393.                         active2[qq._minimizationTag][x] = active[j][x].add(qq);
  1394.                     }
  1395.                 }
  1396.             }
  1397.             ++prog; progress.report(prog);
  1398.         }
  1399.         // initialize pending
  1400.         for (let x: number = 0; x < sigma.length; ++x) {
  1401.             const a0: number = active[0][x].count;
  1402.             const a1: number = active[1][x].count;
  1403.             const j: number = a0 <= a1 ? 0 : 1;
  1404.             pending.push(new _FKeyPair(j, x));
  1405.             pending2[x][j] = true;
  1406.         }
  1407.         // process pending until fixed point
  1408.         let k: number = 2;
  1409.         while (pending.length > 0) {
  1410.             const ip: _FKeyPair = pending.shift();
  1411.             const p: number = ip.key;
  1412.             const x: number = ip.value;
  1413.             pending2[x][p] = false;
  1414.             for (let m: _FListNode = active[p][x].first; m !== null; m = m.next) {
  1415.                 for (const s of reverse[m.state._minimizationTag][x]) {
  1416.                     if (!split2[s._minimizationTag]) {
  1417.                         split2[s._minimizationTag] = true;
  1418.                         split.push(s);
  1419.                         const j: number = block[s._minimizationTag];
  1420.                         splitBlock[j].push(s);
  1421.                         if (refine2[j] !== true) {
  1422.                             refine2[j] = true;
  1423.                             refine.push(j);
  1424.                         }
  1425.                     }
  1426.                 }
  1427.             }
  1428.             ++prog; progress.report(prog);
  1429.             // refine blocks
  1430.             for (const j of refine) {
  1431.                 if (splitBlock[j].length < partition[j].length) {
  1432.                     const b1: Array<FA> = partition[j];
  1433.                     const b2: Array<FA> = partition[k];
  1434.                     const e: Array<FA> = splitBlock[j];
  1435.                     for (const s of e) {
  1436.                         b1.splice(b1.indexOf(s), 1);
  1437.                         b2.push(s);
  1438.                         block[s._minimizationTag] = k;
  1439.                         for (let c: number = 0; c < sigma.length; ++c) {
  1440.                             const sn: _FListNode = active2[s._minimizationTag][c];
  1441.                             if (sn !== null && sn!==undefined && sn.stateList === active[j][c]) {
  1442.                                 sn.remove();
  1443.                                 active2[s._minimizationTag][c] = active[k][c].add(s);
  1444.                             }
  1445.                         }
  1446.                     }
  1447.                     // update pending
  1448.                     for (let c: number = 0; c < sigma.length; ++c) {
  1449.                         const aj: number = active[j][c].count;
  1450.                         const ak: number = active[k][c].count;
  1451.                         if (!pending2[c][j] && 0 < aj && aj <= ak) {
  1452.                             pending2[c][j] = true;
  1453.                             pending.push(new _FKeyPair(j, c));
  1454.                         } else {
  1455.                             pending2[c][k] = true;
  1456.                             pending.push(new _FKeyPair(k, c));
  1457.                         }
  1458.                     }
  1459.                     ++k;
  1460.                 }
  1461.                 const sbj: Array<FA> = splitBlock[j];
  1462.                 for (const s of sbj) {
  1463.                     split2[s._minimizationTag] = false;
  1464.                 }
  1465.                 refine2[j] = false;
  1466.                 splitBlock[j].length = 0;
  1467.                 ++prog; progress.report(prog);
  1468.  
  1469.             }
  1470.             split.length = 0;
  1471.             refine.length = 0;
  1472.         }
  1473.         ++prog; progress.report(prog);
  1474.         // make a new state for each equiv class, set initial state
  1475.         const newstates: FA[] = new Array<FA>();
  1476.         for (let n: number = 0; n < k; ++n) {
  1477.             const s: FA = new FA();
  1478.             s.isDeterministic = true;
  1479.             newstates.push(s);
  1480.             const pn: Array<FA> = partition[n];
  1481.             for (const q of pn) {
  1482.                 if (q === a) {
  1483.                     a = s;
  1484.                 }
  1485.                 s.id = q.id;
  1486.                 s.acceptSymbol = q.acceptSymbol;
  1487.                 s._minimizationTag = q._minimizationTag;
  1488.                 q._minimizationTag = n;
  1489.             }
  1490.             ++prog; progress.report(prog);
  1491.         }
  1492.         // build transitions and set acceptance
  1493.         for (const s of newstates) {
  1494.             const st: FA = states[s._minimizationTag];
  1495.             s.acceptSymbol = st.acceptSymbol;
  1496.             for (const t of st.transitions) {
  1497.                 s.transitions.push(new FATransition(newstates[t.to._minimizationTag], t.min, t.max));
  1498.             }
  1499.             ++prog; progress.report(prog);
  1500.         }
  1501.         // remove dead transitions
  1502.         for (const ffa of a.fillClosure()) {
  1503.             const itrns: FATransition[] = new Array<FATransition>(...ffa.transitions)
  1504.             ffa.transitions = new Array<FATransition>();
  1505.             for (const trns of itrns) {
  1506.                 if (!trns.to.isTrap()) {
  1507.                     ffa.transitions.push(trns);
  1508.                 }
  1509.             }
  1510.         }
  1511.         return a;
  1512.     }
  1513.     public toMinimizedDfa(progress: FAProgress = null) {
  1514.         return FA._minimize(this, progress);
  1515.     }
  1516.     public clone(): FA {
  1517.         const result: FA[] = [];
  1518.         const closure = this.fillClosure();
  1519.         for (let j = 0; j < closure.length; ++j) {
  1520.             result.push(new FA());
  1521.         }
  1522.         let i: number = 0;
  1523.         for (const ffa of closure) {
  1524.             result[i].isCompact = ffa.isCompact;
  1525.             result[i].isDeterministic = ffa.isDeterministic;
  1526.             result[i].acceptSymbol = ffa.acceptSymbol;
  1527.             result[i].tag = ffa.tag;
  1528.             for (const trns of ffa.transitions) {
  1529.                 result[i].transitions.push(new FATransition(result[closure.indexOf(trns.to)], trns.min, trns.max));
  1530.             }
  1531.             ++i;
  1532.         }
  1533.         return result[0];
  1534.     }
  1535.  
  1536.     private static _toExpressionFillEdgesIn(edges: _ExpEdge[], node: FA) : _ExpEdge[]
  1537.     {
  1538.         const result:_ExpEdge[] = new Array<_ExpEdge>();
  1539.         for (let i: number = 0; i < edges.length; ++i)
  1540.         {
  1541.             const edge: _ExpEdge = edges[i];
  1542.             if (edge.to === node)
  1543.             {
  1544.                 result.push(edge);
  1545.             }
  1546.         }
  1547.         return result;
  1548.     }
  1549.     private static _toExpressionFillEdgesOut(edges: _ExpEdge[], node: FA) : _ExpEdge[]
  1550.     {
  1551.         const result:_ExpEdge[] = new Array<_ExpEdge>();
  1552.         for (let i: number = 0; i < edges.length; ++i)
  1553.         {
  1554.             const edge: _ExpEdge = edges[i];
  1555.             if (edge.from === node)
  1556.             {
  1557.                 result.push(edge);
  1558.             }
  1559.         }
  1560.         return result;
  1561.     }
  1562.     private static _toExpressionOrJoin(strings: string[]) : string
  1563.     {
  1564.         if (strings.length == 0) return ""
  1565.         if (strings.length == 1) return strings[0];
  1566.         return "("+ strings.join("|")+ ")";
  1567.     }
  1568.  
  1569.     private static _toExpressionKleeneStar(sb : string,s: string,noWrap: boolean) : string
  1570.     {
  1571.         if (s===undefined || s===null || s.length==0) return "";
  1572.         if (noWrap || s.length == 1)
  1573.         {
  1574.             sb+=s;
  1575.             sb+="*";
  1576.             return;
  1577.         }
  1578.         sb+="(";
  1579.         sb+=s;
  1580.         sb+=")*";
  1581.     }
  1582.  
  1583.  
  1584.     private static _toExpressionFillEdgesOrphanState(edges: _ExpEdge[], node: FA,) :_ExpEdge[]
  1585.     {
  1586.         const result: _ExpEdge[] = new Array<_ExpEdge>();
  1587.         for (let i: number = 0; i < edges.length; ++i)
  1588.         {
  1589.             var edge = edges[i];
  1590.             if (edge.from === node || edge.to === node)
  1591.             {
  1592.                 continue;
  1593.             }
  1594.             result.push(edge);
  1595.         }
  1596.         return result;
  1597.     }
  1598.     private static _toExpression(fa: FA) : string
  1599.     {
  1600.         const closure: FA[] = new Array<FA>();
  1601.         let fsmEdges: _ExpEdge[] = new Array<_ExpEdge>();
  1602.         let first: FA, final: FA = null;
  1603.         first = fa;
  1604.         let acc:FA[] = first.fillClosure().filter((elem)=>elem.isAccepting());
  1605.         if (acc.length == 1)
  1606.         {
  1607.             final = acc[0];
  1608.         }
  1609.         else if (acc.length > 1)
  1610.         {
  1611.             fa = fa.clone();
  1612.             first = fa;
  1613.             acc = fa.fillClosure().filter((elem)=>elem.isAccepting());
  1614.             final = new FA(acc[0].acceptSymbol);
  1615.             for (let i: number = 0; i < acc.length; ++i)
  1616.             {
  1617.                 let a:FA = acc[i];
  1618.                 a.addEpsilon(final, false);
  1619.                 a.acceptSymbol = -1;
  1620.             }
  1621.         }
  1622.         closure.length=0;
  1623.         first.fillClosure(closure);
  1624.         let sb: string = "";
  1625.         // build the machine from the FA
  1626.         var trnsgrp = new Map<FA, FARange[]>();
  1627.         for (let q: number = 0; q < closure.length; ++q)
  1628.         {
  1629.             var cfa = closure[q];
  1630.             trnsgrp.clear();
  1631.             for(const trns of cfa.fillInputTransitionRangesGroupedByState(true,trnsgrp))
  1632.             {
  1633.                 sb="";
  1634.                 if (trns[1].length == 1 && trns[1][0].min == trns[1][0].max)
  1635.                 {
  1636.                     const range: FARange = trns[1][0];
  1637.                     if (range.max==-1||range.min==-1)
  1638.                     {
  1639.                         var eedge = new _ExpEdge();
  1640.                         eedge.exp = "";
  1641.                         eedge.from = cfa;
  1642.                         eedge.to = trns[0];
  1643.                         fsmEdges.push(eedge);
  1644.                         continue;
  1645.                     }
  1646.                     sb+=FA._appendCharTo(String.fromCodePoint(range.min));
  1647.                 }
  1648.                 else
  1649.                 {
  1650.                     sb+="[";
  1651.                     sb+=FA._appendRangeTo(trns[1]);
  1652.                     sb+="]";
  1653.                 }
  1654.                 var edge = new _ExpEdge();
  1655.                 edge.exp = sb;
  1656.                 edge.from = cfa;
  1657.                 edge.to = trns[0];
  1658.                 fsmEdges.push(edge);
  1659.             }
  1660.         }
  1661.         let tmp: FA = new FA();
  1662.         tmp.addEpsilon(first, false);
  1663.         const q0: FA = first;
  1664.         first = tmp;
  1665.         tmp = new FA(final.acceptSymbol);
  1666.         const qLast: FA = final;
  1667.         final.acceptSymbol = -1;
  1668.         final.addEpsilon(tmp, false);
  1669.         final = tmp;
  1670.         // add first and final
  1671.         let newEdge: _ExpEdge = new _ExpEdge();
  1672.         newEdge.exp = "";
  1673.         newEdge.from = first;
  1674.         newEdge.to = q0;
  1675.         fsmEdges.push(newEdge);
  1676.         newEdge = new _ExpEdge();
  1677.         newEdge.exp = "";
  1678.         newEdge.from = qLast;
  1679.         newEdge.to = final;
  1680.         fsmEdges.push(newEdge);
  1681.         closure.splice(0,0,first);
  1682.         closure.push(final);
  1683.         let inEdges: _ExpEdge[] = new Array<_ExpEdge>();
  1684.         inEdges.fill(null,0,fsmEdges.length-1);
  1685.         let outEdges: _ExpEdge[] = new Array<_ExpEdge>();
  1686.         outEdges.fill(null,0,fsmEdges.length-1);
  1687.         while (closure.length > 2)
  1688.         {
  1689.             var node = closure[1];
  1690.             var loops = new Array<string>();
  1691.             inEdges.length=0;
  1692.             inEdges=FA._toExpressionFillEdgesIn(fsmEdges, node);
  1693.             for (let i: number = 0; i < inEdges.length; ++i)
  1694.             {
  1695.                 var edge = inEdges[i];
  1696.                 if (edge.from === edge.to)
  1697.                 {
  1698.                     loops.push(edge.exp);
  1699.                 }
  1700.             }
  1701.             sb=FA._toExpressionKleeneStar(sb,FA._toExpressionOrJoin(loops), loops.length > 1);
  1702.             const middle: string = sb;
  1703.             for (let i: number = 0; i < inEdges.length; ++i)
  1704.             {
  1705.                 var inEdge = inEdges[i];
  1706.                 if (inEdge.from == inEdge.to)
  1707.                 {
  1708.                     continue;
  1709.                 }
  1710.                 outEdges.length = 0;
  1711.                 outEdges=FA._toExpressionFillEdgesOut(fsmEdges, node);
  1712.                 for (let j: number = 0; j < outEdges.length; ++j)
  1713.                 {
  1714.                     var outEdge = outEdges[j];
  1715.                     if (outEdge.from === outEdge.to)
  1716.                     {
  1717.                         continue;
  1718.                     }
  1719.                     var expEdge = new _ExpEdge();
  1720.                     expEdge.from = inEdge.from;
  1721.                     expEdge.to = outEdge.to;
  1722.                     sb="";
  1723.                     sb+=inEdge.exp;
  1724.                     sb+=middle;
  1725.                     sb+=outEdge.exp;
  1726.                     expEdge.exp = sb;
  1727.                     fsmEdges.push(expEdge);
  1728.                 }
  1729.             }
  1730.             inEdges = FA._toExpressionFillEdgesOrphanState(fsmEdges, node);
  1731.             fsmEdges.length = 0;
  1732.             fsmEdges.push(...inEdges);
  1733.             closure.splice(closure.indexOf(node),1);
  1734.         }
  1735.         sb="";
  1736.         if(fsmEdges.length==1)
  1737.         {
  1738.             return fsmEdges[0].exp;
  1739.         }
  1740.         if (fsmEdges.length > 1)
  1741.         {
  1742.             sb+="(";
  1743.             sb+=fsmEdges[0].exp;
  1744.             for (let i: number = 1; i < fsmEdges.length; ++i)
  1745.             {
  1746.                 sb+="|";
  1747.                 sb+=fsmEdges[i].exp;
  1748.             }
  1749.             sb+=")";
  1750.         }
  1751.         return sb;
  1752.     }
  1753.    
  1754.     public toString(format: string, options: FADotGraphOptions = null): string {
  1755.  
  1756.         if (format.toLowerCase() === "d") {
  1757.             if (options != null && options.debugSourceNfa != null && options.debugShowNfa) {
  1758.                 return this._buildCompoundDot(this.fillClosure(), options);
  1759.             }
  1760.             else {
  1761.                 return this._buildDot(this.fillClosure(), options, -1);
  1762.             }
  1763.         } else if(format.toLowerCase()=="e") {
  1764.             return FA._toExpression(this);
  1765.         } else {
  1766.             if (this.id < 0) {
  1767.                 return "[FA]";
  1768.             } else {
  1769.                 return "q" + this.id.toString();
  1770.             }
  1771.         }
  1772.     }
  1773.     public setIds(): void {
  1774.         let i: number = 0;
  1775.         for (const fa of this.fillClosure()) {
  1776.             fa.id = i;
  1777.             ++i;
  1778.         }
  1779.     }
  1780.     public static literal(codepoints: Iterable<number> | string, accept: number = 0, compact: boolean = true): FA {
  1781.         if (typeof codepoints == "string") {
  1782.             codepoints = this.toUtf32(codepoints);
  1783.         }
  1784.         const result: FA = new FA();
  1785.         let current: FA = result;
  1786.         for (const cp of codepoints) {
  1787.             current.acceptSymbol = -1;
  1788.             const newFa: FA = new FA();
  1789.             newFa.acceptSymbol = accept;
  1790.             current.addTransition(new FARange(cp, cp), newFa,compact);
  1791.             current = newFa;
  1792.         }
  1793.         return result;
  1794.     }
  1795.     public static set(ranges: Iterable<FARange>, accept: number = 0, compact: boolean = true): FA {
  1796.         const result: FA = new FA();
  1797.         const final: FA = new FA();
  1798.         final.acceptSymbol = accept;
  1799.         for (const range of [...ranges].sort((x, y) => x.max - y.max)) {
  1800.             result.addTransition(range, final,compact);
  1801.         }
  1802.         return result;
  1803.     }
  1804.     public static concat(exprs: Iterable<FA>, accept: number = 0, compact: boolean = true): FA {
  1805.         let result: FA | null = null;
  1806.         let left: FA | null = null;
  1807.         let right: FA | null = null;
  1808.         for (const expr of exprs) {
  1809.             let nval = expr.clone();
  1810.             if (null === left) {
  1811.                 if (null === result) {
  1812.                     result = nval;
  1813.                 }
  1814.                 left = nval;
  1815.                 continue;
  1816.  
  1817.             }
  1818.             if (null === right) {
  1819.                 right = nval;
  1820.             }
  1821.             nval = right.clone();
  1822.             FA._concat(left!, nval, compact);
  1823.         }
  1824.         const target: FA = null !== right ? right! : result!;
  1825.         const acc: FA[] = target.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  1826.         for (const afa of acc) {
  1827.             afa.acceptSymbol = accept;
  1828.         }
  1829.         return result!;
  1830.     }
  1831.     public static or(exprs: Iterable<FA>, accept: number = 0, compact: boolean = true): FA {
  1832.         const result: FA = new FA();
  1833.         const final: FA = new FA();
  1834.         final.acceptSymbol = accept;
  1835.         for (const expr of exprs) {
  1836.             const nfa = expr.clone();
  1837.             const nacc: FA[] = nfa.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  1838.             for (const afa of nacc) {
  1839.                 afa.acceptSymbol = -1;
  1840.                 afa.addEpsilon(final, compact);
  1841.             }
  1842.             result.addEpsilon(nfa, compact);
  1843.         }
  1844.         return result;
  1845.     }
  1846.     public static optional(expr: FA, accept: number = 0, compact: boolean = true): FA {
  1847.         const result: FA = expr.clone();
  1848.         const acc: FA[] = result.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  1849.         for (const afa of acc) {
  1850.             afa.acceptSymbol = accept;
  1851.             result.addEpsilon(afa, compact);
  1852.         }
  1853.         return result;
  1854.     }
  1855.     public static repeat(expr: FA, minOccurs: number = -1, maxOccurs: number = -1, accept: number = 0, compact: boolean = true): FA {
  1856.         expr = expr.clone();
  1857.         if (minOccurs > 0 && maxOccurs > 0 && minOccurs > maxOccurs) {
  1858.             throw Error("Minimum is greater than maximum");
  1859.         }
  1860.         let result: FA;
  1861.         switch (minOccurs) {
  1862.             case -1:
  1863.             case 0:
  1864.                 switch (maxOccurs) {
  1865.                     case -1:
  1866.                     case 0:
  1867.                         result = new FA();
  1868.                         result.acceptSymbol = accept;
  1869.                         result.addEpsilon(expr, compact);
  1870.                         for (const afa of expr.fillClosure()) {
  1871.                             if (afa.isAccepting()) {
  1872.                                 afa.acceptSymbol = -1;
  1873.                                 afa.addEpsilon(result, compact);
  1874.                             }
  1875.                         }
  1876.                         return result;
  1877.                     case 1:
  1878.                         result = this.optional(expr, accept, compact);
  1879.                         return result;
  1880.                     default:
  1881.                         const l: FA[] = [];
  1882.                         expr = this.optional(expr, accept, compact);
  1883.                         l.push(expr);
  1884.                         for (let i = 1; i < maxOccurs; ++i) {
  1885.                             l.push(expr.clone());
  1886.                         }
  1887.                         result = this.concat(l, accept, compact);
  1888.                         return result;
  1889.                 }
  1890.             case 1:
  1891.                 switch (maxOccurs) {
  1892.                     case -1:
  1893.                     case 0:
  1894.                         result = this.concat([expr, FA.repeat(expr, 0, 0, accept, compact)], accept, compact);
  1895.                         return result;
  1896.                     case 1:
  1897.                         return expr;
  1898.                     default:
  1899.                         result = this.concat([expr, FA.repeat(expr, 0, maxOccurs - 1, accept, compact)], accept, compact);
  1900.                         return result;
  1901.                 }
  1902.             default:
  1903.                 switch (maxOccurs) {
  1904.                     case -1:
  1905.                     case 0:
  1906.                         result = this.concat([FA.repeat(expr, minOccurs, minOccurs, accept, compact), FA.repeat(expr, 0, 0, accept, compact)], accept, compact);
  1907.                         return result;
  1908.                     case 1:
  1909.                         throw new Error("Should never get here");
  1910.                     default:
  1911.                         if (minOccurs == maxOccurs) {
  1912.                             const l: FA[] = [];
  1913.                             expr = this.optional(expr, accept, compact);
  1914.                             l.push(expr);
  1915.                             for (let i = 1; i < maxOccurs; ++i) {
  1916.                                 l.push(expr.clone());
  1917.                             }
  1918.                             result = this.concat(l, accept, compact);
  1919.                             return result;
  1920.                         }
  1921.                         result = this.concat([this.repeat(expr, minOccurs, minOccurs, accept, compact), FA.repeat(FA.optional(expr, accept, compact), maxOccurs - minOccurs, maxOccurs - minOccurs, accept, compact)], accept, compact);
  1922.                         return result;
  1923.                 }
  1924.         }
  1925.         // throw new Error("Should never get here");
  1926.     }
  1927.     public run(value: string, blockEnds: FA[] = null) : FAStringRunner {
  1928.         const result: FAStringRunner = new FAStringStateRunner(this,blockEnds);
  1929.         result.set(value);
  1930.         return result;
  1931.     }
  1932.     public static runDfa(value: string, dfa: number[], blockEnds: number[][]=null) : FAStringRunner {
  1933.         const result: FAStringRunner = new FAStringDfaTableRunner(dfa,blockEnds);
  1934.         result.set(value);
  1935.         return result;
  1936.     }
  1937.     public isNeutral(): boolean {
  1938.         return !this.isAccepting && this.transitions.length == 1 && this.transitions[0].isEpsilon();
  1939.     }
  1940.     public isFinal(): boolean {
  1941.         return this.transitions.length == 0;
  1942.     }
  1943.     public isTrap(): boolean {
  1944.         if (this.isAccepting()) {
  1945.             return false;
  1946.         }
  1947.         for (const ffa of this.fillClosure()) {
  1948.             if (ffa.isAccepting()) {
  1949.                 return false;
  1950.             }
  1951.         }
  1952.         return true;
  1953.     }
  1954.     public fillInputTransitionRangesGroupedByState(includeEpsilonTransitions: boolean = false, result: Map<FA, FARange[]> = null): Map<FA, FARange[]> {
  1955.         if (result === null) {
  1956.             result = new Map<FA, FARange[]>();
  1957.         }
  1958.         for (const fat of this.transitions) {
  1959.             if (includeEpsilonTransitions || !fat.isEpsilon()) {
  1960.                 const res: FARange[] | undefined = result.get(fat.to);
  1961.                 if (res === undefined) {
  1962.                     const ndata: FARange[] = [new FARange(fat.min, fat.max)];
  1963.                     result.set(fat.to, ndata);
  1964.                 } else {
  1965.                     res.push(new FARange(fat.min, fat.max));
  1966.                 }
  1967.             }
  1968.         }
  1969.         for (const values of result.values()) {
  1970.             values.sort((x: FARange, y: FARange) => { var c = x.min - y.min; if (0 != c) return c; return x.max - y.max; });
  1971.         }
  1972.         return result;
  1973.     }
  1974.     public toArray(): number[] {
  1975.         const fa: FA = this;
  1976.         const result: number[] = [];
  1977.         const closure: FA[] = fa.fillClosure();
  1978.         const stateIndices: number[] = [];
  1979.         for (let i: number = 0; i < closure.length; ++i) {
  1980.             const cfa: FA = closure[i];
  1981.             stateIndices.push(result.length);
  1982.             result.push(cfa.isAccepting()?cfa.acceptSymbol:-1);
  1983.             const itrgp: Map<FA, FARange[]> = cfa.fillInputTransitionRangesGroupedByState();
  1984.             result.push(itrgp.size);
  1985.             for (const itr of itrgp.entries()) {
  1986.                 result.push(closure.indexOf(itr[0]));
  1987.                 result.push(itr[1].length);
  1988.                 result.push(...FARange.toPacked(itr[1]));
  1989.             }
  1990.         }
  1991.         let state: number = 0;
  1992.         while (state < result.length) {
  1993.             ++state;
  1994.             const tlen = result[state++];
  1995.             for (let i: number = 0; i < tlen; ++i) {
  1996.                 result[state] = stateIndices[result[state]];
  1997.                 ++state;
  1998.                 const prlen: number = result[state++];
  1999.                 state += prlen * 2;
  2000.             }
  2001.         }
  2002.         return result;
  2003.     }
  2004.     public static fromArray(fa: number[]): FA {
  2005.  
  2006.         if (fa.length == 0) {
  2007.             return new FA();
  2008.         }
  2009.         let si: number = 0;
  2010.         const states: Map<number, FA> = new Map<number, FA>();
  2011.         while (si < fa.length) {
  2012.             const newFa: FA = new FA();
  2013.             states.set(si, newFa);
  2014.             newFa.acceptSymbol = fa[si++];
  2015.             const tlen: number = fa[si++];
  2016.             for (let i: number = 0; i < tlen; ++i) {
  2017.                 ++si; // tto
  2018.                 const prlen: number = fa[si++];
  2019.                 si += prlen * 2;
  2020.             }
  2021.         }
  2022.         si = 0;
  2023.         while (si < fa.length) {
  2024.             var state = states.get(si)!;
  2025.             ++si;
  2026.             const tlen: number = fa[si++];
  2027.             for (let i: number = 0; i < tlen; ++i) {
  2028.                 const tto: number = fa[si++];
  2029.                 const to: FA = states.get(tto)!;
  2030.                 const prlen: number = fa[si++];
  2031.                 for (let j: number = 0; j < prlen; ++j) {
  2032.                     state.addTransition(new FARange(fa[si++], fa[si++]), to);
  2033.                 }
  2034.             }
  2035.         }
  2036.         return states.get(0)!;
  2037.     }
  2038.     public move(codepoint: number) : FA {
  2039.         if (!this.isDeterministic)
  2040.             {
  2041.                 throw "The state machine must be deterministic";
  2042.             }
  2043.             for (let i: number = 0; i < this.transitions.length; ++i)
  2044.             {
  2045.                 const fat: FATransition = this.transitions[i];
  2046.                 if (codepoint < fat.min)
  2047.                 {
  2048.                     return null;
  2049.                 }
  2050.                 if (codepoint <= fat.max)
  2051.                 {
  2052.                     return fat.to;
  2053.                 }
  2054.             }
  2055.             return null;
  2056.     }
  2057.     public static fillMove(states: Iterable<FA>, codepoint: number, result: FA[] = []): FA[] {
  2058.         for (const ffa of states) {
  2059.             for (const fat of ffa.transitions) {
  2060.                 if (!fat.isEpsilon() && (codepoint >= fat.min && codepoint <= fat.max)) {
  2061.                     fat.to.fillEpsilonClosure(result);
  2062.                 }
  2063.             }
  2064.         }
  2065.         return result;
  2066.     }
  2067.     public static getFirstAcceptSymbol(states: Iterable<FA>): number {
  2068.         for (const fa of states) {
  2069.             if (fa.isAccepting()) {
  2070.                 return fa.acceptSymbol;
  2071.             }
  2072.         }
  2073.         return -1;
  2074.     }
  2075.  
  2076.     private static _concat(lhs: FA, rhs: FA, compact: boolean): void {
  2077.         const acc: FA[] = lhs.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  2078.         for (const afa of acc) {
  2079.             afa.acceptSymbol = -1;
  2080.             afa.addEpsilon(rhs, compact);
  2081.         }
  2082.     }
  2083.  
  2084.     public static *toUtf32(str: string): Iterable<number> {
  2085.         for (const character of str) {
  2086.             let cp: number = character.codePointAt(0)!;
  2087.             if (cp >= 0xD800 && cp <= 0xDBFF) { // hi surrogate
  2088.                 const cpl: number = character.codePointAt(1)!
  2089.                 if (!(cpl >= 0xDC00 && cpl <= 0xDFFF)) { // not a low surrogate
  2090.                     throw new Error("Unicode stream error. Unterminated high surrogate");
  2091.                 }
  2092.                 const highValue = cp & 0b11_11111111;
  2093.                 const lowValue = cpl & 0b11_11111111;
  2094.                 const magicAdd = 0b1_00000000_00000000;
  2095.                 cp = (highValue << 10) | lowValue + magicAdd;
  2096.             }
  2097.             yield cp;
  2098.         }
  2099.     }
  2100.     private static *_invertRanges(ranges: Iterable<FARange>): Iterable<FARange> {
  2101.         if (ranges == null) {
  2102.             return;
  2103.         }
  2104.         let last: number = 0x10ffff;
  2105.  
  2106.         let e: Iterator<FARange> = ranges[Symbol.iterator]();
  2107.         let cur = e.next();
  2108.         if (cur.done) {
  2109.             yield new FARange(0, 0x10ffff);
  2110.             return;
  2111.         }
  2112.         if (cur.value.min > 0) {
  2113.             yield new FARange(0, cur.value.min - 1);
  2114.             last = cur.value.max;
  2115.             if (0x10ffff <= last)
  2116.                 return;
  2117.         }
  2118.         else if (cur.value.min == 0) {
  2119.             last = cur.value.max;
  2120.             if (0x10ffff <= last)
  2121.                 return;
  2122.         }
  2123.         cur = e.next();
  2124.         while (!cur.done) {
  2125.             if (0x10ffff <= last)
  2126.                 return;
  2127.             if ((last + 1) < cur.value.min) {
  2128.                 yield new FARange(last + 1, cur.value.min - 1);
  2129.             }
  2130.             last = cur.value.max;
  2131.             cur = e.next();
  2132.         }
  2133.         if (0x10ffff > last) {
  2134.             yield new FARange(last + 1, 0x10ffff);
  2135.         }
  2136.     }
  2137.     private static _appendRangeTo(ranges: FARange[], index: number = -1): string {
  2138.         let result: string = "";
  2139.         if (index === -1) {
  2140.             for (let i: number = 0; i < ranges.length; ++i) {
  2141.                 result += FA._appendRangeTo(ranges, i);
  2142.             }
  2143.             return result;
  2144.         }
  2145.         var first = ranges[index].min;
  2146.         var last = ranges[index].max;
  2147.         result += FA._appendRangeCharTo(String.fromCodePoint(first));
  2148.         if (last === first) return result;
  2149.         if (last === first + 1) // spit out 1 and 2 length ranges as flat chars
  2150.         {
  2151.             result += FA._appendRangeCharTo(String.fromCodePoint(last));
  2152.             return result;
  2153.         }
  2154.         else if (last === first + 2) {
  2155.             result += FA._appendRangeCharTo(String.fromCodePoint(first + 1));
  2156.             result += FA._appendRangeCharTo(String.fromCodePoint(last));
  2157.             return result;
  2158.         }
  2159.         result += "-";
  2160.         result += FA._appendRangeCharTo(String.fromCodePoint(last));
  2161.         return result;
  2162.     }
  2163.     private static _appendCharTo(ch: string): string {
  2164.         let result: string = "";
  2165.         switch (ch) {
  2166.             case '.':
  2167.             case '[':
  2168.             case ']':
  2169.             case '^':
  2170.             case '-':
  2171.             case '+':
  2172.             case '?':
  2173.             case '(':
  2174.             case ')':
  2175.             case '\\':
  2176.                 result += '\\';
  2177.                 result += ch;
  2178.                 break;
  2179.             case '\t':
  2180.                 result += "\\t";
  2181.                 break;
  2182.             case '\n':
  2183.                 result += "\\n";
  2184.                 break;
  2185.             case '\r':
  2186.                 result += "\\r";
  2187.                 break;
  2188.             case '\0':
  2189.                 result += "\\0";
  2190.                 break;
  2191.             case '\f':
  2192.                 result += "\\f";
  2193.                 break;
  2194.             case '\v':
  2195.                 result += "\\v";
  2196.                 break;
  2197.             case '\b':
  2198.                 result += "\\b";
  2199.                 break;
  2200.             default:
  2201.                 const s: string = ch;
  2202.                 const isletter: boolean = s.toLowerCase() != s.toUpperCase();
  2203.                 const isdigit = !isletter && (s >= '0' && s <= '9');
  2204.                 const issym = !isletter && !isdigit && ",._-<>/\\=+~`!@#$%^&*(){}[]\"\';:?".indexOf(s) > -1;
  2205.                 if (!isletter && !isdigit && !issym) {
  2206.                     if (s.length == 1) {
  2207.                         result += "\\u";
  2208.                         const d: number = s.codePointAt(0);
  2209.                         result += ("0000" + (+d).toString(16)).slice(-4);
  2210.                     }
  2211.                     else {
  2212.                         result += "\\U";
  2213.                         const d: number = s.codePointAt(0);
  2214.                         result += ("00000000" + (+d).toString(16)).slice(-8);
  2215.                     }
  2216.  
  2217.                 }
  2218.                 else {
  2219.                     result += s;
  2220.                 }
  2221.                 break;
  2222.         }
  2223.         return result;
  2224.     }
  2225.  
  2226.     private static _appendRangeCharTo(ch: string): string {
  2227.         let result: string = "";
  2228.         switch (ch) {
  2229.             case '.':
  2230.             case '[':
  2231.             case ']':
  2232.             case '^':
  2233.             case '-':
  2234.             case '(':
  2235.             case ')':
  2236.             case '{':
  2237.             case '}':
  2238.             case '\\':
  2239.                 result += '\\';
  2240.                 result += ch;
  2241.                 break;
  2242.             case '\t':
  2243.                 result += "\\t";
  2244.                 break;
  2245.             case '\n':
  2246.                 result += "\\n";
  2247.                 break;
  2248.             case '\r':
  2249.                 result += "\\r";
  2250.                 break;
  2251.             case '\0':
  2252.                 result += "\\0";
  2253.                 break;
  2254.             case '\f':
  2255.                 result += "\\f";
  2256.                 break;
  2257.             case '\v':
  2258.                 result += "\\v";
  2259.                 break;
  2260.             case '\b':
  2261.                 result += "\\b";
  2262.                 break;
  2263.             default:
  2264.                 const s: string = ch;
  2265.                 const isletter: boolean = s.toLowerCase() != s.toUpperCase();
  2266.                 const isdigit = !isletter && (s >= '0' && s <= '9');
  2267.                 const issym = !isletter && !isdigit && ",._-<>/\\=+~`!@#$%^&*(){}[]\"\';:?".indexOf(s) > -1;
  2268.                 if (!isletter && !isdigit && !issym) {
  2269.                     if (s.length == 1) {
  2270.                         result += "\\u";
  2271.                         const d: number = s.codePointAt(0);
  2272.                         result += ("0000" + (+d).toString(16)).slice(-4);
  2273.                     }
  2274.                     else {
  2275.                         result += "\\U";
  2276.                         const d: number = s.codePointAt(0);
  2277.                         result += ("00000000" + (+d).toString(16)).slice(-8);
  2278.                     }
  2279.  
  2280.                 }
  2281.                 else
  2282.                     result += s;
  2283.                 break;
  2284.         }
  2285.         return result;
  2286.     }
  2287.     private static _escapeLabel(label: string): string {
  2288.         if (label === null || label.length == 0) return label;
  2289.         let result: string = label.replace("\\", "\\\\");
  2290.         result = result.replace("\"", "\\\"");
  2291.         result = result.replace("\n", "\\n");
  2292.         result = result.replace("\r", "\\r");
  2293.         result = result.replace("\0", "\\0");
  2294.         result = result.replace("\v", "\\v");
  2295.         result = result.replace("\t", "\\t");
  2296.         result = result.replace("\f", "\\f");
  2297.         return result;
  2298.     }
  2299.     private _buildDot(closure: FA[], options: FADotGraphOptions, clusterIndex: number): string {
  2300.         let result: string = "";
  2301.         if (options === null) {
  2302.             options = new FADotGraphOptions();
  2303.         }
  2304.         const hasBlockEnds: boolean = options.debugShowNfa === false && options.debugString === null && options.blockEnds !== null;
  2305.         const spfx: string = options.statePrefix === null ? "q" : options.statePrefix;
  2306.         let pfx: string = "";
  2307.         if (clusterIndex !== -1) {
  2308.             result += ("subgraph cluster_" + clusterIndex.toString(10) + " {\n");
  2309.             pfx = "c" + clusterIndex.toString(10);
  2310.         } else {
  2311.             result += "digraph FA {\n";
  2312.         }
  2313.         if (!options.vertical) {
  2314.             result += "rankdir=LR\n";
  2315.         }
  2316.         result += "node [shape=circle]\n";
  2317.         let accepting: FA[] = [];
  2318.         let finals: FA[] = [];
  2319.         let neutrals: FA[] = [];
  2320.         for (let i: number = 0; i < closure.length; ++i) {
  2321.             let ffa = closure[i];
  2322.             if (ffa.isAccepting()) {
  2323.                 accepting.push(ffa);
  2324.             } else if (ffa.isNeutral()) {
  2325.                 neutrals.push(ffa);
  2326.             } else if (ffa.isFinal()) {
  2327.                 finals.push(ffa);
  2328.             }
  2329.         }
  2330.         let fromStates: FA[] = null;
  2331.         let toStates: FA[] = null;
  2332.         let tchar: number = -1;
  2333.         if (options.debugString != null) {
  2334.             for (let ch of FA.toUtf32(options.debugString)) {
  2335.                 if (fromStates === null) {
  2336.                     fromStates = [];
  2337.                     closure[0].fillEpsilonClosure(fromStates);
  2338.                 } else {
  2339.                     fromStates = toStates;
  2340.                 }
  2341.                 tchar = ch;
  2342.                 toStates = FA.fillMove(fromStates, ch);
  2343.                 if (0 == toStates.length) {
  2344.                     break;
  2345.                 }
  2346.             }
  2347.         }
  2348.         if (fromStates == null) {
  2349.             fromStates = [];
  2350.             closure[0].fillEpsilonClosure(fromStates);
  2351.         }
  2352.         if (toStates != null) {
  2353.             toStates = FA.fillEpsilonClosureStates(toStates);
  2354.         }
  2355.         let i: number = 0;
  2356.         for (const ffa of closure) {
  2357.             const isfrom: boolean = fromStates !== null && FA.fillEpsilonClosureStates(fromStates).includes(ffa);
  2358.             const rngGrps: Map<FA, FARange[]> = ffa.fillInputTransitionRangesGroupedByState();
  2359.             for (const rngGrp of rngGrps) {
  2360.                 const istrns: boolean = isfrom && toStates !== null && options.debugString !== null && toStates.includes(rngGrp[0]);
  2361.                 const di: number = closure.indexOf(rngGrp[0]);
  2362.                 result += (pfx + spfx);
  2363.                 result += i.toString(10);
  2364.                 result += "->";
  2365.                 result += (pfx + spfx);
  2366.                 result += di.toString(10);
  2367.                 result += " [label=\"";
  2368.                 let sb: string;
  2369.                 let notRanges: FARange[] = Array.from(FA._invertRanges(rngGrp[1]));
  2370.                 if (notRanges.length > rngGrp[1].length) {
  2371.                     sb = FA._appendRangeTo(rngGrp[1]);
  2372.                 } else {
  2373.                     result += "^";
  2374.                     sb = FA._appendRangeTo(notRanges);
  2375.                 }
  2376.                 if (sb.length != 1 || sb === " ") {
  2377.                     result += '[';
  2378.                     if (sb.length > 16) {
  2379.                         sb = sb.substring(0, 16);
  2380.                         sb += "...";
  2381.                     }
  2382.                     result += FA._escapeLabel(sb);
  2383.                     result += "]";
  2384.                 } else {
  2385.                     result += FA._escapeLabel(sb);
  2386.                 }
  2387.                 if (!istrns) {
  2388.                     result += "\"]\n";
  2389.                 } else {
  2390.                     result += "\",color=green]\n";
  2391.                 }
  2392.             }
  2393.             // do epsilons
  2394.             for (const fat of ffa.transitions) {
  2395.                 if (fat.isEpsilon()) {
  2396.                     var istrns = null != toStates && options.debugString != null && toStates.includes(ffa) && toStates.includes(fat.to);
  2397.                     result += (pfx + spfx);
  2398.                     result += i.toString(10);
  2399.                     result += "->";
  2400.                     result += (pfx + spfx);
  2401.                     result += (closure.indexOf(fat.to)).toString(10);
  2402.                     if (!istrns) {
  2403.                         result += " [style=dashed,color=gray]\n";
  2404.                     } else {
  2405.                         result += " [style=dashed,color=green]\n";
  2406.                     }
  2407.                 }
  2408.             }
  2409.             // do block ends
  2410.             if (hasBlockEnds && ffa.isAccepting && options.blockEnds?.length > ffa.acceptSymbol && options.blockEnds[ffa.acceptSymbol] !== null) {
  2411.                 result += (pfx + spfx + i.toString(10) + "->");
  2412.                 result += (pfx + "blockEnd" + ffa.acceptSymbol.toString(10) + spfx + "0");
  2413.                 result += (" [style=dashed,label=\".*?\"]\n");
  2414.             }
  2415.             ++i;
  2416.         }
  2417.         let delim: string;
  2418.         if (hasBlockEnds) {
  2419.             for (i = 0; i < options.blockEnds?.length; ++i) {
  2420.                 const bfa: FA = options.blockEnds[i];
  2421.                 if (bfa !== null) {
  2422.                     const bclose = bfa.fillClosure();
  2423.                     delim = "";
  2424.                     for (let qi: number = 0; qi < bclose.length; ++qi) {
  2425.                         const cbfa: FA = bclose[qi];
  2426.                         const rngGrps = cbfa.fillInputTransitionRangesGroupedByState();
  2427.                         for (const rngGrp of rngGrps) {
  2428.                             const di: number = bclose.indexOf(rngGrp[0]);
  2429.                             result += (pfx + "blockEnd" + i.toString(10) + spfx + qi.toString(10));
  2430.                             result += "->";
  2431.                             result += (pfx + "blockEnd" + i.toString(10) + spfx + di.toString(10));
  2432.                             result += " [label=\"";
  2433.                             let sb: string = FA._appendRangeTo(rngGrp[1]);
  2434.                             if (sb.length != 1 || sb === " ") {
  2435.                                 result += "[";
  2436.                                 if (sb.length > 16) {
  2437.                                     sb = sb.substring(0, 16);
  2438.                                     sb += "...";
  2439.                                 }
  2440.                                 result += FA._escapeLabel(sb);
  2441.                                 result += "]";
  2442.                             } else {
  2443.                                 result += FA._escapeLabel(sb);
  2444.                             }
  2445.                             result += "\"]\n";
  2446.                         }
  2447.                         // do epsilons
  2448.                         for (const fat of cbfa.transitions) {
  2449.                             if (fat.isEpsilon()) {
  2450.                                 result += ("pfx" + "blockEnd" + i.toString(10) + spfx + qi.toString(10));
  2451.                                 result += "->";
  2452.                                 const di: number = bclose.indexOf(fat.to);
  2453.                                 result += ("pfx" + "blockEnd" + i.toString(10) + spfx + di.toString(10));
  2454.                                 result += " [style=dashed,color=gray]\n";
  2455.                             }
  2456.                         }
  2457.                     }
  2458.                     for (let qi: number = 0; qi < bclose.length; ++qi) {
  2459.                         const cbfa: FA = bclose[qi];
  2460.                         result += (pfx + "blockEnd" + i.toString(10) + spfx + qi.toString(10) + " [label=<");
  2461.                         result += "<TABLE BORDER=\"0\"><TR><TD>";
  2462.                         result += ("(be)" + spfx);
  2463.                         result += "<SUB>";
  2464.                         result += qi.toString(10);
  2465.                         result += "</SUB></TD></TR>";
  2466.                         if (cbfa.isAccepting() && !options.hideAcceptSymbolIds) {
  2467.                             result += "<TD><TD>";
  2468.                             let acc: string = null;
  2469.                             if (options.acceptSymbolNames != null && options.acceptSymbolNames.length > i) {
  2470.                                 acc = options.acceptSymbolNames[i];
  2471.                             }
  2472.                             if (acc === null) {
  2473.                                 acc = i.toString(10);
  2474.                             }
  2475.                             result += acc.replace("\"", "&quot;");
  2476.                             result += "</TD></TR>";
  2477.                         }
  2478.                         result += "</TABLE>";
  2479.                         result += ">";
  2480.                         if (cbfa.isAccepting()) {
  2481.                             result += ",shape=doublecircle";
  2482.                         } else if (cbfa.isFinal() || cbfa.isNeutral()) {
  2483.                             result += ",color=gray";
  2484.                         }
  2485.                         result += "]";
  2486.                     }
  2487.                 }
  2488.             }
  2489.         }
  2490.         delim = "";
  2491.         i = 0;
  2492.         for (const ffa of closure) {
  2493.             result += (pfx + spfx);
  2494.             result += i.toString(10);
  2495.             result += " [";
  2496.             if (options.debugString !== null) {
  2497.                 if (toStates !== null) {
  2498.                     const epstates: FA[] = FA.fillEpsilonClosureStates(toStates, null);
  2499.                     if (epstates.includes(ffa)) {
  2500.                         if (!toStates.includes(ffa)) {
  2501.                             result += "color=darkgreen,"
  2502.                         } else {
  2503.                             result += "color=greeen,";
  2504.                         }
  2505.                     }
  2506.                 }
  2507.             }
  2508.             result += "label=<";
  2509.             result += "<TABLE BORDER=\"0\"><TR><TD>";
  2510.             result += spfx;
  2511.             result += "<SUB>";
  2512.             result += i.toString(10);
  2513.             result += "</SUB></TD></TR>";
  2514.             if (options.debugSourceNfa !== null) {
  2515.                 const from: FA[] = ffa.fromStates;
  2516.                 let brk: number = Math.floor(Math.sqrt(from.length));
  2517.                 if (from.length <= 3) brk = 3;
  2518.                 for (let j: number = 0; j < from.length; ++j) {
  2519.                     if (j === 0) {
  2520.                         result += "<TR><TD>";
  2521.                         result += "{ ";
  2522.                         delim = "";
  2523.                     } else if ((j % brk) == 0) {
  2524.                         delim = "";
  2525.                         result += "</TD></TR><TR><TD>";
  2526.                     }
  2527.                     const fromFa: FA = from[j];
  2528.                     result += delim;
  2529.                     result += "q<SUB>";
  2530.                     result += options.debugSourceNfa.fillClosure().indexOf(fromFa).toString(10);
  2531.                     result += "</SUB>";
  2532.                     delim = " ";
  2533.                     if (j === from.length - 1) {
  2534.                         result += " }";
  2535.                         result += "</TD></TR>";
  2536.                     }
  2537.                 }
  2538.             }
  2539.             if (ffa.isAccepting() && !options.hideAcceptSymbolIds && !(hasBlockEnds && options.blockEnds?.length > ffa.acceptSymbol && options.blockEnds[ffa.acceptSymbol] !== null)) {
  2540.                 result += "<TR><TD>";
  2541.                 let acc: string = null;
  2542.                 if (options.acceptSymbolNames !== null && options.acceptSymbolNames.length > ffa.acceptSymbol) {
  2543.                     acc = options.acceptSymbolNames[ffa.acceptSymbol];
  2544.                 }
  2545.                 if (acc === null) {
  2546.                     acc = ffa.acceptSymbol.toString(10);
  2547.                 }
  2548.                 result += acc.replace("\"", "&quot;");
  2549.                 result += "</TD></TR>";
  2550.             }
  2551.             result += "</TABLE>";
  2552.             result += ">";
  2553.             let isFinal: boolean = false;
  2554.             if (accepting.includes(ffa) && ((!hasBlockEnds || options.blockEnds?.length <= ffa.acceptSymbol || options.blockEnds[ffa.acceptSymbol] === null))) {
  2555.                 result += ",shape=doublecircle";
  2556.             } else if (isFinal || neutrals.includes(ffa)) {
  2557.                 if ((fromStates === null || !fromStates.includes(ffa)) &&
  2558.                     (toStates === null) || !toStates.includes(ffa)) {
  2559.                     result += ",color=gray";
  2560.                 }
  2561.             }
  2562.             result += "]\n";
  2563.             ++i;
  2564.         }
  2565.         delim = "";
  2566.         if (accepting.length > 0) {
  2567.             for (const ntfa of accepting) {
  2568.                 if (!hasBlockEnds || options.blockEnds?.length <= ntfa.acceptSymbol || options.blockEnds[ntfa.acceptSymbol] === null) {
  2569.                     result += delim;
  2570.                     result += (pfx + spfx);
  2571.                     result += closure.indexOf(ntfa).toString(10);
  2572.                     delim = ",";
  2573.                 }
  2574.             }
  2575.             if (delim != "") {
  2576.                 result += " [shape=doublecircle]\n";
  2577.             }
  2578.         }
  2579.         delim = "";
  2580.         if (neutrals.length > 0) {
  2581.             for (const ntfa of neutrals) {
  2582.                 if ((fromStates === null || !fromStates.includes(ntfa)) &&
  2583.                     (toStates == null || !toStates.includes(ntfa))) {
  2584.                     result += delim;
  2585.                     result += (pfx + spfx);
  2586.                     result += closure.indexOf(ntfa).toString(10);
  2587.                     delim = ",";
  2588.                 }
  2589.             }
  2590.             result += " [color=gray]\n";
  2591.             delim = "";
  2592.         }
  2593.         delim = "";
  2594.         if (finals.length > 0) {
  2595.             for (const ntfa of finals) {
  2596.                 result += delim;
  2597.                 result += (pfx + spfx);
  2598.                 result += closure.indexOf(ntfa).toString(10);
  2599.                 delim = ",";
  2600.             }
  2601.             result += " [shape=circle,color=gray]\n";
  2602.         }
  2603.         result += "}\n";
  2604.         return result;
  2605.     }
  2606.     private _buildCompoundDot(closure: FA[], options: FADotGraphOptions): string {
  2607.         let result: string = "digraph FA {\n";
  2608.         let vert: boolean = true;
  2609.         if (!options.vertical) {
  2610.             result += "rank=LR\n";
  2611.         }
  2612.         result += "node [shape=circle]\n";
  2613.         const opt2: FADotGraphOptions = new FADotGraphOptions();
  2614.         opt2.debugSourceNfa = null;
  2615.         opt2.statePrefix = options.statePrefix;
  2616.         opt2.debugString = options.debugString;
  2617.         opt2.debugShowNfa = false;
  2618.         opt2.dpi = options.dpi;
  2619.         opt2.acceptSymbolNames = options.acceptSymbolNames;
  2620.         opt2.hideAcceptSymbolIds = options.hideAcceptSymbolIds;
  2621.         opt2.blockEnds = options.blockEnds;
  2622.         if (!vert) {
  2623.             result += this._buildDot(closure, options, 2);
  2624.             result += this._buildDot(options.debugSourceNfa.fillClosure(), opt2, 1);
  2625.         } else {
  2626.             result += this._buildDot(options.debugSourceNfa.fillClosure(), opt2, 2);
  2627.             result += this._buildDot(closure, options, 1);
  2628.         }
  2629.         result += "}\n";
  2630.         return result;
  2631.     }
  2632.     static _normalizeSortedRangeList(pairs: FARange[]) : void
  2633.     {
  2634.         for (let i: number = 1; i < pairs.length; ++i)
  2635.         {
  2636.             if (pairs[i - 1].max + 1 >= pairs[i].min)
  2637.             {
  2638.                 const nr: FARange = new FARange(pairs[i - 1].min, pairs[i].max);
  2639.                 pairs[i - 1] = nr;
  2640.                 pairs.splice(i,1);
  2641.                 --i; // compensated for by ++i in for loop
  2642.             }
  2643.         }
  2644.     }
  2645.     static _fromHexChar(hex: number): number {
  2646.         if (':'.codePointAt(0) > hex && '/'.codePointAt(0) < hex)
  2647.             return (hex - '0'.codePointAt(0));
  2648.         if ('G'.codePointAt(0) > hex && '@'.codePointAt(0) < hex)
  2649.             return (hex - '7'.codePointAt(0)); // 'A'-10
  2650.         if ('g'.codePointAt(0) > hex && '`'.codePointAt(0) < hex)
  2651.             return (hex - 'W'.codePointAt(0)); // 'a'-10
  2652.         throw "The value was not hex.";
  2653.     }
  2654.     static _isHexChar(hex: number): boolean {
  2655.         if (':'.charCodeAt(0) > hex && '/'.codePointAt(0) < hex)
  2656.             return true;
  2657.         if ('G'.codePointAt(0) > hex && '@'.codePointAt(0) < hex)
  2658.             return true;
  2659.         if ('g'.codePointAt(0) > hex && '`'.codePointAt(0) < hex)
  2660.             return true;
  2661.         return false;
  2662.     }
  2663.     static _parseModifier(expr: FA, pc: _ParseContext, accept: number, compact: boolean): FA
  2664.     {
  2665.         var position = pc.position;
  2666.         switch (pc.codepoint)
  2667.         {
  2668.             case '*'.codePointAt(0):
  2669.                 expr = FA.repeat(expr, 0, 0, accept, compact);
  2670.                 pc.advance();
  2671.                 break;
  2672.             case '+'.codePointAt(0):
  2673.                 expr = FA.repeat(expr, 1, 0, accept, compact);
  2674.                 pc.advance();
  2675.                 break;
  2676.             case '?'.codePointAt(0):
  2677.                 expr = FA.optional(expr, accept, compact);
  2678.                 pc.advance();
  2679.                 break;
  2680.             case '{'.codePointAt(0):
  2681.                 pc.advance();
  2682.                 pc.trySkipWhiteSpace();
  2683.                 pc.expecting('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '}');
  2684.                 var min = -1;
  2685.                 var max = -1;
  2686.                 if (','.codePointAt(0) != pc.codepoint && '}'.codePointAt(0) != pc.codepoint)
  2687.                 {
  2688.                     var l = pc.capture_buffer.length;
  2689.                     if (!pc.tryReadDigits())
  2690.                     {
  2691.                         pc.expecting('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
  2692.                     }
  2693.                     min = Number.parseFloat(pc.capture_buffer.substring(l));
  2694.                     pc.trySkipWhiteSpace();
  2695.                 }
  2696.                 if (','.codePointAt(0) == pc.codepoint)
  2697.                 {
  2698.                     pc.advance();
  2699.                     pc.trySkipWhiteSpace();
  2700.                     pc.expecting('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '}');
  2701.                     if ('}'.charCodeAt(0) != pc.codepoint)
  2702.                     {
  2703.                         var l = pc.capture_buffer.length;
  2704.                         pc.tryReadDigits();
  2705.                         max = Number.parseFloat(pc.capture_buffer.substring(l));
  2706.                         pc.trySkipWhiteSpace();
  2707.                     }
  2708.                 }
  2709.                 else { max = min; }
  2710.                 pc.expecting('}');
  2711.                 pc.advance();
  2712.                 expr = FA.repeat(expr, min, max, accept, compact);
  2713.                 break;
  2714.         }
  2715.         return expr;
  2716.     }
  2717.     static _parseEscapePart(pc : _ParseContext) : number
  2718.     {
  2719.         if (-1 == pc.codepoint) return -1;
  2720.         switch (String.fromCodePoint(pc.codepoint))
  2721.         {
  2722.             case 'f':
  2723.                 pc.advance();
  2724.                 return '\f'.codePointAt(0);
  2725.             case 'v':
  2726.                 pc.advance();
  2727.                 return '\v'.codePointAt(0);
  2728.             case 't':
  2729.                 pc.advance();
  2730.                 return '\t'.codePointAt(0);
  2731.             case 'n':
  2732.                 pc.advance();
  2733.                 return '\n'.codePointAt(0);
  2734.             case 'r':
  2735.                 pc.advance();
  2736.                 return '\r'.codePointAt(0);
  2737.             case 'x':
  2738.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2739.                     return 'x'.codePointAt(0);
  2740.                 let b: number = FA._fromHexChar(pc.codepoint);
  2741.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2742.                     return b;
  2743.                 b <<= 4;
  2744.                 b |= FA._fromHexChar(pc.codepoint);
  2745.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2746.                     return b;
  2747.                 b <<= 4;
  2748.                 b |= FA._fromHexChar(pc.codepoint);
  2749.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2750.                     return b;
  2751.                 b <<= 4;
  2752.                 b |= FA._fromHexChar(pc.codepoint);
  2753.                 return b;
  2754.             case 'u':
  2755.                 if (-1 == pc.advance())
  2756.                     return 'u'.codePointAt(0);
  2757.                 let u: number = FA._fromHexChar(pc.codepoint);
  2758.                 u <<= 4;
  2759.                 if (-1 == pc.advance())
  2760.                     return u;
  2761.                 u |= FA._fromHexChar(pc.codepoint);
  2762.                 u <<= 4;
  2763.                 if (-1 == pc.advance())
  2764.                     return u;
  2765.                 u |= FA._fromHexChar(pc.codepoint);
  2766.                 u <<= 4;
  2767.                 if (-1 == pc.advance())
  2768.                     return u;
  2769.                 u |= FA._fromHexChar(pc.codepoint);
  2770.                 return u;
  2771.             default:
  2772.                 const i: number = pc.codepoint;
  2773.                 pc.advance();
  2774.                 return i;
  2775.         }
  2776.     }
  2777.     static _parseRangeEscapePart(pc: _ParseContext) : number
  2778.     {
  2779.         if (-1 == pc.codepoint)
  2780.             return -1;
  2781.         switch (String.fromCodePoint(pc.codepoint))
  2782.         {
  2783.             case '0':
  2784.                 pc.advance();
  2785.                 return '\0'.codePointAt(0);
  2786.             case 'f':
  2787.                 pc.advance();
  2788.                 return '\f'.codePointAt(0);
  2789.             case 'v':
  2790.                 pc.advance();
  2791.                 return '\v'.codePointAt(0);
  2792.             case 't':
  2793.                 pc.advance();
  2794.                 return '\t'.codePointAt(0);
  2795.             case 'n':
  2796.                 pc.advance();
  2797.                 return '\n'.codePointAt(0);
  2798.             case 'r':
  2799.                 pc.advance();
  2800.                 return '\r'.codePointAt(0);
  2801.             case 'x':
  2802.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2803.                     return 'x'.codePointAt(0);
  2804.                 let b: number = FA._fromHexChar(pc.codepoint);
  2805.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2806.                     return b;
  2807.                 b <<= 4;
  2808.                 b |= FA._fromHexChar(pc.codepoint);
  2809.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2810.                     return b;
  2811.                 b <<= 4;
  2812.                 b |= FA._fromHexChar(pc.codepoint);
  2813.                 if (-1 == pc.advance() || !FA._isHexChar(pc.codepoint))
  2814.                     return b;
  2815.                 b <<= 4;
  2816.                 b |= FA._fromHexChar(pc.codepoint);
  2817.                 return b;
  2818.             case 'u':
  2819.                 if (-1 == pc.advance())
  2820.                     return 'u'.codePointAt(0);
  2821.                 let u: number = FA._fromHexChar(pc.codepoint);
  2822.                 u <<= 4;
  2823.                 if (-1 == pc.advance())
  2824.                     return u;
  2825.                 u |= FA._fromHexChar(pc.codepoint);
  2826.                 u <<= 4;
  2827.                 if (-1 == pc.advance())
  2828.                     return u;
  2829.                 u |= FA._fromHexChar(pc.codepoint);
  2830.                 u <<= 4;
  2831.                 if (-1 == pc.advance())
  2832.                     return u;
  2833.                 u |= FA._fromHexChar(pc.codepoint);
  2834.                 return u;
  2835.             default:
  2836.                 const i: number = pc.codepoint;
  2837.                 pc.advance();
  2838.                 return i;
  2839.         }
  2840.     }
  2841.     static _parseSet(pc: _ParseContext) : [boolean, FARange[]]
  2842.     {
  2843.         const result: FARange[] = new Array<FARange>();
  2844.         pc.ensureStarted();
  2845.         pc.expecting('[');
  2846.         pc.advance();
  2847.         pc.expecting();
  2848.         let firstRead: boolean = true;
  2849.         let firstChar: number = 0;
  2850.         let readFirstChar: boolean = false;
  2851.         let wantRange: boolean = false;
  2852.    
  2853.         var isNot = false;
  2854.         if ('^' == String.fromCodePoint(pc.codepoint))
  2855.         {
  2856.             isNot = true;
  2857.             pc.advance();
  2858.             pc.expecting();
  2859.         }
  2860.         while (-1 != pc.codepoint && (firstRead || ']' != String.fromCodePoint(pc.codepoint)))
  2861.         {
  2862.             if (!wantRange)
  2863.             {
  2864.                 // can be a single char,
  2865.                 // a range
  2866.                 // or a named character class
  2867.                 if ('[' == String.fromCodePoint(pc.codepoint)) // named char class
  2868.                 {
  2869.                     const epos: number = pc.position;
  2870.                     pc.advance();
  2871.                     pc.expecting();
  2872.                     if (':' != String.fromCodePoint(pc.codepoint))
  2873.                     {
  2874.                         firstChar = '['.codePointAt(0);
  2875.                         readFirstChar = true;
  2876.                     }
  2877.                     else
  2878.                     {
  2879.                         firstRead = false;
  2880.                         pc.advance();
  2881.                         pc.expecting();
  2882.                         var ll = pc.capture_buffer.length;
  2883.                         if (!pc.tryReadUntil(':'.codePointAt(0), false))
  2884.                             throw "Expecting character class at "+pc.position;
  2885.                         pc.expecting(':');
  2886.                         pc.advance();
  2887.                         pc.expecting(']');
  2888.                         pc.advance();
  2889.                         var cls = pc.capture_buffer.substring(ll);
  2890.                         let ranges: number[] = null;
  2891.                         if (!FACharacterClasses.known().has(cls))
  2892.                             throw "Unknown character class \"" + cls + "\" specified at "+ epos;
  2893.                         ranges = FACharacterClasses.known().get(cls);
  2894.                         if (ranges != null) {
  2895.                             result.push(...FARange.toUnpacked(ranges));
  2896.                         }
  2897.                         readFirstChar = false;
  2898.                         wantRange = false;
  2899.                         firstRead = false;
  2900.                         continue;
  2901.                     }
  2902.                 }
  2903.                 if (!readFirstChar)
  2904.                 {
  2905.                     if ('\\' == String.fromCodePoint(pc.codepoint))
  2906.                     {
  2907.                         pc.advance();
  2908.                         firstChar = FA._parseRangeEscapePart(pc);
  2909.                     }
  2910.                     else
  2911.                     {
  2912.                         firstChar = pc.codepoint;
  2913.                         pc.advance();
  2914.                         pc.expecting();
  2915.                     }
  2916.                     readFirstChar = true;
  2917.                 }
  2918.                 else
  2919.                 {
  2920.                     if ('-' == String.fromCodePoint(pc.codepoint))
  2921.                     {
  2922.                         pc.advance();
  2923.                         pc.expecting();
  2924.                         wantRange = true;
  2925.                     }
  2926.                     else
  2927.                     {
  2928.                         result.push(new FARange(firstChar, firstChar));
  2929.                         readFirstChar = false;
  2930.                     }
  2931.                 }
  2932.                 firstRead = false;
  2933.             }
  2934.             else
  2935.             {
  2936.                 if ('\\' != String.fromCodePoint(pc.codepoint))
  2937.                 {
  2938.                     const ch: number = pc.codepoint;
  2939.                     pc.advance();
  2940.                     pc.expecting();
  2941.                     result.push(new FARange(firstChar, ch));
  2942.                 }
  2943.                 else
  2944.                 {
  2945.                     var min = firstChar;
  2946.                     pc.advance();
  2947.                     result.push(new FARange(min, FA._parseRangeEscapePart(pc)));
  2948.                 }
  2949.                 wantRange = false;
  2950.                 readFirstChar = false;
  2951.             }
  2952.    
  2953.         }
  2954.         if (readFirstChar)
  2955.         {
  2956.             result.push(new FARange(firstChar, firstChar));
  2957.             if (wantRange)
  2958.             {
  2959.                 result.push(new FARange('-'.codePointAt(0), '-'.codePointAt(0)));
  2960.             }
  2961.         }
  2962.         pc.expecting(']');
  2963.         pc.advance();
  2964.         return [isNot, result];
  2965.     }
  2966.     private static _parse(pc: _ParseContext, accept: number = 0, compact: boolean = true): FA {
  2967.         let result: FA = null;
  2968.         let next: FA = null;
  2969.         let ich: number;
  2970.         pc.ensureStarted();
  2971.         while (pc.codepoint!==-1)
  2972.         {
  2973.             switch (pc.codepoint)
  2974.             {
  2975.                 case -1:
  2976.                     if (result == null)
  2977.                     {
  2978.                         // empty string
  2979.                         result = new FA(accept);
  2980.                     }
  2981.                     return result;
  2982.                 case '.'.codePointAt(0):
  2983.                     const dot: FA = FA.set([ new FARange(0, 0x10ffff) ], accept, compact);
  2984.                     if (null == result)
  2985.                         result = dot;
  2986.                     else
  2987.                     {
  2988.                         result = FA.concat([result, dot ], accept, compact);
  2989.                     }
  2990.                     pc.advance();
  2991.                     result = FA._parseModifier(result, pc, accept, compact);
  2992.                     break;
  2993.                 case '\\'.codePointAt(0):
  2994.  
  2995.                     pc.advance();
  2996.                     pc.expecting();
  2997.                     var isNot = false;
  2998.                     switch (pc.codepoint)
  2999.                     {
  3000.                         case 'P'.codePointAt(0):
  3001.                             isNot = true;
  3002.                             // fallthrough
  3003.                         case 'p'.codePointAt(0):
  3004.                             pc.advance();
  3005.                             pc.expecting('{');
  3006.                             let uc: string = "";
  3007.                             while (-1 != pc.advance() && '}' != String.fromCodePoint(pc.codepoint))
  3008.                                 uc+=(String.fromCodePoint(pc.codepoint));
  3009.                             pc.expecting('}');
  3010.                             pc.advance();
  3011.                             let uci: number = 0;
  3012.                             switch (uc)
  3013.                             {
  3014.                                 case "Pe":
  3015.                                     uci = 21;
  3016.                                     break;
  3017.                                 case "Pc":
  3018.                                     uci = 19;
  3019.                                     break;
  3020.                                 case "Cc":
  3021.                                     uci = 14;
  3022.                                     break;
  3023.                                 case "Sc":
  3024.                                     uci = 26;
  3025.                                     break;
  3026.                                 case "Pd":
  3027.                                     uci = 19;
  3028.                                     break;
  3029.                                 case "Nd":
  3030.                                     uci = 8;
  3031.                                     break;
  3032.                                 case "Me":
  3033.                                     uci = 7;
  3034.                                     break;
  3035.                                 case "Pf":
  3036.                                     uci = 23;
  3037.                                     break;
  3038.                                 case "Cf":
  3039.                                     uci = 15;
  3040.                                     break;
  3041.                                 case "Pi":
  3042.                                     uci = 22;
  3043.                                     break;
  3044.                                 case "Nl":
  3045.                                     uci = 9;
  3046.                                     break;
  3047.                                 case "Zl":
  3048.                                     uci = 12;
  3049.                                     break;
  3050.                                 case "Ll":
  3051.                                     uci = 1;
  3052.                                     break;
  3053.                                 case "Sm":
  3054.                                     uci = 25;
  3055.                                     break;
  3056.                                 case "Lm":
  3057.                                     uci = 3;
  3058.                                     break;
  3059.                                 case "Sk":
  3060.                                     uci = 27;
  3061.                                     break;
  3062.                                 case "Mn":
  3063.                                     uci = 5;
  3064.                                     break;
  3065.                                 case "Ps":
  3066.                                     uci = 20;
  3067.                                     break;
  3068.                                 case "Lo":
  3069.                                     uci = 4;
  3070.                                     break;
  3071.                                 case "Cn":
  3072.                                     uci = 29;
  3073.                                     break;
  3074.                                 case "No":
  3075.                                     uci = 10;
  3076.                                     break;
  3077.                                 case "Po":
  3078.                                     uci = 24;
  3079.                                     break;
  3080.                                 case "So":
  3081.                                     uci = 28;
  3082.                                     break;
  3083.                                 case "Zp":
  3084.                                     uci = 13;
  3085.                                     break;
  3086.                                 case "Co":
  3087.                                     uci = 17;
  3088.                                     break;
  3089.                                 case "Zs":
  3090.                                     uci = 11;
  3091.                                     break;
  3092.                                 case "Mc":
  3093.                                     uci = 6;
  3094.                                     break;
  3095.                                 case "Cs":
  3096.                                     uci = 16;
  3097.                                     break;
  3098.                                 case "Lt":
  3099.                                     uci = 2;
  3100.                                     break;
  3101.                                 case "Lu":
  3102.                                     uci = 0;
  3103.                                     break;
  3104.                             }
  3105.                             if (isNot)
  3106.                             {
  3107.                                 next = FA.set(FARange.toUnpacked(FACharacterClasses.unicodeCategories[uci]), accept, compact);
  3108.                             }
  3109.                             else
  3110.                                 next = FA.set(FARange.toUnpacked(FACharacterClasses.notUnicodeCategories[uci]), accept, compact);
  3111.                             break;
  3112.                         case 'd'.codePointAt(0):
  3113.                             next = FA.set(FARange.toUnpacked(FACharacterClasses.digit), accept, compact);
  3114.                             pc.advance();
  3115.                             break;
  3116.                         case 'D'.codePointAt(0):
  3117.                             next = FA.set(FARange.toNotRanges(FARange.toUnpacked(FACharacterClasses.digit)), accept, compact);
  3118.                             pc.advance();
  3119.                             break;
  3120.                         case 's'.codePointAt(0):
  3121.                             next = FA.set(FARange.toUnpacked(FACharacterClasses.space), accept, compact);
  3122.                             pc.advance();
  3123.                             break;
  3124.                         case 'S'.codePointAt(0):
  3125.                             next = FA.set(FARange.toNotRanges(FARange.toUnpacked(FACharacterClasses.space)), accept, compact);
  3126.                             pc.advance();
  3127.                             break;
  3128.                         case 'w'.codePointAt(0):
  3129.                             next = FA.set(FARange.toUnpacked(FACharacterClasses.word), accept, compact);
  3130.                             pc.advance();
  3131.                             break;
  3132.                         case 'W'.codePointAt(0):
  3133.                             next = FA.set(FARange.toNotRanges(FARange.toUnpacked(FACharacterClasses.word)), accept, compact);
  3134.                             pc.advance();
  3135.                             break;
  3136.                         default:
  3137.                             if (-1 != (ich = FA._parseEscapePart(pc)))
  3138.                             {
  3139.                                 next = FA.literal([ ich ], accept, compact);
  3140.  
  3141.                             }
  3142.                             else
  3143.                             {
  3144.                                 pc.expecting(); // throw an error
  3145.                             }
  3146.                             break;
  3147.                     }
  3148.                     next = FA._parseModifier(next, pc, accept, compact);
  3149.                     if (null != result)
  3150.                     {
  3151.                         result = FA.concat([result, next], accept, compact);
  3152.                     }
  3153.                     else
  3154.                         result = next;
  3155.                     break;
  3156.                 case ')'.codePointAt(0):
  3157.                     return result;
  3158.                 case '('.codePointAt(0):
  3159.                     pc.advance();
  3160.                     if (String.fromCodePoint(pc.codepoint) == '?')
  3161.                     {
  3162.                         pc.advance();
  3163.                         pc.expecting(':');
  3164.                         pc.advance();
  3165.                     }
  3166.                     pc.expecting();
  3167.                     next = FA._parse(pc, accept, compact);
  3168.                     pc.expecting(')');
  3169.                     pc.advance();
  3170.                     next = FA._parseModifier(next, pc, accept, compact);
  3171.                     if (null == result)
  3172.                         result = next;
  3173.                     else
  3174.                     {
  3175.                         result = FA.concat([ result, next ], accept, compact);
  3176.                     }
  3177.                     break;
  3178.                 case '|'.codePointAt(0):
  3179.                     if (-1 != pc.advance())
  3180.                     {
  3181.                         next = FA._parse(pc, accept, compact);
  3182.                         result = FA.or([ result, next ], accept, compact);
  3183.                     }
  3184.                     else
  3185.                     {
  3186.                         result = FA.optional(result, accept, compact);
  3187.                     }
  3188.                     break;
  3189.                 case '['.codePointAt(0):
  3190.                     const seti = FA._parseSet(pc);
  3191.                     let set: FARange[] = seti[1];
  3192.                     set.sort((x, y) => { const c: number = x.min-y.min; if (0 != c) return c; return x.max-y.max; });
  3193.                     FA._normalizeSortedRangeList(set);
  3194.                     if (seti[0]===true) {
  3195.                         set = [...FARange.toNotRanges(set)];
  3196.                     }
  3197.                     next = FA.set(set, accept);
  3198.                     next = FA._parseModifier(next, pc, accept, compact);
  3199.                     if (null == result)
  3200.                         result = next;
  3201.                     else
  3202.                     {
  3203.                         result = FA.concat([ result, next ], accept, compact);
  3204.                     }
  3205.                     break;
  3206.                 default:
  3207.                     ich = pc.codepoint;
  3208.                     next = FA.literal([ ich ], accept, compact);
  3209.                     pc.advance();
  3210.                     next = FA._parseModifier(next, pc, accept, compact);
  3211.                     if (null == result)
  3212.                         result = next;
  3213.                     else
  3214.                     {
  3215.                         result = FA.concat([ result, next ], accept, compact);
  3216.                     }
  3217.                     break;
  3218.             }
  3219.         }
  3220.         return result;
  3221.     }
  3222.     public static parse(expression: string, accept: number = 0, compact: boolean = true) : FA {
  3223.         const pc = new _ParseContext(expression);
  3224.         return FA._parse(pc,accept,compact);
  3225.     }
  3226.     public static toLexer(tokens: FA[], makeDfa: boolean = true, compact: boolean = true, progress: FAProgress = null) : FA {
  3227.         if (makeDfa)
  3228.         {
  3229.             for (let i: number = 0; i < tokens.length; i++)
  3230.             {
  3231.                 tokens[i] = tokens[i].toMinimizedDfa(progress);
  3232.             }
  3233.         }
  3234.         var result = new FA();
  3235.         for (let i: number = 0; i < tokens.length; i++)
  3236.         {
  3237.             result.addEpsilon(tokens[i], compact);
  3238.         }
  3239.         if (makeDfa && !result.isDeterministic)
  3240.         {
  3241.             return result.toDfa(progress);
  3242.         }
  3243.         else
  3244.         {
  3245.             return result;
  3246.         }
  3247.     }
  3248. }
  3249. ///// Example
  3250. // console.log("Visual FA");
  3251. //
  3252. //for(const match of FA.toLexer([FA.parse("\\/\\*",0), FA.parse("[A-Z_a-z][A-Z_a-z0-9]*",1),FA.parse("[0-9]+",2)]).run("foo123 456 bar /* test */ baz789",[FA.parse("\\*\\/").toMinimizedDfa()])) {
  3253. //    console.log(match.toString());
  3254. //}
  3255.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement