lambdaworld-archive/node_modules/shift-parser/src/early-errors.js

768 lines
30 KiB
JavaScript

/**
* Copyright 2014 Shape Security, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { reduce, MonoidalReducer } = require('shift-reducer');
const { isStrictModeReservedWord } = require('./utils');
const { ErrorMessages } = require('./errors');
const { EarlyErrorState, EarlyError } = require('./early-error-state');
function isStrictFunctionBody({ directives }) {
return directives.some(directive => directive.rawValue === 'use strict');
}
function isLabelledFunction(node) {
return node.type === 'LabeledStatement' &&
(node.body.type === 'FunctionDeclaration' || isLabelledFunction(node.body));
}
function isIterationStatement(node) {
switch (node.type) {
case 'LabeledStatement':
return isIterationStatement(node.body);
case 'DoWhileStatement':
case 'ForInStatement':
case 'ForOfStatement':
case 'ForStatement':
case 'WhileStatement':
return true;
}
return false;
}
function isSpecialMethod(methodDefinition) {
if (methodDefinition.name.type !== 'StaticPropertyName' || methodDefinition.name.value !== 'constructor') {
return false;
}
switch (methodDefinition.type) {
case 'Getter':
case 'Setter':
return true;
case 'Method':
return methodDefinition.isGenerator || methodDefinition.isAsync;
}
/* istanbul ignore next */
throw new Error('not reached');
}
function enforceDuplicateConstructorMethods(node, s) {
let ctors = node.elements.filter(e =>
!e.isStatic &&
e.method.type === 'Method' &&
!e.method.isGenerator &&
e.method.name.type === 'StaticPropertyName' &&
e.method.name.value === 'constructor'
);
if (ctors.length > 1) {
ctors.slice(1).forEach(ctor => {
s = s.addError(new EarlyError(ctor, 'Duplicate constructor method in class'));
});
}
return s;
}
const SUPERCALL_ERROR = node => new EarlyError(node, ErrorMessages.ILLEGAL_SUPER_CALL);
const SUPERPROPERTY_ERROR = node => new EarlyError(node, 'Member access on super must be in a method');
const DUPLICATE_BINDING = node => new EarlyError(node, `Duplicate binding ${JSON.stringify(node.name)}`);
const FREE_CONTINUE = node => new EarlyError(node, 'Continue statement must be nested within an iteration statement');
const UNBOUND_CONTINUE = node => new EarlyError(node, `Continue statement must be nested within an iteration statement with label ${JSON.stringify(node.label)}`);
const FREE_BREAK = node => new EarlyError(node, 'Break statement must be nested within an iteration statement or a switch statement');
const UNBOUND_BREAK = node => new EarlyError(node, `Break statement must be nested within a statement with label ${JSON.stringify(node.label)}`);
class EarlyErrorChecker extends MonoidalReducer {
constructor() {
super(EarlyErrorState);
}
reduceAssignmentExpression() {
return super.reduceAssignmentExpression(...arguments).clearBoundNames();
}
reduceAssignmentTargetIdentifier(node) {
let s = this.identity;
if (node.name === 'eval' || node.name === 'arguments' || isStrictModeReservedWord(node.name)) {
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.name)} must not be in binding position in strict mode`));
}
return s;
}
reduceArrowExpression(node, { params, body }) {
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
params = params.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
if (node.body.type === 'FunctionBody') {
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
if (isStrictFunctionBody(node.body)) {
params = params.enforceStrictErrors();
body = body.enforceStrictErrors();
}
}
params.yieldExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Arrow parameters must not contain yield expressions'));
});
params.awaitExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Arrow parameters must not contain await expressions'));
});
let s = super.reduceArrowExpression(node, { params, body });
if (!isSimpleParameterList && node.body.type === 'FunctionBody' && isStrictFunctionBody(node.body)) {
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
}
s = s.clearYieldExpressions();
s = s.clearAwaitExpressions();
s = s.observeVarBoundary();
return s;
}
reduceAwaitExpression(node, { expression }) {
return expression.observeAwaitExpression(node);
}
reduceBindingIdentifier(node) {
let s = this.identity;
if (node.name === 'eval' || node.name === 'arguments' || isStrictModeReservedWord(node.name)) {
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.name)} must not be in binding position in strict mode`));
}
s = s.bindName(node.name, node);
return s;
}
reduceBlock() {
let s = super.reduceBlock(...arguments);
s = s.functionDeclarationNamesAreLexical();
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
s = s.observeLexicalBoundary();
return s;
}
reduceBreakStatement(node) {
let s = super.reduceBreakStatement(...arguments);
s = node.label == null
? s.addFreeBreakStatement(node)
: s.addFreeLabeledBreakStatement(node);
return s;
}
reduceCallExpression(node) {
let s = super.reduceCallExpression(...arguments);
if (node.callee.type === 'Super') {
s = s.observeSuperCallExpression(node);
}
return s;
}
reduceCatchClause(node, { binding, body }) {
if (binding != null) {
binding = binding.observeLexicalDeclaration();
binding = binding.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
binding = binding.enforceConflictingLexicallyDeclaredNames(body.previousLexicallyDeclaredNames, DUPLICATE_BINDING);
}
let s = super.reduceCatchClause(node, { binding, body });
s = s.observeLexicalBoundary();
return s;
}
reduceClassDeclaration(node, { name, super: _super, elements }) {
let s = name.enforceStrictErrors();
let sElements = this.append(...elements);
sElements = sElements.enforceStrictErrors();
if (node.super != null) {
_super = _super.enforceStrictErrors();
s = this.append(s, _super);
sElements = sElements.clearSuperCallExpressionsInConstructorMethod();
}
s = this.append(s, sElements);
s = enforceDuplicateConstructorMethods(node, s);
s = s.observeLexicalDeclaration();
return s;
}
reduceClassElement(node) {
let s = super.reduceClassElement(...arguments);
if (!node.isStatic && isSpecialMethod(node.method)) {
s = s.addError(new EarlyError(node, ErrorMessages.ILLEGAL_CONSTRUCTORS));
}
if (node.isStatic && node.method.name.type === 'StaticPropertyName' && node.method.name.value === 'prototype') {
s = s.addError(new EarlyError(node, 'Static class methods cannot be named "prototype"'));
}
return s;
}
reduceClassExpression(node, { name, super: _super, elements }) {
let s = node.name == null ? this.identity : name.enforceStrictErrors();
let sElements = this.append(...elements);
sElements = sElements.enforceStrictErrors();
if (node.super != null) {
_super = _super.enforceStrictErrors();
s = this.append(s, _super);
sElements = sElements.clearSuperCallExpressionsInConstructorMethod();
}
s = this.append(s, sElements);
s = enforceDuplicateConstructorMethods(node, s);
s = s.clearBoundNames();
return s;
}
reduceCompoundAssignmentExpression() {
return super.reduceCompoundAssignmentExpression(...arguments).clearBoundNames();
}
reduceComputedMemberExpression(node) {
let s = super.reduceComputedMemberExpression(...arguments);
if (node.object.type === 'Super') {
s = s.observeSuperPropertyExpression(node);
}
return s;
}
reduceContinueStatement(node) {
let s = super.reduceContinueStatement(...arguments);
s = node.label == null
? s.addFreeContinueStatement(node)
: s.addFreeLabeledContinueStatement(node);
return s;
}
reduceDoWhileStatement(node) {
let s = super.reduceDoWhileStatement(...arguments);
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a do-while statement must not be a labeled function declaration'));
}
s = s.clearFreeContinueStatements();
s = s.clearFreeBreakStatements();
return s;
}
reduceExport() {
let s = super.reduceExport(...arguments);
s = s.functionDeclarationNamesAreLexical();
s = s.exportDeclaredNames();
return s;
}
reduceExportFrom() {
let s = super.reduceExportFrom(...arguments);
s = s.clearExportedBindings();
return s;
}
reduceExportFromSpecifier(node) {
let s = super.reduceExportFromSpecifier(...arguments);
s = s.exportName(node.exportedName || node.name, node);
s = s.exportBinding(node.name, node);
return s;
}
reduceExportLocalSpecifier(node) {
let s = super.reduceExportLocalSpecifier(...arguments);
s = s.exportName(node.exportedName || node.name.name, node);
s = s.exportBinding(node.name.name, node);
return s;
}
reduceExportDefault(node) {
let s = super.reduceExportDefault(...arguments);
s = s.functionDeclarationNamesAreLexical();
s = s.exportName('default', node);
return s;
}
reduceFormalParameters() {
let s = super.reduceFormalParameters(...arguments);
s = s.observeLexicalDeclaration();
return s;
}
reduceForStatement(node, { init, test, update, body }) {
if (init != null) {
init = init.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
init = init.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
}
let s = super.reduceForStatement(node, { init, test, update, body });
if (node.init != null && node.init.type === 'VariableDeclaration' && node.init.kind === 'const') {
node.init.declarators.forEach(declarator => {
if (declarator.init == null) {
s = s.addError(new EarlyError(declarator, 'Constant lexical declarations must have an initialiser'));
}
});
}
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a for statement must not be a labeled function declaration'));
}
s = s.clearFreeContinueStatements();
s = s.clearFreeBreakStatements();
s = s.observeLexicalBoundary();
return s;
}
reduceForInStatement(node, { left, right, body }) {
left = left.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
left = left.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
let s = super.reduceForInStatement(node, { left, right, body });
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a for-in statement must not be a labeled function declaration'));
}
s = s.clearFreeContinueStatements();
s = s.clearFreeBreakStatements();
s = s.observeLexicalBoundary();
return s;
}
reduceForOfStatement(node, { left, right, body }) {
left = left.recordForOfVars();
left = left.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
left = left.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
let s = super.reduceForOfStatement(node, { left, right, body });
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a for-of statement must not be a labeled function declaration'));
}
s = s.clearFreeContinueStatements();
s = s.clearFreeBreakStatements();
s = s.observeLexicalBoundary();
return s;
}
reduceForAwaitStatement(node, { left, right, body }) {
left = left.recordForOfVars();
left = left.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
left = left.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
let s = super.reduceForOfStatement(node, { left, right, body });
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a for-await statement must not be a labeled function declaration'));
}
s = s.clearFreeContinueStatements();
s = s.clearFreeBreakStatements();
s = s.observeLexicalBoundary();
return s;
}
reduceFunctionBody(node) {
let s = super.reduceFunctionBody(...arguments);
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
s = s.enforceFreeContinueStatementErrors(FREE_CONTINUE);
s = s.enforceFreeLabeledContinueStatementErrors(UNBOUND_CONTINUE);
s = s.enforceFreeBreakStatementErrors(FREE_BREAK);
s = s.enforceFreeLabeledBreakStatementErrors(UNBOUND_BREAK);
s = s.clearUsedLabelNames();
s = s.clearYieldExpressions();
s = s.clearAwaitExpressions();
if (isStrictFunctionBody(node)) {
s = s.enforceStrictErrors();
}
return s;
}
reduceFunctionDeclaration(node, { name, params, body }) {
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
let addError = !isSimpleParameterList || node.isGenerator ? 'addError' : 'addStrictError';
params.lexicallyDeclaredNames.forEachEntry(nodes => {
if (nodes.length > 1) {
nodes.slice(1).forEach(dupeNode => {
params = params[addError](DUPLICATE_BINDING(dupeNode));
});
}
});
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
body = body.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
params = params.enforceSuperCallExpressions(SUPERCALL_ERROR);
params = params.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
if (node.isGenerator) {
params.yieldExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Generator parameters must not contain yield expressions'));
});
}
if (node.isAsync) {
params.awaitExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Async function parameters must not contain await expressions'));
});
}
params = params.clearNewTargetExpressions();
body = body.clearNewTargetExpressions();
if (isStrictFunctionBody(node.body)) {
params = params.enforceStrictErrors();
body = body.enforceStrictErrors();
}
let s = super.reduceFunctionDeclaration(node, { name, params, body });
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
}
s = s.clearYieldExpressions();
s = s.clearAwaitExpressions();
s = s.observeFunctionDeclaration();
return s;
}
reduceFunctionExpression(node, { name, params, body }) {
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
let addError = !isSimpleParameterList || node.isGenerator ? 'addError' : 'addStrictError';
params.lexicallyDeclaredNames.forEachEntry((nodes, bindingName) => {
if (nodes.length > 1) {
nodes.slice(1).forEach(dupeNode => {
params = params[addError](new EarlyError(dupeNode, `Duplicate binding ${JSON.stringify(bindingName)}`));
});
}
});
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
body = body.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
params = params.enforceSuperCallExpressions(SUPERCALL_ERROR);
params = params.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
if (node.isGenerator) {
params.yieldExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Generator parameters must not contain yield expressions'));
});
}
if (node.isAsync) {
params.awaitExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Async function parameters must not contain await expressions'));
});
}
params = params.clearNewTargetExpressions();
body = body.clearNewTargetExpressions();
if (isStrictFunctionBody(node.body)) {
params = params.enforceStrictErrors();
body = body.enforceStrictErrors();
}
let s = super.reduceFunctionExpression(node, { name, params, body });
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
}
s = s.clearBoundNames();
s = s.clearYieldExpressions();
s = s.clearAwaitExpressions();
s = s.observeVarBoundary();
return s;
}
reduceGetter(node, { name, body }) {
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
body = body.clearSuperPropertyExpressions();
body = body.clearNewTargetExpressions();
if (isStrictFunctionBody(node.body)) {
body = body.enforceStrictErrors();
}
let s = super.reduceGetter(node, { name, body });
s = s.observeVarBoundary();
return s;
}
reduceIdentifierExpression(node) {
let s = this.identity;
if (isStrictModeReservedWord(node.name)) {
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.name)} must not be in expression position in strict mode`));
}
return s;
}
reduceIfStatement(node, { test, consequent, alternate }) {
if (isLabelledFunction(node.consequent)) {
consequent = consequent.addError(new EarlyError(node.consequent, 'The consequent of an if statement must not be a labeled function declaration'));
}
if (node.alternate != null && isLabelledFunction(node.alternate)) {
alternate = alternate.addError(new EarlyError(node.alternate, 'The alternate of an if statement must not be a labeled function declaration'));
}
if (node.consequent.type === 'FunctionDeclaration') {
consequent = consequent.addStrictError(new EarlyError(node.consequent, 'FunctionDeclarations in IfStatements are disallowed in strict mode'));
consequent = consequent.observeLexicalBoundary();
}
if (node.alternate != null && node.alternate.type === 'FunctionDeclaration') {
alternate = alternate.addStrictError(new EarlyError(node.alternate, 'FunctionDeclarations in IfStatements are disallowed in strict mode'));
alternate = alternate.observeLexicalBoundary();
}
return super.reduceIfStatement(node, { test, consequent, alternate });
}
reduceImport() {
let s = super.reduceImport(...arguments);
s = s.observeLexicalDeclaration();
return s;
}
reduceImportNamespace() {
let s = super.reduceImportNamespace(...arguments);
s = s.observeLexicalDeclaration();
return s;
}
reduceLabeledStatement(node) {
let s = super.reduceLabeledStatement(...arguments);
if (node.label === 'yield' || isStrictModeReservedWord(node.label)) {
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.label)} must not be in label position in strict mode`));
}
if (s.usedLabelNames.indexOf(node.label) >= 0) {
s = s.addError(new EarlyError(node, `Label ${JSON.stringify(node.label)} has already been declared`));
}
if (node.body.type === 'FunctionDeclaration') {
s = s.addStrictError(new EarlyError(node, 'Labeled FunctionDeclarations are disallowed in strict mode'));
}
s = isIterationStatement(node.body)
? s.observeIterationLabel(node.label)
: s.observeNonIterationLabel(node.label);
return s;
}
reduceLiteralRegExpExpression() {
let s = this.identity;
// NOTE: the RegExp pattern acceptor is disabled until we have more confidence in its correctness (more tests)
// if (!PatternAcceptor.test(node.pattern, node.flags.indexOf("u") >= 0)) {
// s = s.addError(new EarlyError(node, "Invalid regular expression pattern"));
// }
return s;
}
reduceMethod(node, { name, params, body }) {
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
params = params.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
if (node.name.type === 'StaticPropertyName' && node.name.value === 'constructor') {
body = body.observeConstructorMethod();
params = params.observeConstructorMethod();
} else {
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
params = params.enforceSuperCallExpressions(SUPERCALL_ERROR);
}
if (node.isGenerator) {
params.yieldExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Generator parameters must not contain yield expressions'));
});
}
if (node.isAsync) {
params.awaitExpressions.forEach(n => {
params = params.addError(new EarlyError(n, 'Async function parameters must not contain await expressions'));
});
}
body = body.clearSuperPropertyExpressions();
params = params.clearSuperPropertyExpressions();
params = params.clearNewTargetExpressions();
body = body.clearNewTargetExpressions();
if (isStrictFunctionBody(node.body)) {
params = params.enforceStrictErrors();
body = body.enforceStrictErrors();
}
let s = super.reduceMethod(node, { name, params, body });
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
}
s = s.clearYieldExpressions();
s = s.clearAwaitExpressions();
s = s.observeVarBoundary();
return s;
}
reduceModule() {
let s = super.reduceModule(...arguments);
s = s.functionDeclarationNamesAreLexical();
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
s.exportedNames.forEachEntry((nodes, bindingName) => {
if (nodes.length > 1) {
nodes.slice(1).forEach(dupeNode => {
s = s.addError(new EarlyError(dupeNode, `Duplicate export ${JSON.stringify(bindingName)}`));
});
}
});
s.exportedBindings.forEachEntry((nodes, bindingName) => {
if (!s.lexicallyDeclaredNames.has(bindingName) && !s.varDeclaredNames.has(bindingName)) {
nodes.forEach(undeclaredNode => {
s = s.addError(new EarlyError(undeclaredNode, `Exported binding ${JSON.stringify(bindingName)} is not declared`));
});
}
});
s.newTargetExpressions.forEach(node => {
s = s.addError(new EarlyError(node, 'new.target must be within function (but not arrow expression) code'));
});
s = s.enforceFreeContinueStatementErrors(FREE_CONTINUE);
s = s.enforceFreeLabeledContinueStatementErrors(UNBOUND_CONTINUE);
s = s.enforceFreeBreakStatementErrors(FREE_BREAK);
s = s.enforceFreeLabeledBreakStatementErrors(UNBOUND_BREAK);
s = s.enforceSuperCallExpressions(SUPERCALL_ERROR);
s = s.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
s = s.enforceStrictErrors();
return s;
}
reduceNewTargetExpression(node) {
return this.identity.observeNewTargetExpression(node);
}
reduceObjectExpression(node) {
let s = super.reduceObjectExpression(...arguments);
s = s.enforceSuperCallExpressionsInConstructorMethod(SUPERCALL_ERROR);
let protos = node.properties.filter(p => p.type === 'DataProperty' && p.name.type === 'StaticPropertyName' && p.name.value === '__proto__');
protos.slice(1).forEach(n => {
s = s.addError(new EarlyError(n, 'Duplicate __proto__ property in object literal not allowed'));
});
return s;
}
reduceUpdateExpression() {
let s = super.reduceUpdateExpression(...arguments);
s = s.clearBoundNames();
return s;
}
reduceUnaryExpression(node) {
let s = super.reduceUnaryExpression(...arguments);
if (node.operator === 'delete' && node.operand.type === 'IdentifierExpression') {
s = s.addStrictError(new EarlyError(node, 'Identifier expressions must not be deleted in strict mode'));
}
return s;
}
reduceScript(node) {
let s = super.reduceScript(...arguments);
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
s.newTargetExpressions.forEach(n => {
s = s.addError(new EarlyError(n, 'new.target must be within function (but not arrow expression) code'));
});
s = s.enforceFreeContinueStatementErrors(FREE_CONTINUE);
s = s.enforceFreeLabeledContinueStatementErrors(UNBOUND_CONTINUE);
s = s.enforceFreeBreakStatementErrors(FREE_BREAK);
s = s.enforceFreeLabeledBreakStatementErrors(UNBOUND_BREAK);
s = s.enforceSuperCallExpressions(SUPERCALL_ERROR);
s = s.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
if (isStrictFunctionBody(node)) {
s = s.enforceStrictErrors();
}
return s;
}
reduceSetter(node, { name, param, body }) {
let isSimpleParameterList = node.param.type === 'BindingIdentifier';
param = param.observeLexicalDeclaration();
param = param.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
body = body.enforceConflictingLexicallyDeclaredNames(param.lexicallyDeclaredNames, DUPLICATE_BINDING);
param = param.enforceSuperCallExpressions(SUPERCALL_ERROR);
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
param = param.clearSuperPropertyExpressions();
body = body.clearSuperPropertyExpressions();
param = param.clearNewTargetExpressions();
body = body.clearNewTargetExpressions();
if (isStrictFunctionBody(node.body)) {
param = param.enforceStrictErrors();
body = body.enforceStrictErrors();
}
let s = super.reduceSetter(node, { name, param, body });
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
}
s = s.observeVarBoundary();
return s;
}
reduceStaticMemberExpression(node) {
let s = super.reduceStaticMemberExpression(...arguments);
if (node.object.type === 'Super') {
s = s.observeSuperPropertyExpression(node);
}
return s;
}
reduceSwitchStatement(node, { discriminant, cases }) {
let sCases = this.append(...cases);
sCases = sCases.functionDeclarationNamesAreLexical();
sCases = sCases.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
sCases = sCases.enforceConflictingLexicallyDeclaredNames(sCases.varDeclaredNames, DUPLICATE_BINDING);
sCases = sCases.observeLexicalBoundary();
let s = this.append(discriminant, sCases);
s = s.clearFreeBreakStatements();
return s;
}
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
let sCases = this.append(defaultCase, ...preDefaultCases, ...postDefaultCases);
sCases = sCases.functionDeclarationNamesAreLexical();
sCases = sCases.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
sCases = sCases.enforceConflictingLexicallyDeclaredNames(sCases.varDeclaredNames, DUPLICATE_BINDING);
sCases = sCases.observeLexicalBoundary();
let s = this.append(discriminant, sCases);
s = s.clearFreeBreakStatements();
return s;
}
reduceVariableDeclaration(node) {
let s = super.reduceVariableDeclaration(...arguments);
switch (node.kind) {
case 'const':
case 'let': {
s = s.observeLexicalDeclaration();
if (s.lexicallyDeclaredNames.has('let')) {
s.lexicallyDeclaredNames.get('let').forEach(n => {
s = s.addError(new EarlyError(n, 'Lexical declarations must not have a binding named "let"'));
});
}
break;
}
case 'var':
s = s.observeVarDeclaration();
break;
}
return s;
}
reduceVariableDeclarationStatement(node) {
let s = super.reduceVariableDeclarationStatement(...arguments);
if (node.declaration.kind === 'const') {
node.declaration.declarators.forEach(declarator => {
if (declarator.init == null) {
s = s.addError(new EarlyError(declarator, 'Constant lexical declarations must have an initialiser'));
}
});
}
return s;
}
reduceWhileStatement(node) {
let s = super.reduceWhileStatement(...arguments);
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a while statement must not be a labeled function declaration'));
}
s = s.clearFreeContinueStatements().clearFreeBreakStatements();
return s;
}
reduceWithStatement(node) {
let s = super.reduceWithStatement(...arguments);
if (isLabelledFunction(node.body)) {
s = s.addError(new EarlyError(node.body, 'The body of a with statement must not be a labeled function declaration'));
}
s = s.addStrictError(new EarlyError(node, 'Strict mode code must not include a with statement'));
return s;
}
reduceYieldExpression(node) {
let s = super.reduceYieldExpression(...arguments);
s = s.observeYieldExpression(node);
return s;
}
reduceYieldGeneratorExpression(node) {
let s = super.reduceYieldGeneratorExpression(...arguments);
s = s.observeYieldExpression(node);
return s;
}
static check(node) {
return reduce(new EarlyErrorChecker, node).errors;
}
}
module.exports = { EarlyErrorChecker };