Peg.js 在 AngularJS 网络应用程序中
Peg.js in AngularJS webapp
我有一个 AngularJS 网络应用程序。
我想在我的申请中使用 peg.js。
我刚刚写了一个 peg.js 语法:CriteriaValue.pegjs 并用命令行生成了解析器:
pegjs CriteriaValue.pegjs
,生成了 CriteriaValue.js。
有人可以向我解释如何使用解析器吗?
var 结果=parser.parse('my string');不起作用。
我创建了一个 plunker:
http://plnkr.co/edit/Ae05SeZAjKOQ75B3lvLc?p=preview
简答
- 在CriteriaValue.js中,将第一行的
module.exports
改为parser
- 在 index.html 中,交换
<script>
标签,使 CriteriaValue.js 排在第一位
- (可选)在 script.js 中,将解析结果输出为格式化的 JSON 字符串,以便查看实际值
这里是 plunker: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
可用于 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 "
});
另一种选择是使用 PEG.buildParser()
:
获取 .pegjs 文件并在客户端生成解析器
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),您需要更改的代码就会少得多。
我有一个 AngularJS 网络应用程序。
我想在我的申请中使用 peg.js。
我刚刚写了一个 peg.js 语法:CriteriaValue.pegjs 并用命令行生成了解析器:
pegjs CriteriaValue.pegjs
,生成了 CriteriaValue.js。
有人可以向我解释如何使用解析器吗?
var 结果=parser.parse('my string');不起作用。
我创建了一个 plunker: http://plnkr.co/edit/Ae05SeZAjKOQ75B3lvLc?p=preview
简答
- 在CriteriaValue.js中,将第一行的
module.exports
改为parser
- 在 index.html 中,交换
<script>
标签,使 CriteriaValue.js 排在第一位 - (可选)在 script.js 中,将解析结果输出为格式化的 JSON 字符串,以便查看实际值
这里是 plunker: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
可用于 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 "
});
另一种选择是使用 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),您需要更改的代码就会少得多。