securemark 0.299.4 → 0.300.1
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 +0 -6
- package/dist/index.js +2847 -1993
- package/index.d.ts +2 -1
- package/markdown.d.ts +209 -183
- package/package.json +1 -1
- package/src/api/bind.test.ts +0 -22
- package/src/api/bind.ts +15 -10
- package/src/api/header.ts +8 -5
- package/src/api/parse.test.ts +118 -122
- package/src/api/parse.ts +13 -31
- package/src/api/run.ts +6 -0
- package/src/api.ts +1 -0
- package/src/combinator/control/inits.ts +35 -0
- package/src/combinator/control/sequence.test.ts +38 -0
- package/src/combinator/control/sequence.ts +19 -0
- package/src/combinator/control/some.test.ts +41 -0
- package/src/combinator/{data/parser → control}/some.ts +39 -26
- package/src/combinator/control/state.ts +33 -0
- package/src/combinator/control/subsequence.test.ts +47 -0
- package/src/combinator/control/subsequence.ts +16 -0
- package/src/combinator/control/tails.ts +8 -0
- package/src/combinator/control/union.test.ts +37 -0
- package/src/combinator/control/union.ts +31 -0
- package/src/combinator/{data/delimiter.ts → delimiter.ts} +40 -60
- package/src/combinator/effect/backtrack.ts +64 -0
- package/src/combinator/effect/clock.ts +10 -0
- package/src/combinator/effect/precedence.ts +50 -0
- package/src/combinator/effect/recursion.ts +30 -0
- package/src/combinator/effect/scope.ts +100 -0
- package/src/combinator/effect/state.ts +72 -0
- package/src/combinator/{data/list → parser}/list.ts +35 -10
- package/src/combinator/parser.ts +303 -0
- package/src/combinator/process/bind.ts +34 -0
- package/src/combinator/process/block.test.ts +20 -0
- package/src/combinator/process/block.ts +33 -0
- package/src/combinator/process/clear.ts +16 -0
- package/src/combinator/process/contract.ts +35 -0
- package/src/combinator/process/duplicate.ts +7 -0
- package/src/combinator/process/error.ts +13 -0
- package/src/combinator/{control/manipulation → process}/fallback.ts +3 -3
- package/src/combinator/process/fence.ts +59 -0
- package/src/combinator/process/fmap.ts +10 -0
- package/src/combinator/process/indent.test.ts +31 -0
- package/src/combinator/process/indent.ts +51 -0
- package/src/combinator/process/lazy.ts +8 -0
- package/src/combinator/process/line.test.ts +21 -0
- package/src/combinator/process/line.ts +55 -0
- package/src/combinator/process/match.ts +37 -0
- package/src/combinator/process/reverse.ts +7 -0
- package/src/combinator/process/scope.ts +102 -0
- package/src/combinator/process/surround.ts +273 -0
- package/src/combinator.ts +28 -24
- package/src/debug.test.ts +11 -8
- package/src/parser/autolink.test.ts +17 -18
- package/src/parser/block/blockquote.test.ts +78 -79
- package/src/parser/block/blockquote.ts +32 -25
- package/src/parser/block/codeblock.test.ts +54 -57
- package/src/parser/block/codeblock.ts +44 -26
- package/src/parser/block/dlist.test.ts +56 -57
- package/src/parser/block/dlist.ts +5 -5
- package/src/parser/block/extension/aside.test.ts +7 -9
- package/src/parser/block/extension/aside.ts +76 -47
- package/src/parser/block/extension/example.test.ts +16 -19
- package/src/parser/block/extension/example.ts +88 -48
- package/src/parser/block/extension/fig.test.ts +37 -36
- package/src/parser/block/extension/fig.ts +20 -25
- package/src/parser/block/extension/figbase.test.ts +18 -19
- package/src/parser/block/extension/figbase.ts +3 -3
- package/src/parser/block/extension/figure.test.ts +58 -63
- package/src/parser/block/extension/figure.ts +23 -21
- package/src/parser/block/extension/message.test.ts +12 -14
- package/src/parser/block/extension/message.ts +52 -39
- package/src/parser/block/extension/placeholder.test.ts +13 -13
- package/src/parser/block/extension/placeholder.ts +23 -21
- package/src/parser/block/extension/table.test.ts +69 -71
- package/src/parser/block/extension/table.ts +43 -31
- package/src/parser/block/extension.test.ts +24 -24
- package/src/parser/block/extension.ts +3 -3
- package/src/parser/block/heading.test.ts +58 -59
- package/src/parser/block/heading.ts +19 -18
- package/src/parser/block/ilist.test.ts +8 -8
- package/src/parser/block/ilist.ts +9 -7
- package/src/parser/block/mathblock.test.ts +29 -32
- package/src/parser/block/mathblock.ts +24 -23
- package/src/parser/block/mediablock.ts +7 -7
- package/src/parser/block/olist.test.ts +102 -103
- package/src/parser/block/olist.ts +11 -12
- package/src/parser/block/pagebreak.test.ts +15 -16
- package/src/parser/block/pagebreak.ts +5 -5
- package/src/parser/block/paragraph.test.ts +57 -58
- package/src/parser/block/paragraph.ts +1 -1
- package/src/parser/block/reply/cite.test.ts +39 -40
- package/src/parser/block/reply/cite.ts +5 -5
- package/src/parser/block/reply/quote.test.ts +50 -51
- package/src/parser/block/reply/quote.ts +8 -7
- package/src/parser/block/reply.test.ts +19 -20
- package/src/parser/block/reply.ts +2 -2
- package/src/parser/block/sidefence.test.ts +41 -48
- package/src/parser/block/sidefence.ts +17 -11
- package/src/parser/block/table.test.ts +48 -49
- package/src/parser/block/table.ts +10 -9
- package/src/parser/block/ulist.test.ts +52 -53
- package/src/parser/block/ulist.ts +9 -8
- package/src/parser/block.ts +63 -51
- package/src/parser/context.ts +40 -40
- package/src/parser/document.ts +48 -0
- package/src/parser/header.test.ts +19 -20
- package/src/parser/header.ts +31 -25
- package/src/parser/inline/annotation.test.ts +49 -50
- package/src/parser/inline/annotation.ts +14 -16
- package/src/parser/inline/autolink/account.test.ts +32 -33
- package/src/parser/inline/autolink/account.ts +18 -19
- package/src/parser/inline/autolink/anchor.test.ts +21 -22
- package/src/parser/inline/autolink/anchor.ts +7 -8
- package/src/parser/inline/autolink/channel.test.ts +14 -15
- package/src/parser/inline/autolink/email.test.ts +36 -37
- package/src/parser/inline/autolink/email.ts +6 -6
- package/src/parser/inline/autolink/hashnum.test.ts +32 -33
- package/src/parser/inline/autolink/hashnum.ts +7 -8
- package/src/parser/inline/autolink/hashtag.test.ts +59 -60
- package/src/parser/inline/autolink/hashtag.ts +8 -9
- package/src/parser/inline/autolink/url.test.ts +75 -76
- package/src/parser/inline/autolink/url.ts +17 -18
- package/src/parser/inline/autolink.ts +24 -11
- package/src/parser/inline/bracket.test.ts +73 -74
- package/src/parser/inline/bracket.ts +88 -63
- package/src/parser/inline/code.test.ts +30 -31
- package/src/parser/inline/code.ts +6 -6
- package/src/parser/inline/deletion.test.ts +27 -28
- package/src/parser/inline/deletion.ts +5 -5
- package/src/parser/inline/emphasis.test.ts +39 -40
- package/src/parser/inline/emphasis.ts +5 -5
- package/src/parser/inline/emstrong.test.ts +101 -102
- package/src/parser/inline/emstrong.ts +103 -85
- package/src/parser/inline/extension/index.test.ts +91 -92
- package/src/parser/inline/extension/index.ts +17 -13
- package/src/parser/inline/extension/indexee.ts +4 -4
- package/src/parser/inline/extension/indexer.test.ts +23 -24
- package/src/parser/inline/extension/indexer.ts +6 -5
- package/src/parser/inline/extension/label.test.ts +32 -33
- package/src/parser/inline/extension/label.ts +14 -5
- package/src/parser/inline/extension/placeholder.test.ts +42 -43
- package/src/parser/inline/extension/placeholder.ts +8 -9
- package/src/parser/inline/html.test.ts +109 -109
- package/src/parser/inline/html.ts +27 -27
- package/src/parser/inline/htmlentity.test.ts +37 -38
- package/src/parser/inline/htmlentity.ts +6 -7
- package/src/parser/inline/insertion.test.ts +27 -28
- package/src/parser/inline/insertion.ts +5 -5
- package/src/parser/inline/italic.test.ts +55 -56
- package/src/parser/inline/italic.ts +5 -5
- package/src/parser/inline/link.test.ts +186 -187
- package/src/parser/inline/link.ts +29 -30
- package/src/parser/inline/mark.test.ts +31 -32
- package/src/parser/inline/mark.ts +6 -6
- package/src/parser/inline/math.test.ts +140 -141
- package/src/parser/inline/math.ts +7 -8
- package/src/parser/inline/media.test.ts +92 -93
- package/src/parser/inline/media.ts +35 -41
- package/src/parser/inline/reference.test.ts +111 -112
- package/src/parser/inline/reference.ts +61 -32
- package/src/parser/inline/remark.test.ts +49 -50
- package/src/parser/inline/remark.ts +13 -13
- package/src/parser/inline/ruby.test.ts +49 -50
- package/src/parser/inline/ruby.ts +100 -52
- package/src/parser/inline/shortmedia.test.ts +9 -10
- package/src/parser/inline/shortmedia.ts +11 -9
- package/src/parser/inline/strong.test.ts +36 -37
- package/src/parser/inline/strong.ts +5 -5
- package/src/parser/inline/template.test.ts +22 -23
- package/src/parser/inline/template.ts +17 -20
- package/src/parser/inline.test.ts +225 -226
- package/src/parser/inline.ts +68 -34
- package/src/parser/parser.ts +51 -0
- package/src/parser/repeat.ts +118 -91
- package/src/parser/segment.test.ts +0 -11
- package/src/parser/segment.ts +25 -28
- package/src/parser/source/escapable.test.ts +23 -24
- package/src/parser/source/escapable.ts +19 -20
- package/src/parser/source/line.test.ts +17 -18
- package/src/parser/source/line.ts +19 -24
- package/src/parser/source/str.ts +17 -10
- package/src/parser/source/text.test.ts +88 -89
- package/src/parser/source/text.ts +32 -62
- package/src/parser/source/unescapable.test.ts +23 -24
- package/src/parser/source/unescapable.ts +15 -16
- package/src/parser/source/whitespace.ts +36 -0
- package/src/parser/source.ts +1 -0
- package/src/parser/util.ts +1 -1
- package/src/parser/visibility.ts +37 -15
- package/src/processor/figure.test.ts +20 -20
- package/src/processor/figure.ts +18 -10
- package/src/processor/note.test.ts +13 -13
- package/src/processor/note.ts +4 -2
- package/src/renderer/render/media/pdf.ts +2 -2
- package/src/renderer/render/media/twitter.ts +2 -2
- package/src/renderer/render/media.test.ts +12 -12
- package/src/renderer/render.test.ts +11 -11
- package/src/util/info.test.ts +2 -2
- package/src/util/quote.test.ts +3 -3
- package/src/util/quote.ts +6 -5
- package/src/util/toc.test.ts +12 -12
- package/src/combinator/control/constraint/block.test.ts +0 -20
- package/src/combinator/control/constraint/block.ts +0 -28
- package/src/combinator/control/constraint/contract.ts +0 -27
- package/src/combinator/control/constraint/line.test.ts +0 -21
- package/src/combinator/control/constraint/line.ts +0 -42
- package/src/combinator/control/manipulation/clear.ts +0 -5
- package/src/combinator/control/manipulation/convert.ts +0 -22
- package/src/combinator/control/manipulation/duplicate.ts +0 -7
- package/src/combinator/control/manipulation/fence.ts +0 -54
- package/src/combinator/control/manipulation/indent.test.ts +0 -31
- package/src/combinator/control/manipulation/indent.ts +0 -39
- package/src/combinator/control/manipulation/lazy.ts +0 -8
- package/src/combinator/control/manipulation/match.ts +0 -27
- package/src/combinator/control/manipulation/recovery.ts +0 -18
- package/src/combinator/control/manipulation/reverse.ts +0 -8
- package/src/combinator/control/manipulation/scope.ts +0 -61
- package/src/combinator/control/manipulation/surround.ts +0 -223
- package/src/combinator/control/monad/bind.ts +0 -26
- package/src/combinator/control/monad/fmap.ts +0 -10
- package/src/combinator/data/parser/context.ts +0 -96
- package/src/combinator/data/parser/inits.ts +0 -20
- package/src/combinator/data/parser/sequence.test.ts +0 -33
- package/src/combinator/data/parser/sequence.ts +0 -20
- package/src/combinator/data/parser/some.test.ts +0 -37
- package/src/combinator/data/parser/subsequence.test.ts +0 -41
- package/src/combinator/data/parser/subsequence.ts +0 -13
- package/src/combinator/data/parser/tails.ts +0 -8
- package/src/combinator/data/parser/union.test.ts +0 -33
- package/src/combinator/data/parser/union.ts +0 -18
- package/src/combinator/data/parser.ts +0 -144
package/src/api.ts
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Parser, SubParsers, Result } from '../parser';
|
|
2
|
+
import { union } from './union';
|
|
3
|
+
import { sequence } from './sequence';
|
|
4
|
+
|
|
5
|
+
export function inits<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
6
|
+
export function inits<T>(parsers: SubParsers<T>): Parser<T> {
|
|
7
|
+
assert(parsers.every(f => f));
|
|
8
|
+
switch (parsers.length) {
|
|
9
|
+
case 0:
|
|
10
|
+
assert(false);
|
|
11
|
+
return (_, output) => output.context;
|
|
12
|
+
case 1:
|
|
13
|
+
return parsers[0];
|
|
14
|
+
default:
|
|
15
|
+
return parsers.reduceRight((acc, parser, i) =>
|
|
16
|
+
sequence([
|
|
17
|
+
parser,
|
|
18
|
+
i !== 0
|
|
19
|
+
? acc
|
|
20
|
+
: union([
|
|
21
|
+
acc,
|
|
22
|
+
recovery,
|
|
23
|
+
]),
|
|
24
|
+
]));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const recovery: Parser<never> = (_, output) => {
|
|
29
|
+
if (output.state) {
|
|
30
|
+
output.state = true;
|
|
31
|
+
// @ts-expect-error
|
|
32
|
+
output.context ??= Result.succ;
|
|
33
|
+
}
|
|
34
|
+
return output.context;
|
|
35
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Parser, Result, Input, Node, input } from '../parser';
|
|
2
|
+
import { sequence } from './sequence';
|
|
3
|
+
import { backtrack } from '../effect/backtrack';
|
|
4
|
+
import { inspect } from '../../debug.test';
|
|
5
|
+
|
|
6
|
+
describe('Unit: lib/parser/control/sequence', () => {
|
|
7
|
+
describe('sequence', () => {
|
|
8
|
+
const A: Parser<string> = (input, output) => {
|
|
9
|
+
if(input.source[input.position] === 'A'){
|
|
10
|
+
++input.position;
|
|
11
|
+
output.append(new Node('a'));
|
|
12
|
+
return Result.succ;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const B: Parser<string> = (input, output) => {
|
|
16
|
+
if(input.source[input.position] === 'B'){
|
|
17
|
+
++input.position;
|
|
18
|
+
output.append(new Node('b'));
|
|
19
|
+
return Result.succ;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const AB = backtrack(sequence<Parser<string, Input, [typeof A, typeof B]>>([A, B]));
|
|
23
|
+
|
|
24
|
+
it('basic', () => {
|
|
25
|
+
const parser = AB;
|
|
26
|
+
assert.deepStrictEqual(inspect(parser, input('')), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser, input('A')), undefined);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser, input('B')), undefined);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser, input('AB')), [['a', 'b'], '']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser, input('BA')), undefined);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser, input('AAB')), undefined);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser, input('ABB')), [['a', 'b'], 'B']);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser, input('BBA')), undefined);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Parser, SubParsers } from '../parser';
|
|
2
|
+
import { success, always } from './state';
|
|
3
|
+
|
|
4
|
+
export function sequence<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
5
|
+
export function sequence<T>(parsers: SubParsers<T>): Parser<T> {
|
|
6
|
+
assert(parsers.every(f => f));
|
|
7
|
+
switch (parsers.length) {
|
|
8
|
+
case 0:
|
|
9
|
+
assert(false);
|
|
10
|
+
return (_, output) => output.context;
|
|
11
|
+
case 1:
|
|
12
|
+
return parsers[0];
|
|
13
|
+
default:
|
|
14
|
+
return parsers.reduceRight((acc, parser) => always([
|
|
15
|
+
parser,
|
|
16
|
+
success(acc),
|
|
17
|
+
]));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Parser, Result, Input, Node, input } from '../parser';
|
|
2
|
+
import { union } from './union';
|
|
3
|
+
import { some } from './some';
|
|
4
|
+
import { inspect } from '../../debug.test';
|
|
5
|
+
|
|
6
|
+
describe('Unit: lib/parser/control/some', () => {
|
|
7
|
+
describe('some', () => {
|
|
8
|
+
const A: Parser<string> = (input, output) => {
|
|
9
|
+
if(input.source[input.position] === 'A'){
|
|
10
|
+
++input.position;
|
|
11
|
+
output.append(new Node('a'));
|
|
12
|
+
return Result.succ;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const B: Parser<string> = (input, output) => {
|
|
16
|
+
if(input.source[input.position] === 'B'){
|
|
17
|
+
++input.position;
|
|
18
|
+
output.append(new Node('b'));
|
|
19
|
+
return Result.succ;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const AB = union<Parser<string, Input, [typeof A, typeof B]>>([A, B]);
|
|
23
|
+
|
|
24
|
+
it('basic', () => {
|
|
25
|
+
const parser = some(AB, /AAA/y);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser, input('')), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser, input('A')), [['a'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser, input('B')), [['b'], '']);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser, input('AB')), [['a', 'b'], '']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser, input('BA')), [['b', 'a'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser, input('AAB')), [['a', 'a', 'b'], '']);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser, input('BBA')), [['b', 'b', 'a'], '']);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser, input('AAA')), undefined);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser, input('BBB')), [['b', 'b', 'b'], '']);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser, input('AAAB')), undefined);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser, input('BAAA')), [['b'], 'AAA']);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Parser,
|
|
1
|
+
import { Parser, Result, Input } from '../parser';
|
|
2
2
|
import { Delimiters } from '../delimiter';
|
|
3
|
+
import { always } from './state';
|
|
3
4
|
|
|
4
5
|
type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
|
|
5
6
|
|
|
@@ -7,7 +8,7 @@ export function some<P extends Parser>(parser: P, limit?: number): P;
|
|
|
7
8
|
export function some<P extends Parser>(parser: P, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
8
9
|
export function some<P extends Parser>(parser: P, delimiter: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
9
10
|
export function some<P extends Parser>(parser: P, delimiter: string | RegExp, after: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
10
|
-
export function some<
|
|
11
|
+
export function some<T>(parser: Parser<T>, delimiter?: number | string | RegExp | readonly DelimiterOption[], after?: number | string | RegExp | readonly DelimiterOption[], delimiters?: number | readonly DelimiterOption[], limit = 0): Parser<T> {
|
|
11
12
|
if (typeof delimiter === 'number') {
|
|
12
13
|
limit = delimiter;
|
|
13
14
|
delimiters = undefined;
|
|
@@ -29,33 +30,45 @@ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp
|
|
|
29
30
|
assert(parser);
|
|
30
31
|
assert(delimiter !== '');
|
|
31
32
|
assert(delimiters === undefined || Array.isArray(delimiters));
|
|
32
|
-
const
|
|
33
|
+
const test = Delimiters.tester(delimiter as string, after as string);
|
|
33
34
|
const delims = delimiters?.map(([delimiter, precedence]) => ({
|
|
34
35
|
signature: Delimiters.signature(delimiter),
|
|
35
36
|
tester: Delimiters.tester(delimiter),
|
|
36
37
|
precedence,
|
|
37
38
|
}));
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
39
|
+
interface Memory {
|
|
40
|
+
readonly position: number;
|
|
41
|
+
}
|
|
42
|
+
// 末尾再帰
|
|
43
|
+
const loop: Result<T, Input<Memory>> = [
|
|
44
|
+
(input, output) =>
|
|
45
|
+
test(input, output) || input.delimiters.test(input, output)
|
|
46
|
+
? Result.skip
|
|
47
|
+
: Result.succ,
|
|
48
|
+
parser,
|
|
49
|
+
(input, output) =>
|
|
50
|
+
output.state
|
|
51
|
+
// 次にパースに成功すれば確実に制限値を超えるので制限値ちょうどでも中止する
|
|
52
|
+
? input.position === input.source.length || limit !== 0 && input.position - input.memory.position >= limit
|
|
53
|
+
? Result.succ
|
|
54
|
+
: loop
|
|
55
|
+
: Result.fail,
|
|
56
|
+
];
|
|
57
|
+
return always<Parser<T, Input<Memory>>>([
|
|
58
|
+
input => {
|
|
59
|
+
const { source, position } = input;
|
|
60
|
+
if (position === source.length) return Result.skip;
|
|
61
|
+
input.memory = {
|
|
62
|
+
position,
|
|
63
|
+
};
|
|
64
|
+
delims && input.delimiters.push(delims);
|
|
65
|
+
return loop;
|
|
66
|
+
},
|
|
67
|
+
input => {
|
|
68
|
+
delims && input.delimiters.pop(delims.length);
|
|
69
|
+
return input.position > input.memory.position
|
|
70
|
+
? Result.succ
|
|
71
|
+
: Result.fail;
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
61
74
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Parser, SubParsers } from '../parser';
|
|
2
|
+
|
|
3
|
+
export function then<P extends Parser>(success: P, failure: P): P;
|
|
4
|
+
export function then<T>(success: Parser<T>, failure: Parser<T>): Parser<T> {
|
|
5
|
+
assert(success);
|
|
6
|
+
assert(failure);
|
|
7
|
+
return (input, output) => output.state ? success(input, output) : failure(input, output);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function success<P extends Parser>(parser: P): P;
|
|
11
|
+
export function success<T>(parser: Parser<T>): Parser<T> {
|
|
12
|
+
assert(parser);
|
|
13
|
+
return (input, output) => output.context && parser(input, output);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function failure<P extends Parser>(parser: P): P;
|
|
17
|
+
export function failure<T>(parser: Parser<T>): Parser<T> {
|
|
18
|
+
assert(parser);
|
|
19
|
+
return (input, output) => output.context ?? parser(input, output);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function always<P extends Parser>(parsers: readonly P[]): P;
|
|
23
|
+
export function always<T, S extends SubParsers<T>>(parsers: S): Parser<T> {
|
|
24
|
+
return () => parsers;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function force<P extends Parser>(parser: P): P;
|
|
28
|
+
export function force<T>(parser: Parser<T>): Parser<T> {
|
|
29
|
+
return (input, output) =>
|
|
30
|
+
input.position === input.source.length
|
|
31
|
+
? output.context
|
|
32
|
+
: parser(input, output);
|
|
33
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Parser, Result, Input, Node, input } from '../parser';
|
|
2
|
+
import { subsequence } from './subsequence';
|
|
3
|
+
import { inspect } from '../../debug.test';
|
|
4
|
+
|
|
5
|
+
describe('Unit: lib/parser/control/subsequence', () => {
|
|
6
|
+
describe('subsequence', () => {
|
|
7
|
+
const A: Parser<string> = (input, output) => {
|
|
8
|
+
if(input.source[input.position] === 'A'){
|
|
9
|
+
++input.position;
|
|
10
|
+
output.append(new Node('a'));
|
|
11
|
+
return Result.succ;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const B: Parser<string> = (input, output) => {
|
|
15
|
+
if(input.source[input.position] === 'B'){
|
|
16
|
+
++input.position;
|
|
17
|
+
output.append(new Node('b'));
|
|
18
|
+
return Result.succ;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const C: Parser<string> = (input, output) => {
|
|
22
|
+
if(input.source[input.position] === 'C'){
|
|
23
|
+
++input.position;
|
|
24
|
+
output.append(new Node('c'));
|
|
25
|
+
return Result.succ;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const ABC = subsequence<Parser<string, Input, [typeof A, typeof B, typeof C]>>([A, B, C]);
|
|
29
|
+
|
|
30
|
+
it('basic', () => {
|
|
31
|
+
const parser = ABC;
|
|
32
|
+
assert.deepStrictEqual(inspect(parser, input('')), undefined);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser, input('A')), [['a'], '']);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser, input('B')), [['b'], '']);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser, input('C')), [['c'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser, input('AB')), [['a', 'b'], '']);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser, input('BA')), [['b'], 'A']);
|
|
38
|
+
assert.deepStrictEqual(inspect(parser, input('AAB')), [['a'], 'AB']);
|
|
39
|
+
assert.deepStrictEqual(inspect(parser, input('ABB')), [['a', 'b'], 'B']);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser, input('BBA')), [['b'], 'BA']);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser, input('AC')), [['a', 'c'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser, input('BC')), [['b', 'c'], '']);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Parser, SubParsers } from '../parser';
|
|
2
|
+
import { union } from './union';
|
|
3
|
+
import { inits } from './inits';
|
|
4
|
+
|
|
5
|
+
export function subsequence<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
6
|
+
export function subsequence<T>(parsers: SubParsers<T>): Parser<T> {
|
|
7
|
+
assert(parsers.every(f => f));
|
|
8
|
+
return union(
|
|
9
|
+
parsers.map((_, i) =>
|
|
10
|
+
i + 1 !== parsers.length
|
|
11
|
+
? inits([
|
|
12
|
+
parsers[i],
|
|
13
|
+
subsequence(parsers.slice(i + 1)),
|
|
14
|
+
])
|
|
15
|
+
: parsers[i]));
|
|
16
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Parser, SubParsers } from '../parser';
|
|
2
|
+
import { union } from './union';
|
|
3
|
+
import { sequence } from './sequence';
|
|
4
|
+
|
|
5
|
+
export function tails<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
6
|
+
export function tails<T>(parsers: SubParsers<T>): Parser<T> {
|
|
7
|
+
return union(parsers.map((_, i) => sequence(parsers.slice(i))));
|
|
8
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Parser, Result, Input, Node, input } from '../parser';
|
|
2
|
+
import { union } from './union';
|
|
3
|
+
import { inspect } from '../../debug.test';
|
|
4
|
+
|
|
5
|
+
describe('Unit: lib/parser/control/union', () => {
|
|
6
|
+
describe('union', () => {
|
|
7
|
+
const A: Parser<string> = (input, output) => {
|
|
8
|
+
if(input.source[input.position] === 'A'){
|
|
9
|
+
++input.position;
|
|
10
|
+
output.append(new Node('a'));
|
|
11
|
+
return Result.succ;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const B: Parser<string> = (input, output) => {
|
|
15
|
+
if(input.source[input.position] === 'B'){
|
|
16
|
+
++input.position;
|
|
17
|
+
output.append(new Node('b'));
|
|
18
|
+
return Result.succ;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const AB = union<Parser<string, Input, [typeof A, typeof B]>>([A, B]);
|
|
22
|
+
|
|
23
|
+
it('basic', () => {
|
|
24
|
+
const parser = AB;
|
|
25
|
+
assert.deepStrictEqual(inspect(parser, input('')), undefined);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser, input('A')), [['a'], '']);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser, input('B')), [['b'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser, input('AB')), [['a'], 'B']);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser, input('BA')), [['b'], 'A']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser, input('AAB')), [['a'], 'AB']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser, input('ABB')), [['a'], 'BB']);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser, input('BBA')), [['b'], 'BA']);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Parser, SubParsers, Result } from '../parser';
|
|
2
|
+
import { failure, always } from './state';
|
|
3
|
+
|
|
4
|
+
export function union<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
5
|
+
export function union<T>(parsers: SubParsers<T>): Parser<T> {
|
|
6
|
+
assert(parsers.every(f => f));
|
|
7
|
+
switch (parsers.length) {
|
|
8
|
+
case 0:
|
|
9
|
+
assert(false);
|
|
10
|
+
return (_, output) => output.context;
|
|
11
|
+
case 1:
|
|
12
|
+
return parsers[0];
|
|
13
|
+
default:
|
|
14
|
+
return parsers.reduceRight((acc, parser) => always([
|
|
15
|
+
parser,
|
|
16
|
+
failure(recovery(acc)),
|
|
17
|
+
]));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function recovery<P extends Parser>(parser: P): P;
|
|
22
|
+
function recovery<T>(parser: Parser<T>): Parser<T> {
|
|
23
|
+
return (input, output) => {
|
|
24
|
+
if (!output.state) {
|
|
25
|
+
output.state = true;
|
|
26
|
+
// @ts-expect-error
|
|
27
|
+
output.context ??= Result.succ;
|
|
28
|
+
}
|
|
29
|
+
return parser(input, output);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { spend } from './
|
|
1
|
+
import { Input, Output } from './parser';
|
|
2
|
+
import { spend } from './effect/clock';
|
|
3
3
|
|
|
4
4
|
interface Delimiter {
|
|
5
5
|
readonly memory: Delimiter[];
|
|
6
6
|
readonly index: number;
|
|
7
|
-
readonly tester: (input: Input) => boolean
|
|
7
|
+
readonly tester: (input: Input, output: Output<unknown>) => boolean;
|
|
8
8
|
readonly precedence: number;
|
|
9
9
|
state: boolean;
|
|
10
10
|
}
|
|
@@ -42,17 +42,17 @@ export class Delimiters {
|
|
|
42
42
|
return index(`/${pattern.source}`);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
public static tester(pattern: string | RegExp | undefined, after?: string | RegExp): (input: Input<
|
|
45
|
+
public static tester(pattern: string | RegExp | undefined, after?: string | RegExp): (input: Input, output: Output<unknown>) => boolean {
|
|
46
46
|
switch (typeof pattern) {
|
|
47
47
|
case 'undefined':
|
|
48
|
-
return () =>
|
|
48
|
+
return () => false;
|
|
49
49
|
case 'string':
|
|
50
50
|
case 'object':
|
|
51
51
|
const test = tester(pattern, false);
|
|
52
|
-
const verify = after
|
|
52
|
+
const verify = after && tester(after, false);
|
|
53
53
|
return verify
|
|
54
|
-
? input => test(input)
|
|
55
|
-
: input => test(input)
|
|
54
|
+
? (input, output) => test(input, output) && verify(input, output)
|
|
55
|
+
: (input, output) => test(input, output);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
private readonly memories: Delimiter[][] = [];
|
|
@@ -68,7 +68,7 @@ export class Delimiters {
|
|
|
68
68
|
public push(
|
|
69
69
|
delims: readonly {
|
|
70
70
|
readonly signature: number;
|
|
71
|
-
readonly tester: (input: Input) => boolean
|
|
71
|
+
readonly tester: (input: Input, output: Output<unknown>) => boolean;
|
|
72
72
|
readonly precedence: number;
|
|
73
73
|
}[]
|
|
74
74
|
): void {
|
|
@@ -139,37 +139,25 @@ export class Delimiters {
|
|
|
139
139
|
delimiters[indexes[i]].state = true;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
public test(input: Input): boolean {
|
|
142
|
+
public test(input: Input, output: Output<unknown>): boolean {
|
|
143
143
|
const { precedence } = input;
|
|
144
144
|
const { delimiters } = this;
|
|
145
145
|
for (let i = delimiters.length; i--;) {
|
|
146
146
|
const delimiter = delimiters[i];
|
|
147
147
|
if (delimiter.precedence <= precedence || !delimiter.state) continue;
|
|
148
|
-
|
|
149
|
-
case true:
|
|
150
|
-
return true;
|
|
151
|
-
case false:
|
|
152
|
-
return false;
|
|
153
|
-
default:
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
148
|
+
if (delimiter.tester(input, output)) return true;
|
|
156
149
|
}
|
|
157
150
|
return false;
|
|
158
151
|
}
|
|
159
152
|
}
|
|
160
153
|
|
|
161
|
-
export function matcher(pattern: string | RegExp, advance: boolean, after?:
|
|
154
|
+
export function matcher(pattern: string | RegExp, advance: boolean, after?: (input: Input, output: Output<unknown>) => boolean): (input: Input, output: Output<unknown>) => string | undefined {
|
|
162
155
|
assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
|
|
163
|
-
const count = typeof pattern === 'object'
|
|
164
|
-
? /[^^\\*+][*+]|{\d+,}/.test(pattern.source)
|
|
165
|
-
: false;
|
|
166
156
|
let sid = 0, pos = 0, index = -1;
|
|
167
157
|
switch (typeof pattern) {
|
|
168
158
|
case 'string':
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const context = input;
|
|
172
|
-
const { SID, source, position } = context;
|
|
159
|
+
return (input, output) => {
|
|
160
|
+
const { SID, source, position } = input;
|
|
173
161
|
const hit = SID === sid && position === pos;
|
|
174
162
|
index = hit
|
|
175
163
|
? index
|
|
@@ -177,19 +165,18 @@ export function matcher(pattern: string | RegExp, advance: boolean, after?: Pars
|
|
|
177
165
|
sid = SID;
|
|
178
166
|
pos = position;
|
|
179
167
|
if (index === -1) return;
|
|
168
|
+
!hit && spend(input, output, pattern.length);
|
|
180
169
|
if (advance) {
|
|
181
|
-
|
|
170
|
+
input.position += pattern.length;
|
|
182
171
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
: new List([new Node(pattern)]);
|
|
172
|
+
return after?.(input, output) ?? true
|
|
173
|
+
? pattern
|
|
174
|
+
: undefined;
|
|
187
175
|
};
|
|
188
176
|
case 'object':
|
|
189
177
|
assert(pattern.sticky);
|
|
190
|
-
return input => {
|
|
191
|
-
const
|
|
192
|
-
const { SID, source, position } = context;
|
|
178
|
+
return (input, output) => {
|
|
179
|
+
const { SID, source, position } = input;
|
|
193
180
|
const hit = SID === sid && position === pos;
|
|
194
181
|
pattern.lastIndex = position;
|
|
195
182
|
index = hit
|
|
@@ -199,48 +186,42 @@ export function matcher(pattern: string | RegExp, advance: boolean, after?: Pars
|
|
|
199
186
|
pos = position;
|
|
200
187
|
if (index === -1) return;
|
|
201
188
|
const src = source.slice(position, index);
|
|
202
|
-
|
|
189
|
+
!hit && spend(input, output, src.length);
|
|
203
190
|
if (advance) {
|
|
204
|
-
|
|
191
|
+
input.position = index;
|
|
205
192
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
: new List([new Node(src)]);
|
|
193
|
+
return after?.(input, output) ?? true
|
|
194
|
+
? src
|
|
195
|
+
: undefined;
|
|
210
196
|
};
|
|
211
197
|
}
|
|
212
198
|
}
|
|
213
199
|
|
|
214
|
-
export function tester(pattern: string | RegExp, advance: boolean, after?:
|
|
200
|
+
export function tester(pattern: string | RegExp, advance: boolean, after?: (input: Input, output: Output<unknown>) => boolean): (input: Input, output: Output<unknown>) => boolean {
|
|
215
201
|
assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
|
|
216
|
-
const count = typeof pattern === 'object'
|
|
217
|
-
? /[^^\\*+][*+]|{\d+,}/.test(pattern.source)
|
|
218
|
-
: false;
|
|
219
202
|
let sid = 0, pos = 0, index = -1;
|
|
220
203
|
switch (typeof pattern) {
|
|
221
204
|
case 'string':
|
|
222
|
-
if (pattern === '') return () =>
|
|
223
|
-
return input => {
|
|
224
|
-
const
|
|
225
|
-
const { SID, source, position } = context;
|
|
205
|
+
if (pattern === '') return () => true;
|
|
206
|
+
return (input, output) => {
|
|
207
|
+
const { SID, source, position } = input;
|
|
226
208
|
const hit = SID === sid && position === pos;
|
|
227
209
|
index = hit
|
|
228
210
|
? index
|
|
229
211
|
: source.startsWith(pattern, position) ? position : -1;
|
|
230
212
|
sid = SID;
|
|
231
213
|
pos = position;
|
|
232
|
-
if (index === -1) return;
|
|
214
|
+
if (index === -1) return false;
|
|
215
|
+
!hit && spend(input, output, pattern.length);
|
|
233
216
|
if (advance) {
|
|
234
|
-
|
|
217
|
+
input.position += pattern.length;
|
|
235
218
|
}
|
|
236
|
-
|
|
237
|
-
return new List();
|
|
219
|
+
return after?.(input, output) ?? true;
|
|
238
220
|
};
|
|
239
221
|
case 'object':
|
|
240
222
|
assert(pattern.sticky);
|
|
241
|
-
return input => {
|
|
242
|
-
const
|
|
243
|
-
const { SID, source, position } = context;
|
|
223
|
+
return (input, output) => {
|
|
224
|
+
const { SID, source, position } = input;
|
|
244
225
|
const hit = SID === sid && position === pos;
|
|
245
226
|
pattern.lastIndex = position;
|
|
246
227
|
index = hit
|
|
@@ -248,14 +229,13 @@ export function tester(pattern: string | RegExp, advance: boolean, after?: Parse
|
|
|
248
229
|
: pattern.test(source) ? pattern.lastIndex : -1;
|
|
249
230
|
sid = SID;
|
|
250
231
|
pos = position;
|
|
251
|
-
if (index === -1) return;
|
|
232
|
+
if (index === -1) return false;
|
|
252
233
|
const len = index - position;
|
|
253
|
-
|
|
234
|
+
!hit && spend(input, output, len);
|
|
254
235
|
if (advance) {
|
|
255
|
-
|
|
236
|
+
input.position = index;
|
|
256
237
|
}
|
|
257
|
-
|
|
258
|
-
return new List();
|
|
238
|
+
return after?.(input, output) ?? true;
|
|
259
239
|
};
|
|
260
240
|
}
|
|
261
241
|
}
|