securemark 0.294.11 → 0.295.1

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 (37) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/design.md +5 -5
  3. package/dist/index.js +119 -119
  4. package/package.json +1 -1
  5. package/src/combinator/control/constraint/block.ts +1 -1
  6. package/src/combinator/control/constraint/contract.ts +5 -6
  7. package/src/combinator/control/constraint/line.ts +1 -2
  8. package/src/combinator/control/manipulation/convert.ts +1 -1
  9. package/src/combinator/control/manipulation/fallback.ts +1 -1
  10. package/src/combinator/control/manipulation/indent.ts +2 -2
  11. package/src/combinator/control/manipulation/lazy.ts +1 -1
  12. package/src/combinator/control/manipulation/match.ts +2 -5
  13. package/src/combinator/control/manipulation/recovery.ts +1 -1
  14. package/src/combinator/control/manipulation/reverse.ts +1 -1
  15. package/src/combinator/control/manipulation/scope.ts +3 -7
  16. package/src/combinator/control/manipulation/surround.ts +45 -56
  17. package/src/combinator/control/monad/bind.ts +7 -12
  18. package/src/combinator/control/monad/fmap.ts +4 -4
  19. package/src/combinator/data/parser/context.ts +12 -12
  20. package/src/combinator/data/parser/inits.ts +3 -6
  21. package/src/combinator/data/parser/sequence.ts +3 -6
  22. package/src/combinator/data/parser/some.ts +2 -2
  23. package/src/combinator/data/parser/subsequence.ts +1 -1
  24. package/src/combinator/data/parser/tails.ts +1 -1
  25. package/src/combinator/data/parser/union.ts +1 -1
  26. package/src/combinator/data/parser.ts +10 -9
  27. package/src/parser/context.ts +6 -6
  28. package/src/parser/inline/annotation.ts +1 -1
  29. package/src/parser/inline/autolink/account.ts +1 -1
  30. package/src/parser/inline/autolink/url.ts +4 -5
  31. package/src/parser/inline/bracket.ts +27 -18
  32. package/src/parser/inline/extension/indexee.ts +1 -1
  33. package/src/parser/inline/link.ts +3 -3
  34. package/src/parser/inline/media.ts +1 -1
  35. package/src/parser/inline/reference.ts +9 -9
  36. package/src/parser/inline/ruby.ts +2 -2
  37. package/src/parser/visibility.ts +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.294.11",
3
+ "version": "0.295.1",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -1,7 +1,7 @@
1
1
  import { Parser, failsafe } from '../../data/parser';
2
2
  import { isBlankline } from './line';
3
3
 
4
- export function block<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
4
+ export function block<P extends Parser>(parser: P, separation?: boolean): P;
5
5
  export function block<N>(parser: Parser<N>, separation = true): Parser<N> {
6
6
  assert(parser);
7
7
  return failsafe(input => {
@@ -1,13 +1,13 @@
1
1
  import { Parser, Input, List, Data, Ctx, Node, Context, failsafe } from '../../data/parser';
2
2
  import { matcher } from '../../../combinator';
3
3
 
4
- //export function contract<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
4
+ //export function contract<P extends Parser>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
5
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
- export function validate<P extends Parser<unknown>>(pattern: string | RegExp, parser: P): P;
10
- export function validate<P extends Parser<unknown>>(cond: ((input: Input<Context<P>>) => boolean), parser: P): P;
9
+ export function validate<P extends Parser>(pattern: string | RegExp, parser: P): P;
10
+ export function validate<P extends Parser>(cond: ((input: Input<Context<P>>) => boolean), parser: P): P;
11
11
  export function validate<N>(pattern: string | RegExp | ((input: Input<Ctx>) => boolean), parser: Parser<N>): Parser<N> {
12
12
  if (typeof pattern === 'function') return guard(pattern, parser);
13
13
  const match = matcher(pattern, false);
@@ -20,7 +20,7 @@ export function validate<N>(pattern: string | RegExp | ((input: Input<Ctx>) => b
20
20
  };
21
21
  }
22
22
 
23
- function guard<P extends Parser<unknown>>(f: (input: Input<Context<P>>) => boolean, parser: P): P;
23
+ function guard<P extends Parser>(f: (input: Input<Context<P>>) => boolean, parser: P): P;
24
24
  function guard<N>(f: (input: Input<Ctx>) => boolean, parser: Parser<N>): Parser<N> {
25
25
  return input =>
26
26
  f(input)
@@ -28,7 +28,7 @@ function guard<N>(f: (input: Input<Ctx>) => boolean, parser: Parser<N>): Parser<
28
28
  : undefined;
29
29
  }
30
30
 
31
- export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: List<Data<Node<P>>>, context: Context<P>) => boolean): P;
31
+ export function verify<P extends Parser>(parser: P, cond: (nodes: List<Data<Node<P>>>, context: Context<P>) => boolean): P;
32
32
  export function verify<N>(parser: Parser<N>, cond: (nodes: List<Data<N>>, context: Ctx) => boolean): Parser<N> {
33
33
  assert(parser);
34
34
  return failsafe(input => {
@@ -36,7 +36,6 @@ export function verify<N>(parser: Parser<N>, cond: (nodes: List<Data<N>>, contex
36
36
  const { source, position } = context;
37
37
  if (position === source.length) return;
38
38
  const result = parser(input);
39
- assert(context.position > position || !result);
40
39
  if (result && !cond(result, context)) return;
41
40
  return result;
42
41
  });
@@ -1,6 +1,6 @@
1
1
  import { Parser, input, failsafe } from '../../data/parser';
2
2
 
3
- export function line<P extends Parser<unknown>>(parser: P): P;
3
+ export function line<P extends Parser>(parser: P): P;
4
4
  export function line<N>(parser: Parser<N>): Parser<N> {
5
5
  assert(parser);
6
6
  return failsafe(({ context }) => {
@@ -12,7 +12,6 @@ export function line<N>(parser: Parser<N>): Parser<N> {
12
12
  const result = parser(input(line, context));
13
13
  context.position += position;
14
14
  context.position += result && context.position === position ? line.length : 0;
15
- assert(context.position > position || !result);
16
15
  context.source = source;
17
16
  context.offset -= position;
18
17
  if (result === undefined) return;
@@ -1,6 +1,6 @@
1
1
  import { Parser, List, Ctx, Context, subinput, failsafe } from '../../data/parser';
2
2
 
3
- export function convert<P extends Parser<unknown>>(conv: (source: string, context: Context<P>) => string, parser: P, empty?: boolean): P;
3
+ export function convert<P extends Parser>(conv: (source: string, context: Context<P>) => string, parser: P, empty?: boolean): P;
4
4
  export function convert<N>(conv: (source: string, context: Ctx) => string, parser: Parser<N>, empty = false): Parser<N> {
5
5
  assert(parser);
6
6
  return failsafe(input => {
@@ -1,7 +1,7 @@
1
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<Node<P>, Context<P>>): P;
4
+ export function fallback<P extends Parser>(parser: P, otherwise: Parser<Node<P>, Context<P>>): P;
5
5
  export function fallback<N>(parser: Parser<N>, otherwise: Parser<N>): Parser<N> {
6
6
  return union([parser, otherwise]);
7
7
  }
@@ -7,8 +7,8 @@ import { match } from './match';
7
7
  import { open } from './surround';
8
8
  import { memoize } from 'spica/memoize';
9
9
 
10
- export function indent<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
11
- export function indent<P extends Parser<unknown>>(opener: RegExp, parser: P, separation?: boolean): P;
10
+ export function indent<P extends Parser>(parser: P, separation?: boolean): P;
11
+ export function indent<P extends Parser>(opener: RegExp, parser: P, separation?: boolean): P;
12
12
  export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolean = false, separation = false): Parser<N> {
13
13
  if (typeof opener === 'function') {
14
14
  separation = parser as boolean;
@@ -1,6 +1,6 @@
1
1
  import { Parser } from '../../data/parser';
2
2
 
3
- export function lazy<P extends Parser<unknown>>(builder: () => P): P;
3
+ export function lazy<P extends Parser>(builder: () => P): P;
4
4
  export function lazy<N>(builder: () => Parser<N>): Parser<N> {
5
5
  let parser: Parser<N>;
6
6
  return input =>
@@ -1,7 +1,7 @@
1
1
  import { Parser, failsafe } from '../../data/parser';
2
2
  import { consume } from '../../../combinator';
3
3
 
4
- export function match<P extends Parser<unknown>>(pattern: RegExp, f: (matched: RegExpMatchArray) => P): P;
4
+ export function match<P extends Parser>(pattern: RegExp, f: (matched: RegExpMatchArray) => P): P;
5
5
  export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Parser<N>): Parser<N> {
6
6
  assert(!pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^'));
7
7
  const count = typeof pattern === 'object'
@@ -18,9 +18,6 @@ export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Pars
18
18
  count && consume(params[0].length, context);
19
19
  const result = f(params)(input);
20
20
  context.position += result && context.position === position ? params[0].length : 0;
21
- assert(context.position > position || !result);
22
- return context.position > position
23
- ? result
24
- : undefined;
21
+ return result;
25
22
  });
26
23
  }
@@ -1,6 +1,6 @@
1
1
  import { Parser, Input, Result, Ctx, 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<Node<P>>): P;
3
+ export function recover<P extends Parser>(parser: P, fallback: (input: Input<Context<P>>, reason: unknown) => Result<Node<P>>): P;
4
4
  export function recover<N>(parser: Parser<N>, fallback: (input: Input<Ctx>, reason: unknown) => Result<N>): Parser<N> {
5
5
  return input => {
6
6
  const { context } = input;
@@ -1,7 +1,7 @@
1
1
  import { Parser, List, Data } from '../../data/parser';
2
2
  import { fmap } from '../monad/fmap';
3
3
 
4
- export function reverse<P extends Parser<unknown>>(parser: P): P;
4
+ export function reverse<P extends Parser>(parser: P): P;
5
5
  export function reverse<N>(parser: Parser<N>): Parser<N> {
6
6
  return fmap(parser, nodes => nodes.foldr((node, acc) => acc.push(nodes.delete(node)) && acc, new List<Data<N>>()));
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { Parser, Context, input, failsafe } from '../../data/parser';
2
2
  import { matcher } from '../../../combinator';
3
3
 
4
- export function focus<P extends Parser<unknown>>(scope: string | RegExp, parser: P, slice?: boolean): P;
4
+ export function focus<P extends Parser>(scope: string | RegExp, parser: P, slice?: boolean): P;
5
5
  export function focus<N>(scope: string | RegExp, parser: Parser<N>, slice = true): Parser<N> {
6
6
  assert(parser);
7
7
  const match = matcher(scope, false);
@@ -16,7 +16,6 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>, slice = true
16
16
  if (!slice) {
17
17
  const result = parser(arg);
18
18
  context.position += result && context.position === position ? range : 0;
19
- assert(context.position > position || !result);
20
19
  return result;
21
20
  }
22
21
  context.offset ??= 0;
@@ -24,7 +23,6 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>, slice = true
24
23
  const result = parser(input(src, context));
25
24
  context.position += position;
26
25
  context.position += result && context.position === position ? src.length : 0;
27
- assert(context.position > position || !result);
28
26
  context.source = source;
29
27
  context.offset -= position;
30
28
  return result;
@@ -32,8 +30,8 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>, slice = true
32
30
  }
33
31
 
34
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>;
35
- export function rewrite<P extends Parser<unknown>>(scope: Parser<unknown, Context<P>>, parser: P, slice?: boolean): P;
36
- export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>, slice = true): Parser<N> {
33
+ export function rewrite<P extends Parser>(scope: Parser<unknown, Context<P>>, parser: P, slice?: boolean): P;
34
+ export function rewrite<N>(scope: Parser, parser: Parser<N>, slice = true): Parser<N> {
37
35
  assert(scope);
38
36
  assert(parser);
39
37
  return failsafe(arg => {
@@ -48,7 +46,6 @@ export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>, slice = tr
48
46
  context.position = position;
49
47
  const res2 = parser(arg);
50
48
  context.position += res2 && context.position === position ? range : 0;
51
- assert(context.position > position || !res2);
52
49
  return res2;
53
50
  }
54
51
  const src = source.slice(position, context.position);
@@ -59,7 +56,6 @@ export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>, slice = tr
59
56
  const res2 = parser(input(src, context));
60
57
  context.position += position;
61
58
  context.position += res2 && context.position === position ? src.length : 0;
62
- assert(context.position > position || !res2);
63
59
  context.source = source;
64
60
  context.offset -= position;
65
61
  return res2;
@@ -1,28 +1,28 @@
1
1
  import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, failsafe } from '../../data/parser';
2
2
  import { matcher, clear } from '../../../combinator';
3
3
 
4
- export function surround<P extends Parser<unknown>, S = string>(
4
+ export function surround<P extends Parser, S = string>(
5
5
  opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
6
6
  optional?: false,
7
7
  backtracks?: readonly number[],
8
8
  f?: (rss: [List<Data<S>>, List<Data<SubNode<P>>>, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
9
9
  g?: (rss: [List<Data<S>>, List<Data<SubNode<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
10
10
  ): P;
11
- export function surround<P extends Parser<unknown>, S = string>(
11
+ export function surround<P extends Parser, S = string>(
12
12
  opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
13
13
  optional?: boolean,
14
14
  backtracks?: readonly number[],
15
15
  f?: (rss: [List<Data<S>>, List<Data<SubNode<P>>> | undefined, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
16
16
  g?: (rss: [List<Data<S>>, List<Data<SubNode<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
17
17
  ): P;
18
- export function surround<P extends Parser<unknown>, S = string>(
18
+ export function surround<P extends Parser, S = string>(
19
19
  opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
20
20
  optional?: false,
21
21
  backtracks?: readonly number[],
22
22
  f?: (rss: [List<Data<S>>, List<Data<Node<P>>>, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
23
23
  g?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
24
24
  ): P;
25
- export function surround<P extends Parser<unknown>, S = string>(
25
+ export function surround<P extends Parser, S = string>(
26
26
  opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
27
27
  optional?: boolean,
28
28
  backtracks?: readonly number[],
@@ -68,6 +68,7 @@ export function surround<N>(
68
68
  closer = clear(matcher(closer, true));
69
69
  }
70
70
  assert(closer);
71
+ const [blen, rbs, wbs] = reduce(backtracks);
71
72
  return failsafe(input => {
72
73
  const { context } = input;
73
74
  const { source, position } = context;
@@ -75,26 +76,23 @@ export function surround<N>(
75
76
  const { linebreak } = context;
76
77
  context.linebreak = 0;
77
78
  const nodesO = opener(input);
78
- assert(context.position >= position);
79
79
  if (!nodesO) {
80
80
  return void revert(context, linebreak);
81
81
  }
82
- if (isBacktrack(context, backtracks, position, context.position - position || 1)) {
82
+ if (rbs && isBacktrack(context, rbs, position, blen)) {
83
83
  return void revert(context, linebreak);
84
84
  }
85
85
  const nodesM = context.position < source.length ? parser(input) : undefined;
86
- assert(context.position >= position);
87
86
  context.range = context.position - position;
88
87
  if (!nodesM && !optional) {
89
- setBacktrack(context, backtracks, position);
88
+ wbs && setBacktrack(context, wbs, position);
90
89
  const result = g?.([nodesO, nodesM], context);
91
90
  return result || void revert(context, linebreak);
92
91
  }
93
92
  const nodesC = nodesM || optional ? closer(input) : undefined;
94
- assert(context.position >= position);
95
93
  context.range = context.position - position;
96
94
  if (!nodesC) {
97
- setBacktrack(context, backtracks, position);
95
+ wbs && setBacktrack(context, wbs, position);
98
96
  const result = g?.([nodesO, nodesM], context);
99
97
  return result || void revert(context, linebreak);
100
98
  }
@@ -111,7 +109,7 @@ export function surround<N>(
111
109
  return result || void revert(context, linebreak);
112
110
  });
113
111
  }
114
- export function open<P extends Parser<unknown>>(
112
+ export function open<P extends Parser>(
115
113
  opener: string | RegExp | Parser<Node<P>, Context<P>>,
116
114
  parser: P,
117
115
  optional?: boolean,
@@ -127,11 +125,11 @@ export function open<N>(
127
125
  opener: string | RegExp | Parser<N, Ctx>,
128
126
  parser: string | RegExp | Parser<N>,
129
127
  optional?: boolean,
130
- backtracks?: readonly number[],
128
+ backtracks: readonly number[] = [],
131
129
  ): Parser<N> {
132
130
  return surround(opener, parser as Parser<N>, '', optional, backtracks);
133
131
  }
134
- export function close<P extends Parser<unknown>>(
132
+ export function close<P extends Parser>(
135
133
  parser: P,
136
134
  closer: string | RegExp | Parser<Node<P>, Context<P>>,
137
135
  optional?: boolean,
@@ -147,72 +145,63 @@ export function close<N>(
147
145
  parser: string | RegExp | Parser<N>,
148
146
  closer: string | RegExp | Parser<N, Ctx>,
149
147
  optional?: boolean,
150
- backtracks?: readonly number[],
148
+ backtracks: readonly number[] = [],
151
149
  ): Parser<N> {
152
150
  return surround('', parser as Parser<N>, closer, optional, backtracks);
153
151
  }
154
152
 
155
- const statesize = 2;
153
+ const commandsize = 2;
156
154
  export function isBacktrack(
157
155
  context: Ctx,
158
- backtracks: readonly number[],
156
+ backtrack: number,
159
157
  position: number = context.position,
160
158
  length: number = 1,
161
159
  ): boolean {
162
- const { source } = context;
163
- if (position === source.length) return false;
164
- if (length === 0) return false;
165
- for (const backtrack of backtracks) {
166
- if (backtrack & 1) {
167
- const { backtracks = {}, offset = 0 } = context;
168
- for (let i = 0; i < length; ++i) {
169
- if (position + i === source.length) break;
170
- if (source[position + i] !== source[position + 0]) break;
171
- const pos = position + i + offset;
172
- if (!(pos in backtracks)) continue;
173
- if (backtracks[pos] & 1 << size(backtrack >>> statesize)) return true;
174
- }
175
- }
160
+ assert(1 & backtrack);
161
+ assert(backtrack >>> commandsize);
162
+ assert(0 < length && length < 3);
163
+ const { backtracks = {}, offset = 0 } = context;
164
+ for (let i = 0; i < length; ++i) {
165
+ if (backtracks[position + i + offset] & backtrack >>> commandsize) return true;
176
166
  }
177
167
  return false;
178
168
  }
179
169
  export function setBacktrack(
180
170
  context: Ctx,
181
- backtracks: readonly number[],
171
+ backtrack: number,
182
172
  position: number,
183
173
  length: number = 1,
184
174
  ): void {
185
175
  // バックトラックの可能性がなく記録不要の場合もあるが判別が面倒なので省略
186
- const { source } = context;
187
- if (position === source.length) return;
188
- if (length === 0) return;
176
+ assert(2 & backtrack);
177
+ assert(backtrack >>> commandsize);
178
+ assert(0 < length && length < 3);
179
+ const { backtracks = {}, offset = 0 } = context;
180
+ for (let i = 0; i < length; ++i) {
181
+ backtracks[position + i + offset] |= backtrack >>> commandsize;
182
+ }
183
+ }
184
+ function reduce(backtracks: readonly number[]): readonly [number, number, number] {
185
+ let len = 1;
186
+ let rbs = 0;
187
+ let wbs = 0;
189
188
  for (const backtrack of backtracks) {
190
- if (backtrack & 2) {
191
- const { backtracks = {}, offset = 0 } = context;
192
- for (let i = 0; i < length; ++i) {
193
- if (position + i === source.length) break;
194
- const pos = position + i + offset;
195
- backtracks[pos] |= 1 << size(backtrack >>> statesize);
196
- }
189
+ if (backtrack >>> commandsize === 0) {
190
+ len = backtrack;
191
+ assert(len > 0);
192
+ continue;
193
+ }
194
+ assert(backtrack >>> commandsize);
195
+ if (1 & backtrack) {
196
+ rbs |= backtrack;
197
+ }
198
+ if (2 & backtrack) {
199
+ wbs |= backtrack;
197
200
  }
198
201
  }
202
+ return [len, rbs, wbs];
199
203
  }
200
204
 
201
205
  function revert(context: Ctx, linebreak: number | undefined): void {
202
206
  context.linebreak = linebreak;
203
207
  }
204
- function size(bits: number): number {
205
- if (bits === 0) return 0;
206
- let p = 0;
207
- for (let s = 32 / 2; s > 0; s >>>= 1) {
208
- const q = p + s;
209
- if (bits >>> q === 0) continue;
210
- p = q;
211
- }
212
- return p + 1;
213
- }
214
- assert(size(0 << 0) === 0);
215
- assert(size(1 << 0) === 1);
216
- assert(size(1 << 1) === 2);
217
- assert(size(1 << 30) === 31);
218
- assert(size(1 << 31) === 32);
@@ -1,23 +1,18 @@
1
1
  import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, failsafe } from '../../data/parser';
2
2
 
3
- export function bind<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: List<Data<SubNode<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
4
- export function bind<P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, 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: List<Data<N>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
6
- export function bind<U, P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => Result<U, Context<P>, SubParsers<P>>): Parser<U, Context<P>, SubParsers<P>>;
3
+ export function bind<P extends Parser>(parser: IntermediateParser<P>, f: (nodes: List<Data<SubNode<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
4
+ export function bind<P extends Parser>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
5
+ export function bind<N, P extends Parser>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: List<Data<N>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
6
+ export function bind<U, P extends Parser>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => Result<U, Context<P>, SubParsers<P>>): Parser<U, Context<P>, SubParsers<P>>;
7
7
  export function bind<N, U>(parser: Parser<N>, f: (nodes: List<Data<N>>, context: Ctx) => Result<U>): Parser<U> {
8
8
  assert(parser);
9
9
  return failsafe(input => {
10
10
  const { context } = input;
11
11
  const { source, position } = context;
12
12
  if (position === source.length) return;
13
- const res1 = parser(input);
14
- assert(context.position > position || !res1);
15
- if (res1 === undefined) return;
13
+ const result = parser(input);
14
+ if (result === undefined) return;
16
15
  context.range = context.position - position;
17
- const res2 = f(res1, context);
18
- assert(context.position > position || !res2);
19
- return context.position > position
20
- ? res2
21
- : undefined;
16
+ return f(result, context);
22
17
  });
23
18
  }
@@ -1,10 +1,10 @@
1
1
  import { Parser, List, Data, 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: List<Data<SubNode<P>>>, context: Context<P>) => List<Data<Node<P>>>): P;
5
- export function fmap<P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<Node<P>>>): P;
6
- export function fmap<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: List<Data<N>>, context: Context<P>) => List<Data<Node<P>>>): P;
7
- export function fmap<U, P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<U>>): Parser<U, Context<P>, SubParsers<P>>;
4
+ export function fmap<P extends Parser>(parser: IntermediateParser<P>, f: (nodes: List<Data<SubNode<P>>>, context: Context<P>) => List<Data<Node<P>>>): P;
5
+ export function fmap<P extends Parser>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<Node<P>>>): P;
6
+ export function fmap<N, P extends Parser>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: List<Data<N>>, context: Context<P>) => List<Data<Node<P>>>): P;
7
+ export function fmap<U, P extends Parser>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<U>>): Parser<U, Context<P>, SubParsers<P>>;
8
8
  export function fmap<N, U>(parser: Parser<N>, f: (nodes: List<Data<N>>, context: Ctx) => List<Data<U>>): Parser<U> {
9
9
  return bind(parser, (nodes, context) => f(nodes, context));
10
10
  }
@@ -2,7 +2,7 @@ import { min } from 'spica/alias';
2
2
  import { Parser, Result, List, Data, Ctx, CtxOptions, Node, Context } from '../../data/parser';
3
3
  import { clone } from 'spica/assign';
4
4
 
5
- export function reset<P extends Parser<unknown>>(base: CtxOptions, parser: P): P;
5
+ export function reset<P extends Parser>(base: CtxOptions, parser: P): P;
6
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));
@@ -13,7 +13,7 @@ export function reset<N>(base: Ctx, parser: Parser<N>): Parser<N> {
13
13
  apply(parser, { ...context }, changes, values, true);
14
14
  }
15
15
 
16
- export function context<P extends Parser<unknown>>(base: CtxOptions, parser: P): P;
16
+ export function context<P extends Parser>(base: CtxOptions, parser: P): P;
17
17
  export function context<N>(base: Ctx, parser: Parser<N>): Parser<N> {
18
18
  assert(Object.getPrototypeOf(base) === Object.prototype);
19
19
  assert(Object.freeze(base));
@@ -23,7 +23,7 @@ export function context<N>(base: Ctx, parser: Parser<N>): Parser<N> {
23
23
  apply(parser, context, changes, values);
24
24
  }
25
25
 
26
- function apply<P extends Parser<unknown>>(parser: P, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Node<P>>;
26
+ function apply<P extends Parser>(parser: P, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Node<P>>;
27
27
  function apply<N>(parser: Parser<N>, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<N> {
28
28
  for (let i = 0; i < changes.length; ++i) {
29
29
  const change = changes[i];
@@ -64,8 +64,8 @@ function apply<N>(parser: Parser<N>, context: Ctx, changes: readonly [string, un
64
64
  return result;
65
65
  }
66
66
 
67
- export function creation<P extends Parser<unknown>>(cost: number, parser: P): P;
68
- export function creation(cost: number, parser: Parser<unknown>): Parser<unknown> {
67
+ export function creation<P extends Parser>(cost: number, parser: P): P;
68
+ export function creation(cost: number, parser: Parser): Parser {
69
69
  assert(cost >= 0);
70
70
  return input => {
71
71
  const { context } = input;
@@ -85,8 +85,8 @@ export function consume(cost: number, context: Ctx): void {
85
85
  resources.clock -= cost;
86
86
  }
87
87
 
88
- export function recursion<P extends Parser<unknown>>(recursion: number, parser: P): P;
89
- export function recursion(recursion: number, parser: Parser<unknown>): Parser<unknown> {
88
+ export function recursion<P extends Parser>(recursion: number, parser: P): P;
89
+ export function recursion(recursion: number, parser: Parser): Parser {
90
90
  assert(recursion >= 0);
91
91
  return input => {
92
92
  const { context } = input;
@@ -102,7 +102,7 @@ export function recursion(recursion: number, parser: Parser<unknown>): Parser<un
102
102
  };
103
103
  }
104
104
 
105
- export function precedence<P extends Parser<unknown>>(precedence: number, parser: P): P;
105
+ export function precedence<P extends Parser>(precedence: number, parser: P): P;
106
106
  export function precedence<N>(precedence: number, parser: Parser<N>): Parser<N> {
107
107
  assert(precedence >= 0);
108
108
  return input => {
@@ -119,8 +119,8 @@ export function precedence<N>(precedence: number, parser: Parser<N>): Parser<N>
119
119
  };
120
120
  }
121
121
 
122
- export function state<P extends Parser<unknown>>(state: number, parser: P): P;
123
- export function state<P extends Parser<unknown>>(state: number, positive: boolean, parser: P): P;
122
+ export function state<P extends Parser>(state: number, parser: P): P;
123
+ export function state<P extends Parser>(state: number, positive: boolean, parser: P): P;
124
124
  export function state<N>(state: number, positive: boolean | Parser<N>, parser?: Parser<N>): Parser<N> {
125
125
  if (typeof positive === 'function') {
126
126
  parser = positive;
@@ -140,8 +140,8 @@ export function state<N>(state: number, positive: boolean | Parser<N>, parser?:
140
140
  };
141
141
  }
142
142
 
143
- export function constraint<P extends Parser<unknown>>(state: number, parser: P): P;
144
- //export function constraint<P extends Parser<unknown>>(state: number, positive: boolean, parser: P): P;
143
+ export function constraint<P extends Parser>(state: number, parser: P): P;
144
+ //export function constraint<P extends Parser>(state: number, positive: boolean, parser: P): P;
145
145
  export function constraint<N>(state: number, positive: boolean | Parser<N>, parser?: Parser<N>): Parser<N> {
146
146
  if (typeof positive === 'function') {
147
147
  parser = positive;
@@ -1,12 +1,12 @@
1
1
  import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
 
3
- export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
3
+ export function inits<P extends Parser>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
4
4
  export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
5
5
  assert(parsers.every(f => f));
6
6
  if (parsers.length === 1) return parsers[0];
7
7
  return input => {
8
8
  const { context } = input;
9
- const { source, position } = context;
9
+ const { source } = context;
10
10
  let nodes: List<Data<N>> | undefined;
11
11
  for (let len = parsers.length, i = 0; i < len; ++i) {
12
12
  if (context.position === source.length) break;
@@ -16,9 +16,6 @@ export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: Lis
16
16
  nodes = nodes?.import(result) ?? result;
17
17
  if (resume?.(result) === false) break;
18
18
  }
19
- assert(context.position >= position);
20
- return context.position > position
21
- ? nodes
22
- : undefined;
19
+ return nodes;
23
20
  };
24
21
  }
@@ -1,12 +1,12 @@
1
1
  import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
 
3
- export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
3
+ export function sequence<P extends Parser>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
4
4
  export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
5
5
  assert(parsers.every(f => f));
6
6
  if (parsers.length === 1) return parsers[0];
7
7
  return input => {
8
8
  const { context } = input;
9
- const { source, position } = context;
9
+ const { source } = context;
10
10
  let nodes: List<Data<N>> | undefined;
11
11
  for (let len = parsers.length, i = 0; i < len; ++i) {
12
12
  if (context.position === source.length) return;
@@ -16,9 +16,6 @@ export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes:
16
16
  nodes = nodes?.import(result) ?? result;
17
17
  if (resume?.(result) === false) return;
18
18
  }
19
- assert(context.position >= position);
20
- return context.position > position
21
- ? nodes
22
- : undefined;
19
+ return nodes;
23
20
  };
24
21
  }
@@ -3,8 +3,8 @@ import { Delimiters } from './context/delimiter';
3
3
 
4
4
  type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
5
5
 
6
- export function some<P extends Parser<unknown>>(parser: P, limit?: number): P;
7
- export function some<P extends Parser<unknown>>(parser: P, end?: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
6
+ export function some<P extends Parser>(parser: P, limit?: number): P;
7
+ export function some<P extends Parser>(parser: P, end?: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
8
8
  export function some<N>(parser: Parser<N>, end?: string | RegExp | number, delimiters: readonly DelimiterOption[] = [], limit = -1): Parser<N> {
9
9
  if (typeof end === 'number') return some(parser, undefined, delimiters, end);
10
10
  assert(parser);
@@ -2,7 +2,7 @@ import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../
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: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
5
+ export function subsequence<P extends Parser>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
6
6
  export function subsequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
7
7
  assert(parsers.every(f => f));
8
8
  return union(
@@ -2,7 +2,7 @@ import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../
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: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
5
+ export function tails<P extends Parser>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
6
6
  export function tails<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, Ctx, D> {
7
7
  return union(parsers.map((_, i) => sequence(parsers.slice(i), resume)) as D);
8
8
  }