PEGjs中的条件语法规则
Conditional grammar rule in PEGjs
我正在尝试实现一个解析基本算术表达式的简单 DSL。这需要在浏览器中完成,所以我使用 PEGjs 来生成解析器。
表达式中的项可以是数字(整数或实数)、变量(变量是传递给解析器的上下文对象的属性)、条件或通过点表示法访问的属性。
我希望条件看起来像这样 condition?value
,如果 condition
为真,则该术语等于 value
。 ?
两边的变量也可以是像这样的对象的点符号访问属性 object.property1?object.property2
.
因此,如果向解析器传递这样的对象:
context = {
depth: 100,
material: {
thickness: 20
include: true
}
edge: {
face: 4.5
}
}
表达式:
500 + depth + material.include?edge.face + material.thickness
应该等于 624.5
.
我一直在使用 PEGjs 在线编辑器。我尝试了很多不同的方法,但我似乎无法确定条件。其他一切都有效。以下是相关规则:
Variable "variable"
= variable:identifier accessor:("." identifier)* {
var result = context[variable], i
for (i = 0; i < accessor.length; i++) {
result = result[accessor[i][1]]
}
return result
}
identifier
= identifier:$([0-9a-zA-Z_$]+)
Conditional
= condition:Variable "?" value:Variable {
return condition ? value : 0
}
我查看了 PEGjs github 存储库中 javascript 的示例语法,条件规则看起来很像我在这里得到的,但我仍然不能让它工作。
实现像我在 PEGjs 规则中描述的那样的条件语句的正确方法是什么?
我知道这有点晚了,但问题是你的 variable
是一个评估为 "material.include"
.
的字符串
看这段代码:
var result = context[variable], i
您正在尝试从上下文对象访问名为 "material.include" 的 属性,它看起来像这样:
{
"material.include": true
}
而不是尝试访问 "material" 属性 引用的对象,然后 "include" 属性 关闭结果对象,它看起来像这样:
{
"material": {
"include": true
}
}
解决方案是将变量字符串拆分为 "."
个字符,然后递归地找到你的 属性:
Variable "variable"
= variable:identifier accessor:("." identifier)* {
var path = variable.split(".");
var result = path.reduce( (nextObject, propName) => nextObject[propName], context );
for (var i = 0; i < accessor.length; i++) {
result = result[accessor[i][1]]
}
return result
}
请注意,此解决方案并不完整,因为如果您尝试访问 material.include
(其中 material
从未在您的上下文中定义),它将导致错误。您可能想要添加额外的错误处理,但它确实适用于给定的示例。
我正在尝试实现一个解析基本算术表达式的简单 DSL。这需要在浏览器中完成,所以我使用 PEGjs 来生成解析器。
表达式中的项可以是数字(整数或实数)、变量(变量是传递给解析器的上下文对象的属性)、条件或通过点表示法访问的属性。
我希望条件看起来像这样 condition?value
,如果 condition
为真,则该术语等于 value
。 ?
两边的变量也可以是像这样的对象的点符号访问属性 object.property1?object.property2
.
因此,如果向解析器传递这样的对象:
context = {
depth: 100,
material: {
thickness: 20
include: true
}
edge: {
face: 4.5
}
}
表达式:
500 + depth + material.include?edge.face + material.thickness
应该等于 624.5
.
我一直在使用 PEGjs 在线编辑器。我尝试了很多不同的方法,但我似乎无法确定条件。其他一切都有效。以下是相关规则:
Variable "variable"
= variable:identifier accessor:("." identifier)* {
var result = context[variable], i
for (i = 0; i < accessor.length; i++) {
result = result[accessor[i][1]]
}
return result
}
identifier
= identifier:$([0-9a-zA-Z_$]+)
Conditional
= condition:Variable "?" value:Variable {
return condition ? value : 0
}
我查看了 PEGjs github 存储库中 javascript 的示例语法,条件规则看起来很像我在这里得到的,但我仍然不能让它工作。
实现像我在 PEGjs 规则中描述的那样的条件语句的正确方法是什么?
我知道这有点晚了,但问题是你的 variable
是一个评估为 "material.include"
.
看这段代码:
var result = context[variable], i
您正在尝试从上下文对象访问名为 "material.include" 的 属性,它看起来像这样:
{
"material.include": true
}
而不是尝试访问 "material" 属性 引用的对象,然后 "include" 属性 关闭结果对象,它看起来像这样:
{
"material": {
"include": true
}
}
解决方案是将变量字符串拆分为 "."
个字符,然后递归地找到你的 属性:
Variable "variable"
= variable:identifier accessor:("." identifier)* {
var path = variable.split(".");
var result = path.reduce( (nextObject, propName) => nextObject[propName], context );
for (var i = 0; i < accessor.length; i++) {
result = result[accessor[i][1]]
}
return result
}
请注意,此解决方案并不完整,因为如果您尝试访问 material.include
(其中 material
从未在您的上下文中定义),它将导致错误。您可能想要添加额外的错误处理,但它确实适用于给定的示例。