PEG.js дает вам немного контекста, когда генерирует SyntaxError. Например, если у вас есть грамматика для SQL и выдает ее что-то вроде:
FOO > 10 A
Тогда PEG.js вернет это:
{
"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"
}
Что он говорит, так это то, что он проанализировал символы 0–9 строки («FOO> 10»), но затем столкнулся с неожиданным токеном на символе 10. И он дает вам список следующих токенов, которые он ожидал: FOO > 10 AND
, FOO > 10 ORDER BY
, FOO > 10
. Если вы добавите их в правильную часть запроса, вы получите хороший набор возможных завершений:
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;
}
Это довольно упрощенно - реальное автозаполнение будет соответствовать не только литералам, и потребуется какой-то способ использовать контекст, недоступный грамматике, например, список аргументов функции, которую вызывает пользователь.