Disallow yield in default parameter initializers
authorwingo <wingo@igalia.com>
Fri, 28 Aug 2015 08:44:17 +0000 (01:44 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 28 Aug 2015 08:44:30 +0000 (08:44 +0000)
R=adamk@chromium.org
LOG=N
BUG=v8:4397

Review URL: https://codereview.chromium.org/1320673007

Cr-Commit-Position: refs/heads/master@{#30431}

src/expression-classifier.h
src/preparser.h
test/cctest/test-parsing.cc

index 80f5e66fd4fea08d2f648824b1caee9ff4ae65d6..fb45f41fa169368b998aacf33afdeaf33e44ec51 100644 (file)
@@ -28,19 +28,22 @@ class ExpressionClassifier {
 
   enum TargetProduction {
     ExpressionProduction = 1 << 0,
-    BindingPatternProduction = 1 << 1,
-    AssignmentPatternProduction = 1 << 2,
-    DistinctFormalParametersProduction = 1 << 3,
-    StrictModeFormalParametersProduction = 1 << 4,
-    StrongModeFormalParametersProduction = 1 << 5,
-    ArrowFormalParametersProduction = 1 << 6,
-
+    FormalParameterInitializerProduction = 1 << 1,
+    BindingPatternProduction = 1 << 2,
+    AssignmentPatternProduction = 1 << 3,
+    DistinctFormalParametersProduction = 1 << 4,
+    StrictModeFormalParametersProduction = 1 << 5,
+    StrongModeFormalParametersProduction = 1 << 6,
+    ArrowFormalParametersProduction = 1 << 7,
+
+    ExpressionProductions =
+        (ExpressionProduction | FormalParameterInitializerProduction),
     PatternProductions =
         (BindingPatternProduction | AssignmentPatternProduction),
     FormalParametersProductions = (DistinctFormalParametersProduction |
                                    StrictModeFormalParametersProduction |
                                    StrongModeFormalParametersProduction),
-    StandardProductions = ExpressionProduction | PatternProductions,
+    StandardProductions = ExpressionProductions | PatternProductions,
     AllProductions = (StandardProductions | FormalParametersProductions |
                       ArrowFormalParametersProduction)
   };
@@ -65,6 +68,10 @@ class ExpressionClassifier {
 
   bool is_valid_expression() const { return is_valid(ExpressionProduction); }
 
+  bool is_valid_formal_parameter_initializer() const {
+    return is_valid(FormalParameterInitializerProduction);
+  }
+
   bool is_valid_binding_pattern() const {
     return is_valid(BindingPatternProduction);
   }
@@ -95,6 +102,10 @@ class ExpressionClassifier {
 
   const Error& expression_error() const { return expression_error_; }
 
+  const Error& formal_parameter_initializer_error() const {
+    return formal_parameter_initializer_error_;
+  }
+
   const Error& binding_pattern_error() const { return binding_pattern_error_; }
 
   const Error& assignment_pattern_error() const {
@@ -135,6 +146,16 @@ class ExpressionClassifier {
     expression_error_.arg = arg;
   }
 
+  void RecordFormalParameterInitializerError(const Scanner::Location& loc,
+                                             MessageTemplate::Template message,
+                                             const char* arg = nullptr) {
+    if (!is_valid_formal_parameter_initializer()) return;
+    invalid_productions_ |= FormalParameterInitializerProduction;
+    formal_parameter_initializer_error_.location = loc;
+    formal_parameter_initializer_error_.message = message;
+    formal_parameter_initializer_error_.arg = arg;
+  }
+
   void RecordBindingPatternError(const Scanner::Location& loc,
                                  MessageTemplate::Template message,
                                  const char* arg = nullptr) {
@@ -212,6 +233,9 @@ class ExpressionClassifier {
       invalid_productions_ |= errors;
       if (errors & ExpressionProduction)
         expression_error_ = inner.expression_error_;
+      if (errors & FormalParameterInitializerProduction)
+        formal_parameter_initializer_error_ =
+            inner.formal_parameter_initializer_error_;
       if (errors & BindingPatternProduction)
         binding_pattern_error_ = inner.binding_pattern_error_;
       if (errors & AssignmentPatternProduction)
@@ -246,6 +270,7 @@ class ExpressionClassifier {
   unsigned invalid_productions_;
   unsigned function_properties_;
   Error expression_error_;
+  Error formal_parameter_initializer_error_;
   Error binding_pattern_error_;
   Error assignment_pattern_error_;
   Error arrow_formal_parameters_error_;
index 07e431bfc54790b0a65c081f9ea8021ab6fba84c..170c744946d651540b098ef1e4337e5b1dd3e796 100644 (file)
@@ -548,6 +548,14 @@ class ParserBase : public Traits {
     }
   }
 
+  void ValidateFormalParameterInitializer(
+      const ExpressionClassifier* classifier, bool* ok) {
+    if (!classifier->is_valid_formal_parameter_initializer()) {
+      ReportClassifierError(classifier->formal_parameter_initializer_error());
+      *ok = false;
+    }
+  }
+
   void ValidateBindingPattern(const ExpressionClassifier* classifier,
                               bool* ok) {
     if (!classifier->is_valid_binding_pattern()) {
@@ -629,6 +637,15 @@ class ParserBase : public Traits {
                                                  message, arg);
   }
 
+  void FormalParameterInitializerUnexpectedToken(
+      ExpressionClassifier* classifier) {
+    MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
+    const char* arg;
+    GetUnexpectedTokenMessage(peek(), &message, &arg);
+    classifier->RecordFormalParameterInitializerError(
+        scanner()->peek_location(), message, arg);
+  }
+
   // Recursive descent functions:
 
   // Parses an identifier that is valid for the current scope, in particular it
@@ -2522,7 +2539,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
       ExpressionT expression =
           ParseAssignmentExpression(true, &computed_name_classifier, CHECK_OK);
       classifier->Accumulate(computed_name_classifier,
-                             ExpressionClassifier::ExpressionProduction);
+                             ExpressionClassifier::ExpressionProductions);
       Expect(Token::RBRACK, CHECK_OK);
       return expression;
     }
@@ -2668,7 +2685,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
       ExpressionT rhs = this->ParseAssignmentExpression(
           true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
       classifier->Accumulate(rhs_classifier,
-                             ExpressionClassifier::ExpressionProduction);
+                             ExpressionClassifier::ExpressionProductions);
       value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
                                        RelocInfo::kNoPosition);
     } else {
@@ -2910,7 +2927,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
   ExpressionT right =
       this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK);
   classifier->Accumulate(rhs_classifier,
-                         ExpressionClassifier::ExpressionProduction);
+                         ExpressionClassifier::ExpressionProductions);
 
   // TODO(1231235): We try to estimate the set of properties set by
   // constructors. We define a new property whenever there is an
@@ -2949,6 +2966,7 @@ ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
   //   'yield' ([no line terminator] '*'? AssignmentExpression)?
   int pos = peek_position();
   BindingPatternUnexpectedToken(classifier);
+  FormalParameterInitializerUnexpectedToken(classifier);
   Expect(Token::YIELD, CHECK_OK);
   ExpressionT generator_object =
       factory()->NewVariableProxy(function_state_->generator_object_variable());
@@ -3676,6 +3694,8 @@ void ParserBase<Traits>::ParseFormalParameter(
       return;
     }
     parameters->is_simple = false;
+    ValidateFormalParameterInitializer(classifier, ok);
+    if (!*ok) return;
     classifier->RecordNonSimpleParameter();
   }
 
@@ -3685,6 +3705,7 @@ void ParserBase<Traits>::ParseFormalParameter(
     initializer = ParseAssignmentExpression(true, &init_classifier, ok);
     if (!*ok) return;
     ValidateExpression(&init_classifier, ok);
+    ValidateFormalParameterInitializer(&init_classifier, ok);
     if (!*ok) return;
     parameters->is_simple = false;
     classifier->RecordNonSimpleParameter();
index 1ea550caab1dc65b1fe0f320531bb250748c604d..4f73c9ffdfca05d167732df183fb460997a4d014 100644 (file)
@@ -6752,6 +6752,71 @@ TEST(DestructuringDisallowPatternsInRestParams) {
 }
 
 
+TEST(DefaultParametersYieldInInitializers) {
+  // clang-format off
+  const char* sloppy_function_context_data[][2] = {
+    {"(function f(", ") { });"},
+    // TODO(wingo): Add arrow functions.
+    {NULL, NULL}
+  };
+
+  const char* strict_function_context_data[][2] = {
+    {"'use strong'; (function f(", ") { });"},
+    {"'use strict'; (function f(", ") { });"},
+    // TODO(wingo,conradw): These should also signal early errors.
+    // {"(function f(", ") {'use strong'; });"},
+    // {"(function f(", ") {'use strict'; });"},
+    // TODO(wingo): Add arrow functions.
+    {NULL, NULL}
+  };
+
+  const char* generator_context_data[][2] = {
+    {"'use strong'; (function *g(", ") { });"},
+    {"'use strict'; (function *g(", ") { });"},
+    // TODO(wingo,conradw): These should also signal early errors.
+    // {"(function *g(", ") {'use strong'; });"},
+    // {"(function *g(", ") {'use strict'; });"},
+    {"(function *g(", ") { });"},
+    {NULL, NULL}
+  };
+
+  const char* formal_parameter_data[] = {
+    "x=yield",
+    "x, y=yield",
+    "{x=yield}",
+    "[x=yield]",
+    "{x}=yield",
+    "[x]=yield",
+
+    "x=(yield)",
+    "x, y=(yield)",
+    "{x=(yield)}",
+    "[x=(yield)]",
+    "{x}=(yield)",
+    "[x]=(yield)",
+
+    "x=f(yield)",
+    "x, y=f(yield)",
+    "{x=f(yield)}",
+    "[x=f(yield)]",
+    "{x}=f(yield)",
+    "[x]=f(yield)",
+    NULL
+  };
+
+  // clang-format on
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyDestructuring, kAllowHarmonyDefaultParameters,
+      kAllowHarmonyArrowFunctions, kAllowStrongMode};
+  RunParserSyncTest(sloppy_function_context_data, formal_parameter_data,
+                    kSuccess, NULL, 0, always_flags, arraysize(always_flags));
+  RunParserSyncTest(strict_function_context_data, formal_parameter_data, kError,
+                    NULL, 0, always_flags, arraysize(always_flags));
+  RunParserSyncTest(generator_context_data, formal_parameter_data, kError, NULL,
+                    0, always_flags, arraysize(always_flags));
+}
+
+
 TEST(SpreadArray) {
   i::FLAG_harmony_spread_arrays = true;