我刚刚完成了我的第一个(玩具)转译器的“版本 0”。有用。它将一串“伪 JavaScript”(具有附加功能的 JavaScript)转换为一串可运行的 JavaScript。现在,我想改进它。
其他 SO 用户可能最感兴趣的工作领域是:编译后的代码(即我的转译器的输出)不注意编码风格建议,如对一些较早的 SO 问题的接受答案中给出的。如果我手头有第二个转译器,该编码风格建议得到重视,我可以就哪个分支更有希望继续开发做出明智的决定——我想比较这两个分支的性能、开发时间需要,错误的数量等,并据此决定。
让我告诉你我的转译器处理的“附加 JS 功能”:“嵌套返回”。考虑像这样的闭包/嵌套函数
function myOuterFunc(){
... code ...
function innerFunc(){
... code ...
}
... code ...
}
(请注意,上面的 '...code...' 应该包括所有可能的 JS 代码,包括更多的嵌套函数声明,因此myOuterFunc
不一定是 的直接父级innerFunc
)
在上述情况下,假设您希望从myOuterFunc
内部某处返回结果- 不一定直接在内部 -innerFunc
实现“嵌套返回”后,您可以简单地编写
return.myOuterFunc result
这是使用此功能并做一些有意义的事情的(不可运行的)函数的示例
function multiDimensionalFind(isNeedle, haystack) {
// haystack is an array of arrays
// loop (recursively) through all ways of picking one element from each array in haystack
// feed the picked elements as array to isNeedle and return immediately when isNeedle gives true
// with those picked elements being the result, i.e. the 'found needle'
var LEVEL = haystack.length;
function inner(stack) {
var level = stack.length;
if (level >= LEVEL) {
if (isNeedle(stack)) return.multiDimensionalFind stack;
} else {
var arr = haystack[level];
for (var i = 0; i < arr.length; i++) {
inner(stack.concat([arr[i]]));
}
}
}
inner([]);
return 'not found'
}
这是我的转译器自动生成的(可运行的)代码(显然,注释是稍后添加/删除的),然后是一些代码测试该函数是否完成了它声称的工作(并且确实如此,你可以说服自己。 )
///////////// the function /////////////////
function multiDimensionalFind(isNeedle, haystack) {
try {
var LEVEL = haystack.length;
function inner(stack) {
var level = stack.length;
if (level >= LEVEL) {
if (isNeedle(stack)) throw stack;
} else {
var arr = haystack[level];
for (var i = 0; i < arr.length; i++) {
inner(stack.concat([arr[i]]));
}
}
}
inner([]);
return 'not found'
} catch(e){
// make sure "genuine" errors don't get destroyed or mishandled
if (e instanceof Error) throw e; else return e;
}
}
////////////////// test it //////////////////
content = document.getElementById('content');
function log2console(){
var digits = [0,1];
var haystack = [digits,digits,digits,digits,digits];
var str = '';
function isNeedle(stack){
str = str + ', ' + stack.join('')
return false;
}
multiDimensionalFind(isNeedle, haystack);
content.textContent = str;
}
function find71529(){ // second button
var digits = [0,1,2,3,4,5,6,7,8,9]
var haystack = [digits,digits,digits,digits,digits]
function isNeedle(stack){
return stack.reduce(function(b,i){ return 10*b+i; }, 0) === 71529
// returns true iff the stack contains [7,1,5,2,9]
}
content.textContent = multiDimensionalFind(
isNeedle, haystack
).join('_')
}
<button onclick='log2console()'>print binary numbers with 5 digits</button>
<br>
<button onclick='find71529()'>find something is 5d space</button>
<div id='content'></div>
你可以在这里玩我的这个小提琴中的转译器。我正在使用esprima 库,esprima之上的 escodegen.js 库,这是我自己的一个正在进行中的微小的抽象语法树生成库(请参阅小提琴中的脚本标签)。不是库的代码,也不是 UI 代码,即转译器的“真肉”只有不到 100 行(见函数transpile
)。所以这可能没有你想象的那么复杂。
我不记得我在哪里看到过风格推荐,但我可以肯定它实际上在多个地方。如果您知道或遇到这样一个问题,我邀请您将链接放入问题下方的评论中,我将标记为有用。到目前为止,只有一个链接,谢谢 Barmar。
你可能会问为什么我什至费心先写一个“不合规”的转译器,而不是马上去写“合规”的版本。这与估计的工作量有关。我估计“合规”版本的工作量要大得多。如此之多,以至于开始这样的努力似乎并不值得。我很想知道这种对工作量的评估是正确的还是错误的。因此问题。请不要暗示问题的修辞,甚至是不诚实的动机;不管对某些人来说听起来多么奇怪,我确实希望被证明是错误的,所以请不要以为我出于任何原因“只是这么说”,你会对我做一个不公正。这是,到目前为止,我投入最多的工作。而且,如果你问我,这是迄今为止我在这里问过的最好的问题。
除了有人帮助我编写转译器的“合规”版本之外,我还对任何客观可证明的东西感兴趣(尽管程度较低)有机会说服我“不合规”的方式是错误的方法。速度测试(带有 jsperf 的链接)、可重现的错误报告,诸如此类。
我应该提到到目前为止我自己进行的速度测试: