clarity-pattern-parser 3.0.16 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -191
- package/dist/ast/Node.d.ts +4 -5
- package/dist/index.browser.js +476 -731
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +10 -18
- package/dist/index.esm.js +469 -716
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +476 -731
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +24 -0
- package/dist/patterns/Literal.d.ts +19 -0
- package/dist/patterns/LookAhead.d.ts +8 -0
- package/dist/patterns/Not.d.ts +11 -0
- package/dist/patterns/Or.d.ts +22 -0
- package/dist/patterns/Pattern.d.ts +6 -7
- package/dist/patterns/{RecursivePattern.d.ts → Recursive.d.ts} +4 -4
- package/dist/patterns/Reference.d.ts +14 -0
- package/dist/patterns/Regex.d.ts +21 -0
- package/dist/patterns/Repeat.d.ts +20 -0
- package/package.json +1 -1
- package/src/CursorHistory.ts +1 -1
- package/src/ast/Node.ts +20 -17
- package/src/ast/Visitor.ts +14 -18
- package/src/index.ts +17 -33
- package/src/patterns/And.ts +178 -0
- package/src/patterns/Literal.ts +91 -0
- package/src/patterns/Not.ts +50 -0
- package/src/patterns/Or.ts +132 -0
- package/src/patterns/Pattern.ts +31 -47
- package/src/patterns/Recursive.ts +92 -0
- package/src/patterns/{ReferencePattern.ts → Reference.ts} +32 -28
- package/src/patterns/Regex.ts +123 -0
- package/src/patterns/Repeat.ts +155 -0
- package/src/tests/{AndValue.test.ts → And.test.ts} +31 -41
- package/src/tests/CursorHistory.test.ts +6 -6
- package/src/tests/Cusor.test.ts +7 -10
- package/src/tests/Literal.test.ts +3 -5
- package/src/tests/LookAhead.test.ts +2 -51
- package/src/tests/Not.test.ts +51 -0
- package/src/tests/Or.test.ts +113 -0
- package/src/tests/Pattern.test.ts +40 -139
- package/src/tests/{RecursivePattern.test.ts → Recursive.test.ts} +10 -8
- package/src/tests/Reference.test.ts +16 -0
- package/src/tests/{RepeatValue.test.ts → Repeat.test.ts} +10 -42
- package/src/tests/TextSuggester.test.ts +20 -28
- package/src/tests/{NodeVisitor.test.ts → Visitor.test.ts} +42 -21
- package/src/tests/cssPatterns/cssValue.ts +2 -2
- package/src/tests/cssPatterns/divider.ts +2 -2
- package/src/tests/cssPatterns/hex.ts +2 -2
- package/src/tests/cssPatterns/method.ts +7 -9
- package/src/tests/cssPatterns/name.ts +2 -2
- package/src/tests/cssPatterns/number.ts +2 -2
- package/src/tests/cssPatterns/optionalSpaces.ts +1 -2
- package/src/tests/cssPatterns/spaces.ts +2 -2
- package/src/tests/cssPatterns/unit.ts +3 -3
- package/src/tests/cssPatterns/value.ts +2 -2
- package/src/tests/cssPatterns/values.ts +2 -2
- package/src/tests/htmlPatterns/element.ts +18 -33
- package/src/tests/javascriptPatterns/boolean.ts +2 -3
- package/src/tests/javascriptPatterns/json.ts +14 -26
- package/src/tests/javascriptPatterns/name.ts +3 -20
- package/src/tests/javascriptPatterns/number.ts +2 -2
- package/src/tests/javascriptPatterns/objectLiteral.ts +9 -16
- package/src/tests/javascriptPatterns/string.ts +26 -24
- package/src/tests/javascriptPatterns/unit.ts +3 -6
- package/src/tests/javascriptPatterns/whitespace.ts +8 -12
- package/src/tests/naturalLanguage/filter.ts +16 -33
- package/src/tests/patterns/sentence.ts +8 -8
- package/dist/Cursor.js +0 -105
- package/dist/Cursor.js.map +0 -1
- package/dist/CursorHistory.js +0 -104
- package/dist/CursorHistory.js.map +0 -1
- package/dist/Permutor.d.ts +0 -13
- package/dist/Permutor.js +0 -52
- package/dist/Permutor.js.map +0 -1
- package/dist/TextSuggester.js +0 -244
- package/dist/TextSuggester.js.map +0 -1
- package/dist/ast/CompositeNode.d.ts +0 -6
- package/dist/ast/CompositeNode.js +0 -17
- package/dist/ast/CompositeNode.js.map +0 -1
- package/dist/ast/Node.js +0 -16
- package/dist/ast/Node.js.map +0 -1
- package/dist/ast/NodeVisitor.d.ts +0 -31
- package/dist/ast/ValueNode.d.ts +0 -6
- package/dist/ast/ValueNode.js +0 -14
- package/dist/ast/ValueNode.js.map +0 -1
- package/dist/ast/Visitor.js +0 -209
- package/dist/ast/Visitor.js.map +0 -1
- package/dist/patterns/ParseError.js +0 -9
- package/dist/patterns/ParseError.js.map +0 -1
- package/dist/patterns/Pattern.js +0 -127
- package/dist/patterns/Pattern.js.map +0 -1
- package/dist/patterns/RecursivePattern.js +0 -65
- package/dist/patterns/RecursivePattern.js.map +0 -1
- package/dist/patterns/composite/AndComposite.d.ts +0 -22
- package/dist/patterns/composite/AndComposite.js +0 -117
- package/dist/patterns/composite/AndComposite.js.map +0 -1
- package/dist/patterns/composite/CompositePattern.d.ts +0 -4
- package/dist/patterns/composite/CompositePattern.js +0 -7
- package/dist/patterns/composite/CompositePattern.js.map +0 -1
- package/dist/patterns/composite/OptionalComposite.d.ts +0 -10
- package/dist/patterns/composite/OptionalComposite.js +0 -29
- package/dist/patterns/composite/OptionalComposite.js.map +0 -1
- package/dist/patterns/composite/OrComposite.d.ts +0 -16
- package/dist/patterns/composite/OrComposite.js +0 -69
- package/dist/patterns/composite/OrComposite.js.map +0 -1
- package/dist/patterns/composite/RepeatComposite.d.ts +0 -21
- package/dist/patterns/composite/RepeatComposite.js +0 -88
- package/dist/patterns/composite/RepeatComposite.js.map +0 -1
- package/dist/patterns/value/AndValue.d.ts +0 -21
- package/dist/patterns/value/AndValue.js +0 -118
- package/dist/patterns/value/AndValue.js.map +0 -1
- package/dist/patterns/value/AnyOfThese.d.ts +0 -18
- package/dist/patterns/value/AnyOfThese.js +0 -59
- package/dist/patterns/value/AnyOfThese.js.map +0 -1
- package/dist/patterns/value/Literal.d.ts +0 -20
- package/dist/patterns/value/Literal.js +0 -63
- package/dist/patterns/value/Literal.js.map +0 -1
- package/dist/patterns/value/NotValue.d.ts +0 -17
- package/dist/patterns/value/NotValue.js +0 -70
- package/dist/patterns/value/NotValue.js.map +0 -1
- package/dist/patterns/value/OptionalValue.d.ts +0 -9
- package/dist/patterns/value/OptionalValue.js +0 -32
- package/dist/patterns/value/OptionalValue.js.map +0 -1
- package/dist/patterns/value/OrValue.d.ts +0 -19
- package/dist/patterns/value/OrValue.js +0 -73
- package/dist/patterns/value/OrValue.js.map +0 -1
- package/dist/patterns/value/RegexValue.d.ts +0 -19
- package/dist/patterns/value/RegexValue.js +0 -69
- package/dist/patterns/value/RegexValue.js.map +0 -1
- package/dist/patterns/value/RepeatValue.d.ts +0 -19
- package/dist/patterns/value/RepeatValue.js +0 -89
- package/dist/patterns/value/RepeatValue.js.map +0 -1
- package/dist/patterns/value/ValuePattern.d.ts +0 -5
- package/dist/patterns/value/ValuePattern.js +0 -7
- package/dist/patterns/value/ValuePattern.js.map +0 -1
- package/src/Permutor.ts +0 -64
- package/src/ast/CompositeNode.ts +0 -26
- package/src/ast/ValueNode.ts +0 -28
- package/src/patterns/RecursivePattern.ts +0 -86
- package/src/patterns/composite/AndComposite.ts +0 -159
- package/src/patterns/composite/CompositePattern.ts +0 -7
- package/src/patterns/composite/OptionalComposite.ts +0 -37
- package/src/patterns/composite/OrComposite.ts +0 -96
- package/src/patterns/composite/RepeatComposite.ts +0 -130
- package/src/patterns/value/AndValue.ts +0 -152
- package/src/patterns/value/AnyOfThese.ts +0 -81
- package/src/patterns/value/Literal.ts +0 -92
- package/src/patterns/value/NotValue.ts +0 -95
- package/src/patterns/value/OptionalValue.ts +0 -39
- package/src/patterns/value/OrValue.ts +0 -103
- package/src/patterns/value/RegexValue.ts +0 -103
- package/src/patterns/value/RepeatValue.ts +0 -131
- package/src/patterns/value/ValuePattern.ts +0 -8
- package/src/tests/AndComposite.test.ts +0 -102
- package/src/tests/AnyOfThese.test.ts +0 -74
- package/src/tests/CompositeNode.test.ts +0 -33
- package/src/tests/NotValue.test.ts +0 -76
- package/src/tests/OptionalValue.test.ts +0 -50
- package/src/tests/OrComposite.test.ts +0 -75
- package/src/tests/OrValue.test.ts +0 -171
- package/src/tests/Permutor.test.ts +0 -30
- package/src/tests/ReferencePattern.test.ts +0 -24
- package/src/tests/RegexValue.test.ts +0 -22
- package/src/tests/RepeatComposite.test.ts +0 -58
- package/src/tests/ValueNode.test.ts +0 -24
- package/src/tests/javascriptPatterns/varStatement.ts +0 -0
- package/src/tests/readmeDemo.test.ts +0 -124
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import ParseError from "../ParseError";
|
|
2
|
-
import ValueNode from "../../ast/ValueNode";
|
|
3
|
-
import ValuePattern from "./ValuePattern";
|
|
4
|
-
import Cursor from "../../Cursor";
|
|
5
|
-
|
|
6
|
-
export default class Literal extends ValuePattern {
|
|
7
|
-
public literal: string;
|
|
8
|
-
public node: ValueNode | null = null;
|
|
9
|
-
public cursor!: Cursor;
|
|
10
|
-
public mark: number = 0;
|
|
11
|
-
public substring: string = "";
|
|
12
|
-
|
|
13
|
-
constructor(name: string, literal: string) {
|
|
14
|
-
super("literal", name);
|
|
15
|
-
this.literal = literal;
|
|
16
|
-
this._assertArguments();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
private _assertArguments() {
|
|
20
|
-
if (typeof this.literal !== "string") {
|
|
21
|
-
throw new Error(
|
|
22
|
-
"Invalid Arguments: The literal argument needs to be a string of characters."
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (this.literal.length < 1) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
"Invalid Arguments: The literalString argument needs to be at least one character long."
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
parse(cursor: Cursor) {
|
|
34
|
-
this._reset(cursor);
|
|
35
|
-
this._tryPattern();
|
|
36
|
-
|
|
37
|
-
return this.node;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private _reset(cursor: Cursor) {
|
|
41
|
-
this.cursor = cursor;
|
|
42
|
-
this.mark = this.cursor.mark();
|
|
43
|
-
this.substring = this.cursor.text.substring(
|
|
44
|
-
this.mark,
|
|
45
|
-
this.mark + this.literal.length
|
|
46
|
-
);
|
|
47
|
-
this.node = null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private _tryPattern() {
|
|
51
|
-
if (this.substring === this.literal) {
|
|
52
|
-
this._processMatch();
|
|
53
|
-
} else {
|
|
54
|
-
this._processError();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private _processError() {
|
|
59
|
-
const message = `ParseError: Expected '${this.literal}' but found '${this.substring}'.`;
|
|
60
|
-
|
|
61
|
-
const parseError = new ParseError(message, this.cursor.getIndex(), this);
|
|
62
|
-
this.cursor.throwError(parseError);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private _processMatch() {
|
|
66
|
-
this.node = new ValueNode(
|
|
67
|
-
"literal",
|
|
68
|
-
this.name,
|
|
69
|
-
this.substring,
|
|
70
|
-
this.mark,
|
|
71
|
-
this.mark + this.literal.length - 1
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
this.cursor.index = this.node.endIndex;
|
|
75
|
-
this.cursor.addMatch(this, this.node);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
clone(name?: string) {
|
|
79
|
-
if (typeof name !== "string") {
|
|
80
|
-
name = this.name;
|
|
81
|
-
}
|
|
82
|
-
return new Literal(name, this.literal);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
getTokenValue() {
|
|
86
|
-
return this.literal;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
getTokens() {
|
|
90
|
-
return [this.getTokenValue()];
|
|
91
|
-
}
|
|
92
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import ValuePattern from "./ValuePattern";
|
|
2
|
-
import ValueNode from "../../ast/ValueNode";
|
|
3
|
-
import ParseError from "../ParseError";
|
|
4
|
-
import Pattern from "../Pattern";
|
|
5
|
-
import Cursor from "../../Cursor";
|
|
6
|
-
|
|
7
|
-
export default class NotValue extends ValuePattern {
|
|
8
|
-
public match: string = "";
|
|
9
|
-
public node: ValueNode | null = null;
|
|
10
|
-
public cursor!: Cursor;
|
|
11
|
-
public mark: number = 0;
|
|
12
|
-
|
|
13
|
-
constructor(name: string, pattern: ValuePattern) {
|
|
14
|
-
super("not-value", name, [pattern]);
|
|
15
|
-
this._assertArguments();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
private _assertArguments() {
|
|
19
|
-
if (!(this.children[0] instanceof Pattern)) {
|
|
20
|
-
throw new Error(
|
|
21
|
-
"Invalid Arguments: Expected the pattern to be a ValuePattern."
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (typeof this.name !== "string") {
|
|
26
|
-
throw new Error("Invalid Arguments: Expected name to be a string.");
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
private _reset(cursor: Cursor) {
|
|
31
|
-
this.match = "";
|
|
32
|
-
this.node = null;
|
|
33
|
-
this.cursor = cursor;
|
|
34
|
-
this.mark = this.cursor.mark();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
parse(cursor: Cursor) {
|
|
38
|
-
this._reset(cursor);
|
|
39
|
-
this._tryPattern();
|
|
40
|
-
|
|
41
|
-
return this.node;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
private _tryPattern() {
|
|
45
|
-
while (true) {
|
|
46
|
-
const mark = this.cursor.mark();
|
|
47
|
-
this.children[0].parse(this.cursor);
|
|
48
|
-
|
|
49
|
-
if (this.cursor.hasUnresolvedError()) {
|
|
50
|
-
this.cursor.resolveError();
|
|
51
|
-
this.cursor.moveToMark(mark);
|
|
52
|
-
this.match += this.cursor.getChar();
|
|
53
|
-
break;
|
|
54
|
-
} else {
|
|
55
|
-
this.cursor.moveToMark(mark);
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this._processMatch();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
private _processMatch() {
|
|
64
|
-
if (this.match.length === 0) {
|
|
65
|
-
const parseError = new ParseError(
|
|
66
|
-
`Didn't find any characters that didn't match the ${this.children[0].name} pattern.`,
|
|
67
|
-
this.mark,
|
|
68
|
-
this
|
|
69
|
-
);
|
|
70
|
-
this.cursor.throwError(parseError);
|
|
71
|
-
} else {
|
|
72
|
-
this.node = new ValueNode(
|
|
73
|
-
"not-value",
|
|
74
|
-
this.name,
|
|
75
|
-
this.match,
|
|
76
|
-
this.mark,
|
|
77
|
-
this.mark
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
this.cursor.index = this.node.endIndex;
|
|
81
|
-
this.cursor.addMatch(this, this.node);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
clone(name?: string) {
|
|
86
|
-
if (typeof name !== "string") {
|
|
87
|
-
name = this.name;
|
|
88
|
-
}
|
|
89
|
-
return new NotValue(name, this.children[0] as ValuePattern);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
getTokens() {
|
|
93
|
-
return [];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import ValuePattern from "./ValuePattern";
|
|
2
|
-
import Pattern from "../Pattern";
|
|
3
|
-
import Cursor from "../../Cursor";
|
|
4
|
-
|
|
5
|
-
export default class OptionalValue extends ValuePattern {
|
|
6
|
-
constructor(pattern: ValuePattern) {
|
|
7
|
-
super("optional-value", "optional-value", [pattern]);
|
|
8
|
-
this._assertArguments();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
private _assertArguments() {
|
|
12
|
-
if (!(this.children[0] instanceof ValuePattern)) {
|
|
13
|
-
throw new Error("Invalid Arguments: Expected a ValuePattern.");
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
parse(cursor: Cursor) {
|
|
18
|
-
const mark = cursor.mark();
|
|
19
|
-
|
|
20
|
-
const node = this.children[0].parse(cursor);
|
|
21
|
-
|
|
22
|
-
if (cursor.hasUnresolvedError() || node == null) {
|
|
23
|
-
cursor.resolveError();
|
|
24
|
-
cursor.moveToMark(mark);
|
|
25
|
-
return null;
|
|
26
|
-
} else {
|
|
27
|
-
cursor.addMatch(this, node);
|
|
28
|
-
return node;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
clone() {
|
|
33
|
-
return new OptionalValue(this.children[0] as ValuePattern);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getTokens() {
|
|
37
|
-
return this._children[0].getTokens();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import ValuePattern from "./ValuePattern";
|
|
2
|
-
import ValueNode from "../../ast/ValueNode";
|
|
3
|
-
import OptionalValue from "./OptionalValue";
|
|
4
|
-
import Pattern from "../Pattern";
|
|
5
|
-
import ParseError from "../ParseError";
|
|
6
|
-
import Cursor from "../../Cursor";
|
|
7
|
-
|
|
8
|
-
export default class OrValue extends ValuePattern {
|
|
9
|
-
public index: number = 0;
|
|
10
|
-
public errors: ParseError[] = [];
|
|
11
|
-
public node: ValueNode | null = null;
|
|
12
|
-
public cursor!: Cursor;
|
|
13
|
-
public mark: number = 0;
|
|
14
|
-
public parseError: ParseError | null = null;
|
|
15
|
-
|
|
16
|
-
constructor(name: string, patterns: ValuePattern[]) {
|
|
17
|
-
super("or-value", name, patterns);
|
|
18
|
-
this._assertArguments();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
private _assertArguments() {
|
|
22
|
-
if (this._children.length < 2) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
"Invalid Argument: OrValue needs to have more than one value pattern."
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const hasOptionalChildren = this._children.some(
|
|
29
|
-
(pattern) => pattern instanceof OptionalValue
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
if (hasOptionalChildren) {
|
|
33
|
-
throw new Error("OrValues cannot have optional values.");
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private _reset(cursor: Cursor) {
|
|
38
|
-
this.index = 0;
|
|
39
|
-
this.errors = [];
|
|
40
|
-
this.node = null;
|
|
41
|
-
this.cursor = cursor;
|
|
42
|
-
this.mark = cursor.mark();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
parse(cursor: Cursor) {
|
|
46
|
-
this._reset(cursor);
|
|
47
|
-
this._tryPattern();
|
|
48
|
-
|
|
49
|
-
return this.node;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private _tryPattern() {
|
|
53
|
-
while (true) {
|
|
54
|
-
const pattern = this._children[this.index];
|
|
55
|
-
const node = pattern.parse(this.cursor) as ValueNode;
|
|
56
|
-
|
|
57
|
-
if (this.cursor.hasUnresolvedError()) {
|
|
58
|
-
if (this.index + 1 < this._children.length) {
|
|
59
|
-
this.cursor.resolveError();
|
|
60
|
-
this.index++;
|
|
61
|
-
this.cursor.moveToMark(this.mark);
|
|
62
|
-
} else {
|
|
63
|
-
this.node = null;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
this.node = new ValueNode(
|
|
68
|
-
"or-value",
|
|
69
|
-
this.name,
|
|
70
|
-
node.value,
|
|
71
|
-
node.startIndex,
|
|
72
|
-
node.endIndex
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
this.cursor.index = this.node.endIndex;
|
|
76
|
-
this.cursor.addMatch(this, this.node);
|
|
77
|
-
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
clone(name: string) {
|
|
84
|
-
if (typeof name !== "string") {
|
|
85
|
-
name = this.name;
|
|
86
|
-
}
|
|
87
|
-
return new OrValue(name, this._children as ValuePattern[]);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getTokens() {
|
|
91
|
-
const tokens = this._children.map((c) => c.getTokens());
|
|
92
|
-
|
|
93
|
-
const hasPrimitiveTokens = tokens.every((t) =>
|
|
94
|
-
t.every((value) => typeof value === "string")
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
if (hasPrimitiveTokens && tokens.length > 0) {
|
|
98
|
-
return tokens.reduce((acc, t) => acc.concat(t), []);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return this._children[0].getTokens();
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import ParseError from "../ParseError";
|
|
2
|
-
import ValueNode from "../../ast/ValueNode";
|
|
3
|
-
import ValuePattern from "./ValuePattern";
|
|
4
|
-
import Cursor from "../../Cursor";
|
|
5
|
-
|
|
6
|
-
export default class RegexValue extends ValuePattern {
|
|
7
|
-
public regexString: string;
|
|
8
|
-
public regex: RegExp;
|
|
9
|
-
public node: ValueNode | null = null;
|
|
10
|
-
public cursor!: Cursor;
|
|
11
|
-
public substring: string = "";
|
|
12
|
-
|
|
13
|
-
constructor(name: string, regex: string) {
|
|
14
|
-
super("regex-value", name);
|
|
15
|
-
this.regexString = regex;
|
|
16
|
-
this.regex = new RegExp(`^${regex}`, "g");
|
|
17
|
-
this._assertArguments();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
private _assertArguments() {
|
|
21
|
-
if (typeof this.regexString !== "string") {
|
|
22
|
-
throw new Error(
|
|
23
|
-
"Invalid Arguments: The regex argument needs to be a string of regex."
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (this.regexString.length < 1) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
"Invalid Arguments: The regex string argument needs to be at least one character long."
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (this.regexString.charAt(0) === "^") {
|
|
34
|
-
throw new Error(
|
|
35
|
-
"Invalid Arguments: The regex string cannot start with a '^' because it is expected to be in the middle of a string."
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (this.regexString.charAt(this.regexString.length - 1) === "$") {
|
|
40
|
-
throw new Error(
|
|
41
|
-
"Invalid Arguments: The regex string cannot end with a '$' because it is expected to be in the middle of a string."
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
parse(cursor: Cursor) {
|
|
47
|
-
this._reset(cursor);
|
|
48
|
-
this._tryPattern();
|
|
49
|
-
|
|
50
|
-
return this.node;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private _reset(cursor: Cursor) {
|
|
54
|
-
this.cursor = cursor;
|
|
55
|
-
this.regex.lastIndex = 0;
|
|
56
|
-
this.substring = this.cursor.text.substr(this.cursor.getIndex());
|
|
57
|
-
this.node = null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private _tryPattern() {
|
|
61
|
-
const result = this.regex.exec(this.substring);
|
|
62
|
-
|
|
63
|
-
if (result != null && result.index === 0) {
|
|
64
|
-
const currentIndex = this.cursor.getIndex();
|
|
65
|
-
const newIndex = currentIndex + result[0].length - 1;
|
|
66
|
-
|
|
67
|
-
this.node = new ValueNode(
|
|
68
|
-
"regex-value",
|
|
69
|
-
this.name,
|
|
70
|
-
result[0],
|
|
71
|
-
currentIndex,
|
|
72
|
-
newIndex
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
this.cursor.index = newIndex;
|
|
76
|
-
this.cursor.addMatch(this, this.node);
|
|
77
|
-
} else {
|
|
78
|
-
this._processError();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
private _processError() {
|
|
83
|
-
const message = `ParseError: Expected regex pattern of '${this.regexString}' but found '${this.substring}'.`;
|
|
84
|
-
const parseError = new ParseError(message, this.cursor.getIndex(), this);
|
|
85
|
-
|
|
86
|
-
this.cursor.throwError(parseError);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
clone(name: string) {
|
|
90
|
-
if (typeof name !== "string") {
|
|
91
|
-
name = this.name;
|
|
92
|
-
}
|
|
93
|
-
return new RegexValue(name, this.regexString);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
getTokenValue() {
|
|
97
|
-
return this.name;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
getTokens() {
|
|
101
|
-
return [this.name];
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import ValuePattern from "./ValuePattern";
|
|
2
|
-
import ValueNode from "../../ast/ValueNode";
|
|
3
|
-
import ParseError from "../ParseError";
|
|
4
|
-
import OptionalValue from "./OptionalValue";
|
|
5
|
-
import Pattern from "../Pattern";
|
|
6
|
-
import Cursor from "../../Cursor";
|
|
7
|
-
|
|
8
|
-
export default class RepeatValue extends ValuePattern {
|
|
9
|
-
public _pattern: ValuePattern;
|
|
10
|
-
public _divider: ValuePattern;
|
|
11
|
-
public nodes: ValueNode[] = [];
|
|
12
|
-
public cursor!: Cursor;
|
|
13
|
-
public mark: number = 0;
|
|
14
|
-
public node: ValueNode | null = null;
|
|
15
|
-
|
|
16
|
-
constructor(name: string, pattern: ValuePattern, divider?: ValuePattern) {
|
|
17
|
-
super(
|
|
18
|
-
"repeat-value",
|
|
19
|
-
name,
|
|
20
|
-
divider != null ? [pattern, divider] : [pattern]
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
this._pattern = this.children[0] as ValuePattern;
|
|
24
|
-
this._divider = this.children[1] as ValuePattern;
|
|
25
|
-
|
|
26
|
-
this._assertArguments();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
private _assertArguments() {
|
|
30
|
-
if (this._pattern instanceof OptionalValue) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
"Invalid Arguments: The pattern cannot be a optional pattern."
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private _reset(cursor: Cursor) {
|
|
38
|
-
this.nodes = [];
|
|
39
|
-
this.cursor = cursor;
|
|
40
|
-
this.mark = this.cursor.mark();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
parse(cursor: Cursor) {
|
|
44
|
-
this._reset(cursor);
|
|
45
|
-
this._tryPattern();
|
|
46
|
-
|
|
47
|
-
return this.node;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private _tryPattern() {
|
|
51
|
-
while (true) {
|
|
52
|
-
const node = this._pattern.parse(this.cursor) as ValueNode;
|
|
53
|
-
|
|
54
|
-
if (this.cursor.hasUnresolvedError()) {
|
|
55
|
-
this._processMatch();
|
|
56
|
-
break;
|
|
57
|
-
} else {
|
|
58
|
-
this.nodes.push(node);
|
|
59
|
-
|
|
60
|
-
if (node.endIndex === this.cursor.lastIndex()) {
|
|
61
|
-
this._processMatch();
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
this.cursor.next();
|
|
66
|
-
|
|
67
|
-
if (this._divider != null) {
|
|
68
|
-
const mark = this.cursor.mark();
|
|
69
|
-
const node = this._divider.parse(this.cursor) as ValueNode;
|
|
70
|
-
|
|
71
|
-
if (this.cursor.hasUnresolvedError()) {
|
|
72
|
-
this.cursor.moveToMark(mark);
|
|
73
|
-
this._processMatch();
|
|
74
|
-
break;
|
|
75
|
-
} else {
|
|
76
|
-
this.nodes.push(node);
|
|
77
|
-
|
|
78
|
-
if (node.endIndex === this.cursor.lastIndex()) {
|
|
79
|
-
this._processMatch();
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
this.cursor.next();
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private _processMatch() {
|
|
91
|
-
const endsOnDivider = this.nodes.length % 2 === 0;
|
|
92
|
-
const noMatch = this.nodes.length === 0;
|
|
93
|
-
const hasDivider = this._divider != null;
|
|
94
|
-
|
|
95
|
-
this.cursor.resolveError();
|
|
96
|
-
|
|
97
|
-
if ((hasDivider && endsOnDivider) || noMatch) {
|
|
98
|
-
const parseError = new ParseError(
|
|
99
|
-
`Did not find a repeating match of ${this.name}.`,
|
|
100
|
-
this.mark,
|
|
101
|
-
this
|
|
102
|
-
);
|
|
103
|
-
this.cursor.throwError(parseError);
|
|
104
|
-
this.node = null;
|
|
105
|
-
} else {
|
|
106
|
-
const value = this.nodes.map((node) => node.value).join("");
|
|
107
|
-
|
|
108
|
-
this.node = new ValueNode(
|
|
109
|
-
"repeat-value",
|
|
110
|
-
this.name,
|
|
111
|
-
value,
|
|
112
|
-
this.nodes[0].startIndex,
|
|
113
|
-
this.nodes[this.nodes.length - 1].endIndex
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
this.cursor.index = this.node.endIndex;
|
|
117
|
-
this.cursor.addMatch(this, this.node);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
clone(name?: string) {
|
|
122
|
-
if (typeof name !== "string") {
|
|
123
|
-
name = this.name;
|
|
124
|
-
}
|
|
125
|
-
return new RepeatValue(name, this._pattern, this._divider);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
getTokens() {
|
|
129
|
-
return this._pattern.getTokens();
|
|
130
|
-
}
|
|
131
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/** @jest-environment node */
|
|
2
|
-
import AndComposite from "../patterns/composite/AndComposite";
|
|
3
|
-
import Literal from "../patterns/value/Literal";
|
|
4
|
-
import OptionalValue from "../patterns/value/OptionalValue";
|
|
5
|
-
import Cursor from "../Cursor";
|
|
6
|
-
|
|
7
|
-
describe("AndComposite", () => {
|
|
8
|
-
test("Match", () => {
|
|
9
|
-
const john = new Literal("john", "John");
|
|
10
|
-
const doe = new Literal("doe", "Doe");
|
|
11
|
-
const cursor = new Cursor("JohnDoe");
|
|
12
|
-
const name = new AndComposite("name", [john, doe]);
|
|
13
|
-
|
|
14
|
-
const node = name.parse(cursor);
|
|
15
|
-
|
|
16
|
-
expect(node?.name).toBe("name");
|
|
17
|
-
expect(node?.children[0].name).toBe("john");
|
|
18
|
-
expect(node?.children[1].name).toBe("doe");
|
|
19
|
-
expect(node?.children[0].value).toBe("John");
|
|
20
|
-
expect(node?.children[1].value).toBe("Doe");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("AndComposite: No Match", () => {
|
|
24
|
-
const john = new Literal("john", "John");
|
|
25
|
-
const doe = new Literal("doe", "Doe");
|
|
26
|
-
const cursor = new Cursor("JohnSmith");
|
|
27
|
-
const name = new AndComposite("name", [john, doe]);
|
|
28
|
-
|
|
29
|
-
const node = name.parse(cursor);
|
|
30
|
-
|
|
31
|
-
expect(node).toBe(null);
|
|
32
|
-
expect(cursor.getIndex()).toBe(0);
|
|
33
|
-
expect(cursor.hasUnresolvedError()).toBe(true);
|
|
34
|
-
expect(cursor.parseError?.message).toBe(
|
|
35
|
-
"ParseError: Expected 'Doe' but found 'Smi'."
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("AndComposite: test.", () => {
|
|
40
|
-
const john = new Literal("john", "John");
|
|
41
|
-
const doe = new Literal("doe", "Doe");
|
|
42
|
-
const name = new AndComposite("name", [john, doe]);
|
|
43
|
-
const isMatch = name.test("JohnDoe");
|
|
44
|
-
|
|
45
|
-
expect(isMatch).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("AndComposite: no children.", () => {
|
|
49
|
-
expect(() => {
|
|
50
|
-
new AndComposite("name");
|
|
51
|
-
}).toThrow();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("AndComposite: string runs out before match is done.", () => {
|
|
55
|
-
const first = new Literal("first", "John");
|
|
56
|
-
const last = new Literal("last", "Doe");
|
|
57
|
-
const name = new AndComposite("name", [first, last]);
|
|
58
|
-
const cursor = new Cursor("JohnDo");
|
|
59
|
-
const result = name.parse(cursor);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("AndComposite: last name is optional.", () => {
|
|
63
|
-
const first = new Literal("first", "John");
|
|
64
|
-
const last = new OptionalValue(new Literal("last", "Boe"));
|
|
65
|
-
const name = new AndComposite("name", [first, last]);
|
|
66
|
-
const cursor = new Cursor("JohnDo");
|
|
67
|
-
const result = name.parse(cursor);
|
|
68
|
-
|
|
69
|
-
expect(result?.name).toBe("name");
|
|
70
|
-
expect(result?.type).toBe("and-composite");
|
|
71
|
-
expect(result?.children[0].value).toBe("John");
|
|
72
|
-
expect(result?.children[0].name).toBe("first");
|
|
73
|
-
expect(result?.children[0].type).toBe("literal");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("AndComposite: three non-optional patterns.", () => {
|
|
77
|
-
const first = new Literal("first", "John");
|
|
78
|
-
const middle = new Literal("middle", "Smith");
|
|
79
|
-
const last = new Literal("last", "Doe");
|
|
80
|
-
const name = new AndComposite("name", [first, middle, last]);
|
|
81
|
-
const cursor = new Cursor("JohnDoe");
|
|
82
|
-
const result = name.parse(cursor);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("AndComposite: full name, middle optional, and last name isn't.", () => {
|
|
86
|
-
const first = new Literal("first", "John");
|
|
87
|
-
const middle = new OptionalValue(new Literal("middle", "Smith"));
|
|
88
|
-
const last = new Literal("last", "Doe");
|
|
89
|
-
const name = new AndComposite("name", [first, middle, last]);
|
|
90
|
-
const cursor = new Cursor("JohnDoe");
|
|
91
|
-
const result = name.parse(cursor);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("AndComposite: clone.", () => {
|
|
95
|
-
const john = new Literal("john", "John");
|
|
96
|
-
const doe = new Literal("doe", "Doe");
|
|
97
|
-
const name = new AndComposite("name", [john, doe]);
|
|
98
|
-
const clone = name.clone("name2");
|
|
99
|
-
|
|
100
|
-
expect(clone.name).toBe("name2");
|
|
101
|
-
});
|
|
102
|
-
});
|