diff --git a/package-lock.json b/package-lock.json index fa16925..cb83ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "fast-deep-equal": "^3.1.3" + "fast-deep-equal": "^3.1.3", + "typescript-memoize": "^1.0.1" }, "devDependencies": { "@types/jest": "^26.0.23", @@ -6181,6 +6182,11 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-memoize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typescript-memoize/-/typescript-memoize-1.0.1.tgz", + "integrity": "sha512-oJNge1qUrOK37d5Y6Ly2txKeuelYVsFtNF6U9kXIN7juudcQaHJQg2MxLOy0CqtkW65rVDYuTCOjnSIVPd8z3w==" + }, "node_modules/union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", @@ -11469,6 +11475,11 @@ "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", "dev": true }, + "typescript-memoize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typescript-memoize/-/typescript-memoize-1.0.1.tgz", + "integrity": "sha512-oJNge1qUrOK37d5Y6Ly2txKeuelYVsFtNF6U9kXIN7juudcQaHJQg2MxLOy0CqtkW65rVDYuTCOjnSIVPd8z3w==" + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", diff --git a/package.json b/package.json index 88821a6..fe843d8 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "typescript": "^4.2.4" }, "dependencies": { - "fast-deep-equal": "^3.1.3" + "fast-deep-equal": "^3.1.3", + "typescript-memoize": "^1.0.1" } } diff --git a/src/parser.ts b/src/parser.ts index cfca65e..5e21b53 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -4,6 +4,7 @@ import { Ast } from './grammar-ast' import * as equal from 'fast-deep-equal/es6' import { getRuleBodyByName } from './utils' import { Tracer } from './tracer' +import { Memoize } from 'typescript-memoize' const idFn = id => id @@ -18,6 +19,8 @@ export class Parser implements Ast.IParser { private projectors: IProjectors constructor(gr: Ast.Grammar, input: any[], proj: IProjectors = {}) { + this.expr = this.expr.bind(this) + this.grammar = gr this.state = new State(input) this.projectors = proj @@ -42,14 +45,14 @@ export class Parser implements Ast.IParser { // ToDo: translate Если ф-ция парсера вызывает другую ф-цию парсера, то успешный результат вложенного парсера нельзя пробрасывать наверх. // Иначе может произойти двойной консум - expr = (e: Ast.Expr): IParserFn => { + @Memoize((...args) => JSON.stringify(args)) + expr (e: Ast.Expr): IParserFn { const combinator = this[e[0]] if (typeof(combinator) !== 'function') { throw new Error(`There is no core combinator with name: '${e[0]}'`) } const fn: IParserFn = combinator.apply(this, e.slice(1)) - return () => { this.trace.start(e, this.state.pos) const res = fn() @@ -64,7 +67,9 @@ export class Parser implements Ast.IParser { // === Parsers rule = (name: string): IParserFn => { - return this.project(name, getRuleBodyByName(name, this.grammar)) + const e = getRuleBodyByName(name, this.grammar) + + return () => this.project(name, e)() } empty = (): IParserFn => () => { @@ -95,7 +100,7 @@ export class Parser implements Ast.IParser { } seq = (exprs: Ast.Expr[]): IParserFn => { - const parsers = exprs.map(e => this.expr(e)) + const parsers = exprs.map(this.expr) return () => { const results: any[] = [] @@ -115,7 +120,7 @@ export class Parser implements Ast.IParser { } alt = (exprs: Ast.Expr[]): IParserFn => { - const parsers = exprs.map(e => this.expr(e)) + const parsers = exprs.map(this.expr) return () => { for (let i = 0; i < exprs.length; i++) { diff --git a/tsconfig.json b/tsconfig.json index bf4ecf0..44ecf6d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "sourceMap": true, "noImplicitAny": false, + "experimentalDecorators": true, "module": "commonjs", "target": "ES2020", "lib": ["ES2020", "dom"],