📄 parser.cc.svn-base
字号:
LexicalScope lexical_scope(this, scope); TemporaryScope temp_scope(this); ZoneListWrapper<Statement> body(16); bool ok = true; ParseSourceElements(&body, Token::EOS, &ok); if (ok) { result = NEW(FunctionLiteral(no_name, top_scope_, body.elements(), temp_scope.materialized_literal_count(), temp_scope.contains_array_literal(), temp_scope.expected_property_count(), 0, 0, source->length(), false)); } else if (scanner().stack_overflow()) { Top::StackOverflow(); } } // Make sure the target stack is empty. ASSERT(target_stack_ == NULL); // If there was a syntax error we have to get rid of the AST // and it is not safe to do so before the scope has been deleted. if (result == NULL) zone_scope.DeleteOnExit(); return result;}FunctionLiteral* Parser::ParseLazy(Handle<String> source, Handle<String> name, int start_position, bool is_expression) { ZoneScope zone_scope(DONT_DELETE_ON_EXIT); StatsRateScope timer(&Counters::parse_lazy); Counters::total_parse_size.Increment(source->length()); SafeStringInputBuffer buffer(source.location()); // Initialize parser state. source->TryFlatten(); scanner_.Init(source, &buffer, start_position); ASSERT(target_stack_ == NULL); mode_ = PARSE_EAGERLY; // Place holder for the result. FunctionLiteral* result = NULL; { // Parse the function literal. Handle<String> no_name = factory()->EmptySymbol(); Scope* scope = factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); LexicalScope lexical_scope(this, scope); TemporaryScope temp_scope(this); FunctionLiteralType type = is_expression ? EXPRESSION : DECLARATION; bool ok = true; result = ParseFunctionLiteral(name, RelocInfo::kNoPosition, type, &ok); // Make sure the results agree. ASSERT(ok == (result != NULL)); // The only errors should be stack overflows. ASSERT(ok || scanner_.stack_overflow()); } // Make sure the target stack is empty. ASSERT(target_stack_ == NULL); // If there was a stack overflow we have to get rid of AST and it is // not safe to do before scope has been deleted. if (result == NULL) { Top::StackOverflow(); zone_scope.DeleteOnExit(); } return result;}void Parser::ReportMessage(const char* type, Vector<const char*> args) { Scanner::Location source_location = scanner_.location(); ReportMessageAt(source_location, type, args);}void AstBuildingParser::ReportMessageAt(Scanner::Location source_location, const char* type, Vector<const char*> args) { MessageLocation location(script_, source_location.beg_pos, source_location.end_pos); Handle<JSArray> array = Factory::NewJSArray(args.length()); for (int i = 0; i < args.length(); i++) { SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i]))); } Handle<Object> result = Factory::NewSyntaxError(type, array); Top::Throw(*result, &location);}void PreParser::ReportMessageAt(Scanner::Location source_location, const char* type, Vector<const char*> args) { recorder()->LogMessage(source_location, type, args);}void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, int end_token, bool* ok) { // SourceElements :: // (Statement)* <end_token> // Allocate a target stack to use for this set of source // elements. This way, all scripts and functions get their own // target stack thus avoiding illegal breaks and continues across // functions. TargetScope scope(this); ASSERT(processor != NULL); while (peek() != end_token) { Statement* stat = ParseStatement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) processor->Add(stat); } return 0;}Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // Statement :: // Block // VariableStatement // EmptyStatement // ExpressionStatement // IfStatement // IterationStatement // ContinueStatement // BreakStatement // ReturnStatement // WithStatement // LabelledStatement // SwitchStatement // ThrowStatement // TryStatement // DebuggerStatement // Note: Since labels can only be used by 'break' and 'continue' // statements, which themselves are only valid within blocks, // iterations or 'switch' statements (i.e., BreakableStatements), // labels can be simply ignored in all other cases; except for // trivial labelled break statements 'label: break label' which is // parsed into an empty statement. // Keep the source position of the statement int statement_pos = scanner().peek_location().beg_pos; Statement* stmt = NULL; switch (peek()) { case Token::LBRACE: return ParseBlock(labels, ok); case Token::CONST: // fall through case Token::VAR: stmt = ParseVariableStatement(ok); break; case Token::SEMICOLON: Next(); return factory()->EmptyStatement(); case Token::IF: stmt = ParseIfStatement(labels, ok); break; case Token::DO: stmt = ParseDoStatement(labels, ok); break; case Token::WHILE: stmt = ParseWhileStatement(labels, ok); break; case Token::FOR: stmt = ParseForStatement(labels, ok); break; case Token::CONTINUE: stmt = ParseContinueStatement(ok); break; case Token::BREAK: stmt = ParseBreakStatement(labels, ok); break; case Token::RETURN: stmt = ParseReturnStatement(ok); break; case Token::WITH: stmt = ParseWithStatement(labels, ok); break; case Token::SWITCH: stmt = ParseSwitchStatement(labels, ok); break; case Token::THROW: stmt = ParseThrowStatement(ok); break; case Token::TRY: { // NOTE: It is somewhat complicated to have labels on // try-statements. When breaking out of a try-finally statement, // one must take great care not to treat it as a // fall-through. It is much easier just to wrap the entire // try-statement in a statement block and put the labels there Block* result = NEW(Block(labels, 1, false)); Target target(this, result); TryStatement* statement = ParseTryStatement(CHECK_OK); if (result) result->AddStatement(statement); return result; } case Token::FUNCTION: return ParseFunctionDeclaration(ok); case Token::NATIVE: return ParseNativeDeclaration(ok); case Token::DEBUGGER: stmt = ParseDebuggerStatement(ok); break; default: stmt = ParseExpressionOrLabelledStatement(labels, ok); } // Store the source position of the statement if (stmt != NULL) stmt->set_statement_pos(statement_pos); return stmt;}VariableProxy* AstBuildingParser::Declare(Handle<String> name, Variable::Mode mode, FunctionLiteral* fun, bool resolve, bool* ok) { Variable* var = NULL; // If we are inside a function, a declaration of a variable // is a truly local variable, and the scope of the variable // is always the function scope. // If a function scope exists, then we can statically declare this // variable and also set its mode. In any case, a Declaration node // will be added to the scope so that the declaration can be added // to the corresponding activation frame at runtime if necessary. // For instance declarations inside an eval scope need to be added // to the calling function context. if (top_scope_->is_function_scope()) { // Declare the variable in the function scope. var = top_scope_->Lookup(name); if (var == NULL) { // Declare the name. var = top_scope_->Declare(name, mode); } else { // The name was declared before; check for conflicting // re-declarations. If the previous declaration was a const or the // current declaration is a const then we have a conflict. There is // similar code in runtime.cc in the Declare functions. if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) { // We only have vars and consts in declarations. ASSERT(var->mode() == Variable::VAR || var->mode() == Variable::CONST); const char* type = (var->mode() == Variable::VAR) ? "var" : "const"; Handle<String> type_string = Factory::NewStringFromUtf8(CStrVector(type), TENURED); Expression* expression = NewThrowTypeError(Factory::redeclaration_symbol(), type_string, name); top_scope_->SetIllegalRedeclaration(expression); } } } // We add a declaration node for every declaration. The compiler // will only generate code if necessary. In particular, declarations // for inner local variables that do not represent functions won't // result in any generated code. // // Note that we always add an unresolved proxy even if it's not // used, simply because we don't know in this method (w/o extra // parameters) if the proxy is needed or not. The proxy will be // bound during variable resolution time unless it was pre-bound // below. // // WARNING: This will lead to multiple declaration nodes for the // same variable if it is declared several times. This is not a // semantic issue as long as we keep the source order, but it may be // a performance issue since it may lead to repeated // Runtime::DeclareContextSlot() calls. VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with()); top_scope_->AddDeclaration(NEW(Declaration(proxy, mode, fun))); // For global const variables we bind the proxy to a variable. if (mode == Variable::CONST && top_scope_->is_global_scope()) { ASSERT(resolve); // should be set by all callers var = NEW(Variable(top_scope_, name, Variable::CONST, true, false)); } // If requested and we have a local variable, bind the proxy to the variable // at parse-time. This is used for functions (and consts) declared inside // statements: the corresponding function (or const) variable must be in the // function scope and not a statement-local scope, e.g. as provided with a // 'with' statement: // // with (obj) { // function f() {} // } // // which is translated into: // // with (obj) { // // in this case this is not: 'var f; f = function () {};' // var f = function () {}; // } // // Note that if 'f' is accessed from inside the 'with' statement, it // will be allocated in the context (because we must be able to look // it up dynamically) but it will also be accessed statically, i.e., // with a context slot index and a context chain length for this // initialization code. Thus, inside the 'with' statement, we need // both access to the static and the dynamic context chain; the // runtime needs to provide both. if (resolve && var != NULL) proxy->BindTo(var); return proxy;}// Language extension which is only enabled for source files loaded// through the API's extension mechanism. A native function// declaration is resolved by looking up the function through a// callback provided by the extension.Statement* Parser::ParseNativeDeclaration(bool* ok) { if (extension_ == NULL) { ReportUnexpectedToken(Token::NATIVE); *ok = false; return NULL; } Expect(Token::NATIVE, CHECK_OK); Expect(Token::FUNCTION, CHECK_OK); Handle<String> name = ParseIdentifier(CHECK_OK); Expect(Token::LPAREN, CHECK_OK); bool done = (peek() == Token::RPAREN); while (!done) { ParseIdentifier(CHECK_OK); done = (peek() == Token::RPAREN); if (!done) Expect(Token::COMMA, CHECK_OK); } Expect(Token::RPAREN, CHECK_OK); Expect(Token::SEMICOLON, CHECK_OK); if (is_pre_parsing_) return NULL; // Make sure that the function containing the native declaration // isn't lazily compiled. The extension structures are only // accessible while parsing the first time not when reparsing // because of lazy compilation. top_scope_->ForceEagerCompilation(); // Compute the function template for the native function. v8::Handle<v8::FunctionTemplate> fun_template = extension_->GetNativeFunction(v8::Utils::ToLocal(name)); ASSERT(!fun_template.IsEmpty()); // Instantiate the function and create a boilerplate function from it. Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction()); const int literals = fun->NumberOfLiterals(); Handle<Code> code = Handle<Code>(fun->shared()->code()); Handle<JSFunction> boilerplate = Factory::NewFunctionBoilerplate(name, literals, false, code); // Copy the function data to the boilerplate. Used by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -