-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcreate-assertion.ts
78 lines (70 loc) · 1.79 KB
/
create-assertion.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { Assertion, Element, NoParent } from "../ast";
import { CharSet } from "../char-set";
import { assertNever } from "../util";
import { Flags } from "./flags";
import { getCharEnv } from "./char-env";
export type BoundaryAssertion = WordBoundaryAssertion | TextBoundaryAssertion;
export interface WordBoundaryAssertion {
kind: "word";
negate: boolean;
}
export interface TextBoundaryAssertion {
kind: "end" | "start";
}
export function createAssertion(assertion: Readonly<BoundaryAssertion>, flags: Readonly<Flags>): NoParent<Element> {
const env = getCharEnv(flags);
switch (assertion.kind) {
case "end":
case "start": {
// /$/m == /(?!.)/
// /$/ == /(?![^])/
// /^/m == /(?<!.)/
// /^/ == /(?<![^])/
const charSet: CharSet = flags.multiline ? env.nonLineTerminator : env.all;
return newAssertion(true, assertion.kind === "start" ? "behind" : "ahead", charSet);
}
case "word": {
// /\b/ == /(?:(?<!\w)(?=\w)|(?<=\w)(?!\w))/
// /\B/ == /(?:(?<=\w)(?=\w)|(?<!\w)(?!\w))/
return {
type: "Alternation",
alternatives: [
{
type: "Concatenation",
elements: [
newAssertion(!assertion.negate, "behind", env.word),
newAssertion(false, "ahead", env.word),
],
},
{
type: "Concatenation",
elements: [
newAssertion(assertion.negate, "behind", env.word),
newAssertion(true, "ahead", env.word),
],
},
],
};
}
default:
throw assertNever(assertion, "Unknown assertion type");
}
}
function newAssertion(negate: boolean, kind: "ahead" | "behind", characters: CharSet): NoParent<Assertion> {
return {
type: "Assertion",
negate,
kind,
alternatives: [
{
type: "Concatenation",
elements: [
{
type: "CharacterClass",
characters,
},
],
},
],
};
}