Skip to content

Commit b64ffe6

Browse files
committed
Add save/restore (and rewind)
Closes #221
1 parent 1443a47 commit b64ffe6

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

lib/nearley.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ Parser.prototype.feed = function(chunk) {
321321
throw err;
322322
}
323323

324+
// maybe save lexer state
325+
if (this.options.keepHistory) {
326+
column.lexerState = lexer.save()
327+
}
328+
324329
this.current++;
325330
}
326331
if (column) {
@@ -334,6 +339,33 @@ Parser.prototype.feed = function(chunk) {
334339
return this;
335340
};
336341

342+
Parser.prototype.save = function() {
343+
var column = this.table[this.current];
344+
column.lexerState = this.lexerState;
345+
return column;
346+
};
347+
348+
Parser.prototype.restore = function(column) {
349+
var index = column.index;
350+
this.current = index;
351+
this.table[index] = column;
352+
this.table.splice(index + 1);
353+
this.lexerState = column.lexerState;
354+
355+
// Incrementally keep track of results
356+
this.results = this.finish();
357+
};
358+
359+
// nb. deprecated: use save/restore instead!
360+
Parser.prototype.rewind = function(index) {
361+
if (!this.options.keepHistory) {
362+
throw new Error('set option `keepHistory` to enable rewinding')
363+
}
364+
// nb. recall column (table) indicies fall between token indicies.
365+
// col 0 -- token 0 -- col 1
366+
this.restore(this.table[index]);
367+
};
368+
337369
Parser.prototype.finish = function() {
338370
// Return the possible parsings
339371
var considerations = [];

test/launch.js

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,20 @@ describe('Parser', function() {
168168
)
169169
})
170170

171-
// TODO: save/restore
172-
173-
/*
174171
var tosh = compile(read("examples/tosh.ne"));
175172

173+
it('can save state', function() {
174+
let first = "say 'hello'";
175+
let second = " for 2 secs";
176+
let p = new nearley.Parser(tosh, { keepHistory: true });
177+
p.feed(first);
178+
p.current.should.equal(11)
179+
p.table.length.should.equal(12)
180+
var col = p.save();
181+
col.index.should.equal(11)
182+
col.lexerState.col.should.equal(first.length)
183+
});
184+
176185
it('can rewind', function() {
177186
let first = "say 'hello'";
178187
let second = " for 2 secs";
@@ -184,6 +193,7 @@ describe('Parser', function() {
184193
p.feed(second);
185194

186195
p.rewind(first.length);
196+
187197
p.current.should.equal(11)
188198
p.table.length.should.equal(12)
189199

@@ -194,6 +204,36 @@ describe('Parser', function() {
194204
let p = new nearley.Parser(tosh, {});
195205
p.rewind.should.throw();
196206
})
197-
*/
207+
208+
it('restores line numbers', function() {
209+
let p = new nearley.Parser(testGrammar);
210+
p.feed('abc\n')
211+
p.save().lexerState.line.should.equal(2)
212+
p.feed('123\n')
213+
var col = p.save();
214+
col.lexerState.line.should.equal(3)
215+
p.feed('q')
216+
p.restore(col);
217+
p.lexer.line.should.equal(3)
218+
p.feed('z')
219+
});
220+
221+
it('restores column number', function() {
222+
let p = new nearley.Parser(testGrammar);
223+
p.feed('foo\nbar')
224+
var col = p.save();
225+
col.lexerState.line.should.equal(2)
226+
col.lexerState.col.should.equal(3)
227+
p.feed('123');
228+
p.lexerState.col.should.equal(6)
229+
230+
p.restore(col);
231+
p.lexerState.line.should.equal(2)
232+
p.lexerState.col.should.equal(3)
233+
p.feed('456')
234+
p.lexerState.col.should.equal(6)
235+
});
236+
237+
// TODO: moo save/restore
198238

199239
});

0 commit comments

Comments
 (0)