securemark 0.289.1 → 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 +8 -0
- package/design.md +2 -1
- package/dist/index.js +114 -90
- 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 +79 -69
- 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/context.ts +5 -6
- package/src/parser/inline/annotation.ts +3 -1
- package/src/parser/inline/autolink/hashnum.ts +5 -1
- package/src/parser/inline/bracket.ts +8 -4
- package/src/parser/inline/code.ts +2 -1
- package/src/parser/inline/extension/index.ts +3 -1
- package/src/parser/inline/extension/label.ts +1 -1
- package/src/parser/inline/extension/placeholder.ts +2 -1
- package/src/parser/inline/link.ts +5 -2
- package/src/parser/inline/media.ts +4 -2
- package/src/parser/inline/reference.ts +2 -1
- package/src/parser/inline/ruby.ts +4 -2
- package/src/parser/inline/template.ts +2 -1
- package/src/parser/util.ts +10 -10
- package/src/parser/visibility.ts +11 -11
- package/src/util/quote.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Parser,
|
|
1
|
+
import { Parser, Node, Context } from '../../data/parser';
|
|
2
2
|
import { union } from '../../data/parser/union';
|
|
3
3
|
|
|
4
|
-
export function fallback<P extends Parser<unknown>>(parser: P, otherwise: Parser<
|
|
5
|
-
export function fallback<
|
|
4
|
+
export function fallback<P extends Parser<unknown>>(parser: P, otherwise: Parser<Node<P>, Context<P>>): P;
|
|
5
|
+
export function fallback<N>(parser: Parser<N>, otherwise: Parser<N>): Parser<N> {
|
|
6
6
|
return union([parser, otherwise]);
|
|
7
7
|
}
|
|
@@ -9,7 +9,7 @@ import { memoize } from 'spica/memoize';
|
|
|
9
9
|
|
|
10
10
|
export function indent<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
|
|
11
11
|
export function indent<P extends Parser<unknown>>(opener: RegExp, parser: P, separation?: boolean): P;
|
|
12
|
-
export function indent<
|
|
12
|
+
export function indent<N>(opener: RegExp | Parser<N>, parser?: Parser<N> | boolean, separation = false): Parser<N> {
|
|
13
13
|
if (typeof opener === 'function') return indent(/^([ \t])\1*/, opener, parser as boolean);
|
|
14
14
|
assert(parser);
|
|
15
15
|
return bind(block(match(
|
|
@@ -17,9 +17,9 @@ export function indent<T>(opener: RegExp | Parser<T>, parser?: Parser<T> | boole
|
|
|
17
17
|
memoize(
|
|
18
18
|
([indent]) =>
|
|
19
19
|
some(line(open(indent, ({ source }) => [[source], '']))),
|
|
20
|
-
([indent]) => indent.length * 2 + +(indent[0] === ' '), {})
|
|
20
|
+
([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
|
|
21
21
|
(lines, rest, context) => {
|
|
22
|
-
assert(parser = parser as Parser<
|
|
22
|
+
assert(parser = parser as Parser<N>);
|
|
23
23
|
// 影響する使用はないはず
|
|
24
24
|
//const { backtracks } = context;
|
|
25
25
|
//context.backtracks = {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Parser } from '../../data/parser';
|
|
2
2
|
|
|
3
3
|
export function lazy<P extends Parser<unknown>>(builder: () => P): P;
|
|
4
|
-
export function lazy<
|
|
5
|
-
let parser: Parser<
|
|
4
|
+
export function lazy<N>(builder: () => Parser<N>): Parser<N> {
|
|
5
|
+
let parser: Parser<N>;
|
|
6
6
|
return input =>
|
|
7
7
|
parser !== undefined
|
|
8
8
|
? parser(input)
|
|
@@ -2,7 +2,7 @@ import { Parser, exec, check } from '../../data/parser';
|
|
|
2
2
|
import { consume } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
export function match<P extends Parser<unknown>>(pattern: RegExp, f: (matched: RegExpMatchArray) => P, cost?: boolean): P;
|
|
5
|
-
export function match<
|
|
5
|
+
export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Parser<N>, cost = false): Parser<N> {
|
|
6
6
|
assert(!pattern.flags.match(/[gmy]/) && pattern.source.startsWith('^'));
|
|
7
7
|
return input => {
|
|
8
8
|
const { source, context } = input;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Parser, Input, Result,
|
|
1
|
+
import { Parser, Input, Result, Node, Context } from '../../data/parser';
|
|
2
2
|
|
|
3
|
-
export function recover<P extends Parser<unknown>>(parser: P, fallback: (input: Input<Context<P>>, reason: unknown) => Result<
|
|
4
|
-
export function recover<
|
|
3
|
+
export function recover<P extends Parser<unknown>>(parser: P, fallback: (input: Input<Context<P>>, reason: unknown) => Result<Node<P>>): P;
|
|
4
|
+
export function recover<N>(parser: Parser<N>, fallback: (input: Input, reason: unknown) => Result<N>): Parser<N> {
|
|
5
5
|
return input => {
|
|
6
6
|
try {
|
|
7
7
|
return parser(input);
|
|
@@ -2,7 +2,7 @@ import { Parser } from '../../data/parser';
|
|
|
2
2
|
import { fmap } from '../monad/fmap';
|
|
3
3
|
|
|
4
4
|
export function reverse<P extends Parser<unknown>>(parser: P): P;
|
|
5
|
-
export function reverse<
|
|
5
|
+
export function reverse<N>(parser: Parser<N>): Parser<N> {
|
|
6
6
|
return fmap(parser, nodes => nodes.reverse());
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import { Parser, Context, eval, exec, check } from '../../data/parser';
|
|
|
2
2
|
import { consume } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
export function focus<P extends Parser<unknown>>(scope: string | RegExp, parser: P, cost?: boolean): P;
|
|
5
|
-
export function focus<
|
|
5
|
+
export function focus<N>(scope: string | RegExp, parser: Parser<N>, cost = true): Parser<N> {
|
|
6
6
|
assert(scope instanceof RegExp ? !scope.flags.match(/[gmy]/) && scope.source.startsWith('^') : scope);
|
|
7
7
|
assert(parser);
|
|
8
8
|
const match: (source: string) => string = typeof scope === 'string'
|
|
@@ -29,9 +29,9 @@ export function focus<T>(scope: string | RegExp, parser: Parser<T>, cost = true)
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//export function rewrite<
|
|
32
|
+
//export function rewrite<N, C extends Ctx, D extends Parser<unknown, C>[]>(scope: Parser<unknown, C, D>, parser: Parser<N, C, never>): Parser<N, C, D>;
|
|
33
33
|
export function rewrite<P extends Parser<unknown>>(scope: Parser<unknown, Context<P>>, parser: P): P;
|
|
34
|
-
export function rewrite<
|
|
34
|
+
export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>): Parser<N> {
|
|
35
35
|
assert(scope);
|
|
36
36
|
assert(parser);
|
|
37
37
|
return input => {
|
|
@@ -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
|
-
|
|
44
|
-
): Parser<
|
|
42
|
+
backtrackstate: number = 0,
|
|
43
|
+
): Parser<N> {
|
|
45
44
|
switch (typeof opener) {
|
|
46
45
|
case 'string':
|
|
47
46
|
case 'object':
|
|
@@ -52,61 +51,63 @@ export function surround<T>(
|
|
|
52
51
|
case 'object':
|
|
53
52
|
closer = match(closer);
|
|
54
53
|
}
|
|
54
|
+
const statesize = 2;
|
|
55
55
|
return ({ source, context }) => {
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
56
|
+
const sme_ = source;
|
|
57
|
+
if (sme_ === '') return;
|
|
58
58
|
const { linebreak } = context;
|
|
59
59
|
context.linebreak = undefined;
|
|
60
|
-
const
|
|
61
|
-
assert(check(
|
|
62
|
-
if (
|
|
63
|
-
const
|
|
64
|
-
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);
|
|
65
65
|
for (const backtrack of backtracks) {
|
|
66
66
|
if (backtrack & 1) {
|
|
67
67
|
const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
|
|
68
|
-
for (let i = 0; i < source.length -
|
|
68
|
+
for (let i = 0; i < source.length - me_.length; ++i) {
|
|
69
69
|
if (source[i] !== source[0]) break;
|
|
70
|
-
const pos = source.length + offset -
|
|
70
|
+
const pos = source.length - i + offset - 1;
|
|
71
|
+
assert(pos >= 0);
|
|
71
72
|
if (!(pos in backtracks)) continue;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (backtracks[pos] & 1 << (backtrack >>> 2) + shift) return void revert(context, linebreak);
|
|
73
|
+
const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
|
|
74
|
+
if (backtracks[pos] & 1 << size(backtrack >>> statesize) + shift) return void revert(context, linebreak);
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
const { backtrack
|
|
79
|
-
context.backtrack =
|
|
80
|
-
const
|
|
81
|
-
assert(check(
|
|
82
|
-
context.backtrack =
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
86
|
-
const
|
|
87
|
-
assert(check(
|
|
88
|
-
const
|
|
89
|
-
const rest = exec(
|
|
90
|
-
if (rest.length ===
|
|
78
|
+
const { backtrack = 0 } = context;
|
|
79
|
+
context.backtrack = backtrack | backtrackstate;
|
|
80
|
+
const resultM = me_ !== '' ? parser({ source: me_, context }) : undefined;
|
|
81
|
+
assert(check(me_, resultM));
|
|
82
|
+
context.backtrack = backtrack;
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
const pos = source.length + offset - 1;
|
|
95
|
+
assert(pos >= 0);
|
|
96
|
+
const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
|
|
97
|
+
backtracks[pos] |= 1 << size(backtrack >>> statesize) + shift;
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
context.recent = [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
sme_.slice(0, sme_.length - me_.length),
|
|
102
|
+
me_.slice(0, me_.length - e_.length),
|
|
103
|
+
e_.slice(0, e_.length - rest.length),
|
|
103
104
|
];
|
|
104
|
-
const result =
|
|
105
|
+
const result = nodesE
|
|
105
106
|
? f
|
|
106
|
-
? f([
|
|
107
|
-
: [push(unshift(
|
|
107
|
+
? f([nodesS, nodesM!, nodesE], rest, context)
|
|
108
|
+
: [push(unshift(nodesS, nodesM ?? []), nodesE), rest] satisfies [N[], string]
|
|
108
109
|
: g
|
|
109
|
-
? g([
|
|
110
|
+
? g([nodesS, nodesM!, me_], rest, context)
|
|
110
111
|
: undefined;
|
|
111
112
|
if (result) {
|
|
112
113
|
context.linebreak ??= linebreak;
|
|
@@ -117,6 +118,14 @@ export function surround<T>(
|
|
|
117
118
|
return result;
|
|
118
119
|
};
|
|
119
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
|
+
}
|
|
120
129
|
|
|
121
130
|
function match(pattern: string | RegExp): (input: Input) => [never[], string] | undefined {
|
|
122
131
|
switch (typeof pattern) {
|
|
@@ -131,20 +140,21 @@ function match(pattern: string | RegExp): (input: Input) => [never[], string] |
|
|
|
131
140
|
};
|
|
132
141
|
}
|
|
133
142
|
}
|
|
134
|
-
|
|
135
143
|
function revert(context: Ctx, linebreak: number | undefined): void {
|
|
136
144
|
context.linebreak = linebreak;
|
|
137
145
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
export function clear<D extends Parser<unknown, C>[], C extends Ctx>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
|
|
149
|
-
return fmap<never, Parser<unknown, C, D>>(parser, () => []);
|
|
146
|
+
function size(bits: number): number {
|
|
147
|
+
if (bits === 0) return 0;
|
|
148
|
+
let p = 0;
|
|
149
|
+
for (let s = 32 / 2; s > 0; s >>>= 1) {
|
|
150
|
+
const q = p + s;
|
|
151
|
+
if (bits >>> q === 0) continue;
|
|
152
|
+
p = q;
|
|
153
|
+
}
|
|
154
|
+
return p + 1;
|
|
150
155
|
}
|
|
156
|
+
assert(size(0 << 0) === 0);
|
|
157
|
+
assert(size(1 << 0) === 1);
|
|
158
|
+
assert(size(1 << 1) === 2);
|
|
159
|
+
assert(size(1 << 30) === 31);
|
|
160
|
+
assert(size(1 << 31) === 32);
|
|
@@ -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) =>
|