securemark 0.289.2 → 0.289.3
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 +4 -0
- package/design.md +2 -1
- package/dist/index.js +94 -78
- package/package.json +1 -1
- package/src/combinator/control/constraint/block.ts +1 -1
- package/src/combinator/control/constraint/contract.ts +7 -7
- package/src/combinator/control/constraint/line.ts +1 -1
- package/src/combinator/control/manipulation/clear.ts +7 -0
- package/src/combinator/control/manipulation/convert.ts +1 -1
- package/src/combinator/control/manipulation/duplicate.ts +4 -4
- package/src/combinator/control/manipulation/fallback.ts +3 -3
- package/src/combinator/control/manipulation/indent.ts +3 -3
- package/src/combinator/control/manipulation/lazy.ts +2 -2
- package/src/combinator/control/manipulation/match.ts +1 -1
- package/src/combinator/control/manipulation/recovery.ts +3 -3
- package/src/combinator/control/manipulation/reverse.ts +1 -1
- package/src/combinator/control/manipulation/scope.ts +3 -3
- package/src/combinator/control/manipulation/surround.ts +59 -61
- package/src/combinator/control/manipulation/trim.ts +3 -3
- package/src/combinator/control/monad/bind.ts +6 -6
- package/src/combinator/control/monad/fmap.ts +6 -6
- package/src/combinator/data/parser/context/delimiter.ts +21 -19
- package/src/combinator/data/parser/context.ts +8 -8
- package/src/combinator/data/parser/inits.ts +4 -4
- package/src/combinator/data/parser/sequence.ts +4 -4
- package/src/combinator/data/parser/some.ts +3 -3
- package/src/combinator/data/parser/subsequence.ts +3 -3
- package/src/combinator/data/parser/tails.ts +3 -3
- package/src/combinator/data/parser/union.ts +3 -3
- package/src/combinator/data/parser.ts +13 -13
- package/src/combinator.ts +1 -0
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/table.ts +3 -3
- package/src/parser/block/olist.ts +4 -4
- package/src/parser/block/reply/cite.ts +3 -3
- package/src/parser/block/ulist.ts +1 -1
- package/src/parser/inline/autolink/hashnum.ts +5 -1
- package/src/parser/inline/code.ts +2 -1
- package/src/parser/inline/extension/label.ts +1 -1
- package/src/parser/util.ts +10 -10
- package/src/parser/visibility.ts +11 -11
- package/src/util/quote.ts +1 -1
|
@@ -1,47 +1,46 @@
|
|
|
1
|
-
import { Parser, Input, Result, Ctx,
|
|
2
|
-
import { fmap } from '../monad/fmap';
|
|
1
|
+
import { Parser, Input, Result, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, exec, check } from '../../data/parser';
|
|
3
2
|
import { unshift, push } from 'spica/array';
|
|
4
3
|
|
|
5
4
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
6
5
|
opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
|
|
7
6
|
optional?: false,
|
|
8
|
-
f?: (rss: [S[],
|
|
9
|
-
g?: (rss: [S[],
|
|
7
|
+
f?: (rss: [S[], SubNode<P>[], S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
8
|
+
g?: (rss: [S[], SubNode<P>[], string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
10
9
|
backtracks?: readonly number[],
|
|
11
10
|
backtrackstate?: number,
|
|
12
11
|
): P;
|
|
13
12
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
14
13
|
opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
|
|
15
14
|
optional?: boolean,
|
|
16
|
-
f?: (rss: [S[],
|
|
17
|
-
g?: (rss: [S[],
|
|
15
|
+
f?: (rss: [S[], SubNode<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
16
|
+
g?: (rss: [S[], SubNode<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
18
17
|
backtracks?: readonly number[],
|
|
19
18
|
backtrackstate?: number,
|
|
20
19
|
): P;
|
|
21
20
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
22
21
|
opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
|
|
23
22
|
optional?: false,
|
|
24
|
-
f?: (rss: [S[],
|
|
25
|
-
g?: (rss: [S[],
|
|
23
|
+
f?: (rss: [S[], Node<P>[], S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
24
|
+
g?: (rss: [S[], Node<P>[], string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
26
25
|
backtracks?: readonly number[],
|
|
27
26
|
backtrackstate?: number,
|
|
28
27
|
): P;
|
|
29
28
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
30
29
|
opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
|
|
31
30
|
optional?: boolean,
|
|
32
|
-
f?: (rss: [S[],
|
|
33
|
-
g?: (rss: [S[],
|
|
31
|
+
f?: (rss: [S[], Node<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
32
|
+
g?: (rss: [S[], Node<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
34
33
|
backtracks?: readonly number[],
|
|
35
34
|
backtrackstate?: number,
|
|
36
35
|
): P;
|
|
37
|
-
export function surround<
|
|
38
|
-
opener: string | RegExp | Parser<
|
|
36
|
+
export function surround<N>(
|
|
37
|
+
opener: string | RegExp | Parser<N>, parser: Parser<N>, closer: string | RegExp | Parser<N>,
|
|
39
38
|
optional: boolean = false,
|
|
40
|
-
f?: (rss: [
|
|
41
|
-
g?: (rss: [
|
|
39
|
+
f?: (rss: [N[], N[], N[]], rest: string, context: Ctx) => Result<N>,
|
|
40
|
+
g?: (rss: [N[], N[], string], rest: string, context: Ctx) => Result<N>,
|
|
42
41
|
backtracks: readonly number[] = [],
|
|
43
42
|
backtrackstate: number = 0,
|
|
44
|
-
): Parser<
|
|
43
|
+
): Parser<N> {
|
|
45
44
|
switch (typeof opener) {
|
|
46
45
|
case 'string':
|
|
47
46
|
case 'object':
|
|
@@ -54,21 +53,22 @@ export function surround<T>(
|
|
|
54
53
|
}
|
|
55
54
|
const statesize = 2;
|
|
56
55
|
return ({ source, context }) => {
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
56
|
+
const sme_ = source;
|
|
57
|
+
if (sme_ === '') return;
|
|
59
58
|
const { linebreak } = context;
|
|
60
59
|
context.linebreak = undefined;
|
|
61
|
-
const
|
|
62
|
-
assert(check(
|
|
63
|
-
if (
|
|
64
|
-
const
|
|
65
|
-
const
|
|
60
|
+
const resultS = opener({ source: sme_, context });
|
|
61
|
+
assert(check(sme_, resultS, false));
|
|
62
|
+
if (resultS === undefined) return void revert(context, linebreak);
|
|
63
|
+
const nodesS = eval(resultS);
|
|
64
|
+
const me_ = exec(resultS);
|
|
66
65
|
for (const backtrack of backtracks) {
|
|
67
66
|
if (backtrack & 1) {
|
|
68
67
|
const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
|
|
69
|
-
for (let i = 0; i < source.length -
|
|
68
|
+
for (let i = 0; i < source.length - me_.length; ++i) {
|
|
70
69
|
if (source[i] !== source[0]) break;
|
|
71
|
-
const pos = source.length + offset -
|
|
70
|
+
const pos = source.length - i + offset - 1;
|
|
71
|
+
assert(pos >= 0);
|
|
72
72
|
if (!(pos in backtracks)) continue;
|
|
73
73
|
const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
|
|
74
74
|
if (backtracks[pos] & 1 << size(backtrack >>> statesize) + shift) return void revert(context, linebreak);
|
|
@@ -77,35 +77,37 @@ export function surround<T>(
|
|
|
77
77
|
}
|
|
78
78
|
const { backtrack = 0 } = context;
|
|
79
79
|
context.backtrack = backtrack | backtrackstate;
|
|
80
|
-
const
|
|
81
|
-
assert(check(
|
|
80
|
+
const resultM = me_ !== '' ? parser({ source: me_, context }) : undefined;
|
|
81
|
+
assert(check(me_, resultM));
|
|
82
82
|
context.backtrack = backtrack;
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
86
|
-
const
|
|
87
|
-
assert(check(
|
|
88
|
-
const
|
|
89
|
-
const rest = exec(
|
|
90
|
-
if (rest.length ===
|
|
83
|
+
const nodesM = eval(resultM);
|
|
84
|
+
const e_ = exec(resultM, me_);
|
|
85
|
+
if (!nodesM && !optional) return void revert(context, linebreak);
|
|
86
|
+
const resultE = closer({ source: e_, context });
|
|
87
|
+
assert(check(e_, resultE, false));
|
|
88
|
+
const nodesE = eval(resultE);
|
|
89
|
+
const rest = exec(resultE, e_);
|
|
90
|
+
if (rest.length === sme_.length) return void revert(context, linebreak);
|
|
91
91
|
for (const backtrack of backtracks) {
|
|
92
|
-
if (backtrack & 2 &&
|
|
92
|
+
if (backtrack & 2 && nodesE === undefined) {
|
|
93
93
|
const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
|
|
94
|
+
const pos = source.length + offset - 1;
|
|
95
|
+
assert(pos >= 0);
|
|
94
96
|
const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
|
|
95
|
-
backtracks[
|
|
97
|
+
backtracks[pos] |= 1 << size(backtrack >>> statesize) + shift;
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
context.recent = [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
sme_.slice(0, sme_.length - me_.length),
|
|
102
|
+
me_.slice(0, me_.length - e_.length),
|
|
103
|
+
e_.slice(0, e_.length - rest.length),
|
|
102
104
|
];
|
|
103
|
-
const result =
|
|
105
|
+
const result = nodesE
|
|
104
106
|
? f
|
|
105
|
-
? f([
|
|
106
|
-
: [push(unshift(
|
|
107
|
+
? f([nodesS, nodesM!, nodesE], rest, context)
|
|
108
|
+
: [push(unshift(nodesS, nodesM ?? []), nodesE), rest] satisfies [N[], string]
|
|
107
109
|
: g
|
|
108
|
-
? g([
|
|
110
|
+
? g([nodesS, nodesM!, me_], rest, context)
|
|
109
111
|
: undefined;
|
|
110
112
|
if (result) {
|
|
111
113
|
context.linebreak ??= linebreak;
|
|
@@ -116,6 +118,14 @@ export function surround<T>(
|
|
|
116
118
|
return result;
|
|
117
119
|
};
|
|
118
120
|
}
|
|
121
|
+
export function open<P extends Parser<unknown>>(opener: string | RegExp | Parser<Node<P>, Context<P>>, parser: P, optional?: boolean): P;
|
|
122
|
+
export function open<N>(opener: string | RegExp | Parser<N>, parser: Parser<N>, optional = false): Parser<N> {
|
|
123
|
+
return surround(opener, parser, '', optional);
|
|
124
|
+
}
|
|
125
|
+
export function close<P extends Parser<unknown>>(parser: P, closer: string | RegExp | Parser<Node<P>, Context<P>>, optional?: boolean): P;
|
|
126
|
+
export function close<N>(parser: Parser<N>, closer: string | RegExp | Parser<N>, optional: boolean = false): Parser<N> {
|
|
127
|
+
return surround('', parser, closer, optional);
|
|
128
|
+
}
|
|
119
129
|
|
|
120
130
|
function match(pattern: string | RegExp): (input: Input) => [never[], string] | undefined {
|
|
121
131
|
switch (typeof pattern) {
|
|
@@ -130,12 +140,16 @@ function match(pattern: string | RegExp): (input: Input) => [never[], string] |
|
|
|
130
140
|
};
|
|
131
141
|
}
|
|
132
142
|
}
|
|
143
|
+
function revert(context: Ctx, linebreak: number | undefined): void {
|
|
144
|
+
context.linebreak = linebreak;
|
|
145
|
+
}
|
|
133
146
|
function size(bits: number): number {
|
|
134
147
|
if (bits === 0) return 0;
|
|
135
148
|
let p = 0;
|
|
136
149
|
for (let s = 32 / 2; s > 0; s >>>= 1) {
|
|
137
|
-
|
|
138
|
-
|
|
150
|
+
const q = p + s;
|
|
151
|
+
if (bits >>> q === 0) continue;
|
|
152
|
+
p = q;
|
|
139
153
|
}
|
|
140
154
|
return p + 1;
|
|
141
155
|
}
|
|
@@ -144,19 +158,3 @@ assert(size(1 << 0) === 1);
|
|
|
144
158
|
assert(size(1 << 1) === 2);
|
|
145
159
|
assert(size(1 << 30) === 31);
|
|
146
160
|
assert(size(1 << 31) === 32);
|
|
147
|
-
function revert(context: Ctx, linebreak: number | undefined): void {
|
|
148
|
-
context.linebreak = linebreak;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function open<P extends Parser<unknown>>(opener: string | RegExp | Parser<Tree<P>, Context<P>>, parser: P, optional?: boolean): P;
|
|
152
|
-
export function open<T>(opener: string | RegExp | Parser<T>, parser: Parser<T>, optional = false): Parser<T> {
|
|
153
|
-
return surround(opener, parser, '', optional);
|
|
154
|
-
}
|
|
155
|
-
export function close<P extends Parser<unknown>>(parser: P, closer: string | RegExp | Parser<Tree<P>, Context<P>>, optional?: boolean): P;
|
|
156
|
-
export function close<T>(parser: Parser<T>, closer: string | RegExp | Parser<T>, optional: boolean = false): Parser<T> {
|
|
157
|
-
return surround('', parser, closer, optional);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function clear<D extends Parser<unknown, C>[], C extends Ctx>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
|
|
161
|
-
return fmap<never, Parser<unknown, C, D>>(parser, () => []);
|
|
162
|
-
}
|
|
@@ -2,16 +2,16 @@ import { Parser } from '../../data/parser';
|
|
|
2
2
|
import { convert } from './convert';
|
|
3
3
|
|
|
4
4
|
export function trim<P extends Parser<unknown>>(parser: P): P;
|
|
5
|
-
export function trim<
|
|
5
|
+
export function trim<N>(parser: Parser<N>): Parser<N> {
|
|
6
6
|
return convert(source => source.trim(), parser, false);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function trimStart<P extends Parser<unknown>>(parser: P): P;
|
|
10
|
-
export function trimStart<
|
|
10
|
+
export function trimStart<N>(parser: Parser<N>): Parser<N> {
|
|
11
11
|
return convert(source => source.trimStart(), parser, true);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function trimEnd<P extends Parser<unknown>>(parser: P): P;
|
|
15
|
-
export function trimEnd<
|
|
15
|
+
export function trimEnd<N>(parser: Parser<N>): Parser<N> {
|
|
16
16
|
return convert(source => source.trimEnd(), parser, false);
|
|
17
17
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Parser, Result, Ctx,
|
|
1
|
+
import { Parser, Result, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, exec, check } from '../../data/parser';
|
|
2
2
|
|
|
3
|
-
export function bind<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes:
|
|
4
|
-
export function bind<P extends Parser<unknown>>(parser: P, f: (nodes:
|
|
5
|
-
export function bind<
|
|
6
|
-
export function bind<U, P extends Parser<unknown>>(parser: P, f: (nodes:
|
|
7
|
-
export function bind<
|
|
3
|
+
export function bind<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: SubNode<P>[], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
4
|
+
export function bind<P extends Parser<unknown>>(parser: P, f: (nodes: Node<P>[], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
5
|
+
export function bind<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: N[], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
6
|
+
export function bind<U, P extends Parser<unknown>>(parser: P, f: (nodes: Node<P>[], rest: string, context: Context<P>) => Result<U, Context<P>, SubParsers<P>>): Parser<U, Context<P>, SubParsers<P>>;
|
|
7
|
+
export function bind<N, U>(parser: Parser<N>, f: (nodes: N[], rest: string, context: Ctx) => Result<U>): Parser<U> {
|
|
8
8
|
assert(parser);
|
|
9
9
|
return input => {
|
|
10
10
|
const { source, context } = input;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Parser, Ctx, SubParsers,
|
|
1
|
+
import { Parser, Ctx, SubParsers, Node, Context, IntermediateParser, SubNode } from '../../data/parser';
|
|
2
2
|
import { bind } from './bind';
|
|
3
3
|
|
|
4
|
-
export function fmap<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes:
|
|
5
|
-
export function fmap<P extends Parser<unknown>>(parser: P, f: (nodes:
|
|
6
|
-
export function fmap<
|
|
7
|
-
export function fmap<U, P extends Parser<unknown>>(parser: P, f: (nodes:
|
|
8
|
-
export function fmap<
|
|
4
|
+
export function fmap<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: SubNode<P>[], rest: string, context: Context<P>) => Node<P>[]): P;
|
|
5
|
+
export function fmap<P extends Parser<unknown>>(parser: P, f: (nodes: Node<P>[], rest: string, context: Context<P>) => Node<P>[]): P;
|
|
6
|
+
export function fmap<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: N[], rest: string, context: Context<P>) => Node<P>[]): P;
|
|
7
|
+
export function fmap<U, P extends Parser<unknown>>(parser: P, f: (nodes: Node<P>[], rest: string, context: Context<P>) => U[]): Parser<U, Context<P>, SubParsers<P>>;
|
|
8
|
+
export function fmap<N, U>(parser: Parser<N>, f: (nodes: N[], rest: string, context: Ctx) => U[]): Parser<U> {
|
|
9
9
|
return bind(parser, (nodes, rest, context) => [f(nodes, rest, context), rest]);
|
|
10
10
|
}
|
|
@@ -2,6 +2,7 @@ import { Ctx } from '../../parser';
|
|
|
2
2
|
import { memoize } from 'spica/memoize';
|
|
3
3
|
|
|
4
4
|
interface Delimiter {
|
|
5
|
+
readonly memory: Delimiter[];
|
|
5
6
|
readonly index: number;
|
|
6
7
|
readonly signature: string;
|
|
7
8
|
readonly matcher: (source: string) => boolean | undefined;
|
|
@@ -11,28 +12,26 @@ interface Delimiter {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export class Delimiters {
|
|
14
|
-
public static signature(pattern: string | RegExp | undefined): string {
|
|
15
|
+
public static signature(pattern: string | RegExp | undefined, linebreakable: boolean): string {
|
|
15
16
|
switch (typeof pattern) {
|
|
16
17
|
case 'undefined':
|
|
17
18
|
return `undefined`;
|
|
18
19
|
case 'string':
|
|
19
|
-
return `s:${pattern}`;
|
|
20
|
+
return `s:${pattern}:${+linebreakable}`;
|
|
20
21
|
case 'object':
|
|
21
|
-
return `r/${pattern.source}/${
|
|
22
|
+
return `r/${pattern.source}/${+linebreakable}`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
public static matcher(pattern: string | RegExp | undefined): (source: string) => true | undefined {
|
|
26
|
+
switch (typeof pattern) {
|
|
27
|
+
case 'undefined':
|
|
28
|
+
return () => undefined;
|
|
29
|
+
case 'string':
|
|
30
|
+
return source => source.slice(0, pattern.length) === pattern || undefined;
|
|
31
|
+
case 'object':
|
|
32
|
+
return source => pattern.test(source) || undefined;
|
|
22
33
|
}
|
|
23
34
|
}
|
|
24
|
-
public static matcher = memoize(
|
|
25
|
-
(pattern: string | RegExp | undefined): (source: string) => true | undefined => {
|
|
26
|
-
switch (typeof pattern) {
|
|
27
|
-
case 'undefined':
|
|
28
|
-
return () => undefined;
|
|
29
|
-
case 'string':
|
|
30
|
-
return source => source.slice(0, pattern.length) === pattern || undefined;
|
|
31
|
-
case 'object':
|
|
32
|
-
return source => pattern.test(source) || undefined;
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
this.signature);
|
|
36
35
|
private readonly registry = memoize<(signature: string) => Delimiter[]>(() => []);
|
|
37
36
|
private readonly delimiters: Delimiter[] = [];
|
|
38
37
|
private readonly stack: number[] = [];
|
|
@@ -52,13 +51,15 @@ export class Delimiters {
|
|
|
52
51
|
const { signature, matcher, precedence, linebreakable } = delims[i];
|
|
53
52
|
const memory = registry(signature);
|
|
54
53
|
const index = memory[0]?.index ?? delimiters.length;
|
|
55
|
-
|
|
54
|
+
assert(memory.length === 0 || precedence === delimiters[index].precedence);
|
|
55
|
+
if (memory.length === 0) {
|
|
56
56
|
const delimiter: Delimiter = {
|
|
57
|
+
memory,
|
|
57
58
|
index,
|
|
58
59
|
signature,
|
|
59
60
|
matcher,
|
|
60
61
|
precedence,
|
|
61
|
-
linebreakable
|
|
62
|
+
linebreakable,
|
|
62
63
|
state: true,
|
|
63
64
|
};
|
|
64
65
|
delimiters[index] = delimiter;
|
|
@@ -74,12 +75,12 @@ export class Delimiters {
|
|
|
74
75
|
}
|
|
75
76
|
public pop(count: number): void {
|
|
76
77
|
assert(count > 0);
|
|
77
|
-
const {
|
|
78
|
+
const { delimiters, stack } = this;
|
|
78
79
|
for (let i = 0; i < count; ++i) {
|
|
79
80
|
assert(this.stack.length > 0);
|
|
80
81
|
const index = stack.pop()!;
|
|
81
82
|
if (index === -1) continue;
|
|
82
|
-
const memory =
|
|
83
|
+
const { memory } = delimiters[index];
|
|
83
84
|
assert(memory.length > 0);
|
|
84
85
|
if (memory.length === 1) {
|
|
85
86
|
assert(index === delimiters.length - 1);
|
|
@@ -88,6 +89,7 @@ export class Delimiters {
|
|
|
88
89
|
delimiters.pop();
|
|
89
90
|
}
|
|
90
91
|
else {
|
|
92
|
+
assert(false);
|
|
91
93
|
memory.pop();
|
|
92
94
|
delimiters[index] = memory.at(-1)!;
|
|
93
95
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ObjectCreate, min } from 'spica/alias';
|
|
2
|
-
import { Parser, Result, Ctx,
|
|
2
|
+
import { Parser, Result, Ctx, Node, Context } from '../../data/parser';
|
|
3
3
|
import { clone } from 'spica/assign';
|
|
4
4
|
|
|
5
5
|
export function reset<P extends Parser<unknown>>(base: Context<P>, parser: P): P;
|
|
6
|
-
export function reset<
|
|
6
|
+
export function reset<N>(base: Ctx, parser: Parser<N>): Parser<N> {
|
|
7
7
|
assert(Object.getPrototypeOf(base) === Object.prototype);
|
|
8
8
|
assert(Object.freeze(base));
|
|
9
9
|
const changes = Object.entries(base);
|
|
@@ -13,7 +13,7 @@ export function reset<T>(base: Ctx, parser: Parser<T>): Parser<T> {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function context<P extends Parser<unknown>>(base: Context<P>, parser: P): P;
|
|
16
|
-
export function context<
|
|
16
|
+
export function context<N>(base: Ctx, parser: Parser<N>): Parser<N> {
|
|
17
17
|
assert(Object.getPrototypeOf(base) === Object.prototype);
|
|
18
18
|
assert(Object.freeze(base));
|
|
19
19
|
const changes = Object.entries(base);
|
|
@@ -22,8 +22,8 @@ export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
|
|
|
22
22
|
apply(parser, source, context, changes, values);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function apply<P extends Parser<unknown>>(parser: P, source: string, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<
|
|
26
|
-
function apply<
|
|
25
|
+
function apply<P extends Parser<unknown>>(parser: P, source: string, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Node<P>>;
|
|
26
|
+
function apply<N>(parser: Parser<N>, source: string, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<N> {
|
|
27
27
|
if (reset) {
|
|
28
28
|
context.backtracks = {};
|
|
29
29
|
}
|
|
@@ -97,7 +97,7 @@ export function recursion(recursion: number, parser: Parser<unknown>): Parser<un
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
export function precedence<P extends Parser<unknown>>(precedence: number, parser: P): P;
|
|
100
|
-
export function precedence<
|
|
100
|
+
export function precedence<N>(precedence: number, parser: Parser<N>): Parser<N> {
|
|
101
101
|
assert(precedence >= 0);
|
|
102
102
|
return input => {
|
|
103
103
|
const { context } = input;
|
|
@@ -115,7 +115,7 @@ export function precedence<T>(precedence: number, parser: Parser<T>): Parser<T>
|
|
|
115
115
|
|
|
116
116
|
export function state<P extends Parser<unknown>>(state: number, parser: P): P;
|
|
117
117
|
export function state<P extends Parser<unknown>>(state: number, positive: boolean, parser: P): P;
|
|
118
|
-
export function state<
|
|
118
|
+
export function state<N>(state: number, positive: boolean | Parser<N>, parser?: Parser<N>): Parser<N> {
|
|
119
119
|
if (typeof positive === 'function') {
|
|
120
120
|
parser = positive;
|
|
121
121
|
positive = true;
|
|
@@ -136,7 +136,7 @@ export function state<T>(state: number, positive: boolean | Parser<T>, parser?:
|
|
|
136
136
|
|
|
137
137
|
export function constraint<P extends Parser<unknown>>(state: number, parser: P): P;
|
|
138
138
|
export function constraint<P extends Parser<unknown>>(state: number, positive: boolean, parser: P): P;
|
|
139
|
-
export function constraint<
|
|
139
|
+
export function constraint<N>(state: number, positive: boolean | Parser<N>, parser?: Parser<N>): Parser<N> {
|
|
140
140
|
if (typeof positive === 'function') {
|
|
141
141
|
parser = positive;
|
|
142
142
|
positive = true;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Parser, Ctx,
|
|
1
|
+
import { Parser, Ctx, Node, Context, SubParsers, SubNode, eval, exec, check } from '../parser';
|
|
2
2
|
import { push } from 'spica/array';
|
|
3
3
|
|
|
4
|
-
export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes:
|
|
5
|
-
export function inits<
|
|
4
|
+
export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubNode<P>[], rest: string) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
5
|
+
export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: N[], rest: string) => boolean): Parser<N, Ctx, D> {
|
|
6
6
|
assert(parsers.every(f => f));
|
|
7
7
|
if (parsers.length === 1) return parsers[0];
|
|
8
8
|
return ({ source, context }) => {
|
|
9
9
|
let rest = source;
|
|
10
|
-
let nodes:
|
|
10
|
+
let nodes: N[] | undefined;
|
|
11
11
|
for (let len = parsers.length, i = 0; i < len; ++i) {
|
|
12
12
|
if (rest === '') break;
|
|
13
13
|
if (context.delimiters?.match(rest, context)) break;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Parser, Ctx,
|
|
1
|
+
import { Parser, Ctx, Node, Context, SubParsers, SubNode, eval, exec, check } from '../parser';
|
|
2
2
|
import { push } from 'spica/array';
|
|
3
3
|
|
|
4
|
-
export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes:
|
|
5
|
-
export function sequence<
|
|
4
|
+
export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubNode<P>[], rest: string) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
5
|
+
export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: N[], rest: string) => boolean): Parser<N, Ctx, D> {
|
|
6
6
|
assert(parsers.every(f => f));
|
|
7
7
|
if (parsers.length === 1) return parsers[0];
|
|
8
8
|
return ({ source, context }) => {
|
|
9
9
|
let rest = source;
|
|
10
|
-
let nodes:
|
|
10
|
+
let nodes: N[] | undefined;
|
|
11
11
|
for (let len = parsers.length, i = 0; i < len; ++i) {
|
|
12
12
|
if (rest === '') return;
|
|
13
13
|
if (context.delimiters?.match(rest, context)) return;
|
|
@@ -6,13 +6,13 @@ type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number,
|
|
|
6
6
|
|
|
7
7
|
export function some<P extends Parser<unknown>>(parser: P, limit?: number): P;
|
|
8
8
|
export function some<P extends Parser<unknown>>(parser: P, end?: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
9
|
-
export function some<
|
|
9
|
+
export function some<N>(parser: Parser<N>, end?: string | RegExp | number, delimiters: readonly DelimiterOption[] = [], limit = -1): Parser<N> {
|
|
10
10
|
if (typeof end === 'number') return some(parser, undefined, delimiters, end);
|
|
11
11
|
assert(parser);
|
|
12
12
|
assert([end].concat(delimiters.map(o => o[0])).every(d => d instanceof RegExp ? !d.flags.match(/[gmy]/) && d.source.startsWith('^') : true));
|
|
13
13
|
const match = Delimiters.matcher(end);
|
|
14
14
|
const delims = delimiters.map(([delimiter, precedence, linebreakable = true]) => ({
|
|
15
|
-
signature: Delimiters.signature(delimiter),
|
|
15
|
+
signature: Delimiters.signature(delimiter, linebreakable),
|
|
16
16
|
matcher: Delimiters.matcher(delimiter),
|
|
17
17
|
precedence,
|
|
18
18
|
linebreakable,
|
|
@@ -21,7 +21,7 @@ export function some<T>(parser: Parser<T>, end?: string | RegExp | number, delim
|
|
|
21
21
|
if (source === '') return;
|
|
22
22
|
assert(context.backtracks ??= {});
|
|
23
23
|
let rest = source;
|
|
24
|
-
let nodes:
|
|
24
|
+
let nodes: N[] | undefined;
|
|
25
25
|
if (delims.length > 0) {
|
|
26
26
|
context.delimiters ??= new Delimiters();
|
|
27
27
|
context.delimiters.push(delims);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Parser, Ctx,
|
|
1
|
+
import { Parser, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { inits } from './inits';
|
|
4
4
|
|
|
5
|
-
export function subsequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes:
|
|
6
|
-
export function subsequence<
|
|
5
|
+
export function subsequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubNode<P>[], rest: string) => 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: N[], rest: string) => 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, Ctx,
|
|
1
|
+
import { Parser, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { sequence } from './sequence';
|
|
4
4
|
|
|
5
|
-
export function tails<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes:
|
|
6
|
-
export function tails<
|
|
5
|
+
export function tails<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubNode<P>[], rest: string) => 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: N[], rest: string) => boolean): Parser<N, Ctx, D> {
|
|
7
7
|
return union(parsers.map((_, i) => sequence(parsers.slice(i), resume)) as D);
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Parser, Ctx,
|
|
1
|
+
import { Parser, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
|
|
2
2
|
|
|
3
|
-
export function union<P extends Parser<unknown>>(parsers: SubParsers<P>):
|
|
4
|
-
export function union<
|
|
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, Ctx, D> {
|
|
5
5
|
assert(parsers.every(f => f));
|
|
6
6
|
switch (parsers.length) {
|
|
7
7
|
case 0:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Delimiters } from './parser/context/delimiter';
|
|
2
2
|
|
|
3
|
-
export type Parser<
|
|
4
|
-
= (input: Input<C>) => Result<
|
|
3
|
+
export type Parser<N, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
|
|
4
|
+
= (input: Input<C>) => Result<N, C, D>;
|
|
5
5
|
export interface Input<C extends Ctx = Ctx> {
|
|
6
6
|
readonly source: string;
|
|
7
7
|
readonly context: C;
|
|
8
8
|
}
|
|
9
|
-
export type Result<
|
|
10
|
-
= readonly [
|
|
11
|
-
| readonly [
|
|
9
|
+
export type Result<N, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
|
|
10
|
+
= readonly [N[], string, C, D]
|
|
11
|
+
| readonly [N[], string]
|
|
12
12
|
| undefined;
|
|
13
13
|
export interface Ctx {
|
|
14
14
|
readonly resources?: {
|
|
@@ -24,19 +24,19 @@ export interface Ctx {
|
|
|
24
24
|
linebreak?: number;
|
|
25
25
|
recent?: string[];
|
|
26
26
|
}
|
|
27
|
-
export type
|
|
27
|
+
export type Node<P extends Parser<unknown>> = P extends Parser<infer N> ? N : never;
|
|
28
28
|
export type SubParsers<P extends Parser<unknown>> = P extends Parser<unknown, Ctx, infer D> ? D : never;
|
|
29
29
|
export type Context<P extends Parser<unknown>> = P extends Parser<unknown, infer C> ? C : never;
|
|
30
|
-
export type
|
|
31
|
-
export type IntermediateParser<P extends Parser<unknown>> = Parser<
|
|
32
|
-
type
|
|
30
|
+
export type SubNode<P extends Parser<unknown>> = ExtractSubNode<SubParsers<P>>;
|
|
31
|
+
export type IntermediateParser<P extends Parser<unknown>> = Parser<SubNode<P>, Context<P>, SubParsers<P>>;
|
|
32
|
+
type ExtractSubNode<D extends Parser<unknown>[]> = ExtractSubParser<D> extends infer N ? N extends Parser<infer U> ? U : never : never;
|
|
33
33
|
type ExtractSubParser<D extends Parser<unknown>[]> = D extends (infer P)[] ? P extends Parser<unknown> ? P : never : never;
|
|
34
34
|
|
|
35
35
|
export { eval_ as eval };
|
|
36
|
-
function eval_<
|
|
37
|
-
function eval_<
|
|
38
|
-
function eval_<
|
|
39
|
-
function eval_<
|
|
36
|
+
function eval_<N>(result: NonNullable<Result<N>>, default_?: N[]): N[];
|
|
37
|
+
function eval_<N>(result: Result<N>, default_: N[]): N[];
|
|
38
|
+
function eval_<N>(result: Result<N>, default_?: undefined): N[] | undefined;
|
|
39
|
+
function eval_<N>(result: Result<N>, default_?: N[]): N[] | undefined {
|
|
40
40
|
return result
|
|
41
41
|
? result[0]
|
|
42
42
|
: default_;
|
package/src/combinator.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from './combinator/control/constraint/contract';
|
|
|
11
11
|
export * from './combinator/control/manipulation/fence';
|
|
12
12
|
export * from './combinator/control/manipulation/indent';
|
|
13
13
|
export * from './combinator/control/manipulation/scope';
|
|
14
|
+
export * from './combinator/control/manipulation/clear';
|
|
14
15
|
export * from './combinator/control/manipulation/surround';
|
|
15
16
|
export * from './combinator/control/manipulation/match';
|
|
16
17
|
export * from './combinator/control/manipulation/convert';
|
|
@@ -43,7 +43,7 @@ export const segment: FigureParser.SegmentParser = block(match(
|
|
|
43
43
|
]),
|
|
44
44
|
]),
|
|
45
45
|
closer),
|
|
46
|
-
([, fence]) => fence.length, {})
|
|
46
|
+
([, fence]) => fence.length, {})));
|
|
47
47
|
|
|
48
48
|
export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
|
|
49
49
|
convert(source => source.slice(source.match(/^~+(?:\w+\s+)?/)![0].length, source.trimEnd().lastIndexOf('\n')),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { max, min, isArray } from 'spica/alias';
|
|
2
2
|
import { ExtensionParser } from '../../block';
|
|
3
|
-
import {
|
|
4
|
-
import { union, subsequence, inits, some, block, line, validate, fence, rewrite, surround, open,
|
|
3
|
+
import { Node, eval } from '../../../combinator/data/parser';
|
|
4
|
+
import { union, subsequence, inits, some, block, line, validate, fence, rewrite, clear, surround, open, convert, dup, lazy, fmap } from '../../../combinator';
|
|
5
5
|
import { inline, medialink, media, shortmedia } from '../../inline';
|
|
6
6
|
import { str, anyline, emptyline, contentline } from '../../source';
|
|
7
7
|
import { lineable, invalid } from '../../util';
|
|
@@ -147,7 +147,7 @@ function attributes(source: string): Record<string, string | undefined> {
|
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
function format(rows:
|
|
150
|
+
function format(rows: Node<RowParser>[]): HTMLTableSectionElement[] {
|
|
151
151
|
const thead = html('thead');
|
|
152
152
|
const tbody = html('tbody');
|
|
153
153
|
const tfoot = html('tfoot');
|