Условное грамматическое правило в 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
  }

Я посмотрел пример грамматики для javascript в репозитории PEGjs github, и условное правило очень похоже на то, что у меня здесь, но я все еще не могу заставить его работать.

Каков будет правильный способ реализации условного оператора, подобного тому, который я описал в правиле PEGjs?

0 ответов

Я знаю, что это немного поздно, но проблема в том, что вы 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никогда не определяется в вашем контексте. Вы можете добавить дополнительную обработку ошибок, но в данном примере это работает.

Другие вопросы по тегам