securemark 0.294.0 → 0.294.2
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/CHANGELOG.md +8 -0
- package/design.md +27 -39
- package/dist/index.js +208 -180
- package/package.json +2 -2
- package/src/combinator/control/constraint/contract.ts +2 -2
- package/src/combinator/control/constraint/line.ts +2 -2
- package/src/combinator/control/manipulation/clear.ts +2 -2
- package/src/combinator/control/manipulation/indent.ts +3 -7
- package/src/combinator/control/manipulation/lazy.ts +1 -3
- package/src/combinator/control/manipulation/scope.ts +4 -6
- package/src/combinator/control/manipulation/surround.ts +5 -8
- package/src/combinator/control/monad/bind.ts +2 -3
- package/src/combinator/data/data.ts +38 -32
- package/src/combinator/data/parser/context.test.ts +4 -4
- package/src/combinator/data/parser/inits.ts +6 -8
- package/src/combinator/data/parser/sequence.test.ts +2 -2
- package/src/combinator/data/parser/sequence.ts +5 -7
- package/src/combinator/data/parser/some.test.ts +2 -2
- package/src/combinator/data/parser/some.ts +5 -7
- package/src/combinator/data/parser/subsequence.test.ts +2 -2
- package/src/combinator/data/parser/subsequence.ts +2 -2
- package/src/combinator/data/parser/tails.ts +2 -2
- package/src/combinator/data/parser/union.test.ts +2 -2
- package/src/combinator/data/parser/union.ts +2 -2
- package/src/combinator/data/parser.ts +36 -39
- package/src/debug.test.ts +2 -2
- package/src/parser/api/bind.ts +6 -6
- package/src/parser/api/header.ts +2 -2
- package/src/parser/api/normalize.ts +2 -2
- package/src/parser/api/parse.ts +11 -11
- package/src/parser/block/codeblock.ts +2 -2
- package/src/parser/block/extension/example.ts +2 -2
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/message.ts +2 -2
- package/src/parser/block/extension/table.ts +2 -2
- package/src/parser/block.ts +5 -1
- package/src/parser/inline/autolink/url.test.ts +71 -72
- package/src/parser/inline/autolink/url.ts +4 -4
- package/src/parser/inline/emstrong.ts +5 -5
- package/src/parser/inline/reference.ts +2 -2
- package/src/parser/inline/ruby.ts +4 -4
- package/src/parser/processor/note.ts +2 -2
- package/src/parser/segment.ts +6 -12
- package/src/parser/source/line.ts +5 -0
- package/src/parser/source/str.ts +1 -1
- package/src/parser/util.ts +5 -4
- package/src/parser/visibility.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securemark",
|
|
3
|
-
"version": "0.294.
|
|
3
|
+
"version": "0.294.2",
|
|
4
4
|
"description": "Secure markdown renderer working on browsers for user input data.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/falsandtru/securemark",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"LICENSE"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"spica": "0.0.
|
|
31
|
+
"spica": "0.0.809"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/dompurify": "3.0.5",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Input, List, Data, Ctx, Node, Context,
|
|
1
|
+
import { Parser, Input, List, Data, Ctx, Node, Context, failsafe } from '../../data/parser';
|
|
2
2
|
import { matcher } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
//export function contract<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
|
|
@@ -37,7 +37,7 @@ export function verify<N>(parser: Parser<N>, cond: (nodes: List<Data<N>>, contex
|
|
|
37
37
|
if (position === source.length) return;
|
|
38
38
|
const result = parser(input);
|
|
39
39
|
assert(context.position > position || !result);
|
|
40
|
-
if (result && !cond(
|
|
40
|
+
if (result && !cond(result, context)) return;
|
|
41
41
|
return result;
|
|
42
42
|
});
|
|
43
43
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, input,
|
|
1
|
+
import { Parser, input, failsafe } from '../../data/parser';
|
|
2
2
|
|
|
3
3
|
export function line<P extends Parser<unknown>>(parser: P): P;
|
|
4
4
|
export function line<N>(parser: Parser<N>): Parser<N> {
|
|
@@ -18,7 +18,7 @@ export function line<N>(parser: Parser<N>): Parser<N> {
|
|
|
18
18
|
if (result === undefined) return;
|
|
19
19
|
if (!isBlank(source.slice(context.position, position + line.length))) return;
|
|
20
20
|
context.position = position + line.length;
|
|
21
|
-
return
|
|
21
|
+
return result;
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Parser, List,
|
|
1
|
+
import { Parser, List, Ctx } from '../../data/parser';
|
|
2
2
|
|
|
3
|
-
export function clear<D extends Parser<unknown, C>[], C extends
|
|
3
|
+
export function clear<D extends Parser<unknown, C>[], C extends Ctx>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
|
|
4
4
|
return input => parser(input) && new List();
|
|
5
5
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data, subinput,
|
|
1
|
+
import { Parser, List, Data, subinput, failsafe } from '../../data/parser';
|
|
2
2
|
import { some } from '../../data/parser/some';
|
|
3
3
|
import { block } from '../constraint/block';
|
|
4
4
|
import { line } from '../constraint/line';
|
|
@@ -26,14 +26,10 @@ export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolea
|
|
|
26
26
|
context.position = source.length;
|
|
27
27
|
return new List([new Data(source.slice(position))]);
|
|
28
28
|
}))),
|
|
29
|
-
([indent]) => indent.length * 2 + +(indent[0] === ' '),
|
|
29
|
+
([indent]) => indent.length <= 16 ? indent.length * 2 + +(indent[0] === ' ') : -1, [])), separation),
|
|
30
30
|
(lines, context) => {
|
|
31
31
|
assert(parser = parser as Parser<N>);
|
|
32
|
-
|
|
33
|
-
assert(result);
|
|
34
|
-
return result
|
|
35
|
-
? eval(result)
|
|
36
|
-
: undefined;
|
|
32
|
+
return parser(subinput(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context));
|
|
37
33
|
}));
|
|
38
34
|
}
|
|
39
35
|
|
|
@@ -4,7 +4,5 @@ export function lazy<P extends Parser<unknown>>(builder: () => P): P;
|
|
|
4
4
|
export function lazy<N>(builder: () => Parser<N>): Parser<N> {
|
|
5
5
|
let parser: Parser<N>;
|
|
6
6
|
return input =>
|
|
7
|
-
parser
|
|
8
|
-
? parser(input)
|
|
9
|
-
: (parser = builder())(input);
|
|
7
|
+
(parser ??= builder())(input);
|
|
10
8
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Context, input,
|
|
1
|
+
import { Parser, Context, input, failsafe } from '../../data/parser';
|
|
2
2
|
import { matcher } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
export function focus<P extends Parser<unknown>>(scope: string | RegExp, parser: P): P;
|
|
@@ -8,7 +8,7 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>): Parser<N> {
|
|
|
8
8
|
return failsafe(({ context }) => {
|
|
9
9
|
const { source, position } = context;
|
|
10
10
|
if (position === source.length) return;
|
|
11
|
-
const src =
|
|
11
|
+
const src = match({ context })?.head?.value ?? '';
|
|
12
12
|
assert(source.startsWith(src, position));
|
|
13
13
|
if (src === '') return;
|
|
14
14
|
context.range = src.length;
|
|
@@ -20,8 +20,7 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>): Parser<N> {
|
|
|
20
20
|
assert(context.position > position || !result);
|
|
21
21
|
context.source = source;
|
|
22
22
|
context.offset -= position;
|
|
23
|
-
|
|
24
|
-
return eval(result);
|
|
23
|
+
return result;
|
|
25
24
|
});
|
|
26
25
|
}
|
|
27
26
|
|
|
@@ -47,7 +46,6 @@ export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>): Parser<N>
|
|
|
47
46
|
assert(context.position > position || !res2);
|
|
48
47
|
context.source = source;
|
|
49
48
|
context.offset -= position;
|
|
50
|
-
|
|
51
|
-
return eval(res2);
|
|
49
|
+
return res2;
|
|
52
50
|
});
|
|
53
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser,
|
|
1
|
+
import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, failsafe } from '../../data/parser';
|
|
2
2
|
import { matcher, clear } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
@@ -52,29 +52,26 @@ export function surround<N>(
|
|
|
52
52
|
if (position === source.length) return;
|
|
53
53
|
const { linebreak } = context;
|
|
54
54
|
context.linebreak = 0;
|
|
55
|
-
const
|
|
55
|
+
const nodesO = opener(input);
|
|
56
56
|
assert(context.position >= position);
|
|
57
|
-
const nodesO = eval(resultO);
|
|
58
57
|
if (!nodesO) {
|
|
59
58
|
return void revert(context, linebreak);
|
|
60
59
|
}
|
|
61
60
|
if (isBacktrack(context, backtracks, position, context.position - position || 1)) {
|
|
62
61
|
return void revert(context, linebreak);
|
|
63
62
|
}
|
|
64
|
-
const
|
|
63
|
+
const nodesM = context.position < source.length ? parser(input) : undefined;
|
|
65
64
|
assert(context.position >= position);
|
|
66
65
|
context.range = context.position - position;
|
|
67
|
-
|
|
68
|
-
if (!resultM && !optional) {
|
|
66
|
+
if (!nodesM && !optional) {
|
|
69
67
|
setBacktrack(context, backtracks, position);
|
|
70
68
|
const result = g?.([nodesO, nodesM], context);
|
|
71
69
|
revert(context, linebreak);
|
|
72
70
|
return result;
|
|
73
71
|
}
|
|
74
|
-
const
|
|
72
|
+
const nodesC = nodesM || optional ? closer(input) : undefined;
|
|
75
73
|
assert(context.position >= position);
|
|
76
74
|
context.range = context.position - position;
|
|
77
|
-
const nodesC = eval(resultC);
|
|
78
75
|
if (!nodesC) {
|
|
79
76
|
setBacktrack(context, backtracks, position);
|
|
80
77
|
const result = g?.([nodesO, nodesM], context);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser,
|
|
1
|
+
import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, failsafe } from '../../data/parser';
|
|
2
2
|
|
|
3
3
|
export function bind<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: List<Data<SubNode<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
4
4
|
export function bind<P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
@@ -14,9 +14,8 @@ export function bind<N, U>(parser: Parser<N>, f: (nodes: List<Data<N>>, context:
|
|
|
14
14
|
assert(context.position > position || !res1);
|
|
15
15
|
if (res1 === undefined) return;
|
|
16
16
|
context.range = context.position - position;
|
|
17
|
-
const res2 = f(
|
|
17
|
+
const res2 = f(res1, context);
|
|
18
18
|
assert(context.position > position || !res2);
|
|
19
|
-
if (res2 === undefined) return;
|
|
20
19
|
return context.position > position
|
|
21
20
|
? res2
|
|
22
21
|
: undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { Parser, Ctx } from './parser';
|
|
2
2
|
|
|
3
|
-
export class List<N extends List.Node = List.Node> {
|
|
3
|
+
export class List<N extends List.Node = List.Node, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any> {
|
|
4
4
|
constructor(nodes?: ArrayLike<N>) {
|
|
5
5
|
if (nodes === undefined) return;
|
|
6
6
|
for (let i = 0; i < nodes.length; ++i) {
|
|
@@ -9,47 +9,55 @@ export class List<N extends List.Node = List.Node> {
|
|
|
9
9
|
}
|
|
10
10
|
public length = 0;
|
|
11
11
|
public head?: N = undefined;
|
|
12
|
+
public last?: N = undefined;
|
|
12
13
|
public get tail(): N | undefined {
|
|
13
14
|
return this.head?.next;
|
|
14
15
|
}
|
|
15
|
-
public get last(): N | undefined {
|
|
16
|
-
return this.head?.prev;
|
|
17
|
-
}
|
|
18
16
|
public insert(node: N, before?: N): N {
|
|
19
|
-
assert(!node.next);
|
|
17
|
+
assert(!node.next && !node.prev);
|
|
18
|
+
if (before === undefined) return this.push(node);
|
|
19
|
+
if (before === this.head) return this.unshift(node);
|
|
20
20
|
if (++this.length === 1) {
|
|
21
|
-
return this.head =
|
|
21
|
+
return this.head = this.last = node;
|
|
22
22
|
}
|
|
23
23
|
assert(node !== before);
|
|
24
|
-
const next = node.next = before
|
|
24
|
+
const next = node.next = before;
|
|
25
25
|
const prev = node.prev = next.prev!;
|
|
26
26
|
return next.prev = prev.next = node;
|
|
27
27
|
}
|
|
28
28
|
public delete(node: N): N {
|
|
29
|
-
assert(node.next);
|
|
29
|
+
assert(node.next || node.prev || this.head === this.last);
|
|
30
30
|
assert(this.length > 0);
|
|
31
31
|
if (--this.length === 0) {
|
|
32
|
-
this.head = undefined;
|
|
32
|
+
this.head = this.last = undefined;
|
|
33
33
|
}
|
|
34
34
|
else {
|
|
35
35
|
const { next, prev } = node;
|
|
36
|
-
|
|
37
|
-
this.head = next
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
prev === undefined
|
|
37
|
+
? this.head = next
|
|
38
|
+
: prev.next = next;
|
|
39
|
+
next === undefined
|
|
40
|
+
? this.last = prev
|
|
41
|
+
: next.prev = prev;
|
|
42
42
|
}
|
|
43
43
|
node.next = node.prev = undefined;
|
|
44
44
|
return node;
|
|
45
45
|
}
|
|
46
46
|
public unshift(node: N): N {
|
|
47
|
-
assert(!node.next);
|
|
48
|
-
|
|
47
|
+
assert(!node.next && !node.prev);
|
|
48
|
+
if (++this.length === 1) {
|
|
49
|
+
return this.head = this.last = node;
|
|
50
|
+
}
|
|
51
|
+
node.next = this.head;
|
|
52
|
+
return this.head = this.head!.prev = node;
|
|
49
53
|
}
|
|
50
54
|
public push(node: N): N {
|
|
51
|
-
assert(!node.next);
|
|
52
|
-
|
|
55
|
+
assert(!node.next && !node.prev);
|
|
56
|
+
if (++this.length === 1) {
|
|
57
|
+
return this.head = this.last = node;
|
|
58
|
+
}
|
|
59
|
+
node.prev = this.last;
|
|
60
|
+
return this.last = this.last!.next = node;
|
|
53
61
|
}
|
|
54
62
|
public shift(): N | undefined {
|
|
55
63
|
if (this.length === 0) return;
|
|
@@ -57,22 +65,25 @@ export class List<N extends List.Node = List.Node> {
|
|
|
57
65
|
}
|
|
58
66
|
public pop(): N | undefined {
|
|
59
67
|
if (this.length === 0) return;
|
|
60
|
-
return this.delete(this.
|
|
68
|
+
return this.delete(this.last!);
|
|
61
69
|
}
|
|
62
70
|
public import(list: List<N>, before?: N): this {
|
|
63
71
|
assert(list !== this);
|
|
64
72
|
if (list.length === 0) return this;
|
|
65
73
|
if (this.length === 0) {
|
|
66
74
|
this.head = list.head;
|
|
67
|
-
this.
|
|
75
|
+
this.last = list.last;
|
|
76
|
+
this.length = list.length;
|
|
68
77
|
list.clear();
|
|
69
78
|
return this;
|
|
70
79
|
}
|
|
71
80
|
const head = list.head!;
|
|
72
81
|
const last = list.last!;
|
|
73
|
-
const next = last.next = before
|
|
74
|
-
const prev = head.prev =
|
|
75
|
-
next
|
|
82
|
+
const next = last.next = before;
|
|
83
|
+
const prev = head.prev = before?.prev ?? this.last!;
|
|
84
|
+
next === undefined
|
|
85
|
+
? this.last = last
|
|
86
|
+
: next.prev = last;
|
|
76
87
|
prev.next = head;
|
|
77
88
|
this.length += list.length;
|
|
78
89
|
list.clear();
|
|
@@ -80,14 +91,13 @@ export class List<N extends List.Node = List.Node> {
|
|
|
80
91
|
}
|
|
81
92
|
public clear(): void {
|
|
82
93
|
this.length = 0;
|
|
83
|
-
this.head = undefined;
|
|
94
|
+
this.head = this.last = undefined;
|
|
84
95
|
}
|
|
85
96
|
public *[Symbol.iterator](): Iterator<N, undefined, undefined> {
|
|
86
97
|
for (let node = this.head; node && this.head;) {
|
|
87
98
|
const next = node.next;
|
|
88
99
|
yield node;
|
|
89
100
|
node = next;
|
|
90
|
-
if (node === this.head) break;
|
|
91
101
|
}
|
|
92
102
|
}
|
|
93
103
|
public flatMap<T extends List.Node>(f: (node: N) => List<T>): List<T> {
|
|
@@ -96,7 +106,6 @@ export class List<N extends List.Node = List.Node> {
|
|
|
96
106
|
const next = node.next;
|
|
97
107
|
acc.import(f(node));
|
|
98
108
|
node = next;
|
|
99
|
-
if (node === this.head) break;
|
|
100
109
|
}
|
|
101
110
|
return acc;
|
|
102
111
|
}
|
|
@@ -105,15 +114,13 @@ export class List<N extends List.Node = List.Node> {
|
|
|
105
114
|
const next = node.next;
|
|
106
115
|
acc = f(acc, node);
|
|
107
116
|
node = next;
|
|
108
|
-
if (node === this.head) break;
|
|
109
117
|
}
|
|
110
118
|
return acc;
|
|
111
119
|
}
|
|
112
120
|
public foldr<T>(f: (node: N, acc: T) => T, acc: T): T {
|
|
113
|
-
for (let node = this.
|
|
121
|
+
for (let node = this.last; node && this.head;) {
|
|
114
122
|
const prev = node.prev;
|
|
115
123
|
acc = f(node, acc);
|
|
116
|
-
if (node === this.head) break;
|
|
117
124
|
node = prev;
|
|
118
125
|
}
|
|
119
126
|
return acc;
|
|
@@ -123,7 +130,6 @@ export class List<N extends List.Node = List.Node> {
|
|
|
123
130
|
const next = node.next;
|
|
124
131
|
if (f(node)) return node;
|
|
125
132
|
node = next;
|
|
126
|
-
if (node === this.head) break;
|
|
127
133
|
}
|
|
128
134
|
}
|
|
129
135
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data, Ctx, CtxOptions, input
|
|
1
|
+
import { Parser, List, Data, Ctx, CtxOptions, input } from '../parser';
|
|
2
2
|
import { some } from './some';
|
|
3
3
|
import { reset, context, creation } from './context';
|
|
4
4
|
import { unwrap } from '../../../parser/util';
|
|
@@ -18,7 +18,7 @@ describe('Unit: combinator/data/parser/context', () => {
|
|
|
18
18
|
it('root', () => {
|
|
19
19
|
const base: Context = { resources: { clock: 3, recursions: [1] } };
|
|
20
20
|
const ctx: Context = {};
|
|
21
|
-
assert.deepStrictEqual([...unwrap(
|
|
21
|
+
assert.deepStrictEqual([...unwrap(reset(base, parser)(input('123', ctx))!)], [3, 2, 1]);
|
|
22
22
|
assert(base.resources?.clock === 3);
|
|
23
23
|
assert(ctx.resources?.clock === undefined);
|
|
24
24
|
assert.throws(() => reset(base, parser)(input('1234', ctx)));
|
|
@@ -28,7 +28,7 @@ describe('Unit: combinator/data/parser/context', () => {
|
|
|
28
28
|
it('node', () => {
|
|
29
29
|
const base: Context = { resources: { clock: 3, recursions: [1] } };
|
|
30
30
|
const ctx: Context = { resources: { clock: 2, recursions: [1] } };
|
|
31
|
-
assert.deepStrictEqual([...unwrap(
|
|
31
|
+
assert.deepStrictEqual([...unwrap(reset(base, parser)(input('1', ctx))!)], [2]);
|
|
32
32
|
assert(base.resources?.clock === 3);
|
|
33
33
|
assert(ctx.resources?.clock === 1);
|
|
34
34
|
assert.throws(() => reset(base, parser)(input('12', ctx)));
|
|
@@ -47,7 +47,7 @@ describe('Unit: combinator/data/parser/context', () => {
|
|
|
47
47
|
it('', () => {
|
|
48
48
|
const base: Context = { status: true };
|
|
49
49
|
const ctx: Context = { resources: { clock: 2, recursions: [1] } };
|
|
50
|
-
assert.deepStrictEqual([...unwrap(
|
|
50
|
+
assert.deepStrictEqual([...unwrap(context(base, parser)(input('1', ctx))!)], [true]);
|
|
51
51
|
assert(base.resources?.clock === undefined);
|
|
52
52
|
assert(ctx.resources?.clock === 1);
|
|
53
53
|
assert(ctx.status === undefined);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Parser, List, Data,
|
|
1
|
+
import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
|
|
3
|
-
export function inits<P extends Parser<unknown
|
|
4
|
-
export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N,
|
|
3
|
+
export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
4
|
+
export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
|
|
5
5
|
assert(parsers.every(f => f));
|
|
6
6
|
if (parsers.length === 1) return parsers[0];
|
|
7
7
|
return input => {
|
|
@@ -13,13 +13,11 @@ export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: Lis
|
|
|
13
13
|
if (context.delimiters?.match(input)) break;
|
|
14
14
|
const result = parsers[i](input);
|
|
15
15
|
if (result === undefined) break;
|
|
16
|
-
nodes = nodes
|
|
17
|
-
|
|
18
|
-
: eval(result);
|
|
19
|
-
if (resume?.(eval(result)) === false) break;
|
|
16
|
+
nodes = nodes?.import(result) ?? result;
|
|
17
|
+
if (resume?.(result) === false) break;
|
|
20
18
|
}
|
|
21
19
|
assert(context.position >= position);
|
|
22
|
-
return
|
|
20
|
+
return context.position > position
|
|
23
21
|
? nodes
|
|
24
22
|
: undefined;
|
|
25
23
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data, input } from '../parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, input } from '../parser';
|
|
2
2
|
import { sequence } from './sequence';
|
|
3
3
|
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@ describe('Unit: combinator/data/parser/sequence', () => {
|
|
|
14
14
|
? void ++context.position || new List([new Data('B')])
|
|
15
15
|
: undefined;
|
|
16
16
|
};
|
|
17
|
-
const ab = sequence<Parser<string,
|
|
17
|
+
const ab = sequence<Parser<string, Ctx, [typeof a, typeof b]>>([a, b]);
|
|
18
18
|
const { context: ctx } = input('', {});
|
|
19
19
|
|
|
20
20
|
it('basic', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Parser, List, Data,
|
|
1
|
+
import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
|
|
3
3
|
export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
4
|
-
export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N,
|
|
4
|
+
export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
|
|
5
5
|
assert(parsers.every(f => f));
|
|
6
6
|
if (parsers.length === 1) return parsers[0];
|
|
7
7
|
return input => {
|
|
@@ -13,13 +13,11 @@ export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes:
|
|
|
13
13
|
if (context.delimiters?.match(input)) return;
|
|
14
14
|
const result = parsers[i](input);
|
|
15
15
|
if (result === undefined) return;
|
|
16
|
-
nodes = nodes
|
|
17
|
-
|
|
18
|
-
: eval(result);
|
|
19
|
-
if (resume?.(eval(result)) === false) return;
|
|
16
|
+
nodes = nodes?.import(result) ?? result;
|
|
17
|
+
if (resume?.(result) === false) return;
|
|
20
18
|
}
|
|
21
19
|
assert(context.position >= position);
|
|
22
|
-
return
|
|
20
|
+
return context.position > position
|
|
23
21
|
? nodes
|
|
24
22
|
: undefined;
|
|
25
23
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data, input } from '../parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, input } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { some } from './some';
|
|
4
4
|
import { inspect } from '../../../debug.test';
|
|
@@ -15,7 +15,7 @@ describe('Unit: combinator/data/parser/some', () => {
|
|
|
15
15
|
? void ++context.position || new List([new Data('B')])
|
|
16
16
|
: undefined;
|
|
17
17
|
};
|
|
18
|
-
const ab = union<Parser<string,
|
|
18
|
+
const ab = union<Parser<string, Ctx, [typeof a, typeof b]>>([a, b]);
|
|
19
19
|
const { context: ctx } = input('', {});
|
|
20
20
|
|
|
21
21
|
it('basic', () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data
|
|
1
|
+
import { Parser, List, Data } from '../parser';
|
|
2
2
|
import { Delimiters } from './context/delimiter';
|
|
3
3
|
|
|
4
4
|
type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
|
|
@@ -23,22 +23,20 @@ export function some<N>(parser: Parser<N>, end?: string | RegExp | number, delim
|
|
|
23
23
|
context.delimiters ??= new Delimiters();
|
|
24
24
|
context.delimiters.push(delims);
|
|
25
25
|
}
|
|
26
|
-
while
|
|
27
|
-
|
|
26
|
+
// whileは数倍遅い
|
|
27
|
+
for (; context.position < source.length;) {
|
|
28
28
|
if (match(input)) break;
|
|
29
29
|
if (context.delimiters?.match(input)) break;
|
|
30
30
|
const result = parser(input);
|
|
31
31
|
if (result === undefined) break;
|
|
32
|
-
nodes = nodes
|
|
33
|
-
? nodes.import(eval(result))
|
|
34
|
-
: eval(result);
|
|
32
|
+
nodes = nodes?.import(result) ?? result;
|
|
35
33
|
if (limit >= 0 && context.position - position > limit) break;
|
|
36
34
|
}
|
|
37
35
|
if (delims.length > 0) {
|
|
38
36
|
context.delimiters!.pop(delims.length);
|
|
39
37
|
}
|
|
40
38
|
assert(context.position >= position);
|
|
41
|
-
return
|
|
39
|
+
return context.position > position
|
|
42
40
|
? nodes
|
|
43
41
|
: undefined;
|
|
44
42
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data, input } from '../parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, input } from '../parser';
|
|
2
2
|
import { subsequence } from './subsequence';
|
|
3
3
|
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ describe('Unit: combinator/data/parser/subsequence', () => {
|
|
|
19
19
|
? void ++context.position || new List([new Data('C')])
|
|
20
20
|
: undefined;
|
|
21
21
|
};
|
|
22
|
-
const abc = subsequence<Parser<string,
|
|
22
|
+
const abc = subsequence<Parser<string, Ctx, [typeof a, typeof b, typeof c]>>([a, b, c]);
|
|
23
23
|
const { context: ctx } = input('', {});
|
|
24
24
|
|
|
25
25
|
it('basic', () => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Parser, List, Data,
|
|
1
|
+
import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { inits } from './inits';
|
|
4
4
|
|
|
5
5
|
export function subsequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
6
|
-
export function subsequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N,
|
|
6
|
+
export function subsequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
|
|
7
7
|
assert(parsers.every(f => f));
|
|
8
8
|
return union(
|
|
9
9
|
parsers.map((_, i) =>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Parser, List, Data,
|
|
1
|
+
import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { sequence } from './sequence';
|
|
4
4
|
|
|
5
5
|
export function tails<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
6
|
-
export function tails<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N,
|
|
6
|
+
export function tails<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
|
|
7
7
|
return union(parsers.map((_, i) => sequence(parsers.slice(i), resume)) as D);
|
|
8
8
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, List, Data, input } from '../parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, input } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@ describe('Unit: combinator/data/parser/union', () => {
|
|
|
14
14
|
? void ++context.position || new List([new Data('B')])
|
|
15
15
|
: undefined;
|
|
16
16
|
};
|
|
17
|
-
const ab = union<Parser<string,
|
|
17
|
+
const ab = union<Parser<string, Ctx, [typeof a, typeof b]>>([a, b]);
|
|
18
18
|
const { context: ctx } = input('', {});
|
|
19
19
|
|
|
20
20
|
it('basic', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Parser,
|
|
1
|
+
import { Parser, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
|
|
3
3
|
export function union<P extends Parser<unknown>>(parsers: SubParsers<P>): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
4
|
-
export function union<N, D extends Parser<N>[]>(parsers: D): Parser<N,
|
|
4
|
+
export function union<N, D extends Parser<N>[]>(parsers: D): Parser<N, Ctx, D> {
|
|
5
5
|
assert(parsers.every(f => f));
|
|
6
6
|
switch (parsers.length) {
|
|
7
7
|
case 0:
|