PEG.js gives you quite a bit of context when it generates a SyntaxError. For example, if you have a grammar for SQL and feed it something like:
FOO > 10 A
Then PEG.js will return this:
{
"message": "Expected \"AND\", \"ORDER BY\" or end of input but \"A\" found.",
"expected": [
{
"type": "literal",
"value": "AND",
"description": "\"AND\""
},
{
"type": "literal",
"value": "ORDER BY",
"description": "\"ORDER BY\""
},
{
"type": "end",
"description": "end of input"
}
],
"found": "A",
"offset": 9,
"line": 1,
"column": 10,
"name": "SyntaxError"
}
What it's saying is that it parsed characters 0–9 of the string ("FOO > 10 ") but then encountered an unexpected token at character 10. And it gives you a list of the next tokens it was expecting: FOO > 10 AND
, FOO > 10 ORDER BY
, FOO > 10
. If you tack these onto the valid portion of the query, you'll get a good set of possible completions:
function getCompletions(pegParse, text) {
var parsedText = pegParse(text);
var completions = [];
if (parsedText.expected) {
var start = text.substr(0, parsedText.offset);
parsedText.expected.forEach(function(expected) {
if (expected.type != 'literal') return;
var completion = start + expected.value;
if (completion.substr(0, text.length) == text) {
completions.push(completion);
}
});
}
return completions;
}
This is quite simplistic -- a real autocomplete would match more than just literals and would need some way to take advantage of context not available to the grammar, e.g. the list of arguments to a function that the user is calling.