diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20ddddb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.map +/.vscode/* \ No newline at end of file diff --git a/README.md b/README.md index 4c2509f..5672d94 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # VHDLFomatter 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 diff --git a/VHDLFormatter.html b/VHDLFormatter.html new file mode 100644 index 0000000..b29747f --- /dev/null +++ b/VHDLFormatter.html @@ -0,0 +1,298 @@ + + + + VHDL Beautifier, Formatter Online + + + + + + + +

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 +

+
+ +
+
Keyword Case: + + | + + | + +
+ +
New line after + , + , + , + , + +
+ + | + + | + +
+ +
+ +
+ +
+ + ( + four blankspace) +
+ +
+ +
+ + + + + +
+

+ output sample 
+
+LIBRARY IEEE; -- declare the library
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.std_logic_arith.ALL;
+ (All reserved words are in capital) 
+ (All indents are in the right place) 
+---------------------------------------------------------------
+
+ENTITY example IS
+	PORT (
+		rst                   : IN std_logic;
+		clk                   : IN std_logic;
+		example_of_long_words : OUT std_logic_vector(3 DOWNTO 0)
+		 (Align signs in PORT() aligns these colons) 
+	);
+END example;
+
+ARCHITECTURE EXA OF example IS
+	ALIAS slv IS std_logic_vector;
+	SUBTYPE bit4 IS slv(3 DOWNTO 0);  (Check ALIAS replaces all "std_logic_vector" with "slv") 
+	 
+BEGIN
+	REPORT "Hello World";  (Remove REPORT) 
+	 
+	stages : PROCESS (rst, clk)
+	BEGIN
+		 
+		IF (rst = '0') THEN
+			CASE bit4 IS
+				WHEN "0000" => bit4 <= "0001";
+				WHEN "0001" => bit4 <= "0100";
+				WHEN "0010" => bit4 <= "0010";
+				WHEN "0100" => bit4 <= "0000";
+				WHEN OTHERS => 
+					REPORT "Are there any more cases?";  (Remove REPORT) 
+			END CASE;
+		ELSIF (clk'event AND clk = '1') THEN
+			IF (bit4 = '0111') THEN
+				bit4 <= "0000";
+			ELSE
+				bit4 <= "1111";
+			END IF;
+			-- Sample comments 1;  
+			 -- Sample comments 2;   (Remove comments) 
+		END IF;
+		 
+	END PROCESS;
+END EXA;
+ + + + + + + \ No newline at end of file diff --git a/VHDLFormatter.js b/VHDLFormatter.js new file mode 100644 index 0000000..d91b094 --- /dev/null +++ b/VHDLFormatter.js @@ -0,0 +1,788 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +let isTesting = false; +const ILCommentPrefix = "@@comments"; +class NewLineSettings { + constructor() { + this.newLineAfter = []; + this.noNewLineAfter = []; + } + newLineAfterPush(keyword) { + this.newLineAfter.push(keyword); + } + noNewLineAfterPush(keyword) { + this.noNewLineAfter.push(keyword); + } + push(keyword, addNewLine) { + if (addNewLine) { + this.newLineAfterPush(keyword); + } + else { + this.noNewLineAfterPush(keyword); + } + } +} +exports.NewLineSettings = NewLineSettings; +function ConstructNewLineSettings(dict) { + let settings = new NewLineSettings(); + for (let key in dict) { + settings.push(key, dict[key]); + } + 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.regexIndexOf = function (pattern, startIndex) { + startIndex = startIndex || 0; + var searchResult = this.substr(startIndex).search(pattern); + return (-1 === searchResult) ? -1 : searchResult + startIndex; +}; +String.prototype.regexLastIndexOf = function (pattern, startIndex) { + startIndex = startIndex === undefined ? this.length : startIndex; + var searchResult = this.substr(0, startIndex).reverse().regexIndexOf(pattern, 0); + return (-1 === searchResult) ? -1 : this.length - ++searchResult; +}; +String.prototype.reverse = function () { + return this.split('').reverse().join(''); +}; +function wordWrap() { + var d = document.getElementById("result"); + if (d.className == "") { + d.className = "wordwrap"; + } + else { + d.className = ""; + } +} +function getHTMLInputElement(name) { + return document.getElementById(name); +} +function noFormat() { + let elements = ["remove_comments", + "remove_lines", + "remove_report", + "check_alias", + "sign_align", + "sign_align_all", + "new_line_after_port", + "new_line", + "use_space", + "compress", + "mix_letter"]; + var t = !(getHTMLInputElement("remove_comments").disabled); + 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++; + } + else { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + result += count[repeatedCharCount] + char; + repeatedCharCount = 0; + } + } + if (result.length < 0) { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + result = count[repeatedCharCount] + char; + } + result = result.replace(/^ & /, ""); + return result; +} +exports.indentDecode = indentDecode; +function Compress(input) { + input = input.replace(/\r\n/g, ''); + input = input.replace(/[\t ]+/g, ' '); + input = input.replace(/[ ]?([&=:\-<>\+|])[ ]?/g, '$1'); + return input; +} +function MixLetters(input) { + let arr = input.split(""); + for (var k = 0; k < arr.length; k++) { + if (arr[k] === arr[k].toUpperCase() && Math.random() > 0.5) { + arr[k] = arr[k].toLowerCase(); + } + else if (Math.random() > 0.5) { + arr[k] = arr[k].toUpperCase(); + } + } + return arr.join(""); +} +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 commentStartIndex = line.indexOf("--"); + if (firstCharIndex < commentStartIndex && firstCharIndex >= 0) { + comments.push(line.substr(commentStartIndex)); + arr[i] = line.substr(firstCharIndex, commentStartIndex - firstCharIndex) + ILCommentPrefix + (commentIndex++); + } + else if ((firstCharIndex > commentStartIndex && commentStartIndex >= 0) || (firstCharIndex < 0 && commentStartIndex >= 0)) { + comments.push(line.substr(commentStartIndex)); + arr[i] = ILCommentPrefix + (commentIndex++); + } + else { + firstCharIndex = firstCharIndex < 0 ? 0 : firstCharIndex; + arr[i] = line.substr(firstCharIndex); + } + } + return commentIndex; +} +function ToLowerCases(arr) { + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].toLowerCase(); + } +} +function ToCamelCases(arr) { + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].charAt(0) + arr[i].slice(1).toLowerCase(); + } +} +function ReplaceKeyWords(text, keywords) { + for (var k = 0; k < keywords.length; k++) { + text = text.replace(new RegExp("([^a-zA-Z0-9_@]|^)" + keywords[k] + "([^a-zA-Z0-9_]|$)", 'gi'), "$1" + keywords[k] + "$2"); + } + return text; +} +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); + } + return input; +} +function SetNewLinesAfterSymbols(text, newLineSettings) { + if (newLineSettings == null) { + return text; + } + if (newLineSettings.newLineAfter != null) { + newLineSettings.newLineAfter.forEach(symbol => { + let regex = new RegExp("(" + symbol.toUpperCase() + ")[ ]?([^ \r\n])", "g"); + text = text.replace(regex, '$1\r\n$2'); + }); + } + if (newLineSettings.noNewLineAfter != null) { + newLineSettings.noNewLineAfter.forEach(symbol => { + let regex = new RegExp("(" + symbol.toUpperCase() + ")[ \r\n]+", "g"); + text = text.replace(regex, '$1 '); + }); + } + return text; +} +class BeautifierSettings { + constructor(removeComments, removeReport, checkAlias, signAlign, signAlignAll, keywordCase, indentation, newLineSettings) { + this.RemoveComments = removeComments; + this.RemoveReport = removeReport; + this.CheckAlias = checkAlias; + this.SignAlign = signAlign; + this.SignAlignAll = signAlignAll; + this.KeywordCase = keywordCase; + this.Indentation = indentation; + this.NewLineSettings = newLineSettings; + } +} +exports.BeautifierSettings = BeautifierSettings; +let KeyWords = ["ABS", "ACCESS", "AFTER", "ALIAS", "ALL", "AND", "ARCHITECTURE", "ARRAY", "ASSERT", "ATTRIBUTE", "BEGIN", "BLOCK", "BODY", "BUFFER", "BUS", "CASE", "COMPONENT", "CONFIGURATION", "CONSTANT", "CONTEXT", "COVER", "DISCONNECT", "DOWNTO", "DEFAULT", "ELSE", "ELSIF", "END", "ENTITY", "EXIT", "FAIRNESS", "FILE", "FOR", "FORCE", "FUNCTION", "GENERATE", "GENERIC", "GROUP", "GUARDED", "IF", "IMPURE", "IN", "INERTIAL", "INOUT", "IS", "LABEL", "LIBRARY", "LINKAGE", "LITERAL", "LOOP", "MAP", "MOD", "NAND", "NEW", "NEXT", "NOR", "NOT", "NULL", "OF", "ON", "OPEN", "OR", "OTHERS", "OUT", "PACKAGE", "PORT", "POSTPONED", "PROCEDURE", "PROCESS", "PROPERTY", "PROTECTED", "PURE", "RANGE", "RECORD", "REGISTER", "REJECT", "RELEASE", "REM", "REPORT", "RESTRICT", "RESTRICT_GUARANTEE", "RETURN", "ROL", "ROR", "SELECT", "SEQUENCE", "SEVERITY", "SHARED", "SIGNAL", "SLA", "SLL", "SRA", "SRL", "STRONG", "SUBTYPE", "THEN", "TO", "TRANSPORT", "TYPE", "UNAFFECTED", "UNITS", "UNTIL", "USE", "VARIABLE", "VMODE", "VPROP", "VUNIT", "WAIT", "WHEN", "WHILE", "WITH", "XNOR", "XOR"]; +let TypeNames = ["BOOLEAN", "BIT", "CHARACTER", "INTEGER", "TIME", "NATURAL", "POSITIVE", "STRING"]; +function beautify(input, settings) { + input = RemoveExtraNewLines(input); + input = input.replace(/[\t ]+/g, ' '); + input = input.replace(/\([\t ]+/g, '\('); + input = input.replace(/[ ]+;/g, ';'); + input = input.replace(/:[ ]*(PROCESS|ENTITY)/gi, ':$1'); + var arr = input.split("\r\n"); + var comments = [], commentsIndex = 0; + commentsIndex = EscapeComments(arr, comments, commentsIndex); + input = arr.join("\r\n"); + if (settings.RemoveComments) { + input = input.replace(/@@comments[0-9]+/g, ''); + } + var quotes = [], quotesIndex = 0; + var singleline = [], singlelineIndex = 0; + 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, need_semi = false, semi_pos = 0, begin_b = true, port_b = false; + input = ReplaceKeyWords(input, KeyWords); + input = ReplaceKeyWords(input, TypeNames); + input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); + input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); + arr = input.split("\r\n"); + var l = arr.length; + var before_begin = true; + for (i = 0; i < l; i++) { + let k4 = arr[i].match(/"([^"]+)"/g); + if (k4 != null) { + var u = k4.length; + for (var j = 0; j < u; j++) { + arr[i] = arr[i].replace(k4[j], "@@quotes" + quotesIndex); + quotes[quotesIndex++] = k4[j]; + } + } + if (arr[i].indexOf("BEGIN") >= 0) { + before_begin = false; + } + if (settings.RemoveReport) { + n = arr[i].indexOf("REPORT "); + p = arr[i].indexOf(";"); + if (need_semi) { + arr[i] = ''; + if (p >= 0) { + need_semi = false; + } + } + if (n >= 0) { + arr[i] = ''; + if (p < 0) { + need_semi = true; + } + } + else if (n < 0) { + n = arr[i].indexOf("ASSERT "); + if (n >= 0) { + arr[i] = ''; + if (p < 0) { + need_semi = true; + } + } + } + } + if (arr[i].match(/FUNCTION|PROCEDURE/) != null) { + arr[i] = arr[i].replace(/;/g, '@@semicolon'); + } + 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'); + } + } + /*if (!new_line) { + if (arr[i].regexIndexOf(/(;|THEN)[ a-z0-9]+[a-z0-9]+/) >= 0) { + singleline[singlelineIndex] = arr[i]; + arr[i] = "@@singleline" + singlelineIndex++; + } + }*/ + } + 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, ')'); + //if (remove_lines) { + // input = input.replace(/(\r\n)*[ \t]*\r\n/g, '\r\n'); + //} + 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 && 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 { + 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.SignAlign) { + 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 (new_line_after_port) { + if (str.indexOf('@@singleend') < 0) { + arr[i] = arr[i].replace(/(PORT|GENERIC)([ \w]*)\(/, "$1$2\r\n" + (Array(tab_n).join(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("@@quotes") >= 0 && str.indexOf("= @@quotes") < 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.SignAlign) { + 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 < quotesIndex; k++) { + input = input.replace("@@quotes" + k, quotes[k]); + } + for (var k = 0; k < singlelineIndex; k++) { + input = input.replace("@@singleline" + k, singleline[k]); + } + for (var k = 0; k < commentsIndex; k++) { + input = input.replace(ILCommentPrefix + k, comments[k]); + } + input = input.replace(/@@semicolon/g, ";"); + input = input.replace(/@@[a-z]+/g, ""); + return input; +} +exports.beautify = beautify; +function RemoveExtraNewLines(input) { + input = input.replace(/(?:\r\n|\r|\n)/g, '\r\n'); + input = input.replace(/ \r\n/g, '\r\n'); + input = input.replace(/\r\n\r\n\r\n/g, '\r\n'); + return input; +} +//# sourceMappingURL=VHDLFormatter.js.map \ No newline at end of file diff --git a/VHDLFormatter.ts b/VHDLFormatter.ts new file mode 100644 index 0000000..891f669 --- /dev/null +++ b/VHDLFormatter.ts @@ -0,0 +1,844 @@ +let isTesting = false; +const ILCommentPrefix = "@@comments"; + +export class NewLineSettings { + newLineAfter: Array; + noNewLineAfter: Array; + constructor() { + this.newLineAfter = []; + this.noNewLineAfter = []; + } + + newLineAfterPush(keyword: string) { + this.newLineAfter.push(keyword); + } + + noNewLineAfterPush(keyword: string) { + this.noNewLineAfter.push(keyword); + } + + push(keyword: string, addNewLine: boolean) { + if (addNewLine) { + this.newLineAfterPush(keyword); + } + else { + this.noNewLineAfterPush(keyword); + } + } +} + +function ConstructNewLineSettings(dict): NewLineSettings { + let settings: NewLineSettings = new NewLineSettings(); + for (let key in dict) { + settings.push(key, dict[key]); + } + 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 { + regexIndexOf: (pattern: RegExp, startIndex?: number) => number; + regexLastIndexOf: (pattern: RegExp, startIndex: number) => number; + reverse: () => string; + } +} + +String.prototype.regexIndexOf = function (pattern, startIndex) { + startIndex = startIndex || 0; + var searchResult = this.substr(startIndex).search(pattern); + return (-1 === searchResult) ? -1 : searchResult + startIndex; +} +String.prototype.regexLastIndexOf = function (pattern, startIndex) { + startIndex = startIndex === undefined ? this.length : startIndex; + var searchResult = this.substr(0, startIndex).reverse().regexIndexOf(pattern, 0); + return (-1 === searchResult) ? -1 : this.length - ++searchResult; +} +String.prototype.reverse = function () { + return this.split('').reverse().join(''); +} + +function wordWrap() { + var d = document.getElementById("result"); + if (d.className == "") { + d.className = "wordwrap"; + } else { + d.className = ""; + } +} + +function getHTMLInputElement(name: string): HTMLInputElement { + return document.getElementById(name); +} + +function noFormat() { + let elements: Array = ["remove_comments", + "remove_lines", + "remove_report", + "check_alias", + "sign_align", + "sign_align_all", + "new_line_after_port", + "new_line", + "use_space", + "compress", + "mix_letter"]; + var t = !(getHTMLInputElement("remove_comments").disabled); + 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; + } + } + + if (result.length < 0) { + switch (char) { + case " ": + char = "blankspace"; + break; + case "\t": + char = "tab"; + } + repeatedCharCount = repeatedCharCount > 8 ? 8 : repeatedCharCount; + result = count[repeatedCharCount] + char; + } + + result = result.replace(/^ & /, "") + return result; +} + +function Compress(input: string) { + input = input.replace(/\r\n/g, ''); + input = input.replace(/[\t ]+/g, ' '); + input = input.replace(/[ ]?([&=:\-<>\+|])[ ]?/g, '$1'); + return input; +} + +function MixLetters(input: string) { + let arr = input.split(""); + for (var k = 0; k < arr.length; k++) { + if (arr[k] === arr[k].toUpperCase() && Math.random() > 0.5) { + arr[k] = arr[k].toLowerCase(); + } else if (Math.random() > 0.5) { + arr[k] = arr[k].toUpperCase(); + } + } + return arr.join(""); +} + +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 commentStartIndex = line.indexOf("--"); + if (firstCharIndex < commentStartIndex && firstCharIndex >= 0) { + comments.push(line.substr(commentStartIndex)); + arr[i] = line.substr(firstCharIndex, commentStartIndex - firstCharIndex) + ILCommentPrefix + (commentIndex++); + } else if ((firstCharIndex > commentStartIndex && commentStartIndex >= 0) || (firstCharIndex < 0 && commentStartIndex >= 0)) { + comments.push(line.substr(commentStartIndex)); + arr[i] = ILCommentPrefix + (commentIndex++); + } else { + firstCharIndex = firstCharIndex < 0 ? 0 : firstCharIndex; + arr[i] = line.substr(firstCharIndex); + } + } + return commentIndex +} + +function ToLowerCases(arr: Array) { + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].toLowerCase(); + } +} + +function ToCamelCases(arr: Array) { + for (var i = 0; i < arr.length; i++) { + arr[i] = arr[i].charAt(0) + arr[i].slice(1).toLowerCase(); + } +} + +function ReplaceKeyWords(text: string, keywords: Array): string { + for (var k = 0; k < keywords.length; k++) { + text = text.replace(new RegExp("([^a-zA-Z0-9_@]|^)" + keywords[k] + "([^a-zA-Z0-9_]|$)", 'gi'), "$1" + keywords[k] + "$2"); + } + return text; +} + +function SetKeywordCase(input: string, keywordcase: string, keywords, typenames) { + 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); + } + return input; +} + +function SetNewLinesAfterSymbols(text: string, newLineSettings: NewLineSettings): string { + if (newLineSettings == null) { + return text; + } + if (newLineSettings.newLineAfter != null) { + newLineSettings.newLineAfter.forEach(symbol => { + let regex: RegExp = new RegExp("(" + symbol.toUpperCase() + ")[ ]?([^ \r\n])", "g"); + text = text.replace(regex, '$1\r\n$2'); + }); + } + if (newLineSettings.noNewLineAfter != null) { + newLineSettings.noNewLineAfter.forEach(symbol => { + let regex: RegExp = new RegExp("(" + symbol.toUpperCase() + ")[ \r\n]+", "g"); + text = text.replace(regex, '$1 '); + }); + } + return text; +} + +export class BeautifierSettings { + RemoveComments: boolean; + RemoveReport: boolean; + CheckAlias: boolean; + SignAlign: boolean; + SignAlignAll: boolean; + KeywordCase: string; + Indentation: string; + NewLineSettings: NewLineSettings + constructor(removeComments: boolean, removeReport: boolean, checkAlias: boolean, + signAlign: boolean, signAlignAll: boolean, keywordCase: string, indentation: string, + newLineSettings: NewLineSettings) { + this.RemoveComments = removeComments; + this.RemoveReport = removeReport; + this.CheckAlias = checkAlias; + this.SignAlign = signAlign; + this.SignAlignAll = signAlignAll; + this.KeywordCase = keywordCase; + this.Indentation = indentation; + this.NewLineSettings = newLineSettings; + } +} + +let KeyWords: Array = ["ABS", "ACCESS", "AFTER", "ALIAS", "ALL", "AND", "ARCHITECTURE", "ARRAY", "ASSERT", "ATTRIBUTE", "BEGIN", "BLOCK", "BODY", "BUFFER", "BUS", "CASE", "COMPONENT", "CONFIGURATION", "CONSTANT", "CONTEXT", "COVER", "DISCONNECT", "DOWNTO", "DEFAULT", "ELSE", "ELSIF", "END", "ENTITY", "EXIT", "FAIRNESS", "FILE", "FOR", "FORCE", "FUNCTION", "GENERATE", "GENERIC", "GROUP", "GUARDED", "IF", "IMPURE", "IN", "INERTIAL", "INOUT", "IS", "LABEL", "LIBRARY", "LINKAGE", "LITERAL", "LOOP", "MAP", "MOD", "NAND", "NEW", "NEXT", "NOR", "NOT", "NULL", "OF", "ON", "OPEN", "OR", "OTHERS", "OUT", "PACKAGE", "PORT", "POSTPONED", "PROCEDURE", "PROCESS", "PROPERTY", "PROTECTED", "PURE", "RANGE", "RECORD", "REGISTER", "REJECT", "RELEASE", "REM", "REPORT", "RESTRICT", "RESTRICT_GUARANTEE", "RETURN", "ROL", "ROR", "SELECT", "SEQUENCE", "SEVERITY", "SHARED", "SIGNAL", "SLA", "SLL", "SRA", "SRL", "STRONG", "SUBTYPE", "THEN", "TO", "TRANSPORT", "TYPE", "UNAFFECTED", "UNITS", "UNTIL", "USE", "VARIABLE", "VMODE", "VPROP", "VUNIT", "WAIT", "WHEN", "WHILE", "WITH", "XNOR", "XOR"]; +let TypeNames: Array = ["BOOLEAN", "BIT", "CHARACTER", "INTEGER", "TIME", "NATURAL", "POSITIVE", "STRING"]; + +export function beautify(input: string, settings: BeautifierSettings) { + input = RemoveExtraNewLines(input); + input = input.replace(/[\t ]+/g, ' '); + input = input.replace(/\([\t ]+/g, '\('); + input = input.replace(/[ ]+;/g, ';'); + input = input.replace(/:[ ]*(PROCESS|ENTITY)/gi, ':$1'); + + var arr = input.split("\r\n"); + var comments = [], + commentsIndex = 0; + commentsIndex = EscapeComments(arr, comments, commentsIndex); + input = arr.join("\r\n"); + + if (settings.RemoveComments) { + input = input.replace(/@@comments[0-9]+/g, ''); + } + + input = ReplaceKeyWords(input, KeyWords); + input = ReplaceKeyWords(input, TypeNames); + input = input.replace(/(PORT|PROCESS|GENERIC)[\s]*\(/g, '$1 ('); + input = SetNewLinesAfterSymbols(input, settings.NewLineSettings); + + input = beautify2(input, settings); + + for (var k = 0; k < commentsIndex; k++) { + input = input.replace(ILCommentPrefix + k, comments[k]); + } + + input = input.replace(/@@semicolon/g, ";"); + input = input.replace(/@@[a-z]+/g, ""); + return input; +} + +function beautify2(input, settings: BeautifierSettings): string { + var quotes = [], + quotesIndex = 0; + var singleline = [], + singlelineIndex = 0; + 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, + need_semi = false, + semi_pos = 0, + begin_b = true, + port_b = false; + + let arr = input.split("\r\n"); + var l = arr.length; + var before_begin = true; + for (i = 0; i < l; i++) { + let k4 = arr[i].match(/"([^"]+)"/g); + if (k4 != null) { + var u = k4.length; + for (var j = 0; j < u; j++) { + arr[i] = arr[i].replace(k4[j], "@@quotes" + quotesIndex); + quotes[quotesIndex++] = k4[j]; + } + } + + if (arr[i].indexOf("BEGIN") >= 0) { + before_begin = false; + } + + if (settings.RemoveReport) { + n = arr[i].indexOf("REPORT "); + p = arr[i].indexOf(";"); + if (need_semi) { + arr[i] = ''; + if (p >= 0) { + need_semi = false; + } + } + if (n >= 0) { + arr[i] = ''; + if (p < 0) { + need_semi = true; + } + } else if (n < 0) { + n = arr[i].indexOf("ASSERT "); + if (n >= 0) { + arr[i] = ''; + if (p < 0) { + need_semi = true; + } + } + } + } + + if (arr[i].match(/FUNCTION|PROCEDURE/) != null) { + arr[i] = arr[i].replace(/;/g, '@@semicolon'); + } + 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'); + } + } + /*if (!new_line) { + if (arr[i].regexIndexOf(/(;|THEN)[ a-z0-9]+[a-z0-9]+/) >= 0) { + singleline[singlelineIndex] = arr[i]; + arr[i] = "@@singleline" + singlelineIndex++; + } + }*/ + } + 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, ')'); + //if (remove_lines) { + // input = input.replace(/(\r\n)*[ \t]*\r\n/g, '\r\n'); + //} + 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 && 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 { + 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.SignAlign) { + 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 (new_line_after_port) { + if (str.indexOf('@@singleend') < 0) { + arr[i] = arr[i].replace(/(PORT|GENERIC)([ \w]*)\(/, "$1$2\r\n" + (Array(tab_n).join(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("@@quotes") >= 0 && str.indexOf("= @@quotes") < 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.SignAlign) { + 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 < quotesIndex; k++) { + input = input.replace("@@quotes" + k, quotes[k]); + } + + for (var k = 0; k < singlelineIndex; k++) { + input = input.replace("@@singleline" + k, singleline[k]); + } + + + return input; +} + +function RemoveExtraNewLines(input: any) { + input = input.replace(/(?:\r\n|\r|\n)/g, '\r\n'); + input = input.replace(/ \r\n/g, '\r\n'); + input = input.replace(/\r\n\r\n\r\n/g, '\r\n'); + return input; +} diff --git a/VHDLFormatterUnitTests.js b/VHDLFormatterUnitTests.js new file mode 100644 index 0000000..0c72eaf --- /dev/null +++ b/VHDLFormatterUnitTests.js @@ -0,0 +1,130 @@ +"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"); +var showUnitTests = true; //window.location.href.indexOf("http") < 0; +if (showUnitTests) { + UnitTest(); + UnitTestIndentDecode(); +} +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 assert(testName, expected, actual, message) { + var result = CompareString(actual, expected); + if (result != true) { + console.log(testName + " failed: " + result); + } + else { + //console.log(testName + " pass"); + } +} +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", ";"]; + 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); + console.log("General", actual == expected); + let newSettings = deepCopy(settings); + newSettings.RemoveComments = true; + 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;"; + actual = VHDLFormatter_1.beautify(input, newSettings); + console.log("Remove comments", actual == expected); + 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); + console.log("ENTITY ARCHITECTURE", CompareString(actual, expected)); + newSettings = deepCopy(settings); + newSettings.SignAlign = true; + input = "port map(\r\ninput_1 => input_1_sig,\r\ninput_2 => input_2_sig,\r\noutput => output_sig\r\n);"; + expected = "PORT MAP(\r\n input_1 => input_1_sig, \r\n input_2 => input_2_sig, \r\n output => output_sig\r\n);"; + actual = VHDLFormatter_1.beautify(input, newSettings); + console.log("Sign align in PORT", actual == expected); + 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); + console.log("IF END IF case 1", CompareString(actual, expected)); + 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); + console.log("IF ELSE END IF case 1", actual == expected); + 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, settings); + console.log("IF ELSE END IF case 2", actual == expected); + 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); + console.log("WHEN CASE", CompareString(actual, expected)); + 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); + console.log("WHEN CASE & IF", CompareString(actual, expected)); + 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\r\n PORT MAP(\r\n long => a, \r\n b => b\r\n );\r\nEND;"; + actual = VHDLFormatter_1.beautify(input, settings); + console.log("PORT MAP", CompareString(actual, expected)); + 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\r\n PORT MAP(\r\n long => a, \r\n b => b\r\n );\r\n D : cc\r\n PORT MAP(\r\n long => a, \r\n b => b\r\n );\r\nEND;"; + actual = VHDLFormatter_1.beautify(input, settings); + console.log("Multiple PORT MAPs", CompareString(actual, expected)); + 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);"; + let 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); + console.log("New line aster PORT", CompareString(actual, expected)); + 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); + console.log("New line aster PORT (single line)", CompareString(actual, expected)); + 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); + console.log("Align parameters in PROCESS", CompareString(actual, expected)); + 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); + console.log("Double BEGIN", CompareString(actual, expected)); + 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); + console.log("Align signs in all places", CompareString(actual, expected)); + input = "begin\r\n P0 : process(input)\r\n variable value: Integer;\r\n begin\r\n result(i) := '0';\r\n end process P0;\r\nend behavior;"; + expected = "BEGIN\r\n P0 : PROCESS (input)\r\n VARIABLE value : INTEGER;\r\n BEGIN\r\n result(i) := '0';\r\n END PROCESS P0;\r\nEND behavior;"; + actual = VHDLFormatter_1.beautify(input, newSettings); + console.log("Indent after Begin", CompareString(actual, expected)); +} +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) + '"' + "\nactual: \n" + actual; + } + } + if (actual != expected) { + return 'actual: \n"' + actual + '"\nexpected: \n"' + expected + '"'; + } + return true; +} +//# sourceMappingURL=VHDLFormatterUnitTests.js.map \ No newline at end of file diff --git a/VHDLFormatterUnitTests.ts b/VHDLFormatterUnitTests.ts new file mode 100644 index 0000000..05cda21 --- /dev/null +++ b/VHDLFormatterUnitTests.ts @@ -0,0 +1,156 @@ +import { beautify } from "./VHDLFormatter"; +import { indentDecode } from "./VHDLFormatter"; +import { NewLineSettings } from "./VHDLFormatter"; +import { BeautifierSettings } from "./VHDLFormatter"; + +var showUnitTests = true;//window.location.href.indexOf("http") < 0; +if (showUnitTests) { + UnitTest(); + UnitTestIndentDecode(); +} + +interface Function { + readonly name: string; +} + +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 assert(testName, expected, actual, message?) { + var result = CompareString(actual, expected); + if (result != true) { + console.log(testName + " failed: " + result); + } + else { + //console.log(testName + " pass"); + } +} + +type StringCallback = (text: string) => string; + +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", ";"]; + 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); + console.log("General", actual == expected); + + let newSettings = deepCopy(settings); + newSettings.RemoveComments = true; + 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;"; + actual = beautify(input, newSettings); + console.log("Remove comments", actual == expected); + + 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); + console.log("ENTITY ARCHITECTURE", CompareString(actual, expected)); + + newSettings = deepCopy(settings); + newSettings.SignAlign = true; + input = "port map(\r\ninput_1 => input_1_sig,\r\ninput_2 => input_2_sig,\r\noutput => output_sig\r\n);"; + expected = "PORT MAP(\r\n input_1 => input_1_sig, \r\n input_2 => input_2_sig, \r\n output => output_sig\r\n);"; + actual = beautify(input, newSettings); + console.log("Sign align in PORT", actual == expected); + + 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); + console.log("IF END IF case 1", CompareString(actual, expected)); + + 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); + console.log("IF ELSE END IF case 1", actual == expected); + + 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, settings); + console.log("IF ELSE END IF case 2", actual == expected); + + 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); + console.log("WHEN CASE", CompareString(actual, expected)); + + 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); + console.log("WHEN CASE & IF", CompareString(actual, expected)); + + 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\r\n PORT MAP(\r\n long => a, \r\n b => b\r\n );\r\nEND;"; + actual = beautify(input, settings); + console.log("PORT MAP", CompareString(actual, expected)); + + 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\r\n PORT MAP(\r\n long => a, \r\n b => b\r\n );\r\n D : cc\r\n PORT MAP(\r\n long => a, \r\n b => b\r\n );\r\nEND;"; + actual = beautify(input, settings); + console.log("Multiple PORT MAPs", CompareString(actual, expected)); + + 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);"; + let new_line_after_symbols_2: NewLineSettings = 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); + console.log("New line aster PORT", CompareString(actual, expected)); + + 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); + console.log("New line aster PORT (single line)", CompareString(actual, expected)); + + 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); + console.log("Align parameters in PROCESS", CompareString(actual, expected)); + + 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); + console.log("Double BEGIN", CompareString(actual, expected)); + + 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); + console.log("Align signs in all places", CompareString(actual, expected)); + + input = "begin\r\n P0 : process(input)\r\n variable value: Integer;\r\n begin\r\n result(i) := '0';\r\n end process P0;\r\nend behavior;"; + expected = "BEGIN\r\n P0 : PROCESS (input)\r\n VARIABLE value : INTEGER;\r\n BEGIN\r\n result(i) := '0';\r\n END PROCESS P0;\r\nEND behavior;"; + actual = beautify(input, newSettings); + console.log("Indent after Begin", CompareString(actual, expected)); +} + +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) + '"' + "\nactual: \n" + actual; + } + } + if (actual != expected) { + return 'actual: \n"' + actual + '"\nexpected: \n"' + expected + '"'; + } + return true; +} \ No newline at end of file diff --git a/highlight.css b/highlight.css new file mode 100644 index 0000000..82abb09 --- /dev/null +++ b/highlight.css @@ -0,0 +1 @@ +.hljs{display:block;overflow-x:auto;padding:.5em;-webkit-text-size-adjust:none}.hljs,.hljs-subst,.hljs-tag .hljs-title,.nginx .hljs-title{color:#000}.hljs-string,.hljs-title,.hljs-constant,.hljs-parent,.hljs-tag .hljs-value,.hljs-rules .hljs-value,.hljs-preprocessor,.hljs-pragma,.haml .hljs-symbol,.ruby .hljs-symbol,.ruby .hljs-symbol .hljs-string,.hljs-template_tag,.django .hljs-variable,.smalltalk .hljs-class,.hljs-addition,.hljs-flow,.hljs-stream,.bash .hljs-variable,.apache .hljs-tag,.apache .hljs-cbracket,.tex .hljs-command,.tex .hljs-special,.erlang_repl .hljs-function_or_atom,.asciidoc .hljs-header,.markdown .hljs-header,.coffeescript .hljs-attribute{color:#800}.smartquote,.hljs-comment,.hljs-annotation,.diff .hljs-header,.hljs-chunk,.asciidoc .hljs-blockquote,.markdown .hljs-blockquote{color:#888}.hljs-number,.hljs-date,.hljs-regexp,.hljs-literal,.hljs-hexcolor,.smalltalk .hljs-symbol,.smalltalk .hljs-char,.go .hljs-constant,.hljs-change,.lasso .hljs-variable,.makefile .hljs-variable,.asciidoc .hljs-bullet,.markdown .hljs-bullet,.asciidoc .hljs-link_url,.markdown .hljs-link_url{color:#080}.hljs-label,.hljs-javadoc,.ruby .hljs-string,.hljs-decorator,.hljs-filter .hljs-argument,.hljs-localvars,.hljs-array,.hljs-attr_selector,.hljs-important,.hljs-pseudo,.hljs-pi,.haml .hljs-bullet,.hljs-doctype,.hljs-deletion,.hljs-envvar,.hljs-shebang,.apache .hljs-sqbracket,.nginx .hljs-built_in,.tex .hljs-formula,.erlang_repl .hljs-reserved,.hljs-prompt,.asciidoc .hljs-link_label,.markdown .hljs-link_label,.vhdl .hljs-attribute,.clojure .hljs-attribute,.asciidoc .hljs-attribute,.lasso .hljs-attribute,.coffeescript .hljs-property,.hljs-phony{color:#88f}.hljs-keyword,.hljs-id,.hljs-title,.hljs-built_in,.css .hljs-tag,.hljs-javadoctag,.hljs-phpdoc,.hljs-dartdoc,.hljs-yardoctag,.smalltalk .hljs-class,.hljs-winutils,.bash .hljs-variable,.apache .hljs-tag,.hljs-type,.hljs-typename,.tex .hljs-command,.asciidoc .hljs-strong,.markdown .hljs-strong,.hljs-request,.hljs-status{font-weight:700}.asciidoc .hljs-emphasis,.markdown .hljs-emphasis{font-style:italic}.nginx .hljs-built_in{font-weight:400}.coffeescript .javascript,.javascript .xml,.lasso .markup,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:.5} \ No newline at end of file diff --git a/highlight.js b/highlight.js new file mode 100644 index 0000000..26426dc --- /dev/null +++ b/highlight.js @@ -0,0 +1,2 @@ +/*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */ +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){s+=""}function c(e){("start"===e.event?o:u)(e.node)}for(var l=0,s="",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":I.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=""}function v(e){L+=e.cN?p(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,E=i||N,x={},L="";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,"",!0)+L);var k="",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&"\n"===e?"
":I.tabReplace?n.replace(/\t/g,I.tabReplace):""}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||"").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="
",I={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("vhdl",function(e){var r="\\d(_|\\d)*",t="[eE][-+]?"+r,n=r+"(\\."+r+")?("+t+")?",o="\\w+",i=r+"#"+o+"(\\."+o+")?#("+t+")?",a="\\b("+i+"|"+n+")";return{cI:!0,k:{keyword:"abs access after alias all and architecture array assert assume assume_guarantee attribute begin block body buffer bus case component configuration constant context cover disconnect downto default else elsif end entity exit fairness file for force function generate generic group guarded if impure in inertial inout is label library linkage literal loop map mod nand new next nor not null of on open or others out package port postponed procedure process property protected pure range record register reject release rem report restrict restrict_guarantee return rol ror select sequence severity shared signal sla sll sra srl strong subtype then to transport type unaffected units until use variable vmode vprop vunit wait when while with xnor xor",built_in:"boolean bit character integer time delay_length natural positive string bit_vector file_open_kind file_open_status std_logic std_logic_vector unsigned signed boolean_vector integer_vector std_ulogic std_ulogic_vector unresolved_unsigned u_unsigned unresolved_signed u_signedreal_vector time_vector",literal:"false true note warning error failure line text side width"},i:"{",c:[e.CBCM,e.C("--","$"),e.QSM,{cN:"number",b:a,r:0},{cN:"string",b:"'(U|X|0|1|Z|W|L|H|-)'",c:[e.BE]},{cN:"symbol",b:"'[A-Za-z](_?[A-Za-z0-9])*",c:[e.BE]}]}}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4f422c7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "lib": ["es6","dom"], + "sourceMap": true + }, + "files": [ + "VHDLFormatter.ts", + "VHDLFormatterUnitTests.ts" + ], + "exclude": [ + "node_modules", + ] +}