Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: src/parser.cc

Issue 6144005: Early draft of strict mode (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 *with_nesting_level_variable_ = prev_level_; 554 *with_nesting_level_variable_ = prev_level_;
555 } 555 }
556 556
557 private: 557 private:
558 Scope** scope_variable_; 558 Scope** scope_variable_;
559 int* with_nesting_level_variable_; 559 int* with_nesting_level_variable_;
560 Scope* prev_scope_; 560 Scope* prev_scope_;
561 int prev_level_; 561 int prev_level_;
562 }; 562 };
563 563
564 // ----------------------------------------------------------------------------
565 // Support for strict mode parser stack. The constructor saves the current
566 // state and the destructor resets it back.
567 class StrictMode BASE_EMBEDDED {
568 public:
569 StrictMode(bool* strict_mode_variable)
570 : strict_mode_variable_(strict_mode_variable),
571 previous_strict_mode_(*strict_mode_variable) {
572 }
573
574 ~StrictMode() {
575 *strict_mode_variable_ = previous_strict_mode_;
576 }
577
578 bool *const strict_mode_variable_;
579 const bool previous_strict_mode_;
580 };
564 581
565 // ---------------------------------------------------------------------------- 582 // ----------------------------------------------------------------------------
566 // The CHECK_OK macro is a convenient macro to enforce error 583 // The CHECK_OK macro is a convenient macro to enforce error
567 // handling for functions that may fail (by returning !*ok). 584 // handling for functions that may fail (by returning !*ok).
568 // 585 //
569 // CAUTION: This macro appends extra statements after a call, 586 // CAUTION: This macro appends extra statements after a call,
570 // thus it must never be used where only a single statement 587 // thus it must never be used where only a single statement
571 // is correct (e.g. an if statement branch w/o braces)! 588 // is correct (e.g. an if statement branch w/o braces)!
572 589
573 #define CHECK_OK ok); \ 590 #define CHECK_OK ok); \
(...skipping 19 matching lines...) Expand all
593 script_(script), 610 script_(script),
594 scanner_(), 611 scanner_(),
595 top_scope_(NULL), 612 top_scope_(NULL),
596 with_nesting_level_(0), 613 with_nesting_level_(0),
597 temp_scope_(NULL), 614 temp_scope_(NULL),
598 target_stack_(NULL), 615 target_stack_(NULL),
599 allow_natives_syntax_(allow_natives_syntax), 616 allow_natives_syntax_(allow_natives_syntax),
600 extension_(extension), 617 extension_(extension),
601 pre_data_(pre_data), 618 pre_data_(pre_data),
602 fni_(NULL), 619 fni_(NULL),
603 stack_overflow_(false) { 620 stack_overflow_(false),
621 strict_mode_(false) {
604 AstNode::ResetIds(); 622 AstNode::ResetIds();
605 } 623 }
606 624
607 625
608 FunctionLiteral* Parser::ParseProgram(Handle<String> source, 626 FunctionLiteral* Parser::ParseProgram(Handle<String> source,
609 bool in_global_context) { 627 bool in_global_context) {
610 CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); 628 CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
611 629
612 HistogramTimerScope timer(&Counters::parse); 630 HistogramTimerScope timer(&Counters::parse);
613 Counters::total_parse_size.Increment(source->length()); 631 Counters::total_parse_size.Increment(source->length());
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 top_scope_, 679 top_scope_,
662 body, 680 body,
663 temp_scope.materialized_literal_count(), 681 temp_scope.materialized_literal_count(),
664 temp_scope.expected_property_count(), 682 temp_scope.expected_property_count(),
665 temp_scope.only_simple_this_property_assignments(), 683 temp_scope.only_simple_this_property_assignments(),
666 temp_scope.this_property_assignments(), 684 temp_scope.this_property_assignments(),
667 0, 685 0,
668 0, 686 0,
669 source->length(), 687 source->length(),
670 false, 688 false,
671 temp_scope.ContainsLoops()); 689 temp_scope.ContainsLoops(),
690 strict_mode_);
672 } else if (stack_overflow_) { 691 } else if (stack_overflow_) {
673 Top::StackOverflow(); 692 Top::StackOverflow();
674 } 693 }
675 } 694 }
676 695
677 // Make sure the target stack is empty. 696 // Make sure the target stack is empty.
678 ASSERT(target_stack_ == NULL); 697 ASSERT(target_stack_ == NULL);
679 698
680 // If there was a syntax error we have to get rid of the AST 699 // If there was a syntax error we have to get rid of the AST
681 // and it is not safe to do so before the scope has been deleted. 700 // and it is not safe to do so before the scope has been deleted.
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 1070
1052 // Allocate a target stack to use for this set of source 1071 // Allocate a target stack to use for this set of source
1053 // elements. This way, all scripts and functions get their own 1072 // elements. This way, all scripts and functions get their own
1054 // target stack thus avoiding illegal breaks and continues across 1073 // target stack thus avoiding illegal breaks and continues across
1055 // functions. 1074 // functions.
1056 TargetScope scope(&this->target_stack_); 1075 TargetScope scope(&this->target_stack_);
1057 1076
1058 ASSERT(processor != NULL); 1077 ASSERT(processor != NULL);
1059 InitializationBlockFinder block_finder; 1078 InitializationBlockFinder block_finder;
1060 ThisNamedPropertyAssigmentFinder this_property_assignment_finder; 1079 ThisNamedPropertyAssigmentFinder this_property_assignment_finder;
1080 bool directive_prologue = true; // Parsing directive prologue.
1081
1061 while (peek() != end_token) { 1082 while (peek() != end_token) {
1083 if (!strict_mode_ && directive_prologue) {
1084 if (peek() == Token::STRING) {
Lasse Reichstein 2011/01/13 07:18:40 As you pointed out, this is too simple (and ECMASc
Lasse Reichstein 2011/01/13 07:44:07 Argh, location should be: Scanner::Location loca
Martin Maly 2011/01/14 00:06:28 Done. However, we still need to add the directives
Lasse Reichstein 2011/01/14 11:42:05 I don't see how that example applies. The "Hello"
Martin Maly 2011/01/14 16:30:43 Sorry, the example was incorrect eval("'hello'").
Lasse Reichstein 2011/01/17 10:17:49 Ack, yes, now I see.
1085 // "use strict" is an ascii literal so no need to check non-ascii ones.
1086 if (scanner().is_next_literal_ascii() &&
1087 Factory::use_strict()->IsAsciiEqualTo(
1088 scanner().next_literal_ascii_string())) {
1089 strict_mode_ = true;
1090 }
1091 } else {
1092 // done with directive prologue
1093 directive_prologue = false;
1094 }
1095 }
1096
1062 Statement* stat = ParseStatement(NULL, CHECK_OK); 1097 Statement* stat = ParseStatement(NULL, CHECK_OK);
1063 if (stat == NULL || stat->IsEmpty()) continue; 1098 if (stat == NULL || stat->IsEmpty()) continue;
1064 // We find and mark the initialization blocks on top level code only. 1099 // We find and mark the initialization blocks on top level code only.
1065 // This is because the optimization prevents reuse of the map transitions, 1100 // This is because the optimization prevents reuse of the map transitions,
1066 // so it should be used only for code that will only be run once. 1101 // so it should be used only for code that will only be run once.
1067 if (top_scope_->is_global_scope()) { 1102 if (top_scope_->is_global_scope()) {
1068 block_finder.Update(stat); 1103 block_finder.Update(stat);
1069 } 1104 }
1070 // Find and mark all assignments to named properties in this (this.x =) 1105 // Find and mark all assignments to named properties in this (this.x =)
1071 if (top_scope_->is_function_scope()) { 1106 if (top_scope_->is_function_scope()) {
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
1407 Block* Parser::ParseVariableStatement(bool* ok) { 1442 Block* Parser::ParseVariableStatement(bool* ok) {
1408 // VariableStatement :: 1443 // VariableStatement ::
1409 // VariableDeclarations ';' 1444 // VariableDeclarations ';'
1410 1445
1411 Expression* dummy; // to satisfy the ParseVariableDeclarations() signature 1446 Expression* dummy; // to satisfy the ParseVariableDeclarations() signature
1412 Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK); 1447 Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK);
1413 ExpectSemicolon(CHECK_OK); 1448 ExpectSemicolon(CHECK_OK);
1414 return result; 1449 return result;
1415 } 1450 }
1416 1451
1452 static bool IsEvalOrArguments(Handle<String> string) {
1453 return string.is_identical_to(Factory::eval_symbol()) ||
1454 string.is_identical_to(Factory::arguments_symbol());
1455 }
1417 1456
1418 // If the variable declaration declares exactly one non-const 1457 // If the variable declaration declares exactly one non-const
1419 // variable, then *var is set to that variable. In all other cases, 1458 // variable, then *var is set to that variable. In all other cases,
1420 // *var is untouched; in particular, it is the caller's responsibility 1459 // *var is untouched; in particular, it is the caller's responsibility
1421 // to initialize it properly. This mechanism is used for the parsing 1460 // to initialize it properly. This mechanism is used for the parsing
1422 // of 'for-in' loops. 1461 // of 'for-in' loops.
1423 Block* Parser::ParseVariableDeclarations(bool accept_IN, 1462 Block* Parser::ParseVariableDeclarations(bool accept_IN,
1424 Expression** var, 1463 Expression** var,
1425 bool* ok) { 1464 bool* ok) {
1426 // VariableDeclarations :: 1465 // VariableDeclarations ::
(...skipping 28 matching lines...) Expand all
1455 VariableProxy* last_var = NULL; // the last variable declared 1494 VariableProxy* last_var = NULL; // the last variable declared
1456 int nvars = 0; // the number of variables declared 1495 int nvars = 0; // the number of variables declared
1457 do { 1496 do {
1458 if (fni_ != NULL) fni_->Enter(); 1497 if (fni_ != NULL) fni_->Enter();
1459 1498
1460 // Parse variable name. 1499 // Parse variable name.
1461 if (nvars > 0) Consume(Token::COMMA); 1500 if (nvars > 0) Consume(Token::COMMA);
1462 Handle<String> name = ParseIdentifier(CHECK_OK); 1501 Handle<String> name = ParseIdentifier(CHECK_OK);
1463 if (fni_ != NULL) fni_->PushVariableName(name); 1502 if (fni_ != NULL) fni_->PushVariableName(name);
1464 1503
1504 // Strict mode variables may not be named eval or arguments
1505 if (strict_mode_ && IsEvalOrArguments(name)) {
1506 ReportMessage("strict_var_name", Vector<const char*>::empty());
1507 *ok = false;
1508 return NULL;
1509 }
1510
1465 // Declare variable. 1511 // Declare variable.
1466 // Note that we *always* must treat the initial value via a separate init 1512 // Note that we *always* must treat the initial value via a separate init
1467 // assignment for variables and constants because the value must be assigned 1513 // assignment for variables and constants because the value must be assigned
1468 // when the variable is encountered in the source. But the variable/constant 1514 // when the variable is encountered in the source. But the variable/constant
1469 // is declared (and set to 'undefined') upon entering the function within 1515 // is declared (and set to 'undefined') upon entering the function within
1470 // which the variable or constant is declared. Only function variables have 1516 // which the variable or constant is declared. Only function variables have
1471 // an initial value in the declaration (because they are initialized upon 1517 // an initial value in the declaration (because they are initialized upon
1472 // entering the function). 1518 // entering the function).
1473 // 1519 //
1474 // If we have a const declaration, in an inner scope, the proxy is always 1520 // If we have a const declaration, in an inner scope, the proxy is always
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
1807 } 1853 }
1808 return result; 1854 return result;
1809 } 1855 }
1810 1856
1811 1857
1812 Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { 1858 Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
1813 // WithStatement :: 1859 // WithStatement ::
1814 // 'with' '(' Expression ')' Statement 1860 // 'with' '(' Expression ')' Statement
1815 1861
1816 Expect(Token::WITH, CHECK_OK); 1862 Expect(Token::WITH, CHECK_OK);
1863
1864 if (strict_mode_) {
1865 ReportMessage("strict_mode_with", Vector<const char*>::empty());
1866 *ok = false;
1867 return NULL;
1868 }
1869
1817 Expect(Token::LPAREN, CHECK_OK); 1870 Expect(Token::LPAREN, CHECK_OK);
1818 Expression* expr = ParseExpression(true, CHECK_OK); 1871 Expression* expr = ParseExpression(true, CHECK_OK);
1819 Expect(Token::RPAREN, CHECK_OK); 1872 Expect(Token::RPAREN, CHECK_OK);
1820 1873
1821 return WithHelper(expr, labels, false, CHECK_OK); 1874 return WithHelper(expr, labels, false, CHECK_OK);
1822 } 1875 }
1823 1876
1824 1877
1825 CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { 1878 CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
1826 // CaseClause :: 1879 // CaseClause ::
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
1939 // the jump targets. 1992 // the jump targets.
1940 ZoneList<BreakTarget*>* catch_target_list = new ZoneList<BreakTarget*>(0); 1993 ZoneList<BreakTarget*>* catch_target_list = new ZoneList<BreakTarget*>(0);
1941 TargetCollector catch_collector(catch_target_list); 1994 TargetCollector catch_collector(catch_target_list);
1942 bool has_catch = false; 1995 bool has_catch = false;
1943 if (tok == Token::CATCH) { 1996 if (tok == Token::CATCH) {
1944 has_catch = true; 1997 has_catch = true;
1945 Consume(Token::CATCH); 1998 Consume(Token::CATCH);
1946 1999
1947 Expect(Token::LPAREN, CHECK_OK); 2000 Expect(Token::LPAREN, CHECK_OK);
1948 Handle<String> name = ParseIdentifier(CHECK_OK); 2001 Handle<String> name = ParseIdentifier(CHECK_OK);
2002
2003 if (strict_mode_ && IsEvalOrArguments(name)) {
2004 ReportMessage("strict_catch_variable", Vector<const char*>::empty());
2005 *ok = false;
2006 return NULL;
2007 }
2008
1949 Expect(Token::RPAREN, CHECK_OK); 2009 Expect(Token::RPAREN, CHECK_OK);
1950 2010
1951 if (peek() == Token::LBRACE) { 2011 if (peek() == Token::LBRACE) {
1952 // Allocate a temporary for holding the finally state while 2012 // Allocate a temporary for holding the finally state while
1953 // executing the finally block. 2013 // executing the finally block.
1954 catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol()); 2014 catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
1955 Literal* name_literal = new Literal(name); 2015 Literal* name_literal = new Literal(name);
1956 VariableProxy* catch_var_use = new VariableProxy(catch_var); 2016 VariableProxy* catch_var_use = new VariableProxy(catch_var);
1957 Expression* obj = new CatchExtensionObject(name_literal, catch_var_use); 2017 Expression* obj = new CatchExtensionObject(name_literal, catch_var_use);
1958 { Target target(&this->target_stack_, &catch_collector); 2018 { Target target(&this->target_stack_, &catch_collector);
(...skipping 1222 matching lines...) Expand 10 before | Expand all | Expand 10 after
3181 3241
3182 int num_parameters = 0; 3242 int num_parameters = 0;
3183 // Parse function body. 3243 // Parse function body.
3184 { Scope* scope = 3244 { Scope* scope =
3185 NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); 3245 NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
3186 LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_, 3246 LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
3187 scope); 3247 scope);
3188 TemporaryScope temp_scope(&this->temp_scope_); 3248 TemporaryScope temp_scope(&this->temp_scope_);
3189 top_scope_->SetScopeName(name); 3249 top_scope_->SetScopeName(name);
3190 3250
3251 // Strict mode stack
3252 StrictMode strict(&strict_mode_);
Lasse Reichstein 2011/01/13 07:18:40 As stated earlier, we define the TemporaryScope ju
Martin Maly 2011/01/14 00:06:28 Done.
3253
3191 // FormalParameterList :: 3254 // FormalParameterList ::
3192 // '(' (Identifier)*[','] ')' 3255 // '(' (Identifier)*[','] ')'
3193 Expect(Token::LPAREN, CHECK_OK); 3256 Expect(Token::LPAREN, CHECK_OK);
3194 int start_pos = scanner().location().beg_pos; 3257 int start_pos = scanner().location().beg_pos;
3195 bool done = (peek() == Token::RPAREN); 3258 bool done = (peek() == Token::RPAREN);
3196 while (!done) { 3259 while (!done) {
3197 Handle<String> param_name = ParseIdentifier(CHECK_OK); 3260 Handle<String> param_name = ParseIdentifier(CHECK_OK);
3198 top_scope_->AddParameter(top_scope_->DeclareLocal(param_name, 3261 top_scope_->AddParameter(top_scope_->DeclareLocal(param_name,
3199 Variable::VAR)); 3262 Variable::VAR));
3200 num_parameters++; 3263 num_parameters++;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
3258 materialized_literal_count = temp_scope.materialized_literal_count(); 3321 materialized_literal_count = temp_scope.materialized_literal_count();
3259 expected_property_count = temp_scope.expected_property_count(); 3322 expected_property_count = temp_scope.expected_property_count();
3260 only_simple_this_property_assignments = 3323 only_simple_this_property_assignments =
3261 temp_scope.only_simple_this_property_assignments(); 3324 temp_scope.only_simple_this_property_assignments();
3262 this_property_assignments = temp_scope.this_property_assignments(); 3325 this_property_assignments = temp_scope.this_property_assignments();
3263 3326
3264 Expect(Token::RBRACE, CHECK_OK); 3327 Expect(Token::RBRACE, CHECK_OK);
3265 end_pos = scanner().location().end_pos; 3328 end_pos = scanner().location().end_pos;
3266 } 3329 }
3267 3330
3331 // Validate strict mode.
3332 if (strict_mode_) {
3333 int position = function_token_position != RelocInfo::kNoPosition
3334 ? function_token_position
3335 : (start_pos > 0 ? start_pos - 1 : start_pos);
3336
3337 if (IsEvalOrArguments(name)) {
3338 ReportMessageAt(Scanner::Location(position, start_pos),
3339 "strict_function_name", Vector<const char*>::empty());
3340 *ok = false;
3341 return NULL;
3342 }
3343 if (top_scope_->HasEvalOrArgumentsParameter()) {
3344 ReportMessageAt(Scanner::Location(position, start_pos),
Lasse Reichstein 2011/01/13 07:18:40 Could you store the position of the argument that
Martin Maly 2011/01/14 00:06:28 It is definitely possible. I was trying to avoid a
Lasse Reichstein 2011/01/14 11:42:05 Yes, we need to either detect the problems when th
Martin Maly 2011/01/14 16:30:43 Sounds good. On 2011/01/14 11:42:05, Lasse Reichs
3345 "strict_param_name", Vector<const char*>::empty());
3346 *ok = false;
3347 return NULL;
3348 }
3349 if (top_scope_->HasDuplicateParameterName()) {
3350 ReportMessageAt(Scanner::Location(position, start_pos),
3351 "strict_param_dupe", Vector<const char*>::empty());
Lasse Reichstein 2011/01/13 07:18:40 Also here, could you store the actual position of
Martin Maly 2011/01/14 00:06:28 I believe it can be done, also at a relatively sma
Lasse Reichstein 2011/01/14 11:42:05 I think I would just drop the HashMap and do the s
Martin Maly 2011/01/14 16:30:43 Done.
3352 *ok = false;
3353 return NULL;
3354 }
Lasse Reichstein 2011/01/13 07:18:40 For later, I would also put the check for octal nu
Martin Maly 2011/01/14 00:06:28 Great idea. that will also handle the case where "
3355 }
3356
3268 FunctionLiteral* function_literal = 3357 FunctionLiteral* function_literal =
3269 new FunctionLiteral(name, 3358 new FunctionLiteral(name,
3270 top_scope_, 3359 top_scope_,
3271 body, 3360 body,
3272 materialized_literal_count, 3361 materialized_literal_count,
3273 expected_property_count, 3362 expected_property_count,
3274 only_simple_this_property_assignments, 3363 only_simple_this_property_assignments,
3275 this_property_assignments, 3364 this_property_assignments,
3276 num_parameters, 3365 num_parameters,
3277 start_pos, 3366 start_pos,
3278 end_pos, 3367 end_pos,
3279 function_name->length() > 0, 3368 function_name->length() > 0,
3280 temp_scope.ContainsLoops()); 3369 temp_scope.ContainsLoops(),
3370 strict_mode_);
3281 function_literal->set_function_token_position(function_token_position); 3371 function_literal->set_function_token_position(function_token_position);
3282 3372
3283 if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal); 3373 if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
3284 return function_literal; 3374 return function_literal;
3285 } 3375 }
3286 } 3376 }
3287 3377
3288 3378
3289 Expression* Parser::ParseV8Intrinsic(bool* ok) { 3379 Expression* Parser::ParseV8Intrinsic(bool* ok) {
3290 // CallRuntime :: 3380 // CallRuntime ::
(...skipping 1404 matching lines...) Expand 10 before | Expand all | Expand 10 after
4695 Handle<String> source = Handle<String>(String::cast(script->source())); 4785 Handle<String> source = Handle<String>(String::cast(script->source()));
4696 result = parser.ParseProgram(source, info->is_global()); 4786 result = parser.ParseProgram(source, info->is_global());
4697 } 4787 }
4698 } 4788 }
4699 4789
4700 info->SetFunction(result); 4790 info->SetFunction(result);
4701 return (result != NULL); 4791 return (result != NULL);
4702 } 4792 }
4703 4793
4704 } } // namespace v8::internal 4794 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698