clarity-pattern-parser
Version:
Parsing Library for Typescript and Javascript.
180 lines (142 loc) • 3.65 kB
text/typescript
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;
}
}