📄 parser.cc.svn-base
字号:
// builtins.cc:HandleApiCall to perform argument type checks and to // find the right native code to call. boilerplate->shared()->set_function_data(fun->shared()->function_data()); int parameters = fun->shared()->formal_parameter_count(); boilerplate->shared()->set_formal_parameter_count(parameters); // TODO(1240846): It's weird that native function declarations are // introduced dynamically when we meet their declarations, whereas // other functions are setup when entering the surrounding scope. FunctionBoilerplateLiteral* lit = NEW(FunctionBoilerplateLiteral(boilerplate)); VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK); return NEW(ExpressionStatement( new Assignment(Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)));}Statement* Parser::ParseFunctionDeclaration(bool* ok) { // Parse a function literal. We may or may not have a function name. // If we have a name we use it as the variable name for the function // (a function declaration) and not as the function name of a function // expression. Expect(Token::FUNCTION, CHECK_OK); int function_token_position = scanner().location().beg_pos; Handle<String> name; if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK); FunctionLiteral* fun = ParseFunctionLiteral(name, function_token_position, DECLARATION, CHECK_OK); if (name.is_null()) { // We don't have a name - it is always an anonymous function // expression. return NEW(ExpressionStatement(fun)); } else { // We have a name so even if we're not at the top-level of the // global or a function scope, we treat is as such and introduce // the function with it's initial value upon entering the // corresponding scope. Declare(name, Variable::VAR, fun, true, CHECK_OK); return factory()->EmptyStatement(); }}Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { // Block :: // '{' Statement* '}' // Note that a Block does not introduce a new execution scope! // (ECMA-262, 3rd, 12.2) // // Construct block expecting 16 statements. Block* result = NEW(Block(labels, 16, false)); Target target(this, result); Expect(Token::LBRACE, CHECK_OK); while (peek() != Token::RBRACE) { Statement* stat = ParseStatement(NULL, CHECK_OK); if (stat && !stat->IsEmpty()) result->AddStatement(stat); } Expect(Token::RBRACE, CHECK_OK); return result;}Block* Parser::ParseVariableStatement(bool* ok) { // VariableStatement :: // VariableDeclarations ';' Expression* dummy; // to satisfy the ParseVariableDeclarations() signature Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK); ExpectSemicolon(CHECK_OK); return result;}// If the variable declaration declares exactly one non-const// variable, then *var is set to that variable. In all other cases,// *var is untouched; in particular, it is the caller's responsibility// to initialize it properly. This mechanism is used for the parsing// of 'for-in' loops.Block* Parser::ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok) { // VariableDeclarations :: // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] Variable::Mode mode = Variable::VAR; bool is_const = false; if (peek() == Token::VAR) { Consume(Token::VAR); } else if (peek() == Token::CONST) { Consume(Token::CONST); mode = Variable::CONST; is_const = true; } else { UNREACHABLE(); // by current callers } // The scope of a variable/const declared anywhere inside a function // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can // transform a source-level variable/const declaration into a (Function) // Scope declaration, and rewrite the source-level initialization into an // assignment statement. We use a block to collect multiple assignments. // // We mark the block as initializer block because we don't want the // rewriter to add a '.result' assignment to such a block (to get compliant // behavior for code such as print(eval('var x = 7')), and for cosmetic // reasons when pretty-printing. Also, unless an assignment (initialization) // is inside an initializer block, it is ignored. // // Create new block with one expected declaration. Block* block = NEW(Block(NULL, 1, true)); VariableProxy* last_var = NULL; // the last variable declared int nvars = 0; // the number of variables declared do { // Parse variable name. if (nvars > 0) Consume(Token::COMMA); Handle<String> name = ParseIdentifier(CHECK_OK); // Declare variable. // Note that we *always* must treat the initial value via a separate init // assignment for variables and constants because the value must be assigned // when the variable is encountered in the source. But the variable/constant // is declared (and set to 'undefined') upon entering the function within // which the variable or constant is declared. Only function variables have // an initial value in the declaration (because they are initialized upon // entering the function). // // If we have a const declaration, in an inner scope, the proxy is always // bound to the declared variable (independent of possibly surrounding with // statements). last_var = Declare(name, mode, NULL, is_const /* always bound for CONST! */, CHECK_OK); nvars++; // Parse initialization expression if present and/or needed. A // declaration of the form: // // var v = x; // // is syntactic sugar for: // // var v; v = x; // // In particular, we need to re-lookup 'v' as it may be a // different 'v' than the 'v' in the declaration (if we are inside // a 'with' statement that makes a object property with name 'v' // visible). // // However, note that const declarations are different! A const // declaration of the form: // // const c = x; // // is *not* syntactic sugar for: // // const c; c = x; // // The "variable" c initialized to x is the same as the declared // one - there is no re-lookup (see the last parameter of the // Declare() call above). Expression* value = NULL; int position = -1; if (peek() == Token::ASSIGN) { Expect(Token::ASSIGN, CHECK_OK); position = scanner().location().beg_pos; value = ParseAssignmentExpression(accept_IN, CHECK_OK); } // Make sure that 'const c' actually initializes 'c' to undefined // even though it seems like a stupid thing to do. if (value == NULL && is_const) { value = GetLiteralUndefined(); } // Global variable declarations must be compiled in a specific // way. When the script containing the global variable declaration // is entered, the global variable must be declared, so that if it // doesn't exist (not even in a prototype of the global object) it // gets created with an initial undefined value. This is handled // by the declarations part of the function representing the // top-level global code; see Runtime::DeclareGlobalVariable. If // it already exists (in the object or in a prototype), it is // *not* touched until the variable declaration statement is // executed. // // Executing the variable declaration statement will always // guarantee to give the global object a "local" variable; a // variable defined in the global object and not in any // prototype. This way, global variable declarations can shadow // properties in the prototype chain, but only after the variable // declaration statement has been executed. This is important in // browsers where the global object (window) has lots of // properties defined in prototype objects. if (!is_pre_parsing_ && top_scope_->is_global_scope()) { // Compute the arguments for the runtime call. ZoneList<Expression*>* arguments = new ZoneList<Expression*>(2); // Be careful not to assign a value to the global variable if // we're in a with. The initialization value should not // necessarily be stored in the global object in that case, // which is why we need to generate a separate assignment node. arguments->Add(NEW(Literal(name))); // we have at least 1 parameter if (is_const || (value != NULL && !inside_with())) { arguments->Add(value); value = NULL; // zap the value to avoid the unnecessary assignment } // Construct the call to Runtime::DeclareGlobal{Variable,Const}Locally // and add it to the initialization statement block. Note that // this function does different things depending on if we have // 1 or 2 parameters. CallRuntime* initialize; if (is_const) { initialize = NEW(CallRuntime( Factory::InitializeConstGlobal_symbol(), Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments)); } else { initialize = NEW(CallRuntime( Factory::InitializeVarGlobal_symbol(), Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments)); } block->AddStatement(NEW(ExpressionStatement(initialize))); } // Add an assignment node to the initialization statement block if // we still have a pending initialization value. We must distinguish // between variables and constants: Variable initializations are simply // assignments (with all the consequences if they are inside a 'with' // statement - they may change a 'with' object property). Constant // initializations always assign to the declared constant which is // always at the function scope level. This is only relevant for // dynamically looked-up variables and constants (the start context // for constant lookups is always the function context, while it is // the top context for variables). Sigh... if (value != NULL) { Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR); Assignment* assignment = NEW(Assignment(op, last_var, value, position)); if (block) block->AddStatement(NEW(ExpressionStatement(assignment))); } } while (peek() == Token::COMMA); if (!is_const && nvars == 1) { // We have a single, non-const variable. if (is_pre_parsing_) { // If we're preparsing then we need to set the var to something // in order for for-in loops to parse correctly. *var = ValidLeftHandSideSentinel::instance(); } else { ASSERT(last_var != NULL); *var = last_var; } } return block;}static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) { ASSERT(!label.is_null()); if (labels != NULL) for (int i = labels->length(); i-- > 0; ) if (labels->at(i).is_identical_to(label)) return true; return false;}Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, bool* ok) { // ExpressionStatement | LabelledStatement :: // Expression ';' // Identifier ':' Statement Expression* expr = ParseExpression(true, CHECK_OK); if (peek() == Token::COLON && expr && expr->AsVariableProxy() != NULL && !expr->AsVariableProxy()->is_this()) { VariableProxy* var = expr->AsVariableProxy(); Handle<String> label = var->name(); // TODO(1240780): We don't check for redeclaration of labels // during preparsing since keeping track of the set of active // labels requires nontrivial changes to the way scopes are // structured. However, these are probably changes we want to // make later anyway so we should go back and fix this then. if (!is_pre_parsing_) { if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS); const char* elms[2] = { "Label", *c_string }; Vector<const char*> args(elms, 2); ReportMessage("redeclaration", args); *ok = false; return NULL; } if (labels == NULL) labels = new ZoneStringList(4); labels->Add(label); // Remove the "ghost" variable that turned out to be a label // from the top scope. This way, we don't try to resolve it // during the scope processing. top_scope_->RemoveUnresolved(var); } Expect(Token::COLON, CHECK_OK); return ParseStatement(labels, ok); } // Parsed expression statement. ExpectSemicolon(CHECK_OK); return NEW(ExpressionStatement(expr));}IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) { // IfStatement :: // 'if' '(' Expression ')' Statement ('else' Statement)? Expect(Token::IF, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); Expression* condition = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); Statement* then_statement = ParseStatement(labels, CHECK_OK); Statement* else_statement = NULL; if (peek() == Token::ELSE) { Next(); else_statement = ParseStatement(labels, CHECK_OK); } else if (!is_pre_parsing_) { else_statement = factory()->EmptyStatement(); } return NEW(IfStatement(condition, then_statement, else_statement));}Statement* Parser::ParseContinueStatement(bool* ok) { // ContinueStatement :: // 'continue' Identifier? ';' Expect(Token::CONTINUE, CHECK_OK); Handle<String> label(static_cast<String**>(NULL)); Token::Value tok = peek(); if (!scanner_.has_line_terminator_before_next() && tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { label = ParseIdentifier(CHECK_OK); } IterationStatement* target = NULL; if (!is_pre_parsing_) { target = LookupContinueTarget(label, CHECK_OK); if (target == NULL) { // Illegal continue statement. To be consistent with KJS we delay // reporting of the syntax error until runtime. Handle<String> error_type = Factory::illegal_continue_symbol(); if (!label.is_null()) error_type = Factory::unknown_label_symbol(); Expression* throw_error = NewThrowSyntaxError(error_type, label); return NEW(ExpressionStatement(throw_error)); } } ExpectSemicolon(CHECK_OK); return NEW(ContinueStatement(target));}Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { // BreakStatement :: // 'break' Identifier? ';' Expect(Token::BREAK, CHECK_OK); Handle<String> label; Token::Value tok = peek(); if (!scanner_.has_line_terminator_before_next() && tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { label = ParseIdentifier(CHECK_OK); } // Parse labelled break statements that target themselves into
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -