tarsec 0.4.0 → 0.4.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.
@@ -82,6 +82,28 @@ export declare function optional<T>(parser: Parser<T>): Parser<T | null>;
82
82
  * If it succeeds, returns a failure.
83
83
  */
84
84
  export declare function not(parser: Parser<any>): Parser<null>;
85
+ /**
86
+ * Positive lookahead. Runs the given parser without consuming any input.
87
+ * On success, returns the parser's result with `rest` set to the original input.
88
+ * On failure, returns the underlying failure (also with `rest` reset to the original input).
89
+ *
90
+ * Useful for disambiguating alternatives without backtracking:
91
+ *
92
+ * ```ts
93
+ * const parser = or(
94
+ * seqR(peek(str("hello!")), str("hello!")),
95
+ * str("hello"),
96
+ * );
97
+ * ```
98
+ *
99
+ * The `peek` decides which branch to commit to; the real parser then consumes.
100
+ * Captures are preserved when the inner parser is a `CaptureParser`.
101
+ *
102
+ * @param parser - parser to look ahead with
103
+ * @returns - a parser that runs the given parser without consuming input
104
+ */
105
+ export declare function peek<T>(parser: Parser<T>): Parser<T>;
106
+ export declare function peek<T, C extends PlainObject>(parser: CaptureParser<T, C>): CaptureParser<T, C>;
85
107
  /**
86
108
  * Takes three parsers, `open`, `close`, and `parser`.
87
109
  * `between` matches multiple instances of `parser`,
@@ -475,3 +497,21 @@ export type OperatorInfo<T> = {
475
497
  * @returns - a parser that handles the full expression grammar
476
498
  */
477
499
  export declare function buildExpressionParser<T>(atom: Parser<T>, operatorTable: OperatorInfo<T>[][], parenParser?: Parser<T>): Parser<T>;
500
+ /**
501
+ * Wraps a parser with a per-input cache. Useful for parsers that may be invoked
502
+ * many times at the same position (e.g. recursive grammars where the same
503
+ * sub-parser is consulted from multiple alternatives).
504
+ *
505
+ * Both successes and failures are cached. The cache is keyed by the input
506
+ * string the parser is called with — because the rest passed between parsers
507
+ * is value-equal across paths, identical sub-parses share a cache entry.
508
+ *
509
+ * `memo` assumes its wrapped parser is a pure function of its input. Don't
510
+ * memoize parsers that consult mutable external state.
511
+ *
512
+ * @param name - optional debug name (shown in `parserDebug` counts/times as `memo(name)`)
513
+ * @param parser - parser to memoize
514
+ * @returns - memoized parser
515
+ */
516
+ export declare function memo<T>(name: string, parser: Parser<T>): Parser<T>;
517
+ export declare function memo<T, C extends PlainObject>(name: string, parser: CaptureParser<T, C>): CaptureParser<T, C>;
@@ -202,6 +202,15 @@ export function not(parser) {
202
202
  return success(null, input);
203
203
  });
204
204
  }
205
+ export function peek(parser) {
206
+ return trace("peek", (input) => {
207
+ const result = parser(input);
208
+ if (!result.success) {
209
+ return Object.assign(Object.assign({}, result), { rest: input });
210
+ }
211
+ return Object.assign(Object.assign({}, result), { rest: input });
212
+ });
213
+ }
205
214
  /**
206
215
  * Takes three parsers, `open`, `close`, and `parser`.
207
216
  * `between` matches multiple instances of `parser`,
@@ -923,3 +932,20 @@ function tryOps(ops, input) {
923
932
  }
924
933
  return null;
925
934
  }
935
+ const DEFAULT_MEMO_LIMIT = 10000;
936
+ export function memo(name, parser) {
937
+ const cache = new Map();
938
+ return trace(name ? `memo(${name})` : "memo", (input) => {
939
+ const hit = cache.get(input);
940
+ if (hit !== undefined)
941
+ return hit;
942
+ const result = parser(input);
943
+ if (cache.size >= DEFAULT_MEMO_LIMIT) {
944
+ const oldest = cache.keys().next().value;
945
+ if (oldest !== undefined)
946
+ cache.delete(oldest);
947
+ }
948
+ cache.set(input, result);
949
+ return result;
950
+ });
951
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tarsec",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "A parser combinator library for TypeScript, inspired by Parsec.",
5
5
  "homepage": "https://github.com/egonSchiele/tarsec",
6
6
  "scripts": {