blob: 716d4c7a3f29c24d2da337721c9089c4c3273616 [file] [log] [blame]
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_EXPRESSION_CLASSIFIER_H
#define V8_EXPRESSION_CLASSIFIER_H
#include "src/v8.h"
#include "src/messages.h"
#include "src/scanner.h"
#include "src/token.h"
namespace v8 {
namespace internal {
class ExpressionClassifier {
public:
struct Error {
Error()
: location(Scanner::Location::invalid()),
message(MessageTemplate::kNone),
arg(nullptr) {}
Scanner::Location location;
MessageTemplate::Template message;
const char* arg;
};
enum TargetProduction {
ExpressionProduction = 1 << 0,
BindingPatternProduction = 1 << 1,
AssignmentPatternProduction = 1 << 2,
DistinctFormalParametersProduction = 1 << 3,
StrictModeFormalParametersProduction = 1 << 4,
StrongModeFormalParametersProduction = 1 << 5,
ArrowFormalParametersProduction = 1 << 6,
PatternProductions =
(BindingPatternProduction | AssignmentPatternProduction),
FormalParametersProductions = (DistinctFormalParametersProduction |
StrictModeFormalParametersProduction |
StrongModeFormalParametersProduction),
StandardProductions = ExpressionProduction | PatternProductions,
AllProductions = (StandardProductions | FormalParametersProductions |
ArrowFormalParametersProduction)
};
ExpressionClassifier()
: invalid_productions_(0), duplicate_finder_(nullptr) {}
explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
: invalid_productions_(0), duplicate_finder_(duplicate_finder) {}
bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
}
DuplicateFinder* duplicate_finder() const { return duplicate_finder_; }
bool is_valid_expression() const { return is_valid(ExpressionProduction); }
bool is_valid_binding_pattern() const {
return is_valid(BindingPatternProduction);
}
bool is_valid_assignment_pattern() const {
return is_valid(AssignmentPatternProduction);
}
bool is_valid_arrow_formal_parameters() const {
return is_valid(ArrowFormalParametersProduction);
}
bool is_valid_formal_parameter_list_without_duplicates() const {
return is_valid(DistinctFormalParametersProduction);
}
// Note: callers should also check
// is_valid_formal_parameter_list_without_duplicates().
bool is_valid_strict_mode_formal_parameters() const {
return is_valid(StrictModeFormalParametersProduction);
}
// Note: callers should also check is_valid_strict_mode_formal_parameters()
// and is_valid_formal_parameter_list_without_duplicates().
bool is_valid_strong_mode_formal_parameters() const {
return is_valid(StrongModeFormalParametersProduction);
}
const Error& expression_error() const { return expression_error_; }
const Error& binding_pattern_error() const { return binding_pattern_error_; }
const Error& assignment_pattern_error() const {
return assignment_pattern_error_;
}
const Error& arrow_formal_parameters_error() const {
return arrow_formal_parameters_error_;
}
const Error& duplicate_formal_parameter_error() const {
return duplicate_formal_parameter_error_;
}
const Error& strict_mode_formal_parameter_error() const {
return strict_mode_formal_parameter_error_;
}
const Error& strong_mode_formal_parameter_error() const {
return strong_mode_formal_parameter_error_;
}
void RecordExpressionError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_expression()) return;
invalid_productions_ |= ExpressionProduction;
expression_error_.location = loc;
expression_error_.message = message;
expression_error_.arg = arg;
}
void RecordBindingPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_binding_pattern()) return;
invalid_productions_ |= BindingPatternProduction;
binding_pattern_error_.location = loc;
binding_pattern_error_.message = message;
binding_pattern_error_.arg = arg;
}
void RecordAssignmentPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_assignment_pattern()) return;
invalid_productions_ |= AssignmentPatternProduction;
assignment_pattern_error_.location = loc;
assignment_pattern_error_.message = message;
assignment_pattern_error_.arg = arg;
}
void RecordArrowFormalParametersError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_arrow_formal_parameters()) return;
invalid_productions_ |= ArrowFormalParametersProduction;
arrow_formal_parameters_error_.location = loc;
arrow_formal_parameters_error_.message = message;
arrow_formal_parameters_error_.arg = arg;
}
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
if (!is_valid_formal_parameter_list_without_duplicates()) return;
invalid_productions_ |= DistinctFormalParametersProduction;
duplicate_formal_parameter_error_.location = loc;
duplicate_formal_parameter_error_.message = MessageTemplate::kParamDupe;
duplicate_formal_parameter_error_.arg = nullptr;
}
// Record a binding that would be invalid in strict mode. Confusingly this
// is not the same as StrictFormalParameterList, which simply forbids
// duplicate bindings.
void RecordStrictModeFormalParameterError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_strict_mode_formal_parameters()) return;
invalid_productions_ |= StrictModeFormalParametersProduction;
strict_mode_formal_parameter_error_.location = loc;
strict_mode_formal_parameter_error_.message = message;
strict_mode_formal_parameter_error_.arg = arg;
}
void RecordStrongModeFormalParameterError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_strong_mode_formal_parameters()) return;
invalid_productions_ |= StrongModeFormalParametersProduction;
strong_mode_formal_parameter_error_.location = loc;
strong_mode_formal_parameter_error_.message = message;
strong_mode_formal_parameter_error_.arg = arg;
}
void Accumulate(const ExpressionClassifier& inner,
unsigned productions = StandardProductions) {
// Propagate errors from inner, but don't overwrite already recorded
// errors.
unsigned non_arrow_inner_invalid_productions =
inner.invalid_productions_ & ~ArrowFormalParametersProduction;
if (non_arrow_inner_invalid_productions == 0) return;
unsigned non_arrow_productions =
productions & ~ArrowFormalParametersProduction;
unsigned errors =
non_arrow_productions & non_arrow_inner_invalid_productions;
errors &= ~invalid_productions_;
if (errors != 0) {
invalid_productions_ |= errors;
if (errors & ExpressionProduction)
expression_error_ = inner.expression_error_;
if (errors & BindingPatternProduction)
binding_pattern_error_ = inner.binding_pattern_error_;
if (errors & AssignmentPatternProduction)
assignment_pattern_error_ = inner.assignment_pattern_error_;
if (errors & DistinctFormalParametersProduction)
duplicate_formal_parameter_error_ =
inner.duplicate_formal_parameter_error_;
if (errors & StrictModeFormalParametersProduction)
strict_mode_formal_parameter_error_ =
inner.strict_mode_formal_parameter_error_;
if (errors & StrongModeFormalParametersProduction)
strong_mode_formal_parameter_error_ =
inner.strong_mode_formal_parameter_error_;
}
// As an exception to the above, the result continues to be a valid arrow
// formal parameters if the inner expression is a valid binding pattern.
if (productions & ArrowFormalParametersProduction &&
is_valid_arrow_formal_parameters() &&
!inner.is_valid_binding_pattern()) {
invalid_productions_ |= ArrowFormalParametersProduction;
arrow_formal_parameters_error_ = inner.binding_pattern_error_;
}
}
private:
unsigned invalid_productions_;
Error expression_error_;
Error binding_pattern_error_;
Error assignment_pattern_error_;
Error arrow_formal_parameters_error_;
Error duplicate_formal_parameter_error_;
Error strict_mode_formal_parameter_error_;
Error strong_mode_formal_parameter_error_;
DuplicateFinder* duplicate_finder_;
};
}
} // v8::internal
#endif // V8_EXPRESSION_CLASSIFIER_H