UNPKG

clarity-pattern-parser

Version:

Parsing Library for Typescript and Javascript.

180 lines (142 loc) 3.65 kB
import { Node } from "../ast/Node"; import { Cursor } from "./Cursor"; import { ParseResult } from "./ParseResult"; import { Pattern } from "./Pattern"; import { execPattern } from "./execPattern"; import { testPattern } from "./testPattern"; let idIndex = 0; export class Literal implements Pattern { private _id: string; private _type: string; private _name: string; private _parent: Pattern | null; private _token: string; private _runes: string[]; private _firstIndex: number; private _lastIndex: number; private _endIndex: number; get id(): string { return this._id; } get type(): string { return this._type; } get name(): string { return this._name; } get token(): string { return this._token; } get parent(): Pattern | null { return this._parent; } set parent(pattern: Pattern | null) { this._parent = pattern; } get children(): Pattern[] { return []; } get startedOnIndex() { return this._firstIndex; } constructor(name: string, value: string) { if (value.length === 0) { throw new Error("Value Cannot be empty."); } this._id = `literal-${idIndex++}`; this._type = "literal"; this._name = name; this._token = value; this._runes = Array.from(value); this._parent = null; this._firstIndex = 0; this._lastIndex = 0; this._endIndex = 0; } test(text: string, record = false): boolean { return testPattern(this, text, record); } exec(text: string, record = false): ParseResult { return execPattern(this, text, record); } parse(cursor: Cursor): Node | null { this._firstIndex = cursor.index; const passed = this._tryToParse(cursor); if (passed) { cursor.resolveError(); const node = this._createNode(); cursor.recordMatch(this, node); return node; } cursor.recordErrorAt(this._firstIndex, this._endIndex, this); return null; } private _tryToParse(cursor: Cursor): boolean { let passed = false; const literalRuneLength = this._runes.length; for (let i = 0; i < literalRuneLength; i++) { const literalRune = this._runes[i]; const cursorRune = cursor.currentChar; if (literalRune !== cursorRune) { this._endIndex = cursor.index; break; } if (i + 1 === literalRuneLength) { this._lastIndex = this._firstIndex + this._token.length - 1; passed = true; break; } if (!cursor.hasNext()) { this._endIndex = cursor.index + 1; break; } cursor.next(); } return passed; } private _createNode(): Node { return new Node( "literal", this._name, this._firstIndex, this._lastIndex, undefined, this._token ); } clone(name = this._name): Pattern { const clone = new Literal(name, this._token); clone._id = this._id; return clone; } getTokens(): string[] { return [this._token]; } getTokensAfter(_lastMatched: Pattern): string[] { return []; } getNextTokens(): string[] { if (this.parent == null) { return []; } return this.parent.getTokensAfter(this); } getPatterns(): Pattern[] { return [this]; } getPatternsAfter(): Pattern[] { return []; } getNextPatterns(): Pattern[] { if (this.parent == null) { return []; } return this.parent.getPatternsAfter(this); } find(_predicate: (p: Pattern) => boolean): Pattern | null { return null; } isEqual(pattern: Literal) { return pattern.type === this.type && pattern._token === this._token; } }