在 JavaScript AST 中遇到 EmptyStatement 的所有方式有哪些?
What are all the ways you can encounter an EmptyStatement in a JavaScript AST?
我正在写一个JS转译器,想知道我会遇到什么。除了晦涩难懂的 EmptyStatement
之外,我几乎处理了所有边缘情况。我遇到的一个地方是这里:
for (arrL = arr.length; arrL--; arr[arrL] *= baseIn);
AST 看起来像这样:
{
"type": "Program",
"body": [
{
"type": "BlockStatement",
"body": [
{
"type": "AssignmentExpression",
"left": {
"type": "Identifier",
"start": 4014,
"end": 4018,
"name": "arrL"
},
"right": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"start": 4021,
"end": 4024,
"name": "arr"
},
"property": {
"type": "Identifier",
"start": 4025,
"end": 4031,
"name": "length"
},
"computed": false
},
"operator": "="
},
{
"type": "WhileStatement",
"test": {
"type": "Literal",
"value": true,
"raw": "true"
},
"body": {
"type": "BlockStatement",
"body": [
{
"type": "IfStatement",
"test": {
"type": "UpdateExpression",
"argument": {
"type": "Identifier",
"start": 4033,
"end": 4037,
"name": "arrL"
},
"operator": "--",
"prefix": false
},
"consequent": {
"type": "BlockStatement",
"body": [
{
"type": "EmptyStatement",
"start": 4061,
"end": 4062
},
{
"type": "AssignmentExpression",
"left": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"start": 4041,
"end": 4044,
"name": "arr"
},
"property": {
"type": "Identifier",
"start": 4045,
"end": 4049,
"name": "arrL"
},
"computed": true
},
"right": {
"type": "Identifier",
"start": 4054,
"end": 4060,
"name": "baseIn"
},
"operator": "*="
}
]
},
"alternate": {
"type": "BlockStatement",
"body": [
{
"type": "BreakStatement"
}
]
}
}
]
}
}
]
}
]
}
我什至不知道 EmptyStatement
指的是什么哈哈。你 运行 变成 EmptyStatement
的其他情况是什么?
如果您仔细查看 for
语句,您会发现它的正文仅包含 ;
。那是一句空话。你会得到同样的效果,比如说,
if (a--);
尽管许多风格指南不鼓励这样做。 {}
更清楚了,恕我直言。那是一个空块,而不是一个空语句。 {;}
将是一个仅由空语句组成的块,这也很少见,但您可能会发现类似的内容:
if (debugging) {
/* Commented out for now */ ;
}
那么,什么是空语句?这是一个只有分号终止符的语句。空的,正如它所说。
有趣的是,for
语句已经被脱糖,这可能会造成混淆。但这是正确的; for(init; test; advance) body;
在语义上等同于
{
init;
while(true) {
if (test) {
body;
advance;
}
else
break;
}
}
显然,即使它对 for
语句进行了脱糖处理,它仍保留了空主体。这可能是为了有一个地方来挂起行号,或者可能只是为了更容易将其留在解析中的那个位置。将(隐式)while (test) { ... }
奇怪地转换为 while (true) { if (test) { ... } else break; }
可能是为了简化基本块的分解,或者启用重新排序代码的标准优化。不过只是猜测。
我正在写一个JS转译器,想知道我会遇到什么。除了晦涩难懂的 EmptyStatement
之外,我几乎处理了所有边缘情况。我遇到的一个地方是这里:
for (arrL = arr.length; arrL--; arr[arrL] *= baseIn);
AST 看起来像这样:
{
"type": "Program",
"body": [
{
"type": "BlockStatement",
"body": [
{
"type": "AssignmentExpression",
"left": {
"type": "Identifier",
"start": 4014,
"end": 4018,
"name": "arrL"
},
"right": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"start": 4021,
"end": 4024,
"name": "arr"
},
"property": {
"type": "Identifier",
"start": 4025,
"end": 4031,
"name": "length"
},
"computed": false
},
"operator": "="
},
{
"type": "WhileStatement",
"test": {
"type": "Literal",
"value": true,
"raw": "true"
},
"body": {
"type": "BlockStatement",
"body": [
{
"type": "IfStatement",
"test": {
"type": "UpdateExpression",
"argument": {
"type": "Identifier",
"start": 4033,
"end": 4037,
"name": "arrL"
},
"operator": "--",
"prefix": false
},
"consequent": {
"type": "BlockStatement",
"body": [
{
"type": "EmptyStatement",
"start": 4061,
"end": 4062
},
{
"type": "AssignmentExpression",
"left": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"start": 4041,
"end": 4044,
"name": "arr"
},
"property": {
"type": "Identifier",
"start": 4045,
"end": 4049,
"name": "arrL"
},
"computed": true
},
"right": {
"type": "Identifier",
"start": 4054,
"end": 4060,
"name": "baseIn"
},
"operator": "*="
}
]
},
"alternate": {
"type": "BlockStatement",
"body": [
{
"type": "BreakStatement"
}
]
}
}
]
}
}
]
}
]
}
我什至不知道 EmptyStatement
指的是什么哈哈。你 运行 变成 EmptyStatement
的其他情况是什么?
如果您仔细查看 for
语句,您会发现它的正文仅包含 ;
。那是一句空话。你会得到同样的效果,比如说,
if (a--);
尽管许多风格指南不鼓励这样做。 {}
更清楚了,恕我直言。那是一个空块,而不是一个空语句。 {;}
将是一个仅由空语句组成的块,这也很少见,但您可能会发现类似的内容:
if (debugging) {
/* Commented out for now */ ;
}
那么,什么是空语句?这是一个只有分号终止符的语句。空的,正如它所说。
有趣的是,for
语句已经被脱糖,这可能会造成混淆。但这是正确的; for(init; test; advance) body;
在语义上等同于
{
init;
while(true) {
if (test) {
body;
advance;
}
else
break;
}
}
显然,即使它对 for
语句进行了脱糖处理,它仍保留了空主体。这可能是为了有一个地方来挂起行号,或者可能只是为了更容易将其留在解析中的那个位置。将(隐式)while (test) { ... }
奇怪地转换为 while (true) { if (test) { ... } else break; }
可能是为了简化基本块的分解,或者启用重新排序代码的标准优化。不过只是猜测。