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)
};
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);
}
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 {
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) {
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)
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_;
}
}
+ 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()) {
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
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;
}
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 {
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
// '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());
return;
}
parameters->is_simple = false;
+ ValidateFormalParameterInitializer(classifier, ok);
+ if (!*ok) return;
classifier->RecordNonSimpleParameter();
}
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();
}
+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;