From b6b1acd4226e06b26fae8ddd565964d1db02bf85 Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 10 Aug 2021 09:40:36 -0700 Subject: [PATCH 1/2] Implement memoization cache --- src/cache.ts | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/cache.ts diff --git a/src/cache.ts b/src/cache.ts new file mode 100644 index 0000000..8f6a758 --- /dev/null +++ b/src/cache.ts @@ -0,0 +1,39 @@ +type Function_ = (...x: never[]) => unknown; + +type Memoize = { + (...x: Parameters): ReturnType; + clearCache: () => void; +}; + +const memoizedFunctions: Memoize[] = []; + +export const memoize = ( + fn: F, +) => { + const cache = new Map(); + + const memoizedFunction = ((...x: never[]) => { + const hash = JSON.stringify(x); + if (cache.has(hash)) { + return cache.get(hash); + } else { + return fn(...x); + } + }) as F; + + const memoizedCallableObject = Object.assign(memoizedFunction, { + clearCache: () => { + cache.clear(); + } + }); + + memoizedFunctions.push(memoizedCallableObject); + + return memoizedCallableObject; +}; + +export const clearCache = () => { + memoizedFunctions.forEach(memoizedFunction => { + memoizedFunction.clearCache(); + }); +} From 1840c2c1c0727a160359049d633d58123573954b Mon Sep 17 00:00:00 2001 From: poteat Date: Tue, 10 Aug 2021 09:42:14 -0700 Subject: [PATCH 2/2] Implement packrat parsing --- src/parser.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/parser.ts b/src/parser.ts index 285bcfc..c9c6636 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,5 +1,6 @@ import { encoder } from './unicode'; import { InputType, InputTypes, isTypedArray } from './inputTypes'; +import { clearCache, memoize } from './cache'; // createParserState :: x -> s -> ParserState e a s const createParserState = (target: InputType, data: D | null = null): ParserState => { @@ -90,13 +91,15 @@ export class Parser { p: StateTransformerFunction; constructor(p: StateTransformerFunction) { - this.p = p; + this.p = memoize(p); } // run :: Parser e a s ~> x -> Either e a run(target: InputType): ResultType { const state = createParserState(target); + clearCache(); + const resultState = this.p(state); if (resultState.isError) { @@ -123,6 +126,8 @@ export class Parser { const state = createParserState(target); const newState = this.p(state); + clearCache(); + if (newState.isError) { return errorFn(newState.error, newState); }