⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parser.cc.svn-base

📁 Google浏览器V8内核代码
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:
  // 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 + -