securemark 0.289.2 → 0.289.4

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 (48) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/design.md +7 -6
  3. package/dist/index.js +141 -88
  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 +47 -26
  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 +14 -13
  31. package/src/combinator.ts +1 -0
  32. package/src/parser/api/parse.test.ts +2 -2
  33. package/src/parser/block/extension/figure.ts +1 -1
  34. package/src/parser/block/extension/table.ts +3 -3
  35. package/src/parser/block/olist.ts +4 -4
  36. package/src/parser/block/reply/cite.ts +3 -3
  37. package/src/parser/block/ulist.ts +1 -1
  38. package/src/parser/inline/autolink/hashnum.ts +5 -1
  39. package/src/parser/inline/code.ts +2 -1
  40. package/src/parser/inline/emstrong.ts +2 -1
  41. package/src/parser/inline/extension/indexer.ts +6 -0
  42. package/src/parser/inline/extension/label.ts +1 -1
  43. package/src/parser/inline/html.ts +2 -2
  44. package/src/parser/inline.test.ts +1 -0
  45. package/src/parser/inline.ts +19 -4
  46. package/src/parser/util.ts +10 -10
  47. package/src/parser/visibility.ts +11 -11
  48. package/src/util/quote.ts +1 -1
@@ -1,16 +1,16 @@
1
1
  import { isArray } from 'spica/alias';
2
- import { Parser, Input, Ctx, Tree, Context, eval, exec, check } from '../../data/parser';
2
+ import { Parser, Input, Ctx, Node, Context, eval, exec, check } from '../../data/parser';
3
3
 
4
4
  //export function contract<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
5
- //export function contract<T>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<T>, cond: (nodes: readonly T[], rest: string) => boolean): Parser<T> {
5
+ //export function contract<N>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<N>, cond: (nodes: readonly N[], rest: string) => boolean): Parser<N> {
6
6
  // return verify(validate(patterns, parser), cond);
7
7
  //}
8
8
 
9
9
  export function validate<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P): P;
10
10
  export function validate<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], has: string, parser: P): P;
11
11
  export function validate<P extends Parser<unknown>>(cond: ((input: Input<Context<P>>) => boolean), parser: P): P;
12
- export function validate<T>(patterns: string | RegExp | (string | RegExp)[] | ((input: Input<Ctx>) => boolean), has: string | Parser<T>, parser?: Parser<T>): Parser<T> {
13
- if (typeof patterns === 'function') return guard(patterns, has as Parser<T>);
12
+ export function validate<N>(patterns: string | RegExp | (string | RegExp)[] | ((input: Input<Ctx>) => boolean), has: string | Parser<N>, parser?: Parser<N>): Parser<N> {
13
+ if (typeof patterns === 'function') return guard(patterns, has as Parser<N>);
14
14
  if (typeof has === 'function') return validate(patterns, '', has);
15
15
  if (!isArray(patterns)) return validate([patterns], has, parser!);
16
16
  assert(patterns.length > 0);
@@ -38,15 +38,15 @@ export function validate<T>(patterns: string | RegExp | (string | RegExp)[] | ((
38
38
  }
39
39
 
40
40
  function guard<P extends Parser<unknown>>(f: (input: Input<Context<P>>) => boolean, parser: P): P;
41
- function guard<T>(f: (input: Input<Ctx>) => boolean, parser: Parser<T>): Parser<T> {
41
+ function guard<N>(f: (input: Input<Ctx>) => boolean, parser: Parser<N>): Parser<N> {
42
42
  return input =>
43
43
  f(input)
44
44
  ? parser(input)
45
45
  : undefined;
46
46
  }
47
47
 
48
- export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: readonly Tree<P>[], rest: string, context: Context<P>) => boolean): P;
49
- export function verify<T>(parser: Parser<T>, cond: (nodes: readonly T[], rest: string, context: Ctx) => boolean): Parser<T> {
48
+ export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: readonly Node<P>[], rest: string, context: Context<P>) => boolean): P;
49
+ export function verify<N>(parser: Parser<N>, cond: (nodes: readonly N[], rest: string, context: Ctx) => boolean): Parser<N> {
50
50
  assert(parser);
51
51
  return input => {
52
52
  const { source, context } = input;
@@ -1,7 +1,7 @@
1
1
  import { Parser, eval, exec, check } from '../../data/parser';
2
2
 
3
3
  export function line<P extends Parser<unknown>>(parser: P): P;
4
- export function line<T>(parser: Parser<T>): Parser<T> {
4
+ export function line<N>(parser: Parser<N>): Parser<N> {
5
5
  assert(parser);
6
6
  return ({ source, context }) => {
7
7
  if (source === '') return;
@@ -0,0 +1,7 @@
1
+ import { Parser, Ctx } from '../../data/parser';
2
+ import { fmap } from '../monad/fmap';
3
+
4
+
5
+ export function clear<D extends Parser<unknown, C>[], C extends Ctx>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
6
+ return fmap<never, Parser<unknown, C, D>>(parser, () => []);
7
+ }
@@ -1,7 +1,7 @@
1
1
  import { Parser, Ctx, Context, check } from '../../data/parser';
2
2
 
3
3
  export function convert<P extends Parser<unknown>>(conv: (source: string, context: Context<P>) => string, parser: P, continuous: boolean, empty?: boolean): P;
4
- export function convert<T>(conv: (source: string, context: Ctx) => string, parser: Parser<T>, continuous: boolean, empty = false): Parser<T> {
4
+ export function convert<N>(conv: (source: string, context: Ctx) => string, parser: Parser<N>, continuous: boolean, empty = false): Parser<N> {
5
5
  assert(parser);
6
6
  return ({ source, context }) => {
7
7
  if (source === '') return;
@@ -1,8 +1,8 @@
1
- import { Parser, Ctx, Tree, Context, SubParsers } from '../../data/parser';
1
+ import { Parser, Ctx, Node, Context, SubParsers } from '../../data/parser';
2
2
  import { fmap } from '../monad/fmap';
3
3
 
4
- export function dup<P extends Parser<unknown[]>>(parser: Parser<Tree<P>[number], Context<P>, SubParsers<P>>): P;
5
- export function dup<T, C extends Ctx, D extends Parser<unknown, C>[]>(parser: Parser<T, C, D>): Parser<T[], C, D>;
6
- export function dup<T>(parser: Parser<T>): Parser<T[]> {
4
+ export function dup<P extends Parser<unknown[]>>(parser: Parser<Node<P>[number], Context<P>, SubParsers<P>>): P;
5
+ export function dup<N, C extends Ctx, D extends Parser<unknown, C>[]>(parser: Parser<N, C, D>): Parser<N[], C, D>;
6
+ export function dup<N>(parser: Parser<N>): Parser<N[]> {
7
7
  return fmap(parser, nodes => [nodes]);
8
8
  }
@@ -1,7 +1,7 @@
1
- import { Parser, Tree, Context } from '../../data/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<Tree<P>, Context<P>>): P;
5
- export function fallback<T>(parser: Parser<T>, otherwise: Parser<T>): Parser<T> {
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<T>(opener: RegExp | Parser<T>, parser?: Parser<T> | boolean, separation = false): Parser<T> {
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] === ' '), {}), false), separation),
20
+ ([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
21
21
  (lines, rest, context) => {
22
- assert(parser = parser as Parser<T>);
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<T>(builder: () => Parser<T>): Parser<T> {
5
- let parser: Parser<T>;
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<T>(pattern: RegExp, f: (matched: RegExpMatchArray) => Parser<T>, cost = true): Parser<T> {
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, Tree, Context } from '../../data/parser';
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<Tree<P>>): P;
4
- export function recover<T>(parser: Parser<T>, fallback: (input: Input, reason: unknown) => Result<T>): Parser<T> {
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<T>(parser: Parser<T>): Parser<T> {
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<T>(scope: string | RegExp, parser: Parser<T>, cost = true): Parser<T> {
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<T, C extends Ctx, D extends Parser<unknown, C>[]>(scope: Parser<unknown, C, D>, parser: Parser<T, C, never>): Parser<T, C, D>;
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<T>(scope: Parser<unknown>, parser: Parser<T>): Parser<T> {
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, 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
  }
@@ -1,9 +1,9 @@
1
1
  import { Ctx } from '../../parser';
2
- import { memoize } from 'spica/memoize';
3
2
 
4
3
  interface Delimiter {
4
+ readonly memory: Delimiter[];
5
5
  readonly index: number;
6
- readonly signature: string;
6
+ readonly signature: number | string;
7
7
  readonly matcher: (source: string) => boolean | undefined;
8
8
  readonly precedence: number;
9
9
  readonly linebreakable: boolean;
@@ -11,54 +11,74 @@ interface Delimiter {
11
11
  }
12
12
 
13
13
  export class Delimiters {
14
- public static signature(pattern: string | RegExp | undefined): string {
14
+ // 手間を惜しまなければ規定のパターンはすべて配列のインデクスに変換可能。
15
+ public static signature(pattern: string | RegExp | undefined, linebreakable: boolean): number | string {
15
16
  switch (typeof pattern) {
16
17
  case 'undefined':
17
- return `undefined`;
18
+ return +linebreakable;
18
19
  case 'string':
19
- return `s:${pattern}`;
20
+ assert(pattern !== '\x00');
21
+ if (pattern.length === 1) {
22
+ const code = pattern.charCodeAt(0);
23
+ // 使用中のパターンの8ビット目が空いてるのでひとまずこうしとく
24
+ if ((code & 1 << 7) === 0) return code | +linebreakable << 7;
25
+ }
26
+ return `s:${pattern}:${+linebreakable}`;
20
27
  case 'object':
21
- return `r/${pattern.source}/${pattern.flags}`;
28
+ return `r/${pattern.source}/${+linebreakable}`;
29
+ }
30
+ }
31
+ public static matcher(pattern: string | RegExp | undefined): (source: string) => true | undefined {
32
+ switch (typeof pattern) {
33
+ case 'undefined':
34
+ return () => undefined;
35
+ case 'string':
36
+ return source => source.slice(0, pattern.length) === pattern || undefined;
37
+ case 'object':
38
+ return source => pattern.test(source) || undefined;
39
+ }
40
+ }
41
+ private readonly heap: Record<number, Delimiter[]> = {};
42
+ private readonly map: Map<string, Delimiter[]> = new Map();
43
+ private registry(signature: number | string): Delimiter[] {
44
+ if (typeof signature === 'number') {
45
+ return this.heap[signature] ??= [];
46
+ }
47
+ else {
48
+ const ds = this.map.get(signature);
49
+ if (ds) return ds;
50
+ const blank: Delimiter[] = [];
51
+ this.map.set(signature, blank);
52
+ return blank;
22
53
  }
23
54
  }
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
- private readonly registry = memoize<(signature: string) => Delimiter[]>(() => []);
37
55
  private readonly delimiters: Delimiter[] = [];
38
56
  private readonly stack: number[] = [];
39
57
  private readonly states: (readonly number[])[] = [];
40
58
  public push(
41
59
  delims: readonly {
42
- readonly signature: string;
60
+ readonly signature: number | string;
43
61
  readonly matcher: (source: string) => boolean | undefined;
44
62
  readonly precedence: number;
45
63
  readonly linebreakable: boolean;
46
64
  }[]
47
65
  ): void {
48
- const { registry, delimiters, stack } = this;
66
+ const { delimiters, stack } = this;
49
67
  // シグネチャ数以下
50
68
  assert(delimiters.length < 100);
51
69
  for (let i = 0; i < delims.length; ++i) {
52
70
  const { signature, matcher, precedence, linebreakable } = delims[i];
53
- const memory = registry(signature);
71
+ const memory = this.registry(signature);
54
72
  const index = memory[0]?.index ?? delimiters.length;
55
- if (memory.length === 0 || precedence > delimiters[index].precedence) {
73
+ assert(memory.length === 0 || precedence === delimiters[index].precedence);
74
+ if (memory.length === 0) {
56
75
  const delimiter: Delimiter = {
76
+ memory,
57
77
  index,
58
78
  signature,
59
79
  matcher,
60
80
  precedence,
61
- linebreakable: linebreakable,
81
+ linebreakable,
62
82
  state: true,
63
83
  };
64
84
  delimiters[index] = delimiter;
@@ -74,12 +94,12 @@ export class Delimiters {
74
94
  }
75
95
  public pop(count: number): void {
76
96
  assert(count > 0);
77
- const { registry, delimiters, stack } = this;
97
+ const { delimiters, stack } = this;
78
98
  for (let i = 0; i < count; ++i) {
79
99
  assert(this.stack.length > 0);
80
100
  const index = stack.pop()!;
81
101
  if (index === -1) continue;
82
- const memory = registry(delimiters[index].signature);
102
+ const { memory } = delimiters[index];
83
103
  assert(memory.length > 0);
84
104
  if (memory.length === 1) {
85
105
  assert(index === delimiters.length - 1);
@@ -88,6 +108,7 @@ export class Delimiters {
88
108
  delimiters.pop();
89
109
  }
90
110
  else {
111
+ assert(false);
91
112
  memory.pop();
92
113
  delimiters[index] = memory.at(-1)!;
93
114
  }