需要正则表达式来完成语言解析器的基本递归功能(或帮助制作 Babel 插件)
Need regex to accomplish basic recursive feature of language parsers (or help making Babel plugin)
我有以下正则表达式:
/(?: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()
的右括号,并且也不会递归操作。我在这里需要某种递归 behavior/control 。
我听说过 xregexp,但我不确定它对我有何帮助。似乎真正的语言解析器可能是唯一的出路。我在那里没有太多经验,但我不怕弄脏我的手。似乎像 Esprima 这样的工具可以提供帮助?
在一天结束时,我希望在我的代码的构建步骤中进行较小的 language/syntax 更改,即与 Babel 完全一样。我实际上正在使用 Babel。也许某种 Babel 插件是一种选择?
无论如何,我对 quickfix 正则表达式技巧或更多 pro/robust 语言解析技术持开放态度。我也很好奇通常是如何解决这些问题的。扫描整个输入并匹配 open/closing braces/parentheses/etc 我假设??
下面是一个如何使用 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']
}
我有以下正则表达式:
/(?: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()
的右括号,并且也不会递归操作。我在这里需要某种递归 behavior/control 。
我听说过 xregexp,但我不确定它对我有何帮助。似乎真正的语言解析器可能是唯一的出路。我在那里没有太多经验,但我不怕弄脏我的手。似乎像 Esprima 这样的工具可以提供帮助?
在一天结束时,我希望在我的代码的构建步骤中进行较小的 language/syntax 更改,即与 Babel 完全一样。我实际上正在使用 Babel。也许某种 Babel 插件是一种选择?
无论如何,我对 quickfix 正则表达式技巧或更多 pro/robust 语言解析技术持开放态度。我也很好奇通常是如何解决这些问题的。扫描整个输入并匹配 open/closing braces/parentheses/etc 我假设??
下面是一个如何使用 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']
}