Использование вложенных макросов в Nearley вкладывает результат данных
Эта проблема
На первый взгляд, макросы не могут быть правильно вложены без серьезных ошибок.
Основная проблема заключается в том, что при получении значения макроса из объекта данных это значение вкладывается в список:
a[X] -> $X {% id %}
main -> a["test"] {% id %}
Parse results:
[ [ 'test' ] ]
Ожидаемый результат будет [ 'test' ]
,
Быстрое решение - вернуть данные [0][0], но этого недостаточно, потому что результат будет вложен для каждого слоя макроса:
a[X] -> b[$X] {% id %}
b[X] -> $X {% id %}
main -> a["test"] {% id %}
Parse results:
[ [ [ 'x' ] ] ]
Чтобы исправить ошибку, мы могли бы использовать data => data[0][0]
для каждого макроса. Однако это абсолютно безобразно.
Реальным решением было бы использование динамического определения объема. Поскольку мы не можем (насколько мне известно) создать макрос без параметров, давайте использовать бесполезные параметры:
a[X] -> b["_"] {% id %}
b[_] -> $X {% id %}
main -> a["test"] {% id %}
Parse results:
[ [ 'test' ] ]
Это останавливает вложенный ад, который случился раньше - мы могли бы пройти 500 суб-макросов и все равно получить тот же результат. Но нам все еще нужно поместить данные [0] [0] для окончательного суб-макроса b
и это мешает нам использовать b
макрос сам по себе - мы должны использовать a
чтобы это работало.
Мы ищем решение, которое: - позволяет использовать последний макрос сам по себе - избегает использования data => data[0][0]
1 ответ
Решение
Чтобы избежать проблемы, лучшим решением является следующее:
a[X] -> b[$X] {% id %}
b[X] -> c[$X] {% id %}
c[X] -> $X {% data => data[0].join('') %}
main -> a["test"] {% id %}
Parse results:
[ 'test' ]
объяснение
Проблема заключалась в том, что, когда последний суб-макрос получает результат, так как nearley рассматривает все как массив по умолчанию, результат вкладывается в массив. Затем каждый слой делает то же самое. Использование метода join в массиве делает его строкой - и каждый макрос перестанет помещать его в массив.
Вы должны подумать о том, какой макрос или нетерминал отвечает за структурирование данных и сглаживание массивов и где это уместно.
Лично мне нравится поддерживать регулярную постобработку, относящуюся к макросу, внутри макроса, и я делаю структурирование (например, сглаживание массивов) дальше по цепочке, внутри нетерминала (или макроса), который отвечает только за это.
пример
withCurlyBrackets[X] -> "{" $X "}" {% d => d[1] %}
withSquareBrackets[X] -> "[" $X "]" {% d => d[1] %}
withRoundBrackets[X] -> "(" $X ")" {% d => d[1] %}
test -> withRoundBrackets[withSquareBrackets[withCurlyBrackets["test"]]] {% id => ({ value: id.flat(Infinity).join('') }) %}
// Parse results for '([{test}])': [ { value: 'test' } ]