昨天跟友人一起大块欢饮之后,问了一个比较好玩的问题? JSON.parse 是怎么实现?当时草草的中规中矩的回答了一番,但终究对自己无知不是很满意
今天上午想起来之后,便迅速翻出node的源码来一探究竟!
对js的解析无疑是 v8的专属,但由于v8是由c++编写,我对c++的各种语法了解比较一般,如果有描述错误的地方,还请各位大神斧正.
v8的git地址 https://chromium.googlesource.com/v8/v8.git 需要FQ
node的官网 https://nodejs.org , 如果速度慢可以直接访问 http://nodejs.cn/
我是在node源码的deps找到的v8的相关代码
在v8的src文件夹中 直接全局搜索 JSON::Parse ( c++的语法 ) 可以找到对应代码编写在 api.cc文件中,具体代码如下:
在刚刚的搜索结果中,找到一个简单的json parse,我们就从这里入手
这个例子里面关键的代码不多,主要是
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
JsonParser(isolate, source).ParseJson(), Object);
对string做处理的是 JSONParse对象的ParseJson函数,然后继续全局搜索 JSONParse,在 json-parser.cc中找到了ParseJson的相关代码
template <bool seq_one_byte> MaybeHandle<Object> JsonParser<seq_one_byte>::ParseJson() { // Advance to the first character (possibly EOS) AdvanceSkipWhitespace(); Handle<Object> result = ParseJsonValue(); if (result.is_null() || c0_ != kEndOfString) { // Some exception (for example stack overflow) is already pending. if (isolate_->has_pending_exception()) return Handle<Object>::null(); // Parse failed. Current character is the unexpected token. Factory* factory = this->factory(); MessageTemplate::Template message; Handle<Object> arg1 = Handle<Smi>(Smi::FromInt(position_), isolate()); Handle<Object> arg2; switch (c0_) { case kEndOfString: message = MessageTemplate::kJsonParseUnexpectedEOS; break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': message = MessageTemplate::kJsonParseUnexpectedTokenNumber; break; case '"': message = MessageTemplate::kJsonParseUnexpectedTokenString; break; default: message = MessageTemplate::kJsonParseUnexpectedToken; arg2 = arg1; arg1 = factory->LookupSingleCharacterStringFromCode(c0_); break; } Handle<Script> script(factory->NewScript(source_)); // We should sent compile error event because we compile JSON object in // separated source file. isolate()->debug()->OnCompileError(script); MessageLocation location(script, position_, position_ + 1); Handle<Object> error = factory->NewSyntaxError(message, arg1, arg2); return isolate()->template Throw<Object>(error, &location); } return result; }