CFG / PEG используется для завершения кода? - PullRequest
12 голосов
/ 16 августа 2011

Мне интересно, возможно ли использовать грамматику CFG или PEG в качестве основы для завершения кода напрямую без изменений.Я слышал, что завершение кода в IDE иногда манипулируют и массируют или даже жестко запрограммируют, чтобы оно работало лучше.

Я хочу завершить код на небольшом DSL, поэтому я полностью понимаю, что грамматика не может помочь кодусистема завершения со знанием библиотечных функций и т. д.

Насколько я знаю, сам парсер должен по крайней мере предоставить систему для запроса того, что он ожидает дальше.

В частности, язаинтересован в решении для завершения кода javascript с использованием peg.js или jison

Ответы [ 2 ]

13 голосов
/ 22 октября 2011

Довольно просто создать редактор Javascript с дополнением кода из грамматики PEG.Я бы описал, как это сделать с PEG.js.Вы должны расширить свою грамматику с помощью некоторых слабых правил синтаксического анализа, которые позволяют предоставлять предложения, когда предыдущие операторы нарушаются.Эти слабые правила необходимо обрабатывать условно, иначе вам понадобятся две отдельные грамматики - одна для разбора исходного кода, а вторая для завершения кода.Вы можете поддерживать одну грамматику, используя предикаты Javascript (доступно в PEG.js).Это выглядит как &{return laxParsing}, и это приводит к тому, что все правило обрабатывается, когда флаг laxParsing равен true.Вы можете легко переключаться между слабым и строгим синтаксическим анализом, устанавливая внутренний флаг анализатора.

Чтобы легко предлагать пользователю рекомендации, вы должны изменить слегка сгенерированный PEG.js анализатор (версия 0.5), чтобы он находился в позиции структуры ошибки синтаксического анализа (рядом сстолбец и строка) и список ожиданий (кроме сообщения об ошибке).Вы можете скопировать подготовленный фрагмент из https://gist.github.com/1281239.

Когда у вас есть парсер, вы можете прикрепить его в редакторе, например, с помощью комбинации клавиш CTRL + SPACE.Когда они нажимаются в текстовом источнике, вам нужно поставить специальный неразборчивый знак вместо курсора (чтобы вызвать ошибку синтаксического анализа) и запустить анализатор в режиме lax.Затем вы получаете сообщение об ошибке со списком предложений.

Некоторые предложения не только синтаксические, но и определяют ссылки (например, сущности, переменные).Вы можете инициировать их поиск при обнаружении определенного ожидания (например, VariableName).Вы можете предоставить список, проанализировав один и тот же источник в другом режиме слабого синтаксического анализа (отфильтровывая только имена переменных).

Рабочий пример и источник этого подхода можно проверить по https://github.com/mstefaniuk/Concrete-Freetext.

5 голосов
/ 14 ноября 2014

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;
}

Это довольно упрощенно - реальное автозаполнение будет соответствовать не только литералам, и потребуется какой-то способ использовать контекст, недоступный грамматике, например, список аргументов функции, которую вызывает пользователь.

...