Add consumption points and error reporting for labelled statement errors
This commit is contained in:
Родитель
1a66243d4f
Коммит
b9971f2876
|
@ -91,7 +91,6 @@ module ts {
|
|||
Invalid_left_hand_side_in_for_in_statement: { code: 1103, category: DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...in' statement." },
|
||||
A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: { code: 1104, category: DiagnosticCategory.Error, key: "A 'continue' statement can only be used within an enclosing iteration statement." },
|
||||
A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: { code: 1105, category: DiagnosticCategory.Error, key: "A 'break' statement can only be used within an enclosing iteration or switch statement." },
|
||||
Jump_target_not_found: { code: 1106, category: DiagnosticCategory.Error, key: "Jump target not found." },
|
||||
Jump_target_cannot_cross_function_boundary: { code: 1107, category: DiagnosticCategory.Error, key: "Jump target cannot cross function boundary." },
|
||||
A_return_statement_can_only_be_used_within_a_function_body: { code: 1108, category: DiagnosticCategory.Error, key: "A 'return' statement can only be used within a function body." },
|
||||
Expression_expected: { code: -9999999, category: DiagnosticCategory.Error, key: "Expression expected." },
|
||||
|
@ -99,6 +98,9 @@ module ts {
|
|||
A_constructor_implementation_cannot_be_declared_in_an_ambient_context: { code: 1111, category: DiagnosticCategory.Error, key: "A constructor implementation cannot be declared in an ambient context." },
|
||||
A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." },
|
||||
A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." },
|
||||
Duplicate_label_0: { code: 1114, category: DiagnosticCategory.Error, key: "Duplicate label '{0}'" },
|
||||
A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement: { code: 1115, category: DiagnosticCategory.Error, key: "A 'continue' statement can only jump to a label of an enclosing iteration statement." },
|
||||
A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement: { code: 1116, category: DiagnosticCategory.Error, key: "A 'break' statement can only jump to a label of an enclosing statement." },
|
||||
Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
|
||||
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead." },
|
||||
Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." },
|
||||
|
|
|
@ -356,10 +356,6 @@
|
|||
"category": "Error",
|
||||
"code": 1105
|
||||
},
|
||||
"Jump target not found.": {
|
||||
"category": "Error",
|
||||
"code": 1106
|
||||
},
|
||||
"Jump target cannot cross function boundary.": {
|
||||
"category": "Error",
|
||||
"code": 1107
|
||||
|
@ -388,6 +384,18 @@
|
|||
"category": "Error",
|
||||
"code": 1113
|
||||
},
|
||||
"Duplicate label '{0}'": {
|
||||
"category": "Error",
|
||||
"code": 1114
|
||||
},
|
||||
"A 'continue' statement can only jump to a label of an enclosing iteration statement.": {
|
||||
"category": "Error",
|
||||
"code": 1115
|
||||
},
|
||||
"A 'break' statement can only jump to a label of an enclosing statement.": {
|
||||
"category": "Error",
|
||||
"code": 1116
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
|
|
|
@ -401,13 +401,17 @@ module ts {
|
|||
var labelledStatementInfo = (() => {
|
||||
// TODO(jfreeman): Implement a data structure for tracking labels
|
||||
var functionBoundarySentinel = <LabelledStatement>{};
|
||||
var labelledStatementStack: LabelledStatement[];
|
||||
var currentLabelSet: Identifier[];
|
||||
var labelSetStack: Identifier[][];
|
||||
var isIterationStack: boolean[];
|
||||
|
||||
// TODO(jfreeman): Fill in these stubs
|
||||
return {
|
||||
pushLabelledStatement: (statement: LabelledStatement) => { },
|
||||
addLabel: (label: Identifier) => { },
|
||||
pushCurrentLabelSet: (isIterationStatement: boolean) => { },
|
||||
pushFunctionBoundary: () => { },
|
||||
pop: () => { }
|
||||
pop: () => { },
|
||||
labelExists: (label: Identifier, requireIterationStatement: boolean): boolean => false,
|
||||
};
|
||||
})();
|
||||
|
||||
|
@ -2082,7 +2086,10 @@ module ts {
|
|||
|
||||
// In an ambient context, we will already give an error for having a statement.
|
||||
if (!inAmbientContext && errorCountBeforeStatement === file.syntacticErrors.length) {
|
||||
if (!node.label) {
|
||||
if (node.label) {
|
||||
checkBreakOrContinueStatementWithLabel(node.label, kind);
|
||||
}
|
||||
else {
|
||||
checkAnonymousBreakOrContinueStatement(kind, keywordStart, keywordLength);
|
||||
}
|
||||
}
|
||||
|
@ -2123,6 +2130,22 @@ module ts {
|
|||
grammarErrorAtPos(errorStart, errorLength, Diagnostics.Jump_target_cannot_cross_function_boundary);
|
||||
}
|
||||
|
||||
function checkBreakOrContinueStatementWithLabel(label: Identifier, kind: SyntaxKind): void {
|
||||
if (labelledStatementInfo.labelExists(label, /*requireIterationStatement*/ kind === SyntaxKind.ContinueStatement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kind === SyntaxKind.ContinueStatement) {
|
||||
grammarErrorOnNode(label, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement);
|
||||
}
|
||||
else if (kind === SyntaxKind.BreakStatement) {
|
||||
grammarErrorOnNode(label, Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement);
|
||||
}
|
||||
else {
|
||||
Debug.fail("checkBreakOrContinueStatementWithLabel");
|
||||
}
|
||||
}
|
||||
|
||||
function parseReturnStatement(): ReturnStatement {
|
||||
var node = <ReturnStatement>createNode(SyntaxKind.ReturnStatement);
|
||||
var errorCountBeforeReturnStatement = file.syntacticErrors.length;
|
||||
|
@ -2261,11 +2284,34 @@ module ts {
|
|||
return finishNode(node);
|
||||
}
|
||||
|
||||
function isIterationStatementStart(): boolean {
|
||||
return token === SyntaxKind.WhileKeyword || token === SyntaxKind.DoKeyword || token === SyntaxKind.ForKeyword;
|
||||
}
|
||||
|
||||
function parseStatementWithLabelSet(): Statement {
|
||||
labelledStatementInfo.pushCurrentLabelSet(isIterationStatementStart());
|
||||
var statement = parseStatement();
|
||||
labelledStatementInfo.pop();
|
||||
return statement;
|
||||
}
|
||||
|
||||
function isLabel(): boolean {
|
||||
return isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.ColonToken);
|
||||
}
|
||||
|
||||
function parseLabelledStatement(): LabelledStatement {
|
||||
var node = <LabelledStatement>createNode(SyntaxKind.LabelledStatement);
|
||||
node.label = parseIdentifier();
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.statement = parseStatement();
|
||||
|
||||
if (labelledStatementInfo.labelExists(node.label, /*requireIterationStatement*/ false)) {
|
||||
grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0);
|
||||
}
|
||||
labelledStatementInfo.addLabel(node.label);
|
||||
|
||||
// We only want to call parseStatementWithLabelSet when the label set is complete
|
||||
// Therefore, keep parsing labels until we know we're done.
|
||||
node.statement = isLabel() ? parseLabelledStatement() : parseStatementWithLabelSet();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
|
@ -2355,7 +2401,7 @@ module ts {
|
|||
case SyntaxKind.DebuggerKeyword:
|
||||
return parseDebuggerStatement();
|
||||
default:
|
||||
if (isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.ColonToken)) {
|
||||
if (isLabel()) {
|
||||
return parseLabelledStatement();
|
||||
}
|
||||
return parseExpressionStatement();
|
||||
|
|
Загрузка…
Ссылка в новой задаче