PEGjs中的条件语法规则

时间:2016-12-20 02:55:10

标签: javascript parsing grammar 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 repo中查看了javascript的示例语法,条件规则看起来很像我在这里得到的,但我仍然无法让它工作。

实现条件语句的正确方法是什么,就像我在PEGjs规则中描述的那样?

1 个答案:

答案 0 :(得分:1)

我知道这有点晚了,但问题是您的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的情况下,将导致错误。您可能需要添加其他错误处理,但是它确实适用于给定的示例。