securemark 0.294.0 → 0.294.2

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 (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/design.md +27 -39
  3. package/dist/index.js +208 -180
  4. package/package.json +2 -2
  5. package/src/combinator/control/constraint/contract.ts +2 -2
  6. package/src/combinator/control/constraint/line.ts +2 -2
  7. package/src/combinator/control/manipulation/clear.ts +2 -2
  8. package/src/combinator/control/manipulation/indent.ts +3 -7
  9. package/src/combinator/control/manipulation/lazy.ts +1 -3
  10. package/src/combinator/control/manipulation/scope.ts +4 -6
  11. package/src/combinator/control/manipulation/surround.ts +5 -8
  12. package/src/combinator/control/monad/bind.ts +2 -3
  13. package/src/combinator/data/data.ts +38 -32
  14. package/src/combinator/data/parser/context.test.ts +4 -4
  15. package/src/combinator/data/parser/inits.ts +6 -8
  16. package/src/combinator/data/parser/sequence.test.ts +2 -2
  17. package/src/combinator/data/parser/sequence.ts +5 -7
  18. package/src/combinator/data/parser/some.test.ts +2 -2
  19. package/src/combinator/data/parser/some.ts +5 -7
  20. package/src/combinator/data/parser/subsequence.test.ts +2 -2
  21. package/src/combinator/data/parser/subsequence.ts +2 -2
  22. package/src/combinator/data/parser/tails.ts +2 -2
  23. package/src/combinator/data/parser/union.test.ts +2 -2
  24. package/src/combinator/data/parser/union.ts +2 -2
  25. package/src/combinator/data/parser.ts +36 -39
  26. package/src/debug.test.ts +2 -2
  27. package/src/parser/api/bind.ts +6 -6
  28. package/src/parser/api/header.ts +2 -2
  29. package/src/parser/api/normalize.ts +2 -2
  30. package/src/parser/api/parse.ts +11 -11
  31. package/src/parser/block/codeblock.ts +2 -2
  32. package/src/parser/block/extension/example.ts +2 -2
  33. package/src/parser/block/extension/figure.ts +1 -1
  34. package/src/parser/block/extension/message.ts +2 -2
  35. package/src/parser/block/extension/table.ts +2 -2
  36. package/src/parser/block.ts +5 -1
  37. package/src/parser/inline/autolink/url.test.ts +71 -72
  38. package/src/parser/inline/autolink/url.ts +4 -4
  39. package/src/parser/inline/emstrong.ts +5 -5
  40. package/src/parser/inline/reference.ts +2 -2
  41. package/src/parser/inline/ruby.ts +4 -4
  42. package/src/parser/processor/note.ts +2 -2
  43. package/src/parser/segment.ts +6 -12
  44. package/src/parser/source/line.ts +5 -0
  45. package/src/parser/source/str.ts +1 -1
  46. package/src/parser/util.ts +5 -4
  47. 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.0",
3
+ "version": "0.294.2",
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",
@@ -28,7 +28,7 @@
28
28
  "LICENSE"
29
29
  ],
30
30
  "dependencies": {
31
- "spica": "0.0.807"
31
+ "spica": "0.0.809"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/dompurify": "3.0.5",
@@ -1,4 +1,4 @@
1
- import { Parser, Input, List, Data, Ctx, Node, Context, eval, failsafe } from '../../data/parser';
1
+ import { Parser, Input, List, Data, Ctx, Node, Context, failsafe } from '../../data/parser';
2
2
  import { matcher } from '../../../combinator';
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;
@@ -37,7 +37,7 @@ export function verify<N>(parser: Parser<N>, cond: (nodes: List<Data<N>>, contex
37
37
  if (position === source.length) return;
38
38
  const result = parser(input);
39
39
  assert(context.position > position || !result);
40
- if (result && !cond(eval(result), context)) return;
40
+ if (result && !cond(result, context)) return;
41
41
  return result;
42
42
  });
43
43
  }
@@ -1,4 +1,4 @@
1
- import { Parser, input, eval, failsafe } from '../../data/parser';
1
+ import { Parser, input, failsafe } from '../../data/parser';
2
2
 
3
3
  export function line<P extends Parser<unknown>>(parser: P): P;
4
4
  export function line<N>(parser: Parser<N>): Parser<N> {
@@ -18,7 +18,7 @@ export function line<N>(parser: Parser<N>): Parser<N> {
18
18
  if (result === undefined) return;
19
19
  if (!isBlank(source.slice(context.position, position + line.length))) return;
20
20
  context.position = position + line.length;
21
- return eval(result);
21
+ return result;
22
22
  });
23
23
  }
24
24
 
@@ -1,5 +1,5 @@
1
- import { Parser, List, CtxOptions } from '../../data/parser';
1
+ import { Parser, List, Ctx } from '../../data/parser';
2
2
 
3
- export function clear<D extends Parser<unknown, C>[], C extends CtxOptions>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
3
+ export function clear<D extends Parser<unknown, C>[], C extends Ctx>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
4
4
  return input => parser(input) && new List();
5
5
  }
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, subinput, eval, failsafe } from '../../data/parser';
1
+ import { Parser, List, Data, subinput, failsafe } from '../../data/parser';
2
2
  import { some } from '../../data/parser/some';
3
3
  import { block } from '../constraint/block';
4
4
  import { line } from '../constraint/line';
@@ -26,14 +26,10 @@ export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolea
26
26
  context.position = source.length;
27
27
  return new List([new Data(source.slice(position))]);
28
28
  }))),
29
- ([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
29
+ ([indent]) => indent.length <= 16 ? indent.length * 2 + +(indent[0] === ' ') : -1, [])), separation),
30
30
  (lines, context) => {
31
31
  assert(parser = parser as Parser<N>);
32
- const result = parser(subinput(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context));
33
- assert(result);
34
- return result
35
- ? eval(result)
36
- : undefined;
32
+ return parser(subinput(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context));
37
33
  }));
38
34
  }
39
35
 
@@ -4,7 +4,5 @@ export function lazy<P extends Parser<unknown>>(builder: () => P): P;
4
4
  export function lazy<N>(builder: () => Parser<N>): Parser<N> {
5
5
  let parser: Parser<N>;
6
6
  return input =>
7
- parser !== undefined
8
- ? parser(input)
9
- : (parser = builder())(input);
7
+ (parser ??= builder())(input);
10
8
  }
@@ -1,4 +1,4 @@
1
- import { Parser, Context, input, eval, failsafe } from '../../data/parser';
1
+ import { Parser, Context, input, failsafe } from '../../data/parser';
2
2
  import { matcher } from '../../../combinator';
3
3
 
4
4
  export function focus<P extends Parser<unknown>>(scope: string | RegExp, parser: P): P;
@@ -8,7 +8,7 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>): Parser<N> {
8
8
  return failsafe(({ context }) => {
9
9
  const { source, position } = context;
10
10
  if (position === source.length) return;
11
- const src = eval(match({ context }))?.head?.value ?? '';
11
+ const src = match({ context })?.head?.value ?? '';
12
12
  assert(source.startsWith(src, position));
13
13
  if (src === '') return;
14
14
  context.range = src.length;
@@ -20,8 +20,7 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>): Parser<N> {
20
20
  assert(context.position > position || !result);
21
21
  context.source = source;
22
22
  context.offset -= position;
23
- if (result === undefined) return;
24
- return eval(result);
23
+ return result;
25
24
  });
26
25
  }
27
26
 
@@ -47,7 +46,6 @@ export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>): Parser<N>
47
46
  assert(context.position > position || !res2);
48
47
  context.source = source;
49
48
  context.offset -= position;
50
- if (res2 === undefined) return;
51
- return eval(res2);
49
+ return res2;
52
50
  });
53
51
  }
@@ -1,4 +1,4 @@
1
- import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, failsafe } from '../../data/parser';
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
4
  export function surround<P extends Parser<unknown>, S = string>(
@@ -52,29 +52,26 @@ export function surround<N>(
52
52
  if (position === source.length) return;
53
53
  const { linebreak } = context;
54
54
  context.linebreak = 0;
55
- const resultO = opener(input);
55
+ const nodesO = opener(input);
56
56
  assert(context.position >= position);
57
- const nodesO = eval(resultO);
58
57
  if (!nodesO) {
59
58
  return void revert(context, linebreak);
60
59
  }
61
60
  if (isBacktrack(context, backtracks, position, context.position - position || 1)) {
62
61
  return void revert(context, linebreak);
63
62
  }
64
- const resultM = context.position < source.length ? parser(input) : undefined;
63
+ const nodesM = context.position < source.length ? parser(input) : undefined;
65
64
  assert(context.position >= position);
66
65
  context.range = context.position - position;
67
- const nodesM = eval(resultM);
68
- if (!resultM && !optional) {
66
+ if (!nodesM && !optional) {
69
67
  setBacktrack(context, backtracks, position);
70
68
  const result = g?.([nodesO, nodesM], context);
71
69
  revert(context, linebreak);
72
70
  return result;
73
71
  }
74
- const resultC = resultM || optional ? closer(input) : undefined;
72
+ const nodesC = nodesM || optional ? closer(input) : undefined;
75
73
  assert(context.position >= position);
76
74
  context.range = context.position - position;
77
- const nodesC = eval(resultC);
78
75
  if (!nodesC) {
79
76
  setBacktrack(context, backtracks, position);
80
77
  const result = g?.([nodesO, nodesM], context);
@@ -1,4 +1,4 @@
1
- import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, failsafe } from '../../data/parser';
1
+ import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, failsafe } from '../../data/parser';
2
2
 
3
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
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;
@@ -14,9 +14,8 @@ export function bind<N, U>(parser: Parser<N>, f: (nodes: List<Data<N>>, context:
14
14
  assert(context.position > position || !res1);
15
15
  if (res1 === undefined) return;
16
16
  context.range = context.position - position;
17
- const res2 = f(eval(res1), context);
17
+ const res2 = f(res1, context);
18
18
  assert(context.position > position || !res2);
19
- if (res2 === undefined) return;
20
19
  return context.position > position
21
20
  ? res2
22
21
  : undefined;
@@ -1,6 +1,6 @@
1
- // Memory-efficient flexible list.
1
+ import { Parser, Ctx } from './parser';
2
2
 
3
- export class List<N extends List.Node = List.Node> {
3
+ export class List<N extends List.Node = List.Node, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any> {
4
4
  constructor(nodes?: ArrayLike<N>) {
5
5
  if (nodes === undefined) return;
6
6
  for (let i = 0; i < nodes.length; ++i) {
@@ -9,47 +9,55 @@ export class List<N extends List.Node = List.Node> {
9
9
  }
10
10
  public length = 0;
11
11
  public head?: N = undefined;
12
+ public last?: N = undefined;
12
13
  public get tail(): N | undefined {
13
14
  return this.head?.next;
14
15
  }
15
- public get last(): N | undefined {
16
- return this.head?.prev;
17
- }
18
16
  public insert(node: N, before?: N): N {
19
- assert(!node.next);
17
+ assert(!node.next && !node.prev);
18
+ if (before === undefined) return this.push(node);
19
+ if (before === this.head) return this.unshift(node);
20
20
  if (++this.length === 1) {
21
- return this.head = node.next = node.prev = node;
21
+ return this.head = this.last = node;
22
22
  }
23
23
  assert(node !== before);
24
- const next = node.next = before ?? this.head!;
24
+ const next = node.next = before;
25
25
  const prev = node.prev = next.prev!;
26
26
  return next.prev = prev.next = node;
27
27
  }
28
28
  public delete(node: N): N {
29
- assert(node.next);
29
+ assert(node.next || node.prev || this.head === this.last);
30
30
  assert(this.length > 0);
31
31
  if (--this.length === 0) {
32
- this.head = undefined;
32
+ this.head = this.last = undefined;
33
33
  }
34
34
  else {
35
35
  const { next, prev } = node;
36
- if (node === this.head) {
37
- this.head = next;
38
- }
39
- // Error if not used.
40
- prev!.next = next;
41
- next!.prev = prev;
36
+ prev === undefined
37
+ ? this.head = next
38
+ : prev.next = next;
39
+ next === undefined
40
+ ? this.last = prev
41
+ : next.prev = prev;
42
42
  }
43
43
  node.next = node.prev = undefined;
44
44
  return node;
45
45
  }
46
46
  public unshift(node: N): N {
47
- assert(!node.next);
48
- return this.head = this.insert(node, this.head);
47
+ assert(!node.next && !node.prev);
48
+ if (++this.length === 1) {
49
+ return this.head = this.last = node;
50
+ }
51
+ node.next = this.head;
52
+ return this.head = this.head!.prev = node;
49
53
  }
50
54
  public push(node: N): N {
51
- assert(!node.next);
52
- return this.insert(node, this.head);
55
+ assert(!node.next && !node.prev);
56
+ if (++this.length === 1) {
57
+ return this.head = this.last = node;
58
+ }
59
+ node.prev = this.last;
60
+ return this.last = this.last!.next = node;
53
61
  }
54
62
  public shift(): N | undefined {
55
63
  if (this.length === 0) return;
@@ -57,22 +65,25 @@ export class List<N extends List.Node = List.Node> {
57
65
  }
58
66
  public pop(): N | undefined {
59
67
  if (this.length === 0) return;
60
- return this.delete(this.head!.prev!);
68
+ return this.delete(this.last!);
61
69
  }
62
70
  public import(list: List<N>, before?: N): this {
63
71
  assert(list !== this);
64
72
  if (list.length === 0) return this;
65
73
  if (this.length === 0) {
66
74
  this.head = list.head;
67
- this.length += list.length;
75
+ this.last = list.last;
76
+ this.length = list.length;
68
77
  list.clear();
69
78
  return this;
70
79
  }
71
80
  const head = list.head!;
72
81
  const last = list.last!;
73
- const next = last.next = before ?? this.head!;
74
- const prev = head.prev = next.prev!;
75
- next.prev = last;
82
+ const next = last.next = before;
83
+ const prev = head.prev = before?.prev ?? this.last!;
84
+ next === undefined
85
+ ? this.last = last
86
+ : next.prev = last;
76
87
  prev.next = head;
77
88
  this.length += list.length;
78
89
  list.clear();
@@ -80,14 +91,13 @@ export class List<N extends List.Node = List.Node> {
80
91
  }
81
92
  public clear(): void {
82
93
  this.length = 0;
83
- this.head = undefined;
94
+ this.head = this.last = undefined;
84
95
  }
85
96
  public *[Symbol.iterator](): Iterator<N, undefined, undefined> {
86
97
  for (let node = this.head; node && this.head;) {
87
98
  const next = node.next;
88
99
  yield node;
89
100
  node = next;
90
- if (node === this.head) break;
91
101
  }
92
102
  }
93
103
  public flatMap<T extends List.Node>(f: (node: N) => List<T>): List<T> {
@@ -96,7 +106,6 @@ export class List<N extends List.Node = List.Node> {
96
106
  const next = node.next;
97
107
  acc.import(f(node));
98
108
  node = next;
99
- if (node === this.head) break;
100
109
  }
101
110
  return acc;
102
111
  }
@@ -105,15 +114,13 @@ export class List<N extends List.Node = List.Node> {
105
114
  const next = node.next;
106
115
  acc = f(acc, node);
107
116
  node = next;
108
- if (node === this.head) break;
109
117
  }
110
118
  return acc;
111
119
  }
112
120
  public foldr<T>(f: (node: N, acc: T) => T, acc: T): T {
113
- for (let node = this.head?.prev; node && this.head;) {
121
+ for (let node = this.last; node && this.head;) {
114
122
  const prev = node.prev;
115
123
  acc = f(node, acc);
116
- if (node === this.head) break;
117
124
  node = prev;
118
125
  }
119
126
  return acc;
@@ -123,7 +130,6 @@ export class List<N extends List.Node = List.Node> {
123
130
  const next = node.next;
124
131
  if (f(node)) return node;
125
132
  node = next;
126
- if (node === this.head) break;
127
133
  }
128
134
  }
129
135
  }
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, Ctx, CtxOptions, input, eval } from '../parser';
1
+ import { Parser, List, Data, Ctx, CtxOptions, input } from '../parser';
2
2
  import { some } from './some';
3
3
  import { reset, context, creation } from './context';
4
4
  import { unwrap } from '../../../parser/util';
@@ -18,7 +18,7 @@ describe('Unit: combinator/data/parser/context', () => {
18
18
  it('root', () => {
19
19
  const base: Context = { resources: { clock: 3, recursions: [1] } };
20
20
  const ctx: Context = {};
21
- assert.deepStrictEqual([...unwrap(eval(reset(base, parser)(input('123', ctx)))!)], [3, 2, 1]);
21
+ assert.deepStrictEqual([...unwrap(reset(base, parser)(input('123', ctx))!)], [3, 2, 1]);
22
22
  assert(base.resources?.clock === 3);
23
23
  assert(ctx.resources?.clock === undefined);
24
24
  assert.throws(() => reset(base, parser)(input('1234', ctx)));
@@ -28,7 +28,7 @@ describe('Unit: combinator/data/parser/context', () => {
28
28
  it('node', () => {
29
29
  const base: Context = { resources: { clock: 3, recursions: [1] } };
30
30
  const ctx: Context = { resources: { clock: 2, recursions: [1] } };
31
- assert.deepStrictEqual([...unwrap(eval(reset(base, parser)(input('1', ctx)))!)], [2]);
31
+ assert.deepStrictEqual([...unwrap(reset(base, parser)(input('1', ctx))!)], [2]);
32
32
  assert(base.resources?.clock === 3);
33
33
  assert(ctx.resources?.clock === 1);
34
34
  assert.throws(() => reset(base, parser)(input('12', ctx)));
@@ -47,7 +47,7 @@ describe('Unit: combinator/data/parser/context', () => {
47
47
  it('', () => {
48
48
  const base: Context = { status: true };
49
49
  const ctx: Context = { resources: { clock: 2, recursions: [1] } };
50
- assert.deepStrictEqual([...unwrap(eval(context(base, parser)(input('1', ctx)))!)], [true]);
50
+ assert.deepStrictEqual([...unwrap(context(base, parser)(input('1', ctx))!)], [true]);
51
51
  assert(base.resources?.clock === undefined);
52
52
  assert(ctx.resources?.clock === 1);
53
53
  assert(ctx.status === undefined);
@@ -1,7 +1,7 @@
1
- import { Parser, List, Data, CtxOptions, Node, Context, SubParsers, SubNode, eval, Ctx } from '../parser';
1
+ import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
 
3
- export function inits<P extends Parser<unknown, Ctx>>(parsers: SubParsers<P>, resume?: (nodes: List<Data<SubNode<P>>>) => boolean): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
4
- export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, CtxOptions, D> {
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>>;
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 => {
@@ -13,13 +13,11 @@ export function inits<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: Lis
13
13
  if (context.delimiters?.match(input)) break;
14
14
  const result = parsers[i](input);
15
15
  if (result === undefined) break;
16
- nodes = nodes
17
- ? nodes.import(eval(result))
18
- : eval(result);
19
- if (resume?.(eval(result)) === false) break;
16
+ nodes = nodes?.import(result) ?? result;
17
+ if (resume?.(result) === false) break;
20
18
  }
21
19
  assert(context.position >= position);
22
- return nodes && context.position > position
20
+ return context.position > position
23
21
  ? nodes
24
22
  : undefined;
25
23
  };
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, input } from '../parser';
1
+ import { Parser, List, Data, Ctx, input } from '../parser';
2
2
  import { sequence } from './sequence';
3
3
  import { inspect } from '../../../debug.test';
4
4
 
@@ -14,7 +14,7 @@ describe('Unit: combinator/data/parser/sequence', () => {
14
14
  ? void ++context.position || new List([new Data('B')])
15
15
  : undefined;
16
16
  };
17
- const ab = sequence<Parser<string, {}, [typeof a, typeof b]>>([a, b]);
17
+ const ab = sequence<Parser<string, Ctx, [typeof a, typeof b]>>([a, b]);
18
18
  const { context: ctx } = input('', {});
19
19
 
20
20
  it('basic', () => {
@@ -1,7 +1,7 @@
1
- import { Parser, List, Data, CtxOptions, Node, Context, SubParsers, SubNode, eval } from '../parser';
1
+ import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
 
3
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>>;
4
- export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, CtxOptions, D> {
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 => {
@@ -13,13 +13,11 @@ export function sequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes:
13
13
  if (context.delimiters?.match(input)) return;
14
14
  const result = parsers[i](input);
15
15
  if (result === undefined) return;
16
- nodes = nodes
17
- ? nodes.import(eval(result))
18
- : eval(result);
19
- if (resume?.(eval(result)) === false) return;
16
+ nodes = nodes?.import(result) ?? result;
17
+ if (resume?.(result) === false) return;
20
18
  }
21
19
  assert(context.position >= position);
22
- return nodes && context.position > position
20
+ return context.position > position
23
21
  ? nodes
24
22
  : undefined;
25
23
  };
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, input } from '../parser';
1
+ import { Parser, List, Data, Ctx, input } from '../parser';
2
2
  import { union } from './union';
3
3
  import { some } from './some';
4
4
  import { inspect } from '../../../debug.test';
@@ -15,7 +15,7 @@ describe('Unit: combinator/data/parser/some', () => {
15
15
  ? void ++context.position || new List([new Data('B')])
16
16
  : undefined;
17
17
  };
18
- const ab = union<Parser<string, {}, [typeof a, typeof b]>>([a, b]);
18
+ const ab = union<Parser<string, Ctx, [typeof a, typeof b]>>([a, b]);
19
19
  const { context: ctx } = input('', {});
20
20
 
21
21
  it('basic', () => {
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, eval } from '../parser';
1
+ import { Parser, List, Data } from '../parser';
2
2
  import { Delimiters } from './context/delimiter';
3
3
 
4
4
  type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
@@ -23,22 +23,20 @@ export function some<N>(parser: Parser<N>, end?: string | RegExp | number, delim
23
23
  context.delimiters ??= new Delimiters();
24
24
  context.delimiters.push(delims);
25
25
  }
26
- while (true) {
27
- if (context.position === source.length) break;
26
+ // whileは数倍遅い
27
+ for (; context.position < source.length;) {
28
28
  if (match(input)) break;
29
29
  if (context.delimiters?.match(input)) break;
30
30
  const result = parser(input);
31
31
  if (result === undefined) break;
32
- nodes = nodes
33
- ? nodes.import(eval(result))
34
- : eval(result);
32
+ nodes = nodes?.import(result) ?? result;
35
33
  if (limit >= 0 && context.position - position > limit) break;
36
34
  }
37
35
  if (delims.length > 0) {
38
36
  context.delimiters!.pop(delims.length);
39
37
  }
40
38
  assert(context.position >= position);
41
- return nodes && context.position > position
39
+ return context.position > position
42
40
  ? nodes
43
41
  : undefined;
44
42
  };
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, input } from '../parser';
1
+ import { Parser, List, Data, Ctx, input } from '../parser';
2
2
  import { subsequence } from './subsequence';
3
3
  import { inspect } from '../../../debug.test';
4
4
 
@@ -19,7 +19,7 @@ describe('Unit: combinator/data/parser/subsequence', () => {
19
19
  ? void ++context.position || new List([new Data('C')])
20
20
  : undefined;
21
21
  };
22
- const abc = subsequence<Parser<string, {}, [typeof a, typeof b, typeof c]>>([a, b, c]);
22
+ const abc = subsequence<Parser<string, Ctx, [typeof a, typeof b, typeof c]>>([a, b, c]);
23
23
  const { context: ctx } = input('', {});
24
24
 
25
25
  it('basic', () => {
@@ -1,9 +1,9 @@
1
- import { Parser, List, Data, CtxOptions, Node, Context, SubParsers, SubNode } from '../parser';
1
+ import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
  import { union } from './union';
3
3
  import { inits } from './inits';
4
4
 
5
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>>;
6
- export function subsequence<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, CtxOptions, D> {
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(
9
9
  parsers.map((_, i) =>
@@ -1,8 +1,8 @@
1
- import { Parser, List, Data, CtxOptions, Node, Context, SubParsers, SubNode } from '../parser';
1
+ import { Parser, List, Data, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
  import { union } from './union';
3
3
  import { sequence } from './sequence';
4
4
 
5
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>>;
6
- export function tails<N, D extends Parser<N>[]>(parsers: D, resume?: (nodes: List<Data<N>>) => boolean): Parser<N, CtxOptions, D> {
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
  }
@@ -1,4 +1,4 @@
1
- import { Parser, List, Data, input } from '../parser';
1
+ import { Parser, List, Data, Ctx, input } from '../parser';
2
2
  import { union } from './union';
3
3
  import { inspect } from '../../../debug.test';
4
4
 
@@ -14,7 +14,7 @@ describe('Unit: combinator/data/parser/union', () => {
14
14
  ? void ++context.position || new List([new Data('B')])
15
15
  : undefined;
16
16
  };
17
- const ab = union<Parser<string, {}, [typeof a, typeof b]>>([a, b]);
17
+ const ab = union<Parser<string, Ctx, [typeof a, typeof b]>>([a, b]);
18
18
  const { context: ctx } = input('', {});
19
19
 
20
20
  it('basic', () => {
@@ -1,7 +1,7 @@
1
- import { Parser, CtxOptions, Node, Context, SubParsers, SubNode } from '../parser';
1
+ import { Parser, Ctx, Node, Context, SubParsers, SubNode } from '../parser';
2
2
 
3
3
  export function union<P extends Parser<unknown>>(parsers: SubParsers<P>): SubNode<P> extends Node<P> ? P : Parser<SubNode<P>, Context<P>, SubParsers<P>>;
4
- export function union<N, D extends Parser<N>[]>(parsers: D): Parser<N, CtxOptions, D> {
4
+ export function union<N, D extends Parser<N>[]>(parsers: D): Parser<N, Ctx, D> {
5
5
  assert(parsers.every(f => f));
6
6
  switch (parsers.length) {
7
7
  case 0: