返回

探索 V8 引擎:抽象语法树之旅,下部

前端

首先声明一下,这种长系列的大块头博客只能保证尽可能的深入到每一行源码,有些代码我不乐意深究就写个注释说明一下作用。另外,由于本地整理的比较好,博客就随心写了。整个 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() 其实就是把 VARSEMI_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() 其实就是把 VARSEMI_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 都组装完成了。