diff --git a/VHDLFormatter.js b/VHDLFormatter.js index 528d7fe..a1d2890 100644 --- a/VHDLFormatter.js +++ b/VHDLFormatter.js @@ -46,6 +46,10 @@ function fetchHeader(url, wch) { return ""; } } +String.prototype.regexStartsWith = function (pattern) { + var searchResult = this.search(pattern); + return searchResult == 0; +}; String.prototype.regexIndexOf = function (pattern, startIndex) { startIndex = startIndex || 0; var searchResult = this.substr(startIndex).search(pattern); @@ -261,7 +265,13 @@ function beautify(input, settings) { input = arr.join("\r\n"); input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); - input = beautify2(input, settings); + //input = beautify2(input, settings); + //new + arr = input.split("\r\n"); + let result = []; + beautify3(arr, result, settings, 0, 0); + arr = FormattedLineToString(result, settings.Indentation); + input = arr.join("\r\n"); for (var k = 0; k < commentsIndex; k++) { input = input.replace(ILCommentPrefix + k, comments[k]); } @@ -270,6 +280,76 @@ function beautify(input, settings) { return input; } exports.beautify = beautify; +class FormattedLine { + constructor(line, indent) { + this.Line = line; + this.Indent = indent; + } +} +exports.FormattedLine = FormattedLine; +function FormattedLineToString(arr, indentation) { + let result = []; + if (arr == null) { + return result; + } + arr.forEach(i => { + if (i instanceof FormattedLine) { + result.push((Array(i.Indent).join(indentation)) + i.Line); + } + else { + result = result.concat(FormattedLineToString(i, indentation)); + } + }); + return result; +} +function beautifyCaseBlock(inputs, result, settings, startIndex, indent, isFirstKeyWord) { + if (!inputs[startIndex].regexStartsWith(/(CASE)([\s]|$)/)) { + return startIndex; + } + result.push(new FormattedLine(inputs[startIndex], indent)); + let i = beautify3(inputs, result, settings, startIndex + 1, indent + 2); + result[i].Indent = indent; + return i; +} +exports.beautifyCaseBlock = beautifyCaseBlock; +function beautify3(inputs, result, settings, startIndex, indent, isFirstKeyWord) { + let i; + let ignoreFirstKeyWords = ["WHEN"]; + let blockMidKeyWords = ["ELSE", "ELSIF"].concat(ignoreFirstKeyWords); + let blockStartsKeyWords = ["IF", "CASE"]; + let blockEndsKeyWords = ["END"]; + let ignoreFirstKeyWordsStr = ignoreFirstKeyWords.join("|"); + let newLineAfterKeyWordsStr = blockStartsKeyWords.join("|"); + let blockEndKeyWordsStr = blockEndsKeyWords.join("|"); + let blockMidKeyWordsStr = blockMidKeyWords.join("|"); + let regexBlockMidKeyWords = new RegExp("(" + blockMidKeyWordsStr + ")([\\s]|$)"); + let regexIgnoreFirstKeyWords = new RegExp("(" + ignoreFirstKeyWordsStr + ")([\\s]|$)"); + let regexBlockStartsKeywords = new RegExp("(" + newLineAfterKeyWordsStr + ")([\\s]|$)"); + let regexBlockEndsKeyWords = new RegExp("(" + blockEndKeyWordsStr + ")([\\s]|$)"); + for (i = startIndex; i < inputs.length; i++) { + let input = inputs[i]; + if (input.regexStartsWith(/(CASE)([\s]|$)/)) { + i = beautifyCaseBlock(inputs, result, settings, i, indent); + continue; + } + result.push(new FormattedLine(input, indent)); + if (startIndex != 0 + && (input.regexStartsWith(regexBlockMidKeyWords))) { + result[i].Indent--; + } + else if (startIndex != 0 + && (input.regexStartsWith(regexBlockEndsKeyWords))) { + result[i].Indent--; + return i; + } + if (input.regexStartsWith(regexBlockStartsKeywords)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } + } + i--; + return i; +} +exports.beautify3 = beautify3; function beautify2(input, settings) { let arr = input.split("\r\n"); let quotes = EscapeQuotes(arr); diff --git a/VHDLFormatter.ts b/VHDLFormatter.ts index a3c247e..183fa7a 100644 --- a/VHDLFormatter.ts +++ b/VHDLFormatter.ts @@ -55,9 +55,14 @@ declare global { regexIndexOf: (pattern: RegExp, startIndex?: number) => number; regexLastIndexOf: (pattern: RegExp, startIndex: number) => number; reverse: () => string; + regexStartsWith: (pattern: RegExp) => boolean; } } +String.prototype.regexStartsWith = function (pattern): boolean { + var searchResult = this.search(pattern); + return searchResult == 0; +} String.prototype.regexIndexOf = function (pattern, startIndex) { startIndex = startIndex || 0; var searchResult = this.substr(startIndex).search(pattern); @@ -297,7 +302,14 @@ export function beautify(input: string, settings: BeautifierSettings) { input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); - input = beautify2(input, settings); + //input = beautify2(input, settings); + + //new + arr = input.split("\r\n"); + let result: (FormattedLine | FormattedLine[])[] = []; + beautify3(arr, result, settings, 0, 0); + arr = FormattedLineToString(result, settings.Indentation); + input = arr.join("\r\n"); for (var k = 0; k < commentsIndex; k++) { input = input.replace(ILCommentPrefix + k, comments[k]); @@ -308,6 +320,81 @@ export function beautify(input: string, settings: BeautifierSettings) { return input; } +export class FormattedLine { + Line: string; + Indent: number; + constructor(line: string, indent: number) { + this.Line = line; + this.Indent = indent; + } +} + +function FormattedLineToString(arr: (FormattedLine | FormattedLine[])[], indentation: string): Array { + let result: Array = []; + if (arr == null) { + return result; + } + arr.forEach(i => { + if (i instanceof FormattedLine) { + result.push((Array(i.Indent).join(indentation)) + i.Line); + } + else { + result = result.concat(FormattedLineToString(i, indentation)); + } + }); + return result; +} + +export function beautifyCaseBlock(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number, isFirstKeyWord?: boolean): number { + if (!inputs[startIndex].regexStartsWith(/(CASE)([\s]|$)/)) { + return startIndex; + } + result.push(new FormattedLine(inputs[startIndex], indent)); + + let i = beautify3(inputs, result, settings, startIndex + 1, indent + 2); + (result[i]).Indent = indent; + return i; +} + +export function beautify3(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number, isFirstKeyWord?: boolean): number { + let i: number; + let ignoreFirstKeyWords: Array = ["WHEN"]; + let blockMidKeyWords: Array = ["ELSE", "ELSIF"].concat(ignoreFirstKeyWords); + let blockStartsKeyWords: Array = ["IF", "CASE"]; + let blockEndsKeyWords: Array = ["END"]; + + let ignoreFirstKeyWordsStr: string = ignoreFirstKeyWords.join("|"); + let newLineAfterKeyWordsStr: string = blockStartsKeyWords.join("|"); + let blockEndKeyWordsStr: string = blockEndsKeyWords.join("|"); + let blockMidKeyWordsStr: string = blockMidKeyWords.join("|"); + let regexBlockMidKeyWords: RegExp = new RegExp("(" + blockMidKeyWordsStr + ")([\\s]|$)") + let regexIgnoreFirstKeyWords: RegExp = new RegExp("(" + ignoreFirstKeyWordsStr + ")([\\s]|$)") + let regexBlockStartsKeywords: RegExp = new RegExp("(" + newLineAfterKeyWordsStr + ")([\\s]|$)") + let regexBlockEndsKeyWords: RegExp = new RegExp("(" + blockEndKeyWordsStr + ")([\\s]|$)") + for (i = startIndex; i < inputs.length; i++) { + let input: string = inputs[i]; + if (input.regexStartsWith(/(CASE)([\s]|$)/)) { + i = beautifyCaseBlock(inputs, result, settings, i, indent); + continue; + } + result.push(new FormattedLine(input, indent)); + if (startIndex != 0 + && (input.regexStartsWith(regexBlockMidKeyWords))) { + (result[i]).Indent--; + } + else if (startIndex != 0 + && (input.regexStartsWith(regexBlockEndsKeyWords))) { + (result[i]).Indent--; + return i; + } + if (input.regexStartsWith(regexBlockStartsKeywords)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } + } + i--; + return i; +} + function beautify2(input, settings: BeautifierSettings): string { let arr = input.split("\r\n"); let quotes = EscapeQuotes(arr); diff --git a/VHDLFormatterUnitTests.js b/VHDLFormatterUnitTests.js index 8f82e6b..7365418 100644 --- a/VHDLFormatterUnitTests.js +++ b/VHDLFormatterUnitTests.js @@ -7,17 +7,143 @@ const VHDLFormatter_4 = require("./VHDLFormatter"); const VHDLFormatter_5 = require("./VHDLFormatter"); const VHDLFormatter_6 = require("./VHDLFormatter"); const VHDLFormatter_7 = require("./VHDLFormatter"); +const VHDLFormatter_8 = require("./VHDLFormatter"); +const VHDLFormatter_9 = require("./VHDLFormatter"); let testCount = 0; var showUnitTests = true; //window.location.href.indexOf("http") < 0; if (showUnitTests) { testCount = 0; - UnitTest(); + //UnitTest(); UnitTestIndentDecode(); UnitTestRemoveAsserts(); UnitTestApplyNoNewLineAfter(); UnitTestSetNewLinesAfterSymbols(); + UnitTestbeautify3(); console.log("total tests: " + testCount); } +function UnitTestbeautify3() { + console.log("=== beautify3 ==="); + Beautify3Case1(); + Beautify3Case2(); + Beautify3Case3(); + Beautify3Case4(); + Beautify3Case5(); + Beautify3Case6(); +} +function Beautify3Case1() { + let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs = ["a;", "b;"]; + let expected = [new VHDLFormatter_9.FormattedLine("a;", 0), new VHDLFormatter_9.FormattedLine("b;", 0)]; + UnitTest6(VHDLFormatter_8.beautify3, "General", settings, inputs, expected, 0, 1, 0); +} +function Beautify3Case2() { + let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs = ["IF x = '1' THEN", "RETURN 1;", "END IF;"]; + let expected = [ + new VHDLFormatter_9.FormattedLine("IF x = '1' THEN", 0), + new VHDLFormatter_9.FormattedLine("RETURN 1;", 1), + new VHDLFormatter_9.FormattedLine("END IF;", 0) + ]; + UnitTest6(VHDLFormatter_8.beautify3, "IF END", settings, inputs, expected, 0, 2, 0); +} +function Beautify3Case3() { + let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs = [ + "IF x = '1' THEN", + "RETURN 1;", + "ELSIF x = '0' THEN", + "RETURN 0;", + "ELSE", + "RETURN -1;", + "END IF;" + ]; + let expected = [ + new VHDLFormatter_9.FormattedLine("IF x = '1' THEN", 0), + new VHDLFormatter_9.FormattedLine("RETURN 1;", 1), + new VHDLFormatter_9.FormattedLine("ELSIF x = '0' THEN", 0), + new VHDLFormatter_9.FormattedLine("RETURN 0;", 1), + new VHDLFormatter_9.FormattedLine("ELSE", 0), + new VHDLFormatter_9.FormattedLine("RETURN -1;", 1), + new VHDLFormatter_9.FormattedLine("END IF;", 0) + ]; + UnitTest6(VHDLFormatter_8.beautify3, "if elsif else end", settings, inputs, expected, 0, 6, 0); +} +function Beautify3Case4() { + let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs = ["END"]; + let expected = [new VHDLFormatter_9.FormattedLine("END", 0)]; + UnitTest6(VHDLFormatter_8.beautify3, "one line END", settings, inputs, expected, 0, 0, 0); +} +function Beautify3Case5() { + let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs = [ + "CASE b", + "WHEN 1 =>", + "c <= d;", + "WHEN 2 =>", + "d <= f;", + "END CASE;" + ]; + let expected = [ + new VHDLFormatter_9.FormattedLine("CASE b", 0), + new VHDLFormatter_9.FormattedLine("WHEN 1 =>", 1), + new VHDLFormatter_9.FormattedLine("c <= d;", 2), + new VHDLFormatter_9.FormattedLine("WHEN 2 =>", 1), + new VHDLFormatter_9.FormattedLine("d <= f;", 2), + new VHDLFormatter_9.FormattedLine("END CASE;", 0) + ]; + UnitTest6(VHDLFormatter_8.beautify3, "case when when end", settings, inputs, expected, 0, 5, 0); +} +function Beautify3Case6() { + let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs = [ + "CASE b", + "WHEN 1 =>", + "c <= d;", + "CASE b", + "WHEN 1 =>", + "c <= d;", + "WHEN 2 =>", + "d <= f;", + "END CASE;", + "WHEN 2 =>", + "d <= f;", + "END CASE;" + ]; + let expected = [ + new VHDLFormatter_9.FormattedLine("CASE b", 0), + new VHDLFormatter_9.FormattedLine("WHEN 1 =>", 1), + new VHDLFormatter_9.FormattedLine("c <= d;", 2), + new VHDLFormatter_9.FormattedLine("CASE b", 2), + new VHDLFormatter_9.FormattedLine("WHEN 1 =>", 3), + new VHDLFormatter_9.FormattedLine("c <= d;", 4), + new VHDLFormatter_9.FormattedLine("WHEN 2 =>", 3), + new VHDLFormatter_9.FormattedLine("d <= f;", 4), + new VHDLFormatter_9.FormattedLine("END CASE;", 2), + new VHDLFormatter_9.FormattedLine("WHEN 2 =>", 1), + new VHDLFormatter_9.FormattedLine("d <= f;", 2), + new VHDLFormatter_9.FormattedLine("END CASE;", 0) + ]; + UnitTest6(VHDLFormatter_8.beautify3, "case & case end", settings, inputs, expected, 0, 11, 0); +} function UnitTestSetNewLinesAfterSymbols() { console.log("=== SetNewLinesAfterSymbols ==="); let input = "a; @@comments1\r\nb;"; @@ -57,6 +183,62 @@ function UnitTestIndentDecode() { UnitTest2(VHDLFormatter_2.indentDecode, "4 blankspaces", " ", "four blankspace"); UnitTest2(VHDLFormatter_2.indentDecode, "9 blankspaces", " ", "many blankspace"); } +function assertFormattedLines(testName, expected, actual, message, cumulateTestCount) { + var l = Math.min(actual.length, expected.length); + let result = ""; + for (var i = 0; i < l; i++) { + if (actual[i] instanceof VHDLFormatter_9.FormattedLine) { + if (expected[i] instanceof VHDLFormatter_9.FormattedLine) { + assertFormattedLine(testName, (expected[i]), (actual[i]), message, false); + } + else { + console.log("expected FormatLine[], actual FormattedLine. actual:" + (actual[i]).Line); + } + } + else { + if (expected[i] instanceof VHDLFormatter_9.FormattedLine) { + console.log("expected FormatLine, actual FormattedLine[]. expected:" + (expected[i]).Line); + } + else { + assertFormattedLines(testName, (actual[i]), (expected[i]), message, false); + } + } + } + if (actual.length > expected.length) { + result += "actual has more items"; + for (var i = expected.length; i < actual.length; i++) { + result += "actual[" + i + "] = " + actual[i]; + } + } + else if (actual.length < expected.length) { + result += "expected has more items"; + for (var i = actual.length; i < expected.length; i++) { + result += "expected[" + i + "] = " + expected[i]; + } + } + if (result.length > 0) { + console.log(result); + } + if (cumulateTestCount != false) { + testCount++; + } +} +function assertFormattedLine(testName, expected, actual, message, cumulateTestCount) { + if (expected.Indent != actual.Indent) { + console.log(testName + ' failed:\nexpected: "' + expected.Line + '", ' + expected.Indent + + ';\nactual: "' + actual.Line + '", ' + actual.Indent); + } + var result = CompareString(actual.Line, expected.Line); + if (result != true) { + console.log(testName + " failed: " + result); + } + else { + //console.log(testName + " pass"); + } + if (cumulateTestCount != false) { + testCount++; + } +} function assert(testName, expected, actual, message) { var result = CompareString(actual, expected); if (result != true) { @@ -77,6 +259,14 @@ function assertArray(testName, expected, actual, message) { } testCount++; } +function UnitTest6(func, testName, parameters, inputs, expected, startIndex, expectedEndIndex, indent) { + let actual = []; + let endIndex = func(inputs, actual, parameters, startIndex, indent); + if (endIndex != expectedEndIndex) { + console.log(testName + " failed;\nend index, actual: " + endIndex + "; expected: " + expectedEndIndex); + } + assertFormattedLines(testName, expected, actual); +} function UnitTest5(func, testName, parameters, inputs, expected) { let actual = func(inputs, parameters); assert(testName, expected, actual); diff --git a/VHDLFormatterUnitTests.ts b/VHDLFormatterUnitTests.ts index 8211b9f..deeb761 100644 --- a/VHDLFormatterUnitTests.ts +++ b/VHDLFormatterUnitTests.ts @@ -5,17 +5,22 @@ import { BeautifierSettings } from "./VHDLFormatter"; import { RemoveAsserts } from "./VHDLFormatter"; import { ApplyNoNewLineAfter } from "./VHDLFormatter"; import { SetNewLinesAfterSymbols } from "./VHDLFormatter"; +import { beautify3 } from "./VHDLFormatter"; +import { FormattedLine } from "./VHDLFormatter"; let testCount: number = 0; var showUnitTests = true;//window.location.href.indexOf("http") < 0; if (showUnitTests) { testCount = 0; - UnitTest(); + //UnitTest(); + UnitTestIndentDecode(); UnitTestRemoveAsserts(); UnitTestApplyNoNewLineAfter(); UnitTestSetNewLinesAfterSymbols(); + + UnitTestbeautify3(); console.log("total tests: " + testCount); } @@ -23,6 +28,136 @@ interface Function { readonly name: string; } +function UnitTestbeautify3() { + console.log("=== beautify3 ==="); + Beautify3Case1(); + Beautify3Case2(); + Beautify3Case3(); + Beautify3Case4(); + Beautify3Case5(); + Beautify3Case6(); +} + +function Beautify3Case1() { + let new_line_after_symbols: NewLineSettings = new NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs: Array = ["a;", "b;"]; + let expected: (FormattedLine | FormattedLine[])[] = [new FormattedLine("a;", 0), new FormattedLine("b;", 0)]; + UnitTest6(beautify3, "General", settings, inputs, expected, 0, 1, 0); +} + +function Beautify3Case2() { + let new_line_after_symbols: NewLineSettings = new NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs: Array = ["IF x = '1' THEN", "RETURN 1;", "END IF;"]; + let expected: (FormattedLine | FormattedLine[])[] = [ + new FormattedLine("IF x = '1' THEN", 0), + new FormattedLine("RETURN 1;", 1), + new FormattedLine("END IF;", 0) + ]; + UnitTest6(beautify3, "IF END", settings, inputs, expected, 0, 2, 0); +} + +function Beautify3Case3() { + let new_line_after_symbols: NewLineSettings = new NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs: Array = [ + "IF x = '1' THEN", + "RETURN 1;", + "ELSIF x = '0' THEN", + "RETURN 0;", + "ELSE", + "RETURN -1;", + "END IF;"]; + let expected: (FormattedLine | FormattedLine[])[] = [ + new FormattedLine("IF x = '1' THEN", 0), + new FormattedLine("RETURN 1;", 1), + new FormattedLine("ELSIF x = '0' THEN", 0), + new FormattedLine("RETURN 0;", 1), + new FormattedLine("ELSE", 0), + new FormattedLine("RETURN -1;", 1), + new FormattedLine("END IF;", 0) + ]; + UnitTest6(beautify3, "if elsif else end", settings, inputs, expected, 0, 6, 0); +} + +function Beautify3Case4() { + let new_line_after_symbols: NewLineSettings = new NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs: Array = ["END"]; + let expected: (FormattedLine | FormattedLine[])[] = [new FormattedLine("END", 0)]; + UnitTest6(beautify3, "one line END", settings, inputs, expected, 0, 0, 0); +} + +function Beautify3Case5() { + let new_line_after_symbols: NewLineSettings = new NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs: Array = [ + "CASE b", + "WHEN 1 =>", + "c <= d;", + "WHEN 2 =>", + "d <= f;", + "END CASE;" + ]; + let expected: (FormattedLine | FormattedLine[])[] = [ + new FormattedLine("CASE b", 0), + new FormattedLine("WHEN 1 =>", 1), + new FormattedLine("c <= d;", 2), + new FormattedLine("WHEN 2 =>", 1), + new FormattedLine("d <= f;", 2), + new FormattedLine("END CASE;", 0) + ]; + UnitTest6(beautify3, "case when when end", settings, inputs, expected, 0, 5, 0); +} + +function Beautify3Case6() { + let new_line_after_symbols: NewLineSettings = new NewLineSettings(); + new_line_after_symbols.newLineAfter = ["then", ";"]; + new_line_after_symbols.noNewLineAfter = ["port", "generic"]; + let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); + let inputs: Array = [ + "CASE b", + "WHEN 1 =>", + "c <= d;", + "CASE b", + "WHEN 1 =>", + "c <= d;", + "WHEN 2 =>", + "d <= f;", + "END CASE;", + "WHEN 2 =>", + "d <= f;", + "END CASE;" + ]; + let expected: (FormattedLine | FormattedLine[])[] = [ + new FormattedLine("CASE b", 0), + new FormattedLine("WHEN 1 =>", 1), + new FormattedLine("c <= d;", 2), + new FormattedLine("CASE b", 2), + new FormattedLine("WHEN 1 =>", 3), + new FormattedLine("c <= d;", 4), + new FormattedLine("WHEN 2 =>", 3), + new FormattedLine("d <= f;", 4), + new FormattedLine("END CASE;", 2), + new FormattedLine("WHEN 2 =>", 1), + new FormattedLine("d <= f;", 2), + new FormattedLine("END CASE;", 0) + ]; + UnitTest6(beautify3, "case & case end", settings, inputs, expected, 0, 11, 0); +} + + function UnitTestSetNewLinesAfterSymbols() { console.log("=== SetNewLinesAfterSymbols ==="); let input = "a; @@comments1\r\nb;" @@ -69,6 +204,65 @@ function UnitTestIndentDecode() { UnitTest2(indentDecode, "9 blankspaces", " ", "many blankspace"); } +function assertFormattedLines(testName, expected: (FormattedLine | FormattedLine[])[], actual: (FormattedLine | FormattedLine[])[], message?, cumulateTestCount?: boolean) { + var l = Math.min(actual.length, expected.length); + let result: string = ""; + for (var i = 0; i < l; i++) { + if (actual[i] instanceof FormattedLine) { + if (expected[i] instanceof FormattedLine) { + assertFormattedLine(testName, (expected[i]), (actual[i]), message, false); + } + else { + console.log("expected FormatLine[], actual FormattedLine. actual:" + ((actual[i])).Line); + } + } + else { + if (expected[i] instanceof FormattedLine) { + console.log("expected FormatLine, actual FormattedLine[]. expected:" + ((expected[i])).Line); + } + else { + assertFormattedLines(testName, (actual[i]), (expected[i]), message, false); + } + } + } + if (actual.length > expected.length) { + result += "actual has more items"; + for (var i = expected.length; i < actual.length; i++) { + result += "actual[" + i + "] = " + actual[i]; + } + } + else if (actual.length < expected.length) { + result += "expected has more items"; + for (var i = actual.length; i < expected.length; i++) { + result += "expected[" + i + "] = " + expected[i]; + } + } + if (result.length > 0) { + console.log(result); + } + + if (cumulateTestCount != false) { + testCount++; + } +} + +function assertFormattedLine(testName, expected: FormattedLine, actual: FormattedLine, message?, cumulateTestCount?: boolean) { + if (expected.Indent != actual.Indent) { + console.log(testName + ' failed:\nexpected: "' + expected.Line + '", ' + expected.Indent + + ';\nactual: "' + actual.Line + '", ' + actual.Indent); + } + var result = CompareString(actual.Line, expected.Line); + if (result != true) { + console.log(testName + " failed: " + result); + } + else { + //console.log(testName + " pass"); + } + if (cumulateTestCount != false) { + testCount++; + } +} + function assert(testName, expected, actual, message?) { var result = CompareString(actual, expected); if (result != true) { @@ -99,6 +293,17 @@ type Array2Callback = (arr: Array, parameters: Array) => void; type String2Callback = (text: string, parameters: NewLineSettings) => string; +type BeautifyCallback = (inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number) => number; + +function UnitTest6(func: BeautifyCallback, testName: string, parameters: BeautifierSettings, inputs: Array, expected: (FormattedLine | FormattedLine[])[], startIndex: number, expectedEndIndex: number, indent: number) { + let actual: (FormattedLine | FormattedLine[])[] = [] + let endIndex: number = func(inputs, actual, parameters, startIndex, indent); + if (endIndex != expectedEndIndex) { + console.log(testName + " failed;\nend index, actual: " + endIndex + "; expected: " + expectedEndIndex) + } + assertFormattedLines(testName, expected, actual); +} + function UnitTest5(func: String2Callback, testName: string, parameters: NewLineSettings, inputs, expected: string) { let actual: string = func(inputs, parameters); assert(testName, expected, actual);