Advertisement
honey_the_codewitch

beginning of DFA engine

Dec 26th, 2023 (edited)
1,290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. class FAInputContext {
  2.     input: Iterable<string>;
  3.     codepoint: number = -2;
  4.     position: number = 0;
  5.     line: number = 1;
  6.     column: number = 0;
  7.     tabWidth: number = 4;
  8.     constructor(input: string, tabWidth:number = 4, position: number = 0, line: number = 1, column: number = 0) {
  9.         this.input = input;
  10.         this.tabWidth = tabWidth;
  11.         this.position = position;
  12.         this.line = line;
  13.         this.column = column;
  14.     }
  15.  
  16.     advance(): number {
  17.         const it = this.input[Symbol.iterator]();
  18.         const n = it.next();
  19.         if(true===n.done) {
  20.             this.codepoint = -1;
  21.         } else {
  22.             this.codepoint = n.value.codePointAt(0)!;
  23.         }
  24.         switch (this.codepoint) {
  25.             case 10:
  26.                 ++this.line;
  27.                 this.column = 0;
  28.                 break;
  29.             case 13:
  30.                 this.column = 0;
  31.                 break;
  32.             case 9:
  33.                 this.column = (((this.column-1)/this.tabWidth)+1)*this.tabWidth+1;
  34.                 break;
  35.             default:
  36.                 if(this.codepoint>31)
  37.                     ++this.column;
  38.                 break;
  39.         }
  40.         ++this.position;
  41.         return this.codepoint;
  42.     }
  43. }
  44. class FARange {
  45.     min: number;
  46.     max: number;
  47.     constructor(min: number, max: number) {
  48.         this.min = min;
  49.         this.max = max;
  50.     }
  51.  
  52. }
  53. class FATransition {
  54.     min: number;
  55.     max: number;
  56.     to: FA;
  57.     constructor(min: number, max: number, to: FA) {
  58.         this.min = min;
  59.         this.max = max;
  60.         this.to = to;
  61.     }
  62. }
  63. class FA {
  64.     isDeterministic: boolean = true;
  65.     tag: number = -1;
  66.     acceptSymbol: number = -1;
  67.     id: number = -1;
  68.     transitions: FATransition[] = [];
  69.     fillClosure(result: FA[] = []): FA[] {
  70.         if (result.includes(this)) {
  71.             return result;
  72.         }
  73.         // add this instance
  74.         result.push(this);
  75.         // add sub instances
  76.         for (const transition of this.transitions) {
  77.             transition.to.fillClosure(result);
  78.         }
  79.         // Return the list of fa instances
  80.         return result;
  81.     }
  82.     isAccepting(): boolean {
  83.         return this.acceptSymbol > -1;
  84.     }
  85.     addEpsilon(to: FA): void {
  86.         this.isDeterministic = false;
  87.         if (to.isAccepting() && !this.isAccepting()) {
  88.             this.acceptSymbol = to.acceptSymbol;
  89.         }
  90.         for (const fat of to.transitions) {
  91.             this.transitions.push(new FATransition(fat.min,fat.max,fat.to));
  92.         }
  93.     }
  94.     private static _crackSet(str: string, closure:FA[]): FA[] {
  95.         const result : FA[] = [];
  96.         if(str=="") {
  97.             return result;
  98.         }
  99.         const sa: string[] = str.split(" ");
  100.         for(const s of sa) {
  101.             result.push(closure[Number.parseInt(s,10)]);
  102.         }
  103.         return result;
  104.     }
  105.     private static _makeSet(closure: FA[], states: Iterable<FA>): string {
  106.         let result: string = "";
  107.         let delim: string = "";
  108.         let ns : number[] = [];
  109.         for(const fa of states) {
  110.             const idx = closure.indexOf(fa);
  111.             ns.push(idx);
  112.         }
  113.         ns.sort((x,y)=>x-y);
  114.         for(const i of ns) {
  115.             result+=(delim+i.toString(10));
  116.             delim = " ";
  117.         }
  118.         return result;
  119.     }
  120.     toDfa(): FA {
  121.         const closure: FA[] = this.fillClosure();
  122.         const p: Set<number> = new Set<number>();
  123.         for (const ffa of closure) {
  124.             p.add(0);
  125.             for (const t of ffa.transitions) {
  126.                 p.add(t.min);
  127.                 if (t.max < 0x10ffff) {
  128.                     p.add(t.max + 1);
  129.                 }
  130.             }
  131.         }
  132.         const points: number[] = [...p];
  133.         points.sort((x, y) => x - y);
  134.         const sets: Map<string, Set<FA>> = new Map<string, Set<FA>>();
  135.         const working: string[] = [];
  136.         const dfaMap: Map<string, FA> = new Map<string, FA>();
  137.         let initial: string = "0";
  138.         sets.set(initial, new Set<FA>([this]));
  139.         working.push(initial);
  140.         const result: FA = new FA();
  141.         if(this.isAccepting()) {
  142.             result.acceptSymbol = this.acceptSymbol;
  143.         }
  144.         dfaMap.set(initial, result);
  145.         while (working.length > 0) {
  146.             const s: string = working[0];
  147.             working.shift();
  148.             const dfa: FA = dfaMap.get(s)!;
  149.             const crackedS1: FA[] = FA._crackSet(s,closure);
  150.             for (const q of crackedS1) {
  151.                 if (q.isAccepting()) {
  152.                     dfa.acceptSymbol = q.acceptSymbol;
  153.                     break;
  154.                 }
  155.             }
  156.             let i: number = 0;
  157.             for (const pnt of points) {
  158.                 const set: Set<FA> = new Set<FA>();
  159.                 for (const c of crackedS1) {
  160.                     for (let trns of c.transitions) {
  161.                         if (trns.min <= pnt && pnt <= trns.max) {
  162.                             set.add(trns.to);
  163.                         }
  164.                     }
  165.                 }
  166.                 const skey: string = FA._makeSet(closure,set);
  167.                 if (!sets.has(skey)) {
  168.                     sets.set(skey, set);
  169.                     working.push(skey);
  170.                     let newFa: FA = new FA();
  171.                     dfaMap.set(skey, newFa);
  172.                 }
  173.                 const dst: FA = dfaMap.get(skey)!;
  174.                 const first: number = pnt;
  175.                 let last: number;
  176.                 if (i + 1 < points.length) {
  177.                     last = points[i + 1] - 1;
  178.                 } else {
  179.                     last = 0x10ffff;
  180.                 }
  181.                 dfa.transitions.push(new FATransition(first, last, dst));
  182.                 ++i;
  183.             }
  184.         }
  185.         for (const ffa of result.fillClosure()) {
  186.             const itrns: FATransition[] = [...ffa.transitions];
  187.             for (const trns of itrns) {
  188.                 const acc: FA[] = trns.to.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  189.                 if (acc.length == 0) {
  190.                     ffa.transitions.splice(ffa.transitions.indexOf(trns), 1);
  191.                 }
  192.             }
  193.         }
  194.         return result;
  195.     }
  196.     clone(): FA {
  197.         const result: FA[] = [];
  198.         const closure = this.fillClosure();
  199.         for (let j = 0; j < closure.length; ++j) {
  200.             result.push(new FA());
  201.         }
  202.         let i: number = 0;
  203.         for (const fa of closure) {
  204.             result[i].isDeterministic = fa.isDeterministic;
  205.             result[i].acceptSymbol = fa.acceptSymbol;
  206.             result[i].tag = fa.tag;
  207.             for (const trns of fa.transitions) {
  208.                 result[i].transitions.push(new FATransition(trns.min, trns.max, result[closure.indexOf(trns.to)]));
  209.             }
  210.             ++i;
  211.         }
  212.         return result[0];
  213.     }
  214.     toString(): string {
  215.         if(this.id < 0) {
  216.             return "[FA]";
  217.         } else {
  218.             return "q"+this.id.toString();
  219.         }
  220.     }
  221.     setIds(): void {
  222.         let i: number = 0;
  223.         for(const fa of this.fillClosure()) {
  224.             fa.id = i;
  225.             ++i;
  226.         }
  227.     }
  228.     static literal(accept: number, codepoints: Iterable<number>): FA {
  229.         const result: FA = new FA();
  230.         let current: FA = result;
  231.         for (const cp of codepoints) {
  232.             current.acceptSymbol = -1;
  233.             const fa: FA = new FA();
  234.             fa.acceptSymbol = accept;
  235.             current.transitions.push(new FATransition(cp, cp, fa));
  236.             current = fa;
  237.         }
  238.         return result;
  239.     }
  240.     static set(accept: number, ranges: Iterable<FARange>): FA {
  241.         const result: FA = new FA();
  242.         const final: FA = new FA();
  243.         final.acceptSymbol = accept;
  244.         for (const range of [...ranges].sort((x, y) => x.max - y.max)) {
  245.             result.transitions.push(new FATransition(range.min, range.max, final));
  246.         }
  247.         return result;
  248.     }
  249.     static concat(accept: number, exprs: Iterable<FA>): FA {
  250.         let result: FA | null = null;
  251.         let left: FA | null = null;
  252.         let right: FA | null = null;
  253.         for (const expr of exprs) {
  254.             let nval = expr.clone();
  255.             if (null === left) {
  256.                 if (null === result) {
  257.                     result = nval;
  258.                 }
  259.                 left = nval;
  260.                 continue;
  261.                
  262.             }
  263.             if (null === right) {
  264.                 right = nval;
  265.             }
  266.             nval = right.clone();
  267.             FA._concat(left!, nval);
  268.         }
  269.         const target: FA = null !== right ? right! : result!;
  270.         const acc: FA[] = target.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  271.         for (const afa of acc) {
  272.             afa.acceptSymbol = accept;
  273.         }
  274.         return result!;
  275.     }
  276.     static or(accept: number, exprs: Iterable<FA>): FA {
  277.         const result: FA = new FA();
  278.         const final: FA = new FA();
  279.         final.acceptSymbol = accept;
  280.         for (const expr of exprs) {
  281.             const nfa = expr.clone();
  282.             const nacc: FA[] = nfa.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  283.             for (const afa of nacc) {
  284.                 afa.acceptSymbol = -1;
  285.                 afa.addEpsilon(final);
  286.             }
  287.             result.addEpsilon(nfa);
  288.         }
  289.         return result;
  290.     }
  291.     static optional(accept: number, expr: FA): FA {
  292.         const result: FA = expr.clone();
  293.         const acc: FA[] = result.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  294.         for (const afa of acc) {
  295.             afa.acceptSymbol = accept;
  296.             result.addEpsilon(afa);
  297.         }
  298.         return result;
  299.     }
  300.     static repeat(accept: number, expr: FA, minOccurs: number = -1, maxOccurs: number = -1): FA {
  301.         expr = expr.clone();
  302.         if (minOccurs > 0 && maxOccurs > 0 && minOccurs > maxOccurs) {
  303.             throw Error("Minimum is greater than maximum");
  304.         }
  305.         let result: FA;
  306.         switch (minOccurs) {
  307.             case -1:
  308.             case 0:
  309.                 switch (maxOccurs) {
  310.                     case -1:
  311.                     case 0:
  312.                         result = new FA();
  313.                         result.acceptSymbol = accept;
  314.                         result.addEpsilon(expr);
  315.                         const racc: FA[] = expr.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting());
  316.                         for (const afa of racc) {
  317.                             afa.addEpsilon(result);
  318.                         }
  319.                         return result;
  320.                     case 1:
  321.                         result = this.optional(accept, expr);
  322.                         return result;
  323.                     default:
  324.                         const l: FA[] = [];
  325.                         expr = this.optional(accept, expr);
  326.                         l.push(expr);
  327.                         for (let i = 1; i < maxOccurs; ++i) {
  328.                             l.push(expr.clone());
  329.                         }
  330.                         result = this.concat(accept, l);
  331.                         return result;
  332.                 }
  333.             case 1:
  334.                 switch (maxOccurs) {
  335.                     case -1:
  336.                     case 0:
  337.                         result = this.concat(accept, [expr, FA.repeat(accept,expr, 0, 0)]);
  338.                         return result;
  339.                     case 1:
  340.                         return expr;
  341.                     default:
  342.                         result = this.concat(accept, [expr, FA.repeat(accept, expr, 0, maxOccurs - 1)]);
  343.                         return result;
  344.                 }
  345.             default:
  346.                 switch (maxOccurs) {
  347.                     case -1:
  348.                     case 0:
  349.                         result = this.concat(accept, [FA.repeat(accept, expr, minOccurs, minOccurs), FA.repeat(accept, expr, 0, 0)]);
  350.                         return result;
  351.                     case 1:
  352.                         throw new Error("Should never get here");
  353.                     default:
  354.                         if (minOccurs == maxOccurs) {
  355.                             const l: FA[] = [];
  356.                             expr = this.optional(accept, expr);
  357.                             l.push(expr);
  358.                             for (let i = 1; i < maxOccurs; ++i) {
  359.                                 l.push(expr.clone());
  360.                             }
  361.                             result = this.concat(accept, l);
  362.                             return result;
  363.                         }
  364.                         result = this.concat(accept, [this.repeat(accept, expr, minOccurs, minOccurs), FA.repeat(accept, FA.optional(accept, expr), maxOccurs - minOccurs, maxOccurs - minOccurs)]);
  365.                         return result;
  366.                 }
  367.         }
  368.         // throw new Error("Should never get here");
  369.     }
  370.     isMatch(str: string): boolean {
  371.         let states: FA[] = [];
  372.         states.push(this);
  373.         let remaining: number = str.length - 1;
  374.         for (const cp of FA.toUtf32(str)) {
  375.             const next: FA[] = FA.fillMove(cp, states);
  376.             if (next.length == 0) {
  377.                 if (FA.hasAnyAccepting(states)) {
  378.                     return remaining == 0;
  379.                 }
  380.             }
  381.             states = next;
  382.             --remaining;
  383.         }
  384.         return FA.hasAnyAccepting(states);
  385.     }
  386.     fillInputTransitionRangesGroupedByState() : Map<FA, FARange[]> {
  387.         const result: Map<FA, FARange[]> = new Map<FA, FARange[]>();
  388.         for(const fat of this.transitions) {
  389.             const res : FARange[] | undefined = result.get(fat.to);
  390.             if(res===undefined) {
  391.                 const ndata : FARange[] = [new FARange(fat.min,fat.max)];
  392.                 result.set(fat.to, ndata);
  393.             } else {
  394.                 res.push(new FARange(fat.min,fat.max));
  395.             }
  396.         }
  397.         for(const values of result.values()) {
  398.             values.sort((x: FARange,y: FARange)=>{ var c = x.min - y.min; if(0!=c) return c; return x.max-y.max;});
  399.         }
  400.         return result;
  401.     }
  402.     toDfaTable(): number[] {
  403.         let fa: FA = this;
  404.         if(!this.isDeterministic) {
  405.             fa = this.toDfa();
  406.         }
  407.         const result: number[] = [];
  408.         const closure: FA[] = fa.fillClosure();
  409.         const stateIndices: number[] = [];
  410.         for(let i: number = 0;i<closure.length;++i) {
  411.             const cfa: FA = closure[i];
  412.             stateIndices.push(result.length);
  413.             result.push(cfa.acceptSymbol);
  414.             const itrgp: Map<FA,FARange[]> = cfa.fillInputTransitionRangesGroupedByState();
  415.             result.push(itrgp.size);
  416.             for(const itr of itrgp.entries()) {
  417.                 result.push(closure.indexOf(itr[0]));
  418.                 result.push(itr[1].length);
  419.                 for(const pair of itr[1]) {
  420.                     result.push(pair.min);
  421.                     result.push(pair.max);
  422.                 }
  423.             }
  424.         }
  425.         let state: number = 0;
  426.         while(state< result.length) {
  427.             ++state;
  428.             const tlen = result[state++];
  429.             for(let i: number = 0;i<tlen;++i) {
  430.                 result[state]=stateIndices[result[state]];
  431.                 ++state;
  432.                 const prlen: number = result[state++];
  433.                 state += prlen * 2;
  434.             }
  435.         }
  436.         return result;
  437.     }
  438.     static fromDfaTable(dfa: number[]) : FA {
  439.         if(dfa.length==0) {
  440.             return new FA();
  441.         }
  442.         let si: number = 0;
  443.         const states: Map<number, FA> = new Map<number, FA>();
  444.         while(si<dfa.length) {
  445.             const fa: FA = new FA();
  446.             states.set(si,fa);
  447.             fa.acceptSymbol = dfa[si++];
  448.             const tlen: number = dfa[si++];
  449.             for(let i: number = 0; i< tlen; ++i) {
  450.                 ++si; // tto
  451.                 const prlen: number = dfa[si++];
  452.                 si+=prlen*2;
  453.             }
  454.         }
  455.         si = 0;
  456.         while(si<dfa.length) {
  457.             var fa = states.get(si)!;
  458.             ++si;
  459.             const tlen: number = dfa[si++];
  460.             for (let i: number = 0; i < tlen; ++i) {
  461.                 const tto: number = dfa[si++];
  462.                 const to: FA = states.get(tto)!;
  463.                 const prlen: number = dfa[si++];
  464.                 for(let j: number = 0; j <prlen;++j) {
  465.                     const fat: FATransition = new FATransition(dfa[si++],dfa[si++],to);
  466.                     fa.transitions.push(fat);
  467.                 }
  468.             }
  469.         }
  470.         return states.get(0)!;
  471.     }
  472.     static fillMove(codepoint: number, states: Iterable<FA>): FA[] {
  473.         const result: FA[] = [];
  474.         for (const fa of states) {
  475.             for (const fat of fa.transitions) {
  476.                 if (fat.min <= codepoint && codepoint <= fat.max) {
  477.                     if (!result.includes(fat.to)) {
  478.                         result.push(fat.to);
  479.                     }
  480.                 }
  481.             }
  482.         }
  483.         return result;
  484.     }
  485.     static hasAnyAccepting(states: Iterable<FA>): boolean {
  486.         for (const fa of states) {
  487.             if (fa.isAccepting()) {
  488.                 return true;
  489.             }
  490.         }
  491.         return false;
  492.     }
  493.     private static _concat(lhs: FA, rhs: FA): void {
  494.         const acc: FA[] = lhs.fillClosure().filter((value: FA, index: number, array: FA[]) => value.isAccepting() );
  495.         for (const afa of acc) {
  496.             afa.acceptSymbol = -1;
  497.             afa.addEpsilon(rhs);
  498.         }
  499.     }
  500.     static *toUtf32(str: string): Iterable<number> {
  501.         for (const character of str) {
  502.             let cp: number = character.codePointAt(0)!;
  503.             if(cp>=0xD800 && cp<=0xDBFF) { // hi surrogate
  504.                 const cpl: number = character.codePointAt(1)!
  505.                 if(!(cpl>=0xDC00 && cpl<=0xDFFF)) { // not a low surrogate
  506.                     throw new Error("Unicode stream error. Unterminated high surrogate");
  507.                 }
  508.                 const highValue = cp & 0b11_11111111;
  509.                 const lowValue = cpl & 0b11_11111111;
  510.                 const magicAdd = 0b1_00000000_00000000;
  511.                 cp = (highValue << 10) | lowValue + magicAdd;
  512.             }
  513.             yield cp;
  514.         }
  515.     }
  516. }
  517. const foo: FA = FA.literal(0, FA.toUtf32("foo"));
  518. const ba: FA = FA.literal(0, FA.toUtf32("ba"));
  519. const rcp: number = "r".codePointAt(0)!;
  520. let zcp: number = 0;
  521. for(const num of FA.toUtf32("𠮷")) {
  522.     zcp = num;
  523. }
  524. const rz = FA.set(0, [new FARange(rcp, rcp), new FARange(zcp, zcp)]);
  525. const barz = FA.concat(0,[ba,rz]);
  526. let fooOrBarz = FA.repeat(0,FA.or(0,[foo,barz]),1,0).toDfa();
  527. const table = fooOrBarz.toDfaTable();
  528. fooOrBarz = FA.fromDfaTable(table);
  529. console.log(fooOrBarz.isMatch("foo"));
  530. console.log(fooOrBarz.isMatch("barfooba𠮷"));
  531. console.log(fooOrBarz.isMatch("test"));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement