Требуется регулярное выражение для выполнения основной рекурсивной функции парсеров языка (или помощь в создании плагина Babel)
У меня есть следующее регулярное выражение:
/(?:this\.(\w+)\(([\s\S]*?)\))/g
он используется для получения кода, подобного следующему:
this.doSomething(foo, bar)
и заменить его на:
this.lookup('doSomething', [foo, bar])
для этого варианта использования (который является наиболее распространенным) он работает правильно, но не работает, если this
используется в нем так:
this.doSomething(foo, bar, this.baz())
результат неправильно это:
this.lookup('doSomething', [foo, bar, this.baz(]))
должно быть так:
this.lookup('doSomething', [foo, bar, this.baz()])
Ну, это первая проблема. На самом деле это должно быть преобразовано так же, как this.doSomething
итоговый результат действительно должен быть:
this.lookup('doSomething', [foo, bar, this.lookup('baz', [])]);
В основном мое регулярное выражение предполагает закрывающую скобку из this.baz()
закрывающая круглая скобка this.doSomething()
а также не работает рекурсивно. Мне нужно какое-то рекурсивное поведение / контроль здесь.
Я слышал о xregexp, но я не уверен, как это может мне помочь. Также кажется, что настоящий синтаксический анализатор языка - единственный путь. У меня там мало опыта, но я не боюсь испачкать руки. Кажется, такие инструменты, как Esprima, могут помочь?
В конце дня я собираюсь внести небольшие изменения в язык / синтаксис на этапе сборки моего кода, то есть точно так же, как это делает Babel. Я на самом деле использую Бабель. Может быть, какой-то плагин Babel является вариантом?
В любом случае, я открыт как для быстрого исправления трюка с регулярными выражениями, так и для более про / надежных методов синтаксического анализа языка. Мне также просто любопытно, как обычно решаются такие проблемы. Сканирование по всему вводу и сопоставление открытых / закрывающих скобок / скобок / и т. Д. Я предполагаю??
1 ответ
Вот пример того, как вы можете сделать это с помощью плагина Babel:
var names = ['doSomething', 'baz'];
module.exports = function(context){
var t = context.types;
return {
visitor: {
CallExpression: function(path){
var callee = path.get('callee');
// Only process "this.*()" calls.
if (!callee.isMemberExpression() ||
!callee.get('object').isThisExpression() ||
!callee.get('property').isIdentifier()) return;
// Make sure the call is to one of your specific functions.
if (names.indexOf(path.node.callee.property.name) === -1) return;
// Build "this.lookup('<name>', [])".
path.replaceWith(t.callExpression(
t.memberExpression(t.thisExpression(), t.identifier('lookup')),
[
t.stringLiteral(path.node.callee.property.name),
t.arrayExpression(path.node.arguments),
]
));
}
}
};
}
Если вы бросите это в plugin.js
функция, например, вы можете создать .babelrc
Конфиг файл и убедитесь, ./plugin.js
или какой-либо путь, указывающий на это, находится в вашем plugins
массив, например
.babelrc
{
"presets": ['es2015'],
"plugins": ['./plugin']
}