gnablib
Version:
A lean, zero dependency library to provide a useful base for your project.
2 lines • 3.13 kB
JavaScript
/*! Copyright 2023-2024 the gnablib contributors MPL-1.1 */
import{StringBuilder as t}from"../../primitive/StringBuilder.js";import{sNum as s}from"../../safe/safe.js";const n=Symbol.for("nodejs.util.inspect.custom");class i{constructor(){this._dests=[]}addTransition(t,s){if(this._dests.length>0)throw new Error("Destinations already defined");this._by=t,this._dests.push(s)}addEpsilon(t){if(void 0!==this._by)throw new Error("Destination is already by match");this._dests.push(t)}transition(t,s=!1){if(void 0!==this._by)return this._by.match(t)?(s&&console.log(`${t}==${this._by.toString()}`),this._dests[0]):void(s&&console.log(`${t}!=${this._by.toString()}`))}get isEpsilon(){return this._dests.length>0&&void 0===this._by}get isEnd(){return 0===this._dests.length}[Symbol.iterator](){return this._dests[Symbol.iterator]()}debug(t,s=!1){var n,i;this.isEnd?t.append("⊞"):(s?t.append(">()-"):t.append("⊡-"),this.isEpsilon?(t.append("ε"),this._dests.length>1&&t.append(":"+this._dests.length.toString())):t.append(null!==(i=null===(n=this._by)||void 0===n?void 0:n.toString())&&void 0!==i?i:""),t.append("-"),this._dests[0].debug(t,!0))}toString(){return this[n]()}[n](){const s=new t;return s.append("Node"),this.debug(s),s.toString()}}export class Nfa{constructor(){this.debug=!1;const t=new i;this._start=t,this._end=t}get start(){return this._start}get end(){return this._end}concat(...t){for(const s of t){const t=new i;s instanceof Nfa?(this._end.addEpsilon(s._start),s._end.addEpsilon(t)):this._end.addTransition(s,t),this._end=t}return this}union(...t){const s=new i;for(const n of t)if(n instanceof Nfa)this._end.addEpsilon(n.start),n.end.addEpsilon(s);else{const t=new i;this._end.addEpsilon(t),t.addTransition(n,s)}return this._end=s,this}repeat(t,n,e){s("min",n).unsigned().throwNot(),void 0===e?e=n:s("max",e).atLeast(n).throwNot();let d=0;for(;d<n;d++){const s=new i;this._end.addTransition(t,s),this._end=s}if(e>n){const s=new i;for(;d<e;d++){const n=new i,e=new i;this._end.addEpsilon(e),this._end.addEpsilon(s),e.addTransition(t,n),this._end=n}this._end.addEpsilon(s),this._end=s}return this}zeroOrMore(){const t=new i,s=new i;return t.addEpsilon(this._start),t.addEpsilon(s),this._end.addEpsilon(s),this._end.addEpsilon(this._start),this._start=t,this._end=s,this}zeroOrOne(){const t=new i,s=new i;return t.addEpsilon(this._start),t.addEpsilon(s),this._end.addEpsilon(s),this._start=t,this._end=s,this}oneOrMore(){const t=new i,s=new i;return t.addEpsilon(this._start),this._end.addEpsilon(s),this._end.addEpsilon(this._start),this._start=t,this._end=s,this}addNextState(t,s,n){if(t.isEpsilon)for(const i of t)n.find((t=>t===i))||(n.push(i),this.addNextState(i,s,n));else s.push(t)}search(t){let s=[],n=0,i=-1;for(this.addNextState(this._start,s,[]);n<t.length;n++){const e=[];for(const d of s){const s=d.transition(t.codePointAt(n),this.debug);s&&this.addNextState(s,e,[]),d.isEnd&&(i=n)}s=e,this.debug&&(console.log(s),console.log(`eating char ${n}`))}return this.debug&&console.log(s),void 0!==s.find((t=>t.isEnd))?n:i>=0?i:-1}[n](){const s=new t;return s.append("NFA "),this._start.debug(s),s.toString()}}