Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port: LG error related changes #1785

Merged
merged 18 commits into from
Feb 26, 2020
Merged
Next Next commit
port LG error centralization
cosmicshuai committed Feb 21, 2020
commit 5384e5586562358d93bc9e478ae06f870d7fc708
7 changes: 4 additions & 3 deletions libraries/botbuilder-lg/src/analyzer.ts
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import { LGFileParserVisitor } from './generated/LGFileParserVisitor';
import { LGTemplate } from './lgTemplate';
import { LGExtensions } from './lgExtensions';
import { AnalyzerResult } from './analyzerResult';
import {LGErrors} from './lgErrors';

// tslint:disable-next-line: max-classes-per-file
/**
@@ -49,11 +50,11 @@ export class Analyzer extends AbstractParseTreeVisitor<AnalyzerResult> implement
*/
public analyzeTemplate(templateName: string): AnalyzerResult {
if (!(templateName in this.templateMap)) {
throw new Error(`No such template: ${ templateName }`);
throw new Error(LGErrors.templateNotExist(templateName));
}

if (this.evalutationTargetStack.find((u: EvaluationTarget): boolean => u.templateName === templateName) !== undefined) {
throw new Error(`Loop detected: ${ this.evalutationTargetStack.reverse()
throw new Error(`${ LGErrors.loopDetected } ${ this.evalutationTargetStack.reverse()
.map((u: EvaluationTarget): string => u.templateName)
.join(' => ') }`);
}
@@ -79,7 +80,7 @@ export class Analyzer extends AbstractParseTreeVisitor<AnalyzerResult> implement
}
}

throw Error(`template name match failed`);
return new AnalyzerResult();
}

public visitNormalBody(ctx: lp.NormalBodyContext): AnalyzerResult {
2 changes: 1 addition & 1 deletion libraries/botbuilder-lg/src/customizedMemory.ts
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ export class CustomizedMemory implements MemoryInterface {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public setValue(_path: string, _value: any): void {
return;
throw Error(`Method not implemented.`)
}

public version(): string {
90 changes: 31 additions & 59 deletions libraries/botbuilder-lg/src/evaluator.ts
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import { LGTemplate } from './lgTemplate';
import * as path from 'path';
import * as fs from 'fs';
import { LGExtensions } from './lgExtensions';
import {LGErrors} from './lgErrors';

/**
* Evaluation tuntime engine
@@ -71,11 +72,11 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa
*/
public evaluateTemplate(templateName: string, scope: any): any {
if (!(templateName in this.templateMap)) {
throw new Error(`No such template: ${ templateName }`);
throw new Error(LGErrors.templateNotExist(templateName));
}

if (this.evalutationTargetStack.find((u: EvaluationTarget): boolean => u.templateName === templateName) !== undefined) {
throw new Error(`Loop detected: ${ this.evalutationTargetStack.reverse()
throw new Error(`${ LGErrors.loopDetected }: ${ this.evalutationTargetStack.reverse()
.map((u: EvaluationTarget): string => u.templateName)
.join(' => ') }`);
}
@@ -238,7 +239,7 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa

public constructScope(templateName: string, args: any[]): any {
if (!this.templateMap[templateName]) {
throw new Error(`No such template ${ templateName }`);
throw new Error(LGErrors.templateNotExist(templateName));
}

const parameters: string[] = this.templateMap[templateName].parameters;
@@ -264,7 +265,7 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa

return memory;
} else {
throw new Error(`Scope is a LG customized memory`);
throw new Error(`Scope is not a LG customized memory`);
}
}

@@ -353,10 +354,10 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa

const { value: result, error }: { value: any; error: string } = this.evalByExpressionEngine(exp, this.currentTarget().scope);
if (error !== undefined) {
throw new Error(`Error occurs when evaluating expression ${ exp }: ${ error }`);
throw new Error(LGErrors.errorExpression(exp, error));
}
if (result === undefined) {
throw new Error(`Error occurs when evaluating expression '${ exp }': ${ exp } is evaluated to null`);
throw new Error(LGErrors.nullExpression(exp));
}

return result;
@@ -413,15 +414,19 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa
}

if (name === Evaluator.fromFileFunctionName) {
return new ExpressionEvaluator(Evaluator.fromFileFunctionName, ExpressionFunctions.apply(this.fromFile()), ReturnType.Object, this.validateFromFile);
return new ExpressionEvaluator(Evaluator.fromFileFunctionName, ExpressionFunctions.apply(this.fromFile()), ReturnType.Object, ExpressionFunctions.validateUnaryString);
}

if (name === Evaluator.activityAttachmentFunctionName) {
return new ExpressionEvaluator(Evaluator.activityAttachmentFunctionName, ExpressionFunctions.apply(this.activityAttachment()), ReturnType.Object, this.validateActivityAttachment);
return new ExpressionEvaluator(
Evaluator.activityAttachmentFunctionName,
ExpressionFunctions.apply(this.activityAttachment()),
ReturnType.Object,
(expr): void => ExpressionFunctions.validateOrder(expr, undefined, ReturnType.Object, ReturnType.String));
}

if (name === Evaluator.isTemplateFunctionName) {
return new ExpressionEvaluator(Evaluator.isTemplateFunctionName, ExpressionFunctions.apply(this.isTemplate()), ReturnType.Boolean, this.validateIsTemplate);
return new ExpressionEvaluator(Evaluator.isTemplateFunctionName, ExpressionFunctions.apply(this.isTemplate()), ReturnType.Boolean, ExpressionFunctions.validateUnaryString);
}

return baseLookup(name);
@@ -448,17 +453,6 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa
return templateName in this.templateMap;
}

private readonly validateIsTemplate = (expression: Expression): void => {
if (expression.children.length !== 1) {
throw new Error(`isTemplate should have one parameter`);
}

const children0: Expression = expression.children[0];
if (children0.returnType !== ReturnType.Object && children0.returnType !== ReturnType.String) {
throw new Error(`${ children0 } can't be used as a template name, must be a string value`);
}
}

private readonly fromFile = (): any => (args: readonly any[]): any => {
const filePath: string = LGExtensions.normalizePath(args[0].toString());
const resourcePath: string = this.getResourcePath(filePath);
@@ -491,17 +485,6 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa
return resourcePath;
}

private readonly validateFromFile = (expression: Expression): void => {
if (expression.children.length !== 1) {
throw new Error(`fromFile should have one parameter`);
}

const children0: Expression = expression.children[0];
if (children0.returnType !== ReturnType.Object && children0.returnType !== ReturnType.String) {
throw new Error(`${ children0 } can't be used as a file path, must be a string value`);
}
}

private readonly activityAttachment = (): any => (args: readonly any[]): any => {
return {
[Evaluator.LGType]: 'attachment',
@@ -510,22 +493,6 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa
};
}

private readonly validateActivityAttachment = (expression: Expression): void => {
if (expression.children.length !== 2) {
throw new Error(`ActivityAttachment should have two parameters`);
}

const children0: Expression = expression.children[0];
if (children0.returnType !== ReturnType.Object) {
throw new Error(`${ children0 } can't be used as a json file`);
}

const children1: Expression = expression.children[1];
if (children1.returnType !== ReturnType.Object && children1.returnType !== ReturnType.String) {
throw new Error(`${ children0 } can't be used as an attachment format, must be a string value`);
}
}

private readonly templateFunction = (): any => (args: readonly any[]): any => {
const templateName: string = args[0];
const newScope: any = this.constructScope(templateName, args.slice(1));
@@ -534,30 +501,35 @@ export class Evaluator extends AbstractParseTreeVisitor<any> implements LGFilePa
}

private readonly validateTemplateFunction = (expression: Expression): void => {
if (expression.children.length === 0) {
throw new Error(`No template name is provided when calling lgTemplate, expected: lgTemplate(templateName, ...args)`);
}

ExpressionFunctions.validateAtLeastOne(expression);

const children0: Expression = expression.children[0];

// Validate return type
if (children0.returnType !== ReturnType.Object && children0.returnType !== ReturnType.String) {
throw new Error(`${ children0 } can't be used as a template name, must be a string value`);
throw new Error(LGErrors.errorTemplateNameformat(children0.toString()));
}

// Validate more if the name is string constant
if (children0.type === ExpressionType.Constant) {
const templateName: string = (children0 as Constant).value;
if (!this.templateMap[templateName]) {
throw new Error(`No such template '${ templateName }' to call in ${ expression }`);
}
this.checkTemplateReference(templateName, expression.children.slice(1));
}
}

const expectedArgsCount: number = this.templateMap[templateName].parameters.length;
const actualArgsCount: number = expression.children.length - 1;
private checkTemplateReference(templateName: string, children: Expression[]): void{
if (!(templateName in this.templateMap))
{
throw new Error(LGErrors.templateNotExist(templateName));
}

if (expectedArgsCount !== actualArgsCount) {
throw new Error(`Arguments mismatch for template ${ templateName }, expect ${ expectedArgsCount } actual ${ actualArgsCount }`);
}
var expectedArgsCount = this.templateMap[templateName].parameters.length;
var actualArgsCount = children.length;

if (actualArgsCount !== 0 && expectedArgsCount !== actualArgsCount)
{
throw new Error(LGErrors.argumentMismatch(templateName, expectedArgsCount, actualArgsCount));
}
}

13 changes: 7 additions & 6 deletions libraries/botbuilder-lg/src/expander.ts
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import { LGFileParserVisitor } from './generated/LGFileParserVisitor';
import { LGTemplate } from './lgTemplate';
import { LGExtensions } from './lgExtensions';
import { CustomizedMemory } from './customizedMemory';
import { LGErrors } from './lgErrors';

// tslint:disable-next-line: max-classes-per-file
// tslint:disable-next-line: completed-docs
@@ -55,11 +56,11 @@ export class Expander extends AbstractParseTreeVisitor<string[]> implements LGFi
*/
public expandTemplate(templateName: string, scope: any): string[] {
if (!(templateName in this.templateMap)) {
throw new Error(`No such template: ${ templateName }`);
throw new Error(LGErrors.templateNotExist(templateName));
}

if (this.evalutationTargetStack.find((u: EvaluationTarget): boolean => u.templateName === templateName)) {
throw new Error(`Loop detected: ${ this.evalutationTargetStack.reverse()
throw new Error(`${ LGErrors.loopDetected } ${ this.evalutationTargetStack.reverse()
.map((u: EvaluationTarget): string => u.templateName)
.join(' => ') }`);
}
@@ -350,10 +351,10 @@ export class Expander extends AbstractParseTreeVisitor<string[]> implements LGFi

const { value: result, error }: { value: any; error: string } = this.evalByExpressionEngine(exp, this.currentTarget().scope);
if (error) {
throw new Error(`Error occurs when evaluating expression ${ exp }: ${ error }`);
throw new Error(LGErrors.errorExpression(exp, error));
}
if (result === undefined) {
throw new Error(`Error occurs when evaluating expression '${ exp }': ${ exp } is evaluated to null`);
throw new Error(LGErrors.nullExpression(exp));
}

if (Array.isArray(result)) {
@@ -421,14 +422,14 @@ export class Expander extends AbstractParseTreeVisitor<string[]> implements LGFi
const templateName: string = expression.type;

if (!this.templateMap[templateName]) {
throw new Error(`no such template '${ templateName }' to call in ${ expression }`);
throw new Error(LGErrors.templateNotExist(templateName));
}

const expectedArgsCount: number = this.templateMap[templateName].parameters.length;
const actualArgsCount: number = expression.children.length;

if (expectedArgsCount !== actualArgsCount) {
throw new Error(`arguments mismatch for template ${ templateName }, expect ${ expectedArgsCount } actual ${ actualArgsCount }`);
throw new Error(LGErrors.argumentMismatch(templateName, expectedArgsCount, actualArgsCount));
}
}

6 changes: 3 additions & 3 deletions libraries/botbuilder-lg/src/lgErrors.ts
Original file line number Diff line number Diff line change
@@ -17,13 +17,13 @@ export class LGErrors

public static readonly invalidTemplateBody = 'Invalid template body line, did you miss "-" at line begin';

public static readonly invalidStrucName = 'structured name format error.';
public static readonly invalidStrucName = 'Structured name format error.';

public static readonly missingStrucEnd = 'structured LG missing ending "]"';
public static readonly missingStrucEnd = 'Structured LG missing ending "]"';

public static readonly emptyStrucContent = 'Structured content is empty';

public static readonly invalidStrucBody = 'structured body format error.';
public static readonly invalidStrucBody = 'Structured body format error.';

public static readonly invalidWhitespaceInCondition = 'At most 1 whitespace is allowed between IF/ELSEIF/ELSE and :';

3 changes: 2 additions & 1 deletion libraries/botbuilder-lg/src/lgFile.ts
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ import { Expander } from './expander';
import { Analyzer } from './analyzer';
import { LGParser } from './lgParser';
import { AnalyzerResult } from './analyzerResult';
import { LGErrors } from './lgErrors';

/// <summary>
/// LG entrance, including properties that LG file has, and evaluate functions.
@@ -227,7 +228,7 @@ export class LGFile {
public addTemplate(templateName: string, parameters: string[], templateBody: string): LGFile {
const template: LGTemplate = this.templates.find((u: LGTemplate): boolean => u.name === templateName);
if (template !== undefined) {
throw new Error(`template ${ templateName } already exists.`);
throw new Error(LGErrors.templateExist(templateName));
}

const templateNameLine: string = this.buildTemplateNameLine(templateName, parameters);
44 changes: 22 additions & 22 deletions libraries/botbuilder-lg/src/staticChecker.ts
Original file line number Diff line number Diff line change
@@ -142,20 +142,20 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
let result: Diagnostic[] = [];

if (context.structuredBodyNameLine().errorStructuredName() !== undefined) {
result.push(this.buildLGDiagnostic({message: `Structured name format error.`, context: context.structuredBodyNameLine()}));
result.push(this.buildLGDiagnostic({message: LGErrors.invalidStrucName, context: context.structuredBodyNameLine()}));
}

if (context.structuredBodyEndLine() === undefined) {
result.push(this.buildLGDiagnostic({message: `Structured LG missing ending ']'.`, context: context}));
result.push(this.buildLGDiagnostic({message: LGErrors.missingStrucEnd, context: context}));
}

const bodys = context.structuredBodyContentLine();
if (bodys === null || bodys.length === 0) {
result.push(this.buildLGDiagnostic({message: `Structured LG content is empty.`, context: context}));
result.push(this.buildLGDiagnostic({message: LGErrors.emptyStrucContent, context: context}));
} else {
for (const body of bodys) {
if (body.errorStructureLine() !== undefined) {
result.push(this.buildLGDiagnostic({message: `structured body format error.`, context: body.errorStructureLine()}));
result.push(this.buildLGDiagnostic({message: LGErrors.invalidStrucBody, context: body.errorStructureLine()}));
} else if (body.objectStructureLine() !== undefined) {
result = result.concat(this.checkExpression(body.objectStructureLine().text, body.objectStructureLine()));
} else {
@@ -190,45 +190,45 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
if (node.text.split(' ').length - 1 > 1) {
result.push(this.buildLGDiagnostic({
// tslint:disable-next-line: max-line-length
message: `At most 1 whitespace is allowed between IF/ELSEIF/ELSE and :.`,
message: LGErrors.invalidWhitespaceInCondition,
context: conditionNode
}));
}

if (idx === 0 && !ifExpr) {
result.push(this.buildLGDiagnostic({
message: `condition is not start with if`,
message: LGErrors.notStartWithIfInCondition,
severity: DiagnosticSeverity.Warning,
context: conditionNode
}));
}

if (idx > 0 && ifExpr) {
result.push(this.buildLGDiagnostic({
message: `condition can't have more than one if`,
message: LGErrors.multipleIfInCondition,
context: conditionNode
}));
}

if (idx === ifRules.length - 1 && !elseExpr) {
result.push(this.buildLGDiagnostic({
message: `condition is not end with else`,
message: LGErrors.notEndWithElseInCondition,
severity: DiagnosticSeverity.Warning,
context: conditionNode
}));
}

if (idx > 0 && idx < ifRules.length - 1 && !elseIfExpr) {
result.push(this.buildLGDiagnostic({
message: `only elseif is allowed in middle of condition`,
message: LGErrors.invalidMiddleInCondition,
context: conditionNode
}));
}

if (!elseExpr) {
if (ifRule.ifCondition().EXPRESSION().length !== 1) {
result.push(this.buildLGDiagnostic({
message: `if and elseif should followed by one valid expression`,
message: LGErrors.invalidExpressionInCondition,
context: conditionNode
}));
} else {
@@ -237,7 +237,7 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
} else {
if (ifRule.ifCondition().EXPRESSION().length !== 0) {
result.push(this.buildLGDiagnostic({
message: `else should not followed by any expression`,
message: LGErrors.extraExpressionInCondition,
context: conditionNode
}));
}
@@ -246,7 +246,7 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
result = result.concat(this.visit(ifRule.normalTemplateBody()));
} else {
result.push(this.buildLGDiagnostic({
message: `no normal template body in condition block`,
message: LGErrors.missingTemplateBodyInCondition,
context: conditionNode
}));
}
@@ -275,43 +275,43 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
if (node.text.split(' ').length - 1 > 1) {
result.push(this.buildLGDiagnostic({
// tslint:disable-next-line: max-line-length
message: `At most 1 whitespace is allowed between SWITCH/CASE/DEFAULT and :.`,
message: LGErrors.invalidWhitespaceInSwitchCase,
context: switchCaseStat
}));
}

if (idx === 0 && !switchExpr) {
result.push(this.buildLGDiagnostic({
message: `control flow is not starting with switch`,
message: LGErrors.notStartWithSwitchInSwitchCase,
context: switchCaseStat
}));
}

if (idx > 0 && switchExpr) {
result.push(this.buildLGDiagnostic({
message: `control flow cannot have more than one switch statement`,
message: LGErrors.multipleSwithStatementInSwitchCase,
context: switchCaseStat
}));
}

if (idx > 0 && idx < length - 1 && !caseExpr) {
result.push(this.buildLGDiagnostic({
message: `only case statement is allowed in the middle of control flow`,
message: LGErrors.invalidStatementInMiddlerOfSwitchCase,
context: switchCaseStat
}));
}

if (idx === length - 1 && (caseExpr || defaultExpr)) {
if (caseExpr) {
result.push(this.buildLGDiagnostic({
message: `control flow is not ending with default statement`,
message: LGErrors.notEndWithDefaultInSwitchCase,
severity: DiagnosticSeverity.Warning,
context: switchCaseStat
}));
} else {
if (length === 2) {
result.push(this.buildLGDiagnostic({
message: `control flow should have at least one case statement`,
message: LGErrors.missingCaseInSwitchCase,
severity: DiagnosticSeverity.Warning,
context: switchCaseStat
}));
@@ -321,7 +321,7 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
if (switchExpr || caseExpr) {
if (switchCaseStat.EXPRESSION().length !== 1) {
result.push(this.buildLGDiagnostic({
message: `switch and case should followed by one valid expression`,
message: LGErrors.invalidExpressionInSwiathCase,
context: switchCaseStat
}));
} else {
@@ -330,7 +330,7 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
} else {
if (switchCaseStat.EXPRESSION().length !== 0 || switchCaseStat.TEXT().length !== 0) {
result.push(this.buildLGDiagnostic({
message: `default should not followed by any expression or any text`,
message: LGErrors.extraExpressionInSwitchCase,
context: switchCaseStat
}));
}
@@ -340,7 +340,7 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen
result = result.concat(this.visit(iterNode.normalTemplateBody()));
} else {
result.push(this.buildLGDiagnostic({
message: `no normal template body in case or default block`,
message: LGErrors.missingTemplateBodyInSwitchCase,
context: switchCaseStat
}));
}
@@ -363,7 +363,7 @@ class StaticCheckerInner extends AbstractParseTreeVisitor<Diagnostic[]> implemen

if (multiLinePrefix !== undefined && multiLineSuffix === undefined) {
result.push(this.buildLGDiagnostic({
message: 'Close ``` is missing.',
message: LGErrors.noEndingInMultiline,
context: context
}));
}
10 changes: 5 additions & 5 deletions libraries/botbuilder-lg/tests/lgDiagnostic.test.js
Original file line number Diff line number Diff line change
@@ -25,13 +25,13 @@ describe(`LGExceptionTest`, function() {
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[1].severity);
assert.strictEqual(diagnostics[1].message.includes(`if and elseif should followed by one valid expression`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[2].severity);
assert.strictEqual(diagnostics[2].message.includes(`condition can't have more than one if`), true);
assert.strictEqual(diagnostics[2].message.includes(`condition can not have more than one if`), true);
assert.strictEqual(DiagnosticSeverity.Warning, diagnostics[3].severity);
assert.strictEqual(diagnostics[3].message.includes(`condition is not end with else`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[4].severity);
assert.strictEqual(diagnostics[4].message.includes(`else should not followed by any expression`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[5].severity);
assert.strictEqual(diagnostics[5].message.includes(`condition can't have more than one if`), true);
assert.strictEqual(diagnostics[5].message.includes(`condition can not have more than one if`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[6].severity);
assert.strictEqual(diagnostics[6].message.includes(`only elseif is allowed in middle of condition`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[7].severity);
@@ -88,9 +88,9 @@ describe(`LGExceptionTest`, function() {

assert.strictEqual(5, diagnostics.length);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[0].severity);
assert.strictEqual(diagnostics[0].message.includes(`structured body format error`), true);
assert.strictEqual(diagnostics[0].message.includes(`Structured body format error`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[1].severity);
assert.strictEqual(diagnostics[1].message.includes(`Structured LG content is empty`), true);
assert.strictEqual(diagnostics[1].message.includes(`Structured content is empty`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[2].severity);
assert.strictEqual(diagnostics[2].message.includes(`does not have an evaluator`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[3].severity);
@@ -166,7 +166,7 @@ describe(`LGExceptionTest`, function() {
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[0].severity);
assert.strictEqual(diagnostics[0].message.includes(`At most 1 whitespace is allowed between SWITCH/CASE/DEFAULT and :.`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[1].severity);
assert.strictEqual(diagnostics[1].message.includes(`control flow cannot have more than one switch statement`), true);
assert.strictEqual(diagnostics[1].message.includes(`control flow can not have more than one switch statement`), true);
assert.strictEqual(DiagnosticSeverity.Error, diagnostics[2].severity);
assert.strictEqual(diagnostics[2].message.includes(`control flow is not starting with switch`), true);
assert.strictEqual(DiagnosticSeverity.Warning, diagnostics[3].severity);