From e2617750b1ab7580687a153645c7e3300c6b53ec Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 22 Jul 2014 15:45:51 -0700 Subject: [PATCH 1/7] Track control flow contexts in the parser, and give errors for break, continue, return --- .../diagnosticInformationMap.generated.ts | 7 +- src/compiler/diagnosticMessages.json | 10 +-- src/compiler/parser.ts | 79 ++++++++++++++++++- src/compiler/types.ts | 12 ++- 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 8f58d9f3042..54dd92ca36a 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -89,11 +89,11 @@ module ts { with_statements_are_not_allowed_in_strict_mode: { code: 1101, category: DiagnosticCategory.Error, key: "'with' statements are not allowed in strict mode." }, delete_cannot_be_called_on_an_identifier_in_strict_mode: { code: 1102, category: DiagnosticCategory.Error, key: "'delete' cannot be called on an identifier in strict mode." }, Invalid_left_hand_side_in_for_in_statement: { code: 1103, category: DiagnosticCategory.Error, key: "Invalid left-hand side in 'for...in' statement." }, - continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: { code: 1104, category: DiagnosticCategory.Error, key: "'continue' statement can only be used within an enclosing iteration statement." }, - break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: { code: 1105, category: DiagnosticCategory.Error, key: "'break' statement can only be used within an enclosing iteration or switch 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." }, - return_statement_must_be_contained_within_a_function_body: { code: 1108, category: DiagnosticCategory.Error, key: "'return' statement must be contained within a function body." }, + 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." }, Type_expected: { code: -9999999, category: DiagnosticCategory.Error, key: "Type expected." }, 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." }, @@ -269,7 +269,6 @@ module ts { Unknown_identifier_0: { code: -9999999, category: DiagnosticCategory.Error, key: "Unknown identifier '{0}'." }, Property_0_is_inaccessible: { code: -9999999, category: DiagnosticCategory.Error, key: "Property '{0}' is inaccessible." }, Function_implementation_expected: { code: -9999999, category: DiagnosticCategory.Error, key: "Function implementation expected." }, - return_statement_has_no_containing_function: { code: -9999999, category: DiagnosticCategory.Error, key: "'return' statement has no containing function." }, Property_0_of_type_1_is_not_assignable_to_string_index_type_2: { code: -9999999, category: DiagnosticCategory.Error, key: "Property '{0}' of type '{1}' is not assignable to string index type '{2}'." }, Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2: { code: -9999999, category: DiagnosticCategory.Error, key: "Property '{0}' of type '{1}' is not assignable to numeric index type '{2}'." }, Numeric_index_type_0_is_not_assignable_to_string_index_type_1: { code: -9999999, category: DiagnosticCategory.Error, key: "Numeric index type '{0}' is not assignable to string index type '{1}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b418ec7a404..05f5280ad8f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -348,11 +348,11 @@ "category": "Error", "code": 1103 }, - "'continue' statement can only be used within an enclosing iteration statement.": { + "A 'continue' statement can only be used within an enclosing iteration statement.": { "category": "Error", "code": 1104 }, - "'break' statement can only be used within an enclosing iteration or switch statement.": { + "A 'break' statement can only be used within an enclosing iteration or switch statement.": { "category": "Error", "code": 1105 }, @@ -364,7 +364,7 @@ "category": "Error", "code": 1107 }, - "'return' statement must be contained within a function body.": { + "A 'return' statement can only be used within a function body.": { "category": "Error", "code": 1108 }, @@ -1095,10 +1095,6 @@ "category": "Error", "code": -9999999 }, - "'return' statement has no containing function.": { - "category": "Error", - "code": -9999999 - }, "Property '{0}' of type '{1}' is not assignable to string index type '{2}'.": { "category": "Error", "code": -9999999 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 67b0e2f9dac..7d34f8987c4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -373,6 +373,14 @@ module ts { Preserve } + // Tracks whether we nested (directly or indirectly) in a certain control block. + // Used for validating break and continue statements. + enum ControlBlockContext { + NotNested, + Nested, + CrossingFunctionBoundary + } + export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget): SourceFile { var file: SourceFile; var scanner: Scanner; @@ -386,6 +394,19 @@ module ts { var lookAheadMode = LookAheadMode.NotLookingAhead; var inAmbientContext = false; + var inFunctionBody = false; + var inSwitchStatement = ControlBlockContext.NotNested; + var inIterationStatement = ControlBlockContext.NotNested; + + var labelledStatementInfo = (() => { + var functionBoundarySentinel = {}; + var labelledStatementStack: LabelledStatement[]; + return { + getLength: (): number => 0, + enqueueFunctionBoundary: () => { }, + resetStack: (length: number) => { } + }; + })(); function getLineAndCharacterlFromSourcePosition(position: number) { if (!lineStarts) { @@ -1914,8 +1935,29 @@ module ts { } function parseBody(ignoreMissingOpenBrace: boolean): Block { + var saveInFunctionBody = inFunctionBody; + var saveInSwitchStatement = inSwitchStatement; + var saveInIterationStatement = inIterationStatement; + + inFunctionBody = true; + if (inSwitchStatement === ControlBlockContext.Nested) { + inSwitchStatement = ControlBlockContext.CrossingFunctionBoundary; + } + if (inIterationStatement === ControlBlockContext.Nested) { + inIterationStatement = ControlBlockContext.CrossingFunctionBoundary; + } + + var labelStackLength = labelledStatementInfo.getLength(); + labelledStatementInfo.enqueueFunctionBoundary(); + var block = parseBlock(ignoreMissingOpenBrace); block.kind = SyntaxKind.FunctionBlock; + + labelledStatementInfo.resetStack(labelStackLength); + inFunctionBody = saveInFunctionBody; + inSwitchStatement = saveInSwitchStatement; + inIterationStatement = saveInIterationStatement; + return block; } @@ -1939,7 +1981,12 @@ module ts { function parseDoStatement(): DoStatement { var node = createNode(SyntaxKind.DoStatement); parseExpected(SyntaxKind.DoKeyword); + + var saveInIterationStatement = inIterationStatement; + inIterationStatement = ControlBlockContext.Nested; node.statement = parseStatement(); + inIterationStatement = saveInIterationStatement; + parseExpected(SyntaxKind.WhileKeyword); parseExpected(SyntaxKind.OpenParenToken); node.expression = parseExpression(); @@ -1959,7 +2006,12 @@ module ts { parseExpected(SyntaxKind.OpenParenToken); node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); + + var saveInIterationStatement = inIterationStatement; + inIterationStatement = ControlBlockContext.Nested; node.statement = parseStatement(); + inIterationStatement = saveInIterationStatement; + return finishNode(node); } @@ -1978,6 +2030,7 @@ module ts { var varOrInit = parseExpression(true); } } + var forOrForInStatement: IterationStatement; if (parseOptional(SyntaxKind.InKeyword)) { var forInStat = createNode(SyntaxKind.ForInStatement, pos); if (declarations) { @@ -1991,8 +2044,7 @@ module ts { } forInStat.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); - forInStat.statement = parseStatement(); - return finishNode(forInStat); + forOrForInStatement = forInStat; } else { var forStat = createNode(SyntaxKind.ForStatement, pos); @@ -2007,9 +2059,15 @@ module ts { forStat.iterator = parseExpression(); } parseExpected(SyntaxKind.CloseParenToken); - forStat.statement = parseStatement(); - return finishNode(forStat); + forOrForInStatement = forStat; } + + var saveInIterationStatement = inIterationStatement; + inIterationStatement = ControlBlockContext.Nested; + forOrForInStatement.statement = parseStatement(); + inIterationStatement = saveInIterationStatement; + + return finishNode(forOrForInStatement); } function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { @@ -2022,9 +2080,17 @@ module ts { function parseReturnStatement(): ReturnStatement { var node = createNode(SyntaxKind.ReturnStatement); + var errorCountBeforeReturnStatement = file.syntacticErrors.length; + var returnTokenStart = scanner.getTokenPos(); + var returnTokenLength = scanner.getTextPos() - returnTokenStart; + parseExpected(SyntaxKind.ReturnKeyword); if (!isSemicolon()) node.expression = parseExpression(); parseSemicolon(); + + if (!inFunctionBody && errorCountBeforeReturnStatement === file.syntacticErrors.length) { + grammarErrorAtPos(returnTokenStart, returnTokenLength, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); + } return finishNode(node); } @@ -2066,7 +2132,12 @@ module ts { node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); parseExpected(SyntaxKind.OpenBraceToken); + + var saveInSwitchStatement = inSwitchStatement; + inSwitchStatement = ControlBlockContext.Nested; node.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); + inSwitchStatement = saveInSwitchStatement; + parseExpected(SyntaxKind.CloseBraceToken); // Error on duplicate 'default' clauses. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5decadcfe17..8aeea1ad235 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -402,17 +402,21 @@ module ts { elseStatement?: Statement; } - export interface DoStatement extends Statement { + export interface IterationStatement extends Statement { + statement: Statement; + } + + export interface DoStatement extends IterationStatement { statement: Statement; expression: Expression; } - export interface WhileStatement extends Statement { + export interface WhileStatement extends IterationStatement { statement: Statement; expression: Expression; } - export interface ForStatement extends Statement { + export interface ForStatement extends IterationStatement { declarations?: NodeArray; initializer?: Expression; condition?: Expression; @@ -420,7 +424,7 @@ module ts { statement: Statement; } - export interface ForInStatement extends Statement { + export interface ForInStatement extends IterationStatement { declaration?: VariableDeclaration; variable?: Expression; expression: Expression; From 76804eb1f9bcb301f07efdb91a6b91dc806f9e29 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 22 Jul 2014 16:36:53 -0700 Subject: [PATCH 2/7] Add errors for break and continue statements --- src/compiler/checker.ts | 3 - src/compiler/parser.ts | 54 +++++++++++++++- src/compiler/types.ts | 4 -- ...otInIterationOrSwitchStatement1.errors.txt | 4 ++ .../breakNotInIterationOrSwitchStatement1.js | 5 -- ...otInIterationOrSwitchStatement2.errors.txt | 8 +++ .../breakNotInIterationOrSwitchStatement2.js | 13 ---- ...ontinueNotInIterationStatement1.errors.txt | 4 ++ .../continueNotInIterationStatement1.js | 5 -- ...ontinueNotInIterationStatement2.errors.txt | 8 +++ .../continueNotInIterationStatement2.js | 13 ---- ...ontinueNotInIterationStatement3.errors.txt | 7 ++ .../continueNotInIterationStatement3.js | 11 ---- .../interfaceExtendingClass2.errors.txt | 4 +- .../invalidDoWhileBreakStatements.errors.txt | 41 ++++++++++++ .../invalidDoWhileBreakStatements.js | 64 ------------------- ...nvalidDoWhileContinueStatements.errors.txt | 41 ++++++++++++ .../invalidDoWhileContinueStatements.js | 64 ------------------- .../invalidForBreakStatements.errors.txt | 40 ++++++++++++ .../reference/invalidForBreakStatements.js | 62 ------------------ .../invalidForContinueStatements.errors.txt | 40 ++++++++++++ .../reference/invalidForContinueStatements.js | 62 ------------------ .../invalidForInBreakStatements.errors.txt | 41 ++++++++++++ .../reference/invalidForInBreakStatements.js | 63 ------------------ .../invalidForInContinueStatements.errors.txt | 41 ++++++++++++ .../invalidForInContinueStatements.js | 63 ------------------ .../invalidSwitchContinueStatement.errors.txt | 10 +++ .../invalidSwitchContinueStatement.js | 14 ---- .../invalidWhileBreakStatements.errors.txt | 41 ++++++++++++ .../reference/invalidWhileBreakStatements.js | 63 ------------------ .../invalidWhileContinueStatements.errors.txt | 41 ++++++++++++ .../invalidWhileContinueStatements.js | 63 ------------------ ...overloadOnConstAsTypeAnnotation.errors.txt | 6 +- ...serErrorRecovery_ModuleElement1.errors.txt | 8 +-- ...rserErrorRecovery_VariableList1.errors.txt | 6 +- .../reference/parserNotRegex1.errors.txt | 4 +- tests/baselines/reference/parserNotRegex1.js | 10 --- .../reference/parserPublicBreak1.errors.txt | 4 +- .../parserRegularExpression1.errors.txt | 4 +- .../reference/parserRegularExpression1.js | 5 -- .../parserReturnStatement1.d.errors.txt | 2 +- .../parserReturnStatement1.errors.txt | 4 ++ .../reference/parserReturnStatement1.js | 5 -- .../parserReturnStatement2.errors.txt | 6 ++ .../reference/parserReturnStatement2.js | 9 --- ...sNotAMemberVariableDeclaration1.errors.txt | 15 +---- ...atementIsNotAMemberVariableDeclaration1.js | 18 ------ .../reference/parserWithStatement2.errors.txt | 6 +- .../reference/parserWithStatement2.js | 7 -- ...r_breakNotInIterationOrSwitchStatement1.js | 5 -- ...r_breakNotInIterationOrSwitchStatement2.js | 13 ---- ...parser_continueNotInIterationStatement1.js | 5 -- ...parser_continueNotInIterationStatement2.js | 13 ---- ...parser_continueNotInIterationStatement3.js | 11 ---- .../reference/propertyWrappedInTry.errors.txt | 4 +- ...hStatementsWithMultipleDefaults.errors.txt | 4 +- ...r_breakNotInIterationOrSwitchStatement1.ts | 1 - ...r_breakNotInIterationOrSwitchStatement2.ts | 5 -- ...parser_continueNotInIterationStatement1.ts | 1 - ...parser_continueNotInIterationStatement2.ts | 5 -- ...parser_continueNotInIterationStatement3.ts | 4 -- 61 files changed, 463 insertions(+), 724 deletions(-) create mode 100644 tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt delete mode 100644 tests/baselines/reference/breakNotInIterationOrSwitchStatement1.js create mode 100644 tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt delete mode 100644 tests/baselines/reference/breakNotInIterationOrSwitchStatement2.js create mode 100644 tests/baselines/reference/continueNotInIterationStatement1.errors.txt delete mode 100644 tests/baselines/reference/continueNotInIterationStatement1.js create mode 100644 tests/baselines/reference/continueNotInIterationStatement2.errors.txt delete mode 100644 tests/baselines/reference/continueNotInIterationStatement2.js create mode 100644 tests/baselines/reference/continueNotInIterationStatement3.errors.txt delete mode 100644 tests/baselines/reference/continueNotInIterationStatement3.js create mode 100644 tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidDoWhileBreakStatements.js create mode 100644 tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidDoWhileContinueStatements.js create mode 100644 tests/baselines/reference/invalidForBreakStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidForBreakStatements.js create mode 100644 tests/baselines/reference/invalidForContinueStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidForContinueStatements.js create mode 100644 tests/baselines/reference/invalidForInBreakStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidForInBreakStatements.js create mode 100644 tests/baselines/reference/invalidForInContinueStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidForInContinueStatements.js create mode 100644 tests/baselines/reference/invalidSwitchContinueStatement.errors.txt delete mode 100644 tests/baselines/reference/invalidSwitchContinueStatement.js create mode 100644 tests/baselines/reference/invalidWhileBreakStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidWhileBreakStatements.js create mode 100644 tests/baselines/reference/invalidWhileContinueStatements.errors.txt delete mode 100644 tests/baselines/reference/invalidWhileContinueStatements.js delete mode 100644 tests/baselines/reference/parserNotRegex1.js delete mode 100644 tests/baselines/reference/parserRegularExpression1.js create mode 100644 tests/baselines/reference/parserReturnStatement1.errors.txt delete mode 100644 tests/baselines/reference/parserReturnStatement1.js create mode 100644 tests/baselines/reference/parserReturnStatement2.errors.txt delete mode 100644 tests/baselines/reference/parserReturnStatement2.js delete mode 100644 tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.js delete mode 100644 tests/baselines/reference/parserWithStatement2.js delete mode 100644 tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.js delete mode 100644 tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.js delete mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement1.js delete mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement2.js delete mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement3.js delete mode 100644 tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts delete mode 100644 tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts delete mode 100644 tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts delete mode 100644 tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts delete mode 100644 tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3c994fc3fe4..25c537f169a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5276,9 +5276,6 @@ module ts { } } } - else { - error(node, Diagnostics.return_statement_has_no_containing_function); - } } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7d34f8987c4..47df80893ff 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -394,13 +394,17 @@ module ts { var lookAheadMode = LookAheadMode.NotLookingAhead; var inAmbientContext = false; + var inModuleBody = false; var inFunctionBody = false; var inSwitchStatement = ControlBlockContext.NotNested; var inIterationStatement = ControlBlockContext.NotNested; var labelledStatementInfo = (() => { + // TODO(jfreeman): Implement a data structure for tracking labels var functionBoundarySentinel = {}; var labelledStatementStack: LabelledStatement[]; + + // TODO(jfreeman): Fill in these stubs return { getLength: (): number => 0, enqueueFunctionBoundary: () => { }, @@ -2072,12 +2076,56 @@ module ts { function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { var node = createNode(kind); + var errorCountBeforeStatement = file.syntacticErrors.length; + var keywordStart = scanner.getTokenPos(); + var keywordLength = scanner.getTextPos() - keywordStart; parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); if (!isSemicolon()) node.label = parseIdentifier(); parseSemicolon(); + + // In an ambient context, we will already give an error for having a statement. + if (!inAmbientContext && errorCountBeforeStatement === file.syntacticErrors.length) { + if (!node.label) { + checkAnonymousBreakOrContinueStatement(kind, keywordStart, keywordLength); + } + } return finishNode(node); } + function checkAnonymousBreakOrContinueStatement(kind: SyntaxKind, errorStart: number, errorLength: number): void { + if (kind === SyntaxKind.BreakStatement) { + if (inIterationStatement === ControlBlockContext.Nested + || inSwitchStatement === ControlBlockContext.Nested) { + return; + } + else if (inIterationStatement === ControlBlockContext.NotNested + && inSwitchStatement === ControlBlockContext.NotNested) { + grammarErrorAtPos(errorStart, errorLength, + Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement); + return; + } + // Fall through + } + else if (kind === SyntaxKind.ContinueStatement) { + if (inIterationStatement === ControlBlockContext.Nested) { + return; + } + else if (inIterationStatement === ControlBlockContext.NotNested) { + grammarErrorAtPos(errorStart, errorLength, + Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement); + return; + } + // Fall through + } + else { + Debug.fail("checkAnonymousBreakOrContinueStatement"); + } + + Debug.assert(inIterationStatement === ControlBlockContext.CrossingFunctionBoundary + || inSwitchStatement === ControlBlockContext.CrossingFunctionBoundary); + grammarErrorAtPos(errorStart, errorLength, Diagnostics.Jump_target_cannot_cross_function_boundary); + } + function parseReturnStatement(): ReturnStatement { var node = createNode(SyntaxKind.ReturnStatement); var errorCountBeforeReturnStatement = file.syntacticErrors.length; @@ -2088,7 +2136,7 @@ module ts { if (!isSemicolon()) node.expression = parseExpression(); parseSemicolon(); - if (!inFunctionBody && errorCountBeforeReturnStatement === file.syntacticErrors.length) { + if (!inFunctionBody && !inModuleBody && errorCountBeforeReturnStatement === file.syntacticErrors.length) { grammarErrorAtPos(returnTokenStart, returnTokenLength, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); } return finishNode(node); @@ -2827,7 +2875,11 @@ module ts { function parseModuleBody(): Block { var node = createNode(SyntaxKind.ModuleBlock); if (parseExpected(SyntaxKind.OpenBraceToken)) { + var saveInModuleBody = inModuleBody; + inModuleBody = true; node.statements = parseList(ParsingContext.ModuleElements, parseModuleElement); + inModuleBody = saveInModuleBody; + parseExpected(SyntaxKind.CloseBraceToken); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8aeea1ad235..6173750759f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -407,12 +407,10 @@ module ts { } export interface DoStatement extends IterationStatement { - statement: Statement; expression: Expression; } export interface WhileStatement extends IterationStatement { - statement: Statement; expression: Expression; } @@ -421,14 +419,12 @@ module ts { initializer?: Expression; condition?: Expression; iterator?: Expression; - statement: Statement; } export interface ForInStatement extends IterationStatement { declaration?: VariableDeclaration; variable?: Expression; expression: Expression; - statement: Statement; } export interface BreakOrContinueStatement extends Statement { diff --git a/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt b/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt new file mode 100644 index 00000000000..fb72cb2337f --- /dev/null +++ b/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt @@ -0,0 +1,4 @@ +==== tests/cases/compiler/breakNotInIterationOrSwitchStatement1.ts (1 errors) ==== + break; + ~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. \ No newline at end of file diff --git a/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.js b/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.js deleted file mode 100644 index 21ca5d4cce4..00000000000 --- a/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.js +++ /dev/null @@ -1,5 +0,0 @@ -//// [breakNotInIterationOrSwitchStatement1.ts] -break; - -//// [breakNotInIterationOrSwitchStatement1.js] -break; diff --git a/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt b/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt new file mode 100644 index 00000000000..3a04554decf --- /dev/null +++ b/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/compiler/breakNotInIterationOrSwitchStatement2.ts (1 errors) ==== + while (true) { + function f() { + break; + ~~~~~ +!!! Jump target cannot cross function boundary. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.js b/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.js deleted file mode 100644 index 531e5b5e5b6..00000000000 --- a/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [breakNotInIterationOrSwitchStatement2.ts] -while (true) { - function f() { - break; - } -} - -//// [breakNotInIterationOrSwitchStatement2.js] -while (true) { - function f() { - break; - } -} diff --git a/tests/baselines/reference/continueNotInIterationStatement1.errors.txt b/tests/baselines/reference/continueNotInIterationStatement1.errors.txt new file mode 100644 index 00000000000..6875d311520 --- /dev/null +++ b/tests/baselines/reference/continueNotInIterationStatement1.errors.txt @@ -0,0 +1,4 @@ +==== tests/cases/compiler/continueNotInIterationStatement1.ts (1 errors) ==== + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. \ No newline at end of file diff --git a/tests/baselines/reference/continueNotInIterationStatement1.js b/tests/baselines/reference/continueNotInIterationStatement1.js deleted file mode 100644 index b6fd1786cdf..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement1.js +++ /dev/null @@ -1,5 +0,0 @@ -//// [continueNotInIterationStatement1.ts] -continue; - -//// [continueNotInIterationStatement1.js] -continue; diff --git a/tests/baselines/reference/continueNotInIterationStatement2.errors.txt b/tests/baselines/reference/continueNotInIterationStatement2.errors.txt new file mode 100644 index 00000000000..945f8e7eede --- /dev/null +++ b/tests/baselines/reference/continueNotInIterationStatement2.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/compiler/continueNotInIterationStatement2.ts (1 errors) ==== + while (true) { + function f() { + continue; + ~~~~~~~~ +!!! Jump target cannot cross function boundary. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/continueNotInIterationStatement2.js b/tests/baselines/reference/continueNotInIterationStatement2.js deleted file mode 100644 index 047c3b49f06..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [continueNotInIterationStatement2.ts] -while (true) { - function f() { - continue; - } -} - -//// [continueNotInIterationStatement2.js] -while (true) { - function f() { - continue; - } -} diff --git a/tests/baselines/reference/continueNotInIterationStatement3.errors.txt b/tests/baselines/reference/continueNotInIterationStatement3.errors.txt new file mode 100644 index 00000000000..56aef1000f7 --- /dev/null +++ b/tests/baselines/reference/continueNotInIterationStatement3.errors.txt @@ -0,0 +1,7 @@ +==== tests/cases/compiler/continueNotInIterationStatement3.ts (1 errors) ==== + switch (0) { + default: + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + } \ No newline at end of file diff --git a/tests/baselines/reference/continueNotInIterationStatement3.js b/tests/baselines/reference/continueNotInIterationStatement3.js deleted file mode 100644 index 11018019871..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement3.js +++ /dev/null @@ -1,11 +0,0 @@ -//// [continueNotInIterationStatement3.ts] -switch (0) { - default: - continue; -} - -//// [continueNotInIterationStatement3.js] -switch (0) { - default: - continue; -} diff --git a/tests/baselines/reference/interfaceExtendingClass2.errors.txt b/tests/baselines/reference/interfaceExtendingClass2.errors.txt index bfff1be2b3c..d3de7666ea4 100644 --- a/tests/baselines/reference/interfaceExtendingClass2.errors.txt +++ b/tests/baselines/reference/interfaceExtendingClass2.errors.txt @@ -19,8 +19,8 @@ return 1; ~~~~~~ !!! Property or signature expected. - ~~~~~~~~~ -!!! 'return' statement has no containing function. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. }; ~ !!! Declaration or statement expected. diff --git a/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt b/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt new file mode 100644 index 00000000000..91852a9e77e --- /dev/null +++ b/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt @@ -0,0 +1,41 @@ +==== tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts (1 errors) ==== + // All errors + + // naked break not allowed + break; + ~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. + + // non-existent label + ONE: + do break TWO; while (true) + + // break from inside function + TWO: + do { + var x = () => { + break TWO; + } + }while (true) + + THREE: + do { + var fn = function () { + break THREE; + } + }while (true) + + // break forward + do { + break FIVE; + FIVE: + do { } while (true) + }while (true) + + // label on non-loop statement + NINE: + var y = 12; + + do { + break NINE; + }while (true) \ No newline at end of file diff --git a/tests/baselines/reference/invalidDoWhileBreakStatements.js b/tests/baselines/reference/invalidDoWhileBreakStatements.js deleted file mode 100644 index 4eab7f5098c..00000000000 --- a/tests/baselines/reference/invalidDoWhileBreakStatements.js +++ /dev/null @@ -1,64 +0,0 @@ -//// [invalidDoWhileBreakStatements.ts] -// All errors - -// naked break not allowed -break; - -// non-existent label -ONE: -do break TWO; while (true) - -// break from inside function -TWO: -do { - var x = () => { - break TWO; - } -}while (true) - -THREE: -do { - var fn = function () { - break THREE; - } -}while (true) - -// break forward -do { - break FIVE; - FIVE: - do { } while (true) -}while (true) - -// label on non-loop statement -NINE: -var y = 12; - -do { - break NINE; -}while (true) - -//// [invalidDoWhileBreakStatements.js] -break; -ONE: do - break TWO; -while (true); -TWO: do { - var x = function () { - break TWO; - }; -} while (true); -THREE: do { - var fn = function () { - break THREE; - }; -} while (true); -do { - break FIVE; - FIVE: do { - } while (true); -} while (true); -NINE: var y = 12; -do { - break NINE; -} while (true); diff --git a/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt b/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt new file mode 100644 index 00000000000..798afdc3b75 --- /dev/null +++ b/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt @@ -0,0 +1,41 @@ +==== tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts (1 errors) ==== + // All errors + + // naked continue not allowed + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + + // non-existent label + ONE: + do continue TWO; while (true) + + // continue from inside function + TWO: + do { + var x = () => { + continue TWO; + } + }while (true) + + THREE: + do { + var fn = function () { + continue THREE; + } + }while (true) + + // continue forward + do { + continue FIVE; + FIVE: + do { } while (true) + }while (true) + + // label on non-loop statement + NINE: + var y = 12; + + do { + continue NINE; + }while (true) \ No newline at end of file diff --git a/tests/baselines/reference/invalidDoWhileContinueStatements.js b/tests/baselines/reference/invalidDoWhileContinueStatements.js deleted file mode 100644 index ebb76c707ad..00000000000 --- a/tests/baselines/reference/invalidDoWhileContinueStatements.js +++ /dev/null @@ -1,64 +0,0 @@ -//// [invalidDoWhileContinueStatements.ts] -// All errors - -// naked continue not allowed -continue; - -// non-existent label -ONE: -do continue TWO; while (true) - -// continue from inside function -TWO: -do { - var x = () => { - continue TWO; - } -}while (true) - -THREE: -do { - var fn = function () { - continue THREE; - } -}while (true) - -// continue forward -do { - continue FIVE; - FIVE: - do { } while (true) -}while (true) - -// label on non-loop statement -NINE: -var y = 12; - -do { - continue NINE; -}while (true) - -//// [invalidDoWhileContinueStatements.js] -continue; -ONE: do - continue TWO; -while (true); -TWO: do { - var x = function () { - continue TWO; - }; -} while (true); -THREE: do { - var fn = function () { - continue THREE; - }; -} while (true); -do { - continue FIVE; - FIVE: do { - } while (true); -} while (true); -NINE: var y = 12; -do { - continue NINE; -} while (true); diff --git a/tests/baselines/reference/invalidForBreakStatements.errors.txt b/tests/baselines/reference/invalidForBreakStatements.errors.txt new file mode 100644 index 00000000000..0edc26132cb --- /dev/null +++ b/tests/baselines/reference/invalidForBreakStatements.errors.txt @@ -0,0 +1,40 @@ +==== tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts (1 errors) ==== + // All errors + + // naked break not allowed + break; + ~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. + + // non-existent label + ONE: + for(;;) break TWO; + + // break from inside function + TWO: + for(;;) { + var x = () => { + break TWO; + } + } + + THREE: + for(;;) { + var fn = function () { + break THREE; + } + } + + // break forward + for(;;) { + break FIVE; + FIVE: + for (; ;) { } + } + // label on non-loop statement + NINE: + var y = 12; + + for(;;) { + break NINE; + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForBreakStatements.js b/tests/baselines/reference/invalidForBreakStatements.js deleted file mode 100644 index 42a05d9d451..00000000000 --- a/tests/baselines/reference/invalidForBreakStatements.js +++ /dev/null @@ -1,62 +0,0 @@ -//// [invalidForBreakStatements.ts] -// All errors - -// naked break not allowed -break; - -// non-existent label -ONE: -for(;;) break TWO; - -// break from inside function -TWO: -for(;;) { - var x = () => { - break TWO; - } -} - -THREE: -for(;;) { - var fn = function () { - break THREE; - } -} - -// break forward -for(;;) { - break FIVE; - FIVE: - for (; ;) { } -} -// label on non-loop statement -NINE: -var y = 12; - -for(;;) { - break NINE; -} - -//// [invalidForBreakStatements.js] -break; -ONE: for (;;) - break TWO; -TWO: for (;;) { - var x = function () { - break TWO; - }; -} -THREE: for (;;) { - var fn = function () { - break THREE; - }; -} -for (;;) { - break FIVE; - FIVE: for (;;) { - } -} -NINE: var y = 12; -for (;;) { - break NINE; -} diff --git a/tests/baselines/reference/invalidForContinueStatements.errors.txt b/tests/baselines/reference/invalidForContinueStatements.errors.txt new file mode 100644 index 00000000000..e5bf379e931 --- /dev/null +++ b/tests/baselines/reference/invalidForContinueStatements.errors.txt @@ -0,0 +1,40 @@ +==== tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts (1 errors) ==== + // All errors + + // naked continue not allowed + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + + // non-existent label + ONE: + for(;;) continue TWO; + + // continue from inside function + TWO: + for(;;) { + var x = () => { + continue TWO; + } + } + + THREE: + for(;;) { + var fn = function () { + continue THREE; + } + } + + // continue forward + for(;;) { + continue FIVE; + FIVE: + for (; ;) { } + } + // label on non-loop statement + NINE: + var y = 12; + + for(;;) { + continue NINE; + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForContinueStatements.js b/tests/baselines/reference/invalidForContinueStatements.js deleted file mode 100644 index 1204fe981c7..00000000000 --- a/tests/baselines/reference/invalidForContinueStatements.js +++ /dev/null @@ -1,62 +0,0 @@ -//// [invalidForContinueStatements.ts] -// All errors - -// naked continue not allowed -continue; - -// non-existent label -ONE: -for(;;) continue TWO; - -// continue from inside function -TWO: -for(;;) { - var x = () => { - continue TWO; - } -} - -THREE: -for(;;) { - var fn = function () { - continue THREE; - } -} - -// continue forward -for(;;) { - continue FIVE; - FIVE: - for (; ;) { } -} -// label on non-loop statement -NINE: -var y = 12; - -for(;;) { - continue NINE; -} - -//// [invalidForContinueStatements.js] -continue; -ONE: for (;;) - continue TWO; -TWO: for (;;) { - var x = function () { - continue TWO; - }; -} -THREE: for (;;) { - var fn = function () { - continue THREE; - }; -} -for (;;) { - continue FIVE; - FIVE: for (;;) { - } -} -NINE: var y = 12; -for (;;) { - continue NINE; -} diff --git a/tests/baselines/reference/invalidForInBreakStatements.errors.txt b/tests/baselines/reference/invalidForInBreakStatements.errors.txt new file mode 100644 index 00000000000..a9b3034bccc --- /dev/null +++ b/tests/baselines/reference/invalidForInBreakStatements.errors.txt @@ -0,0 +1,41 @@ +==== tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts (1 errors) ==== + // All errors + + // naked break not allowed + break; + ~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. + + // non-existent label + ONE: + for (var x in {}) break TWO; + + // break from inside function + TWO: + for (var x in {}) { + var fn = () => { + break TWO; + } + } + + THREE: + for (var x in {}) { + var fn = function () { + break THREE; + } + } + + // break forward + for (var x in {}) { + break FIVE; + FIVE: + for (var x in {}) { } + } + + // label on non-loop statement + NINE: + var y = 12; + + for (var x in {}) { + break NINE; + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForInBreakStatements.js b/tests/baselines/reference/invalidForInBreakStatements.js deleted file mode 100644 index b9f4c0dcb97..00000000000 --- a/tests/baselines/reference/invalidForInBreakStatements.js +++ /dev/null @@ -1,63 +0,0 @@ -//// [invalidForInBreakStatements.ts] -// All errors - -// naked break not allowed -break; - -// non-existent label -ONE: -for (var x in {}) break TWO; - -// break from inside function -TWO: -for (var x in {}) { - var fn = () => { - break TWO; - } -} - -THREE: -for (var x in {}) { - var fn = function () { - break THREE; - } -} - -// break forward -for (var x in {}) { - break FIVE; - FIVE: - for (var x in {}) { } -} - -// label on non-loop statement -NINE: -var y = 12; - -for (var x in {}) { - break NINE; -} - -//// [invalidForInBreakStatements.js] -break; -ONE: for (var x in {}) - break TWO; -TWO: for (var x in {}) { - var fn = function () { - break TWO; - }; -} -THREE: for (var x in {}) { - var fn = function () { - break THREE; - }; -} -for (var x in {}) { - break FIVE; - FIVE: for (var x in {}) { - } -} -NINE: var y = 12; -for (var x in {}) { - break NINE; -} diff --git a/tests/baselines/reference/invalidForInContinueStatements.errors.txt b/tests/baselines/reference/invalidForInContinueStatements.errors.txt new file mode 100644 index 00000000000..690b40acdd9 --- /dev/null +++ b/tests/baselines/reference/invalidForInContinueStatements.errors.txt @@ -0,0 +1,41 @@ +==== tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts (1 errors) ==== + // All errors + + // naked continue not allowed + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + + // non-existent label + ONE: + for (var x in {}) continue TWO; + + // continue from inside function + TWO: + for (var x in {}) { + var fn = () => { + continue TWO; + } + } + + THREE: + for (var x in {}) { + var fn = function () { + continue THREE; + } + } + + // continue forward + for (var x in {}) { + continue FIVE; + FIVE: + for (var x in {}) { } + } + + // label on non-loop statement + NINE: + var y = 12; + + for (var x in {}) { + continue NINE; + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForInContinueStatements.js b/tests/baselines/reference/invalidForInContinueStatements.js deleted file mode 100644 index 8884f35034a..00000000000 --- a/tests/baselines/reference/invalidForInContinueStatements.js +++ /dev/null @@ -1,63 +0,0 @@ -//// [invalidForInContinueStatements.ts] -// All errors - -// naked continue not allowed -continue; - -// non-existent label -ONE: -for (var x in {}) continue TWO; - -// continue from inside function -TWO: -for (var x in {}) { - var fn = () => { - continue TWO; - } -} - -THREE: -for (var x in {}) { - var fn = function () { - continue THREE; - } -} - -// continue forward -for (var x in {}) { - continue FIVE; - FIVE: - for (var x in {}) { } -} - -// label on non-loop statement -NINE: -var y = 12; - -for (var x in {}) { - continue NINE; -} - -//// [invalidForInContinueStatements.js] -continue; -ONE: for (var x in {}) - continue TWO; -TWO: for (var x in {}) { - var fn = function () { - continue TWO; - }; -} -THREE: for (var x in {}) { - var fn = function () { - continue THREE; - }; -} -for (var x in {}) { - continue FIVE; - FIVE: for (var x in {}) { - } -} -NINE: var y = 12; -for (var x in {}) { - continue NINE; -} diff --git a/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt b/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt new file mode 100644 index 00000000000..c6ac769f7ac --- /dev/null +++ b/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt @@ -0,0 +1,10 @@ +==== tests/cases/conformance/statements/continueStatements/invalidSwitchContinueStatement.ts (1 errors) ==== + // continue is not allowed in a switch statement + + switch (12) { + case 5: + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + } + \ No newline at end of file diff --git a/tests/baselines/reference/invalidSwitchContinueStatement.js b/tests/baselines/reference/invalidSwitchContinueStatement.js deleted file mode 100644 index da3a5075e0e..00000000000 --- a/tests/baselines/reference/invalidSwitchContinueStatement.js +++ /dev/null @@ -1,14 +0,0 @@ -//// [invalidSwitchContinueStatement.ts] -// continue is not allowed in a switch statement - -switch (12) { - case 5: - continue; -} - - -//// [invalidSwitchContinueStatement.js] -switch (12) { - case 5: - continue; -} diff --git a/tests/baselines/reference/invalidWhileBreakStatements.errors.txt b/tests/baselines/reference/invalidWhileBreakStatements.errors.txt new file mode 100644 index 00000000000..4ad5b0cfff9 --- /dev/null +++ b/tests/baselines/reference/invalidWhileBreakStatements.errors.txt @@ -0,0 +1,41 @@ +==== tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts (1 errors) ==== + // All errors + + // naked break not allowed + break; + ~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. + + // non-existent label + ONE: + while (true) break TWO; + + // break from inside function + TWO: + while (true){ + var x = () => { + break TWO; + } + } + + THREE: + while (true) { + var fn = function () { + break THREE; + } + } + + // break forward + while (true) { + break FIVE; + FIVE: + while (true) { } + } + + // label on non-loop statement + NINE: + var y = 12; + + while (true) { + break NINE; + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidWhileBreakStatements.js b/tests/baselines/reference/invalidWhileBreakStatements.js deleted file mode 100644 index 9206a28d09d..00000000000 --- a/tests/baselines/reference/invalidWhileBreakStatements.js +++ /dev/null @@ -1,63 +0,0 @@ -//// [invalidWhileBreakStatements.ts] -// All errors - -// naked break not allowed -break; - -// non-existent label -ONE: -while (true) break TWO; - -// break from inside function -TWO: -while (true){ - var x = () => { - break TWO; - } -} - -THREE: -while (true) { - var fn = function () { - break THREE; - } -} - -// break forward -while (true) { - break FIVE; - FIVE: - while (true) { } -} - -// label on non-loop statement -NINE: -var y = 12; - -while (true) { - break NINE; -} - -//// [invalidWhileBreakStatements.js] -break; -ONE: while (true) - break TWO; -TWO: while (true) { - var x = function () { - break TWO; - }; -} -THREE: while (true) { - var fn = function () { - break THREE; - }; -} -while (true) { - break FIVE; - FIVE: while (true) { - } -} -NINE: var y = 12; -while (true) { - break NINE; -} diff --git a/tests/baselines/reference/invalidWhileContinueStatements.errors.txt b/tests/baselines/reference/invalidWhileContinueStatements.errors.txt new file mode 100644 index 00000000000..5dbc8fdaafa --- /dev/null +++ b/tests/baselines/reference/invalidWhileContinueStatements.errors.txt @@ -0,0 +1,41 @@ +==== tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts (1 errors) ==== + // All errors + + // naked continue not allowed + continue; + ~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + + // non-existent label + ONE: + while (true) continue TWO; + + // continue from inside function + TWO: + while (true){ + var x = () => { + continue TWO; + } + } + + THREE: + while (true) { + var fn = function () { + continue THREE; + } + } + + // continue forward + while (true) { + continue FIVE; + FIVE: + while (true) { } + } + + // label on non-loop statement + NINE: + var y = 12; + + while (true) { + continue NINE; + } \ No newline at end of file diff --git a/tests/baselines/reference/invalidWhileContinueStatements.js b/tests/baselines/reference/invalidWhileContinueStatements.js deleted file mode 100644 index afd5799a7cf..00000000000 --- a/tests/baselines/reference/invalidWhileContinueStatements.js +++ /dev/null @@ -1,63 +0,0 @@ -//// [invalidWhileContinueStatements.ts] -// All errors - -// naked continue not allowed -continue; - -// non-existent label -ONE: -while (true) continue TWO; - -// continue from inside function -TWO: -while (true){ - var x = () => { - continue TWO; - } -} - -THREE: -while (true) { - var fn = function () { - continue THREE; - } -} - -// continue forward -while (true) { - continue FIVE; - FIVE: - while (true) { } -} - -// label on non-loop statement -NINE: -var y = 12; - -while (true) { - continue NINE; -} - -//// [invalidWhileContinueStatements.js] -continue; -ONE: while (true) - continue TWO; -TWO: while (true) { - var x = function () { - continue TWO; - }; -} -THREE: while (true) { - var fn = function () { - continue THREE; - }; -} -while (true) { - continue FIVE; - FIVE: while (true) { - } -} -NINE: var y = 12; -while (true) { - continue NINE; -} diff --git a/tests/baselines/reference/overloadOnConstAsTypeAnnotation.errors.txt b/tests/baselines/reference/overloadOnConstAsTypeAnnotation.errors.txt index 2dcdf22960d..42336209049 100644 --- a/tests/baselines/reference/overloadOnConstAsTypeAnnotation.errors.txt +++ b/tests/baselines/reference/overloadOnConstAsTypeAnnotation.errors.txt @@ -2,7 +2,7 @@ var f: (x: 'hi') => number = ('hi') => { return 1; }; ~~ !!! ';' expected. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. ~~~~~~~~~~~~~~~~~~~ -!!! Specialized overload signature is not assignable to any non-specialized signature. - ~~~~~~~~~ -!!! 'return' statement has no containing function. \ No newline at end of file +!!! Specialized overload signature is not assignable to any non-specialized signature. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_ModuleElement1.errors.txt b/tests/baselines/reference/parserErrorRecovery_ModuleElement1.errors.txt index 56292f2a369..1a8a96d2dda 100644 --- a/tests/baselines/reference/parserErrorRecovery_ModuleElement1.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ModuleElement1.errors.txt @@ -1,13 +1,13 @@ ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ModuleElements/parserErrorRecovery_ModuleElement1.ts (4 errors) ==== return foo; - ~~~~~~~~~~~ -!!! 'return' statement has no containing function. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. } ~ !!! Declaration or statement expected. return bar; - ~~~~~~~~~~~ -!!! 'return' statement has no containing function. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. } ~ !!! Declaration or statement expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_VariableList1.errors.txt b/tests/baselines/reference/parserErrorRecovery_VariableList1.errors.txt index 5804357b5a4..2c27e1cebf3 100644 --- a/tests/baselines/reference/parserErrorRecovery_VariableList1.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_VariableList1.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserErrorRecovery_VariableList1.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/VariableLists/parserErrorRecovery_VariableList1.ts (2 errors) ==== var a, ~ !!! Trailing comma not allowed. - return; \ No newline at end of file + return; + ~~~~~~ +!!! A 'return' statement can only be used within a function body. \ No newline at end of file diff --git a/tests/baselines/reference/parserNotRegex1.errors.txt b/tests/baselines/reference/parserNotRegex1.errors.txt index ccb67029604..5f302243177 100644 --- a/tests/baselines/reference/parserNotRegex1.errors.txt +++ b/tests/baselines/reference/parserNotRegex1.errors.txt @@ -4,6 +4,6 @@ !!! Cannot find name 'a'. { return true; - ~~~~~~~~~~~~ -!!! 'return' statement has no containing function. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. } \ No newline at end of file diff --git a/tests/baselines/reference/parserNotRegex1.js b/tests/baselines/reference/parserNotRegex1.js deleted file mode 100644 index 1169640d850..00000000000 --- a/tests/baselines/reference/parserNotRegex1.js +++ /dev/null @@ -1,10 +0,0 @@ -//// [parserNotRegex1.ts] - if (a.indexOf(-(4/3))) // We should not get a regex here becuase of the / in the comment. - { - return true; - } - -//// [parserNotRegex1.js] -if (a.indexOf(-(4 / 3))) { - return true; -} diff --git a/tests/baselines/reference/parserPublicBreak1.errors.txt b/tests/baselines/reference/parserPublicBreak1.errors.txt index af0ddd96ae3..afd0cd5df74 100644 --- a/tests/baselines/reference/parserPublicBreak1.errors.txt +++ b/tests/baselines/reference/parserPublicBreak1.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserPublicBreak1.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserPublicBreak1.ts (2 errors) ==== public break; ~~~~~~ !!! Declaration or statement expected. + ~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. \ No newline at end of file diff --git a/tests/baselines/reference/parserRegularExpression1.errors.txt b/tests/baselines/reference/parserRegularExpression1.errors.txt index e2def505e32..f14e8c33120 100644 --- a/tests/baselines/reference/parserRegularExpression1.errors.txt +++ b/tests/baselines/reference/parserRegularExpression1.errors.txt @@ -1,4 +1,4 @@ ==== tests/cases/conformance/parser/ecmascript5/RegularExpressions/parserRegularExpression1.ts (1 errors) ==== return /(#?-?\d*\.\d\w*%?)|(@?#?[\w-?]+%?)/g; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! 'return' statement has no containing function. \ No newline at end of file + ~~~~~~ +!!! A 'return' statement can only be used within a function body. \ No newline at end of file diff --git a/tests/baselines/reference/parserRegularExpression1.js b/tests/baselines/reference/parserRegularExpression1.js deleted file mode 100644 index eb6fe1b7c8a..00000000000 --- a/tests/baselines/reference/parserRegularExpression1.js +++ /dev/null @@ -1,5 +0,0 @@ -//// [parserRegularExpression1.ts] -return /(#?-?\d*\.\d\w*%?)|(@?#?[\w-?]+%?)/g; - -//// [parserRegularExpression1.js] -return /(#?-?\d*\.\d\w*%?)|(@?#?[\w-?]+%?)/g; diff --git a/tests/baselines/reference/parserReturnStatement1.d.errors.txt b/tests/baselines/reference/parserReturnStatement1.d.errors.txt index d5b47b3e933..bbacb5d6c57 100644 --- a/tests/baselines/reference/parserReturnStatement1.d.errors.txt +++ b/tests/baselines/reference/parserReturnStatement1.d.errors.txt @@ -1,4 +1,4 @@ ==== tests/cases/conformance/parser/ecmascript5/Statements/parserReturnStatement1.d.ts (1 errors) ==== return; ~~~~~~ -!!! Statements are not allowed in ambient contexts. \ No newline at end of file +!!! A 'return' statement can only be used within a function body. \ No newline at end of file diff --git a/tests/baselines/reference/parserReturnStatement1.errors.txt b/tests/baselines/reference/parserReturnStatement1.errors.txt new file mode 100644 index 00000000000..7a3adc21aca --- /dev/null +++ b/tests/baselines/reference/parserReturnStatement1.errors.txt @@ -0,0 +1,4 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ReturnStatements/parserReturnStatement1.ts (1 errors) ==== + return; + ~~~~~~ +!!! A 'return' statement can only be used within a function body. \ No newline at end of file diff --git a/tests/baselines/reference/parserReturnStatement1.js b/tests/baselines/reference/parserReturnStatement1.js deleted file mode 100644 index 10ee6d83935..00000000000 --- a/tests/baselines/reference/parserReturnStatement1.js +++ /dev/null @@ -1,5 +0,0 @@ -//// [parserReturnStatement1.ts] -return; - -//// [parserReturnStatement1.js] -return; diff --git a/tests/baselines/reference/parserReturnStatement2.errors.txt b/tests/baselines/reference/parserReturnStatement2.errors.txt new file mode 100644 index 00000000000..f887561d72c --- /dev/null +++ b/tests/baselines/reference/parserReturnStatement2.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ReturnStatements/parserReturnStatement2.ts (1 errors) ==== + { + return; + ~~~~~~ +!!! A 'return' statement can only be used within a function body. + } \ No newline at end of file diff --git a/tests/baselines/reference/parserReturnStatement2.js b/tests/baselines/reference/parserReturnStatement2.js deleted file mode 100644 index b54cf2b5acd..00000000000 --- a/tests/baselines/reference/parserReturnStatement2.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserReturnStatement2.ts] -{ - return; -} - -//// [parserReturnStatement2.js] -{ - return; -} diff --git a/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt b/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt index 604acb796eb..0d8f7d23d3b 100644 --- a/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt +++ b/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.errors.txt @@ -1,22 +1,13 @@ ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserStatementIsNotAMemberVariableDeclaration1.ts (1 errors) ==== return { - ~~~~~~~~ - + ~~~~~~ +!!! A 'return' statement can only be used within a function body. "set": function (key, value) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // 'private' should not be considered a member variable here. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private[key] = value; - ~~~~~~~~~~~~~~~~~~~~~~~~~ - } - ~~~ - - }; - ~~ -!!! 'return' statement has no containing function. \ No newline at end of file + }; \ No newline at end of file diff --git a/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.js b/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.js deleted file mode 100644 index 333e1824db7..00000000000 --- a/tests/baselines/reference/parserStatementIsNotAMemberVariableDeclaration1.js +++ /dev/null @@ -1,18 +0,0 @@ -//// [parserStatementIsNotAMemberVariableDeclaration1.ts] -return { - - "set": function (key, value) { - - // 'private' should not be considered a member variable here. - private[key] = value; - - } - -}; - -//// [parserStatementIsNotAMemberVariableDeclaration1.js] -return { - "set": function (key, value) { - private[key] = value; - } -}; diff --git a/tests/baselines/reference/parserWithStatement2.errors.txt b/tests/baselines/reference/parserWithStatement2.errors.txt index aa87edfd36c..9212d1b27dd 100644 --- a/tests/baselines/reference/parserWithStatement2.errors.txt +++ b/tests/baselines/reference/parserWithStatement2.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/Statements/parserWithStatement2.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Statements/parserWithStatement2.ts (2 errors) ==== with (1) ~ !!! All symbols within a 'with' block will be resolved to 'any'. - return; \ No newline at end of file + return; + ~~~~~~ +!!! A 'return' statement can only be used within a function body. \ No newline at end of file diff --git a/tests/baselines/reference/parserWithStatement2.js b/tests/baselines/reference/parserWithStatement2.js deleted file mode 100644 index be3ed9c6c24..00000000000 --- a/tests/baselines/reference/parserWithStatement2.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserWithStatement2.ts] -with (1) - return; - -//// [parserWithStatement2.js] -with (1) - return; diff --git a/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.js b/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.js deleted file mode 100644 index 9ed3e677f9f..00000000000 --- a/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.js +++ /dev/null @@ -1,5 +0,0 @@ -//// [parser_breakNotInIterationOrSwitchStatement1.ts] -break; - -//// [parser_breakNotInIterationOrSwitchStatement1.js] -break; diff --git a/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.js b/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.js deleted file mode 100644 index b95bfca8404..00000000000 --- a/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parser_breakNotInIterationOrSwitchStatement2.ts] -while (true) { - function f() { - break; - } -} - -//// [parser_breakNotInIterationOrSwitchStatement2.js] -while (true) { - function f() { - break; - } -} diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement1.js b/tests/baselines/reference/parser_continueNotInIterationStatement1.js deleted file mode 100644 index 824a99d9e37..00000000000 --- a/tests/baselines/reference/parser_continueNotInIterationStatement1.js +++ /dev/null @@ -1,5 +0,0 @@ -//// [parser_continueNotInIterationStatement1.ts] -continue; - -//// [parser_continueNotInIterationStatement1.js] -continue; diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement2.js b/tests/baselines/reference/parser_continueNotInIterationStatement2.js deleted file mode 100644 index 690c3fd910d..00000000000 --- a/tests/baselines/reference/parser_continueNotInIterationStatement2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parser_continueNotInIterationStatement2.ts] -while (true) { - function f() { - continue; - } -} - -//// [parser_continueNotInIterationStatement2.js] -while (true) { - function f() { - continue; - } -} diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement3.js b/tests/baselines/reference/parser_continueNotInIterationStatement3.js deleted file mode 100644 index d5cf6feb221..00000000000 --- a/tests/baselines/reference/parser_continueNotInIterationStatement3.js +++ /dev/null @@ -1,11 +0,0 @@ -//// [parser_continueNotInIterationStatement3.ts] -switch (0) { - default: - continue; -} - -//// [parser_continueNotInIterationStatement3.js] -switch (0) { - default: - continue; -} diff --git a/tests/baselines/reference/propertyWrappedInTry.errors.txt b/tests/baselines/reference/propertyWrappedInTry.errors.txt index f3a4c14f538..1f8b5b1a1f9 100644 --- a/tests/baselines/reference/propertyWrappedInTry.errors.txt +++ b/tests/baselines/reference/propertyWrappedInTry.errors.txt @@ -26,8 +26,8 @@ !!! Cannot find name 'baz'. return this.bar; // doesn't get rewritten to Foo.bar. - ~~~~~~~~~~~~~~~~ -!!! 'return' statement has no containing function. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. } diff --git a/tests/baselines/reference/switchStatementsWithMultipleDefaults.errors.txt b/tests/baselines/reference/switchStatementsWithMultipleDefaults.errors.txt index 2ddcc832e02..e84c4cdcc0e 100644 --- a/tests/baselines/reference/switchStatementsWithMultipleDefaults.errors.txt +++ b/tests/baselines/reference/switchStatementsWithMultipleDefaults.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/switchStatementsWithMultipleDefaults.ts (8 errors) ==== +==== tests/cases/compiler/switchStatementsWithMultipleDefaults.ts (9 errors) ==== var x = 10; @@ -39,6 +39,8 @@ default: return; ~~~~~~~~ !!! A 'default' clause cannot appear more than once in a 'switch' statement. + ~~~~~~ +!!! A 'return' statement can only be used within a function body. default: default: ~~~~~~~~ !!! A 'default' clause cannot appear more than once in a 'switch' statement. diff --git a/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts b/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts deleted file mode 100644 index 8cb76cf02d7..00000000000 --- a/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts +++ /dev/null @@ -1 +0,0 @@ -break; \ No newline at end of file diff --git a/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts b/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts deleted file mode 100644 index 7d4c337e29f..00000000000 --- a/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts +++ /dev/null @@ -1,5 +0,0 @@ -while (true) { - function f() { - break; - } -} \ No newline at end of file diff --git a/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts b/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts deleted file mode 100644 index 45127c0ad12..00000000000 --- a/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts +++ /dev/null @@ -1 +0,0 @@ -continue; \ No newline at end of file diff --git a/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts b/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts deleted file mode 100644 index 114c300a70e..00000000000 --- a/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts +++ /dev/null @@ -1,5 +0,0 @@ -while (true) { - function f() { - continue; - } -} \ No newline at end of file diff --git a/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts b/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts deleted file mode 100644 index 203a3477af9..00000000000 --- a/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts +++ /dev/null @@ -1,4 +0,0 @@ -switch (0) { - default: - continue; -} \ No newline at end of file From 1a66243d4f1f4b59e59810a7d5b4db2023bf35bc Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 23 Jul 2014 14:09:17 -0700 Subject: [PATCH 3/7] Remove inModuleBody --- src/compiler/parser.ts | 20 +++++++------------ .../parserReturnStatement1.d.errors.txt | 2 +- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 47df80893ff..76b556decb4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -394,7 +394,6 @@ module ts { var lookAheadMode = LookAheadMode.NotLookingAhead; var inAmbientContext = false; - var inModuleBody = false; var inFunctionBody = false; var inSwitchStatement = ControlBlockContext.NotNested; var inIterationStatement = ControlBlockContext.NotNested; @@ -406,9 +405,9 @@ module ts { // TODO(jfreeman): Fill in these stubs return { - getLength: (): number => 0, - enqueueFunctionBoundary: () => { }, - resetStack: (length: number) => { } + pushLabelledStatement: (statement: LabelledStatement) => { }, + pushFunctionBoundary: () => { }, + pop: () => { } }; })(); @@ -1950,14 +1949,12 @@ module ts { if (inIterationStatement === ControlBlockContext.Nested) { inIterationStatement = ControlBlockContext.CrossingFunctionBoundary; } - - var labelStackLength = labelledStatementInfo.getLength(); - labelledStatementInfo.enqueueFunctionBoundary(); + labelledStatementInfo.pushFunctionBoundary(); var block = parseBlock(ignoreMissingOpenBrace); block.kind = SyntaxKind.FunctionBlock; - labelledStatementInfo.resetStack(labelStackLength); + labelledStatementInfo.pop(); inFunctionBody = saveInFunctionBody; inSwitchStatement = saveInSwitchStatement; inIterationStatement = saveInIterationStatement; @@ -2136,7 +2133,8 @@ module ts { if (!isSemicolon()) node.expression = parseExpression(); parseSemicolon(); - if (!inFunctionBody && !inModuleBody && errorCountBeforeReturnStatement === file.syntacticErrors.length) { + // In an ambient context, we will already give an error for having a statement. + if (!inFunctionBody && !inAmbientContext && errorCountBeforeReturnStatement === file.syntacticErrors.length) { grammarErrorAtPos(returnTokenStart, returnTokenLength, Diagnostics.A_return_statement_can_only_be_used_within_a_function_body); } return finishNode(node); @@ -2875,11 +2873,7 @@ module ts { function parseModuleBody(): Block { var node = createNode(SyntaxKind.ModuleBlock); if (parseExpected(SyntaxKind.OpenBraceToken)) { - var saveInModuleBody = inModuleBody; - inModuleBody = true; node.statements = parseList(ParsingContext.ModuleElements, parseModuleElement); - inModuleBody = saveInModuleBody; - parseExpected(SyntaxKind.CloseBraceToken); } else { diff --git a/tests/baselines/reference/parserReturnStatement1.d.errors.txt b/tests/baselines/reference/parserReturnStatement1.d.errors.txt index bbacb5d6c57..d5b47b3e933 100644 --- a/tests/baselines/reference/parserReturnStatement1.d.errors.txt +++ b/tests/baselines/reference/parserReturnStatement1.d.errors.txt @@ -1,4 +1,4 @@ ==== tests/cases/conformance/parser/ecmascript5/Statements/parserReturnStatement1.d.ts (1 errors) ==== return; ~~~~~~ -!!! A 'return' statement can only be used within a function body. \ No newline at end of file +!!! Statements are not allowed in ambient contexts. \ No newline at end of file From b9971f28767c3393bb4a0ce124a21b73e87bf760 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 23 Jul 2014 16:48:18 -0700 Subject: [PATCH 4/7] Add consumption points and error reporting for labelled statement errors --- .../diagnosticInformationMap.generated.ts | 4 +- src/compiler/diagnosticMessages.json | 16 +++-- src/compiler/parser.ts | 58 +++++++++++++++++-- 3 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 54dd92ca36a..2358447cc02 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -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()' instead." }, Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 05f5280ad8f..04e28234f83 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -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", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 76b556decb4..ada08165029 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -401,13 +401,17 @@ module ts { var labelledStatementInfo = (() => { // TODO(jfreeman): Implement a data structure for tracking labels var functionBoundarySentinel = {}; - 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 = 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 = 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(); From 742637bec97d4502b05ea5dd5f08e3f571164c51 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 24 Jul 2014 12:36:10 -0700 Subject: [PATCH 5/7] Add tracking for labelled statements, and errors on labelled jumps --- src/compiler/core.ts | 2 + src/compiler/parser.ts | 149 ++++++++++++++---- .../breakInIterationOrSwitchStatement1.js | 9 -- .../breakInIterationOrSwitchStatement2.js | 10 -- .../breakInIterationOrSwitchStatement3.js | 9 -- ...akInIterationOrSwitchStatement4.errors.txt | 6 - .../breakInIterationOrSwitchStatement4.js | 9 -- ...otInIterationOrSwitchStatement1.errors.txt | 4 - ...otInIterationOrSwitchStatement2.errors.txt | 8 - tests/baselines/reference/breakTarget1.js | 6 - tests/baselines/reference/breakTarget2.js | 10 -- tests/baselines/reference/breakTarget3.js | 11 -- tests/baselines/reference/breakTarget4.js | 11 -- tests/baselines/reference/breakTarget5.js | 18 --- tests/baselines/reference/breakTarget6.js | 9 -- .../continueInIterationStatement1.js | 9 -- .../continueInIterationStatement2.js | 10 -- .../continueInIterationStatement3.js | 9 -- .../continueInIterationStatement4.errors.txt | 6 - .../continueInIterationStatement4.js | 9 -- tests/baselines/reference/continueLabel.js | 9 -- ...ontinueNotInIterationStatement1.errors.txt | 4 - ...ontinueNotInIterationStatement2.errors.txt | 8 - ...ontinueNotInIterationStatement3.errors.txt | 7 - .../continueNotInIterationStatement4.js | 15 -- tests/baselines/reference/continueTarget1.js | 6 - tests/baselines/reference/continueTarget2.js | 10 -- tests/baselines/reference/continueTarget3.js | 11 -- tests/baselines/reference/continueTarget4.js | 11 -- tests/baselines/reference/continueTarget5.js | 18 --- tests/baselines/reference/continueTarget6.js | 9 -- tests/baselines/reference/duplicateLabel1.js | 9 -- tests/baselines/reference/duplicateLabel2.js | 13 -- tests/baselines/reference/duplicateLabel3.js | 17 -- tests/baselines/reference/duplicateLabel4.js | 14 -- .../invalidDoWhileBreakStatements.errors.txt | 14 +- ...nvalidDoWhileContinueStatements.errors.txt | 14 +- .../invalidForBreakStatements.errors.txt | 14 +- .../invalidForContinueStatements.errors.txt | 14 +- .../invalidForInBreakStatements.errors.txt | 14 +- .../invalidForInContinueStatements.errors.txt | 14 +- .../invalidSwitchContinueStatement.errors.txt | 2 +- .../invalidWhileBreakStatements.errors.txt | 14 +- .../invalidWhileContinueStatements.errors.txt | 14 +- .../reference/parserPublicBreak1.errors.txt | 2 +- ...otInIterationOrSwitchStatement1.errors.txt | 4 + ...otInIterationOrSwitchStatement2.errors.txt | 8 + .../reference/parser_breakTarget5.errors.txt | 11 ++ .../reference/parser_breakTarget5.js | 18 --- .../reference/parser_breakTarget6.errors.txt | 6 + .../reference/parser_breakTarget6.js | 9 -- ...ontinueNotInIterationStatement1.errors.txt | 4 + ...ontinueNotInIterationStatement2.errors.txt | 8 + ...ontinueNotInIterationStatement3.errors.txt | 7 + ...ontinueNotInIterationStatement4.errors.txt | 10 ++ ...parser_continueNotInIterationStatement4.js | 15 -- .../parser_continueTarget1.errors.txt | 5 + .../reference/parser_continueTarget1.js | 6 - .../parser_continueTarget5.errors.txt | 11 ++ .../reference/parser_continueTarget5.js | 18 --- .../parser_continueTarget6.errors.txt | 6 + .../reference/parser_continueTarget6.js | 9 -- .../parser_duplicateLabel1.errors.txt | 7 + .../reference/parser_duplicateLabel1.js | 9 -- .../parser_duplicateLabel2.errors.txt | 9 ++ .../reference/parser_duplicateLabel2.js | 13 -- .../breakInIterationOrSwitchStatement1.ts | 3 - .../breakInIterationOrSwitchStatement2.ts | 4 - .../breakInIterationOrSwitchStatement3.ts | 3 - .../breakInIterationOrSwitchStatement4.ts | 3 - tests/cases/compiler/breakTarget1.ts | 2 - tests/cases/compiler/breakTarget2.ts | 4 - tests/cases/compiler/breakTarget3.ts | 5 - tests/cases/compiler/breakTarget4.ts | 5 - tests/cases/compiler/breakTarget5.ts | 8 - tests/cases/compiler/breakTarget6.ts | 3 - .../compiler/continueInIterationStatement1.ts | 3 - .../compiler/continueInIterationStatement2.ts | 4 - .../compiler/continueInIterationStatement3.ts | 3 - .../compiler/continueInIterationStatement4.ts | 3 - tests/cases/compiler/continueLabel.ts | 3 - .../continueNotInIterationStatement4.ts | 6 - tests/cases/compiler/continueTarget1.ts | 2 - tests/cases/compiler/continueTarget2.ts | 4 - tests/cases/compiler/continueTarget3.ts | 5 - tests/cases/compiler/continueTarget4.ts | 5 - tests/cases/compiler/continueTarget5.ts | 8 - tests/cases/compiler/continueTarget6.ts | 3 - tests/cases/compiler/duplicateLabel1.ts | 4 - tests/cases/compiler/duplicateLabel2.ts | 6 - tests/cases/compiler/duplicateLabel3.ts | 8 - tests/cases/compiler/duplicateLabel4.ts | 7 - ..._breakNotInIterationOrSwitchStatement1.ts} | 0 ..._breakNotInIterationOrSwitchStatement2.ts} | 0 ...arser_continueNotInIterationStatement1.ts} | 0 ...arser_continueNotInIterationStatement2.ts} | 0 ...arser_continueNotInIterationStatement3.ts} | 0 97 files changed, 318 insertions(+), 580 deletions(-) delete mode 100644 tests/baselines/reference/breakInIterationOrSwitchStatement1.js delete mode 100644 tests/baselines/reference/breakInIterationOrSwitchStatement2.js delete mode 100644 tests/baselines/reference/breakInIterationOrSwitchStatement3.js delete mode 100644 tests/baselines/reference/breakInIterationOrSwitchStatement4.errors.txt delete mode 100644 tests/baselines/reference/breakInIterationOrSwitchStatement4.js delete mode 100644 tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt delete mode 100644 tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt delete mode 100644 tests/baselines/reference/breakTarget1.js delete mode 100644 tests/baselines/reference/breakTarget2.js delete mode 100644 tests/baselines/reference/breakTarget3.js delete mode 100644 tests/baselines/reference/breakTarget4.js delete mode 100644 tests/baselines/reference/breakTarget5.js delete mode 100644 tests/baselines/reference/breakTarget6.js delete mode 100644 tests/baselines/reference/continueInIterationStatement1.js delete mode 100644 tests/baselines/reference/continueInIterationStatement2.js delete mode 100644 tests/baselines/reference/continueInIterationStatement3.js delete mode 100644 tests/baselines/reference/continueInIterationStatement4.errors.txt delete mode 100644 tests/baselines/reference/continueInIterationStatement4.js delete mode 100644 tests/baselines/reference/continueLabel.js delete mode 100644 tests/baselines/reference/continueNotInIterationStatement1.errors.txt delete mode 100644 tests/baselines/reference/continueNotInIterationStatement2.errors.txt delete mode 100644 tests/baselines/reference/continueNotInIterationStatement3.errors.txt delete mode 100644 tests/baselines/reference/continueNotInIterationStatement4.js delete mode 100644 tests/baselines/reference/continueTarget1.js delete mode 100644 tests/baselines/reference/continueTarget2.js delete mode 100644 tests/baselines/reference/continueTarget3.js delete mode 100644 tests/baselines/reference/continueTarget4.js delete mode 100644 tests/baselines/reference/continueTarget5.js delete mode 100644 tests/baselines/reference/continueTarget6.js delete mode 100644 tests/baselines/reference/duplicateLabel1.js delete mode 100644 tests/baselines/reference/duplicateLabel2.js delete mode 100644 tests/baselines/reference/duplicateLabel3.js delete mode 100644 tests/baselines/reference/duplicateLabel4.js create mode 100644 tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.errors.txt create mode 100644 tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.errors.txt create mode 100644 tests/baselines/reference/parser_breakTarget5.errors.txt delete mode 100644 tests/baselines/reference/parser_breakTarget5.js create mode 100644 tests/baselines/reference/parser_breakTarget6.errors.txt delete mode 100644 tests/baselines/reference/parser_breakTarget6.js create mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement1.errors.txt create mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement2.errors.txt create mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement3.errors.txt create mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement4.errors.txt delete mode 100644 tests/baselines/reference/parser_continueNotInIterationStatement4.js create mode 100644 tests/baselines/reference/parser_continueTarget1.errors.txt delete mode 100644 tests/baselines/reference/parser_continueTarget1.js create mode 100644 tests/baselines/reference/parser_continueTarget5.errors.txt delete mode 100644 tests/baselines/reference/parser_continueTarget5.js create mode 100644 tests/baselines/reference/parser_continueTarget6.errors.txt delete mode 100644 tests/baselines/reference/parser_continueTarget6.js create mode 100644 tests/baselines/reference/parser_duplicateLabel1.errors.txt delete mode 100644 tests/baselines/reference/parser_duplicateLabel1.js create mode 100644 tests/baselines/reference/parser_duplicateLabel2.errors.txt delete mode 100644 tests/baselines/reference/parser_duplicateLabel2.js delete mode 100644 tests/cases/compiler/breakInIterationOrSwitchStatement1.ts delete mode 100644 tests/cases/compiler/breakInIterationOrSwitchStatement2.ts delete mode 100644 tests/cases/compiler/breakInIterationOrSwitchStatement3.ts delete mode 100644 tests/cases/compiler/breakInIterationOrSwitchStatement4.ts delete mode 100644 tests/cases/compiler/breakTarget1.ts delete mode 100644 tests/cases/compiler/breakTarget2.ts delete mode 100644 tests/cases/compiler/breakTarget3.ts delete mode 100644 tests/cases/compiler/breakTarget4.ts delete mode 100644 tests/cases/compiler/breakTarget5.ts delete mode 100644 tests/cases/compiler/breakTarget6.ts delete mode 100644 tests/cases/compiler/continueInIterationStatement1.ts delete mode 100644 tests/cases/compiler/continueInIterationStatement2.ts delete mode 100644 tests/cases/compiler/continueInIterationStatement3.ts delete mode 100644 tests/cases/compiler/continueInIterationStatement4.ts delete mode 100644 tests/cases/compiler/continueLabel.ts delete mode 100644 tests/cases/compiler/continueNotInIterationStatement4.ts delete mode 100644 tests/cases/compiler/continueTarget1.ts delete mode 100644 tests/cases/compiler/continueTarget2.ts delete mode 100644 tests/cases/compiler/continueTarget3.ts delete mode 100644 tests/cases/compiler/continueTarget4.ts delete mode 100644 tests/cases/compiler/continueTarget5.ts delete mode 100644 tests/cases/compiler/continueTarget6.ts delete mode 100644 tests/cases/compiler/duplicateLabel1.ts delete mode 100644 tests/cases/compiler/duplicateLabel2.ts delete mode 100644 tests/cases/compiler/duplicateLabel3.ts delete mode 100644 tests/cases/compiler/duplicateLabel4.ts rename tests/cases/{compiler/breakNotInIterationOrSwitchStatement1.ts => conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts} (100%) rename tests/cases/{compiler/breakNotInIterationOrSwitchStatement2.ts => conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts} (100%) rename tests/cases/{compiler/continueNotInIterationStatement1.ts => conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts} (100%) rename tests/cases/{compiler/continueNotInIterationStatement2.ts => conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts} (100%) rename tests/cases/{compiler/continueNotInIterationStatement3.ts => conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts} (100%) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 27a9f163d5b..8e59408f151 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -5,6 +5,8 @@ module ts { [index: string]: T; } + export interface StringSet extends Map { } + export function forEach(array: T[], callback: (element: T) => U): U { var result: U; if (array) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ada08165029..763968e763e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -55,6 +55,10 @@ module ts { return skipTrivia(getSourceFileOfNode(node).text, node.pos); } + export function getSourceTextOfNodeFromSourceText(sourceText: string, node: Node): string { + return sourceText.substring(skipTrivia(sourceText, node.pos), node.end); + } + export function getSourceTextOfNode(node: Node): string { var text = getSourceFileOfNode(node).text; return text.substring(skipTrivia(text, node.pos), node.end); @@ -400,18 +404,98 @@ module ts { var labelledStatementInfo = (() => { // TODO(jfreeman): Implement a data structure for tracking labels - var functionBoundarySentinel = {}; - var currentLabelSet: Identifier[]; - var labelSetStack: Identifier[][]; + var functionBoundarySentinel: StringSet = {}; + var currentLabelSet: StringSet; + var labelSetStack: StringSet[]; var isIterationStack: boolean[]; + function addLabel(label: Identifier): void { + if (!currentLabelSet) { + currentLabelSet = {}; + } + currentLabelSet[label.text] = true; + } + + function pushCurrentLabelSet(isIterationStatement: boolean): void { + if (!labelSetStack && !isIterationStack) { + labelSetStack = []; + isIterationStack = []; + } + Debug.assert(currentLabelSet !== undefined); + labelSetStack.push(currentLabelSet); + isIterationStack.push(isIterationStatement); + currentLabelSet = undefined; + } + + function pushFunctionBoundary(): void { + if (!labelSetStack && !isIterationStack) { + labelSetStack = []; + isIterationStack = []; + } + Debug.assert(currentLabelSet === undefined); + labelSetStack.push(functionBoundarySentinel); + + // It does not matter what we push here, since we will never ask if a function boundary + // is an iteration statement + isIterationStack.push(false); + } + + function pop(): void { + // Assert that we are in a "pushed" state + Debug.assert(labelSetStack.length && isIterationStack.length && currentLabelSet === undefined); + labelSetStack.pop(); + isIterationStack.pop(); + } + + function nodeIsNestedInLabel(label: Identifier, requireIterationStatement: boolean, stopAtFunctionBoundary: boolean): ControlBlockContext { + if (!requireIterationStatement && currentLabelSet && hasProperty(currentLabelSet, label.text)) { + return ControlBlockContext.Nested; + } + + if (!labelSetStack) { + return ControlBlockContext.NotNested; + } + + // We want to start searching for the label at the lowest point in the tree, + // and climb up from there. So we start at the end of the labelSetStack array. + var crossedFunctionBoundary = false; + for (var i = labelSetStack.length - 1; i >= 0; i--) { + var labelSet = labelSetStack[i]; + // Not allowed to cross function boundaries, so stop if we encounter one + if (labelSet === functionBoundarySentinel) { + if (stopAtFunctionBoundary) { + break; + } + else { + crossedFunctionBoundary = true; + continue; + } + } + + // If we require an iteration statement, only search in the current + // statement if it is an iteration statement + if (requireIterationStatement && isIterationStack[i] === false) { + continue; + } + + if (hasProperty(labelSet, label.text)) { + return crossedFunctionBoundary ? ControlBlockContext.CrossingFunctionBoundary : ControlBlockContext.Nested; + } + } + + // This is a bit of a misnomer. If the caller passed true for stopAtFunctionBoundary, + // there actually may be an enclosing label across a function boundary, but we will + // just return NotNested + return ControlBlockContext.NotNested; + } + // TODO(jfreeman): Fill in these stubs return { - addLabel: (label: Identifier) => { }, - pushCurrentLabelSet: (isIterationStatement: boolean) => { }, - pushFunctionBoundary: () => { }, - pop: () => { }, - labelExists: (label: Identifier, requireIterationStatement: boolean): boolean => false, + addLabel: addLabel, + pushCurrentLabelSet: pushCurrentLabelSet, + pushFunctionBoundary: pushFunctionBoundary, + pop: pop, + nodeIsNestedInLabel: nodeIsNestedInLabel, }; })(); @@ -2083,40 +2167,39 @@ module ts { parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); if (!isSemicolon()) node.label = parseIdentifier(); parseSemicolon(); + finishNode(node); // In an ambient context, we will already give an error for having a statement. if (!inAmbientContext && errorCountBeforeStatement === file.syntacticErrors.length) { if (node.label) { - checkBreakOrContinueStatementWithLabel(node.label, kind); + checkBreakOrContinueStatementWithLabel(node); } else { - checkAnonymousBreakOrContinueStatement(kind, keywordStart, keywordLength); + checkAnonymousBreakOrContinueStatement(node); } } - return finishNode(node); + return node; } - function checkAnonymousBreakOrContinueStatement(kind: SyntaxKind, errorStart: number, errorLength: number): void { - if (kind === SyntaxKind.BreakStatement) { + function checkAnonymousBreakOrContinueStatement(node: BreakOrContinueStatement): void { + if (node.kind === SyntaxKind.BreakStatement) { if (inIterationStatement === ControlBlockContext.Nested || inSwitchStatement === ControlBlockContext.Nested) { return; } else if (inIterationStatement === ControlBlockContext.NotNested && inSwitchStatement === ControlBlockContext.NotNested) { - grammarErrorAtPos(errorStart, errorLength, - Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement); + grammarErrorOnNode(node, Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement); return; } // Fall through } - else if (kind === SyntaxKind.ContinueStatement) { + else if (node.kind === SyntaxKind.ContinueStatement) { if (inIterationStatement === ControlBlockContext.Nested) { return; } else if (inIterationStatement === ControlBlockContext.NotNested) { - grammarErrorAtPos(errorStart, errorLength, - Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement); + grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement); return; } // Fall through @@ -2127,19 +2210,31 @@ module ts { Debug.assert(inIterationStatement === ControlBlockContext.CrossingFunctionBoundary || inSwitchStatement === ControlBlockContext.CrossingFunctionBoundary); - grammarErrorAtPos(errorStart, errorLength, Diagnostics.Jump_target_cannot_cross_function_boundary); + grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary); } - function checkBreakOrContinueStatementWithLabel(label: Identifier, kind: SyntaxKind): void { - if (labelledStatementInfo.labelExists(label, /*requireIterationStatement*/ kind === SyntaxKind.ContinueStatement)) { + function checkBreakOrContinueStatementWithLabel(node: BreakOrContinueStatement): void { + // For error specificity, if the label is not found, we want to distinguish whether it is because + // it crossed a function boundary or it was simply not found. To do this, we pass false for + // stopAtFunctionBoundary. + var nodeIsNestedInLabel = labelledStatementInfo.nodeIsNestedInLabel(node.label, + /*requireIterationStatement*/ node.kind === SyntaxKind.ContinueStatement, + /*stopAtFunctionBoundary*/ false); + if (nodeIsNestedInLabel === ControlBlockContext.Nested) { return; } - if (kind === SyntaxKind.ContinueStatement) { - grammarErrorOnNode(label, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + if (nodeIsNestedInLabel === ControlBlockContext.CrossingFunctionBoundary) { + grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary); + return; } - else if (kind === SyntaxKind.BreakStatement) { - grammarErrorOnNode(label, Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement); + + // It is NotNested + if (node.kind === SyntaxKind.ContinueStatement) { + grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + } + else if (node.kind === SyntaxKind.BreakStatement) { + grammarErrorOnNode(node, Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement); } else { Debug.fail("checkBreakOrContinueStatementWithLabel"); @@ -2304,8 +2399,8 @@ module ts { node.label = parseIdentifier(); parseExpected(SyntaxKind.ColonToken); - if (labelledStatementInfo.labelExists(node.label, /*requireIterationStatement*/ false)) { - grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0); + if (labelledStatementInfo.nodeIsNestedInLabel(node.label, /*requireIterationStatement*/ false, /*stopAtFunctionBoundary*/ true)) { + grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getSourceTextOfNodeFromSourceText(sourceText, node.label)); } labelledStatementInfo.addLabel(node.label); diff --git a/tests/baselines/reference/breakInIterationOrSwitchStatement1.js b/tests/baselines/reference/breakInIterationOrSwitchStatement1.js deleted file mode 100644 index 0a3de64c675..00000000000 --- a/tests/baselines/reference/breakInIterationOrSwitchStatement1.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [breakInIterationOrSwitchStatement1.ts] -while (true) { - break; -} - -//// [breakInIterationOrSwitchStatement1.js] -while (true) { - break; -} diff --git a/tests/baselines/reference/breakInIterationOrSwitchStatement2.js b/tests/baselines/reference/breakInIterationOrSwitchStatement2.js deleted file mode 100644 index 903bed733db..00000000000 --- a/tests/baselines/reference/breakInIterationOrSwitchStatement2.js +++ /dev/null @@ -1,10 +0,0 @@ -//// [breakInIterationOrSwitchStatement2.ts] -do { - break; -} -while (true); - -//// [breakInIterationOrSwitchStatement2.js] -do { - break; -} while (true); diff --git a/tests/baselines/reference/breakInIterationOrSwitchStatement3.js b/tests/baselines/reference/breakInIterationOrSwitchStatement3.js deleted file mode 100644 index dfadaf03182..00000000000 --- a/tests/baselines/reference/breakInIterationOrSwitchStatement3.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [breakInIterationOrSwitchStatement3.ts] -for (;;) { - break; -} - -//// [breakInIterationOrSwitchStatement3.js] -for (;;) { - break; -} diff --git a/tests/baselines/reference/breakInIterationOrSwitchStatement4.errors.txt b/tests/baselines/reference/breakInIterationOrSwitchStatement4.errors.txt deleted file mode 100644 index 667108c902d..00000000000 --- a/tests/baselines/reference/breakInIterationOrSwitchStatement4.errors.txt +++ /dev/null @@ -1,6 +0,0 @@ -==== tests/cases/compiler/breakInIterationOrSwitchStatement4.ts (1 errors) ==== - for (var i in something) { - ~~~~~~~~~ -!!! Cannot find name 'something'. - break; - } \ No newline at end of file diff --git a/tests/baselines/reference/breakInIterationOrSwitchStatement4.js b/tests/baselines/reference/breakInIterationOrSwitchStatement4.js deleted file mode 100644 index ef1978666e2..00000000000 --- a/tests/baselines/reference/breakInIterationOrSwitchStatement4.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [breakInIterationOrSwitchStatement4.ts] -for (var i in something) { - break; -} - -//// [breakInIterationOrSwitchStatement4.js] -for (var i in something) { - break; -} diff --git a/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt b/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt deleted file mode 100644 index fb72cb2337f..00000000000 --- a/tests/baselines/reference/breakNotInIterationOrSwitchStatement1.errors.txt +++ /dev/null @@ -1,4 +0,0 @@ -==== tests/cases/compiler/breakNotInIterationOrSwitchStatement1.ts (1 errors) ==== - break; - ~~~~~ -!!! A 'break' statement can only be used within an enclosing iteration or switch statement. \ No newline at end of file diff --git a/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt b/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt deleted file mode 100644 index 3a04554decf..00000000000 --- a/tests/baselines/reference/breakNotInIterationOrSwitchStatement2.errors.txt +++ /dev/null @@ -1,8 +0,0 @@ -==== tests/cases/compiler/breakNotInIterationOrSwitchStatement2.ts (1 errors) ==== - while (true) { - function f() { - break; - ~~~~~ -!!! Jump target cannot cross function boundary. - } - } \ No newline at end of file diff --git a/tests/baselines/reference/breakTarget1.js b/tests/baselines/reference/breakTarget1.js deleted file mode 100644 index 5283dfe1911..00000000000 --- a/tests/baselines/reference/breakTarget1.js +++ /dev/null @@ -1,6 +0,0 @@ -//// [breakTarget1.ts] -target: - break target; - -//// [breakTarget1.js] -target: break target; diff --git a/tests/baselines/reference/breakTarget2.js b/tests/baselines/reference/breakTarget2.js deleted file mode 100644 index 9ca050c18e5..00000000000 --- a/tests/baselines/reference/breakTarget2.js +++ /dev/null @@ -1,10 +0,0 @@ -//// [breakTarget2.ts] -target: -while (true) { - break target; -} - -//// [breakTarget2.js] -target: while (true) { - break target; -} diff --git a/tests/baselines/reference/breakTarget3.js b/tests/baselines/reference/breakTarget3.js deleted file mode 100644 index 0fa6cd2d298..00000000000 --- a/tests/baselines/reference/breakTarget3.js +++ /dev/null @@ -1,11 +0,0 @@ -//// [breakTarget3.ts] -target1: -target2: -while (true) { - break target1; -} - -//// [breakTarget3.js] -target1: target2: while (true) { - break target1; -} diff --git a/tests/baselines/reference/breakTarget4.js b/tests/baselines/reference/breakTarget4.js deleted file mode 100644 index 4586301d71b..00000000000 --- a/tests/baselines/reference/breakTarget4.js +++ /dev/null @@ -1,11 +0,0 @@ -//// [breakTarget4.ts] -target1: -target2: -while (true) { - break target2; -} - -//// [breakTarget4.js] -target1: target2: while (true) { - break target2; -} diff --git a/tests/baselines/reference/breakTarget5.js b/tests/baselines/reference/breakTarget5.js deleted file mode 100644 index 197e4e147bd..00000000000 --- a/tests/baselines/reference/breakTarget5.js +++ /dev/null @@ -1,18 +0,0 @@ -//// [breakTarget5.ts] -target: -while (true) { - function f() { - while (true) { - break target; - } - } -} - -//// [breakTarget5.js] -target: while (true) { - function f() { - while (true) { - break target; - } - } -} diff --git a/tests/baselines/reference/breakTarget6.js b/tests/baselines/reference/breakTarget6.js deleted file mode 100644 index 9c5bcc3ded1..00000000000 --- a/tests/baselines/reference/breakTarget6.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [breakTarget6.ts] -while (true) { - break target; -} - -//// [breakTarget6.js] -while (true) { - break target; -} diff --git a/tests/baselines/reference/continueInIterationStatement1.js b/tests/baselines/reference/continueInIterationStatement1.js deleted file mode 100644 index e1c787ae7ea..00000000000 --- a/tests/baselines/reference/continueInIterationStatement1.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [continueInIterationStatement1.ts] -while (true) { - continue; -} - -//// [continueInIterationStatement1.js] -while (true) { - continue; -} diff --git a/tests/baselines/reference/continueInIterationStatement2.js b/tests/baselines/reference/continueInIterationStatement2.js deleted file mode 100644 index d7ff84895f6..00000000000 --- a/tests/baselines/reference/continueInIterationStatement2.js +++ /dev/null @@ -1,10 +0,0 @@ -//// [continueInIterationStatement2.ts] -do { - continue; -} -while (true); - -//// [continueInIterationStatement2.js] -do { - continue; -} while (true); diff --git a/tests/baselines/reference/continueInIterationStatement3.js b/tests/baselines/reference/continueInIterationStatement3.js deleted file mode 100644 index 90619118ac5..00000000000 --- a/tests/baselines/reference/continueInIterationStatement3.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [continueInIterationStatement3.ts] -for (;;) { - continue; -} - -//// [continueInIterationStatement3.js] -for (;;) { - continue; -} diff --git a/tests/baselines/reference/continueInIterationStatement4.errors.txt b/tests/baselines/reference/continueInIterationStatement4.errors.txt deleted file mode 100644 index c0f4388cf79..00000000000 --- a/tests/baselines/reference/continueInIterationStatement4.errors.txt +++ /dev/null @@ -1,6 +0,0 @@ -==== tests/cases/compiler/continueInIterationStatement4.ts (1 errors) ==== - for (var i in something) { - ~~~~~~~~~ -!!! Cannot find name 'something'. - continue; - } \ No newline at end of file diff --git a/tests/baselines/reference/continueInIterationStatement4.js b/tests/baselines/reference/continueInIterationStatement4.js deleted file mode 100644 index e72ab3ed9ab..00000000000 --- a/tests/baselines/reference/continueInIterationStatement4.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [continueInIterationStatement4.ts] -for (var i in something) { - continue; -} - -//// [continueInIterationStatement4.js] -for (var i in something) { - continue; -} diff --git a/tests/baselines/reference/continueLabel.js b/tests/baselines/reference/continueLabel.js deleted file mode 100644 index 390566353eb..00000000000 --- a/tests/baselines/reference/continueLabel.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [continueLabel.ts] -label1: for(var i = 0; i < 1; i++) { - continue label1; -} - -//// [continueLabel.js] -label1: for (var i = 0; i < 1; i++) { - continue label1; -} diff --git a/tests/baselines/reference/continueNotInIterationStatement1.errors.txt b/tests/baselines/reference/continueNotInIterationStatement1.errors.txt deleted file mode 100644 index 6875d311520..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement1.errors.txt +++ /dev/null @@ -1,4 +0,0 @@ -==== tests/cases/compiler/continueNotInIterationStatement1.ts (1 errors) ==== - continue; - ~~~~~~~~ -!!! A 'continue' statement can only be used within an enclosing iteration statement. \ No newline at end of file diff --git a/tests/baselines/reference/continueNotInIterationStatement2.errors.txt b/tests/baselines/reference/continueNotInIterationStatement2.errors.txt deleted file mode 100644 index 945f8e7eede..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement2.errors.txt +++ /dev/null @@ -1,8 +0,0 @@ -==== tests/cases/compiler/continueNotInIterationStatement2.ts (1 errors) ==== - while (true) { - function f() { - continue; - ~~~~~~~~ -!!! Jump target cannot cross function boundary. - } - } \ No newline at end of file diff --git a/tests/baselines/reference/continueNotInIterationStatement3.errors.txt b/tests/baselines/reference/continueNotInIterationStatement3.errors.txt deleted file mode 100644 index 56aef1000f7..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement3.errors.txt +++ /dev/null @@ -1,7 +0,0 @@ -==== tests/cases/compiler/continueNotInIterationStatement3.ts (1 errors) ==== - switch (0) { - default: - continue; - ~~~~~~~~ -!!! A 'continue' statement can only be used within an enclosing iteration statement. - } \ No newline at end of file diff --git a/tests/baselines/reference/continueNotInIterationStatement4.js b/tests/baselines/reference/continueNotInIterationStatement4.js deleted file mode 100644 index f3f52ecb48c..00000000000 --- a/tests/baselines/reference/continueNotInIterationStatement4.js +++ /dev/null @@ -1,15 +0,0 @@ -//// [continueNotInIterationStatement4.ts] -TWO: -while (true){ - var x = () => { - continue TWO; - } -} - - -//// [continueNotInIterationStatement4.js] -TWO: while (true) { - var x = function () { - continue TWO; - }; -} diff --git a/tests/baselines/reference/continueTarget1.js b/tests/baselines/reference/continueTarget1.js deleted file mode 100644 index 07e5a7b9b50..00000000000 --- a/tests/baselines/reference/continueTarget1.js +++ /dev/null @@ -1,6 +0,0 @@ -//// [continueTarget1.ts] -target: - continue target; - -//// [continueTarget1.js] -target: continue target; diff --git a/tests/baselines/reference/continueTarget2.js b/tests/baselines/reference/continueTarget2.js deleted file mode 100644 index eb3b4118f7f..00000000000 --- a/tests/baselines/reference/continueTarget2.js +++ /dev/null @@ -1,10 +0,0 @@ -//// [continueTarget2.ts] -target: -while (true) { - continue target; -} - -//// [continueTarget2.js] -target: while (true) { - continue target; -} diff --git a/tests/baselines/reference/continueTarget3.js b/tests/baselines/reference/continueTarget3.js deleted file mode 100644 index 052b7b593c3..00000000000 --- a/tests/baselines/reference/continueTarget3.js +++ /dev/null @@ -1,11 +0,0 @@ -//// [continueTarget3.ts] -target1: -target2: -while (true) { - continue target1; -} - -//// [continueTarget3.js] -target1: target2: while (true) { - continue target1; -} diff --git a/tests/baselines/reference/continueTarget4.js b/tests/baselines/reference/continueTarget4.js deleted file mode 100644 index 0f6211f9202..00000000000 --- a/tests/baselines/reference/continueTarget4.js +++ /dev/null @@ -1,11 +0,0 @@ -//// [continueTarget4.ts] -target1: -target2: -while (true) { - continue target2; -} - -//// [continueTarget4.js] -target1: target2: while (true) { - continue target2; -} diff --git a/tests/baselines/reference/continueTarget5.js b/tests/baselines/reference/continueTarget5.js deleted file mode 100644 index 5bf309d2690..00000000000 --- a/tests/baselines/reference/continueTarget5.js +++ /dev/null @@ -1,18 +0,0 @@ -//// [continueTarget5.ts] -target: -while (true) { - function f() { - while (true) { - continue target; - } - } -} - -//// [continueTarget5.js] -target: while (true) { - function f() { - while (true) { - continue target; - } - } -} diff --git a/tests/baselines/reference/continueTarget6.js b/tests/baselines/reference/continueTarget6.js deleted file mode 100644 index aefa8e97652..00000000000 --- a/tests/baselines/reference/continueTarget6.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [continueTarget6.ts] -while (true) { - continue target; -} - -//// [continueTarget6.js] -while (true) { - continue target; -} diff --git a/tests/baselines/reference/duplicateLabel1.js b/tests/baselines/reference/duplicateLabel1.js deleted file mode 100644 index e7976895c94..00000000000 --- a/tests/baselines/reference/duplicateLabel1.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [duplicateLabel1.ts] -target: -target: -while (true) { -} - -//// [duplicateLabel1.js] -target: target: while (true) { -} diff --git a/tests/baselines/reference/duplicateLabel2.js b/tests/baselines/reference/duplicateLabel2.js deleted file mode 100644 index 9ee9671d59d..00000000000 --- a/tests/baselines/reference/duplicateLabel2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [duplicateLabel2.ts] -target: -while (true) { - target: - while (true) { - } -} - -//// [duplicateLabel2.js] -target: while (true) { - target: while (true) { - } -} diff --git a/tests/baselines/reference/duplicateLabel3.js b/tests/baselines/reference/duplicateLabel3.js deleted file mode 100644 index 37e9619e8f6..00000000000 --- a/tests/baselines/reference/duplicateLabel3.js +++ /dev/null @@ -1,17 +0,0 @@ -//// [duplicateLabel3.ts] -target: -while (true) { - function f() { - target: - while (true) { - } - } -} - -//// [duplicateLabel3.js] -target: while (true) { - function f() { - target: while (true) { - } - } -} diff --git a/tests/baselines/reference/duplicateLabel4.js b/tests/baselines/reference/duplicateLabel4.js deleted file mode 100644 index 22d072d38d7..00000000000 --- a/tests/baselines/reference/duplicateLabel4.js +++ /dev/null @@ -1,14 +0,0 @@ -//// [duplicateLabel4.ts] -target: -while (true) { -} - -target: -while (true) { -} - -//// [duplicateLabel4.js] -target: while (true) { -} -target: while (true) { -} diff --git a/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt b/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt index 91852a9e77e..9b526d3c219 100644 --- a/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts (6 errors) ==== // All errors // naked break not allowed break; - ~~~~~ + ~~~~~~ !!! A 'break' statement can only be used within an enclosing iteration or switch statement. // non-existent label ONE: do break TWO; while (true) + ~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. // break from inside function TWO: do { var x = () => { break TWO; + ~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } }while (true) @@ -22,12 +26,16 @@ do { var fn = function () { break THREE; + ~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } }while (true) // break forward do { break FIVE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. FIVE: do { } while (true) }while (true) @@ -38,4 +46,6 @@ do { break NINE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. }while (true) \ No newline at end of file diff --git a/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt b/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt index 798afdc3b75..38c54104d39 100644 --- a/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts (6 errors) ==== // All errors // naked continue not allowed continue; - ~~~~~~~~ + ~~~~~~~~~ !!! A 'continue' statement can only be used within an enclosing iteration statement. // non-existent label ONE: do continue TWO; while (true) + ~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. // continue from inside function TWO: do { var x = () => { continue TWO; + ~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } }while (true) @@ -22,12 +26,16 @@ do { var fn = function () { continue THREE; + ~~~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } }while (true) // continue forward do { continue FIVE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. FIVE: do { } while (true) }while (true) @@ -38,4 +46,6 @@ do { continue NINE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. }while (true) \ No newline at end of file diff --git a/tests/baselines/reference/invalidForBreakStatements.errors.txt b/tests/baselines/reference/invalidForBreakStatements.errors.txt index 0edc26132cb..28c110b1105 100644 --- a/tests/baselines/reference/invalidForBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidForBreakStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts (6 errors) ==== // All errors // naked break not allowed break; - ~~~~~ + ~~~~~~ !!! A 'break' statement can only be used within an enclosing iteration or switch statement. // non-existent label ONE: for(;;) break TWO; + ~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. // break from inside function TWO: for(;;) { var x = () => { break TWO; + ~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } @@ -22,12 +26,16 @@ for(;;) { var fn = function () { break THREE; + ~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } // break forward for(;;) { break FIVE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. FIVE: for (; ;) { } } @@ -37,4 +45,6 @@ for(;;) { break NINE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForContinueStatements.errors.txt b/tests/baselines/reference/invalidForContinueStatements.errors.txt index e5bf379e931..d3aadb0b694 100644 --- a/tests/baselines/reference/invalidForContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidForContinueStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts (6 errors) ==== // All errors // naked continue not allowed continue; - ~~~~~~~~ + ~~~~~~~~~ !!! A 'continue' statement can only be used within an enclosing iteration statement. // non-existent label ONE: for(;;) continue TWO; + ~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. // continue from inside function TWO: for(;;) { var x = () => { continue TWO; + ~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } @@ -22,12 +26,16 @@ for(;;) { var fn = function () { continue THREE; + ~~~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } // continue forward for(;;) { continue FIVE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. FIVE: for (; ;) { } } @@ -37,4 +45,6 @@ for(;;) { continue NINE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForInBreakStatements.errors.txt b/tests/baselines/reference/invalidForInBreakStatements.errors.txt index a9b3034bccc..6e29ea04c8e 100644 --- a/tests/baselines/reference/invalidForInBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidForInBreakStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts (6 errors) ==== // All errors // naked break not allowed break; - ~~~~~ + ~~~~~~ !!! A 'break' statement can only be used within an enclosing iteration or switch statement. // non-existent label ONE: for (var x in {}) break TWO; + ~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. // break from inside function TWO: for (var x in {}) { var fn = () => { break TWO; + ~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } @@ -22,12 +26,16 @@ for (var x in {}) { var fn = function () { break THREE; + ~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } // break forward for (var x in {}) { break FIVE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. FIVE: for (var x in {}) { } } @@ -38,4 +46,6 @@ for (var x in {}) { break NINE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. } \ No newline at end of file diff --git a/tests/baselines/reference/invalidForInContinueStatements.errors.txt b/tests/baselines/reference/invalidForInContinueStatements.errors.txt index 690b40acdd9..f9cf403c975 100644 --- a/tests/baselines/reference/invalidForInContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidForInContinueStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts (6 errors) ==== // All errors // naked continue not allowed continue; - ~~~~~~~~ + ~~~~~~~~~ !!! A 'continue' statement can only be used within an enclosing iteration statement. // non-existent label ONE: for (var x in {}) continue TWO; + ~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. // continue from inside function TWO: for (var x in {}) { var fn = () => { continue TWO; + ~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } @@ -22,12 +26,16 @@ for (var x in {}) { var fn = function () { continue THREE; + ~~~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } // continue forward for (var x in {}) { continue FIVE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. FIVE: for (var x in {}) { } } @@ -38,4 +46,6 @@ for (var x in {}) { continue NINE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. } \ No newline at end of file diff --git a/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt b/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt index c6ac769f7ac..94b219ea365 100644 --- a/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt +++ b/tests/baselines/reference/invalidSwitchContinueStatement.errors.txt @@ -4,7 +4,7 @@ switch (12) { case 5: continue; - ~~~~~~~~ + ~~~~~~~~~ !!! A 'continue' statement can only be used within an enclosing iteration statement. } \ No newline at end of file diff --git a/tests/baselines/reference/invalidWhileBreakStatements.errors.txt b/tests/baselines/reference/invalidWhileBreakStatements.errors.txt index 4ad5b0cfff9..9357f522984 100644 --- a/tests/baselines/reference/invalidWhileBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidWhileBreakStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts (6 errors) ==== // All errors // naked break not allowed break; - ~~~~~ + ~~~~~~ !!! A 'break' statement can only be used within an enclosing iteration or switch statement. // non-existent label ONE: while (true) break TWO; + ~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. // break from inside function TWO: while (true){ var x = () => { break TWO; + ~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } @@ -22,12 +26,16 @@ while (true) { var fn = function () { break THREE; + ~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } // break forward while (true) { break FIVE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. FIVE: while (true) { } } @@ -38,4 +46,6 @@ while (true) { break NINE; + ~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. } \ No newline at end of file diff --git a/tests/baselines/reference/invalidWhileContinueStatements.errors.txt b/tests/baselines/reference/invalidWhileContinueStatements.errors.txt index 5dbc8fdaafa..24ef7381e03 100644 --- a/tests/baselines/reference/invalidWhileContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidWhileContinueStatements.errors.txt @@ -1,20 +1,24 @@ -==== tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts (1 errors) ==== +==== tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts (6 errors) ==== // All errors // naked continue not allowed continue; - ~~~~~~~~ + ~~~~~~~~~ !!! A 'continue' statement can only be used within an enclosing iteration statement. // non-existent label ONE: while (true) continue TWO; + ~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. // continue from inside function TWO: while (true){ var x = () => { continue TWO; + ~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } @@ -22,12 +26,16 @@ while (true) { var fn = function () { continue THREE; + ~~~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. } } // continue forward while (true) { continue FIVE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. FIVE: while (true) { } } @@ -38,4 +46,6 @@ while (true) { continue NINE; + ~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. } \ No newline at end of file diff --git a/tests/baselines/reference/parserPublicBreak1.errors.txt b/tests/baselines/reference/parserPublicBreak1.errors.txt index afd0cd5df74..d502e53722f 100644 --- a/tests/baselines/reference/parserPublicBreak1.errors.txt +++ b/tests/baselines/reference/parserPublicBreak1.errors.txt @@ -2,6 +2,6 @@ public break; ~~~~~~ !!! Declaration or statement expected. - ~~~~~ + ~~~~~~ !!! A 'break' statement can only be used within an enclosing iteration or switch statement. \ No newline at end of file diff --git a/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.errors.txt b/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.errors.txt new file mode 100644 index 00000000000..cb68016f0be --- /dev/null +++ b/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement1.errors.txt @@ -0,0 +1,4 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts (1 errors) ==== + break; + ~~~~~~ +!!! A 'break' statement can only be used within an enclosing iteration or switch statement. \ No newline at end of file diff --git a/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.errors.txt b/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.errors.txt new file mode 100644 index 00000000000..29ea7d85b4b --- /dev/null +++ b/tests/baselines/reference/parser_breakNotInIterationOrSwitchStatement2.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts (1 errors) ==== + while (true) { + function f() { + break; + ~~~~~~ +!!! Jump target cannot cross function boundary. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_breakTarget5.errors.txt b/tests/baselines/reference/parser_breakTarget5.errors.txt new file mode 100644 index 00000000000..01aa2dd3a26 --- /dev/null +++ b/tests/baselines/reference/parser_breakTarget5.errors.txt @@ -0,0 +1,11 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakTarget5.ts (1 errors) ==== + target: + while (true) { + function f() { + while (true) { + break target; + ~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_breakTarget5.js b/tests/baselines/reference/parser_breakTarget5.js deleted file mode 100644 index 743ad6c2631..00000000000 --- a/tests/baselines/reference/parser_breakTarget5.js +++ /dev/null @@ -1,18 +0,0 @@ -//// [parser_breakTarget5.ts] -target: -while (true) { - function f() { - while (true) { - break target; - } - } -} - -//// [parser_breakTarget5.js] -target: while (true) { - function f() { - while (true) { - break target; - } - } -} diff --git a/tests/baselines/reference/parser_breakTarget6.errors.txt b/tests/baselines/reference/parser_breakTarget6.errors.txt new file mode 100644 index 00000000000..d35364658ab --- /dev/null +++ b/tests/baselines/reference/parser_breakTarget6.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakTarget6.ts (1 errors) ==== + while (true) { + break target; + ~~~~~~~~~~~~~ +!!! A 'break' statement can only jump to a label of an enclosing statement. + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_breakTarget6.js b/tests/baselines/reference/parser_breakTarget6.js deleted file mode 100644 index 93b15ac0362..00000000000 --- a/tests/baselines/reference/parser_breakTarget6.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parser_breakTarget6.ts] -while (true) { - break target; -} - -//// [parser_breakTarget6.js] -while (true) { - break target; -} diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement1.errors.txt b/tests/baselines/reference/parser_continueNotInIterationStatement1.errors.txt new file mode 100644 index 00000000000..2454e0d4f8c --- /dev/null +++ b/tests/baselines/reference/parser_continueNotInIterationStatement1.errors.txt @@ -0,0 +1,4 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts (1 errors) ==== + continue; + ~~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement2.errors.txt b/tests/baselines/reference/parser_continueNotInIterationStatement2.errors.txt new file mode 100644 index 00000000000..aeb979736ef --- /dev/null +++ b/tests/baselines/reference/parser_continueNotInIterationStatement2.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts (1 errors) ==== + while (true) { + function f() { + continue; + ~~~~~~~~~ +!!! Jump target cannot cross function boundary. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement3.errors.txt b/tests/baselines/reference/parser_continueNotInIterationStatement3.errors.txt new file mode 100644 index 00000000000..1acc582492d --- /dev/null +++ b/tests/baselines/reference/parser_continueNotInIterationStatement3.errors.txt @@ -0,0 +1,7 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts (1 errors) ==== + switch (0) { + default: + continue; + ~~~~~~~~~ +!!! A 'continue' statement can only be used within an enclosing iteration statement. + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement4.errors.txt b/tests/baselines/reference/parser_continueNotInIterationStatement4.errors.txt new file mode 100644 index 00000000000..fd9de545c1b --- /dev/null +++ b/tests/baselines/reference/parser_continueNotInIterationStatement4.errors.txt @@ -0,0 +1,10 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement4.ts (1 errors) ==== + TWO: + while (true){ + var x = () => { + continue TWO; + ~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueNotInIterationStatement4.js b/tests/baselines/reference/parser_continueNotInIterationStatement4.js deleted file mode 100644 index af2a4ee61b3..00000000000 --- a/tests/baselines/reference/parser_continueNotInIterationStatement4.js +++ /dev/null @@ -1,15 +0,0 @@ -//// [parser_continueNotInIterationStatement4.ts] -TWO: -while (true){ - var x = () => { - continue TWO; - } -} - - -//// [parser_continueNotInIterationStatement4.js] -TWO: while (true) { - var x = function () { - continue TWO; - }; -} diff --git a/tests/baselines/reference/parser_continueTarget1.errors.txt b/tests/baselines/reference/parser_continueTarget1.errors.txt new file mode 100644 index 00000000000..0870792fbc8 --- /dev/null +++ b/tests/baselines/reference/parser_continueTarget1.errors.txt @@ -0,0 +1,5 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueTarget1.ts (1 errors) ==== + target: + continue target; + ~~~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueTarget1.js b/tests/baselines/reference/parser_continueTarget1.js deleted file mode 100644 index fd6ea5750c6..00000000000 --- a/tests/baselines/reference/parser_continueTarget1.js +++ /dev/null @@ -1,6 +0,0 @@ -//// [parser_continueTarget1.ts] -target: - continue target; - -//// [parser_continueTarget1.js] -target: continue target; diff --git a/tests/baselines/reference/parser_continueTarget5.errors.txt b/tests/baselines/reference/parser_continueTarget5.errors.txt new file mode 100644 index 00000000000..e9e7d6f6ff8 --- /dev/null +++ b/tests/baselines/reference/parser_continueTarget5.errors.txt @@ -0,0 +1,11 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueTarget5.ts (1 errors) ==== + target: + while (true) { + function f() { + while (true) { + continue target; + ~~~~~~~~~~~~~~~~ +!!! Jump target cannot cross function boundary. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueTarget5.js b/tests/baselines/reference/parser_continueTarget5.js deleted file mode 100644 index 7be6997c070..00000000000 --- a/tests/baselines/reference/parser_continueTarget5.js +++ /dev/null @@ -1,18 +0,0 @@ -//// [parser_continueTarget5.ts] -target: -while (true) { - function f() { - while (true) { - continue target; - } - } -} - -//// [parser_continueTarget5.js] -target: while (true) { - function f() { - while (true) { - continue target; - } - } -} diff --git a/tests/baselines/reference/parser_continueTarget6.errors.txt b/tests/baselines/reference/parser_continueTarget6.errors.txt new file mode 100644 index 00000000000..3b2e0fe7c06 --- /dev/null +++ b/tests/baselines/reference/parser_continueTarget6.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueTarget6.ts (1 errors) ==== + while (true) { + continue target; + ~~~~~~~~~~~~~~~~ +!!! A 'continue' statement can only jump to a label of an enclosing iteration statement. + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_continueTarget6.js b/tests/baselines/reference/parser_continueTarget6.js deleted file mode 100644 index 56f1b6a485c..00000000000 --- a/tests/baselines/reference/parser_continueTarget6.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parser_continueTarget6.ts] -while (true) { - continue target; -} - -//// [parser_continueTarget6.js] -while (true) { - continue target; -} diff --git a/tests/baselines/reference/parser_duplicateLabel1.errors.txt b/tests/baselines/reference/parser_duplicateLabel1.errors.txt new file mode 100644 index 00000000000..611fd108c6f --- /dev/null +++ b/tests/baselines/reference/parser_duplicateLabel1.errors.txt @@ -0,0 +1,7 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel1.ts (1 errors) ==== + target: + target: + ~~~~~~ +!!! Duplicate label 'target' + while (true) { + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_duplicateLabel1.js b/tests/baselines/reference/parser_duplicateLabel1.js deleted file mode 100644 index 0fe1801a099..00000000000 --- a/tests/baselines/reference/parser_duplicateLabel1.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parser_duplicateLabel1.ts] -target: -target: -while (true) { -} - -//// [parser_duplicateLabel1.js] -target: target: while (true) { -} diff --git a/tests/baselines/reference/parser_duplicateLabel2.errors.txt b/tests/baselines/reference/parser_duplicateLabel2.errors.txt new file mode 100644 index 00000000000..23bca695a49 --- /dev/null +++ b/tests/baselines/reference/parser_duplicateLabel2.errors.txt @@ -0,0 +1,9 @@ +==== tests/cases/conformance/parser/ecmascript5/Statements/LabeledStatements/parser_duplicateLabel2.ts (1 errors) ==== + target: + while (true) { + target: + ~~~~~~ +!!! Duplicate label 'target' + while (true) { + } + } \ No newline at end of file diff --git a/tests/baselines/reference/parser_duplicateLabel2.js b/tests/baselines/reference/parser_duplicateLabel2.js deleted file mode 100644 index 00c0e5532e5..00000000000 --- a/tests/baselines/reference/parser_duplicateLabel2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parser_duplicateLabel2.ts] -target: -while (true) { - target: - while (true) { - } -} - -//// [parser_duplicateLabel2.js] -target: while (true) { - target: while (true) { - } -} diff --git a/tests/cases/compiler/breakInIterationOrSwitchStatement1.ts b/tests/cases/compiler/breakInIterationOrSwitchStatement1.ts deleted file mode 100644 index 831d2bd7faa..00000000000 --- a/tests/cases/compiler/breakInIterationOrSwitchStatement1.ts +++ /dev/null @@ -1,3 +0,0 @@ -while (true) { - break; -} \ No newline at end of file diff --git a/tests/cases/compiler/breakInIterationOrSwitchStatement2.ts b/tests/cases/compiler/breakInIterationOrSwitchStatement2.ts deleted file mode 100644 index e502557f3bc..00000000000 --- a/tests/cases/compiler/breakInIterationOrSwitchStatement2.ts +++ /dev/null @@ -1,4 +0,0 @@ -do { - break; -} -while (true); \ No newline at end of file diff --git a/tests/cases/compiler/breakInIterationOrSwitchStatement3.ts b/tests/cases/compiler/breakInIterationOrSwitchStatement3.ts deleted file mode 100644 index 19858da08b2..00000000000 --- a/tests/cases/compiler/breakInIterationOrSwitchStatement3.ts +++ /dev/null @@ -1,3 +0,0 @@ -for (;;) { - break; -} \ No newline at end of file diff --git a/tests/cases/compiler/breakInIterationOrSwitchStatement4.ts b/tests/cases/compiler/breakInIterationOrSwitchStatement4.ts deleted file mode 100644 index da939495217..00000000000 --- a/tests/cases/compiler/breakInIterationOrSwitchStatement4.ts +++ /dev/null @@ -1,3 +0,0 @@ -for (var i in something) { - break; -} \ No newline at end of file diff --git a/tests/cases/compiler/breakTarget1.ts b/tests/cases/compiler/breakTarget1.ts deleted file mode 100644 index 03f96cbc602..00000000000 --- a/tests/cases/compiler/breakTarget1.ts +++ /dev/null @@ -1,2 +0,0 @@ -target: - break target; \ No newline at end of file diff --git a/tests/cases/compiler/breakTarget2.ts b/tests/cases/compiler/breakTarget2.ts deleted file mode 100644 index daa11e45b95..00000000000 --- a/tests/cases/compiler/breakTarget2.ts +++ /dev/null @@ -1,4 +0,0 @@ -target: -while (true) { - break target; -} \ No newline at end of file diff --git a/tests/cases/compiler/breakTarget3.ts b/tests/cases/compiler/breakTarget3.ts deleted file mode 100644 index 9cef599692c..00000000000 --- a/tests/cases/compiler/breakTarget3.ts +++ /dev/null @@ -1,5 +0,0 @@ -target1: -target2: -while (true) { - break target1; -} \ No newline at end of file diff --git a/tests/cases/compiler/breakTarget4.ts b/tests/cases/compiler/breakTarget4.ts deleted file mode 100644 index 2c3eadca7db..00000000000 --- a/tests/cases/compiler/breakTarget4.ts +++ /dev/null @@ -1,5 +0,0 @@ -target1: -target2: -while (true) { - break target2; -} \ No newline at end of file diff --git a/tests/cases/compiler/breakTarget5.ts b/tests/cases/compiler/breakTarget5.ts deleted file mode 100644 index a05ee1cf879..00000000000 --- a/tests/cases/compiler/breakTarget5.ts +++ /dev/null @@ -1,8 +0,0 @@ -target: -while (true) { - function f() { - while (true) { - break target; - } - } -} \ No newline at end of file diff --git a/tests/cases/compiler/breakTarget6.ts b/tests/cases/compiler/breakTarget6.ts deleted file mode 100644 index bd94d0030e3..00000000000 --- a/tests/cases/compiler/breakTarget6.ts +++ /dev/null @@ -1,3 +0,0 @@ -while (true) { - break target; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueInIterationStatement1.ts b/tests/cases/compiler/continueInIterationStatement1.ts deleted file mode 100644 index 89b9743144c..00000000000 --- a/tests/cases/compiler/continueInIterationStatement1.ts +++ /dev/null @@ -1,3 +0,0 @@ -while (true) { - continue; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueInIterationStatement2.ts b/tests/cases/compiler/continueInIterationStatement2.ts deleted file mode 100644 index 40bb1c438af..00000000000 --- a/tests/cases/compiler/continueInIterationStatement2.ts +++ /dev/null @@ -1,4 +0,0 @@ -do { - continue; -} -while (true); \ No newline at end of file diff --git a/tests/cases/compiler/continueInIterationStatement3.ts b/tests/cases/compiler/continueInIterationStatement3.ts deleted file mode 100644 index 3b23060504c..00000000000 --- a/tests/cases/compiler/continueInIterationStatement3.ts +++ /dev/null @@ -1,3 +0,0 @@ -for (;;) { - continue; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueInIterationStatement4.ts b/tests/cases/compiler/continueInIterationStatement4.ts deleted file mode 100644 index 9bd164bc366..00000000000 --- a/tests/cases/compiler/continueInIterationStatement4.ts +++ /dev/null @@ -1,3 +0,0 @@ -for (var i in something) { - continue; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueLabel.ts b/tests/cases/compiler/continueLabel.ts deleted file mode 100644 index a3c36c4a263..00000000000 --- a/tests/cases/compiler/continueLabel.ts +++ /dev/null @@ -1,3 +0,0 @@ -label1: for(var i = 0; i < 1; i++) { - continue label1; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueNotInIterationStatement4.ts b/tests/cases/compiler/continueNotInIterationStatement4.ts deleted file mode 100644 index 5996eb4323a..00000000000 --- a/tests/cases/compiler/continueNotInIterationStatement4.ts +++ /dev/null @@ -1,6 +0,0 @@ -TWO: -while (true){ - var x = () => { - continue TWO; - } -} diff --git a/tests/cases/compiler/continueTarget1.ts b/tests/cases/compiler/continueTarget1.ts deleted file mode 100644 index 7235f96bac8..00000000000 --- a/tests/cases/compiler/continueTarget1.ts +++ /dev/null @@ -1,2 +0,0 @@ -target: - continue target; \ No newline at end of file diff --git a/tests/cases/compiler/continueTarget2.ts b/tests/cases/compiler/continueTarget2.ts deleted file mode 100644 index 8b57308a2df..00000000000 --- a/tests/cases/compiler/continueTarget2.ts +++ /dev/null @@ -1,4 +0,0 @@ -target: -while (true) { - continue target; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueTarget3.ts b/tests/cases/compiler/continueTarget3.ts deleted file mode 100644 index 26bea241a7a..00000000000 --- a/tests/cases/compiler/continueTarget3.ts +++ /dev/null @@ -1,5 +0,0 @@ -target1: -target2: -while (true) { - continue target1; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueTarget4.ts b/tests/cases/compiler/continueTarget4.ts deleted file mode 100644 index e00c222aa9c..00000000000 --- a/tests/cases/compiler/continueTarget4.ts +++ /dev/null @@ -1,5 +0,0 @@ -target1: -target2: -while (true) { - continue target2; -} \ No newline at end of file diff --git a/tests/cases/compiler/continueTarget5.ts b/tests/cases/compiler/continueTarget5.ts deleted file mode 100644 index dd3a806ab2d..00000000000 --- a/tests/cases/compiler/continueTarget5.ts +++ /dev/null @@ -1,8 +0,0 @@ -target: -while (true) { - function f() { - while (true) { - continue target; - } - } -} \ No newline at end of file diff --git a/tests/cases/compiler/continueTarget6.ts b/tests/cases/compiler/continueTarget6.ts deleted file mode 100644 index bcdda2ab5e1..00000000000 --- a/tests/cases/compiler/continueTarget6.ts +++ /dev/null @@ -1,3 +0,0 @@ -while (true) { - continue target; -} \ No newline at end of file diff --git a/tests/cases/compiler/duplicateLabel1.ts b/tests/cases/compiler/duplicateLabel1.ts deleted file mode 100644 index c588e7b8183..00000000000 --- a/tests/cases/compiler/duplicateLabel1.ts +++ /dev/null @@ -1,4 +0,0 @@ -target: -target: -while (true) { -} \ No newline at end of file diff --git a/tests/cases/compiler/duplicateLabel2.ts b/tests/cases/compiler/duplicateLabel2.ts deleted file mode 100644 index bdb0396a246..00000000000 --- a/tests/cases/compiler/duplicateLabel2.ts +++ /dev/null @@ -1,6 +0,0 @@ -target: -while (true) { - target: - while (true) { - } -} \ No newline at end of file diff --git a/tests/cases/compiler/duplicateLabel3.ts b/tests/cases/compiler/duplicateLabel3.ts deleted file mode 100644 index d4db9399ed2..00000000000 --- a/tests/cases/compiler/duplicateLabel3.ts +++ /dev/null @@ -1,8 +0,0 @@ -target: -while (true) { - function f() { - target: - while (true) { - } - } -} \ No newline at end of file diff --git a/tests/cases/compiler/duplicateLabel4.ts b/tests/cases/compiler/duplicateLabel4.ts deleted file mode 100644 index 2c62180a2ab..00000000000 --- a/tests/cases/compiler/duplicateLabel4.ts +++ /dev/null @@ -1,7 +0,0 @@ -target: -while (true) { -} - -target: -while (true) { -} \ No newline at end of file diff --git a/tests/cases/compiler/breakNotInIterationOrSwitchStatement1.ts b/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts similarity index 100% rename from tests/cases/compiler/breakNotInIterationOrSwitchStatement1.ts rename to tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement1.ts diff --git a/tests/cases/compiler/breakNotInIterationOrSwitchStatement2.ts b/tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts similarity index 100% rename from tests/cases/compiler/breakNotInIterationOrSwitchStatement2.ts rename to tests/cases/conformance/parser/ecmascript5/Statements/BreakStatements/parser_breakNotInIterationOrSwitchStatement2.ts diff --git a/tests/cases/compiler/continueNotInIterationStatement1.ts b/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts similarity index 100% rename from tests/cases/compiler/continueNotInIterationStatement1.ts rename to tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement1.ts diff --git a/tests/cases/compiler/continueNotInIterationStatement2.ts b/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts similarity index 100% rename from tests/cases/compiler/continueNotInIterationStatement2.ts rename to tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement2.ts diff --git a/tests/cases/compiler/continueNotInIterationStatement3.ts b/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts similarity index 100% rename from tests/cases/compiler/continueNotInIterationStatement3.ts rename to tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement3.ts From fde2591d6fc16c167895ffe6ab648fddf8487f08 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 24 Jul 2014 12:55:51 -0700 Subject: [PATCH 6/7] Add interface LabelledStatementInfo --- src/compiler/parser.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 763968e763e..3e1f9afe580 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -385,6 +385,14 @@ module ts { CrossingFunctionBoundary } + interface LabelledStatementInfo { + addLabel(label: Identifier): void; + pushCurrentLabelSet(isIterationStatement: boolean): void; + pushFunctionBoundary(): void; + pop(): void; + nodeIsNestedInLabel(label: Identifier, requireIterationStatement: boolean, stopAtFunctionBoundary: boolean): ControlBlockContext; + } + export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget): SourceFile { var file: SourceFile; var scanner: Scanner; @@ -402,8 +410,7 @@ module ts { var inSwitchStatement = ControlBlockContext.NotNested; var inIterationStatement = ControlBlockContext.NotNested; - var labelledStatementInfo = (() => { - // TODO(jfreeman): Implement a data structure for tracking labels + var labelledStatementInfo: LabelledStatementInfo = (() => { var functionBoundarySentinel: StringSet = {}; var currentLabelSet: StringSet; var labelSetStack: StringSet[]; From a19698c37de7423fe0e19b5088a2888682856aed Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 24 Jul 2014 17:38:37 -0700 Subject: [PATCH 7/7] Address feedback --- src/compiler/parser.ts | 44 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3e1f9afe580..c6423591c45 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -410,8 +410,14 @@ module ts { var inSwitchStatement = ControlBlockContext.NotNested; var inIterationStatement = ControlBlockContext.NotNested; + // The following is a state machine that tracks what labels are in our current parsing + // context. So if we are parsing a node that is nested (arbitrarily deeply) in a label, + // it will be tracked in this data structure. It is used for checking break/continue + // statements, and checking for duplicate labels. var labelledStatementInfo: LabelledStatementInfo = (() => { - var functionBoundarySentinel: StringSet = {}; + // These are initialized on demand because labels are rare, so it is usually + // not even necessary to allocate these. + var functionBoundarySentinel: StringSet; var currentLabelSet: StringSet; var labelSetStack: StringSet[]; var isIterationStack: boolean[]; @@ -435,9 +441,12 @@ module ts { } function pushFunctionBoundary(): void { - if (!labelSetStack && !isIterationStack) { - labelSetStack = []; - isIterationStack = []; + if (!functionBoundarySentinel) { + functionBoundarySentinel = {}; + if (!labelSetStack && !isIterationStack) { + labelSetStack = []; + isIterationStack = []; + } } Debug.assert(currentLabelSet === undefined); labelSetStack.push(functionBoundarySentinel); @@ -496,7 +505,6 @@ module ts { return ControlBlockContext.NotNested; } - // TODO(jfreeman): Fill in these stubs return { addLabel: addLabel, pushCurrentLabelSet: pushCurrentLabelSet, @@ -2128,34 +2136,34 @@ module ts { } var forOrForInStatement: IterationStatement; if (parseOptional(SyntaxKind.InKeyword)) { - var forInStat = createNode(SyntaxKind.ForInStatement, pos); + var forInStatement = createNode(SyntaxKind.ForInStatement, pos); if (declarations) { if (declarations.length > 1) { error(Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement); } - forInStat.declaration = declarations[0]; + forInStatement.declaration = declarations[0]; } else { - forInStat.variable = varOrInit; + forInStatement.variable = varOrInit; } - forInStat.expression = parseExpression(); + forInStatement.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); - forOrForInStatement = forInStat; + forOrForInStatement = forInStatement; } else { - var forStat = createNode(SyntaxKind.ForStatement, pos); - if (declarations) forStat.declarations = declarations; - if (varOrInit) forStat.initializer = varOrInit; + var forStatement = createNode(SyntaxKind.ForStatement, pos); + if (declarations) forStatement.declarations = declarations; + if (varOrInit) forStatement.initializer = varOrInit; parseExpected(SyntaxKind.SemicolonToken); if (token !== SyntaxKind.SemicolonToken && token !== SyntaxKind.CloseParenToken) { - forStat.condition = parseExpression(); + forStatement.condition = parseExpression(); } parseExpected(SyntaxKind.SemicolonToken); if (token !== SyntaxKind.CloseParenToken) { - forStat.iterator = parseExpression(); + forStatement.iterator = parseExpression(); } parseExpected(SyntaxKind.CloseParenToken); - forOrForInStatement = forStat; + forOrForInStatement = forStatement; } var saveInIterationStatement = inIterationStatement; @@ -2182,13 +2190,13 @@ module ts { checkBreakOrContinueStatementWithLabel(node); } else { - checkAnonymousBreakOrContinueStatement(node); + checkBareBreakOrContinueStatement(node); } } return node; } - function checkAnonymousBreakOrContinueStatement(node: BreakOrContinueStatement): void { + function checkBareBreakOrContinueStatement(node: BreakOrContinueStatement): void { if (node.kind === SyntaxKind.BreakStatement) { if (inIterationStatement === ControlBlockContext.Nested || inSwitchStatement === ControlBlockContext.Nested) {