AngularJS webapp中的Peg.js

时间:2015-06-11 16:00:51

标签: angularjs pegjs

我有一个AngularJS网络应用程序。

我想在我的应用程序中使用peg.js。 我刚刚编写了一个peg.js语法:CriteriaValue.pegjs并使用命令行生成解析器: pegjs CriteriaValue.pegjs,生成了CriteriaValue.js。

有人可以向我解释如何使用解析器吗?

var result = parser.parse(' my string');不起作用。

我创造了一个傻瓜: http://plnkr.co/edit/Ae05SeZAjKOQ75B3lvLc?p=preview

1 个答案:

答案 0 :(得分:4)

简答

  • 在CriteriaValue.js中,将第一行中的module.exports更改为parser
  • 在index.html中,交换<script>代码,以便首先使用CriteriaValue.js
  • (可选)在script.js中,将解析的结果输出为格式化的JSON字符串,以便查看实际值

以上是这个问题:http://plnkr.co/edit/kiBp2Na9s4PXpenCzQjx?p=preview

长答案

运行原始的plunker并检查控制台日志;你会注意到2个错误:

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

第一个错误是由于在全局范围内,script.js或CriteriaValue.js都没有创建parser个对象。

查看CriteriaValue.js,您可以看到它实际上将生成的解析器对象分配给不存在的modules.export。这是PEG.js的默认行为,因为它假设您将使用node.js使用解析器。您发现错误的原因是没有module个对象,因此我们无法分配这个不存在的对象export属性。将作业更改为parser,这是我们可以指定的内容(因为PEG.js不使用strict mode),可以避免此错误并使parser可用于脚本的.js。

最后,需要在script.js可以使用之前创建解析器;因此<script>交换的原因。

为了将来创建CriteriaValue.js,请执行以下操作:

pegjs --export-var parser CriteriaValue.pegjs

这将生成文件,以便将对象分配给变量parser而不是module.exports

AngularJS进来的地方

正如@dirkk在评论中所说,将解析器定义为全局变量是不好的做法,当然不是AngularJS方式,即将解析器实现为服务。

最快(但不一定是最好)的方法是获取已经生成的CriteriaValue.js代码并围绕它包装服务。 e.g:

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

另一种选择是获取.pegjs文件&amp;使用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),那么您将需要更少的代码进行更改。