Peg.js в веб-приложении AngularJS

У меня есть веб-приложение AngularJS.

Я хотел бы использовать peg.js в своем приложении. Я только что написал грамматику peg.js: CriteriaValue.pegjs и сгенерировал синтаксический анализатор с помощью командной строки: pegjs CriteriaValue.pegjs, который сгенерировал CriteriaValue.js.

Может ли кто-нибудь объяснить мне, как использовать парсер?

var result = parser.parse('моя строка'); не работает.

Я создал планкер: http://plnkr.co/edit/Ae05SeZAjKOQ75B3lvLc?p=preview< /а>


person user3181983    schedule 11.06.2015    source источник
comment
как вы включаете CriteriaValue.js на свою страницу?   -  person Joao Leal    schedule 11.06.2015


Ответы (1)


Короткий ответ

  • В CriteriaValue.js измените module.exports в первой строке на parser.
  • В index.html поменяйте местами теги <script>, чтобы CriteriaValue.js стоял первым.
  • (Необязательно) В script.js выведите результаты синтаксического анализа в виде отформатированной строки JSON, чтобы увидеть фактические значения.

Вот плункер: http://plnkr.co/edit/kiBp2Na9s4PXpenCzQjx?p=preview

Длинный ответ

Запустите свой оригинальный плункер и проверьте журналы консоли; вы заметите 2 ошибки:

  • ReferenceError: Can't find variable: parser (script.js:3)
  • ReferenceError: Can't find variable: error (CriteriaValue.js:1)

Первая ошибка связана с тем, что объект parser никогда не создается в глобальной области видимости с помощью script.js или CriteriaValue.js.

Глядя на CriteriaValue.js, вы можете увидеть, что он фактически присваивает сгенерированный объект парсера несуществующему modules.export. Это поведение PEG.js по умолчанию, так как предполагается, что вы собираетесь использовать свой синтаксический анализатор с node.js. Причина, по которой вы видите ошибку, заключается в том, что объекта module нет, поэтому мы не можем присвоить этому несуществующему объекту свойство export. Изменение назначения на parser, которому мы можем назначить (поскольку PEG.js не использует строгий режим), позволяет избежать этой ошибки и делает parser доступным для использования в script.js.

Наконец, синтаксический анализатор должен быть создан до того, как script.js сможет его использовать; отсюда и причина свопа <script>.

Для будущего создания CriteriaValue.js сделайте это следующим образом:

pegjs --export-var parser CriteriaValue.pegjs

Это сгенерирует файл так, что объект будет назначен переменной parser вместо module.exports.

Где появляется AngularJS

Как сказал @dirkk в комментариях, определение синтаксического анализатора как глобальной переменной является плохой практикой и, конечно же, не способом AngularJS, который заключается в реализации вашего синтаксического анализатора как службы.

Самый быстрый (но не обязательно лучший) способ сделать это — взять уже сгенерированный код CriteriaValue.js и обернуть вокруг него сервис. например.:

angular.module('yourApp.services', [])
.factory('Parser', function() {
  // The generated code, except replace "parser = " with "return "
});

Другой вариант — получить файл .pegjs и сгенерировать парсер на клиенте, используя PEG.buildParser():

angular.module('yourApp.services', [])
.factory('Parser', ['$http', '$q', function($http, $q) {
  var deferred = $q.defer();
  $http.get('path/to/CriteriaValue.pegjs')
  .success(function(grammar) {
    try {
      deferred.resolve(PEG.buildParser(grammar));
    } catch (e) {
      deferred.reject(e);
    }
  })
  .error(function(message) {
    deferred.reject('Unable to load grammar: ' + message);
  });

  return deferred.promise;
}]);

Это упрощает обновление вашей грамматики, так как вам не придется каждый раз переписывать свой сервис, но добавляет задержку при загрузке вашего приложения. Осуществимость этого зависит от того, насколько сложна ваша грамматика и как часто ее действительно нужно менять.

Несмотря на то, как вы строите свой парсер, вам не обязательно предоставлять сгенерированный объект парсера непосредственно остальной части вашего приложения Angular. Вместо этого вы можете реализовать API более высокого уровня для того, что ваше приложение на самом деле будет делать с этим парсером (например, validate(input), getAST(input) и т. д.). Таким образом, если вы решите в будущем переключиться на другой парсер (например, Jison), у вас будет гораздо меньше кода для изменения.

person tavnab    schedule 12.06.2015
comment
Хотя я в целом согласен с вашим ответом, я бы рекомендовал обернуть скрипт в службу Angular вместо использования глобальной переменной. Таким образом вы убираете глобальные переменные, что является довольно плохой практикой, и вы можете воспользоваться преимуществами фреймворка Angular DI. - person dirkk; 12.06.2015
comment
@dirkk Я абсолютно согласен. Я слишком много внимания уделял тому, что сломалось при работе с PEG.js, а не тому, как правильно реализовать PEG.js в angular. - person tavnab; 12.06.2015