先声明一下,这种长系列的大块头博客只能保证尽量的深刻到每一行源码,有些代码我不乐意深究就写个注释说明一下做用。另外,因为本地整理的比较好,博客就随心写了。
整个Compile过程目前只看到asmjs以前,简单的过了几遍,大部分方法没有点进去看,实在是太复杂了。上一篇的结尾指出了AST的入口,也就是命名空间parsing的一个公共方法,以下。
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
Parser parser(info);
FunctionLiteral* result = nullptr;
result = parser.ParseProgram(isolate, info);
info->set_literal(result);
return (result != nullptr);
}复制代码
所须要关心的核心代码就是这些,很是简单,Parser对象的初始化属性很是多,这里就不列出来了。
接下来进入第二个核心方法,即ParseProgram。
FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
scanner_.Initialize();
FunctionLiteral* result = DoParseProgram(isolate, info);
return result;
}复制代码
一样,所须要关心代码只有两行,其中第一步则是启动了scanner的初始化,第二步则是开始全面解析。
Scanner包含scanner、scanner-character-strams两个部分,其中stream则是通过初步处理的源String,必须转换后才能进行解析。处理的过程在以前省略的代码中,这里稍微给出大概的转换流程。
bool ParseProgram(ParseInfo* info, Isolate* isolate) {
Handle<String> source(String::cast(info->script()->source()), isolate);
std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(isolate, source));
info->set_character_stream(std::move(stream));
}
Utf16CharacterStream* ScannerStream::For(Isolate* isolate, Handle<String> data, int start_pos, int end_pos) {
size_t start_offset = 0;
if (data->IsSeqOneByteString()) {
return new BufferedCharacterStream<OnHeapStream>(
static_cast<size_t>(start_pos), Handle<SeqOneByteString>::cast(data),
start_offset, static_cast<size_t>(end_pos));
}
}复制代码
常规的字符串通常都是OneByteString,这里就不细讲了。最后返回一个特殊Stream类,其属性记录字符串的长度、当前的解析进度、解析的开始与结束标记等等。
将字符串转换后,就能够利用Scanner来进行逐步解析,在此以前,须要对Scanner类有一个简单的了解,以下。
class V8_EXPORT_PRIVATE Scanner {
public:
Token::Value peek() const { return next().token; }
const Location& location() const { return current().location; }
private:
uc32 c0_;
TokenDesc* current_;
TokenDesc* next_;
TokenDesc* next_next_;
Utf16CharacterStream* const source_;
}复制代码
选取了一些比较简单的属性和方法,Scanner内部有三个游标属性负责遍历字符串,分别是current_、next_、next_next_,字面意思理解就好了。source_则是以前说的转换Stream类,全部的解析实际上都是调用这个属性的方法。而两个结构体TokenDesc、Location也很是重要,一个负责词法描述,一个负责记录词法位置信息,以下。
struct TokenDesc {
Location location = {0, 0};
LiteralBuffer literal_chars;
LiteralBuffer raw_literal_chars;
Token::Value token = Token::UNINITIALIZED;
MessageTemplate invalid_template_escape_message = MessageTemplate::kNone;
Location invalid_template_escape_location;
uint32_t smi_value_ = 0;
bool after_line_terminator = false;
}复制代码
经过这个结构体和一些方法,就能完整的将源字符串逐步转换为抽象语法树。可是实际转换过程很是复杂,分支极多,后面再继续探究。