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.
Files changed (42) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/design.md +2 -1
  3. package/dist/index.js +94 -78
  4. package/package.json +1 -1
  5. package/src/combinator/control/constraint/block.ts +1 -1
  6. package/src/combinator/control/constraint/contract.ts +7 -7
  7. package/src/combinator/control/constraint/line.ts +1 -1
  8. package/src/combinator/control/manipulation/clear.ts +7 -0
  9. package/src/combinator/control/manipulation/convert.ts +1 -1
  10. package/src/combinator/control/manipulation/duplicate.ts +4 -4
  11. package/src/combinator/control/manipulation/fallback.ts +3 -3
  12. package/src/combinator/control/manipulation/indent.ts +3 -3
  13. package/src/combinator/control/manipulation/lazy.ts +2 -2
  14. package/src/combinator/control/manipulation/match.ts +1 -1
  15. package/src/combinator/control/manipulation/recovery.ts +3 -3
  16. package/src/combinator/control/manipulation/reverse.ts +1 -1
  17. package/src/combinator/control/manipulation/scope.ts +3 -3
  18. package/src/combinator/control/manipulation/surround.ts +59 -61
  19. package/src/combinator/control/manipulation/trim.ts +3 -3
  20. package/src/combinator/control/monad/bind.ts +6 -6
  21. package/src/combinator/control/monad/fmap.ts +6 -6
  22. package/src/combinator/data/parser/context/delimiter.ts +21 -19
  23. package/src/combinator/data/parser/context.ts +8 -8
  24. package/src/combinator/data/parser/inits.ts +4 -4
  25. package/src/combinator/data/parser/sequence.ts +4 -4
  26. package/src/combinator/data/parser/some.ts +3 -3
  27. package/src/combinator/data/parser/subsequence.ts +3 -3
  28. package/src/combinator/data/parser/tails.ts +3 -3
  29. package/src/combinator/data/parser/union.ts +3 -3
  30. package/src/combinator/data/parser.ts +13 -13
  31. package/src/combinator.ts +1 -0
  32. package/src/parser/block/extension/figure.ts +1 -1
  33. package/src/parser/block/extension/table.ts +3 -3
  34. package/src/parser/block/olist.ts +4 -4
  35. package/src/parser/block/reply/cite.ts +3 -3
  36. package/src/parser/block/ulist.ts +1 -1
  37. package/src/parser/inline/autolink/hashnum.ts +5 -1
  38. package/src/parser/inline/code.ts +2 -1
  39. package/src/parser/inline/extension/label.ts +1 -1
  40. package/src/parser/util.ts +10 -10
  41. package/src/parser/visibility.ts +11 -11
  42. package/src/util/quote.ts +1 -1
@@ -1,47 +1,46 @@
1
- import { Parser, Input, Result, Ctx, Tree, Context, SubParsers, SubTree, IntermediateParser, eval, exec, check } from '../../data/parser';
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[], SubTree<P>[], S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
9
- g?: (rss: [S[], SubTree<P>[], string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
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[], SubTree<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
17
- g?: (rss: [S[], SubTree<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
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[], Tree<P>[], S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
25
- g?: (rss: [S[], Tree<P>[], string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
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[], Tree<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
33
- g?: (rss: [S[], Tree<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
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<T>(
38
- opener: string | RegExp | Parser<T>, parser: Parser<T>, closer: string | RegExp | Parser<T>,
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: [T[], T[], T[]], rest: string, context: Ctx) => Result<T>,
41
- g?: (rss: [T[], T[], string], rest: string, context: Ctx) => Result<T>,
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<T> {
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 lmr_ = source;
58
- if (lmr_ === '') return;
56
+ const sme_ = source;
57
+ if (sme_ === '') return;
59
58
  const { linebreak } = context;
60
59
  context.linebreak = undefined;
61
- const res1 = opener({ source: lmr_, context });
62
- assert(check(lmr_, res1, false));
63
- if (res1 === undefined) return void revert(context, linebreak);
64
- const rl = eval(res1);
65
- const mr_ = exec(res1);
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 - mr_.length; ++i) {
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 - i - 1;
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 res2 = mr_ !== '' ? parser({ source: mr_, context }) : undefined;
81
- assert(check(mr_, res2));
80
+ const resultM = me_ !== '' ? parser({ source: me_, context }) : undefined;
81
+ assert(check(me_, resultM));
82
82
  context.backtrack = backtrack;
83
- const rm = eval(res2);
84
- const r_ = exec(res2, mr_);
85
- if (!rm && !optional) return void revert(context, linebreak);
86
- const res3 = closer({ source: r_, context });
87
- assert(check(r_, res3, false));
88
- const rr = eval(res3);
89
- const rest = exec(res3, r_);
90
- if (rest.length === lmr_.length) return void revert(context, linebreak);
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 && rr === undefined) {
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[source.length + offset - 1] |= 1 << size(backtrack >>> statesize) + shift;
97
+ backtracks[pos] |= 1 << size(backtrack >>> statesize) + shift;
96
98
  }
97
99
  }
98
100
  context.recent = [
99
- lmr_.slice(0, lmr_.length - mr_.length),
100
- mr_.slice(0, mr_.length - r_.length),
101
- r_.slice(0, r_.length - rest.length),
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 = rr
105
+ const result = nodesE
104
106
  ? f
105
- ? f([rl, rm!, rr], rest, context)
106
- : [push(unshift(rl, rm ?? []), rr), rest] satisfies [T[], string]
107
+ ? f([nodesS, nodesM!, nodesE], rest, context)
108
+ : [push(unshift(nodesS, nodesM ?? []), nodesE), rest] satisfies [N[], string]
107
109
  : g
108
- ? g([rl, rm!, mr_], rest, context)
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
- if (bits >>> p + s === 0) continue;
138
- p += s;
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<T>(parser: Parser<T>): Parser<T> {
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<T>(parser: Parser<T>): Parser<T> {
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<T>(parser: Parser<T>): Parser<T> {
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, Tree, Context, SubParsers, SubTree, IntermediateParser, eval, exec, check } from '../../data/parser';
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: SubTree<P>[], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>): P;
4
- export function bind<P extends Parser<unknown>>(parser: P, f: (nodes: Tree<P>[], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>): P;
5
- export function bind<T, P extends Parser<unknown>>(parser: Parser<T, Context<P>, SubParsers<P>>, f: (nodes: T[], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>): P;
6
- export function bind<U, P extends Parser<unknown>>(parser: P, f: (nodes: Tree<P>[], rest: string, context: Context<P>) => Result<U, Context<P>, SubParsers<P>>): Parser<U, Context<P>, SubParsers<P>>;
7
- export function bind<T, U>(parser: Parser<T>, f: (nodes: T[], rest: string, context: Ctx) => Result<U>): Parser<U> {
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, Tree, Context, IntermediateParser, SubTree } from '../../data/parser';
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: SubTree<P>[], rest: string, context: Context<P>) => Tree<P>[]): P;
5
- export function fmap<P extends Parser<unknown>>(parser: P, f: (nodes: Tree<P>[], rest: string, context: Context<P>) => Tree<P>[]): P;
6
- export function fmap<T, P extends Parser<unknown>>(parser: Parser<T, Context<P>, SubParsers<P>>, f: (nodes: T[], rest: string, context: Context<P>) => Tree<P>[]): P;
7
- export function fmap<U, P extends Parser<unknown>>(parser: P, f: (nodes: Tree<P>[], rest: string, context: Context<P>) => U[]): Parser<U, Context<P>, SubParsers<P>>;
8
- export function fmap<T, U>(parser: Parser<T>, f: (nodes: T[], rest: string, context: Ctx) => U[]): Parser<U> {
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}/${pattern.flags}`;
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
- if (memory.length === 0 || precedence > delimiters[index].precedence) {
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: 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 { registry, delimiters, stack } = this;
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 = registry(delimiters[index].signature);
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, Tree, Context } from '../../data/parser';
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<T>(base: Ctx, parser: Parser<T>): Parser<T> {
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<T>(base: Ctx, parser: Parser<T>): Parser<T> {
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<Tree<P>>;
26
- function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<T> {
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<T>(precedence: number, parser: Parser<T>): Parser<T> {
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<T>(state: number, positive: boolean | Parser<T>, parser?: Parser<T>): Parser<T> {
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<T>(state: number, positive: boolean | Parser<T>, parser?: Parser<T>): Parser<T> {
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, Tree, Context, SubParsers, SubTree, eval, exec, check } from '../parser';
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: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
5
- export function inits<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
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: T[] | undefined;
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, Tree, Context, SubParsers, SubTree, eval, exec, check } from '../parser';
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: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
5
- export function sequence<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
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: T[] | undefined;
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<T>(parser: Parser<T>, end?: string | RegExp | number, delimiters: readonly DelimiterOption[] = [], limit = -1): Parser<T> {
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: T[] | undefined;
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, Tree, Context, SubParsers, SubTree } from '../parser';
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: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
6
- export function subsequence<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
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, Tree, Context, SubParsers, SubTree } from '../parser';
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: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
6
- export function tails<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
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, Tree, Context, SubParsers, SubTree } from '../parser';
1
+ import { Parser, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
 
3
- export function union<P extends Parser<unknown>>(parsers: SubParsers<P>): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
4
- export function union<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
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<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
4
- = (input: Input<C>) => Result<T, C, D>;
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<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
10
- = readonly [T[], string, C, D]
11
- | readonly [T[], string]
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 Tree<P extends Parser<unknown>> = P extends Parser<infer T> ? T : never;
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 SubTree<P extends Parser<unknown>> = ExtractSubTree<SubParsers<P>>;
31
- export type IntermediateParser<P extends Parser<unknown>> = Parser<SubTree<P>, Context<P>, SubParsers<P>>;
32
- type ExtractSubTree<D extends Parser<unknown>[]> = ExtractSubParser<D> extends infer T ? T extends Parser<infer U> ? U : never : never;
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_<T>(result: NonNullable<Result<T>>, default_?: T[]): T[];
37
- function eval_<T>(result: Result<T>, default_: T[]): T[];
38
- function eval_<T>(result: Result<T>, default_?: undefined): T[] | undefined;
39
- function eval_<T>(result: Result<T>, default_?: T[]): T[] | undefined {
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, {}), false));
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 { Tree, eval } from '../../../combinator/data/parser';
4
- import { union, subsequence, inits, some, block, line, validate, fence, rewrite, surround, open, clear, convert, dup, lazy, fmap } from '../../../combinator';
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: Tree<RowParser>[]): HTMLTableSectionElement[] {
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');