clarity-pattern-parser
Version:
Parsing Library for Typescript and Javascript.
156 lines (114 loc) • 4.57 kB
text/typescript
import { Cursor } from "./Cursor";
import { Literal } from "./Literal";
import { Node } from "../ast/Node";
import { patterns } from "../grammar/patterns";
const { name } = patterns`
john = "John"
jane = "Jane"
first-names = john | jane
doe = "Doe"
smith = "Smith"
last-names = doe | smith
space = " "
name = first-names + space + last-names
`;
describe("Cursor", () => {
test("Empty Text", () => {
const cursor = new Cursor("");
cursor.next();
expect(cursor.index).toBe(0);
cursor.previous();
expect(cursor.index).toBe(0);
const text = cursor.getChars(0, 1);
expect(text).toBe("");
});
test("Move Cursor", () => {
const cursor = new Cursor("Hello World!");
cursor.moveTo(6);
expect(cursor.currentChar).toBe("W");
cursor.moveToFirstChar();
cursor.previous();
expect(cursor.isOnFirst).toBeTruthy();
expect(cursor.currentChar).toBe("H");
cursor.next();
expect(cursor.currentChar).toBe("e");
cursor.moveToLastChar();
cursor.next();
expect(cursor.isOnLast).toBeTruthy();
expect(cursor.currentChar).toBe("!");
cursor.previous();
expect(cursor.currentChar).toBe("d");
});
test("Error Handling", () => {
const pattern = new Literal("a", "A");
const cursor = new Cursor("Hello World!");
cursor.recordErrorAt(0, 0, pattern);
expect(cursor.hasError).toBeTruthy();
expect(cursor.error?.startIndex).toBe(0);
expect(cursor.error?.lastIndex).toBe(0);
expect(cursor.error?.pattern).toBe(pattern);
cursor.resolveError();
expect(cursor.hasError).toBeFalsy();
expect(cursor.error).toBe(null);
expect(cursor.furthestError?.startIndex).toBe(0);
expect(cursor.furthestError?.lastIndex).toBe(0);
expect(cursor.furthestError?.pattern).toBe(pattern);
});
test("Error Handling", () => {
const pattern = new Literal("h", "H");
const node = new Node("literal", "h", 0, 0, [], "H");
const cursor = new Cursor("Hello World!");
cursor.recordMatch(pattern, node);
expect(cursor.leafMatch.node).toBe(node);
expect(cursor.leafMatch.pattern).toBe(pattern);
expect(cursor.rootMatch.node).toBe(node);
expect(cursor.rootMatch.pattern).toBe(pattern);
});
test("Recording", () => {
const cursor = new Cursor("Hello World!");
cursor.startRecording();
expect(cursor.isRecording).toBeTruthy();
cursor.stopRecording();
expect(cursor.isRecording).toBeFalsy();
});
test("Text Information", () => {
const cursor = new Cursor("Hello World!");
const hello = cursor.getChars(0, 4);
expect(hello).toBe("Hello");
expect(cursor.length).toBe(12);
expect(cursor.text).toBe("Hello World!");
expect(cursor.index).toBe(0);
});
test("Records All matches", () => {
const { ast, cursor } = name.exec("John Doe", true);
const records = cursor.records;
expect(ast?.toString()).toBe("John Doe");
expect(records[0].ast?.toString()).toBe("John");
expect(records[1].ast?.toString()).toBe(" ");
expect(records[2].ast?.toString()).toBe("Doe");
expect(records[3].ast?.toString()).toBe("John Doe");
});
test("Records Some Error Some Matches", () => {
const { ast, cursor } = name.exec("John Smith", true);
const records = cursor.records;
expect(ast?.toString()).toBe("John Smith");
expect(records[0].ast?.toString()).toBe("John");
expect(records[1].ast?.toString()).toBe(" ");
expect(records[2].error?.pattern.name).toBe("doe");
expect(records[2].error?.startIndex).toBe(5);
expect(records[2].error?.lastIndex).toBe(5);
expect(records[3].ast?.toString()).toBe("Smith");
expect(records[4].ast?.toString()).toBe("John Smith");
});
test("Records All Errors", () => {
const { ast, cursor } = name.exec("Jack Smith", true);
const records = cursor.records;
expect(ast).toBeNull();
expect(records[0].error).not.toBeNull();
expect(records[0].pattern.name).toBe("john");
expect(records[1].error).not.toBeNull();
expect(records[1].pattern.name).toBe("jane");
expect(records[2].error).not.toBeNull();
expect(records[2].pattern.name).toBe("first-names");
});
});