Skip to content

Commit e205692

Browse files
fix support for nested range quantifiers
1 parent 5ad5fe2 commit e205692

File tree

6 files changed

+65
-75
lines changed

6 files changed

+65
-75
lines changed

assembly/__spec_tests__/generated.spec.ts

+49-20
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ xit("line: 78 - lazy quantifiers are not supported", () => {});
411411
xit("line: 79 - lazy quantifiers are not supported", () => {});
412412
xit("line: 80 - lazy quantifiers are not supported", () => {});
413413
xit("line: 81 - lazy quantifiers are not supported", () => {});
414-
xit("line: 82 - test regex is not supported in JS", () => {});
414+
xit("line: 82 - test regex contains syntax not supported in JS", () => {});
415415
it("line: 83 - matches ^[ab\\]cde] against 'athing'", () => {
416416
const match = exec("^[ab\\]cde]", "athing", "");
417417
expect(match.matches[0]).toBe("athing".substring(0, 1));
@@ -674,13 +674,17 @@ it("line: 152 - matches ([\\da-f:]+)$ against 'abc'", () => {
674674
expect(match.matches[0]).toBe("abc".substring(0, 3));
675675
expect(match.matches[1]).toBe("abc".substring(0, 3));
676676
});
677-
xit("line: 153 - requires triage", () => {});
677+
xit("line: 153 - aspect [Actual]: <Match>null vs [Expected]: Not <Match>null issue", () => {});
678678
it("line: 154 - matches ([\\da-f:]+)$ against 'E'", () => {
679679
const match = exec("([\\da-f:]+)$", "E", "i");
680680
expect(match.matches[0]).toBe("E".substring(0, 1));
681681
expect(match.matches[1]).toBe("E".substring(0, 1));
682682
});
683-
xit("line: 155 - requires triage", () => {});
683+
it("line: 155 - matches ([\\da-f:]+)$ against '::'", () => {
684+
const match = exec("([\\da-f:]+)$", "::", "i");
685+
expect(match.matches[0]).toBe("::".substring(0, 2));
686+
expect(match.matches[1]).toBe("::".substring(0, 2));
687+
});
684688
it("line: 156 - matches ([\\da-f:]+)$ against '5f03:12C0::932e'", () => {
685689
const match = exec("([\\da-f:]+)$", "5f03:12C0::932e", "i");
686690
expect(match.matches[0]).toBe("5f03:12C0::932e".substring(0, 15));
@@ -1070,8 +1074,32 @@ xit("line: 257 - non capturing groups not supported", () => {});
10701074
xit("line: 258 - back references are not supported", () => {});
10711075
xit("line: 259 - back references are not supported", () => {});
10721076
xit("line: 260 - back references are not supported", () => {});
1073-
xit("line: 261 - requires triage", () => {});
1074-
xit("line: 262 - requires triage", () => {});
1077+
it("line: 261 - matches ^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9] against 'From abcd Mon Sep 01 12:33:02 1997'", () => {
1078+
const match = exec(
1079+
"^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]",
1080+
"From abcd Mon Sep 01 12:33:02 1997",
1081+
""
1082+
);
1083+
expect(match.matches[0]).toBe(
1084+
"From abcd Mon Sep 01 12:33:02 1997".substring(0, 27)
1085+
);
1086+
expect(match.matches[1]).toBe(
1087+
"From abcd Mon Sep 01 12:33:02 1997".substring(5, 9)
1088+
);
1089+
});
1090+
it("line: 262 - matches ^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d against 'From abcd Mon Sep 01 12:33:02 1997'", () => {
1091+
const match = exec(
1092+
"^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",
1093+
"From abcd Mon Sep 01 12:33:02 1997",
1094+
""
1095+
);
1096+
expect(match.matches[0]).toBe(
1097+
"From abcd Mon Sep 01 12:33:02 1997".substring(0, 27)
1098+
);
1099+
expect(match.matches[1]).toBe(
1100+
"From abcd Mon Sep 01 12:33:02 1997".substring(15, 19)
1101+
);
1102+
});
10751103
xit("line: 263 - requires triage", () => {});
10761104
xit("line: 264 - requires triage", () => {});
10771105
xit("line: 265 - test cases with CRs not supported yet!", () => {});
@@ -1084,7 +1112,10 @@ xit("line: 271 - non capturing groups not supported", () => {});
10841112
xit("line: 272 - non capturing groups not supported", () => {});
10851113
xit("line: 273 - non capturing groups not supported", () => {});
10861114
xit("line: 274 - non capturing groups not supported", () => {});
1087-
xit("line: 281 - requires triage", () => {});
1115+
it("line: 281 - matches ^abcd#rhubarb against 'abcd'", () => {
1116+
const match = exec("^abcd#rhubarb", "abcd", "");
1117+
expect(match.matches[0]).toBe("abcd".substring(0, 4));
1118+
});
10881119
xit("line: 282 - back references are not supported", () => {});
10891120
xit("line: 283 - back references are not supported", () => {});
10901121
xit("line: 284 - back references are not supported", () => {});
@@ -1266,7 +1297,7 @@ it("line: 1154 - matches ^abc$ against 'abc'", () => {
12661297
xit("line: 1155 - test cases with CRs not supported yet!", () => {});
12671298
xit("line: 1156 - test cases with CRs not supported yet!", () => {});
12681299
xit("line: 1157 - test cases with CRs not supported yet!", () => {});
1269-
xit("line: 1158 - requires triage", () => {});
1300+
xit("line: 1158 - test regex contains syntax not supported in JS", () => {});
12701301
xit("line: 1159 - test cases with CRs not supported yet!", () => {});
12711302
xit("line: 1160 - test cases with CRs not supported yet!", () => {});
12721303
xit("line: 1161 - test cases with CRs not supported yet!", () => {});
@@ -1378,15 +1409,13 @@ xit("line: 1228 - back references are not supported", () => {});
13781409
xit("line: 1229 - back references are not supported", () => {});
13791410
xit("line: 1230 - back references are not supported", () => {});
13801411
xit("line: 1231 - test cases with CRs not supported yet!", () => {});
1381-
xit("line: 1232 - requires triage", () => {});
1382-
xit("line: 1233 - requires triage", () => {});
1383-
xit("line: 1234 - requires triage", () => {});
1384-
xit("line: 1235 - requires triage", () => {});
1385-
it("line: 1236 - matches ^([^a])([^\\\b])([^c]*)([^d]{3,4}) against 'anything'", () => {
1386-
expectNotMatch("^([^a])([^\\\b])([^c]*)([^d]{3,4})", ["anything"]);
1387-
});
1388-
xit("line: 1237 - requires triage", () => {});
1389-
xit("line: 1238 - requires triage", () => {});
1412+
xit("line: 1232 - word boundary class not supported yet!", () => {});
1413+
xit("line: 1233 - word boundary class not supported yet!", () => {});
1414+
xit("line: 1234 - word boundary class not supported yet!", () => {});
1415+
xit("line: 1235 - word boundary class not supported yet!", () => {});
1416+
xit("line: 1236 - word boundary class not supported yet!", () => {});
1417+
xit("line: 1237 - word boundary class not supported yet!", () => {});
1418+
xit("line: 1238 - word boundary class not supported yet!", () => {});
13901419
xit("line: 1239 - requires triage", () => {});
13911420
it("line: 1240 - matches [^a] against 'Abc'", () => {
13921421
const match = exec("[^a]", "Abc", "");
@@ -1507,7 +1536,7 @@ xit("line: 1276 - non capturing groups not supported", () => {});
15071536
xit("line: 1277 - non capturing groups not supported", () => {});
15081537
xit("line: 1278 - non capturing groups not supported", () => {});
15091538
xit("line: 1279 - non capturing groups not supported", () => {});
1510-
xit("line: 1280 - requires triage", () => {});
1539+
xit("line: 1280 - word boundary class not supported yet!", () => {});
15111540
it("line: 1281 - matches foo(.*)bar against 'The food is under the bar in the barn.'", () => {
15121541
const match = exec(
15131542
"foo(.*)bar",
@@ -1543,7 +1572,7 @@ it("line: 1287 - matches (.*)(\\d+)$ against 'I have 2 numbers: 53147'", () => {
15431572
expect(match.matches[2]).toBe("I have 2 numbers: 53147".substring(22, 23));
15441573
});
15451574
xit("line: 1288 - lazy quantifiers are not supported", () => {});
1546-
xit("line: 1289 - requires triage", () => {});
1575+
xit("line: 1289 - word boundary class not supported yet!", () => {});
15471576
it("line: 1290 - matches (.*\\D)(\\d+)$ against 'I have 2 numbers: 53147'", () => {
15481577
const match = exec("(.*\\D)(\\d+)$", "I have 2 numbers: 53147", "");
15491578
expect(match.matches[0]).toBe("I have 2 numbers: 53147".substring(0, 23));
@@ -1888,8 +1917,8 @@ it("line: 1406 - matches ab\\d{0}e against 'ab1e '", () => {
18881917
xit("line: 1407 - test cases with quotes are not supported yet!", () => {});
18891918
xit("line: 1408 - test cases with quotes are not supported yet!", () => {});
18901919
xit("line: 1409 - lazy quantifiers are not supported", () => {});
1891-
xit("line: 1410 - requires triage", () => {});
1892-
xit("line: 1411 - test doesn't support NULL", () => {});
1920+
xit("line: 1410 - word boundary class not supported yet!", () => {});
1921+
xit("line: 1411 - word boundary class not supported yet!", () => {});
18931922
xit("line: 1412 - requires triage", () => {});
18941923
xit("line: 1413 - requires triage", () => {});
18951924
it("line: 1414 - matches a[^a]b against 'acb'", () => {

assembly/__tests__/range-quantifiers.spec.ts

+4
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ it("handles imcomplete quantifier ", () => {
3333
expectMatch("a{2,3a", ["a{2,3a"]);
3434
expectMatch("a{2,3a}", ["a{2,3a}"]);
3535
});
36+
37+
it("handles nested quantifiers", () => {
38+
expectMatch("(a{3}){2}", ["aaaaaa"]);
39+
});

assembly/parser/node.ts

+4
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ export class RangeRepetitionNode extends Node {
162162
replace(node: Node, replacement: Node): void {
163163
this.expression = replacement;
164164
}
165+
166+
children(): Node[] {
167+
return [this.expression];
168+
}
165169
}
166170

167171
export class AlternationNode extends Node {

assembly/parser/walker.ts

-42
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Char } from "../char";
22
import {
3-
AssertionNode,
43
AST,
54
ConcatenationNode,
65
Node,
@@ -10,13 +9,7 @@ import {
109
} from "./node";
1110

1211
export class NodeVisitor {
13-
_delete: bool = false;
14-
1512
constructor(public node: Node, public parentNode: Node) {}
16-
17-
delete(): void {
18-
this._delete = true;
19-
}
2013
}
2114

2215
function walkNode(
@@ -31,26 +24,6 @@ function walkNode(
3124

3225
const nodeVisitor = new NodeVisitor(node, parentNode);
3326
visitor(nodeVisitor);
34-
35-
// TODO - the delete function is a bit half-baked, it needs to crawl up the tree
36-
if (nodeVisitor._delete) {
37-
if (parentNode != null && parentNode.type == NodeType.Concatenation) {
38-
const _c = parentNode as ConcatenationNode;
39-
const expressions = _c.expressions;
40-
const index = expressions.indexOf(node);
41-
const subset = expressions
42-
.slice(0, index)
43-
.concat(expressions.slice(index + 1));
44-
_c.expressions = subset;
45-
} else if (parentNode != null && parentNode.type == NodeType.AST) {
46-
const _c = parentNode as AST;
47-
// c.body = null;
48-
} else {
49-
throw new Error(
50-
"cannot delete a node that doesn't have a ConcatenationNode parent"
51-
);
52-
}
53-
}
5427
}
5528

5629
// depth first, right-left walker
@@ -61,21 +34,6 @@ export function walker(ast: AST, visitor: (node: NodeVisitor) => void): void {
6134
}
6235
}
6336

64-
export function deleteAssertionNodes(nodeVisitor: NodeVisitor): void {
65-
if (AssertionNode.is(nodeVisitor.node)) {
66-
nodeVisitor.delete();
67-
}
68-
}
69-
70-
export function deleteEmptyConcatenationNodes(nodeVisitor: NodeVisitor): void {
71-
let node = nodeVisitor.node;
72-
if (node.type == NodeType.Concatenation) {
73-
if ((node as ConcatenationNode).expressions.length == 0) {
74-
nodeVisitor.delete();
75-
}
76-
}
77-
}
78-
7937
// range quantifiers are implemented via 'expansion', which significantly
8038
// increases the size of the AST. This imposes a hard limit to prevent
8139
// memory-related issues

spec/test-generator.js

+6-11
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,6 @@ const knownIssues = {
1717
"issues with repeated capture groups": [...range(63, 68), 1391, 1392],
1818
"bug that needs filing": [1102],
1919
"requires triage": [
20-
141,
21-
153,
22-
155,
23-
255,
24-
1158,
25-
...range(1232, 1235),
26-
1280,
27-
1289,
28-
256,
29-
261,
3020
262,
3121
281,
3222
264,
@@ -64,7 +54,7 @@ const knownIssues = {
6454
],
6555
"as-pect test issue": [1145, 1146],
6656
"test indicates a malformed regex, whereas it appears OK in JS": [1189],
67-
"test regex is not supported in JS": [82],
57+
"test regex contains syntax not supported in JS": [82, 1158],
6858
"test doesn't support NULL": [1411],
6959
"aspect [Actual]: <Match>null vs [Expected]: Not <Match>null issue": [
7060
153,
@@ -120,6 +110,11 @@ lines.forEach((line, index) => {
120110
return;
121111
}
122112

113+
if (regex.includes("\\b")) {
114+
testCase += `xit("line: ${index} - word boundary class not supported yet!", () => { });`;
115+
return;
116+
}
117+
123118
if (str.includes("\\n")) {
124119
testCase += `xit("line: ${index} - test cases with CRs not supported yet!", () => { });`;
125120
return;

ts/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ globalAny.log = console.log;
55

66
import { RegExp } from "../assembly/regexp";
77

8-
const regexObj = new RegExp("\\�");
9-
const match = regexObj.exec("");
8+
const regexObj = new RegExp("(a{3}){2}");
9+
const match = regexObj.exec("From abcd Mon Sep 01 12:33:02 1997");
1010

1111
console.log(match);

0 commit comments

Comments
 (0)