Заменить комментарий в JavaScript AST с поддеревом, полученным из содержимого комментария
Я автор doctest, быстрый и грязный доктрины для JavaScript и CoffeeScript. Я хотел бы сделать библиотеку менее грязной, используя парсер JavaScript, а не регулярные выражения для поиска комментариев.
Я хотел бы использовать Esprima или Acorn, чтобы сделать следующее:
- Создайте AST
- Пройдите дерево, и для каждого комментария node:
- Создайте AST из комментария node text
- Заменить комментарий node в главном дереве с помощью этого поддерева
Ввод:
!function() {
// > toUsername("Jesper Nøhr")
// "jespernhr"
var toUsername = function(text) {
return ('' + text).replace(/\W/g, '').toLowerCase()
}
}()
Вывод:
!function() {
doctest.input(function() {
return toUsername("Jesper Nøhr")
});
doctest.output(4, function() {
return "jespernhr"
});
var toUsername = function(text) {
return ('' + text).replace(/\W/g, '').toLowerCase()
}
}()
Я не знаю, как это сделать. Acorn предоставляет walker, который принимает тип и функцию node и выполняет дерево, вызывающее функцию каждый раз, когда встречается node указанного типа. Это кажется многообещающим, но не относится к комментариям.
С Esprima я могу использовать esprima.parse(input, {comment: true, loc: true}).comments
для получения комментариев, но я не уверен, как обновлять дерево.
Ответы
Ответ 1
Большинство аналитиков, производящих АСТ, бросают комментарии. Я не знаю, что делают Esprima или Acorn, но это может быть проблемой.
.... Фактически, Esprima перечисляет захват комментариев как текущую ошибку:
http://code.google.com/p/esprima/issues/detail?id=197
... Желудочный код находится прямо в GitHub. Похоже, что он тоже отсылает комментарии.
Итак, похоже, что вы можете исправить либо синтаксический анализатор, чтобы сначала записать комментарии, и в какой момент ваша задача должна быть простой, или вы застряли.
В нашем DMS Software Reengineering Toolkit есть парсеры JavaScript, которые фиксируют комментарии в дереве. Он также содержит парсы для подстроки языка, которые могут использоваться для анализа текста комментария в JavaScript AST, любого типа, который представляет комментарий (например, объявление функции, выражение, объявление переменной)... и механизм поддержки для прививки таких новых АСТ в основное дерево. Если вы собираетесь манипулировать АСТ, эта возможность подстроки, вероятно, важна: большинство парсеров не будут анализировать фрагменты произвольного языка, они проводятся только для анализа "целых программ". Для DMS нет узлов комментариев для замены; есть комментарии, связанные с узлами AST, поэтому процесс трансплантации немного сложнее, чем просто "заменить узлы комментариев". Все еще довольно легко.
Я понаблюдаю, что большинство парсеров (включая их) читают источник и разбивают его на токены, используя или применяя эквивалент регулярных выражений. Таким образом, если вы уже используете их для поиска комментариев (это означает, что они используют их для поиска * не * комментариев для выброса, например, вам нужно распознать строковые литералы, содержащие текстовые комментарии и игнорировать их), вы так же, как и парсеры, все равно будут искать комментарии. И если все, что вы хотите сделать, это заменить их именно своим контентом, повторение исходного потока с префиксом комментария /suffix/ * */stripped сделает apparantly именно то, что вы хотите, поэтому весь этот механизм синтаксического анализа кажется излишним.
Ответ 2
Вы уже можете использовать Esprima для достижения того, чего хотите:
- Разберите код, получите комментарии (в виде массива).
- Итерации над комментариями, посмотрите, интересует ли вас каждый из них.
- Если вам нужно преобразовать комментарий, обратите внимание на его диапазон. Соберите все преобразования.
- Применить преобразование назад к первому, чтобы диапазоны не сдвигались.
Трюк здесь не изменяет AST. Просто примените изменение текста, как если бы вы выполняли обычную замену поиска в исходной строке напрямую. Поскольку позиция замены может измениться, вам нужно собрать все, а затем сделать это с последнего. Для примера о том, как выполнить такое преобразование, посмотрите на мой пост в блоге "От двойных кавычек до одиночных кавычек" (это относится к строковым кавычкам, но принцип остается тем же).
И последнее, но не менее важное: вы можете использовать несколько более высокоуровневую утилиту, такую как Rocambole.