Skip to content

Commit

Permalink
add memoization to Parser.expr. Remove infinite recursion by moving s…
Browse files Browse the repository at this point in the history
…ome code from Parser.rule combinator to parser function
  • Loading branch information
maestrow committed May 17, 2021
1 parent aaf7ba1 commit 0b1605b
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 7 deletions.
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
15 changes: 10 additions & 5 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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()
Expand All @@ -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 => () => {
Expand Down Expand Up @@ -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[] = []
Expand All @@ -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++) {
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"sourceMap": true,
"noImplicitAny": false,
"experimentalDecorators": true,
"module": "commonjs",
"target": "ES2020",
"lib": ["ES2020", "dom"],
Expand Down

0 comments on commit 0b1605b

Please sign in to comment.