From df023d1835aa314d9b86f48c37e0427a0d92836e Mon Sep 17 00:00:00 2001 From: g2384 Date: Fri, 22 Feb 2019 10:58:42 +0000 Subject: [PATCH] squash commits; refactoring --- .github/issue_template.md | 32 + .gitignore | 3 +- README.md | 39 +- VHDLFiles/indent.vhd | 26 + VHDLFiles/instance.vhd | 49 + VHDLFormatter.js | 938 +++++++------------ VHDLFormatter.ts | 969 +++++++------------- VHDLFormatterUnitTests.js | 739 --------------- VHDLFormatterUnitTests.ts | 813 ----------------- descriptiveCounter.js | 57 ++ descriptiveCounter.ts | 57 ++ VHDLFormatter.html => index.html | 374 +++++--- tests/VHDLFormatterUnitTests.ts | 1437 ++++++++++++++++++++++++++++++ tests/assert.ts | 27 + tests/descriptiveCounterTests.ts | 30 + tsconfig.json | 5 +- 16 files changed, 2692 insertions(+), 2903 deletions(-) create mode 100644 .github/issue_template.md create mode 100644 VHDLFiles/indent.vhd create mode 100644 VHDLFiles/instance.vhd delete mode 100644 VHDLFormatterUnitTests.js delete mode 100644 VHDLFormatterUnitTests.ts create mode 100644 descriptiveCounter.js create mode 100644 descriptiveCounter.ts rename VHDLFormatter.html => index.html (58%) create mode 100644 tests/VHDLFormatterUnitTests.ts create mode 100644 tests/assert.ts create mode 100644 tests/descriptiveCounterTests.ts diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 0000000..858a461 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,32 @@ + + + +## Report a bug + +### Input + + +### Expected Behavior + + +### Actual Behavior + + + + + + +--- + +## Request a new feature + +### As a user, I want to... + + +#### Example Input: + + +#### Example Output: + + + diff --git a/.gitignore b/.gitignore index 20ddddb..f39c44e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.map -/.vscode/* \ No newline at end of file +/.vscode/* +/tests/*.js \ No newline at end of file diff --git a/README.md b/README.md index 5672d94..050c9ac 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,39 @@ -# VHDLFomatter +# VHDL Fomatter + VHDL formatter web online written in javascript -[Online version http://g2384.github.io/work/VHDLformatter.html](http://g2384.github.io/work/VHDLformatter.html) \ No newline at end of file +[Online version https://g2384.github.io/VHDLFormatter/](https://g2384.github.io/VHDLFormatter/) + +## Release Notes + +### 2.2 [2018-10-16] + +- support enumerated types + +### 2.1 [2018-03-22] + +- fix keywords case issues +- anything in quotes will not be touched +- correct format for comments after multi-line statement +- options to align signs in parameter lists +- fix function indentation +- fix "align symbols affects process label" +- do not align multi-occurrence symbols in a line +- better styles (checkbox, button, disabled) +- support package bodies +- fix "newline after PORT affects PORT MAP" + +### 2.0 [2018-02-16] + +- rewrite the main algorithm (& move to a new repository) +- add more unit tests +- fix all known issues + +### 1.1 [2016-11] + +- fix some bugs reported by users +- add unit tests + +### 1.0 [2015-01] + +- support most of the VHDL features \ No newline at end of file diff --git a/VHDLFiles/indent.vhd b/VHDLFiles/indent.vhd new file mode 100644 index 0000000..d749481 --- /dev/null +++ b/VHDLFiles/indent.vhd @@ -0,0 +1,26 @@ +package run_base_pkg is + signal runner : runner_sync_t := (phase => test_runner_entry, + locks => ((false, false), + (false, false), + (false, false)), + exit_without_errors => false, + exit_simulation => false); + + shared variable runner_trace_logger : logger_t; + + procedure runner_init; + + impure function get_phase + return runner_phase_t; + + procedure set_test_case_name ( + constant index : in positive; + constant new_name : in string); + + impure function get_test_case_name ( + constant index : positive) + return string; + + procedure set_num_of_test_cases ( + constant new_value : in integer); +end package; \ No newline at end of file diff --git a/VHDLFiles/instance.vhd b/VHDLFiles/instance.vhd new file mode 100644 index 0000000..2fae166 --- /dev/null +++ b/VHDLFiles/instance.vhd @@ -0,0 +1,49 @@ +architecture test of instance is +begin + + a: foo; + + b: entity work.foo; + + b1: entity work.foo(goo); + + c: configuration work.bar; + + d: component foo; + + e: entity work.foo + port map ( a, b, c ); + + f: entity work.foo + port map ( a, b, x => c ); + + g: entity work.foo + generic map ( X => 1 ) + port map ( a, b ); + + h: entity work.foo + port map ( a => open ); + + i: foo port map ( x ); + + UUT : ENTITY work.csa_adder + PORT MAP( + osum => sum, + ocarry => carry + ); + + UUT_S : ENTITY work.csa_adder + PORT MAP( + osum => sums, + ocarry => carrys + ); + +end architecture; + +ARCHITECTURE test3 OF test IS + COMPONENT comp IS PORT (a : BOOLEAN); + END COMPONENT; + SIGNAL s_ok : BOOLEAN; +BEGIN + comp PORT MAP(a => s_ok); -- unlabeled component instantiation +END ARCHITECTURE; \ No newline at end of file diff --git a/VHDLFormatter.js b/VHDLFormatter.js index f15c369..0920106 100644 --- a/VHDLFormatter.js +++ b/VHDLFormatter.js @@ -3,6 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true }); let isTesting = false; const ILCommentPrefix = "@@comments"; const ILQuotesPrefix = "@@quotes"; +const ILSingleQuotesPrefix = "@@singlequotes"; +var FormatMode; +(function (FormatMode) { + FormatMode[FormatMode["Default"] = 0] = "Default"; + FormatMode[FormatMode["EndsWithSemicolon"] = 1] = "EndsWithSemicolon"; + FormatMode[FormatMode["CaseWhen"] = 2] = "CaseWhen"; + FormatMode[FormatMode["IfElse"] = 3] = "IfElse"; + FormatMode[FormatMode["PortGeneric"] = 4] = "PortGeneric"; +})(FormatMode || (FormatMode = {})); +let Mode = FormatMode.Default; class NewLineSettings { constructor() { this.newLineAfter = []; @@ -16,10 +26,10 @@ class NewLineSettings { } push(keyword, addNewLine) { let str = addNewLine.toLowerCase(); - if (str.indexOf("none") >= 0) { + if (str == "none") { return; } - else if (str.indexOf("no") < 0) { + else if (!str.startsWith("no")) { this.newLineAfterPush(keyword); } else { @@ -35,21 +45,12 @@ function ConstructNewLineSettings(dict) { } return settings; } -function fetchHeader(url, wch) { - try { - var req = new XMLHttpRequest(); - req.open("HEAD", url, false); - req.send(null); - if (req.status == 200) { - return req.getResponseHeader(wch); - } - else - return false; - } - catch (e) { - return ""; +String.prototype.regexCount = function (pattern) { + if (pattern.flags.indexOf("g") < 0) { + pattern = new RegExp(pattern.source, pattern.flags + "g"); } -} + return (this.match(pattern) || []).length; +}; String.prototype.count = function (text) { return this.split(text).length - 1; }; @@ -70,6 +71,15 @@ String.prototype.regexLastIndexOf = function (pattern, startIndex) { String.prototype.reverse = function () { return this.split('').reverse().join(''); }; +String.prototype.convertToRegexBlockWords = function () { + let result = new RegExp("(" + this + ")([^\\w]|$)"); + return result; +}; +Array.prototype.convertToRegexBlockWords = function () { + let wordsStr = this.join("|"); + let result = new RegExp("(" + wordsStr + ")([^\\w]|$)"); + return result; +}; function wordWrap() { var d = document.getElementById("result"); if (d.className == "") { @@ -79,74 +89,49 @@ function wordWrap() { d.className = ""; } } -function getHTMLInputElement(name) { - return document.getElementById(name); +function getHTMLInputElement(id) { + return document.getElementById(id); } function noFormat() { - let elements = ["remove_comments", + let elements = [ + "remove_comments", "remove_lines", "remove_report", "check_alias", - "sign_align", + "sign_align_in", + "sign_align_port", + "sign_align_generic", + "sign_align_function", + "sign_align_procedure", "sign_align_all", - "new_line_after_port", - "new_line", + "new_line_after", "use_space", + "customise_indentation", "compress", - "mix_letter"]; - var t = !(getHTMLInputElement("remove_comments").disabled); + "mix_letter" + ]; + var isDisabled = getHTMLInputElement("no_format").checked; elements.forEach(element => { - getHTMLInputElement(element).disabled = t; - }); - let keyword = document.getElementById("keyword"); - for (let i = 0; i < keyword.elements.length; i++) { - keyword.elements[i].disabled = t; - } -} -function indent_decode() { - var custom_indent = getHTMLInputElement("cust_indent").value; - var result = indentDecode(custom_indent); - document.getElementById("indent_s").innerHTML = result; -} -function indentDecode(input) { - input = input.replace(/\\t/g, " "); - var count = [" & one ", " & two ", " & three ", " & four ", " & five ", " & six ", " & seven ", " & eight ", " & many "]; - var tokens = input.split(""); - var result = ""; - var repeatedCharCount = 0; - for (var i = 0; i < tokens.length; i++) { - var char = input.substr(i, 1); - if (char == input.substr(i + 1, 1)) { - repeatedCharCount++; + var htmlElement = getHTMLInputElement(element + "_div"); + try { + getHTMLInputElement(element).disabled = isDisabled; + } + catch (_a) { } + if (isDisabled) { + htmlElement.className += " disabled"; } else { - switch (char) { - case " ": - char = "blankspace"; - break; - case "\t": - char = "tab"; - } - repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; - result += count[repeatedCharCount] + char; - repeatedCharCount = 0; + htmlElement.className = htmlElement.className.replace(/\bdisabled\b/g, ""); } - } - if (result.length < 0) { - switch (char) { - case " ": - char = "blankspace"; - break; - case "\t": - char = "tab"; + }); + let radioButtons = document.getElementsByTagName("input"); + for (let i = 0; i < radioButtons.length; i++) { + if (radioButtons[i].type == "radio") { + radioButtons[i].disabled = isDisabled; } - repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; - result = count[repeatedCharCount] + char; } - result = result.replace(/^ & /, ""); - return result; + getHTMLInputElement("cust_indent").disabled = isDisabled; } -exports.indentDecode = indentDecode; function Compress(input) { input = input.replace(/\r\n/g, ''); input = input.replace(/[\t ]+/g, ' '); @@ -168,7 +153,7 @@ function MixLetters(input) { function EscapeComments(arr, comments, commentIndex) { for (var i = 0; i < arr.length; i++) { let line = arr[i]; - var firstCharIndex = line.regexIndexOf(/[a-zA-Z0-9\(\&\)%_\+'"|]/); + var firstCharIndex = line.regexIndexOf(/[a-zA-Z0-9\(\&\)%_\+'"|\\]/); var commentStartIndex = line.indexOf("--"); if (firstCharIndex < commentStartIndex && firstCharIndex >= 0) { comments.push(line.substr(commentStartIndex)); @@ -190,6 +175,11 @@ function ToLowerCases(arr) { arr[i] = arr[i].toLowerCase(); } } +function ToUpperCases(arr) { + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].toUpperCase(); + } +} function ToCamelCases(arr) { for (var i = 0; i < arr.length; i++) { arr[i] = arr[i].charAt(0) + arr[i].slice(1).toLowerCase(); @@ -203,18 +193,21 @@ function ReplaceKeyWords(text, keywords) { } function SetKeywordCase(input, keywordcase, keywords, typenames) { let inputcase = keywordcase.toLowerCase(); - if (inputcase == "lowercase") { - ToLowerCases(keywords); - ToLowerCases(typenames); - } - else if (inputcase == "defaultcase") { - ToCamelCases(keywords); - ToCamelCases(typenames); - } - if (inputcase != "uppercase") { - input = ReplaceKeyWords(input, keywords); - input = ReplaceKeyWords(input, typenames); - } + switch (keywordcase.toLowerCase()) { + case "lowercase": + ToLowerCases(keywords); + ToLowerCases(typenames); + break; + case "defaultcase": + ToCamelCases(keywords); + ToCamelCases(typenames); + break; + case "uppercase": + ToUpperCases(keywords); + ToUpperCases(typenames); + } + input = ReplaceKeyWords(input, keywords); + input = ReplaceKeyWords(input, typenames); return input; } function SetNewLinesAfterSymbols(text, newLineSettings) { @@ -225,6 +218,9 @@ function SetNewLinesAfterSymbols(text, newLineSettings) { newLineSettings.newLineAfter.forEach(symbol => { let regex = new RegExp("(" + symbol.toUpperCase() + ")[ ]?([^ \r\n@])", "g"); text = text.replace(regex, '$1\r\n$2'); + if (symbol.toUpperCase() == "PORT") { + text = text.replace(/PORT\s+MAP/, "PORT MAP"); + } }); } if (newLineSettings.noNewLineAfter != null) { @@ -268,21 +264,23 @@ function beautify(input, settings) { input = input.replace(/\([\t ]+/g, '\('); input = input.replace(/[ ]+;/g, ';'); input = input.replace(/:[ ]*(PROCESS|ENTITY)/gi, ':$1'); - input = ReplaceKeyWords(input, KeyWords); - input = ReplaceKeyWords(input, TypeNames); arr = input.split("\r\n"); - ReserveSemicolonInKeywords(arr); + let quotes = EscapeQuotes(arr); + let singleQuotes = EscapeSingleQuotes(arr); input = arr.join("\r\n"); - input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); - input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); + input = SetKeywordCase(input, "uppercase", KeyWords, TypeNames); arr = input.split("\r\n"); - let quotes = EscapeQuotes(arr); if (settings.RemoveAsserts) { RemoveAsserts(arr); //RemoveAsserts must be after EscapeQuotes } + ReserveSemicolonInKeywords(arr); + input = arr.join("\r\n"); + input = input.replace(/(PORT|GENERIC)\s+MAP/g, '$1 MAP'); + input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); + input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); + arr = input.split("\r\n"); ApplyNoNewLineAfter(arr, settings.NewLineSettings.noNewLineAfter); input = arr.join("\r\n"); - //input = beautify2(input, settings); //new input = input.replace(/([a-zA-Z0-9\); ])\);(@@comments[0-9]+)?@@end/g, '$1\r\n);$2@@end'); input = input.replace(/[ ]?([&=:\-<>\+|\*])[ ]?/g, ' $1 '); @@ -299,14 +297,22 @@ function beautify(input, settings) { input = input.replace(/\r\n\r\n\r\n/g, '\r\n'); input = input.replace(/[\r\n\s]+$/g, ''); input = input.replace(/[ \t]+\)/g, ')'); + input = input.replace(/\s*\)\s+RETURN\s+([\w]+;)/g, '\r\n) RETURN $1'); //function(..\r\n)return type; -> function(..\r\n)return type; arr = input.split("\r\n"); let result = []; beautify3(arr, result, settings, 0, 0); + if (settings.SignAlignAll) { + AlignSigns(result, 0, result.length - 1); + } arr = FormattedLineToString(result, settings.Indentation); input = arr.join("\r\n"); + input = SetKeywordCase(input, settings.KeywordCase, KeyWords, TypeNames); for (var k = 0; k < quotes.length; k++) { input = input.replace(ILQuotesPrefix + k, quotes[k]); } + for (var k = 0; k < singleQuotes.length; k++) { + input = input.replace(ILSingleQuotesPrefix + k, singleQuotes[k]); + } for (var k = 0; k < commentsIndex; k++) { input = input.replace(ILCommentPrefix + k, comments[k]); } @@ -357,16 +363,16 @@ function GetCloseparentheseEndIndex(inputs, startIndex) { } return startIndex; } -function beautifyPortGenericBlock(inputs, result, settings, startIndex, indent, mode) { +function beautifyPortGenericBlock(inputs, result, settings, startIndex, parentEndIndex, indent, mode) { let firstLine = inputs[startIndex]; let regex = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)"); if (!firstLine.regexStartsWith(regex)) { - return startIndex; + return [startIndex, parentEndIndex]; } let firstLineHasParenthese = firstLine.indexOf("(") >= 0; let hasParenthese = firstLineHasParenthese; let blockBodyStartIndex = startIndex; - let secondLineHasParenthese = inputs[startIndex + 1].startsWith("("); + let secondLineHasParenthese = startIndex + 1 < inputs.length && inputs[startIndex + 1].startsWith("("); if (secondLineHasParenthese) { hasParenthese = true; blockBodyStartIndex++; @@ -379,15 +385,17 @@ function beautifyPortGenericBlock(inputs, result, settings, startIndex, indent, inputs[startIndex] = newInputs[0]; inputs.splice(startIndex + 1, 0, newInputs[1]); endIndex++; + parentEndIndex++; } } - else if (endIndex != startIndex && secondLineHasParenthese) { + else if (endIndex > startIndex + 1 && secondLineHasParenthese) { inputs[startIndex + 1] = inputs[startIndex + 1].replace(/\(([\w\(\) ]+)/, '(\r\n$1'); let newInputs = inputs[startIndex + 1].split("\r\n"); if (newInputs.length == 2) { inputs[startIndex + 1] = newInputs[0]; inputs.splice(startIndex + 2, 0, newInputs[1]); endIndex++; + parentEndIndex++; } } if (firstLineHasParenthese && inputs[startIndex].indexOf("MAP") > 0) { @@ -395,7 +403,11 @@ function beautifyPortGenericBlock(inputs, result, settings, startIndex, indent, } result.push(new FormattedLine(inputs[startIndex], indent)); if (secondLineHasParenthese) { - result.push(new FormattedLine(inputs[startIndex + 1], indent)); + let secondLineIndent = indent; + if (endIndex == startIndex + 1) { + secondLineIndent++; + } + result.push(new FormattedLine(inputs[startIndex + 1], secondLineIndent)); } let blockBodyEndIndex = endIndex; let i = beautify3(inputs, result, settings, blockBodyStartIndex + 1, indent + 1, endIndex); @@ -403,36 +415,69 @@ function beautifyPortGenericBlock(inputs, result, settings, startIndex, indent, result[i].Indent--; blockBodyEndIndex--; } - if (settings.SignAlignRegional) { + if (settings.SignAlignRegional && !settings.SignAlignAll + && settings.SignAlignKeyWords != null + && settings.SignAlignKeyWords.indexOf(mode) >= 0) { blockBodyStartIndex++; - SignsAlignRegional(result, blockBodyStartIndex, blockBodyEndIndex); + AlignSigns(result, blockBodyStartIndex, blockBodyEndIndex); } - return i; + return [i, parentEndIndex]; } exports.beautifyPortGenericBlock = beautifyPortGenericBlock; -function SignsAlignRegional(result, startIndex, endIndex) { - SignAlignRegional(result, startIndex, endIndex, ":"); - SignAlignRegional(result, startIndex, endIndex, ":="); - SignAlignRegional(result, startIndex, endIndex, "=>"); -} -exports.SignsAlignRegional = SignsAlignRegional; -function SignAlignRegional(result, startIndex, endIndex, symbol) { +function AlignSigns(result, startIndex, endIndex) { + AlignSign_(result, startIndex, endIndex, ":"); + AlignSign_(result, startIndex, endIndex, ":="); + AlignSign_(result, startIndex, endIndex, "=>"); + AlignSign_(result, startIndex, endIndex, "<="); +} +exports.AlignSigns = AlignSigns; +function AlignSign_(result, startIndex, endIndex, symbol) { let maxSymbolIndex = -1; - let allSymbolIndex = {}; + let symbolIndices = {}; + let startLine = startIndex; + let labelAndKeywords = [ + "([\\w\\s]*:(\\s)*PROCESS)", + "([\\w\\s]*:(\\s)*POSTPONED PROCESS)", + "([\\w\\s]*:\\s*$)", + "([\\w\\s]*:.*\\s+GENERATE)" + ]; + let labelAndKeywordsStr = labelAndKeywords.join("|"); + let labelAndKeywordsRegex = new RegExp("(" + labelAndKeywordsStr + ")([^\\w]|$)"); for (let i = startIndex; i <= endIndex; i++) { let line = result[i].Line; - let regex = new RegExp("([\\s\\w]|^)" + symbol + "([\\s\\w]|$)"); + if (symbol == ":" && line.regexStartsWith(labelAndKeywordsRegex)) { + continue; + } + let regex = new RegExp("([\\s\\w\\\\]|^)" + symbol + "([\\s\\w\\\\]|$)"); + if (line.regexCount(regex) > 1) { + continue; + } let colonIndex = line.regexIndexOf(regex); if (colonIndex > 0) { maxSymbolIndex = Math.max(maxSymbolIndex, colonIndex); - allSymbolIndex[i] = colonIndex; + symbolIndices[i] = colonIndex; } + else if (!line.startsWith(ILCommentPrefix) && line.length != 0) { + if (startLine < i - 1) // if cannot find the symbol, a block of symbols ends + { + AlignSign(result, startLine, i - 1, symbol, maxSymbolIndex, symbolIndices); + } + maxSymbolIndex = -1; + symbolIndices = {}; + startLine = i; + } + } + if (startLine < endIndex) // if cannot find the symbol, a block of symbols ends + { + AlignSign(result, startLine, endIndex, symbol, maxSymbolIndex, symbolIndices); } +} +function AlignSign(result, startIndex, endIndex, symbol, maxSymbolIndex = -1, symbolIndices = {}) { if (maxSymbolIndex < 0) { return; } - for (let lineIndex in allSymbolIndex) { - let symbolIndex = allSymbolIndex[lineIndex]; + for (let lineIndex in symbolIndices) { + let symbolIndex = symbolIndices[lineIndex]; if (symbolIndex == maxSymbolIndex) { continue; } @@ -442,7 +487,7 @@ function SignAlignRegional(result, startIndex, endIndex, symbol) { + line.substring(symbolIndex); } } -exports.SignAlignRegional = SignAlignRegional; +exports.AlignSign = AlignSign; function beautifyCaseBlock(inputs, result, settings, startIndex, indent) { if (!inputs[startIndex].regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) { return startIndex; @@ -453,52 +498,185 @@ function beautifyCaseBlock(inputs, result, settings, startIndex, indent) { return i; } exports.beautifyCaseBlock = beautifyCaseBlock; +function getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex) { + let endIndex = 0; + let openBracketsCount = 0; + let closeBracketsCount = 0; + for (let i = startIndex; i < inputs.length; i++) { + let input = inputs[i]; + let indexOfSemicolon = input.indexOf(";"); + let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1; + let stringBeforeSemicolon = input.substring(0, splitIndex); + let stringAfterSemicolon = input.substring(splitIndex); + stringAfterSemicolon = stringAfterSemicolon.replace(new RegExp(ILCommentPrefix + "[0-9]+"), ""); + openBracketsCount += stringBeforeSemicolon.count("("); + closeBracketsCount += stringBeforeSemicolon.count(")"); + if (indexOfSemicolon < 0) { + continue; + } + if (openBracketsCount == closeBracketsCount) { + endIndex = i; + if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) { + inputs[i] = stringBeforeSemicolon; + inputs.splice(i, 0, stringAfterSemicolon); + parentEndIndex++; + } + break; + } + } + return [endIndex, parentEndIndex]; +} +function beautifyComponentBlock(inputs, result, settings, startIndex, parentEndIndex, indent) { + let endIndex = startIndex; + for (let i = startIndex; i < inputs.length; i++) { + if (inputs[i].regexStartsWith(/END(\s|$)/)) { + endIndex = i; + break; + } + } + result.push(new FormattedLine(inputs[startIndex], indent)); + if (endIndex != startIndex) { + let actualEndIndex = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex); + let incremental = actualEndIndex - endIndex; + endIndex += incremental; + parentEndIndex += incremental; + } + return [endIndex, parentEndIndex]; +} +exports.beautifyComponentBlock = beautifyComponentBlock; +function beautifySemicolonBlock(inputs, result, settings, startIndex, parentEndIndex, indent) { + let endIndex = startIndex; + [endIndex, parentEndIndex] = getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex); + result.push(new FormattedLine(inputs[startIndex], indent)); + if (endIndex != startIndex) { + let i = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex); + } + return [endIndex, parentEndIndex]; +} +exports.beautifySemicolonBlock = beautifySemicolonBlock; function beautify3(inputs, result, settings, startIndex, indent, endIndex) { let i; - let regexOneLineBlockKeyWords = new RegExp(/(PROCEDURE|FUNCTION|IMPURE FUNCTION)[^\w](?!.+[^\w]IS([^\w]|$))/); //match PROCEDURE..; but not PROCEDURE .. IS; - let blockMidKeyWords = ["ELSE", "ELSIF", "WHEN", "BEGIN"]; + let regexOneLineBlockKeyWords = new RegExp(/(PROCEDURE)[^\w](?!.+[^\w]IS([^\w]|$))/); //match PROCEDURE..; but not PROCEDURE .. IS; + let regexFunctionMultiLineBlockKeyWords = new RegExp(/(FUNCTION|IMPURE FUNCTION)[^\w](?=.+[^\w]IS([^\w]|$))/); //match FUNCTION .. IS; but not FUNCTION + let blockMidKeyWords = ["BEGIN"]; let blockStartsKeyWords = [ "IF", "CASE", "ARCHITECTURE", "PROCEDURE", "PACKAGE", - "PROCESS", - "POSTPONED PROCESS", - "([\\w\\s]+:\\s*PROCESS)", - "FUNCTION", - "IMPURE FUNCTION", - "(.+\\sPROTECTED)", - "COMPONENT", - "ENTITY" + "(([\\w\\s]*:)?(\\s)*PROCESS)", + "(([\\w\\s]*:)?(\\s)*POSTPONED PROCESS)", + "(.*\\s*PROTECTED)", + "(COMPONENT)", + "(ENTITY(?!.+;))", + "FOR", + "WHILE", + "LOOP", + "(.*\\s*GENERATE)", + "(CONTEXT[\\w\\s\\\\]+IS)", + "(CONFIGURATION(?!.+;))", + "BLOCK", + "UNITS", + "\\w+\\s+\\w+\\s+IS\\s+RECORD" + ]; + let blockEndsKeyWords = ["END", ".*\\)\\s*RETURN\\s+[\\w]+;"]; + let blockEndsWithSemicolon = [ + "(WITH\\s+[\\w\\s\\\\]+SELECT)", + "([\\w\\\\]+[\\s]*<=)", + "([\\w\\\\]+[\\s]*:=)", + "FOR\\s+[\\w\\s,]+:\\s*\\w+\\s+USE", + "REPORT" ]; - let blockEndsKeyWords = ["END"]; let newLineAfterKeyWordsStr = blockStartsKeyWords.join("|"); - let blockEndKeyWordsStr = blockEndsKeyWords.join("|"); - let blockMidKeyWordsStr = blockMidKeyWords.join("|"); - let regexBlockMidKeyWords = new RegExp("(" + blockMidKeyWordsStr + ")([^\\w]|$)"); - let regexBlockStartsKeywords = new RegExp("(" + newLineAfterKeyWordsStr + ")([^\\w]|$)"); - let regexBlockEndsKeyWords = new RegExp("(" + blockEndKeyWordsStr + ")([^\\w]|$)"); + let regexBlockMidKeyWords = blockMidKeyWords.convertToRegexBlockWords(); + let regexBlockStartsKeywords = new RegExp("([\\w]+\\s*:\\s*)?(" + newLineAfterKeyWordsStr + ")([^\\w]|$)"); + let regexBlockEndsKeyWords = blockEndsKeyWords.convertToRegexBlockWords(); + let regexblockEndsWithSemicolon = blockEndsWithSemicolon.convertToRegexBlockWords(); + let regexMidKeyWhen = "WHEN".convertToRegexBlockWords(); + let regexMidKeyElse = "ELSE|ELSIF".convertToRegexBlockWords(); if (endIndex == null) { endIndex = inputs.length - 1; } for (i = startIndex; i <= endIndex; i++) { + if (indent < 0) { + indent = 0; + } let input = inputs[i].trim(); + if (input.regexStartsWith(/COMPONENT\s/)) { + let modeCache = Mode; + Mode = FormatMode.EndsWithSemicolon; + [i, endIndex] = beautifyComponentBlock(inputs, result, settings, i, endIndex, indent); + Mode = modeCache; + continue; + } + if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) { + let modeCache = Mode; + Mode = FormatMode.EndsWithSemicolon; + [i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent); + Mode = modeCache; + continue; + } + if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) { + let modeCache = Mode; + Mode = FormatMode.EndsWithSemicolon; + [i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent); + Mode = modeCache; + continue; + } if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) { + let modeCache = Mode; + Mode = FormatMode.CaseWhen; i = beautifyCaseBlock(inputs, result, settings, i, indent); + Mode = modeCache; continue; } if (input.regexStartsWith(/[\w\s:]*PORT([\s]|$)/)) { - i = beautifyPortGenericBlock(inputs, result, settings, i, indent, "PORT"); + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PORT"); + continue; + } + if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IS"); continue; } if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) { - i = beautifyPortGenericBlock(inputs, result, settings, i, indent, "GENERIC"); + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "GENERIC"); + continue; + } + if (input.regexStartsWith(/[\w\s:]*PROCEDURE[\s\w]+\($/)) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PROCEDURE"); + if (inputs[i].regexStartsWith(/.*\)[\s]*IS/)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } + continue; + } + if (input.regexStartsWith(/FUNCTION[^\w]/) + && input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "FUNCTION"); + if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } + else { + result[i].Indent++; + } + continue; + } + if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/) + && input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IMPURE FUNCTION"); + if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } + else { + result[i].Indent++; + } continue; } result.push(new FormattedLine(input, indent)); if (startIndex != 0 - && (input.regexStartsWith(regexBlockMidKeyWords))) { + && (input.regexStartsWith(regexBlockMidKeyWords) + || (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse)) + || (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) { result[i].Indent--; } else if (startIndex != 0 @@ -509,7 +687,8 @@ function beautify3(inputs, result, settings, startIndex, indent, endIndex) { if (input.regexStartsWith(regexOneLineBlockKeyWords)) { continue; } - if (input.regexStartsWith(regexBlockStartsKeywords)) { + if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords) + || input.regexStartsWith(regexBlockStartsKeywords)) { i = beautify3(inputs, result, settings, i + 1, indent + 1); } } @@ -517,491 +696,6 @@ function beautify3(inputs, result, settings, startIndex, indent, endIndex) { return i; } exports.beautify3 = beautify3; -function beautify2(input, settings) { - let arr = input.split("\r\n"); - let quotes = EscapeQuotes(arr); - if (settings.RemoveAsserts) { - RemoveAsserts(arr); //RemoveAsserts must be after EscapeQuotes - } - ApplyNoNewLineAfter(arr, settings.NewLineSettings.noNewLineAfter); - var align = [], align_max = [], align_i1 = 0, align_i = 0; - var str = "", str1 = ""; - var p = 0; - var n = 0, j = 0; - var tab_n = 0, str_len = 0, port_s = ""; - var back_tab = false, forward_tab = false, semi_pos = 0, begin_b = true, port_b = false; - var before_begin = true; - var l = arr.length; - for (i = 0; i < l; i++) { - if (arr[i].indexOf("BEGIN") >= 0) { - before_begin = false; - } - if (port_s) { - port_s += arr[i]; - var k_port = port_s.split("(").length; - if (k_port == port_s.split(")").length) { - arr[i] = arr[i] + "@@end"; - port_s = ""; - port_b = false; - } - } - if ((!port_b && arr[i].regexIndexOf(/(\s|\(|^)(PORT|GENERIC|PROCESS|PROCEDURE)(\s|\(|$)/) >= 0) - || (arr[i].regexIndexOf(/:[ ]?=[ ]?\(/) >= 0 && before_begin)) { - port_b = true; - port_s = arr[i]; - var k_port = port_s.split("(").length; - if (k_port == 1) { - port_b = false; - port_s = ""; - } - else if (k_port == port_s.split(")").length) { - port_s = ""; - port_b = false; - arr[i] = arr[i] + "@@singleend"; - } - else { - arr[i] = arr[i].replace(/(PORT|GENERIC|PROCEDURE)([a-z0-9A-Z_ ]+)\(([a-zA-Z0-9_\(\) ]+)/, '$1$2(\r\n$3'); - } - } - } - input = arr.join("\r\n"); - input = input.replace(/([a-zA-Z0-9\); ])\);(@@comments[0-9]+)?@@end/g, '$1\r\n);$2@@end'); - input = input.replace(/[ ]?([&=:\-<>\+|\*])[ ]?/g, ' $1 '); - input = input.replace(/[ ]?([,])[ ]?/g, '$1 '); - input = input.replace(/[ ]?(['"])(THEN)/g, '$1 $2'); - input = input.replace(/[ ]?(\?)?[ ]?(<|:|>|\/)?[ ]+(=)?[ ]?/g, ' $1$2$3 '); - input = input.replace(/(IF)[ ]?([\(\)])/g, '$1 $2'); - input = input.replace(/([\(\)])[ ]?(THEN)/gi, '$1 $2'); - input = input.replace(/(^|[\(\)])[ ]?(AND|OR|XOR|XNOR)[ ]*([\(])/g, '$1 $2 $3'); - input = input.replace(/ ([\-\*\/=+<>])[ ]*([\-\*\/=+<>]) /g, " $1$2 "); - input = input.replace(/\r\n[ \t]+--\r\n/g, "\r\n"); - input = input.replace(/[ ]+/g, ' '); - input = input.replace(/\r\n\r\n\r\n/g, '\r\n'); - input = input.replace(/[\r\n\s]+$/g, ''); - input = input.replace(/[ \t]+\)/g, ')'); - var matches = input.match(/'([a-zA-Z]+)\s/g); - if (matches != null) { - for (var k2 = 0; k2 < matches.length; k2++) { - input = input.replace(matches[k2], matches[k2].toUpperCase()); - } - } - input = input.replace(/(MAP)[ \r\n]+\(/g, '$1('); - //input = input.replace(/(;|THEN)[ ]?(@@comments[0-9]+)([a-zA-Z])/g, '$1 $2\r\n$3'); - input = input.replace(/[\r\n ]+RETURN/g, ' RETURN'); - input = input.replace(/BEGIN[\r\n ]+/g, 'BEGIN\r\n'); - input = input.replace(/ (PORT|GENERIC) /g, '\r\n$1 '); - if (settings.CheckAlias) { - var alias = [], subarr = [], o = 0, p = 0, p2 = 0, l2 = 0, i2 = 0; - arr = input.split("ARCHITECTURE "); - l = arr.length; - for (i = 0; i < l; i++) { - subarr = arr[i].split("ALIAS "); - l2 = subarr.length; - if (l2 > 1) { - o = 0; - for (i2 = 1; i2 < l2; i2++) { - o = subarr[i2].indexOf(";", n); - str = subarr[i2].substring(0, o); - alias[p2++] = str.split(" IS "); - } - i2--; - var str2 = subarr[i2].substr(o); - for (p = 0; p < p2; p++) { - var reg = new RegExp(alias[p][1], 'gi'); - str2 = str2.replace(reg, alias[p][0]); - } - subarr[i2] = subarr[i2].substring(0, o) + str2; - } - arr[i] = subarr.join("ALIAS "); - } - input = arr.join("ARCHITECTURE "); - } - arr = input.split("\r\n"); - l = arr.length; - var signAlignPos = ""; - var if_b = 0, white_space = "", case_b = false, case_n = 0, procfun_b = false, semi_b = false, set_false = false, entity_b = false, then_b = false, conditional_b = false, generic_map_b = false, architecture_begin_b = false, process_begin_b = false, case_indent = [0, 0, 0, 0, 0, 0, 0]; - var align_groups = [], align_groups_max = [], lastAlignedSign = "", current_align_group = 0, aligned_group_starts = 0; - var indent_start = []; - for (i = 0; i < l; i++) { - str = arr[i]; - str_len = str.length; - if (str.replace(/[ \-\t]*/, "").length > 0) { - var first_word = str.split(/[^\w]/)[0]; - var indent_start_last = indent_start.length == 0 ? 0 : indent_start[indent_start.length - 1]; - if (then_b) { - arr[i] = " " + arr[i]; - if (str.indexOf(" THEN") >= 0) { - then_b = false; - back_tab = true; - } - } - arr[i] = white_space + arr[i]; - if (first_word == "ELSIF") { - tab_n = indent_start_last - 1; - indent_start.pop(); - back_tab = true; - } - else if (str.indexOf("END CASE") == 0) { - indent_start.pop(); - case_n--; - tab_n = indent_start[indent_start.length - 1]; - } - else if (first_word == "END") { - tab_n = indent_start_last - 1; - indent_start.pop(); - if (str.indexOf("END IF") == 0) { - if_b--; - } - if (i == l - 1) { - tab_n = 1; - } - } - else if (first_word == "ELSE" && if_b) { - tab_n = indent_start_last - 1; - indent_start.pop(); - back_tab = true; - } - else if (case_n) { - if (first_word == "WHEN") { - tab_n = case_indent[case_n - 1]; - //back_tab = true; - } - } - else if (first_word == "BEGIN") { - if (begin_b) { - if (architecture_begin_b) { - tab_n = indent_start_last - 1; - architecture_begin_b = false; - } - else if (process_begin_b) { - tab_n = indent_start_last - 1; - process_begin_b = false; - } - else { - tab_n = indent_start_last; - indent_start.push(tab_n + 1); - } - //indent_start.pop(); - back_tab = true; - begin_b = false; - if (procfun_b) { - tab_n++; - indent_start.push(tab_n); - begin_b = true; - } - } - else { - back_tab = true; - } - } - else if (first_word == "PROCESS") { - begin_b = true; - } - else if (str.indexOf(": PROCESS") >= 0) { - back_tab = true; - begin_b = true; - process_begin_b = true; - } - else if (str.indexOf(": ENTITY") >= 0) { - back_tab = true; - entity_b = true; - } - else if (str.indexOf("PROCEDURE ") >= 0) { - back_tab = true; - begin_b = true; - } - if (port_b && str.indexOf("@@") < 0) { - if (i + 1 <= arr.length - 1 && arr[i + 1].indexOf("@@") < 0) { - if (signAlignPos == ":") { - if (str.indexOf(';') < 0) { - arr[i] += arr[i + 1]; - arr[i + 1] = '@@removeline'; - } - } - else if (signAlignPos == "=>") { - if (str.indexOf(',') < 0) { - arr[i] += arr[i + 1]; - arr[i + 1] = '@@removeline'; - } - } - } - } - if (str.indexOf("PORT MAP") >= 0) { - back_tab = true; - port_b = true; - if (str.indexOf(");") < 0) { - align_i1 = align_i; - var t = str.indexOf("=>"); - if (t >= 0) { - signAlignPos = "=>"; - } - else { - if (i + 1 < arr.length) { - t = arr[i + 1].indexOf("=>"); - if (t >= 0) { - signAlignPos = "=>"; - } - } - } - } - else { - signAlignPos = ""; - } - } - else if (str.indexOf("GENERIC MAP") >= 0) { - tab_n++; - indent_start.push(tab_n); - generic_map_b = true; - if (!begin_b) { - back_tab = false; - } - } - else if (str.indexOf("PORT (") >= 0 && begin_b) { - back_tab = true; - port_b = true; - t = str.indexOf(":"); - if (str.indexOf(");") < 0) { - align_i1 = align_i; - if (t >= 0) { - signAlignPos = ":"; - } - else { - t = arr[i + 1].indexOf(":"); - if (t >= 0) { - signAlignPos = ":"; - } - } - } - else { - signAlignPos = ""; - } - } - if (set_false) { - procfun_b = false; - set_false = false; - } - if (str.indexOf("(") >= 0) { - if (str.indexOf("PROCEDURE") >= 0 || str.indexOf("FUNCTION") >= 0) { - procfun_b = true; - back_tab = true; - } - if ((str.indexOf("GENERIC") >= 0 || str.indexOf(":= (") >= 0 || str.regexIndexOf(/PROCEDURE[a-zA-Z0-9_ ]+\(/) >= 0) && begin_b) { - port_b = true; - back_tab = true; - } - } - else if (first_word == "FUNCTION") { - back_tab = true; - begin_b = true; - } - if (str.indexOf("@@singleend") >= 0) { - back_tab = false; - port_b = false; - if (!begin_b) { - forward_tab = true; - } - } - else if (str.indexOf("@@end") >= 0 && port_b) { - port_b = false; - indent_start.pop(); - tab_n = indent_start[indent_start.length - 1]; - if (entity_b) { - forward_tab = true; - } - if (generic_map_b) { - forward_tab = true; - generic_map_b = false; - } - } - if (settings.SignAlignAll) { - var alignedSigns = [":", "<=", "=>"]; - for (var currentSign = 0; currentSign < alignedSigns.length; currentSign++) { - if (str.indexOf(alignedSigns[currentSign]) > 0) { - var char_before_sign = str.split(alignedSigns[currentSign])[0]; - var char_before_sign_length = char_before_sign.length; - align_groups.push(char_before_sign_length); - align_groups_max.push(char_before_sign_length); - if (alignedSigns[currentSign] == lastAlignedSign) { - if (align_groups_max[current_align_group - 1] < char_before_sign_length) { - for (var k3 = aligned_group_starts; k3 <= current_align_group; k3++) { - align_groups_max[k3] = char_before_sign_length; - } - } - else { - align_groups_max[current_align_group] = align_groups_max[current_align_group - 1]; - } - } - else { - aligned_group_starts = current_align_group; - } - arr[i] = char_before_sign + "@@alignall" + (current_align_group++) + str.substring(char_before_sign.length, arr[i].length); - lastAlignedSign = alignedSigns[currentSign]; - break; - } - } - if (currentSign == alignedSigns.length) { - lastAlignedSign = ""; - } - } - else if (settings.SignAlignRegional) { - if (port_b && signAlignPos != "") { - if (str.indexOf(signAlignPos) >= 0) { - var a1 = arr[i].split(signAlignPos); - var l1 = a1[0].length; - if (align_i >= 0 && align_i > align_i1) { - align_max[align_i] = align_max[align_i - 1]; - } - else { - align_max[align_i] = l1; - } - if (align_i > align_i1 && align_max[align_i] < l1) { - for (var k3 = align_i1; k3 <= align_i; k3++) { - align_max[k3] = l1; - } - } - align[align_i] = l1; - arr[i] = a1[0] + "@@align" + (align_i++) + signAlignPos + arr[i].substring(l1 + signAlignPos.length, arr[i].length); - } - } - } - tab_n = tab_n < 1 ? 1 : tab_n; - if (str_len) { - if (isTesting) { - console.log(tab_n, arr[i], indent_start); - } - arr[i] = (Array(tab_n).join(settings.Indentation)) + arr[i]; //indent - if (settings.NewLineSettings.newLineAfter.indexOf("port")) { - if (str.indexOf('@@singleend') < 0) { - arr[i] = arr[i].replace(/(PORT)([ \r\n\w]*)\(/, "$1$2\r\n" + (Array(tab_n).join(settings.Indentation)) + "("); - } - } - if (settings.NewLineSettings.newLineAfter.indexOf("generic")) { - if (str.indexOf('@@singleend') < 0) { - arr[i] = arr[i].replace(/(GENERIC)([ \r\n\w]*)\(/, "$1$2\r\n" + (Array(tab_n).join(settings.Indentation)) + "("); - } - } - } - if (back_tab) { - tab_n++; - indent_start.push(tab_n); - back_tab = false; - } - if (forward_tab) { - tab_n = indent_start_last; - indent_start.pop(); - forward_tab = false; - } - if (conditional_b && str.indexOf(";") >= 0) { - conditional_b = false; - white_space = ""; - } - else if (str.indexOf(";") >= 0 && semi_b) { - semi_b = false; - tab_n = indent_start_last; - indent_start.pop(); - } - else if (!semi_b && str.indexOf(";") < 0 && !port_b) { - if (!conditional_b) { - if (str.indexOf("WHEN") > 3 && str.indexOf("<=") > 1) { - conditional_b = true; - white_space = (Array(str.indexOf("= ") + 3).join(" ")); - } - else if (first_word == "WHEN" && i + 1 < arr.length && arr[i + 1].indexOf("WHEN") < 0) { - tab_n = indent_start_last + 1; - } - else if (str.indexOf("=>") < 0 && ((str.indexOf(ILQuotesPrefix) >= 0 && str.indexOf("= " + ILQuotesPrefix) < 0 && str.indexOf("IF") < 0) || (str.indexOf("<=") > 0 && str.indexOf("IF") < 0 && str.indexOf("THEN") < 0))) { - tab_n++; - indent_start.push(tab_n); - semi_b = true; - } - } - } - if (first_word == "ENTITY") { - tab_n++; - indent_start.push(tab_n); - } - else if (",RECORD,PACKAGE,FOR,COMPONENT,CONFIGURATION,".indexOf("," + first_word + ",") >= 0) { - tab_n++; - indent_start.push(tab_n); - } - else if (str.indexOf(": FOR ") >= 0) { - tab_n++; - indent_start.push(tab_n); - } - else if (first_word == "CASE" || str.indexOf(": CASE") >= 0) { - tab_n++; - indent_start.push(tab_n); - case_indent[case_n] = tab_n; - case_n++; - } - else if (first_word == "ARCHITECTURE") { - tab_n++; - indent_start.push(tab_n); - begin_b = true; - architecture_begin_b = true; - } - else if (first_word == "IF") { - if_b++; - tab_n++; - indent_start.push(tab_n); - if (str.indexOf(" THEN") < 0) { - then_b = true; - tab_n = indent_start_last; - //indent_start.pop(); - } - } - if (procfun_b) { - if (str.regexIndexOf(/(\))|(RETURN [A-Za-z0-9 ]+)[\r\n ]+IS/) >= 0) { - tab_n = indent_start_last; - indent_start.pop(); - set_false = true; - } - } - } - } - input = arr.join("\r\n"); - input = input.replace(/[\t]*@@removeline\r\n/g, ''); - p = input.indexOf('PROCESS'); - while (p >= 0) { - let nextBracket = input.indexOf('(', p); - let nextNewLine = input.indexOf('\r\n', p); - let nextCloseBracket = input.indexOf(')', nextBracket); - if (nextBracket < nextNewLine && nextCloseBracket > nextNewLine) { - let processArray = input.substring(p, nextCloseBracket).split('\r\n'); - if (settings.Indentation.replace(/[ ]+/g, '').length == 0) { - for (var i = 1; i < processArray.length; i++) { - processArray[i] = (Array(nextBracket - p + 2).join(' ')) + processArray[i]; - } - } - else { - for (var i = 1; i < processArray.length; i++) { - processArray[i] = settings.Indentation + processArray[i]; - } - } - input = input.substring(0, p) + processArray.join('\r\n') + input.substring(nextCloseBracket, input.length); - p = input.regexIndexOf('PROCESS[ ]+\\(', nextCloseBracket); - } - else { - p = input.indexOf('PROCESS[ ]+\\(', p + 7); - } - } - input = SetKeywordCase(input, settings.KeywordCase, KeyWords, TypeNames); - if (settings.SignAlignAll) { - for (var k = 0; k < current_align_group; k++) { - input = input.replace("@@alignall" + k, Array((align_groups_max[k] - align_groups[k] + 1)).join(" ")); - } - } - if (settings.SignAlignRegional) { - for (var k = 0; k < align_i; k++) { - input = input.replace("@@align" + k, Array((align_max[k] - align[k] + 2)).join(" ")); - } - } - for (var k = 0; k < quotes.length; k++) { - input = input.replace(ILQuotesPrefix + k, quotes[k]); - } - input = input.replace(/@@singleline[ \r\n]*/, " "); - return input; -} function ReserveSemicolonInKeywords(arr) { for (let i = 0; i < arr.length; i++) { if (arr[i].match(/FUNCTION|PROCEDURE/) != null) { @@ -1062,6 +756,20 @@ function EscapeQuotes(arr) { } return quotes; } +function EscapeSingleQuotes(arr) { + let quotes = []; + let quotesIndex = 0; + for (let i = 0; i < arr.length; i++) { + let quote = arr[i].match(/'[^']'/g); + if (quote != null) { + for (var j = 0; j < quote.length; j++) { + arr[i] = arr[i].replace(quote[j], ILSingleQuotesPrefix + quotesIndex); + quotes[quotesIndex++] = quote[j]; + } + } + } + return quotes; +} function RemoveExtraNewLines(input) { input = input.replace(/(?:\r\n|\r|\n)/g, '\r\n'); input = input.replace(/ \r\n/g, '\r\n'); diff --git a/VHDLFormatter.ts b/VHDLFormatter.ts index 0c18286..39fb11a 100644 --- a/VHDLFormatter.ts +++ b/VHDLFormatter.ts @@ -1,6 +1,17 @@ let isTesting = false; const ILCommentPrefix = "@@comments"; const ILQuotesPrefix = "@@quotes"; +const ILSingleQuotesPrefix = "@@singlequotes"; + +enum FormatMode { + Default, + EndsWithSemicolon, + CaseWhen, + IfElse, + PortGeneric, +} + +let Mode: FormatMode = FormatMode.Default; export class NewLineSettings { newLineAfter: Array; @@ -20,10 +31,10 @@ export class NewLineSettings { push(keyword: string, addNewLine: string) { let str = addNewLine.toLowerCase(); - if (str.indexOf("none") >= 0) { + if (str == "none") { return; } - else if (str.indexOf("no") < 0) { + else if (!str.startsWith("no")) { this.newLineAfterPush(keyword); } else { @@ -40,19 +51,6 @@ function ConstructNewLineSettings(dict): NewLineSettings { return settings; } -function fetchHeader(url, wch) { - try { - var req = new XMLHttpRequest(); - req.open("HEAD", url, false); - req.send(null); - if (req.status == 200) { - return req.getResponseHeader(wch); - } - else return false; - } catch (e) { - return ""; - } -} declare global { interface String { @@ -61,9 +59,21 @@ declare global { reverse: () => string; regexStartsWith: (pattern: RegExp) => boolean; count: (text: string) => number; + regexCount: (pattern: RegExp) => number; + convertToRegexBlockWords: () => RegExp; + } + interface Array{ + convertToRegexBlockWords: () => RegExp; } } +String.prototype.regexCount = function (pattern): number { + if (pattern.flags.indexOf("g") < 0) { + pattern = new RegExp(pattern.source, pattern.flags + "g"); + } + return (this.match(pattern) || []).length; +} + String.prototype.count = function (text): number { return this.split(text).length - 1; } @@ -89,6 +99,17 @@ String.prototype.reverse = function () { return this.split('').reverse().join(''); } +String.prototype.convertToRegexBlockWords = function (): RegExp { + let result: RegExp = new RegExp("(" + this + ")([^\\w]|$)"); + return result; +} + +Array.prototype.convertToRegexBlockWords = function (): RegExp { + let wordsStr: string = this.join("|"); + let result: RegExp = new RegExp("(" + wordsStr + ")([^\\w]|$)"); + return result; +} + function wordWrap() { var d = document.getElementById("result"); if (d.className == "") { @@ -98,76 +119,49 @@ function wordWrap() { } } -function getHTMLInputElement(name: string): HTMLInputElement { - return document.getElementById(name); +function getHTMLInputElement(id: string): HTMLInputElement { + return document.getElementById(id); } function noFormat() { - let elements: Array = ["remove_comments", + let elements: Array = [ + "remove_comments", "remove_lines", "remove_report", "check_alias", - "sign_align", + "sign_align_in", + "sign_align_port", + "sign_align_generic", + "sign_align_function", + "sign_align_procedure", "sign_align_all", - "new_line_after_port", - "new_line", + "new_line_after", "use_space", + "customise_indentation", "compress", - "mix_letter"]; - var t = !(getHTMLInputElement("remove_comments").disabled); + "mix_letter" + ]; + var isDisabled = getHTMLInputElement("no_format").checked; elements.forEach(element => { - getHTMLInputElement(element).disabled = t; - }); - let keyword = document.getElementById("keyword"); - for (let i = 0; i < keyword.elements.length; i++) { - (keyword.elements[i]).disabled = t; - } -} - -function indent_decode() { - var custom_indent: string = getHTMLInputElement("cust_indent").value; - var result: string = indentDecode(custom_indent); - document.getElementById("indent_s").innerHTML = result; -} - -export function indentDecode(input: string): string { - input = input.replace(/\\t/g, " "); - var count = [" & one ", " & two ", " & three ", " & four ", " & five ", " & six ", " & seven ", " & eight ", " & many "]; - var tokens: Array = input.split(""); - var result = ""; - var repeatedCharCount = 0; - for (var i = 0; i < tokens.length; i++) { - var char = input.substr(i, 1); - if (char == input.substr(i + 1, 1)) { - repeatedCharCount++; - } else { - switch (char) { - case " ": - char = "blankspace"; - break; - case "\t": - char = "tab"; - } - repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; - result += count[repeatedCharCount] + char; - repeatedCharCount = 0; + var htmlElement = getHTMLInputElement(element + "_div"); + try { + getHTMLInputElement(element).disabled = isDisabled; } - } - - if (result.length < 0) { - switch (char) { - case " ": - char = "blankspace"; - break; - case "\t": - char = "tab"; + catch{ } + if (isDisabled) { + htmlElement.className += " disabled"; + } + else { + htmlElement.className = htmlElement.className.replace(/\bdisabled\b/g, ""); + } + }); + let radioButtons = >document.getElementsByTagName("input"); + for (let i = 0; i < radioButtons.length; i++) { + if ((radioButtons[i]).type == "radio") { + (radioButtons[i]).disabled = isDisabled; } - repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; - result = count[repeatedCharCount] + char; } - - result = result.replace(/^ & /, "") - return result; + getHTMLInputElement("cust_indent").disabled = isDisabled; } function Compress(input: string) { @@ -192,7 +186,7 @@ function MixLetters(input: string) { function EscapeComments(arr: Array, comments: Array, commentIndex: number): number { for (var i = 0; i < arr.length; i++) { let line: string = arr[i]; - var firstCharIndex = line.regexIndexOf(/[a-zA-Z0-9\(\&\)%_\+'"|]/); + var firstCharIndex = line.regexIndexOf(/[a-zA-Z0-9\(\&\)%_\+'"|\\]/); var commentStartIndex = line.indexOf("--"); if (firstCharIndex < commentStartIndex && firstCharIndex >= 0) { comments.push(line.substr(commentStartIndex)); @@ -214,6 +208,12 @@ function ToLowerCases(arr: Array) { } } +function ToUpperCases(arr: Array) { + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].toUpperCase(); + } +} + function ToCamelCases(arr: Array) { for (var i = 0; i < arr.length; i++) { arr[i] = arr[i].charAt(0) + arr[i].slice(1).toLowerCase(); @@ -227,19 +227,24 @@ function ReplaceKeyWords(text: string, keywords: Array): string { return text; } -function SetKeywordCase(input: string, keywordcase: string, keywords, typenames) { +function SetKeywordCase(input: string, keywordcase: string, keywords: string[], typenames: string[]): string { let inputcase: string = keywordcase.toLowerCase(); - if (inputcase == "lowercase") { - ToLowerCases(keywords); - ToLowerCases(typenames); - } else if (inputcase == "defaultcase") { - ToCamelCases(keywords); - ToCamelCases(typenames); - } - if (inputcase != "uppercase") { - input = ReplaceKeyWords(input, keywords); - input = ReplaceKeyWords(input, typenames); - } + switch (keywordcase.toLowerCase()) { + case "lowercase": + ToLowerCases(keywords); + ToLowerCases(typenames); + break; + case "defaultcase": + ToCamelCases(keywords); + ToCamelCases(typenames); + break; + case "uppercase": + ToUpperCases(keywords); + ToUpperCases(typenames); + } + + input = ReplaceKeyWords(input, keywords); + input = ReplaceKeyWords(input, typenames); return input; } @@ -251,6 +256,9 @@ export function SetNewLinesAfterSymbols(text: string, newLineSettings: NewLineSe newLineSettings.newLineAfter.forEach(symbol => { let regex: RegExp = new RegExp("(" + symbol.toUpperCase() + ")[ ]?([^ \r\n@])", "g"); text = text.replace(regex, '$1\r\n$2'); + if (symbol.toUpperCase() == "PORT") { + text = text.replace(/PORT\s+MAP/, "PORT MAP"); + } }); } if (newLineSettings.noNewLineAfter != null) { @@ -268,6 +276,7 @@ export class BeautifierSettings { CheckAlias: boolean; SignAlignRegional: boolean; SignAlignAll: boolean; + SignAlignKeyWords: Array; KeywordCase: string; Indentation: string; NewLineSettings: NewLineSettings @@ -308,23 +317,26 @@ export function beautify(input: string, settings: BeautifierSettings) { input = input.replace(/\([\t ]+/g, '\('); input = input.replace(/[ ]+;/g, ';'); input = input.replace(/:[ ]*(PROCESS|ENTITY)/gi, ':$1'); - input = ReplaceKeyWords(input, KeyWords); - input = ReplaceKeyWords(input, TypeNames); arr = input.split("\r\n"); - ReserveSemicolonInKeywords(arr); + let quotes = EscapeQuotes(arr); + let singleQuotes = EscapeSingleQuotes(arr); input = arr.join("\r\n"); - input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); - input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); + input = SetKeywordCase(input, "uppercase", KeyWords, TypeNames); + arr = input.split("\r\n"); - let quotes = EscapeQuotes(arr); if (settings.RemoveAsserts) { RemoveAsserts(arr);//RemoveAsserts must be after EscapeQuotes } + ReserveSemicolonInKeywords(arr); + input = arr.join("\r\n"); + input = input.replace(/(PORT|GENERIC)\s+MAP/g, '$1 MAP'); + input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); + input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); + arr = input.split("\r\n"); ApplyNoNewLineAfter(arr, settings.NewLineSettings.noNewLineAfter); input = arr.join("\r\n"); - //input = beautify2(input, settings); //new input = input.replace(/([a-zA-Z0-9\); ])\);(@@comments[0-9]+)?@@end/g, '$1\r\n);$2@@end'); @@ -342,16 +354,26 @@ export function beautify(input: string, settings: BeautifierSettings) { input = input.replace(/\r\n\r\n\r\n/g, '\r\n'); input = input.replace(/[\r\n\s]+$/g, ''); input = input.replace(/[ \t]+\)/g, ')'); + input = input.replace(/\s*\)\s+RETURN\s+([\w]+;)/g, '\r\n) RETURN $1');//function(..\r\n)return type; -> function(..\r\n)return type; arr = input.split("\r\n"); let result: (FormattedLine | FormattedLine[])[] = []; beautify3(arr, result, settings, 0, 0); + if (settings.SignAlignAll) { + AlignSigns(result, 0, result.length - 1); + } + arr = FormattedLineToString(result, settings.Indentation); input = arr.join("\r\n"); + input = SetKeywordCase(input, settings.KeywordCase, KeyWords, TypeNames); for (var k = 0; k < quotes.length; k++) { input = input.replace(ILQuotesPrefix + k, quotes[k]); } + for (var k = 0; k < singleQuotes.length; k++) { + input = input.replace(ILSingleQuotesPrefix + k, singleQuotes[k]); + } + for (var k = 0; k < commentsIndex; k++) { input = input.replace(ILCommentPrefix + k, comments[k]); } @@ -406,16 +428,16 @@ function GetCloseparentheseEndIndex(inputs: Array, startIndex: number): return startIndex; } -export function beautifyPortGenericBlock(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number, mode: string): number { +export function beautifyPortGenericBlock(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, parentEndIndex: number, indent: number, mode: string): [number, number] { let firstLine: string = inputs[startIndex]; let regex: RegExp = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)"); if (!firstLine.regexStartsWith(regex)) { - return startIndex; + return [startIndex, parentEndIndex]; } let firstLineHasParenthese: boolean = firstLine.indexOf("(") >= 0; let hasParenthese: boolean = firstLineHasParenthese; let blockBodyStartIndex = startIndex; - let secondLineHasParenthese: boolean = inputs[startIndex + 1].startsWith("("); + let secondLineHasParenthese: boolean = startIndex + 1 < inputs.length && inputs[startIndex + 1].startsWith("("); if (secondLineHasParenthese) { hasParenthese = true; blockBodyStartIndex++; @@ -428,15 +450,17 @@ export function beautifyPortGenericBlock(inputs: Array, result: (Formatt inputs[startIndex] = newInputs[0]; inputs.splice(startIndex + 1, 0, newInputs[1]); endIndex++; + parentEndIndex++; } } - else if (endIndex != startIndex && secondLineHasParenthese) { + else if (endIndex > startIndex + 1 && secondLineHasParenthese) { inputs[startIndex + 1] = inputs[startIndex + 1].replace(/\(([\w\(\) ]+)/, '(\r\n$1'); let newInputs = inputs[startIndex + 1].split("\r\n"); if (newInputs.length == 2) { inputs[startIndex + 1] = newInputs[0]; inputs.splice(startIndex + 2, 0, newInputs[1]); endIndex++; + parentEndIndex++; } } if (firstLineHasParenthese && inputs[startIndex].indexOf("MAP") > 0) { @@ -444,7 +468,11 @@ export function beautifyPortGenericBlock(inputs: Array, result: (Formatt } result.push(new FormattedLine(inputs[startIndex], indent)); if (secondLineHasParenthese) { - result.push(new FormattedLine(inputs[startIndex + 1], indent)); + let secondLineIndent = indent; + if (endIndex == startIndex + 1) { + secondLineIndent++; + } + result.push(new FormattedLine(inputs[startIndex + 1], secondLineIndent)); } let blockBodyEndIndex = endIndex; let i = beautify3(inputs, result, settings, blockBodyStartIndex + 1, indent + 1, endIndex); @@ -452,38 +480,72 @@ export function beautifyPortGenericBlock(inputs: Array, result: (Formatt (result[i]).Indent--; blockBodyEndIndex--; } - if (settings.SignAlignRegional) { + if (settings.SignAlignRegional && !settings.SignAlignAll + && settings.SignAlignKeyWords != null + && settings.SignAlignKeyWords.indexOf(mode) >= 0) { blockBodyStartIndex++; - SignsAlignRegional(result, blockBodyStartIndex, blockBodyEndIndex); + AlignSigns(result, blockBodyStartIndex, blockBodyEndIndex); } - return i; + return [i, parentEndIndex]; } -export function SignsAlignRegional(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number) { - SignAlignRegional(result, startIndex, endIndex, ":"); - SignAlignRegional(result, startIndex, endIndex, ":="); - SignAlignRegional(result, startIndex, endIndex, "=>"); +export function AlignSigns(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number) { + AlignSign_(result, startIndex, endIndex, ":"); + AlignSign_(result, startIndex, endIndex, ":="); + AlignSign_(result, startIndex, endIndex, "=>"); + AlignSign_(result, startIndex, endIndex, "<="); } -export function SignAlignRegional(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number, symbol: string) { +function AlignSign_(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number, symbol: string) { let maxSymbolIndex: number = -1; - let allSymbolIndex = {}; + let symbolIndices = {}; + let startLine = startIndex; + let labelAndKeywords: Array = [ + "([\\w\\s]*:(\\s)*PROCESS)", + "([\\w\\s]*:(\\s)*POSTPONED PROCESS)", + "([\\w\\s]*:\\s*$)", + "([\\w\\s]*:.*\\s+GENERATE)" + ]; + let labelAndKeywordsStr: string = labelAndKeywords.join("|"); + let labelAndKeywordsRegex = new RegExp("(" + labelAndKeywordsStr + ")([^\\w]|$)"); for (let i = startIndex; i <= endIndex; i++) { let line = (result[i]).Line; - let regex: RegExp = new RegExp("([\\s\\w]|^)" + symbol + "([\\s\\w]|$)"); + if (symbol == ":" && line.regexStartsWith(labelAndKeywordsRegex)) { + continue; + } + + let regex: RegExp = new RegExp("([\\s\\w\\\\]|^)" + symbol + "([\\s\\w\\\\]|$)"); + if (line.regexCount(regex) > 1) { + continue; + } let colonIndex = line.regexIndexOf(regex); if (colonIndex > 0) { maxSymbolIndex = Math.max(maxSymbolIndex, colonIndex); - allSymbolIndex[i] = colonIndex; + symbolIndices[i] = colonIndex; } + else if (!line.startsWith(ILCommentPrefix) && line.length != 0) { + if (startLine < i - 1) // if cannot find the symbol, a block of symbols ends + { + AlignSign(result, startLine, i - 1, symbol, maxSymbolIndex, symbolIndices); + } + maxSymbolIndex = -1; + symbolIndices = {}; + startLine = i; + } + } + if (startLine < endIndex) // if cannot find the symbol, a block of symbols ends + { + AlignSign(result, startLine, endIndex, symbol, maxSymbolIndex, symbolIndices); } +} +export function AlignSign(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number, symbol: string, maxSymbolIndex: number = -1, symbolIndices = {}) { if (maxSymbolIndex < 0) { return; } - for (let lineIndex in allSymbolIndex) { - let symbolIndex = allSymbolIndex[lineIndex]; + for (let lineIndex in symbolIndices) { + let symbolIndex = symbolIndices[lineIndex]; if (symbolIndex == maxSymbolIndex) { continue; } @@ -505,52 +567,186 @@ export function beautifyCaseBlock(inputs: Array, result: (FormattedLine return i; } +function getSemicolonBlockEndIndex(inputs: Array, settings: BeautifierSettings, startIndex: number, parentEndIndex: number): [number, number] { + let endIndex = 0; + let openBracketsCount = 0; + let closeBracketsCount = 0; + for (let i = startIndex; i < inputs.length; i++) { + let input = inputs[i]; + let indexOfSemicolon = input.indexOf(";"); + let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1; + let stringBeforeSemicolon = input.substring(0, splitIndex); + let stringAfterSemicolon = input.substring(splitIndex); + stringAfterSemicolon = stringAfterSemicolon.replace(new RegExp(ILCommentPrefix + "[0-9]+"), ""); + openBracketsCount += stringBeforeSemicolon.count("("); + closeBracketsCount += stringBeforeSemicolon.count(")"); + if (indexOfSemicolon < 0) { + continue; + } + if (openBracketsCount == closeBracketsCount) { + endIndex = i; + if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) { + inputs[i] = stringBeforeSemicolon; + inputs.splice(i, 0, stringAfterSemicolon); + parentEndIndex++; + } + break; + } + } + return [endIndex, parentEndIndex]; +} + +export function beautifyComponentBlock(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, parentEndIndex: number, indent: number): [number, number] { + let endIndex = startIndex; + for (let i = startIndex; i < inputs.length; i++) { + if (inputs[i].regexStartsWith(/END(\s|$)/)) { + endIndex = i; + break; + } + } + result.push(new FormattedLine(inputs[startIndex], indent)); + if (endIndex != startIndex) { + let actualEndIndex = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex); + let incremental = actualEndIndex - endIndex; + endIndex += incremental; + parentEndIndex += incremental; + } + + return [endIndex, parentEndIndex]; +} + +export function beautifySemicolonBlock(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, parentEndIndex: number, indent: number): [number, number] { + let endIndex = startIndex; + [endIndex, parentEndIndex] = getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex); + result.push(new FormattedLine(inputs[startIndex], indent)); + if (endIndex != startIndex) { + let i = beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex); + } + + return [endIndex, parentEndIndex]; +} + export function beautify3(inputs: Array, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number, endIndex?: number): number { let i: number; - let regexOneLineBlockKeyWords: RegExp = new RegExp(/(PROCEDURE|FUNCTION|IMPURE FUNCTION)[^\w](?!.+[^\w]IS([^\w]|$))/);//match PROCEDURE..; but not PROCEDURE .. IS; - let blockMidKeyWords: Array = ["ELSE", "ELSIF", "WHEN", "BEGIN"]; + let regexOneLineBlockKeyWords: RegExp = new RegExp(/(PROCEDURE)[^\w](?!.+[^\w]IS([^\w]|$))/);//match PROCEDURE..; but not PROCEDURE .. IS; + let regexFunctionMultiLineBlockKeyWords: RegExp = new RegExp(/(FUNCTION|IMPURE FUNCTION)[^\w](?=.+[^\w]IS([^\w]|$))/);//match FUNCTION .. IS; but not FUNCTION + let blockMidKeyWords: Array = ["BEGIN"]; let blockStartsKeyWords: Array = [ "IF", "CASE", "ARCHITECTURE", "PROCEDURE", "PACKAGE", - "PROCESS", - "POSTPONED PROCESS", - "([\\w\\s]+:\\s*PROCESS)", - "FUNCTION", - "IMPURE FUNCTION", - "(.+\\sPROTECTED)", - "COMPONENT", - "ENTITY"]; - let blockEndsKeyWords: Array = ["END"]; + "(([\\w\\s]*:)?(\\s)*PROCESS)",// with label + "(([\\w\\s]*:)?(\\s)*POSTPONED PROCESS)",// with label + "(.*\\s*PROTECTED)", + "(COMPONENT)", + "(ENTITY(?!.+;))", + "FOR", + "WHILE", + "LOOP", + "(.*\\s*GENERATE)", + "(CONTEXT[\\w\\s\\\\]+IS)", + "(CONFIGURATION(?!.+;))", + "BLOCK", + "UNITS", + "\\w+\\s+\\w+\\s+IS\\s+RECORD"]; + let blockEndsKeyWords: Array = ["END", ".*\\)\\s*RETURN\\s+[\\w]+;"]; + let blockEndsWithSemicolon: Array = [ + "(WITH\\s+[\\w\\s\\\\]+SELECT)", + "([\\w\\\\]+[\\s]*<=)", + "([\\w\\\\]+[\\s]*:=)", + "FOR\\s+[\\w\\s,]+:\\s*\\w+\\s+USE", + "REPORT" + ]; let newLineAfterKeyWordsStr: string = blockStartsKeyWords.join("|"); - let blockEndKeyWordsStr: string = blockEndsKeyWords.join("|"); - let blockMidKeyWordsStr: string = blockMidKeyWords.join("|"); - let regexBlockMidKeyWords: RegExp = new RegExp("(" + blockMidKeyWordsStr + ")([^\\w]|$)") - let regexBlockStartsKeywords: RegExp = new RegExp("(" + newLineAfterKeyWordsStr + ")([^\\w]|$)") - let regexBlockEndsKeyWords: RegExp = new RegExp("(" + blockEndKeyWordsStr + ")([^\\w]|$)") + let regexBlockMidKeyWords: RegExp = blockMidKeyWords.convertToRegexBlockWords(); + let regexBlockStartsKeywords: RegExp = new RegExp("([\\w]+\\s*:\\s*)?(" + newLineAfterKeyWordsStr + ")([^\\w]|$)") + let regexBlockEndsKeyWords: RegExp = blockEndsKeyWords.convertToRegexBlockWords() + let regexblockEndsWithSemicolon: RegExp = blockEndsWithSemicolon.convertToRegexBlockWords(); + let regexMidKeyWhen: RegExp = "WHEN".convertToRegexBlockWords(); + let regexMidKeyElse: RegExp = "ELSE|ELSIF".convertToRegexBlockWords(); if (endIndex == null) { endIndex = inputs.length - 1; } for (i = startIndex; i <= endIndex; i++) { + if (indent < 0) { + indent = 0; + } let input: string = inputs[i].trim(); + if (input.regexStartsWith(/COMPONENT\s/)) { + let modeCache = Mode; + Mode = FormatMode.EndsWithSemicolon; + [i, endIndex] = beautifyComponentBlock(inputs, result, settings, i, endIndex, indent); + Mode = modeCache; + continue; + } + if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) { + let modeCache = Mode; + Mode = FormatMode.EndsWithSemicolon; + [i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent); + Mode = modeCache; + continue; + } + if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) { + let modeCache = Mode; + Mode = FormatMode.EndsWithSemicolon; + [i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent); + Mode = modeCache; + continue; + } if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) { + let modeCache = Mode; + Mode = FormatMode.CaseWhen; i = beautifyCaseBlock(inputs, result, settings, i, indent); + Mode = modeCache; continue; } if (input.regexStartsWith(/[\w\s:]*PORT([\s]|$)/)) { - i = beautifyPortGenericBlock(inputs, result, settings, i, indent, "PORT"); + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PORT"); + continue; + } + if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IS"); continue; } if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) { - i = beautifyPortGenericBlock(inputs, result, settings, i, indent, "GENERIC"); + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "GENERIC"); + continue; + } + if (input.regexStartsWith(/[\w\s:]*PROCEDURE[\s\w]+\($/)) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PROCEDURE"); + if (inputs[i].regexStartsWith(/.*\)[\s]*IS/)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } + continue; + } + if (input.regexStartsWith(/FUNCTION[^\w]/) + && input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "FUNCTION"); + if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } else { + (result[i]).Indent++; + } + continue; + } + if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/) + && input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { + [i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IMPURE FUNCTION"); + if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) { + i = beautify3(inputs, result, settings, i + 1, indent + 1); + } else { + (result[i]).Indent++; + } continue; } result.push(new FormattedLine(input, indent)); if (startIndex != 0 - && (input.regexStartsWith(regexBlockMidKeyWords))) { + && (input.regexStartsWith(regexBlockMidKeyWords) + || (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse)) + || (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) { (result[i]).Indent--; } else if (startIndex != 0 @@ -561,7 +757,8 @@ export function beautify3(inputs: Array, result: (FormattedLine | Format if (input.regexStartsWith(regexOneLineBlockKeyWords)) { continue; } - if (input.regexStartsWith(regexBlockStartsKeywords)) { + if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords) + || input.regexStartsWith(regexBlockStartsKeywords)) { i = beautify3(inputs, result, settings, i + 1, indent + 1); } } @@ -569,503 +766,6 @@ export function beautify3(inputs: Array, result: (FormattedLine | Format return i; } -function beautify2(input, settings: BeautifierSettings): string { - let arr = input.split("\r\n"); - let quotes = EscapeQuotes(arr); - if (settings.RemoveAsserts) { - RemoveAsserts(arr);//RemoveAsserts must be after EscapeQuotes - } - - ApplyNoNewLineAfter(arr, settings.NewLineSettings.noNewLineAfter); - - var align = [], - align_max = [], - align_i1 = 0, - align_i = 0; - var str = "", - str1 = ""; - var p = 0; - var n = 0, - j = 0; - var tab_n = 0, - str_len = 0, - port_s = ""; - var back_tab = false, - forward_tab = false, - semi_pos = 0, - begin_b = true, - port_b = false; - var before_begin = true; - var l = arr.length; - - for (i = 0; i < l; i++) { - if (arr[i].indexOf("BEGIN") >= 0) { - before_begin = false; - } - - if (port_s) { - port_s += arr[i]; - var k_port = port_s.split("(").length; - if (k_port == port_s.split(")").length) { - arr[i] = arr[i] + "@@end"; - port_s = ""; - port_b = false; - } - } - if ((!port_b && arr[i].regexIndexOf(/(\s|\(|^)(PORT|GENERIC|PROCESS|PROCEDURE)(\s|\(|$)/) >= 0) - || (arr[i].regexIndexOf(/:[ ]?=[ ]?\(/) >= 0 && before_begin)) { - port_b = true; - port_s = arr[i]; - var k_port = port_s.split("(").length; - if (k_port == 1) { - port_b = false; - port_s = ""; - } else if (k_port == port_s.split(")").length) { - port_s = ""; - port_b = false; - arr[i] = arr[i] + "@@singleend"; - } else { - arr[i] = arr[i].replace(/(PORT|GENERIC|PROCEDURE)([a-z0-9A-Z_ ]+)\(([a-zA-Z0-9_\(\) ]+)/, '$1$2(\r\n$3'); - } - } - } - input = arr.join("\r\n"); - input = input.replace(/([a-zA-Z0-9\); ])\);(@@comments[0-9]+)?@@end/g, '$1\r\n);$2@@end'); - input = input.replace(/[ ]?([&=:\-<>\+|\*])[ ]?/g, ' $1 '); - input = input.replace(/[ ]?([,])[ ]?/g, '$1 '); - input = input.replace(/[ ]?(['"])(THEN)/g, '$1 $2'); - input = input.replace(/[ ]?(\?)?[ ]?(<|:|>|\/)?[ ]+(=)?[ ]?/g, ' $1$2$3 '); - input = input.replace(/(IF)[ ]?([\(\)])/g, '$1 $2'); - input = input.replace(/([\(\)])[ ]?(THEN)/gi, '$1 $2'); - input = input.replace(/(^|[\(\)])[ ]?(AND|OR|XOR|XNOR)[ ]*([\(])/g, '$1 $2 $3'); - input = input.replace(/ ([\-\*\/=+<>])[ ]*([\-\*\/=+<>]) /g, " $1$2 "); - input = input.replace(/\r\n[ \t]+--\r\n/g, "\r\n"); - input = input.replace(/[ ]+/g, ' '); - input = input.replace(/\r\n\r\n\r\n/g, '\r\n'); - input = input.replace(/[\r\n\s]+$/g, ''); - input = input.replace(/[ \t]+\)/g, ')'); - - var matches = input.match(/'([a-zA-Z]+)\s/g); - if (matches != null) { - for (var k2 = 0; k2 < matches.length; k2++) { - input = input.replace(matches[k2], matches[k2].toUpperCase()); - } - } - input = input.replace(/(MAP)[ \r\n]+\(/g, '$1('); - //input = input.replace(/(;|THEN)[ ]?(@@comments[0-9]+)([a-zA-Z])/g, '$1 $2\r\n$3'); - input = input.replace(/[\r\n ]+RETURN/g, ' RETURN'); - input = input.replace(/BEGIN[\r\n ]+/g, 'BEGIN\r\n'); - input = input.replace(/ (PORT|GENERIC) /g, '\r\n$1 '); - if (settings.CheckAlias) { - var alias = [], - subarr = [], - o = 0, - p = 0, - p2 = 0, - l2 = 0, - i2 = 0; - arr = input.split("ARCHITECTURE "); - l = arr.length; - for (i = 0; i < l; i++) { - subarr = arr[i].split("ALIAS "); - l2 = subarr.length; - if (l2 > 1) { - o = 0; - for (i2 = 1; i2 < l2; i2++) { - o = subarr[i2].indexOf(";", n); - str = subarr[i2].substring(0, o); - alias[p2++] = str.split(" IS "); - } - i2--; - var str2 = subarr[i2].substr(o); - for (p = 0; p < p2; p++) { - var reg = new RegExp(alias[p][1], 'gi'); - str2 = str2.replace(reg, alias[p][0]); - } - subarr[i2] = subarr[i2].substring(0, o) + str2; - } - arr[i] = subarr.join("ALIAS "); - } - input = arr.join("ARCHITECTURE "); - } - arr = input.split("\r\n"); - l = arr.length; - var signAlignPos = ""; - var if_b = 0, - white_space = "", - case_b = false, - case_n = 0, - procfun_b = false, - semi_b = false, - set_false = false, - entity_b = false, - then_b = false, - conditional_b = false, - generic_map_b = false, - architecture_begin_b = false, - process_begin_b = false, - case_indent = [0, 0, 0, 0, 0, 0, 0]; - var align_groups = [], - align_groups_max = [], - lastAlignedSign = "", - current_align_group = 0, - aligned_group_starts = 0; - var indent_start = []; - for (i = 0; i < l; i++) { - str = arr[i]; - str_len = str.length; - if (str.replace(/[ \-\t]*/, "").length > 0) { - var first_word = str.split(/[^\w]/)[0]; - var indent_start_last = indent_start.length == 0 ? 0 : indent_start[indent_start.length - 1]; - if (then_b) { - arr[i] = " " + arr[i]; - if (str.indexOf(" THEN") >= 0) { - then_b = false; - back_tab = true; - } - } - arr[i] = white_space + arr[i]; - if (first_word == "ELSIF") { - tab_n = indent_start_last - 1; - indent_start.pop(); - back_tab = true; - } else if (str.indexOf("END CASE") == 0) { - indent_start.pop(); - case_n--; - tab_n = indent_start[indent_start.length - 1]; - } else if (first_word == "END") { - tab_n = indent_start_last - 1; - indent_start.pop(); - if (str.indexOf("END IF") == 0) { - if_b--; - } - if (i == l - 1) { - tab_n = 1; - } - } else if (first_word == "ELSE" && if_b) { - tab_n = indent_start_last - 1; - indent_start.pop(); - back_tab = true; - } else if (case_n) { - if (first_word == "WHEN") { - tab_n = case_indent[case_n - 1]; - //back_tab = true; - } - } else if (first_word == "BEGIN") { - if (begin_b) { - if (architecture_begin_b) { - tab_n = indent_start_last - 1; - architecture_begin_b = false; - } else if (process_begin_b) { - tab_n = indent_start_last - 1; - process_begin_b = false; - } else { - tab_n = indent_start_last; - indent_start.push(tab_n + 1); - } - //indent_start.pop(); - back_tab = true; - begin_b = false; - if (procfun_b) { - tab_n++; - indent_start.push(tab_n); - begin_b = true; - } - } else { - back_tab = true; - } - } else if (first_word == "PROCESS") { - begin_b = true; - } else if (str.indexOf(": PROCESS") >= 0) { - back_tab = true; - begin_b = true; - process_begin_b = true; - } else if (str.indexOf(": ENTITY") >= 0) { - back_tab = true; - entity_b = true; - } else if (str.indexOf("PROCEDURE ") >= 0) { - back_tab = true; - begin_b = true; - } - if (port_b && str.indexOf("@@") < 0) { - if (i + 1 <= arr.length - 1 && arr[i + 1].indexOf("@@") < 0) { - if (signAlignPos == ":") { - if (str.indexOf(';') < 0) { - arr[i] += arr[i + 1]; - arr[i + 1] = '@@removeline'; - } - } else if (signAlignPos == "=>") { - if (str.indexOf(',') < 0) { - arr[i] += arr[i + 1]; - arr[i + 1] = '@@removeline'; - } - } - } - } - if (str.indexOf("PORT MAP") >= 0) { - back_tab = true; - port_b = true; - if (str.indexOf(");") < 0) { - align_i1 = align_i; - var t = str.indexOf("=>"); - if (t >= 0) { - signAlignPos = "=>"; - } else { - if (i + 1 < arr.length) { - t = arr[i + 1].indexOf("=>"); - if (t >= 0) { - signAlignPos = "=>"; - } - } - } - } else { - signAlignPos = ""; - } - } else if (str.indexOf("GENERIC MAP") >= 0) { - tab_n++; - indent_start.push(tab_n); - generic_map_b = true; - if (!begin_b) { - back_tab = false; - } - } else if (str.indexOf("PORT (") >= 0 && begin_b) { - back_tab = true; - port_b = true; - t = str.indexOf(":"); - if (str.indexOf(");") < 0) { - align_i1 = align_i; - if (t >= 0) { - signAlignPos = ":"; - } else { - t = arr[i + 1].indexOf(":"); - if (t >= 0) { - signAlignPos = ":"; - } - } - } else { - signAlignPos = ""; - } - } - if (set_false) { - procfun_b = false; - set_false = false; - } - if (str.indexOf("(") >= 0) { - if (str.indexOf("PROCEDURE") >= 0 || str.indexOf("FUNCTION") >= 0) { - procfun_b = true; - back_tab = true; - } - if ((str.indexOf("GENERIC") >= 0 || str.indexOf(":= (") >= 0 || str.regexIndexOf(/PROCEDURE[a-zA-Z0-9_ ]+\(/) >= 0) && begin_b) { - port_b = true; - back_tab = true; - } - } else if (first_word == "FUNCTION") { - back_tab = true; - begin_b = true; - } - if (str.indexOf("@@singleend") >= 0) { - back_tab = false; - port_b = false; - if (!begin_b) { - forward_tab = true; - } - } else if (str.indexOf("@@end") >= 0 && port_b) { - port_b = false; - indent_start.pop(); - tab_n = indent_start[indent_start.length - 1]; - if (entity_b) { - forward_tab = true; - } - if (generic_map_b) { - forward_tab = true; - generic_map_b = false; - } - } - if (settings.SignAlignAll) { - var alignedSigns = [":", "<=", "=>"]; - for (var currentSign = 0; currentSign < alignedSigns.length; currentSign++) { - if (str.indexOf(alignedSigns[currentSign]) > 0) { - var char_before_sign = str.split(alignedSigns[currentSign])[0]; - var char_before_sign_length = char_before_sign.length; - align_groups.push(char_before_sign_length); - align_groups_max.push(char_before_sign_length); - if (alignedSigns[currentSign] == lastAlignedSign) { - if (align_groups_max[current_align_group - 1] < char_before_sign_length) { - for (var k3 = aligned_group_starts; k3 <= current_align_group; k3++) { - align_groups_max[k3] = char_before_sign_length; - } - } else { - align_groups_max[current_align_group] = align_groups_max[current_align_group - 1]; - } - } else { - aligned_group_starts = current_align_group; - } - arr[i] = char_before_sign + "@@alignall" + (current_align_group++) + str.substring(char_before_sign.length, arr[i].length); - lastAlignedSign = alignedSigns[currentSign]; - break; - } - } - if (currentSign == alignedSigns.length) { - lastAlignedSign = ""; - } - } else if (settings.SignAlignRegional) { - if (port_b && signAlignPos != "") { - if (str.indexOf(signAlignPos) >= 0) { - var a1 = arr[i].split(signAlignPos); - var l1 = a1[0].length; - if (align_i >= 0 && align_i > align_i1) { - align_max[align_i] = align_max[align_i - 1]; - } else { - align_max[align_i] = l1; - } - if (align_i > align_i1 && align_max[align_i] < l1) { - for (var k3 = align_i1; k3 <= align_i; k3++) { - align_max[k3] = l1; - } - } - align[align_i] = l1; - arr[i] = a1[0] + "@@align" + (align_i++) + signAlignPos + arr[i].substring(l1 + signAlignPos.length, arr[i].length); - } - } - } - tab_n = tab_n < 1 ? 1 : tab_n; - if (str_len) { - if (isTesting) { - console.log(tab_n, arr[i], indent_start); - } - arr[i] = (Array(tab_n).join(settings.Indentation)) + arr[i]; //indent - if (settings.NewLineSettings.newLineAfter.indexOf("port")) { - if (str.indexOf('@@singleend') < 0) { - arr[i] = arr[i].replace(/(PORT)([ \r\n\w]*)\(/, "$1$2\r\n" + (Array(tab_n).join(settings.Indentation)) + "("); - } - } - if (settings.NewLineSettings.newLineAfter.indexOf("generic")) { - if (str.indexOf('@@singleend') < 0) { - arr[i] = arr[i].replace(/(GENERIC)([ \r\n\w]*)\(/, "$1$2\r\n" + (Array(tab_n).join(settings.Indentation)) + "("); - } - } - } - if (back_tab) { - tab_n++; - indent_start.push(tab_n); - back_tab = false; - } - if (forward_tab) { - tab_n = indent_start_last; - indent_start.pop(); - forward_tab = false; - } - - if (conditional_b && str.indexOf(";") >= 0) { - conditional_b = false; - white_space = ""; - } else if (str.indexOf(";") >= 0 && semi_b) { - semi_b = false; - tab_n = indent_start_last; - indent_start.pop(); - } else if (!semi_b && str.indexOf(";") < 0 && !port_b) { - if (!conditional_b) { - if (str.indexOf("WHEN") > 3 && str.indexOf("<=") > 1) { - conditional_b = true; - white_space = (Array(str.indexOf("= ") + 3).join(" ")); - } else if (first_word == "WHEN" && i + 1 < arr.length && arr[i + 1].indexOf("WHEN") < 0) { - tab_n = indent_start_last + 1; - } else if (str.indexOf("=>") < 0 && ((str.indexOf(ILQuotesPrefix) >= 0 && str.indexOf("= " + ILQuotesPrefix) < 0 && str.indexOf("IF") < 0) || (str.indexOf("<=") > 0 && str.indexOf("IF") < 0 && str.indexOf("THEN") < 0))) { - tab_n++; - indent_start.push(tab_n); - semi_b = true; - } - } - } - - if (first_word == "ENTITY") { - tab_n++; - indent_start.push(tab_n); - } else if (",RECORD,PACKAGE,FOR,COMPONENT,CONFIGURATION,".indexOf("," + first_word + ",") >= 0) { - tab_n++; - indent_start.push(tab_n); - } else if (str.indexOf(": FOR ") >= 0) { - tab_n++; - indent_start.push(tab_n); - } else if (first_word == "CASE" || str.indexOf(": CASE") >= 0) { - tab_n++; - indent_start.push(tab_n); - case_indent[case_n] = tab_n; - case_n++; - } else if (first_word == "ARCHITECTURE") { - tab_n++; - indent_start.push(tab_n); - begin_b = true; - architecture_begin_b = true; - } else if (first_word == "IF") { - if_b++; - tab_n++; - indent_start.push(tab_n); - if (str.indexOf(" THEN") < 0) { - then_b = true; - tab_n = indent_start_last; - //indent_start.pop(); - } - } - if (procfun_b) { - if (str.regexIndexOf(/(\))|(RETURN [A-Za-z0-9 ]+)[\r\n ]+IS/) >= 0) { - tab_n = indent_start_last; - indent_start.pop(); - set_false = true; - } - } - } - } - - input = arr.join("\r\n"); - input = input.replace(/[\t]*@@removeline\r\n/g, ''); - - p = input.indexOf('PROCESS'); - while (p >= 0) { - let nextBracket = input.indexOf('(', p); - let nextNewLine = input.indexOf('\r\n', p); - let nextCloseBracket = input.indexOf(')', nextBracket); - if (nextBracket < nextNewLine && nextCloseBracket > nextNewLine) { - let processArray = input.substring(p, nextCloseBracket).split('\r\n'); - if (settings.Indentation.replace(/[ ]+/g, '').length == 0) { - for (var i = 1; i < processArray.length; i++) { - processArray[i] = (Array(nextBracket - p + 2).join(' ')) + processArray[i]; - } - } else { - for (var i = 1; i < processArray.length; i++) { - processArray[i] = settings.Indentation + processArray[i]; - } - } - input = input.substring(0, p) + processArray.join('\r\n') + input.substring(nextCloseBracket, input.length); - p = input.regexIndexOf('PROCESS[ ]+\\(', nextCloseBracket); - } else { - p = input.indexOf('PROCESS[ ]+\\(', p + 7); - } - } - - input = SetKeywordCase(input, settings.KeywordCase, KeyWords, TypeNames); - - if (settings.SignAlignAll) { - for (var k = 0; k < current_align_group; k++) { - input = input.replace("@@alignall" + k, Array((align_groups_max[k] - align_groups[k] + 1)).join(" ")); - } - } - - if (settings.SignAlignRegional) { - for (var k = 0; k < align_i; k++) { - input = input.replace("@@align" + k, Array((align_max[k] - align[k] + 2)).join(" ")); - } - } - - for (var k = 0; k < quotes.length; k++) { - input = input.replace(ILQuotesPrefix + k, quotes[k]); - } - - input = input.replace(/@@singleline[ \r\n]*/, " "); - return input; -} - - function ReserveSemicolonInKeywords(arr: Array) { for (let i = 0; i < arr.length; i++) { if (arr[i].match(/FUNCTION|PROCEDURE/) != null) { @@ -1128,6 +828,21 @@ function EscapeQuotes(arr: Array): Array { return quotes; } +function EscapeSingleQuotes(arr: Array): Array { + let quotes: Array = []; + let quotesIndex = 0; + for (let i = 0; i < arr.length; i++) { + let quote = arr[i].match(/'[^']'/g); + if (quote != null) { + for (var j = 0; j < quote.length; j++) { + arr[i] = arr[i].replace(quote[j], ILSingleQuotesPrefix + quotesIndex); + quotes[quotesIndex++] = quote[j]; + } + } + } + return quotes; +} + function RemoveExtraNewLines(input: any) { input = input.replace(/(?:\r\n|\r|\n)/g, '\r\n'); input = input.replace(/ \r\n/g, '\r\n'); diff --git a/VHDLFormatterUnitTests.js b/VHDLFormatterUnitTests.js deleted file mode 100644 index 1e582a2..0000000 --- a/VHDLFormatterUnitTests.js +++ /dev/null @@ -1,739 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const VHDLFormatter_1 = require("./VHDLFormatter"); -const VHDLFormatter_2 = require("./VHDLFormatter"); -const VHDLFormatter_3 = require("./VHDLFormatter"); -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"); -const VHDLFormatter_10 = require("./VHDLFormatter"); -let testCount = 0; -var showUnitTests = true; //window.location.href.indexOf("http") < 0; -if (showUnitTests) { - testCount = 0; - UnitTest(); - UnitTestIndentDecode(); - UnitTestRemoveAsserts(); - UnitTestApplyNoNewLineAfter(); - UnitTestSetNewLinesAfterSymbols(); - UnitTestFormattedLineToString(); - UnitTestbeautify3(); - console.log("total tests: " + testCount); -} -function UnitTestFormattedLineToString() { - console.log("=== FormattedLineToString ==="); - FormattedLineToStringCase1(); - FormattedLineToStringCase2(); -} -function FormattedLineToStringCase1() { - let inputs = [ - new VHDLFormatter_9.FormattedLine("a;", 0), - new VHDLFormatter_9.FormattedLine("b;", 0) - ]; - let expected = ["a;", "b;"]; - UnitTest7(VHDLFormatter_10.FormattedLineToString, "General", " ", inputs, expected); -} -function FormattedLineToStringCase2() { - let inputs = [ - new VHDLFormatter_9.FormattedLine("a;", 1), - new VHDLFormatter_9.FormattedLine("b;", 2) - ]; - let expected = [" a;", " b;"]; - UnitTest7(VHDLFormatter_10.FormattedLineToString, "General", " ", inputs, expected); -} -function UnitTestbeautify3() { - console.log("=== beautify3 ==="); - Beautify3Case1(); - Beautify3Case2(); - Beautify3Case3(); - Beautify3Case4(); - Beautify3Case5(); - Beautify3Case6(); - Beautify3Case7(); - Beautify3Case8(); - Beautify3Case9(); - Beautify3Case10(); - Beautify3Case11(); - Beautify3Case12(); - Beautify3Case13(); - Beautify3Case14(); -} -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 Beautify3Case7() { - 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 = [ - "ARCHITECTURE a OF one IS", - "SIGNAL x : INTEGER;", - "BEGIN", - "-- architecture", - "END ARCHITECTURE;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("ARCHITECTURE a OF one IS", 0), - new VHDLFormatter_9.FormattedLine("SIGNAL x : INTEGER;", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 0), - new VHDLFormatter_9.FormattedLine("-- architecture", 1), - new VHDLFormatter_9.FormattedLine("END ARCHITECTURE;", 0), - ]; - UnitTest6(VHDLFormatter_8.beautify3, "architecture", settings, inputs, expected, 0, 4, 0); -} -function Beautify3Case8() { - 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 = [ - "ARCHITECTURE a OF one IS", - "SIGNAL x : INTEGER;", - "BEGIN", - "-- architecture", - "END ARCHITECTURE;", - "ARCHITECTURE b OF one IS", - "SIGNAL x : INTEGER;", - "BEGIN", - "-- architecture", - "END ARCHITECTURE;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("ARCHITECTURE a OF one IS", 0), - new VHDLFormatter_9.FormattedLine("SIGNAL x : INTEGER;", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 0), - new VHDLFormatter_9.FormattedLine("-- architecture", 1), - new VHDLFormatter_9.FormattedLine("END ARCHITECTURE;", 0), - new VHDLFormatter_9.FormattedLine("ARCHITECTURE b OF one IS", 0), - new VHDLFormatter_9.FormattedLine("SIGNAL x : INTEGER;", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 0), - new VHDLFormatter_9.FormattedLine("-- architecture", 1), - new VHDLFormatter_9.FormattedLine("END ARCHITECTURE;", 0), - ]; - UnitTest6(VHDLFormatter_8.beautify3, "architecture 2", settings, inputs, expected, 0, 9, 0); -} -function Beautify3Case9() { - 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 = [ - "PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", - "VARIABLE i : INTEGER;", - "BEGIN", - "y := x + 1;", - "END PROCEDURE;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", 0), - new VHDLFormatter_9.FormattedLine("VARIABLE i : INTEGER;", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 0), - new VHDLFormatter_9.FormattedLine("y := x + 1;", 1), - new VHDLFormatter_9.FormattedLine("END PROCEDURE;", 0) - ]; - UnitTest6(VHDLFormatter_8.beautify3, "procedure", settings, inputs, expected, 0, 4, 0); -} -function Beautify3Case10() { - 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 = [ - "PACKAGE three IS", - "SIGNAL s : INTEGER;", - "ALIAS sa IS s;", - "END PACKAGE;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("PACKAGE three IS", 0), - new VHDLFormatter_9.FormattedLine("SIGNAL s : INTEGER;", 1), - new VHDLFormatter_9.FormattedLine("ALIAS sa IS s;", 1), - new VHDLFormatter_9.FormattedLine("END PACKAGE;", 0) - ]; - UnitTest6(VHDLFormatter_8.beautify3, "package", settings, inputs, expected, 0, 3, 0); -} -function Beautify3Case11() { - 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 = [ - "PACKAGE p IS", - "PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER);", - "END PACKAGE;", - "PACKAGE BODY p IS", - "PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", - "VARIABLE i : INTEGER;", - "BEGIN", - "y := x + 1;", - "END PROCEDURE;", - "PROCEDURE bar(FILE x : text);", - "PROCEDURE baz IS", - "TYPE foo;", - "ALIAS x IS y;", - "BEGIN", - "END PROCEDURE;", - "PROCEDURE tralala IS", - "USE work.foo;", - "BEGIN", - "END PROCEDURE;", - "END PACKAGE BODY;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("PACKAGE p IS", 0), - new VHDLFormatter_9.FormattedLine("PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER);", 1), - new VHDLFormatter_9.FormattedLine("END PACKAGE;", 0), - new VHDLFormatter_9.FormattedLine("PACKAGE BODY p IS", 0), - new VHDLFormatter_9.FormattedLine("PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", 1), - new VHDLFormatter_9.FormattedLine("VARIABLE i : INTEGER;", 2), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("y := x + 1;", 2), - new VHDLFormatter_9.FormattedLine("END PROCEDURE;", 1), - new VHDLFormatter_9.FormattedLine("PROCEDURE bar(FILE x : text);", 1), - new VHDLFormatter_9.FormattedLine("PROCEDURE baz IS", 1), - new VHDLFormatter_9.FormattedLine("TYPE foo;", 2), - new VHDLFormatter_9.FormattedLine("ALIAS x IS y;", 2), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("END PROCEDURE;", 1), - new VHDLFormatter_9.FormattedLine("PROCEDURE tralala IS", 1), - new VHDLFormatter_9.FormattedLine("USE work.foo;", 2), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("END PROCEDURE;", 1), - new VHDLFormatter_9.FormattedLine("END PACKAGE BODY;", 0) - ]; - UnitTest6(VHDLFormatter_8.beautify3, "package procedure", settings, inputs, expected, 0, expected.length - 1, 0); -} -function Beautify3Case12() { - 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 = [ - "ARCHITECTURE a OF b IS", - "SIGNAL x : INTEGER := 0;", - "BEGIN", - "p: PROCESS IS", - "BEGIN", - "END PROCESS;", - "PROCESS", - "VARIABLE y : INTEGER := 5;", - "BEGIN", - "x <= y;", - "END PROCESS;", - "PROCESS (x) IS", - "BEGIN", - "x <= x + 1;", - "END PROCESS;", - "POSTPONED PROCESS IS", - "BEGIN", - "END PROCESS;", - "POSTPONED assert x = 1;", - "END ARCHITECTURE;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("ARCHITECTURE a OF b IS", 0), - new VHDLFormatter_9.FormattedLine("SIGNAL x : INTEGER := 0;", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 0), - new VHDLFormatter_9.FormattedLine("p: PROCESS IS", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("END PROCESS;", 1), - new VHDLFormatter_9.FormattedLine("PROCESS", 1), - new VHDLFormatter_9.FormattedLine("VARIABLE y : INTEGER := 5;", 2), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("x <= y;", 2), - new VHDLFormatter_9.FormattedLine("END PROCESS;", 1), - new VHDLFormatter_9.FormattedLine("PROCESS (x) IS", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("x <= x + 1;", 2), - new VHDLFormatter_9.FormattedLine("END PROCESS;", 1), - new VHDLFormatter_9.FormattedLine("POSTPONED PROCESS IS", 1), - new VHDLFormatter_9.FormattedLine("BEGIN", 1), - new VHDLFormatter_9.FormattedLine("END PROCESS;", 1), - new VHDLFormatter_9.FormattedLine("POSTPONED assert x = 1;", 1), - new VHDLFormatter_9.FormattedLine("END ARCHITECTURE;", 0) - ]; - UnitTest6(VHDLFormatter_8.beautify3, "package postponed procedure", settings, inputs, expected, 0, expected.length - 1, 0); -} -function Beautify3Case13() { - 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 = [ - "TYPE SharedCounter IS PROTECTED", - "PROCEDURE increment (N : INTEGER := 1);", - "IMPURE FUNCTION value RETURN INTEGER;", - "END PROTECTED SharedCounter;" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("TYPE SharedCounter IS PROTECTED", 0), - new VHDLFormatter_9.FormattedLine("PROCEDURE increment (N : INTEGER := 1);", 1), - new VHDLFormatter_9.FormattedLine("IMPURE FUNCTION value RETURN INTEGER;", 1), - new VHDLFormatter_9.FormattedLine("END PROTECTED SharedCounter;", 0) - ]; - UnitTest6(VHDLFormatter_8.beautify3, "type projected", settings, inputs, expected, 0, expected.length - 1, 0); -} -function Beautify3Case14() { - 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 = [ - "PACKAGE p IS", - "TYPE SharedCounter IS PROTECTED", - "PROCEDURE increment (N : INTEGER := 1);", - "IMPURE FUNCTION value RETURN INTEGER;", - "END PROTECTED SharedCounter;", - "TYPE SharedCounter IS PROTECTED BODY" - ]; - let expected = [ - new VHDLFormatter_9.FormattedLine("PACKAGE p IS", 0), - new VHDLFormatter_9.FormattedLine("TYPE SharedCounter IS PROTECTED", 1), - new VHDLFormatter_9.FormattedLine("PROCEDURE increment (N : INTEGER := 1);", 2), - new VHDLFormatter_9.FormattedLine("IMPURE FUNCTION value RETURN INTEGER;", 2), - new VHDLFormatter_9.FormattedLine("END PROTECTED SharedCounter;", 1), - new VHDLFormatter_9.FormattedLine("TYPE SharedCounter IS PROTECTED BODY", 1) - ]; - UnitTest6(VHDLFormatter_8.beautify3, "type projected", settings, inputs, expected, 0, expected.length - 1, 0); -} -function UnitTestSetNewLinesAfterSymbols() { - console.log("=== SetNewLinesAfterSymbols ==="); - let input = "a; @@comments1\r\nb;"; - let expected = "a; @@comments1\r\nb;"; - let parameters = new VHDLFormatter_3.NewLineSettings(); - parameters.newLineAfter = ["then", ";"]; - parameters.noNewLineAfter = ["port", "generic"]; - UnitTest5(VHDLFormatter_7.SetNewLinesAfterSymbols, "no new line after comment", parameters, input, expected); - input = "a; b;"; - expected = "a;\r\nb;"; - UnitTest5(VHDLFormatter_7.SetNewLinesAfterSymbols, "new line after ;", parameters, input, expected); -} -function UnitTestApplyNoNewLineAfter() { - console.log("=== ApplyNoNewLineAfter ==="); - let input = ["a;", "b;"]; - let expected = ["a;@@singleline", "b;@@singleline"]; - let parameters = [";"]; - UnitTest4(VHDLFormatter_6.ApplyNoNewLineAfter, "one blankspace", parameters, input, expected); - input = ["a;", "b THEN", "c"]; - expected = ["a;@@singleline", "b THEN@@singleline", "c"]; - parameters = [";", "then"]; - UnitTest4(VHDLFormatter_6.ApplyNoNewLineAfter, "one blankspace", parameters, input, expected); -} -function UnitTestRemoveAsserts() { - console.log("=== RemoveAsserts ==="); - let input = ["ASSERT a;"]; - let expected = [""]; - UnitTest3(VHDLFormatter_5.RemoveAsserts, "one assert", input, expected); - input = ["ASSERT a", "b;", "c"]; - expected = ["", "", "c"]; - UnitTest3(VHDLFormatter_5.RemoveAsserts, "multiline assert", input, expected); -} -function UnitTestIndentDecode() { - console.log("=== IndentDecode ==="); - UnitTest2(VHDLFormatter_2.indentDecode, "one blankspace", " ", "one blankspace"); - UnitTest2(VHDLFormatter_2.indentDecode, "mixed chars", " A ", "one blankspace & one A & one blankspace"); - UnitTest2(VHDLFormatter_2.indentDecode, "4 blankspaces", " ", "four blankspace"); - UnitTest2(VHDLFormatter_2.indentDecode, "9 blankspaces", " ", "many blankspace"); -} -function compareFormattedLines(expected, actual, message) { - 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) { - let compareResult = compareFormattedLine((expected[i]), (actual[i]), message, false); - if (compareResult.length > 0) { - result += "index " + i + "\n" + compareResult; - } - } - else { - result += "index " + i + "\nexpected FormatLine[], actual FormattedLine. actual:" + (actual[i]).Line; - } - } - else { - if (expected[i] instanceof VHDLFormatter_9.FormattedLine) { - result += "index " + i + "\nexpected FormatLine, actual FormattedLine[]. expected:" + (expected[i]).Line; - } - else { - let compareResult = compareFormattedLines((actual[i]), (expected[i]), message); - if (compareResult.length > 0) { - result += "index " + i + "\n" + compareResult; - } - } - } - } - 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]; - } - } - return result; -} -function assertFormattedLines(testName, expected, actual, message) { - let result = compareFormattedLines(expected, actual, message); - if (result.length > 0) { - console.log(testName + " failed:\n" + result); - } - testCount++; -} -function compareFormattedLine(expected, actual, message, cumulateTestCount) { - let result = ""; - if (expected.Indent != actual.Indent) { - result += 'indents are not equal;\nexpected: "' + expected.Line + '", ' + expected.Indent - + ';\nactual: "' + actual.Line + '", ' + actual.Indent + "\n"; - } - let compareResult = CompareString(actual.Line, expected.Line); - if (compareResult != true) { - result += compareResult; - } - return result; -} -function assert(testName, expected, actual, message) { - var result = CompareString(actual, expected); - if (result != true) { - console.log(testName + " failed: \n" + result); - } - else { - //console.log(testName + " pass"); - } - testCount++; -} -function assertArray(testName, expected, actual, message) { - var result = CompareArray(actual, expected); - if (result != true) { - console.log(testName + " failed: " + result); - } - else { - //console.log(testName + " pass"); - } - testCount++; -} -function UnitTest7(func, testName, indentation, inputs, expected) { - let actual = func(inputs, indentation); - assertArray(testName, expected, actual); -} -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); -} -function UnitTest4(func, testName, parameters, inputs, expected) { - let actual = JSON.parse(JSON.stringify(inputs)); - func(actual, parameters); - assertArray(testName, expected, actual); -} -function UnitTest3(func, testName, inputs, expected) { - let actual = JSON.parse(JSON.stringify(inputs)); - func(actual); - assertArray(testName, expected, actual); -} -function UnitTest2(func, testName, inputs, expected) { - let actual = func(inputs); - assert(testName, expected, actual); -} -function deepCopy(objectToCopy) { - return (JSON.parse(JSON.stringify(objectToCopy))); -} -function UnitTest() { - 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 input = "architecture TB of TB_CPU is\r\n component CPU_IF\r\n port -- port list\r\n end component;\r\n signal CPU_DATA_VALID: std_ulogic;\r\n signal CLK, RESET: std_ulogic := '0';\r\n constant PERIOD : time := 10 ns;\r\n constant MAX_SIM: time := 50 * PERIOD;\r\n begin\r\n -- concurrent statements\r\n end TB;"; - let expected = "ARCHITECTURE TB OF TB_CPU IS\r\n COMPONENT CPU_IF\r\n PORT -- port list\r\n END COMPONENT;\r\n SIGNAL CPU_DATA_VALID : std_ulogic;\r\n SIGNAL CLK, RESET : std_ulogic := '0';\r\n CONSTANT PERIOD : TIME := 10 ns;\r\n CONSTANT MAX_SIM : TIME := 50 * PERIOD;\r\nBEGIN\r\n -- concurrent statements\r\nEND TB;"; - let actual = VHDLFormatter_1.beautify(input, settings); - assert("General", expected, actual); - IntegrationTest2(); - let new_line_after_symbols_2 = new VHDLFormatter_3.NewLineSettings(); - new_line_after_symbols_2.newLineAfter = []; - new_line_after_symbols_2.noNewLineAfter = ["then", ";", "generic", "port"]; - let newSettings = deepCopy(settings); - newSettings.NewLineSettings = new_line_after_symbols_2; - expected = "a; b; c;"; - input = "a; \r\nb;\r\n c;"; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("Remove line after ;", expected, actual); - newSettings = deepCopy(settings); - newSettings.RemoveAsserts = true; - input = "architecture arch of ent is\r\nbegin\r\n assert False report sdfjcsdfcsdj;\r\n assert False report sdfjcsdfcsdj severity note;\r\nend architecture;"; - expected = "ARCHITECTURE arch OF ent IS\r\nBEGIN\r\nEND ARCHITECTURE;"; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("Remove asserts", expected, actual); - input = "entity TB_DISPLAY is\r\n-- port declarations\r\nend TB_DISPLAY;\r\n\r\narchitecture TEST of TB_DISPLAY is\r\n-- signal declarations\r\nbegin\r\n-- component instance(s)\r\nend TEST;"; - expected = "ENTITY TB_DISPLAY IS\r\n -- port declarations\r\nEND TB_DISPLAY;\r\n\r\nARCHITECTURE TEST OF TB_DISPLAY IS\r\n -- signal declarations\r\nBEGIN\r\n -- component instance(s)\r\nEND TEST;"; - actual = VHDLFormatter_1.beautify(input, settings); - assert("ENTITY ARCHITECTURE", expected, actual); - IntegrationTest5(); - IntegrationTest6(); - IntegrationTest7(); - input = 'if a(3 downto 0) > "0100" then\r\na(3 downto 0) := a(3 downto 0) + "0011" ;\r\nend if ;'; - expected = 'IF a(3 DOWNTO 0) > "0100" THEN\r\n a(3 DOWNTO 0) := a(3 DOWNTO 0) + "0011";\r\nEND IF;'; - actual = VHDLFormatter_1.beautify(input, settings); - assert("IF END IF case 1", expected, actual); - input = "if s = '1' then\r\no <= \"010\";\r\nelse\r\no <= \"101\";\r\nend if;"; - expected = "IF s = '1' THEN\r\n o <= \"010\";\r\nELSE\r\n o <= \"101\";\r\nEND IF;"; - actual = VHDLFormatter_1.beautify(input, settings); - assert("IF ELSE END IF case 1", expected, actual); - newSettings = deepCopy(settings); - newSettings.NewLineSettings.newLineAfter.push("ELSE"); - input = "IF (s = r) THEN rr := '0'; ELSE rr := '1'; END IF;"; - expected = "IF (s = r) THEN\r\n rr := '0';\r\nELSE\r\n rr := '1';\r\nEND IF;"; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("IF ELSE END IF case 2", expected, actual); - input = 'P1:process\r\nvariable x: Integer range 1 to 3;\r\nvariable y: BIT_VECTOR (0 to 1);\r\nbegin\r\n C1: case x is\r\n when 1 => Out_1 <= 0;\r\n when 2 => Out_1 <= 1;\r\n end case C1;\r\n C2: case y is\r\n when "00" => Out_2 <= 0;\r\n when "01" => Out_2 <= 1;\r\n end case C2;\r\nend process;'; - expected = 'P1 : PROCESS\r\n VARIABLE x : INTEGER RANGE 1 TO 3;\r\n VARIABLE y : BIT_VECTOR (0 TO 1);\r\nBEGIN\r\n C1 : CASE x IS\r\n WHEN 1 => Out_1 <= 0;\r\n WHEN 2 => Out_1 <= 1;\r\n END CASE C1;\r\n C2 : CASE y IS\r\n WHEN "00" => Out_2 <= 0;\r\n WHEN "01" => Out_2 <= 1;\r\n END CASE C2;\r\nEND PROCESS;'; - actual = VHDLFormatter_1.beautify(input, settings); - assert("WHEN CASE", expected, actual); - input = "case READ_CPU_STATE is\r\n when WAITING =>\r\n if CPU_DATA_VALID = '1' then\r\n CPU_DATA_READ <= '1';\r\n READ_CPU_STATE <= DATA1;\r\n end if;\r\n when DATA1 =>\r\n -- etc.\r\nend case;"; - expected = "CASE READ_CPU_STATE IS\r\n WHEN WAITING =>\r\n IF CPU_DATA_VALID = '1' THEN\r\n CPU_DATA_READ <= '1';\r\n READ_CPU_STATE <= DATA1;\r\n END IF;\r\n WHEN DATA1 =>\r\n -- etc.\r\nEND CASE;"; - actual = VHDLFormatter_1.beautify(input, settings); - assert("WHEN CASE & IF", expected, actual); - input = "entity aa is\r\n port (a : in std_logic;\r\n b : in std_logic;\r\n );\r\nend aa;\r\narchitecture bb of aa is\r\n component cc\r\n port(\r\n a : in std_logic;\r\n b : in std_logic;\r\n );\r\n end cc;\r\n\r\nbegin\r\n C : cc port map (\r\n long => a,\r\n b => b\r\n );\r\nend;"; - expected = "ENTITY aa IS\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\nEND aa;\r\nARCHITECTURE bb OF aa IS\r\n COMPONENT cc\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n END cc;\r\n\r\nBEGIN\r\n C : cc PORT MAP(\r\n long => a,\r\n b => b\r\n );\r\nEND;"; - actual = VHDLFormatter_1.beautify(input, settings); - assert("PORT MAP", expected, actual); - input = "entity aa is\r\n port (a : in std_logic;\r\n b : in std_logic;\r\n );\r\n port (a : in std_logic;\r\n b : in std_logic;\r\n );\r\nend aa;\r\narchitecture bb of aa is\r\n component cc\r\n port(\r\n a : in std_logic;\r\n b : in std_logic;\r\n );\r\n port(\r\n a : in std_logic;\r\n b : in std_logic;\r\n );\r\n end cc;\r\n\r\nbegin\r\n C : cc port map (\r\n long => a,\r\n b => b\r\n );\r\n D : cc port map (\r\n long => a,\r\n b => b\r\n );\r\nend;"; - expected = "ENTITY aa IS\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\nEND aa;\r\nARCHITECTURE bb OF aa IS\r\n COMPONENT cc\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n END cc;\r\n\r\nBEGIN\r\n C : cc PORT MAP(\r\n long => a,\r\n b => b\r\n );\r\n D : cc PORT MAP(\r\n long => a,\r\n b => b\r\n );\r\nEND;"; - actual = VHDLFormatter_1.beautify(input, settings); - assert("Multiple PORT MAPs", expected, actual); - input = "port (a : in std_logic;\r\n b : in std_logic;\r\n);"; - expected = "PORT\r\n(\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n);"; - new_line_after_symbols_2 = new VHDLFormatter_3.NewLineSettings(); - new_line_after_symbols_2.newLineAfter = ["then", ";", "generic", "port"]; - newSettings = deepCopy(settings); - newSettings.NewLineSettings = new_line_after_symbols_2; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("New line after PORT", expected, actual); - newSettings = deepCopy(settings); - newSettings.NewLineSettings.newLineAfter = []; - input = "component a is\r\nport( Data : inout Std_Logic_Vector(7 downto 0););\r\nend component a;"; - expected = "COMPONENT a IS\r\n PORT (Data : INOUT Std_Logic_Vector(7 DOWNTO 0););\r\nEND COMPONENT a;"; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("New line after PORT (single line)", expected, actual); - input = "process xyx (vf,fr,\r\nde -- comment\r\n)"; - expected = "PROCESS xyx (vf, fr, \r\n de -- comment\r\n )"; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("Align parameters in PROCESS", expected, actual); - input = "architecture a of b is\r\nbegin\r\n process (w)\r\n variable t : std_logic_vector (4 downto 0) ;\r\nbegin\r\n a := (others => '0') ;\r\nend process ;\r\nend a;"; - expected = "ARCHITECTURE a OF b IS\r\nBEGIN\r\n PROCESS (w)\r\n VARIABLE t : std_logic_vector (4 DOWNTO 0);\r\n BEGIN\r\n a := (OTHERS => '0');\r\n END PROCESS;\r\nEND a;"; - actual = VHDLFormatter_1.beautify(input, newSettings); - assert("Double BEGIN", expected, actual); - let newSettings2 = deepCopy(newSettings); - newSettings2.SignAlignAll = true; - input = "entity a is\r\n port ( w : in std_logic_vector (7 downto 0) ;\r\n w_s : out std_logic_vector (3 downto 0) ; ) ;\r\nend a ;\r\narchitecture b of a is\r\nbegin\r\n process ( w )\r\n variable t : std_logic_vector (4 downto 0) ;\r\n variable bcd : std_logic_vector (11 downto 0) ;\r\nbegin\r\n b(2 downto 0) := w(7 downto 5) ;\r\n t := w(4 downto 0) ;\r\n w_s <= b(11 downto 8) ;\r\n w <= b(3 downto 0) ;\r\nend process ;\r\nend b ;"; - expected = "ENTITY a IS\r\n PORT\r\n (\r\n w : IN std_logic_vector (7 DOWNTO 0);\r\n w_s : OUT std_logic_vector (3 DOWNTO 0); \r\n );\r\nEND a;\r\nARCHITECTURE b OF a IS\r\nBEGIN\r\n PROCESS (w)\r\n VARIABLE t : std_logic_vector (4 DOWNTO 0);\r\n VARIABLE bcd : std_logic_vector (11 DOWNTO 0);\r\n BEGIN\r\n b(2 DOWNTO 0) := w(7 DOWNTO 5);\r\n t := w(4 DOWNTO 0);\r\n w_s <= b(11 DOWNTO 8);\r\n w <= b(3 DOWNTO 0);\r\n END PROCESS;\r\nEND b;"; - actual = VHDLFormatter_1.beautify(input, newSettings2); - assert("Align signs in all places", expected, actual); -} -function IntegrationTest5() { - let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";"]; - new_line_after_symbols.noNewLineAfter = ["generic"]; - let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.SignAlignRegional = true; - let input = "port map(\r\ninput_1 => input_1_sig,\r\ninput_2 => input_2_sig,\r\noutput => output_sig\r\n);"; - let expected = "PORT MAP(\r\n input_1 => input_1_sig,\r\n input_2 => input_2_sig,\r\n output => output_sig\r\n);"; - let actual = VHDLFormatter_1.beautify(input, settings); - assert("Sign align in PORT", expected, actual); -} -function IntegrationTest6() { - let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";", "port map"]; - new_line_after_symbols.noNewLineAfter = ["generic"]; - let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.SignAlignRegional = true; - let input = "port map(\r\ninput_1 => input_1_sig,\r\ninput_2 => input_2_sig,\r\noutput => output_sig\r\n);"; - let expected = "PORT MAP\r\n(\r\n input_1 => input_1_sig,\r\n input_2 => input_2_sig,\r\n output => output_sig\r\n);"; - let actual = VHDLFormatter_1.beautify(input, settings); - assert("Sign align in PORT & new line after MAP", expected, actual); -} -function IntegrationTest7() { - let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";"]; - let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.SignAlignRegional = true; - let input = "entity p is\r\n generic\r\n (\r\n -- INCLK\r\n INCLK0_INPUT_FREQUENCY : natural;\r\n\r\n -- CLK1\r\n CLK1_DIVIDE_BY : natural := 1;\r\n CLK1_MULTIPLY_BY : unnatural:= 1;\r\n CLK1_PHASE_SHIFT : string := \"0\"\r\n );\r\n port\r\n (\r\n inclk0 : in std_logic := '0';\r\n c0 : out std_logic ;\r\n c1 : out std_logic \r\n );\r\nEND pll;"; - let expected = "ENTITY p IS\r\n GENERIC (\r\n -- INCLK\r\n INCLK0_INPUT_FREQUENCY : NATURAL;\r\n\r\n -- CLK1\r\n CLK1_DIVIDE_BY : NATURAL := 1;\r\n CLK1_MULTIPLY_BY : unnatural := 1;\r\n CLK1_PHASE_SHIFT : STRING := \"0\"\r\n );\r\n PORT (\r\n inclk0 : IN std_logic := '0';\r\n c0 : OUT std_logic;\r\n c1 : OUT std_logic\r\n );\r\nEND pll;"; - let actual = VHDLFormatter_1.beautify(input, settings); - assert("Sign align in PORT & GENERIC", expected, actual); -} -function IntegrationTest2() { - let new_line_after_symbols = new VHDLFormatter_3.NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";"]; - new_line_after_symbols.noNewLineAfter = ["generic"]; - let settings = new VHDLFormatter_4.BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.RemoveComments = true; - let input = "architecture TB of TB_CPU is\r\n component CPU_IF\r\n port -- port list\r\n end component;\r\n signal CPU_DATA_VALID: std_ulogic;\r\n signal CLK, RESET: std_ulogic := '0';\r\n constant PERIOD : time := 10 ns;\r\n constant MAX_SIM: time := 50 * PERIOD;\r\n begin\r\n -- concurrent statements\r\n end TB;"; - let expected = "ARCHITECTURE TB OF TB_CPU IS\r\n COMPONENT CPU_IF\r\n PORT\r\n END COMPONENT;\r\n SIGNAL CPU_DATA_VALID : std_ulogic;\r\n SIGNAL CLK, RESET : std_ulogic := '0';\r\n CONSTANT PERIOD : TIME := 10 ns;\r\n CONSTANT MAX_SIM : TIME := 50 * PERIOD;\r\nBEGIN\r\nEND TB;"; - let actual = VHDLFormatter_1.beautify(input, settings); - assert("Remove comments", expected, actual); -} -function CompareString(actual, expected) { - var l = Math.min(actual.length, expected.length); - for (var i = 0; i < l; i++) { - if (actual[i] != expected[i]) { - var toEnd = Math.min(i + 50, l); - return '\ndifferent at ' + i.toString() + - '\nactual: "\n' + actual.substring(i, toEnd) + - '\nexpected: "\n' + expected.substring(i, toEnd) + '"\n---' + - "\nactual (full): \n" + actual + "\n---" + - "\nexpected (full): \n" + expected + "\n====\n"; - } - } - if (actual != expected) { - return 'actual: \n"' + actual + '"\nexpected: \n"' + expected + '"'; - } - return true; -} -function CompareArray(actual, expected) { - var l = Math.min(actual.length, expected.length); - let result = ""; - for (var i = 0; i < l; i++) { - if (actual[i] != expected[i]) { - result += CompareString(actual[i], expected[i]) + "\n"; - } - } - 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]; - } - } - return true; -} -//# sourceMappingURL=VHDLFormatterUnitTests.js.map \ No newline at end of file diff --git a/VHDLFormatterUnitTests.ts b/VHDLFormatterUnitTests.ts deleted file mode 100644 index b7969b4..0000000 --- a/VHDLFormatterUnitTests.ts +++ /dev/null @@ -1,813 +0,0 @@ -import { beautify } from "./VHDLFormatter"; -import { indentDecode } from "./VHDLFormatter"; -import { NewLineSettings } from "./VHDLFormatter"; -import { BeautifierSettings } from "./VHDLFormatter"; -import { RemoveAsserts } from "./VHDLFormatter"; -import { ApplyNoNewLineAfter } from "./VHDLFormatter"; -import { SetNewLinesAfterSymbols } from "./VHDLFormatter"; -import { beautify3 } from "./VHDLFormatter"; -import { FormattedLine } from "./VHDLFormatter"; -import { FormattedLineToString } from "./VHDLFormatter"; - -let testCount: number = 0; - -var showUnitTests = true;//window.location.href.indexOf("http") < 0; -if (showUnitTests) { - testCount = 0; - UnitTest(); - - UnitTestIndentDecode(); - UnitTestRemoveAsserts(); - UnitTestApplyNoNewLineAfter(); - UnitTestSetNewLinesAfterSymbols(); - UnitTestFormattedLineToString(); - UnitTestbeautify3(); - console.log("total tests: " + testCount); -} - -interface Function { - readonly name: string; -} - -function UnitTestFormattedLineToString() { - console.log("=== FormattedLineToString ==="); - FormattedLineToStringCase1(); - FormattedLineToStringCase2(); -} - -function FormattedLineToStringCase1() { - let inputs: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("a;", 0), - new FormattedLine("b;", 0)]; - let expected: Array = ["a;", "b;"]; - UnitTest7(FormattedLineToString, "General", " ", inputs, expected); -} - -function FormattedLineToStringCase2() { - let inputs: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("a;", 1), - new FormattedLine("b;", 2)]; - let expected: Array = [" a;", " b;"]; - UnitTest7(FormattedLineToString, "General", " ", inputs, expected); -} - -function UnitTestbeautify3() { - console.log("=== beautify3 ==="); - Beautify3Case1(); - Beautify3Case2(); - Beautify3Case3(); - Beautify3Case4(); - Beautify3Case5(); - Beautify3Case6(); - Beautify3Case7(); - Beautify3Case8(); - Beautify3Case9(); - Beautify3Case10(); - Beautify3Case11(); - Beautify3Case12(); - Beautify3Case13(); - Beautify3Case14(); -} - -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 Beautify3Case7() { - 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 = [ - "ARCHITECTURE a OF one IS", - "SIGNAL x : INTEGER;", - "BEGIN", - "-- architecture", - "END ARCHITECTURE;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("ARCHITECTURE a OF one IS", 0), - new FormattedLine("SIGNAL x : INTEGER;", 1), - new FormattedLine("BEGIN", 0), - new FormattedLine("-- architecture", 1), - new FormattedLine("END ARCHITECTURE;", 0), - ]; - UnitTest6(beautify3, "architecture", settings, inputs, expected, 0, 4, 0); -} - -function Beautify3Case8() { - 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 = [ - "ARCHITECTURE a OF one IS", - "SIGNAL x : INTEGER;", - "BEGIN", - "-- architecture", - "END ARCHITECTURE;", - "ARCHITECTURE b OF one IS", - "SIGNAL x : INTEGER;", - "BEGIN", - "-- architecture", - "END ARCHITECTURE;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("ARCHITECTURE a OF one IS", 0), - new FormattedLine("SIGNAL x : INTEGER;", 1), - new FormattedLine("BEGIN", 0), - new FormattedLine("-- architecture", 1), - new FormattedLine("END ARCHITECTURE;", 0), - new FormattedLine("ARCHITECTURE b OF one IS", 0), - new FormattedLine("SIGNAL x : INTEGER;", 1), - new FormattedLine("BEGIN", 0), - new FormattedLine("-- architecture", 1), - new FormattedLine("END ARCHITECTURE;", 0), - ]; - UnitTest6(beautify3, "architecture 2", settings, inputs, expected, 0, 9, 0); -} - -function Beautify3Case9() { - 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 = [ - "PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", - "VARIABLE i : INTEGER;", - "BEGIN", - "y := x + 1;", - "END PROCEDURE;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", 0), - new FormattedLine("VARIABLE i : INTEGER;", 1), - new FormattedLine("BEGIN", 0), - new FormattedLine("y := x + 1;", 1), - new FormattedLine("END PROCEDURE;", 0) - ]; - UnitTest6(beautify3, "procedure", settings, inputs, expected, 0, 4, 0); -} - -function Beautify3Case10() { - 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 = [ - "PACKAGE three IS", - "SIGNAL s : INTEGER;", - "ALIAS sa IS s;", - "END PACKAGE;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("PACKAGE three IS", 0), - new FormattedLine("SIGNAL s : INTEGER;", 1), - new FormattedLine("ALIAS sa IS s;", 1), - new FormattedLine("END PACKAGE;", 0) - ]; - UnitTest6(beautify3, "package", settings, inputs, expected, 0, 3, 0); -} - -function Beautify3Case11() { - 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 = [ - "PACKAGE p IS", - "PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER);", - "END PACKAGE;", - "PACKAGE BODY p IS", - "PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", - "VARIABLE i : INTEGER;", - "BEGIN", - "y := x + 1;", - "END PROCEDURE;", - "PROCEDURE bar(FILE x : text);", - "PROCEDURE baz IS", - "TYPE foo;", - "ALIAS x IS y;", - "BEGIN", - "END PROCEDURE;", - "PROCEDURE tralala IS", - "USE work.foo;", - "BEGIN", - "END PROCEDURE;", - "END PACKAGE BODY;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("PACKAGE p IS", 0), - new FormattedLine("PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER);", 1), - new FormattedLine("END PACKAGE;", 0), - new FormattedLine("PACKAGE BODY p IS", 0), - new FormattedLine("PROCEDURE foo(x : IN INTEGER; y : OUT INTEGER) IS", 1), - new FormattedLine("VARIABLE i : INTEGER;", 2), - new FormattedLine("BEGIN", 1), - new FormattedLine("y := x + 1;", 2), - new FormattedLine("END PROCEDURE;", 1), - new FormattedLine("PROCEDURE bar(FILE x : text);", 1), - new FormattedLine("PROCEDURE baz IS", 1), - new FormattedLine("TYPE foo;", 2), - new FormattedLine("ALIAS x IS y;", 2), - new FormattedLine("BEGIN", 1), - new FormattedLine("END PROCEDURE;", 1), - new FormattedLine("PROCEDURE tralala IS", 1), - new FormattedLine("USE work.foo;", 2), - new FormattedLine("BEGIN", 1), - new FormattedLine("END PROCEDURE;", 1), - new FormattedLine("END PACKAGE BODY;", 0) - ]; - UnitTest6(beautify3, "package procedure", settings, inputs, expected, 0, expected.length - 1, 0); -} - -function Beautify3Case12() { - 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 = [ - "ARCHITECTURE a OF b IS", - "SIGNAL x : INTEGER := 0;", - "BEGIN", - "p: PROCESS IS", - "BEGIN", - "END PROCESS;", - "PROCESS", - "VARIABLE y : INTEGER := 5;", - "BEGIN", - "x <= y;", - "END PROCESS;", - "PROCESS (x) IS", - "BEGIN", - "x <= x + 1;", - "END PROCESS;", - "POSTPONED PROCESS IS", - "BEGIN", - "END PROCESS;", - "POSTPONED assert x = 1;", - "END ARCHITECTURE;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("ARCHITECTURE a OF b IS", 0), - new FormattedLine("SIGNAL x : INTEGER := 0;", 1), - new FormattedLine("BEGIN", 0), - new FormattedLine("p: PROCESS IS", 1), - new FormattedLine("BEGIN", 1), - new FormattedLine("END PROCESS;", 1), - new FormattedLine("PROCESS", 1), - new FormattedLine("VARIABLE y : INTEGER := 5;", 2), - new FormattedLine("BEGIN", 1), - new FormattedLine("x <= y;", 2), - new FormattedLine("END PROCESS;", 1), - new FormattedLine("PROCESS (x) IS", 1), - new FormattedLine("BEGIN", 1), - new FormattedLine("x <= x + 1;", 2), - new FormattedLine("END PROCESS;", 1), - new FormattedLine("POSTPONED PROCESS IS", 1), - new FormattedLine("BEGIN", 1), - new FormattedLine("END PROCESS;", 1), - new FormattedLine("POSTPONED assert x = 1;", 1), - new FormattedLine("END ARCHITECTURE;", 0) - ]; - UnitTest6(beautify3, "package postponed procedure", settings, inputs, expected, 0, expected.length - 1, 0); -} - -function Beautify3Case13() { - 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 = [ - "TYPE SharedCounter IS PROTECTED", - "PROCEDURE increment (N : INTEGER := 1);", - "IMPURE FUNCTION value RETURN INTEGER;", - "END PROTECTED SharedCounter;" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("TYPE SharedCounter IS PROTECTED", 0), - new FormattedLine("PROCEDURE increment (N : INTEGER := 1);", 1), - new FormattedLine("IMPURE FUNCTION value RETURN INTEGER;", 1), - new FormattedLine("END PROTECTED SharedCounter;", 0) - ]; - UnitTest6(beautify3, "type projected", settings, inputs, expected, 0, expected.length - 1, 0); -} - -function Beautify3Case14() { - 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 = [ - "PACKAGE p IS", - "TYPE SharedCounter IS PROTECTED", - "PROCEDURE increment (N : INTEGER := 1);", - "IMPURE FUNCTION value RETURN INTEGER;", - "END PROTECTED SharedCounter;", - "TYPE SharedCounter IS PROTECTED BODY" - ]; - let expected: (FormattedLine | FormattedLine[])[] = [ - new FormattedLine("PACKAGE p IS", 0), - new FormattedLine("TYPE SharedCounter IS PROTECTED", 1), - new FormattedLine("PROCEDURE increment (N : INTEGER := 1);", 2), - new FormattedLine("IMPURE FUNCTION value RETURN INTEGER;", 2), - new FormattedLine("END PROTECTED SharedCounter;", 1), - new FormattedLine("TYPE SharedCounter IS PROTECTED BODY", 1) - ]; - UnitTest6(beautify3, "type projected", settings, inputs, expected, 0, expected.length - 1, 0); -} - -function UnitTestSetNewLinesAfterSymbols() { - console.log("=== SetNewLinesAfterSymbols ==="); - let input = "a; @@comments1\r\nb;" - let expected = "a; @@comments1\r\nb;"; - let parameters: NewLineSettings = new NewLineSettings(); - parameters.newLineAfter = ["then", ";"]; - parameters.noNewLineAfter = ["port", "generic"]; - UnitTest5(SetNewLinesAfterSymbols, "no new line after comment", parameters, input, expected); - - input = "a; b;" - expected = "a;\r\nb;"; - UnitTest5(SetNewLinesAfterSymbols, "new line after ;", parameters, input, expected); -} - -function UnitTestApplyNoNewLineAfter() { - console.log("=== ApplyNoNewLineAfter ==="); - let input: Array = ["a;", "b;"]; - let expected: Array = ["a;@@singleline", "b;@@singleline"]; - let parameters: Array = [";"]; - UnitTest4(ApplyNoNewLineAfter, "one blankspace", parameters, input, expected); - - input = ["a;", "b THEN", "c"]; - expected = ["a;@@singleline", "b THEN@@singleline", "c"]; - parameters = [";", "then"]; - UnitTest4(ApplyNoNewLineAfter, "one blankspace", parameters, input, expected); -} - -function UnitTestRemoveAsserts() { - console.log("=== RemoveAsserts ==="); - let input: Array = ["ASSERT a;"]; - let expected: Array = [""]; - UnitTest3(RemoveAsserts, "one assert", input, expected); - - input = ["ASSERT a", "b;", "c"]; - expected = ["", "", "c"]; - UnitTest3(RemoveAsserts, "multiline assert", input, expected); -} - -function UnitTestIndentDecode() { - console.log("=== IndentDecode ==="); - UnitTest2(indentDecode, "one blankspace", " ", "one blankspace"); - UnitTest2(indentDecode, "mixed chars", " A ", "one blankspace & one A & one blankspace"); - UnitTest2(indentDecode, "4 blankspaces", " ", "four blankspace"); - UnitTest2(indentDecode, "9 blankspaces", " ", "many blankspace"); -} - -function compareFormattedLines(expected: (FormattedLine | FormattedLine[])[], actual: (FormattedLine | FormattedLine[])[], message?): string { - 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) { - let compareResult = compareFormattedLine((expected[i]), (actual[i]), message, false); - if (compareResult.length > 0) { - result += "index " + i + "\n" + compareResult; - } - } - else { - result += "index " + i + "\nexpected FormatLine[], actual FormattedLine. actual:" + ((actual[i])).Line; - } - } - else { - if (expected[i] instanceof FormattedLine) { - result += "index " + i + "\nexpected FormatLine, actual FormattedLine[]. expected:" + ((expected[i])).Line; - } - else { - let compareResult = compareFormattedLines((actual[i]), (expected[i]), message); - if (compareResult.length > 0) { - result += "index " + i + "\n" + compareResult; - } - } - } - } - 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]; - } - } - return result; -} - -function assertFormattedLines(testName, expected: (FormattedLine | FormattedLine[])[], actual: (FormattedLine | FormattedLine[])[], message?) { - let result = compareFormattedLines(expected, actual, message); - if (result.length > 0) { - console.log(testName + " failed:\n" + result); - } - testCount++; -} - -function compareFormattedLine(expected: FormattedLine, actual: FormattedLine, message?, cumulateTestCount?: boolean) { - let result = ""; - if (expected.Indent != actual.Indent) { - result += 'indents are not equal;\nexpected: "' + expected.Line + '", ' + expected.Indent - + ';\nactual: "' + actual.Line + '", ' + actual.Indent + "\n"; - } - let compareResult = CompareString(actual.Line, expected.Line); - if (compareResult != true) { - result += compareResult; - } - return result; -} - -function assert(testName, expected: string, actual: string, message?) { - var result = CompareString(actual, expected); - if (result != true) { - console.log(testName + " failed: \n" + result); - } - else { - //console.log(testName + " pass"); - } - testCount++; -} - -function assertArray(testName, expected, actual, message?) { - var result = CompareArray(actual, expected); - if (result != true) { - console.log(testName + " failed: " + result); - } - else { - //console.log(testName + " pass"); - } - testCount++; -} - -type StringCallback = (text: string) => string; - -type ArrayCallback = (arr: Array) => void; - -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; - -type FormattedLinesCallback = (inputs: (FormattedLine | FormattedLine[])[], indentation: string) => Array; - -function UnitTest7(func: FormattedLinesCallback, testName: string, indentation: string, inputs: (FormattedLine | FormattedLine[])[], expected: Array) { - let actual = func(inputs, indentation); - assertArray(testName, expected, actual); -} - -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); -} - -function UnitTest4(func: Array2Callback, testName: string, parameters: Array, inputs: Array, expected: Array) { - let actual = JSON.parse(JSON.stringify(inputs)); - func(actual, parameters); - assertArray(testName, expected, actual); -} - -function UnitTest3(func: ArrayCallback, testName: string, inputs: Array, expected: Array) { - let actual = JSON.parse(JSON.stringify(inputs)); - func(actual); - assertArray(testName, expected, actual); -} - -function UnitTest2(func: StringCallback, testName: string, inputs, expected: string) { - let actual: string = func(inputs); - assert(testName, expected, actual); -} - -function deepCopy(objectToCopy: BeautifierSettings): BeautifierSettings { - return (JSON.parse(JSON.stringify(objectToCopy))); -} - -function UnitTest() { - 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 input = "architecture TB of TB_CPU is\r\n component CPU_IF\r\n port -- port list\r\n end component;\r\n signal CPU_DATA_VALID: std_ulogic;\r\n signal CLK, RESET: std_ulogic := '0';\r\n constant PERIOD : time := 10 ns;\r\n constant MAX_SIM: time := 50 * PERIOD;\r\n begin\r\n -- concurrent statements\r\n end TB;" - let expected = "ARCHITECTURE TB OF TB_CPU IS\r\n COMPONENT CPU_IF\r\n PORT -- port list\r\n END COMPONENT;\r\n SIGNAL CPU_DATA_VALID : std_ulogic;\r\n SIGNAL CLK, RESET : std_ulogic := '0';\r\n CONSTANT PERIOD : TIME := 10 ns;\r\n CONSTANT MAX_SIM : TIME := 50 * PERIOD;\r\nBEGIN\r\n -- concurrent statements\r\nEND TB;"; - let actual = beautify(input, settings); - assert("General", expected, actual); - - IntegrationTest2(); - - let new_line_after_symbols_2: NewLineSettings = new NewLineSettings(); - new_line_after_symbols_2.newLineAfter = []; - new_line_after_symbols_2.noNewLineAfter = ["then", ";", "generic", "port"]; - let newSettings = deepCopy(settings); - newSettings.NewLineSettings = new_line_after_symbols_2; - expected = "a; b; c;"; - input = "a; \r\nb;\r\n c;" - actual = beautify(input, newSettings); - assert("Remove line after ;", expected, actual); - - newSettings = deepCopy(settings); - newSettings.RemoveAsserts = true; - input = "architecture arch of ent is\r\nbegin\r\n assert False report sdfjcsdfcsdj;\r\n assert False report sdfjcsdfcsdj severity note;\r\nend architecture;"; - expected = "ARCHITECTURE arch OF ent IS\r\nBEGIN\r\nEND ARCHITECTURE;" - actual = beautify(input, newSettings); - assert("Remove asserts", expected, actual); - - input = "entity TB_DISPLAY is\r\n-- port declarations\r\nend TB_DISPLAY;\r\n\r\narchitecture TEST of TB_DISPLAY is\r\n-- signal declarations\r\nbegin\r\n-- component instance(s)\r\nend TEST;"; - expected = "ENTITY TB_DISPLAY IS\r\n -- port declarations\r\nEND TB_DISPLAY;\r\n\r\nARCHITECTURE TEST OF TB_DISPLAY IS\r\n -- signal declarations\r\nBEGIN\r\n -- component instance(s)\r\nEND TEST;"; - actual = beautify(input, settings); - assert("ENTITY ARCHITECTURE", expected, actual); - - IntegrationTest5(); - IntegrationTest6(); - IntegrationTest7(); - - input = 'if a(3 downto 0) > "0100" then\r\na(3 downto 0) := a(3 downto 0) + "0011" ;\r\nend if ;'; - expected = 'IF a(3 DOWNTO 0) > "0100" THEN\r\n a(3 DOWNTO 0) := a(3 DOWNTO 0) + "0011";\r\nEND IF;'; - actual = beautify(input, settings); - assert("IF END IF case 1", expected, actual); - - input = "if s = '1' then\r\no <= \"010\";\r\nelse\r\no <= \"101\";\r\nend if;"; - expected = "IF s = '1' THEN\r\n o <= \"010\";\r\nELSE\r\n o <= \"101\";\r\nEND IF;"; - actual = beautify(input, settings); - assert("IF ELSE END IF case 1", expected, actual); - - newSettings = deepCopy(settings); - newSettings.NewLineSettings.newLineAfter.push("ELSE"); - input = "IF (s = r) THEN rr := '0'; ELSE rr := '1'; END IF;"; - expected = "IF (s = r) THEN\r\n rr := '0';\r\nELSE\r\n rr := '1';\r\nEND IF;"; - actual = beautify(input, newSettings); - assert("IF ELSE END IF case 2", expected, actual); - - input = 'P1:process\r\nvariable x: Integer range 1 to 3;\r\nvariable y: BIT_VECTOR (0 to 1);\r\nbegin\r\n C1: case x is\r\n when 1 => Out_1 <= 0;\r\n when 2 => Out_1 <= 1;\r\n end case C1;\r\n C2: case y is\r\n when "00" => Out_2 <= 0;\r\n when "01" => Out_2 <= 1;\r\n end case C2;\r\nend process;'; - expected = 'P1 : PROCESS\r\n VARIABLE x : INTEGER RANGE 1 TO 3;\r\n VARIABLE y : BIT_VECTOR (0 TO 1);\r\nBEGIN\r\n C1 : CASE x IS\r\n WHEN 1 => Out_1 <= 0;\r\n WHEN 2 => Out_1 <= 1;\r\n END CASE C1;\r\n C2 : CASE y IS\r\n WHEN "00" => Out_2 <= 0;\r\n WHEN "01" => Out_2 <= 1;\r\n END CASE C2;\r\nEND PROCESS;'; - actual = beautify(input, settings); - assert("WHEN CASE", expected, actual); - - input = "case READ_CPU_STATE is\r\n when WAITING =>\r\n if CPU_DATA_VALID = '1' then\r\n CPU_DATA_READ <= '1';\r\n READ_CPU_STATE <= DATA1;\r\n end if;\r\n when DATA1 =>\r\n -- etc.\r\nend case;"; - expected = "CASE READ_CPU_STATE IS\r\n WHEN WAITING =>\r\n IF CPU_DATA_VALID = '1' THEN\r\n CPU_DATA_READ <= '1';\r\n READ_CPU_STATE <= DATA1;\r\n END IF;\r\n WHEN DATA1 =>\r\n -- etc.\r\nEND CASE;"; - actual = beautify(input, settings); - assert("WHEN CASE & IF", expected, actual); - - input = "entity aa is\r\n port (a : in std_logic;\r\n b : in std_logic;\r\n );\r\nend aa;\r\narchitecture bb of aa is\r\n component cc\r\n port(\r\n a : in std_logic;\r\n b : in std_logic;\r\n );\r\n end cc;\r\n\r\nbegin\r\n C : cc port map (\r\n long => a,\r\n b => b\r\n );\r\nend;"; - expected = "ENTITY aa IS\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\nEND aa;\r\nARCHITECTURE bb OF aa IS\r\n COMPONENT cc\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n END cc;\r\n\r\nBEGIN\r\n C : cc PORT MAP(\r\n long => a,\r\n b => b\r\n );\r\nEND;"; - actual = beautify(input, settings); - assert("PORT MAP", expected, actual); - - input = "entity aa is\r\n port (a : in std_logic;\r\n b : in std_logic;\r\n );\r\n port (a : in std_logic;\r\n b : in std_logic;\r\n );\r\nend aa;\r\narchitecture bb of aa is\r\n component cc\r\n port(\r\n a : in std_logic;\r\n b : in std_logic;\r\n );\r\n port(\r\n a : in std_logic;\r\n b : in std_logic;\r\n );\r\n end cc;\r\n\r\nbegin\r\n C : cc port map (\r\n long => a,\r\n b => b\r\n );\r\n D : cc port map (\r\n long => a,\r\n b => b\r\n );\r\nend;"; - expected = "ENTITY aa IS\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\nEND aa;\r\nARCHITECTURE bb OF aa IS\r\n COMPONENT cc\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n PORT (\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n );\r\n END cc;\r\n\r\nBEGIN\r\n C : cc PORT MAP(\r\n long => a,\r\n b => b\r\n );\r\n D : cc PORT MAP(\r\n long => a,\r\n b => b\r\n );\r\nEND;"; - actual = beautify(input, settings); - assert("Multiple PORT MAPs", expected, actual); - - input = "port (a : in std_logic;\r\n b : in std_logic;\r\n);"; - expected = "PORT\r\n(\r\n a : IN std_logic;\r\n b : IN std_logic;\r\n);"; - new_line_after_symbols_2 = new NewLineSettings(); - new_line_after_symbols_2.newLineAfter = ["then", ";", "generic", "port"]; - newSettings = deepCopy(settings); - newSettings.NewLineSettings = new_line_after_symbols_2; - actual = beautify(input, newSettings); - assert("New line after PORT", expected, actual); - - newSettings = deepCopy(settings); - newSettings.NewLineSettings.newLineAfter = []; - input = "component a is\r\nport( Data : inout Std_Logic_Vector(7 downto 0););\r\nend component a;"; - expected = "COMPONENT a IS\r\n PORT (Data : INOUT Std_Logic_Vector(7 DOWNTO 0););\r\nEND COMPONENT a;"; - actual = beautify(input, newSettings); - assert("New line after PORT (single line)", expected, actual); - - input = "process xyx (vf,fr,\r\nde -- comment\r\n)"; - expected = "PROCESS xyx (vf, fr, \r\n de -- comment\r\n )"; - actual = beautify(input, newSettings); - assert("Align parameters in PROCESS", expected, actual); - - input = "architecture a of b is\r\nbegin\r\n process (w)\r\n variable t : std_logic_vector (4 downto 0) ;\r\nbegin\r\n a := (others => '0') ;\r\nend process ;\r\nend a;"; - expected = "ARCHITECTURE a OF b IS\r\nBEGIN\r\n PROCESS (w)\r\n VARIABLE t : std_logic_vector (4 DOWNTO 0);\r\n BEGIN\r\n a := (OTHERS => '0');\r\n END PROCESS;\r\nEND a;"; - actual = beautify(input, newSettings); - assert("Double BEGIN", expected, actual); - - let newSettings2 = deepCopy(newSettings); - newSettings2.SignAlignAll = true; - input = "entity a is\r\n port ( w : in std_logic_vector (7 downto 0) ;\r\n w_s : out std_logic_vector (3 downto 0) ; ) ;\r\nend a ;\r\narchitecture b of a is\r\nbegin\r\n process ( w )\r\n variable t : std_logic_vector (4 downto 0) ;\r\n variable bcd : std_logic_vector (11 downto 0) ;\r\nbegin\r\n b(2 downto 0) := w(7 downto 5) ;\r\n t := w(4 downto 0) ;\r\n w_s <= b(11 downto 8) ;\r\n w <= b(3 downto 0) ;\r\nend process ;\r\nend b ;"; - expected = "ENTITY a IS\r\n PORT\r\n (\r\n w : IN std_logic_vector (7 DOWNTO 0);\r\n w_s : OUT std_logic_vector (3 DOWNTO 0); \r\n );\r\nEND a;\r\nARCHITECTURE b OF a IS\r\nBEGIN\r\n PROCESS (w)\r\n VARIABLE t : std_logic_vector (4 DOWNTO 0);\r\n VARIABLE bcd : std_logic_vector (11 DOWNTO 0);\r\n BEGIN\r\n b(2 DOWNTO 0) := w(7 DOWNTO 5);\r\n t := w(4 DOWNTO 0);\r\n w_s <= b(11 DOWNTO 8);\r\n w <= b(3 DOWNTO 0);\r\n END PROCESS;\r\nEND b;"; - actual = beautify(input, newSettings2); - assert("Align signs in all places", expected, actual); -} - -function IntegrationTest5() { - let new_line_after_symbols: NewLineSettings = new NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";"]; - new_line_after_symbols.noNewLineAfter = ["generic"]; - let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.SignAlignRegional = true; - let input = "port map(\r\ninput_1 => input_1_sig,\r\ninput_2 => input_2_sig,\r\noutput => output_sig\r\n);"; - let expected = "PORT MAP(\r\n input_1 => input_1_sig,\r\n input_2 => input_2_sig,\r\n output => output_sig\r\n);"; - let actual = beautify(input, settings); - assert("Sign align in PORT", expected, actual); -} - -function IntegrationTest6() { - let new_line_after_symbols: NewLineSettings = new NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";","port map"]; - new_line_after_symbols.noNewLineAfter = ["generic"]; - let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.SignAlignRegional = true; - let input = "port map(\r\ninput_1 => input_1_sig,\r\ninput_2 => input_2_sig,\r\noutput => output_sig\r\n);"; - let expected = "PORT MAP\r\n(\r\n input_1 => input_1_sig,\r\n input_2 => input_2_sig,\r\n output => output_sig\r\n);"; - let actual = beautify(input, settings); - assert("Sign align in PORT & new line after MAP", expected, actual); -} - -function IntegrationTest7() { - let new_line_after_symbols: NewLineSettings = new NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";"]; - let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.SignAlignRegional = true; - let input = "entity p is\r\n generic\r\n (\r\n -- INCLK\r\n INCLK0_INPUT_FREQUENCY : natural;\r\n\r\n -- CLK1\r\n CLK1_DIVIDE_BY : natural := 1;\r\n CLK1_MULTIPLY_BY : unnatural:= 1;\r\n CLK1_PHASE_SHIFT : string := \"0\"\r\n );\r\n port\r\n (\r\n inclk0 : in std_logic := '0';\r\n c0 : out std_logic ;\r\n c1 : out std_logic \r\n );\r\nEND pll;"; - let expected = "ENTITY p IS\r\n GENERIC (\r\n -- INCLK\r\n INCLK0_INPUT_FREQUENCY : NATURAL;\r\n\r\n -- CLK1\r\n CLK1_DIVIDE_BY : NATURAL := 1;\r\n CLK1_MULTIPLY_BY : unnatural := 1;\r\n CLK1_PHASE_SHIFT : STRING := \"0\"\r\n );\r\n PORT (\r\n inclk0 : IN std_logic := '0';\r\n c0 : OUT std_logic;\r\n c1 : OUT std_logic\r\n );\r\nEND pll;"; - let actual = beautify(input, settings); - assert("Sign align in PORT & GENERIC", expected, actual); -} - -function IntegrationTest2() { - let new_line_after_symbols: NewLineSettings = new NewLineSettings(); - new_line_after_symbols.newLineAfter = ["then", ";"]; - new_line_after_symbols.noNewLineAfter = ["generic"]; - let settings: BeautifierSettings = new BeautifierSettings(false, false, false, false, false, "uppercase", " ", new_line_after_symbols); - settings.RemoveComments = true; - let input = "architecture TB of TB_CPU is\r\n component CPU_IF\r\n port -- port list\r\n end component;\r\n signal CPU_DATA_VALID: std_ulogic;\r\n signal CLK, RESET: std_ulogic := '0';\r\n constant PERIOD : time := 10 ns;\r\n constant MAX_SIM: time := 50 * PERIOD;\r\n begin\r\n -- concurrent statements\r\n end TB;" - let expected = "ARCHITECTURE TB OF TB_CPU IS\r\n COMPONENT CPU_IF\r\n PORT\r\n END COMPONENT;\r\n SIGNAL CPU_DATA_VALID : std_ulogic;\r\n SIGNAL CLK, RESET : std_ulogic := '0';\r\n CONSTANT PERIOD : TIME := 10 ns;\r\n CONSTANT MAX_SIM : TIME := 50 * PERIOD;\r\nBEGIN\r\nEND TB;"; - let actual = beautify(input, settings); - assert("Remove comments", expected, actual); -} - -function CompareString(actual: string, expected: string) { - var l = Math.min(actual.length, expected.length); - for (var i = 0; i < l; i++) { - if (actual[i] != expected[i]) { - var toEnd = Math.min(i + 50, l); - return '\ndifferent at ' + i.toString() + - '\nactual: "\n' + actual.substring(i, toEnd) + - '\nexpected: "\n' + expected.substring(i, toEnd) + '"\n---' + - "\nactual (full): \n" + actual + "\n---" + - "\nexpected (full): \n" + expected + "\n====\n"; - } - } - if (actual != expected) { - return 'actual: \n"' + actual + '"\nexpected: \n"' + expected + '"'; - } - return true; -} - -function CompareArray(actual: Array, expected: Array) { - var l = Math.min(actual.length, expected.length); - let result: string = ""; - for (var i = 0; i < l; i++) { - if (actual[i] != expected[i]) { - result += CompareString(actual[i], expected[i]) + "\n"; - } - } - 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]; - } - } - return true; -} \ No newline at end of file diff --git a/descriptiveCounter.js b/descriptiveCounter.js new file mode 100644 index 0000000..37deb63 --- /dev/null +++ b/descriptiveCounter.js @@ -0,0 +1,57 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function indent_decode() { + var custom_indent = document.getElementById("cust_indent").value; + var result = descriptiveCounter(custom_indent); + document.getElementById("indent_s").innerHTML = result; +} +function descriptiveCounter(input) { + input = input.replace(/\\t/g, " "); + var tokens = input.split(""); + var result = ""; + var repeatedCharCount = 0; + for (var i = 0; i < tokens.length; i++) { + var char = input.substr(i, 1); + if (char == input.substr(i + 1, 1)) { + repeatedCharCount++; + } + else { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + break; + default: + char = "'" + char + "'"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + if (repeatedCharCount > 0) { + char += "s"; + } + result += getCountText(repeatedCharCount, char); + repeatedCharCount = 0; + } + } + if (result.length < 0) { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + result = getCountText(repeatedCharCount, char); + } + result = result.replace(/^ & /, ""); + return result; +} +exports.descriptiveCounter = descriptiveCounter; +function getCountText(count, char) { + const dict = ["one", "two", "three", "four", "five", "six", "seven", "eight", "many"]; + const ampersand = " & "; + return ampersand + dict[count] + " " + char; +} +//# sourceMappingURL=descriptiveCounter.js.map \ No newline at end of file diff --git a/descriptiveCounter.ts b/descriptiveCounter.ts new file mode 100644 index 0000000..963e1c3 --- /dev/null +++ b/descriptiveCounter.ts @@ -0,0 +1,57 @@ +function indent_decode() { + var custom_indent: string = (document.getElementById("cust_indent")).value; + var result: string = descriptiveCounter(custom_indent); + document.getElementById("indent_s").innerHTML = result; +} + +export function descriptiveCounter(input: string): string { + input = input.replace(/\\t/g, " "); + + var tokens: Array = input.split(""); + var result = ""; + var repeatedCharCount = 0; + for (var i = 0; i < tokens.length; i++) { + var char = input.substr(i, 1); + if (char == input.substr(i + 1, 1)) { + repeatedCharCount++; + } else { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + break; + default: + char = "'" + char + "'"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + if (repeatedCharCount > 0) { + char += "s"; + } + result += getCountText(repeatedCharCount, char); + repeatedCharCount = 0; + } + } + + if (result.length < 0) { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + result = getCountText(repeatedCharCount, char); + } + + result = result.replace(/^ & /, "") + return result; +} + +function getCountText(count: number, char: string): string { + const dict = ["one", "two", "three", "four", "five", "six", "seven", "eight", "many"]; + const ampersand = " & "; + return ampersand + dict[count] + " " + char; +} \ No newline at end of file diff --git a/VHDLFormatter.html b/index.html similarity index 58% rename from VHDLFormatter.html rename to index.html index 06fe1ac..d4ae014 100644 --- a/VHDLFormatter.html +++ b/index.html @@ -7,14 +7,33 @@ margin: 0 auto; max-width: 960px; tab-size: 4; - font-family: Helvetica, arial; + font-family: arial, sans-serif; } - + textarea { width: 100%; font-family: Consolas, Courier; } - + + fieldset { + width: fit-content; + border: 1px solid #9a9a9a; + margin: 25px 0 5px 0; + padding-left: 0; + } + + legend { + padding: 2px 5px; + background-color: #e0e0e0; + border-radius: 2px; + margin: -27px 0 0 -1px; + position: absolute; + } + + .subtitle { + font-weight: normal; + } + .btn { margin: 10px 10px; padding: 5px 8px; @@ -27,23 +46,17 @@ text-align: center; white-space: nowrap; border: 1px solid rgb(194, 194, 194); + background-color: #fff; } - + .btn:hover { - background-color: #afd9ee; + background-color: #eee; } - + .show { display: none; } - - input[type="checkbox"]+label { - display: inline-block; - width: 19px; - height: 19px; - margin: -1px 4px 0 0; - } - + .wordwrap { white-space: pre-wrap; white-space: -moz-pre-wrap; @@ -51,34 +64,142 @@ white-space: -o-pre-wrap; word-wrap: break-word; } - + label { cursor: pointer; line-height: 1.5em; } - + label:hover { color: #555; text-decoration: underline; } - + form { margin-bottom: 0px; } - + form span { width: 170px; display: inline-block; text-align: right; } - + a { color: #4b9aff; text-decoration: none; + background: #f0f8ff; + padding: 2px 5px; + border-radius: 3px; + font-size: 0.8em; } - + a:hover { - text-decoration: underline; + text-decoration: none; + background: #d6e8ff; + } + + p { + line-height: 1em; + margin: 0.5em 0em; + } + + .code { + font-family: 'Consolas', Courier, monospace; + } + + .inline { + display: inline-block; + } + + .disabled { + color: #ccc; + cursor: default; + } + + .disabled label:hover { + color: #ccc; + text-decoration: none; + cursor: default; + } + + .checkbox input[type="checkbox"] { + opacity: 0; + display: none; + } + + .checkbox label { + position: relative; + display: inline-block; + /*16px width of fake checkbox + 6px distance between fake checkbox and text*/ + padding-left: 22px; + } + + .checkbox label::before, + .checkbox label::after { + position: absolute; + content: ""; + /*Needed for the line-height to take effect*/ + display: inline-block; + } + /*Outer box of the fake checkbox*/ + + .checkbox label::before { + height: 16px; + width: 16px; + border: 1px solid #9A9A9A; + left: 0px; + /*(24px line-height - 16px height of fake checkbox) / 2 - 1px for the border to vertically center it.*/ + top: 3px; + } + /*Checkmark of the fake checkbox*/ + + .checkbox label::after { + height: 5px; + width: 9px; + border-left: 2px solid; + border-bottom: 2px solid; + transform: rotate(-45deg); + left: 4px; + top: 7px; + color: #333; + } + /*Hide the checkmark by default*/ + + .checkbox input[type="checkbox"]+label::after { + content: none; + } + /*Unhide on the checked state*/ + + .checkbox input[type="checkbox"]:checked+label::after { + content: ""; + } + /*Adding focus styles on the outer-box of the fake checkbox*/ + + .checkbox input[type="checkbox"]:hover+label::after { + border-color: #888; + outline: #ccc; + } + + .checkbox input[type="checkbox"]:hover+label::before { + outline: #888; + border-color: #888; + background-color: #eee; + } + + .checkbox input[type="checkbox"]:disabled+label::before { + outline: #ccc; + border-color: #ccc; + background-color: #fff; + color: #ccc; + } + + .checkbox input[type="checkbox"]:disabled+label::after { + color: #888; + } + + .checkbox input[type="checkbox"]:focus+label::before { + outline: #333 auto 5px; } @@ -105,111 +226,139 @@

VHDL Beautifier, Formatter

-

Beautify and format your VHDL code online

-

- Proper formatting makes code easier to read and understand. -
Please make a backup before you replace your code! -
- Report bugs if your code is not properly formatted, please provide sample code which causes the failure +

Beautify and format your VHDL code online

+

Proper formatting makes code easier to read and understand.

+

Please make a backup before you replace your code!

+

+ Release notes + Report 🐞 bug + Source code

-

+
+ + +
Keyword Case: - | + UPPERCASE | - | + lowercase |
- -
New line after -
-
- THEN -