const WHITESPACE_RE = /[ \t]*/ export function escapeRegExp(str: string) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); } export class MicroParser { constructor(str: string, readonly options: { whitespace_regex?: RegExp } = {}) { this.stream = str; this.options.whitespace_regex ||= WHITESPACE_RE; } protected stream: string // Utilities PEEK(n = 1) { // if (this.stream.length < n) throw 'EOF'; return this.stream.slice(0, n); } TRY_CONSUME(what: string | RegExp): false | string { let result: string; if (typeof what == 'string' && this.stream.startsWith(what)) { result = what; } else if (typeof what == 'object') { let regex = new RegExp(`^(?:${what.source})`); const match = regex.exec(this.stream); if (match) { result = match[0]; } } if (result) { this.stream = this.stream.slice(result.length); return result; } return false; } CONSUME(what: string | RegExp) { const result = this.TRY_CONSUME(what); if (result === false) throw `Expected token "${what.toString()}"` return result; } TRY_CONSUME_WS(what: string | RegExp) { this.TRY_CONSUME(this.options.whitespace_regex); return this.TRY_CONSUME(what); } CONSUME_WS(what?: string | RegExp) { this.TRY_CONSUME(this.options.whitespace_regex); if (what) return this.CONSUME(what); } }