From b64ffe6bc3c0edef04defa7583c4c266f1bff069 Mon Sep 17 00:00:00 2001 From: tjvr Date: Mon, 17 Apr 2017 15:36:03 +0100 Subject: [PATCH] Add save/restore (and rewind) Closes #221 --- lib/nearley.js | 32 ++++++++++++++++++++++++++++++++ test/launch.js | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/lib/nearley.js b/lib/nearley.js index 9cce0070..cd039936 100644 --- a/lib/nearley.js +++ b/lib/nearley.js @@ -321,6 +321,11 @@ Parser.prototype.feed = function(chunk) { throw err; } + // maybe save lexer state + if (this.options.keepHistory) { + column.lexerState = lexer.save() + } + this.current++; } if (column) { @@ -334,6 +339,33 @@ Parser.prototype.feed = function(chunk) { return this; }; +Parser.prototype.save = function() { + var column = this.table[this.current]; + column.lexerState = this.lexerState; + return column; +}; + +Parser.prototype.restore = function(column) { + var index = column.index; + this.current = index; + this.table[index] = column; + this.table.splice(index + 1); + this.lexerState = column.lexerState; + + // Incrementally keep track of results + this.results = this.finish(); +}; + +// nb. deprecated: use save/restore instead! +Parser.prototype.rewind = function(index) { + if (!this.options.keepHistory) { + throw new Error('set option `keepHistory` to enable rewinding') + } + // nb. recall column (table) indicies fall between token indicies. + // col 0 -- token 0 -- col 1 + this.restore(this.table[index]); +}; + Parser.prototype.finish = function() { // Return the possible parsings var considerations = []; diff --git a/test/launch.js b/test/launch.js index 2b2bc4f7..511c1af7 100644 --- a/test/launch.js +++ b/test/launch.js @@ -168,11 +168,20 @@ describe('Parser', function() { ) }) - // TODO: save/restore - - /* var tosh = compile(read("examples/tosh.ne")); + it('can save state', function() { + let first = "say 'hello'"; + let second = " for 2 secs"; + let p = new nearley.Parser(tosh, { keepHistory: true }); + p.feed(first); + p.current.should.equal(11) + p.table.length.should.equal(12) + var col = p.save(); + col.index.should.equal(11) + col.lexerState.col.should.equal(first.length) + }); + it('can rewind', function() { let first = "say 'hello'"; let second = " for 2 secs"; @@ -184,6 +193,7 @@ describe('Parser', function() { p.feed(second); p.rewind(first.length); + p.current.should.equal(11) p.table.length.should.equal(12) @@ -194,6 +204,36 @@ describe('Parser', function() { let p = new nearley.Parser(tosh, {}); p.rewind.should.throw(); }) - */ + + it('restores line numbers', function() { + let p = new nearley.Parser(testGrammar); + p.feed('abc\n') + p.save().lexerState.line.should.equal(2) + p.feed('123\n') + var col = p.save(); + col.lexerState.line.should.equal(3) + p.feed('q') + p.restore(col); + p.lexer.line.should.equal(3) + p.feed('z') + }); + + it('restores column number', function() { + let p = new nearley.Parser(testGrammar); + p.feed('foo\nbar') + var col = p.save(); + col.lexerState.line.should.equal(2) + col.lexerState.col.should.equal(3) + p.feed('123'); + p.lexerState.col.should.equal(6) + + p.restore(col); + p.lexerState.line.should.equal(2) + p.lexerState.col.should.equal(3) + p.feed('456') + p.lexerState.col.should.equal(6) + }); + + // TODO: moo save/restore });