Browse Source

Fix for #43 (#44)

* UnitTests: Fix typename case expectations

* UnitTests: Fix two beautify3 false fails

* UnitTests: Add test for issue#43

* Introduce notion of Code Blocks to track state of indentation code

The previous approach meant that in nested indentation calls, if
code further down the stack split an input line, code further up
the stack would not update its iteration variables, leading to
duplication of some lines and removal of others.

To fix this, introduce a CodeBlock class that keeps track of nested
sub-blocks and updates all iteration variables in the call chain
if a line is being split. This also removes the need for a bunch
of parameters and return variables, so the function signatures
get a little shorter.

This fixes issue #43.
master
Joachim Fenkes 3 years ago
committed by GitHub
parent
commit
e95d09f082
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 362 additions and 307 deletions
  1. +149
    -144
      VHDLFormatter.js
  2. +161
    -147
      VHDLFormatter.ts
  3. +52
    -16
      tests/VHDLFormatterUnitTests.ts

+ 149
- 144
VHDLFormatter.js View File

@ -1,6 +1,6 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.RemoveAsserts = exports.ApplyNoNewLineAfter = exports.beautify3 = exports.beautifySemicolonBlock = exports.beautifyVariableInitialiseBlock = exports.beautifyPackageIsNewBlock = exports.beautifyComponentBlock = exports.beautifyCaseBlock = exports.AlignSign = exports.AlignSigns = exports.beautifyPortGenericBlock = exports.FormattedLineToString = exports.FormattedLine = exports.beautify = exports.BeautifierSettings = exports.signAlignSettings = exports.SetNewLinesAfterSymbols = exports.NewLineSettings = void 0;
exports.RemoveAsserts = exports.ApplyNoNewLineAfter = exports.beautify3 = exports.beautifySemicolonBlock = exports.beautifyVariableInitialiseBlock = exports.beautifyPackageIsNewBlock = exports.beautifyComponentBlock = exports.beautifyCaseBlock = exports.AlignSign = exports.AlignSigns = exports.beautifyPortGenericBlock = exports.FormattedLineToString = exports.CodeBlock = exports.FormattedLine = exports.beautify = exports.BeautifierSettings = exports.signAlignSettings = exports.SetNewLinesAfterSymbols = exports.NewLineSettings = void 0;
let isTesting = false; let isTesting = false;
const ILEscape = "@@"; const ILEscape = "@@";
const ILCommentPrefix = ILEscape + "comments"; const ILCommentPrefix = ILEscape + "comments";
@ -335,7 +335,8 @@ function beautify(input, settings) {
input = input.replace(/(\() +([+\-]) +(\w)/g, '$1$2$3'); // `( - 2)` -> `(-2)` input = input.replace(/(\() +([+\-]) +(\w)/g, '$1$2$3'); // `( - 2)` -> `(-2)`
arr = input.split("\r\n"); arr = input.split("\r\n");
let result = []; let result = [];
beautify3(arr, result, settings, 0, 0);
let block = new CodeBlock(arr);
beautify3(block, result, settings, 0);
var alignSettings = settings.SignAlignSettings; var alignSettings = settings.SignAlignSettings;
if (alignSettings != null && alignSettings.isAll) { if (alignSettings != null && alignSettings.isAll) {
AlignSigns(result, 0, result.length - 1, alignSettings.mode, alignSettings.alignComments); AlignSigns(result, 0, result.length - 1, alignSettings.mode, alignSettings.alignComments);
@ -386,6 +387,36 @@ class FormattedLine {
} }
} }
exports.FormattedLine = FormattedLine; exports.FormattedLine = FormattedLine;
class CodeBlock {
constructor(lines, start = 0, end = lines.length - 1) {
this.lines = lines;
this.start = start;
this.end = end;
this.parent = null;
this.cursor = start;
}
_notifySplit(atLine) {
if (this.start > atLine)
this.start++;
if (this.end >= atLine)
this.end++;
if (this.cursor >= atLine)
this.cursor++;
if (this.parent)
this.parent._notifySplit(atLine);
}
splitLine(atLine, firstText, secondText) {
this.lines[atLine] = firstText;
this.lines.splice(atLine + 1, 0, secondText);
this._notifySplit(atLine);
}
subBlock(start, end) {
let newBlock = new CodeBlock(this.lines, start, end);
newBlock.parent = this;
return newBlock;
}
}
exports.CodeBlock = CodeBlock;
function FormattedLineToString(arr, indentation) { function FormattedLineToString(arr, indentation) {
let result = []; let result = [];
if (arr == null) { if (arr == null) {
@ -410,82 +441,75 @@ function FormattedLineToString(arr, indentation) {
return result; return result;
} }
exports.FormattedLineToString = FormattedLineToString; exports.FormattedLineToString = FormattedLineToString;
function GetCloseparentheseEndIndex(inputs, startIndex) {
function GetCloseparentheseEndIndex(block) {
let openParentheseCount = 0; let openParentheseCount = 0;
let closeParentheseCount = 0; let closeParentheseCount = 0;
for (let i = startIndex; i < inputs.length; i++) {
let input = inputs[i];
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
let input = block.lines[block.cursor];
openParentheseCount += input.count("("); openParentheseCount += input.count("(");
closeParentheseCount += input.count(")"); closeParentheseCount += input.count(")");
if (openParentheseCount > 0 if (openParentheseCount > 0
&& openParentheseCount <= closeParentheseCount) { && openParentheseCount <= closeParentheseCount) {
return i;
return;
} }
} }
return startIndex;
block.cursor = startIndex;
} }
function beautifyPortGenericBlock(inputs, result, settings, startIndex, parentEndIndex, indent, mode) {
let firstLine = inputs[startIndex];
function beautifyPortGenericBlock(block, result, settings, indent, mode) {
let startIndex = block.cursor;
let firstLine = block.lines[startIndex];
let regex = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)"); let regex = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)");
if (!firstLine.regexStartsWith(regex)) { if (!firstLine.regexStartsWith(regex)) {
return [startIndex, parentEndIndex];
return;
} }
let firstLineHasParenthese = firstLine.indexOf("(") >= 0; let firstLineHasParenthese = firstLine.indexOf("(") >= 0;
let hasParenthese = firstLineHasParenthese;
let blockBodyStartIndex = startIndex;
let secondLineHasParenthese = startIndex + 1 < inputs.length && inputs[startIndex + 1].startsWith("(");
if (secondLineHasParenthese) {
hasParenthese = true;
blockBodyStartIndex++;
}
let endIndex = hasParenthese ? GetCloseparentheseEndIndex(inputs, startIndex) : startIndex;
let secondLineHasParenthese = startIndex + 1 <= block.end && block.lines[startIndex + 1].startsWith("(");
let hasParenthese = firstLineHasParenthese || secondLineHasParenthese;
let blockBodyStartIndex = startIndex + (secondLineHasParenthese ? 1 : 0);
if (hasParenthese) {
GetCloseparentheseEndIndex(block);
}
let endIndex = block.cursor;
let bodyBlock = block.subBlock(blockBodyStartIndex, endIndex);
if (endIndex != startIndex && firstLineHasParenthese) { if (endIndex != startIndex && firstLineHasParenthese) {
inputs[startIndex] = inputs[startIndex].replace(/\b(PORT|GENERIC|PROCEDURE)\b([\w ]+)\(([\w\(\) ]+)/, '$1$2(\r\n$3');
let newInputs = inputs[startIndex].split("\r\n");
block.lines[startIndex] = block.lines[startIndex].replace(/\b(PORT|GENERIC|PROCEDURE)\b([\w ]+)\(([\w\(\) ]+)/, '$1$2(\r\n$3');
let newInputs = block.lines[startIndex].split("\r\n");
if (newInputs.length == 2) { if (newInputs.length == 2) {
inputs[startIndex] = newInputs[0];
inputs.splice(startIndex + 1, 0, newInputs[1]);
endIndex++;
parentEndIndex++;
bodyBlock.splitLine(startIndex, newInputs[0], newInputs[1]);
} }
} }
else if (endIndex > startIndex + 1 && 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");
block.lines[startIndex + 1] = block.lines[startIndex + 1].replace(/\(([\w\(\) ]+)/, '(\r\n$1');
let newInputs = block.lines[startIndex + 1].split("\r\n");
if (newInputs.length == 2) { if (newInputs.length == 2) {
inputs[startIndex + 1] = newInputs[0];
inputs.splice(startIndex + 2, 0, newInputs[1]);
endIndex++;
parentEndIndex++;
bodyBlock.splitLine(startIndex + 1, newInputs[0], newInputs[1]);
} }
} }
if (firstLineHasParenthese && inputs[startIndex].indexOf("MAP") > 0) {
inputs[startIndex] = inputs[startIndex].replace(/([^\w])(MAP)\s+\(/g, '$1$2(');
if (firstLineHasParenthese && block.lines[startIndex].indexOf("MAP") > 0) {
block.lines[startIndex] = block.lines[startIndex].replace(/([^\w])(MAP)\s+\(/g, '$1$2(');
} }
result.push(new FormattedLine(inputs[startIndex], indent));
result.push(new FormattedLine(block.lines[startIndex], indent));
if (secondLineHasParenthese) { if (secondLineHasParenthese) {
let secondLineIndent = indent; let secondLineIndent = indent;
if (endIndex == startIndex + 1) { if (endIndex == startIndex + 1) {
secondLineIndent++; secondLineIndent++;
} }
result.push(new FormattedLine(inputs[startIndex + 1], secondLineIndent));
result.push(new FormattedLine(block.lines[startIndex + 1], secondLineIndent));
} }
let blockBodyEndIndex = endIndex;
let i = beautify3(inputs, result, settings, blockBodyStartIndex + 1, indent + 1, endIndex);
if (inputs[i].startsWith(")")) {
result[i].Indent--;
blockBodyEndIndex--;
beautify3(bodyBlock.subBlock(bodyBlock.start + 1, bodyBlock.end), result, settings, indent + 1);
if (block.lines[block.cursor].startsWith(")")) {
result[block.cursor].Indent--;
bodyBlock.end--;
} }
var alignSettings = settings.SignAlignSettings; var alignSettings = settings.SignAlignSettings;
if (alignSettings != null) { if (alignSettings != null) {
if (alignSettings.isRegional && !alignSettings.isAll if (alignSettings.isRegional && !alignSettings.isAll
&& alignSettings.keyWords != null && alignSettings.keyWords != null
&& alignSettings.keyWords.indexOf(mode) >= 0) { && alignSettings.keyWords.indexOf(mode) >= 0) {
blockBodyStartIndex++;
AlignSigns(result, blockBodyStartIndex, blockBodyEndIndex, alignSettings.mode, alignSettings.alignComments);
AlignSigns(result, bodyBlock.start + 1, bodyBlock.end, alignSettings.mode, alignSettings.alignComments);
} }
} }
return [i, parentEndIndex];
} }
exports.beautifyPortGenericBlock = beautifyPortGenericBlock; exports.beautifyPortGenericBlock = beautifyPortGenericBlock;
function AlignSigns(result, startIndex, endIndex, mode, alignComments = false) { function AlignSigns(result, startIndex, endIndex, mode, alignComments = false) {
@ -580,22 +604,22 @@ function AlignSign(result, startIndex, endIndex, symbol, maxSymbolIndex = -1, sy
} }
} }
exports.AlignSign = AlignSign; exports.AlignSign = AlignSign;
function beautifyCaseBlock(inputs, result, settings, startIndex, indent) {
if (!inputs[startIndex].regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
return startIndex;
function beautifyCaseBlock(block, result, settings, indent) {
if (!block.lines[block.cursor].regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
return;
} }
result.push(new FormattedLine(inputs[startIndex], indent));
let i = beautify3(inputs, result, settings, startIndex + 1, indent + 2);
result[i].Indent = indent;
return i;
result.push(new FormattedLine(block.lines[block.cursor], indent));
block.cursor++;
beautify3(block, result, settings, indent + 2);
result[block.cursor].Indent = indent;
} }
exports.beautifyCaseBlock = beautifyCaseBlock; exports.beautifyCaseBlock = beautifyCaseBlock;
function getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex) {
let endIndex = 0;
function getSemicolonBlockEndIndex(block, settings) {
let endIndex = block.cursor;
let openBracketsCount = 0; let openBracketsCount = 0;
let closeBracketsCount = 0; let closeBracketsCount = 0;
for (let i = startIndex; i < inputs.length; i++) {
let input = inputs[i];
for (; block.cursor <= block.end; block.cursor++) {
let input = block.lines[block.cursor];
let indexOfSemicolon = input.indexOf(";"); let indexOfSemicolon = input.indexOf(";");
let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1; let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1;
let stringBeforeSemicolon = input.substring(0, splitIndex); let stringBeforeSemicolon = input.substring(0, splitIndex);
@ -607,80 +631,62 @@ function getSemicolonBlockEndIndex(inputs, settings, startIndex, parentEndIndex)
continue; continue;
} }
if (openBracketsCount == closeBracketsCount) { if (openBracketsCount == closeBracketsCount) {
endIndex = i;
endIndex = block.cursor;
if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) { if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) {
inputs[i] = stringBeforeSemicolon;
inputs.splice(i, 0, stringAfterSemicolon);
parentEndIndex++;
block.splitLine(block.cursor, stringBeforeSemicolon, stringAfterSemicolon);
} }
break; break;
} }
} }
return [endIndex, parentEndIndex];
block.cursor = endIndex;
} }
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;
function beautifyComponentBlock(block, result, settings, indent) {
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
if (block.lines[block.cursor].regexStartsWith(/END(\s|$)/)) {
break; 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;
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
} }
return [endIndex, parentEndIndex];
} }
exports.beautifyComponentBlock = beautifyComponentBlock; exports.beautifyComponentBlock = beautifyComponentBlock;
function beautifyPackageIsNewBlock(inputs, result, settings, startIndex, parentEndIndex, indent) {
let endIndex = startIndex;
for (let i = startIndex; i < inputs.length; i++) {
if (inputs[i].regexIndexOf(/;(\s|$)/) >= 0) {
endIndex = i;
function beautifyPackageIsNewBlock(block, result, settings, indent) {
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
if (block.lines[block.cursor].regexIndexOf(/;(\s|$)/) >= 0) {
break; 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;
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
} }
return [endIndex, parentEndIndex];
} }
exports.beautifyPackageIsNewBlock = beautifyPackageIsNewBlock; exports.beautifyPackageIsNewBlock = beautifyPackageIsNewBlock;
function beautifyVariableInitialiseBlock(inputs, result, settings, startIndex, parentEndIndex, indent) {
let endIndex = startIndex;
for (let i = startIndex; i < inputs.length; i++) {
if (inputs[i].regexIndexOf(/;(\s|$)/) >= 0) {
endIndex = i;
function beautifyVariableInitialiseBlock(block, result, settings, indent) {
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
if (block.lines[block.cursor].regexIndexOf(/;(\s|$)/) >= 0) {
break; 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;
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
} }
return [endIndex, parentEndIndex];
} }
exports.beautifyVariableInitialiseBlock = beautifyVariableInitialiseBlock; exports.beautifyVariableInitialiseBlock = beautifyVariableInitialiseBlock;
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) {
beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex);
alignSignalAssignmentBlock(settings, inputs, startIndex, endIndex, result);
function beautifySemicolonBlock(block, result, settings, indent) {
let startIndex = block.cursor;
getSemicolonBlockEndIndex(block, settings);
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
alignSignalAssignmentBlock(settings, block.lines, startIndex, block.cursor, result);
} }
return [endIndex, parentEndIndex];
} }
exports.beautifySemicolonBlock = beautifySemicolonBlock; exports.beautifySemicolonBlock = beautifySemicolonBlock;
function alignSignalAssignmentBlock(settings, inputs, startIndex, endIndex, result) { function alignSignalAssignmentBlock(settings, inputs, startIndex, endIndex, result) {
@ -698,8 +704,7 @@ function alignSignalAssignmentBlock(settings, inputs, startIndex, endIndex, resu
} }
} }
} }
function beautify3(inputs, result, settings, startIndex, indent, endIndex) {
let i;
function beautify3(block, result, settings, indent) {
let regexOneLineBlockKeyWords = new RegExp(/(PROCEDURE)[^\w](?!.+[^\w]IS([^\w]|$))/); //match PROCEDURE..; but not PROCEDURE .. IS; 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 regexFunctionMultiLineBlockKeyWords = new RegExp(/(FUNCTION|IMPURE FUNCTION)[^\w](?=.+[^\w]IS([^\w]|$))/); //match FUNCTION .. IS; but not FUNCTION
let blockMidKeyWords = ["BEGIN"]; let blockMidKeyWords = ["BEGIN"];
@ -741,29 +746,26 @@ function beautify3(inputs, result, settings, startIndex, indent, endIndex) {
let regexblockEndsWithSemicolon = blockEndsWithSemicolon.convertToRegexBlockWords(); let regexblockEndsWithSemicolon = blockEndsWithSemicolon.convertToRegexBlockWords();
let regexMidKeyWhen = "WHEN".convertToRegexBlockWords(); let regexMidKeyWhen = "WHEN".convertToRegexBlockWords();
let regexMidKeyElse = "ELSE|ELSIF".convertToRegexBlockWords(); let regexMidKeyElse = "ELSE|ELSIF".convertToRegexBlockWords();
if (endIndex == null) {
endIndex = inputs.length - 1;
}
for (i = startIndex; i <= endIndex; i++) {
for (; block.cursor <= block.end; block.cursor++) {
if (indent < 0) { if (indent < 0) {
indent = 0; indent = 0;
} }
let input = inputs[i].trim();
let input = block.lines[block.cursor].trim();
if (input.regexStartsWith(regexBlockIndentedEndsKeyWords)) { if (input.regexStartsWith(regexBlockIndentedEndsKeyWords)) {
result.push(new FormattedLine(input, indent)); result.push(new FormattedLine(input, indent));
return i;
return;
} }
if (input.regexStartsWith(/COMPONENT\s/)) { if (input.regexStartsWith(/COMPONENT\s/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifyComponentBlock(inputs, result, settings, i, endIndex, indent);
beautifyComponentBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (input.regexStartsWith(/PACKAGE[\s\w]+IS\s+NEW/)) { if (input.regexStartsWith(/PACKAGE[\s\w]+IS\s+NEW/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifyPackageIsNewBlock(inputs, result, settings, i, endIndex, indent);
beautifyPackageIsNewBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
@ -771,10 +773,10 @@ function beautify3(inputs, result, settings, startIndex, indent, endIndex) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
let endsWithBracket = input.regexIndexOf(/:\s*=\s*\(/) > 0; let endsWithBracket = input.regexIndexOf(/:\s*=\s*\(/) > 0;
let startIndex = i;
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
if (endsWithBracket && startIndex != i) {
let fl = result[endIndex];
let startIndex = block.cursor;
beautifySemicolonBlock(block, result, settings, indent);
if (endsWithBracket && startIndex != block.cursor) {
let fl = result[block.end];
if (fl.Line.regexStartsWith(/\);$/)) { if (fl.Line.regexStartsWith(/\);$/)) {
fl.Indent--; fl.Indent--;
} }
@ -785,96 +787,99 @@ function beautify3(inputs, result, settings, startIndex, indent, endIndex) {
if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) { if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
beautifySemicolonBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) { if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
beautifySemicolonBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) { if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.CaseWhen; Mode = FormatMode.CaseWhen;
i = beautifyCaseBlock(inputs, result, settings, i, indent);
beautifyCaseBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*(:=)([\s]|$)/)) { if (input.regexStartsWith(/[\w\s:]*(:=)([\s]|$)/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, ":=");
beautifyPortGenericBlock(block, result, settings, indent, ":=");
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*\bPORT\b([\s]|$)/)) { if (input.regexStartsWith(/[\w\s:]*\bPORT\b([\s]|$)/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PORT");
beautifyPortGenericBlock(block, result, settings, indent, "PORT");
continue; continue;
} }
if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) { if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IS");
beautifyPortGenericBlock(block, result, settings, indent, "IS");
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) { if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "GENERIC");
beautifyPortGenericBlock(block, result, settings, indent, "GENERIC");
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*PROCEDURE[\s\w]+\($/)) { 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);
beautifyPortGenericBlock(block, result, settings, indent, "PROCEDURE");
if (block.lines[block.cursor].regexStartsWith(/.*\)[\s]*IS/)) {
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
continue; continue;
} }
if (input.regexStartsWith(/FUNCTION[^\w]/) if (input.regexStartsWith(/FUNCTION[^\w]/)
&& input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { && 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);
beautifyPortGenericBlock(block, result, settings, indent, "FUNCTION");
if (!block.lines[block.cursor].regexStartsWith(regexBlockEndsKeyWords)) {
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
else { else {
result[i].Indent++;
result[block.cursor].Indent++;
} }
continue; continue;
} }
if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/) if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/)
&& input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { && input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IMPURE FUNCTION");
if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) {
if (inputs[i].regexStartsWith(regexBlockIndentedEndsKeyWords)) {
result[i].Indent++;
beautifyPortGenericBlock(block, result, settings, indent, "IMPURE FUNCTION");
if (!block.lines[block.cursor].regexStartsWith(regexBlockEndsKeyWords)) {
if (block.lines[block.cursor].regexStartsWith(regexBlockIndentedEndsKeyWords)) {
result[block.cursor].Indent++;
} }
else { else {
i = beautify3(inputs, result, settings, i + 1, indent + 1);
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
} }
else { else {
result[i].Indent++;
result[block.cursor].Indent++;
} }
continue; continue;
} }
result.push(new FormattedLine(input, indent)); result.push(new FormattedLine(input, indent));
if (startIndex != 0
if (indent > 0
&& (input.regexStartsWith(regexBlockMidKeyWords) && (input.regexStartsWith(regexBlockMidKeyWords)
|| (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse)) || (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse))
|| (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) { || (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) {
result[i].Indent--;
result[block.cursor].Indent--;
} }
else if (startIndex != 0
else if (indent > 0
&& (input.regexStartsWith(regexBlockEndsKeyWords))) { && (input.regexStartsWith(regexBlockEndsKeyWords))) {
result[i].Indent--;
return i;
result[block.cursor].Indent--;
return;
} }
if (input.regexStartsWith(regexOneLineBlockKeyWords)) { if (input.regexStartsWith(regexOneLineBlockKeyWords)) {
continue; continue;
} }
if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords) if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords)
|| input.regexStartsWith(regexBlockStartsKeywords)) { || input.regexStartsWith(regexBlockStartsKeywords)) {
i = beautify3(inputs, result, settings, i + 1, indent + 1);
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
} }
i--;
return i;
block.cursor--;
} }
exports.beautify3 = beautify3; exports.beautify3 = beautify3;
function ReserveSemicolonInKeywords(arr) { function ReserveSemicolonInKeywords(arr) {


+ 161
- 147
VHDLFormatter.ts View File

@ -390,7 +390,8 @@ export function beautify(input: string, settings: BeautifierSettings) {
input = input.replace(/(\() +([+\-]) +(\w)/g, '$1$2$3');// `( - 2)` -> `(-2)` input = input.replace(/(\() +([+\-]) +(\w)/g, '$1$2$3');// `( - 2)` -> `(-2)`
arr = input.split("\r\n"); arr = input.split("\r\n");
let result: (FormattedLine | FormattedLine[])[] = []; let result: (FormattedLine | FormattedLine[])[] = [];
beautify3(arr, result, settings, 0, 0);
let block = new CodeBlock(arr);
beautify3(block, result, settings, 0);
var alignSettings = settings.SignAlignSettings; var alignSettings = settings.SignAlignSettings;
if (alignSettings != null && alignSettings.isAll) { if (alignSettings != null && alignSettings.isAll) {
AlignSigns(result, 0, result.length - 1, alignSettings.mode, alignSettings.alignComments); AlignSigns(result, 0, result.length - 1, alignSettings.mode, alignSettings.alignComments);
@ -448,6 +449,45 @@ export class FormattedLine {
} }
} }
export class CodeBlock {
lines: Array<string>;
start: number; // index of first line of range
end: number; // index of last line of range
cursor: number; // line currently being processed
parent: CodeBlock;
constructor(lines: Array<string>, start = 0, end = lines.length - 1) {
this.lines = lines;
this.start = start;
this.end = end;
this.parent = null;
this.cursor = start;
}
_notifySplit(atLine: number) {
if (this.start > atLine)
this.start++;
if (this.end >= atLine)
this.end++;
if (this.cursor >= atLine)
this.cursor++;
if (this.parent)
this.parent._notifySplit(atLine);
}
splitLine(atLine: number, firstText: string, secondText: string) {
this.lines[atLine] = firstText;
this.lines.splice(atLine + 1, 0, secondText);
this._notifySplit(atLine);
}
subBlock(start: number, end: number): CodeBlock {
let newBlock = new CodeBlock(this.lines, start, end);
newBlock.parent = this;
return newBlock;
}
}
export function FormattedLineToString(arr: (FormattedLine | FormattedLine[])[], indentation: string): Array<string> { export function FormattedLineToString(arr: (FormattedLine | FormattedLine[])[], indentation: string): Array<string> {
let result: Array<string> = []; let result: Array<string> = [];
if (arr == null) { if (arr == null) {
@ -472,83 +512,81 @@ export function FormattedLineToString(arr: (FormattedLine | FormattedLine[])[],
return result; return result;
} }
function GetCloseparentheseEndIndex(inputs: Array<string>, startIndex: number): number {
function GetCloseparentheseEndIndex(block: CodeBlock) {
let openParentheseCount: number = 0; let openParentheseCount: number = 0;
let closeParentheseCount: number = 0; let closeParentheseCount: number = 0;
for (let i = startIndex; i < inputs.length; i++) {
let input = inputs[i];
let startIndex = block.cursor;
for (;block.cursor <= block.end; block.cursor++) {
let input = block.lines[block.cursor];
openParentheseCount += input.count("("); openParentheseCount += input.count("(");
closeParentheseCount += input.count(")"); closeParentheseCount += input.count(")");
if (openParentheseCount > 0 if (openParentheseCount > 0
&& openParentheseCount <= closeParentheseCount) { && openParentheseCount <= closeParentheseCount) {
return i;
return;
} }
} }
return startIndex;
block.cursor = startIndex;
} }
export function beautifyPortGenericBlock(inputs: Array<string>, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, parentEndIndex: number, indent: number, mode: string): [number, number] {
let firstLine: string = inputs[startIndex];
export function beautifyPortGenericBlock(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number, mode: string) {
let startIndex = block.cursor;
let firstLine: string = block.lines[startIndex];
let regex: RegExp = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)"); let regex: RegExp = new RegExp("[\\w\\s:]*(" + mode + ")([\\s]|$)");
if (!firstLine.regexStartsWith(regex)) { if (!firstLine.regexStartsWith(regex)) {
return [startIndex, parentEndIndex];
return;
} }
let firstLineHasParenthese: boolean = firstLine.indexOf("(") >= 0; let firstLineHasParenthese: boolean = firstLine.indexOf("(") >= 0;
let hasParenthese: boolean = firstLineHasParenthese;
let blockBodyStartIndex = startIndex;
let secondLineHasParenthese: boolean = startIndex + 1 < inputs.length && inputs[startIndex + 1].startsWith("(");
if (secondLineHasParenthese) {
hasParenthese = true;
blockBodyStartIndex++;
let secondLineHasParenthese: boolean = startIndex + 1 <= block.end && block.lines[startIndex + 1].startsWith("(");
let hasParenthese: boolean = firstLineHasParenthese || secondLineHasParenthese;
let blockBodyStartIndex = startIndex + (secondLineHasParenthese ? 1 : 0);
if (hasParenthese) {
GetCloseparentheseEndIndex(block);
} }
let endIndex: number = hasParenthese ? GetCloseparentheseEndIndex(inputs, startIndex) : startIndex;
let endIndex: number = block.cursor;
let bodyBlock = block.subBlock(blockBodyStartIndex, endIndex);
if (endIndex != startIndex && firstLineHasParenthese) { if (endIndex != startIndex && firstLineHasParenthese) {
inputs[startIndex] = inputs[startIndex].replace(/\b(PORT|GENERIC|PROCEDURE)\b([\w ]+)\(([\w\(\) ]+)/, '$1$2(\r\n$3');
let newInputs = inputs[startIndex].split("\r\n");
block.lines[startIndex] = block.lines[startIndex].replace(/\b(PORT|GENERIC|PROCEDURE)\b([\w ]+)\(([\w\(\) ]+)/, '$1$2(\r\n$3');
let newInputs = block.lines[startIndex].split("\r\n");
if (newInputs.length == 2) { if (newInputs.length == 2) {
inputs[startIndex] = newInputs[0];
inputs.splice(startIndex + 1, 0, newInputs[1]);
endIndex++;
parentEndIndex++;
bodyBlock.splitLine(startIndex, newInputs[0], newInputs[1]);
} }
} }
else if (endIndex > startIndex + 1 && 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");
block.lines[startIndex + 1] = block.lines[startIndex + 1].replace(/\(([\w\(\) ]+)/, '(\r\n$1');
let newInputs = block.lines[startIndex + 1].split("\r\n");
if (newInputs.length == 2) { if (newInputs.length == 2) {
inputs[startIndex + 1] = newInputs[0];
inputs.splice(startIndex + 2, 0, newInputs[1]);
endIndex++;
parentEndIndex++;
bodyBlock.splitLine(startIndex + 1, newInputs[0], newInputs[1]);
} }
} }
if (firstLineHasParenthese && inputs[startIndex].indexOf("MAP") > 0) {
inputs[startIndex] = inputs[startIndex].replace(/([^\w])(MAP)\s+\(/g, '$1$2(');
if (firstLineHasParenthese && block.lines[startIndex].indexOf("MAP") > 0) {
block.lines[startIndex] = block.lines[startIndex].replace(/([^\w])(MAP)\s+\(/g, '$1$2(');
} }
result.push(new FormattedLine(inputs[startIndex], indent));
result.push(new FormattedLine(block.lines[startIndex], indent));
if (secondLineHasParenthese) { if (secondLineHasParenthese) {
let secondLineIndent = indent; let secondLineIndent = indent;
if (endIndex == startIndex + 1) { if (endIndex == startIndex + 1) {
secondLineIndent++; secondLineIndent++;
} }
result.push(new FormattedLine(inputs[startIndex + 1], secondLineIndent));
result.push(new FormattedLine(block.lines[startIndex + 1], secondLineIndent));
} }
let blockBodyEndIndex = endIndex;
let i = beautify3(inputs, result, settings, blockBodyStartIndex + 1, indent + 1, endIndex);
if (inputs[i].startsWith(")")) {
(<FormattedLine>result[i]).Indent--;
blockBodyEndIndex--;
beautify3(bodyBlock.subBlock(bodyBlock.start + 1, bodyBlock.end), result, settings, indent + 1);
if (block.lines[block.cursor].startsWith(")")) {
(<FormattedLine>result[block.cursor]).Indent--;
bodyBlock.end--;
} }
var alignSettings = settings.SignAlignSettings; var alignSettings = settings.SignAlignSettings;
if (alignSettings != null) { if (alignSettings != null) {
if (alignSettings.isRegional && !alignSettings.isAll if (alignSettings.isRegional && !alignSettings.isAll
&& alignSettings.keyWords != null && alignSettings.keyWords != null
&& alignSettings.keyWords.indexOf(mode) >= 0) { && alignSettings.keyWords.indexOf(mode) >= 0) {
blockBodyStartIndex++;
AlignSigns(result, blockBodyStartIndex, blockBodyEndIndex, alignSettings.mode, alignSettings.alignComments);
AlignSigns(result, bodyBlock.start + 1, bodyBlock.end, alignSettings.mode, alignSettings.alignComments);
} }
} }
return [i, parentEndIndex];
} }
export function AlignSigns(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number, mode: string, alignComments: boolean = false) { export function AlignSigns(result: (FormattedLine | FormattedLine[])[], startIndex: number, endIndex: number, mode: string, alignComments: boolean = false) {
@ -646,23 +684,22 @@ export function AlignSign(result: (FormattedLine | FormattedLine[])[], startInde
} }
} }
export function beautifyCaseBlock(inputs: Array<string>, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number): number {
if (!inputs[startIndex].regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
return startIndex;
export function beautifyCaseBlock(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) {
if (!block.lines[block.cursor].regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
return;
} }
result.push(new FormattedLine(inputs[startIndex], indent));
let i = beautify3(inputs, result, settings, startIndex + 1, indent + 2);
(<FormattedLine>result[i]).Indent = indent;
return i;
result.push(new FormattedLine(block.lines[block.cursor], indent));
block.cursor++;
beautify3(block, result, settings, indent + 2);
(<FormattedLine>result[block.cursor]).Indent = indent;
} }
function getSemicolonBlockEndIndex(inputs: Array<string>, settings: BeautifierSettings, startIndex: number, parentEndIndex: number): [number, number] {
let endIndex = 0;
function getSemicolonBlockEndIndex(block: CodeBlock, settings: BeautifierSettings) {
let endIndex = block.cursor;
let openBracketsCount = 0; let openBracketsCount = 0;
let closeBracketsCount = 0; let closeBracketsCount = 0;
for (let i = startIndex; i < inputs.length; i++) {
let input = inputs[i];
for (; block.cursor <= block.end; block.cursor++) {
let input = block.lines[block.cursor];
let indexOfSemicolon = input.indexOf(";"); let indexOfSemicolon = input.indexOf(";");
let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1; let splitIndex = indexOfSemicolon < 0 ? input.length : indexOfSemicolon + 1;
let stringBeforeSemicolon = input.substring(0, splitIndex); let stringBeforeSemicolon = input.substring(0, splitIndex);
@ -674,85 +711,63 @@ function getSemicolonBlockEndIndex(inputs: Array<string>, settings: BeautifierSe
continue; continue;
} }
if (openBracketsCount == closeBracketsCount) { if (openBracketsCount == closeBracketsCount) {
endIndex = i;
endIndex = block.cursor;
if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) { if (stringAfterSemicolon.trim().length > 0 && settings.NewLineSettings.newLineAfter.indexOf(";") >= 0) {
inputs[i] = stringBeforeSemicolon;
inputs.splice(i, 0, stringAfterSemicolon);
parentEndIndex++;
block.splitLine(block.cursor, stringBeforeSemicolon, stringAfterSemicolon);
} }
break; break;
} }
} }
return [endIndex, parentEndIndex];
block.cursor = endIndex;
} }
export function beautifyComponentBlock(inputs: Array<string>, 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;
export function beautifyComponentBlock(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) {
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
if (block.lines[block.cursor].regexStartsWith(/END(\s|$)/)) {
break; 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;
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
} }
return [endIndex, parentEndIndex];
} }
export function beautifyPackageIsNewBlock(inputs: Array<string>, 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].regexIndexOf(/;(\s|$)/) >= 0) {
endIndex = i;
export function beautifyPackageIsNewBlock(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) {
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
if (block.lines[block.cursor].regexIndexOf(/;(\s|$)/) >= 0) {
break; 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;
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
} }
return [endIndex, parentEndIndex];
} }
export function beautifyVariableInitialiseBlock(inputs: Array<string>, 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].regexIndexOf(/;(\s|$)/) >= 0) {
endIndex = i;
export function beautifyVariableInitialiseBlock(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) {
let startIndex = block.cursor;
for (; block.cursor <= block.end; block.cursor++) {
if (block.lines[block.cursor].regexIndexOf(/;(\s|$)/) >= 0) {
break; 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;
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
} }
return [endIndex, parentEndIndex];
} }
export function beautifySemicolonBlock(inputs: Array<string>, 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) {
beautify3(inputs, result, settings, startIndex + 1, indent + 1, endIndex);
alignSignalAssignmentBlock(settings, inputs, startIndex, endIndex, result);
export function beautifySemicolonBlock(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) {
let startIndex = block.cursor;
getSemicolonBlockEndIndex(block, settings);
result.push(new FormattedLine(block.lines[startIndex], indent));
if (block.cursor != startIndex) {
beautify3(block.subBlock(startIndex + 1, block.cursor), result, settings, indent + 1);
alignSignalAssignmentBlock(settings, block.lines, startIndex, block.cursor, result);
} }
return [endIndex, parentEndIndex];
} }
function alignSignalAssignmentBlock(settings: BeautifierSettings, inputs: string[], startIndex: number, endIndex: number, result: (FormattedLine | FormattedLine[])[]) { function alignSignalAssignmentBlock(settings: BeautifierSettings, inputs: string[], startIndex: number, endIndex: number, result: (FormattedLine | FormattedLine[])[]) {
@ -771,8 +786,7 @@ function alignSignalAssignmentBlock(settings: BeautifierSettings, inputs: string
} }
} }
export function beautify3(inputs: Array<string>, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number, endIndex?: number): number {
let i: number;
export function beautify3(block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) {
let regexOneLineBlockKeyWords: RegExp = new RegExp(/(PROCEDURE)[^\w](?!.+[^\w]IS([^\w]|$))/);//match PROCEDURE..; but not PROCEDURE .. IS; 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 regexFunctionMultiLineBlockKeyWords: RegExp = new RegExp(/(FUNCTION|IMPURE FUNCTION)[^\w](?=.+[^\w]IS([^\w]|$))/);//match FUNCTION .. IS; but not FUNCTION
let blockMidKeyWords: Array<string> = ["BEGIN"]; let blockMidKeyWords: Array<string> = ["BEGIN"];
@ -814,29 +828,26 @@ export function beautify3(inputs: Array<string>, result: (FormattedLine | Format
let regexblockEndsWithSemicolon: RegExp = blockEndsWithSemicolon.convertToRegexBlockWords(); let regexblockEndsWithSemicolon: RegExp = blockEndsWithSemicolon.convertToRegexBlockWords();
let regexMidKeyWhen: RegExp = "WHEN".convertToRegexBlockWords(); let regexMidKeyWhen: RegExp = "WHEN".convertToRegexBlockWords();
let regexMidKeyElse: RegExp = "ELSE|ELSIF".convertToRegexBlockWords(); let regexMidKeyElse: RegExp = "ELSE|ELSIF".convertToRegexBlockWords();
if (endIndex == null) {
endIndex = inputs.length - 1;
}
for (i = startIndex; i <= endIndex; i++) {
for (; block.cursor <= block.end; block.cursor++) {
if (indent < 0) { if (indent < 0) {
indent = 0; indent = 0;
} }
let input: string = inputs[i].trim();
let input: string = block.lines[block.cursor].trim();
if (input.regexStartsWith(regexBlockIndentedEndsKeyWords)) { if (input.regexStartsWith(regexBlockIndentedEndsKeyWords)) {
result.push(new FormattedLine(input, indent)); result.push(new FormattedLine(input, indent));
return i;
return;
} }
if (input.regexStartsWith(/COMPONENT\s/)) { if (input.regexStartsWith(/COMPONENT\s/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifyComponentBlock(inputs, result, settings, i, endIndex, indent);
beautifyComponentBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (input.regexStartsWith(/PACKAGE[\s\w]+IS\s+NEW/)) { if (input.regexStartsWith(/PACKAGE[\s\w]+IS\s+NEW/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifyPackageIsNewBlock(inputs, result, settings, i, endIndex, indent);
beautifyPackageIsNewBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
@ -844,10 +855,10 @@ export function beautify3(inputs: Array<string>, result: (FormattedLine | Format
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
let endsWithBracket = input.regexIndexOf(/:\s*=\s*\(/) > 0; let endsWithBracket = input.regexIndexOf(/:\s*=\s*\(/) > 0;
let startIndex = i;
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
if (endsWithBracket && startIndex != i) {
let fl = result[endIndex] as FormattedLine;
let startIndex = block.cursor;
beautifySemicolonBlock(block, result, settings, indent);
if (endsWithBracket && startIndex != block.cursor) {
let fl = result[block.end] as FormattedLine;
if (fl.Line.regexStartsWith(/\);$/)) { if (fl.Line.regexStartsWith(/\);$/)) {
fl.Indent--; fl.Indent--;
} }
@ -858,93 +869,96 @@ export function beautify3(inputs: Array<string>, result: (FormattedLine | Format
if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) { if (input.regexStartsWith(/\w+\s*:\s*ENTITY/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
beautifySemicolonBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) { if (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexblockEndsWithSemicolon)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.EndsWithSemicolon; Mode = FormatMode.EndsWithSemicolon;
[i, endIndex] = beautifySemicolonBlock(inputs, result, settings, i, endIndex, indent);
beautifySemicolonBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) { if (input.regexStartsWith(/(.+:\s*)?(CASE)([\s]|$)/)) {
let modeCache = Mode; let modeCache = Mode;
Mode = FormatMode.CaseWhen; Mode = FormatMode.CaseWhen;
i = beautifyCaseBlock(inputs, result, settings, i, indent);
beautifyCaseBlock(block, result, settings, indent);
Mode = modeCache; Mode = modeCache;
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*(:=)([\s]|$)/)) { if (input.regexStartsWith(/[\w\s:]*(:=)([\s]|$)/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, ":=");
beautifyPortGenericBlock(block, result, settings, indent, ":=");
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*\bPORT\b([\s]|$)/)) { if (input.regexStartsWith(/[\w\s:]*\bPORT\b([\s]|$)/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "PORT");
beautifyPortGenericBlock(block, result, settings, indent, "PORT");
continue; continue;
} }
if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) { if (input.regexStartsWith(/TYPE\s+\w+\s+IS\s+\(/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IS");
beautifyPortGenericBlock(block, result, settings, indent, "IS");
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) { if (input.regexStartsWith(/[\w\s:]*GENERIC([\s]|$)/)) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "GENERIC");
beautifyPortGenericBlock(block, result, settings, indent, "GENERIC");
continue; continue;
} }
if (input.regexStartsWith(/[\w\s:]*PROCEDURE[\s\w]+\($/)) { 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);
beautifyPortGenericBlock(block, result, settings, indent, "PROCEDURE");
if (block.lines[block.cursor].regexStartsWith(/.*\)[\s]*IS/)) {
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
continue; continue;
} }
if (input.regexStartsWith(/FUNCTION[^\w]/) if (input.regexStartsWith(/FUNCTION[^\w]/)
&& input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { && 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);
beautifyPortGenericBlock(block, result, settings, indent, "FUNCTION");
if (!block.lines[block.cursor].regexStartsWith(regexBlockEndsKeyWords)) {
block.cursor++;
beautify3(block, result, settings, indent + 1);
} else { } else {
(<FormattedLine>result[i]).Indent++;
(<FormattedLine>result[block.cursor]).Indent++;
} }
continue; continue;
} }
if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/) if (input.regexStartsWith(/IMPURE FUNCTION[^\w]/)
&& input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) { && input.regexIndexOf(/[^\w]RETURN[^\w]/) < 0) {
[i, endIndex] = beautifyPortGenericBlock(inputs, result, settings, i, endIndex, indent, "IMPURE FUNCTION");
if (!inputs[i].regexStartsWith(regexBlockEndsKeyWords)) {
if (inputs[i].regexStartsWith(regexBlockIndentedEndsKeyWords)) {
(<FormattedLine>result[i]).Indent++;
beautifyPortGenericBlock(block, result, settings, indent, "IMPURE FUNCTION");
if (!block.lines[block.cursor].regexStartsWith(regexBlockEndsKeyWords)) {
if (block.lines[block.cursor].regexStartsWith(regexBlockIndentedEndsKeyWords)) {
(<FormattedLine>result[block.cursor]).Indent++;
} else { } else {
i = beautify3(inputs, result, settings, i + 1, indent + 1);
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
} else { } else {
(<FormattedLine>result[i]).Indent++;
(<FormattedLine>result[block.cursor]).Indent++;
} }
continue; continue;
} }
result.push(new FormattedLine(input, indent)); result.push(new FormattedLine(input, indent));
if (startIndex != 0
if (indent > 0
&& (input.regexStartsWith(regexBlockMidKeyWords) && (input.regexStartsWith(regexBlockMidKeyWords)
|| (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse)) || (Mode != FormatMode.EndsWithSemicolon && input.regexStartsWith(regexMidKeyElse))
|| (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) { || (Mode == FormatMode.CaseWhen && input.regexStartsWith(regexMidKeyWhen)))) {
(<FormattedLine>result[i]).Indent--;
(<FormattedLine>result[block.cursor]).Indent--;
} }
else if (startIndex != 0
else if (indent > 0
&& (input.regexStartsWith(regexBlockEndsKeyWords))) { && (input.regexStartsWith(regexBlockEndsKeyWords))) {
(<FormattedLine>result[i]).Indent--;
return i;
(<FormattedLine>result[block.cursor]).Indent--;
return;
} }
if (input.regexStartsWith(regexOneLineBlockKeyWords)) { if (input.regexStartsWith(regexOneLineBlockKeyWords)) {
continue; continue;
} }
if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords) if (input.regexStartsWith(regexFunctionMultiLineBlockKeyWords)
|| input.regexStartsWith(regexBlockStartsKeywords)) { || input.regexStartsWith(regexBlockStartsKeywords)) {
i = beautify3(inputs, result, settings, i + 1, indent + 1);
block.cursor++;
beautify3(block, result, settings, indent + 1);
} }
} }
i--;
return i;
block.cursor--;
} }
function ReserveSemicolonInKeywords(arr: Array<string>) { function ReserveSemicolonInKeywords(arr: Array<string>) {


+ 52
- 16
tests/VHDLFormatterUnitTests.ts View File

@ -4,7 +4,7 @@ import { BeautifierSettings } from "../VHDLFormatter";
import { RemoveAsserts } from "../VHDLFormatter"; import { RemoveAsserts } from "../VHDLFormatter";
import { ApplyNoNewLineAfter } from "../VHDLFormatter"; import { ApplyNoNewLineAfter } from "../VHDLFormatter";
import { SetNewLinesAfterSymbols } from "../VHDLFormatter"; import { SetNewLinesAfterSymbols } from "../VHDLFormatter";
import { beautify3 } from "../VHDLFormatter";
import { CodeBlock, beautify3 } from "../VHDLFormatter";
import { FormattedLine } from "../VHDLFormatter"; import { FormattedLine } from "../VHDLFormatter";
import { FormattedLineToString } from "../VHDLFormatter"; import { FormattedLineToString } from "../VHDLFormatter";
import { CompareString } from "./assert"; import { CompareString } from "./assert";
@ -75,6 +75,7 @@ function UnitTestbeautify3() {
Beautify3Case19(); Beautify3Case19();
Beautify3Case20(); Beautify3Case20();
Beautify3Case21(); Beautify3Case21();
Beautify3Case22();
} }
function Beautify3Case1() { function Beautify3Case1() {
@ -471,8 +472,8 @@ function Beautify3Case16() {
]; ];
let expected: (FormattedLine | FormattedLine[])[] = [ let expected: (FormattedLine | FormattedLine[])[] = [
new FormattedLine("x <= 1 WHEN foo", 0), new FormattedLine("x <= 1 WHEN foo", 0),
new FormattedLine("ELSE 2 WHEN bar", 1),
new FormattedLine("ELSE 3;", 1),
new FormattedLine(" ELSE 2 WHEN bar", 1),
new FormattedLine(" ELSE 3;", 1),
new FormattedLine("y <= 2;", 0) new FormattedLine("y <= 2;", 0)
]; ];
UnitTest6(beautify3, "one line ends with ;", settings, inputs, expected, 0, expected.length - 1, 0); UnitTest6(beautify3, "one line ends with ;", settings, inputs, expected, 0, expected.length - 1, 0);
@ -562,7 +563,7 @@ function Beautify3Case20() {
]; ];
let expected: (FormattedLine | FormattedLine[])[] = [ let expected: (FormattedLine | FormattedLine[])[] = [
new FormattedLine("m <= ((1, 2, 3, 4)", 0), new FormattedLine("m <= ((1, 2, 3, 4)", 0),
new FormattedLine("(5, 6, 7, 8));", 1),
new FormattedLine(" (5, 6, 7, 8));", 1),
new FormattedLine("y <= 2;", 0) new FormattedLine("y <= 2;", 0)
]; ];
UnitTest6(beautify3, "function", settings, inputs, expected, 0, expected.length - 1, 0); UnitTest6(beautify3, "function", settings, inputs, expected, 0, expected.length - 1, 0);
@ -590,6 +591,39 @@ function Beautify3Case21() {
UnitTest6(beautify3, "function", settings, inputs, expected, 0, expected.length - 1, 0); UnitTest6(beautify3, "function", settings, inputs, expected, 0, expected.length - 1, 0);
} }
function Beautify3Case22() {
let new_line_after_symbols: NewLineSettings = new NewLineSettings();
new_line_after_symbols.newLineAfter = ["then", ";"];
let settings = getDefaultBeautifierSettings(new_line_after_symbols);
let inputs: Array<string> = [
"test: ENTITY work.testing",
"GENERIC MAP( x => 1,",
"y => 2",
")",
"PORT MAP( z => OPEN,",
"w => '1'",
");",
"",
"foo <= '1';",
"bar <= '1';",
];
let expected: (FormattedLine | FormattedLine[])[] = [
new FormattedLine("test: ENTITY work.testing", 0),
new FormattedLine("GENERIC MAP(", 1),
new FormattedLine("x => 1,", 2),
new FormattedLine("y => 2", 2),
new FormattedLine(")", 1),
new FormattedLine("PORT MAP(", 1),
new FormattedLine("z => OPEN,", 2),
new FormattedLine("w => '1'", 2),
new FormattedLine(");", 1),
new FormattedLine("", 0),
new FormattedLine("foo <= '1';", 0),
new FormattedLine("bar <= '1';", 0),
];
UnitTest6(beautify3, "inserted line breaks in generic maps (issue #43)", settings, inputs, expected, 0, expected.length - 1, 0);
}
function UnitTestSetNewLinesAfterSymbols() { function UnitTestSetNewLinesAfterSymbols() {
console.log("=== SetNewLinesAfterSymbols ==="); console.log("=== SetNewLinesAfterSymbols ===");
let input = "a; @@comments1\r\nb;" let input = "a; @@comments1\r\nb;"
@ -712,7 +746,7 @@ type Array2Callback = (arr: Array<string>, parameters: Array<string>) => void;
type String2Callback = (text: string, parameters: NewLineSettings) => string; type String2Callback = (text: string, parameters: NewLineSettings) => string;
type BeautifyCallback = (inputs: Array<string>, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, startIndex: number, indent: number) => number;
type BeautifyCallback = (block: CodeBlock, result: (FormattedLine | FormattedLine[])[], settings: BeautifierSettings, indent: number) => void;
type FormattedLinesCallback = (inputs: (FormattedLine | FormattedLine[])[], indentation: string) => Array<string>; type FormattedLinesCallback = (inputs: (FormattedLine | FormattedLine[])[], indentation: string) => Array<string>;
@ -723,9 +757,11 @@ function UnitTest7(func: FormattedLinesCallback, testName: string, indentation:
function UnitTest6(func: BeautifyCallback, testName: string, parameters: BeautifierSettings, inputs: Array<string>, expected: (FormattedLine | FormattedLine[])[], startIndex: number, expectedEndIndex: number, indent: number) { function UnitTest6(func: BeautifyCallback, testName: string, parameters: BeautifierSettings, inputs: Array<string>, expected: (FormattedLine | FormattedLine[])[], startIndex: number, expectedEndIndex: number, indent: number) {
let actual: (FormattedLine | FormattedLine[])[] = [] 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)
let block = new CodeBlock(inputs);
block.cursor = startIndex;
func(block, actual, parameters, indent);
if (block.cursor != expectedEndIndex) {
console.log(testName + " failed;\nend index, actual: " + block.cursor + "; expected: " + expectedEndIndex)
} }
assertFormattedLines(testName, expected, actual); assertFormattedLines(testName, expected, actual);
} }
@ -759,7 +795,7 @@ function IntegrationTest() {
new_line_after_symbols.noNewLineAfter = ["port", "generic"]; new_line_after_symbols.noNewLineAfter = ["port", "generic"];
let settings = getDefaultBeautifierSettings(new_line_after_symbols); let settings = getDefaultBeautifierSettings(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 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 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); let actual = beautify(input, settings);
assertAndCountTest("General", expected, actual); assertAndCountTest("General", expected, actual);
@ -818,17 +854,17 @@ function IntegrationTest() {
assertAndCountTest("WHEN CASE & IF", expected, actual); assertAndCountTest("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;"; 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;";
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); actual = beautify(input, settings);
assertAndCountTest("PORT MAP", expected, actual); assertAndCountTest("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;"; 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;";
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); actual = beautify(input, settings);
assertAndCountTest("Multiple PORT MAPs", expected, actual); assertAndCountTest("Multiple PORT MAPs", expected, actual);
input = "port (a : in std_logic;\r\n b : in std_logic;\r\n);"; 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);";
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 = new NewLineSettings();
new_line_after_symbols_2.newLineAfter = ["then", ";", "generic", "port"]; new_line_after_symbols_2.newLineAfter = ["then", ";", "generic", "port"];
newSettings = deepCopy(settings); newSettings = deepCopy(settings);
@ -839,14 +875,14 @@ function IntegrationTest() {
newSettings = deepCopy(settings); newSettings = deepCopy(settings);
newSettings.NewLineSettings.newLineAfter = []; newSettings.NewLineSettings.newLineAfter = [];
input = "component a is\r\nport( Data : inout Std_Logic_Vector(7 downto 0););\r\nend component a;"; 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;";
expected = "COMPONENT a IS\r\n PORT (Data : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0););\r\nEND COMPONENT a;";
actual = beautify(input, newSettings); actual = beautify(input, newSettings);
assertAndCountTest("New line after PORT (single line)", expected, actual); assertAndCountTest("New line after PORT (single line)", expected, actual);
//IntegrationTest20(); //IntegrationTest20();
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;"; 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;";
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); actual = beautify(input, newSettings);
assertAndCountTest("Double BEGIN", expected, actual); assertAndCountTest("Double BEGIN", expected, actual);
@ -1459,7 +1495,7 @@ function IntegrationTest2() {
let settings = getDefaultBeautifierSettings(new_line_after_symbols); let settings = getDefaultBeautifierSettings(new_line_after_symbols);
settings.RemoveComments = true; 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 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 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); let actual = beautify(input, settings);
assertAndCountTest("Remove comments", expected, actual); assertAndCountTest("Remove comments", expected, actual);
} }
@ -1490,4 +1526,4 @@ function CompareArray(actual: Array<string>, expected: Array<string>) {
} }
} }
return true; return true;
}
}

Loading…
Cancel
Save