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.
Files changed (52) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/design.md +2 -1
  3. package/dist/index.js +114 -90
  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 +79 -69
  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/context.ts +5 -6
  38. package/src/parser/inline/annotation.ts +3 -1
  39. package/src/parser/inline/autolink/hashnum.ts +5 -1
  40. package/src/parser/inline/bracket.ts +8 -4
  41. package/src/parser/inline/code.ts +2 -1
  42. package/src/parser/inline/extension/index.ts +3 -1
  43. package/src/parser/inline/extension/label.ts +1 -1
  44. package/src/parser/inline/extension/placeholder.ts +2 -1
  45. package/src/parser/inline/link.ts +5 -2
  46. package/src/parser/inline/media.ts +4 -2
  47. package/src/parser/inline/reference.ts +2 -1
  48. package/src/parser/inline/ruby.ts +4 -2
  49. package/src/parser/inline/template.ts +2 -1
  50. package/src/parser/util.ts +10 -10
  51. package/src/parser/visibility.ts +11 -11
  52. package/src/util/quote.ts +1 -1
@@ -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
- bstate?: number,
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
- bstate?: number,
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
- bstate?: number,
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
- bstate?: number,
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
- bstate: number = 0,
44
- ): Parser<T> {
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 lmr_ = source;
57
- if (lmr_ === '') return;
56
+ const sme_ = source;
57
+ if (sme_ === '') return;
58
58
  const { linebreak } = context;
59
59
  context.linebreak = undefined;
60
- const res1 = opener({ source: lmr_, context });
61
- assert(check(lmr_, res1, false));
62
- if (res1 === undefined) return void revert(context, linebreak);
63
- const rl = eval(res1);
64
- 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);
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 - mr_.length; ++i) {
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 - i - 1;
70
+ const pos = source.length - i + offset - 1;
71
+ assert(pos >= 0);
71
72
  if (!(pos in backtracks)) continue;
72
- // bracket only
73
- const shift = backtrack >>> 2 === state >>> 2 ? state & 3 : 0;
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: state = 0 } = context;
79
- context.backtrack = state | bstate;
80
- const res2 = mr_ !== '' ? parser({ source: mr_, context }) : undefined;
81
- assert(check(mr_, res2));
82
- context.backtrack = state;
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);
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 && rr === undefined) {
92
+ if (backtrack & 2 && nodesE === undefined) {
93
93
  const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
94
- // bracket only
95
- const shift = backtrack >>> 2 === state >>> 2 ? state & 3 : 0;
96
- backtracks[source.length + offset - 1] |= 1 << (backtrack >>> 2) + shift;
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
- lmr_.slice(0, lmr_.length - mr_.length),
101
- mr_.slice(0, mr_.length - r_.length),
102
- 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),
103
104
  ];
104
- const result = rr
105
+ const result = nodesE
105
106
  ? f
106
- ? f([rl, rm!, rr], rest, context)
107
- : [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]
108
109
  : g
109
- ? g([rl, rm!, mr_], rest, context)
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
- export function open<P extends Parser<unknown>>(opener: string | RegExp | Parser<Tree<P>, Context<P>>, parser: P, optional?: boolean): P;
140
- export function open<T>(opener: string | RegExp | Parser<T>, parser: Parser<T>, optional = false): Parser<T> {
141
- return surround(opener, parser, '', optional);
142
- }
143
- export function close<P extends Parser<unknown>>(parser: P, closer: string | RegExp | Parser<Tree<P>, Context<P>>, optional?: boolean): P;
144
- export function close<T>(parser: Parser<T>, closer: string | RegExp | Parser<T>, optional: boolean = false): Parser<T> {
145
- return surround('', parser, closer, optional);
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<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) =>