探索 V8 引擎:抽象语法树之旅,下部
2024-02-19 05:55:43
首先声明一下,这种长系列的大块头博客只能保证尽可能的深入到每一行源码,有些代码我不乐意深究就写个注释说明一下作用。另外,由于本地整理的比较好,博客就随心写了。整个 Compile 过程目前只看到 asmjs 之前,简单的过了几遍,大部分方法没有点进去看,实在是太复杂了。
上一篇的结尾指出:V8 在 Parse() 函数里生成的 AST 其实不完整,比如你写个 a = 10
,它解析到 parse = 等号后面的 10 就完事了。如果代码里只是这样使用的话,当然没问题,那如果是后面还有 .toString()
或其它方法呢?
function SimpleTest() {
var a = 10.toString();
var b = a.toUpperCase();
}
// start of 0
function SimpleTest() { // end of 1
var a = 10; // end of 2
var b = a.toString(); // end of 3
var b = b.toUpperCase(); // end of 4
}
第一步,TokenInfoVector 里只有这四个 Token:
TokenInfo start_token(Token::FUNCTION, 0, 1);
TokenInfo end_token(Token::FUNCTION, 1, 2);
TokenInfo start_var_token(Token::VAR, 2, 3);
TokenInfo end_var_token(Token::SEMI_COLON, 3, 4);
下一步,Parser::ParseVariableDeclaration() 其实就是把 VAR
和 SEMI_COLON
之间所有的 TokenInfo 作为 varDeclaration 的 AST:
ParseResult result = ParseVariableDeclaration(
&var_declarations, start_var_token.end_pos(), false);
然后 ParseResult
里的内容是这样的:
{
pos: 3,
end_pos: 4,
syntax_error: nullptr,
ast: var_declaration_node
};
var_declaration_node
的内容是这样的:
VariableDeclaration* var_declaration_node = new VariableDeclaration(
start_var_token.location().start_position(),
end_var_token.location().end_position(),
variable_declarations);
variable_declarations
里的内容是这样的:
Vector<const AstNode*> variable_declarations;
variable_declarations.push_back(new VariableProxy(
start_token.location().start_position(), end_token.location().end_position(),
start_token.literal()));
start_token.literal()
里的内容就是 a
,所以 variableProxy
里的内容就是:
VariableProxy* variableProxy = new VariableProxy(
start_token.location().start_position(), end_token.location().end_position(),
start_token.literal());
搞到这步,就有了第一个 varDeclaration AST 了。
function SimpleTest() {
VariableDeclaration a = 10;
}
还差 a.toString()
和 b.toUpperCase()
呢,那咱们继续往后走。
第五步,Parser::ParseExpression() 其实就是把 VAR
和 SEMI_COLON
之间所有的 TokenInfo 作为 expression 的 AST:
ParseResult result = ParseExpression(&expr, &next_token_info);
然后 ParseResult
里的内容是这样的:
{
pos: 3,
end_pos: 4,
syntax_error: nullptr,
ast: expression_node
};
expression_node
的内容是这样的:
Expression* expression_node = new Call(
start_token.location().start_position(), end_token.location().end_position(),
ast_result_for_call, 0);
ast_result_for_call
的内容是这样的:
ParseResult ast_result_for_call =
ParseMemberExpression(&function, false, &next_token_info);
ast_result_for_call
里的内容是这样的:
{
pos: 2,
end_pos: 3,
syntax_error: nullptr,
ast: ast_member_expr
};
ast_member_expr
的内容是这样的:
MemberExpression* ast_member_expr = new MemberExpression(
start_token.location().start_position(), end_token.location().end_position(),
VariableProxy(start_token.location().start_position(),
end_token.location().end_position(), start_token.literal()),
Token::PERIOD, ast_result_for_period);
ast_result_for_period
的内容是这样的:
ParseResult ast_result_for_period =
ParseIdentifier(&literal, &next_token_info);
ast_result_for_period
里的内容是这样的:
{
pos: 3,
end_pos: 4,
syntax_error: nullptr,
ast: ast_identifier
};
ast_identifier
的内容是这样的:
Identifier* ast_identifier = new Identifier(start_token.location().start_position(),
end_token.location().end_position(),
start_token.literal());
把这些东西组装一下,就有了第一个 expression AST 了。
function SimpleTest() {
VariableDeclaration a = 10.toString();
}
再往后走,来到了字符串字面量
function SimpleTest() {
var a = 10.toString();
var b = a.toUpperCase();
}
然后 ParseResult
里的内容是这样的:
{
pos: 4,
end_pos: 5,
syntax_error: nullptr,
ast: ast_literal
};
ast_literal
的内容是这样的:
Literal* ast_literal = new Literal(start_token.location().start_position(),
end_token.location().end_position(),
start_token.literal());
然后 start_token.literal()
里的内容就是 toUpperCase
,所以 ast_literal
里的内容就是:
Literal* ast_literal = new Literal(start_token.location().start_position(),
end_token.location().end_position(),
start_token.literal());
把这些东西组装一下,就有了第二个 expression AST 了。
function SimpleTest() {
VariableDeclaration a = 10.toString();
VariableDeclaration b = a.toUpperCase();
}
这样所有的 AST 都出来了,可以用一个 Block 把它们组装起来
function SimpleTest() {
VariableDeclaration a = 10.toString();
VariableDeclaration b = a.toUpperCase();
}
Block* block = new Block(
start_token.location().start_position(), end_token.location().end_position(),
var_declarations, exprs);
var_declarations
里的内容就是 VariableDeclaration a = 10.toString()
,exprs
里的内容就是 VariableDeclaration b = a.toUpperCase()
。
然后把 block
作为根节点,所有的 AST 都组装完成了。