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