Run dfmt on itself and debug some wrapping calculations

This commit is contained in:
Hackerpilot 2016-01-19 05:20:31 -08:00
parent 7ec932a1e3
commit 24be6ddc2e
14 changed files with 333 additions and 196 deletions

View file

@ -96,7 +96,8 @@ final class FormatVisitor : ASTVisitor
auto condition = dec.compileCondition;
if (condition.versionCondition !is null)
{
astInformation.conditionalWithElseLocations ~= condition.versionCondition.versionIndex;
astInformation.conditionalWithElseLocations
~= condition.versionCondition.versionIndex;
}
else if (condition.debugCondition !is null)
{
@ -151,8 +152,10 @@ final class FormatVisitor : ASTVisitor
{
if (functionBody.blockStatement !is null)
astInformation.doubleNewlineLocations ~= functionBody.blockStatement.endLocation;
if (functionBody.bodyStatement !is null && functionBody.bodyStatement.blockStatement !is null)
astInformation.doubleNewlineLocations ~= functionBody.bodyStatement.blockStatement.endLocation;
if (functionBody.bodyStatement !is null && functionBody.bodyStatement
.blockStatement !is null)
astInformation.doubleNewlineLocations
~= functionBody.bodyStatement.blockStatement.endLocation;
functionBody.accept(this);
}
@ -203,8 +206,8 @@ final class FormatVisitor : ASTVisitor
override void visit(const UnaryExpression unary)
{
if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&"
|| unary.prefix.type == tok!"*" || unary.prefix.type == tok!"+"
|| unary.prefix.type == tok!"-")
|| unary.prefix.type == tok!"*"
|| unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-")
{
astInformation.unaryLocations ~= unary.prefix.index;
}

View file

@ -21,7 +21,7 @@ enum BraceStyle
enum TemplateConstraintStyle
{
unspecified,
unspecified,
conditional_newline_indent,
conditional_newline,
always_newline,
@ -54,7 +54,6 @@ struct Config
mixin StandardEditorConfigFields;
/**
* Initializes the standard EditorConfig properties with default values that
* make sense for D code.
@ -89,8 +88,9 @@ struct Config
if (dfmt_soft_max_line_length > max_line_length)
{
stderr.writefln("Column hard limit (%d) must be greater than or equal to column soft limit (%d)",
max_line_length, dfmt_soft_max_line_length);
stderr.writefln(
"Column hard limit (%d) must be greater than or equal to column soft limit (%d)",
max_line_length, dfmt_soft_max_line_length);
return false;
}
return true;

View file

@ -73,11 +73,11 @@ mixin template StandardEditorConfigFields()
auto thisN = &mixin("this." ~ N);
static if (N == "pattern")
continue;
else static if (is (T == enum))
else static if (is(T == enum))
*thisN = otherN != T.unspecified ? otherN : *thisN;
else static if (is (T == int))
else static if (is(T == int))
*thisN = otherN != -1 ? otherN : *thisN;
else static if (is (T == string))
else static if (is(T == string))
*thisN = otherN !is null ? otherN : *thisN;
else
static assert(false);
@ -143,6 +143,7 @@ EC getConfigFor(EC)(string path)
static if (__VERSION__ >= 2067)
{
import std.algorithm : each;
configs.each!(a => a.each!(b => result.merge(b, fileName)))();
}
else

View file

@ -15,7 +15,7 @@ import dfmt.wrapping;
import std.array;
void format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output,
Config* formatterConfig)
Config* formatterConfig)
{
LexerConfig config;
config.stringBehavior = StringBehavior.source;
@ -33,7 +33,7 @@ void format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output,
auto tokens = byToken(buffer, config, &cache).array();
auto depths = generateDepthInfo(tokens);
auto tokenFormatter = TokenFormatter!OutputRange(buffer, tokens, depths,
output, &astInformation, formatterConfig);
output, &astInformation, formatterConfig);
tokenFormatter.format();
}
@ -79,7 +79,7 @@ struct TokenFormatter(OutputRange)
* decisions.
*/
this(const ubyte[] rawSource, const(Token)[] tokens, immutable short[] depths,
OutputRange output, ASTInformation* astInformation, Config* config)
OutputRange output, ASTInformation* astInformation, Config* config)
{
this.rawSource = rawSource;
this.tokens = tokens;
@ -259,7 +259,7 @@ private:
|| isBasicType(current.type) || currentIs(tok!"@")
|| currentIs(tok!"if")
|| isNumberLiteral(tokens[index].type) || (inAsm
&& peekBack2Is(tok!";") && currentIs(tok!"["))))
&& peekBack2Is(tok!";") && currentIs(tok!"["))))
{
write(" ");
}
@ -387,7 +387,7 @@ private:
break;
else if (t == tok!"import" && !currentIs(tok!"import")
&& !currentIs(tok!"}") && !(currentIs(tok!"public")
&& peekIs(tok!"import"))
&& peekIs(tok!"import"))
&& !indents.topIsOneOf(tok!"if", tok!"debug", tok!"version"))
{
simpleNewline();
@ -461,11 +461,11 @@ private:
newline();
immutable size_t j = expressionEndIndex(index);
linebreakHints = chooseLineBreakTokens(index, tokens[index .. j],
depths[index .. j], config, currentLineLength, indentLevel);
depths[index .. j], config, currentLineLength, indentLevel);
}
else if (!currentIs(tok!")") && !currentIs(tok!"]")
&& (linebreakHints.canFindIndex(index - 1)
|| (linebreakHints.length == 0 && currentLineLength > config.max_line_length)))
|| (linebreakHints.length == 0 && currentLineLength > config.max_line_length)))
{
newline();
}
@ -479,8 +479,7 @@ private:
body
{
parenDepth--;
if (parenDepth == 0)
indents.popWrapIndents();
indents.popWrapIndents();
if (indents.topIs(tok!"("))
indents.pop();
@ -686,7 +685,7 @@ private:
a => tokenLength(a)).sum();
immutable bool multiline = l > config.dfmt_soft_max_line_length
|| tokens[index .. e].canFind!(a => a.type == tok!"comment"
|| isBlockHeaderToken(a.type))();
|| isBlockHeaderToken(a.type))();
writeToken();
if (multiline)
{
@ -762,7 +761,7 @@ private:
write("}");
if (index + 1 < tokens.length
&& astInformation.doubleNewlineLocations.canFindIndex(
tokens[index].index) && !peekIs(tok!"}")
tokens[index].index) && !peekIs(tok!"}")
&& !peekIs(tok!";") && !peekIs(tok!"comment", false))
{
simpleNewline();
@ -1150,7 +1149,7 @@ private:
}
else if (!peekIs(tok!"}") && (linebreakHints.canFind(index)
|| (linebreakHints.length == 0
&& currentLineLength > config.dfmt_soft_max_line_length)))
&& currentLineLength > config.dfmt_soft_max_line_length)))
{
pushWrapIndent();
writeToken();
@ -1172,7 +1171,7 @@ private:
{
immutable size_t j = expressionEndIndex(i);
linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j],
config, currentLineLength, indentLevel);
config, currentLineLength, indentLevel);
}
void regenLineBreakHintsIfNecessary(immutable size_t i)
@ -1215,7 +1214,7 @@ private:
if (niBraceDepth > 0 && !peekBackIsSlashSlash() && hasCurrent
&& tokens[index].type == tok!"}"
&& !assumeSorted(astInformation.funLitEndLocations).equalRange(
tokens[index].index).empty)
tokens[index].index).empty)
{
write(" ");
return;
@ -1279,6 +1278,7 @@ private:
}
else if (currentIs(tok!"{"))
{
indents.dump();
indents.popWrapIndents();
if (peekBackIsSlashSlash() && peekBack2Is(tok!";"))
{
@ -1298,7 +1298,7 @@ private:
}
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if"
&& indents.top != tok!"version") || !peekIs(tok!"else")))
&& indents.top != tok!"version") || !peekIs(tok!"else")))
{
indents.pop();
}
@ -1329,10 +1329,12 @@ private:
}
else
{
indents.dump();
if (indents.topIsTemp() && (peekBackIsOneOf(true, tok!"}",
tok!";") && indents.top != tok!";"))
indents.popTempIndents();
indentLevel = indents.indentLevel;
indents.dump();
}
indent();
}

View file

@ -10,15 +10,15 @@ import std.path : filenameCharCmp, isDirSeparator;
// From std.path with changes:
// * changes meaning to match all characters except '/'
// ** added to take over the old meaning of *
bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)
(Range path, const(C)[] pattern)
@safe pure nothrow
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range)))
bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)(
Range path, const(C)[] pattern) @safe pure nothrow if (isForwardRange!Range
&& isSomeChar!(ElementEncodingType!Range) && isSomeChar!C
&& is(Unqual!C == Unqual!(ElementEncodingType!Range)))
in
{
// Verify that pattern[] is valid
import std.algorithm : balancedParens;
assert(balancedParens(pattern, '[', ']', 0));
assert(balancedParens(pattern, '{', '}', 0));
}
@ -29,11 +29,13 @@ body
static if (RC.sizeof == 1 && isSomeString!Range)
{
import std.utf : byChar;
return globMatchEditorConfig!cs(path.byChar, pattern);
}
else static if (RC.sizeof == 2 && isSomeString!Range)
{
import std.utf : byWchar;
return globMatchEditorConfig!cs(path.byWchar, pattern);
}
else
@ -44,134 +46,131 @@ body
const pc = pattern[pi];
switch (pc)
{
case '*':
if (pi < pattern.length-1 && pattern[pi+1] == '*')
case '*':
if (pi < pattern.length - 1 && pattern[pi + 1] == '*')
{
if (pi + 2 == pattern.length)
return true;
for (; !path.empty; path.popFront())
{
if (pi + 2 == pattern.length)
auto p = path.save;
if (globMatchEditorConfig!(cs, C)(p, pattern[pi + 2 .. pattern.length]))
return true;
for (; !path.empty; path.popFront())
}
return false;
}
else
{
if (pi + 1 == pattern.length)
return true;
for (; !path.empty; path.popFront())
{
auto p = path.save;
//if (p[0].to!dchar.isDirSeparator() && !pattern[pi+1].isDirSeparator())
// return false;
if (globMatchEditorConfig!(cs, C)(p, pattern[pi + 1 .. pattern.length]))
return true;
if (p[0].to!dchar.isDirSeparator())
return false;
}
return false;
}
case '?':
if (path.empty)
return false;
path.popFront();
break;
case '[':
if (path.empty)
return false;
auto nc = path.front;
path.popFront();
auto not = false;
++pi;
if (pattern[pi] == '!')
{
not = true;
++pi;
}
auto anymatch = false;
while (1)
{
const pc2 = pattern[pi];
if (pc2 == ']')
break;
if (!anymatch && (filenameCharCmp!cs(nc, pc2) == 0))
anymatch = true;
++pi;
}
if (anymatch == not)
return false;
break;
case '{':
// find end of {} section
auto piRemain = pi;
for (; piRemain < pattern.length && pattern[piRemain] != '}'; ++piRemain)
{
}
if (piRemain < pattern.length)
++piRemain;
++pi;
while (pi < pattern.length)
{
const pi0 = pi;
C pc3 = pattern[pi];
// find end of current alternative
for (; pi < pattern.length && pc3 != '}' && pc3 != ','; ++pi)
{
pc3 = pattern[pi];
}
auto p = path.save;
if (pi0 == pi)
{
if (globMatchEditorConfig!(cs, C)(p, pattern[piRemain .. $]))
{
auto p = path.save;
if (globMatchEditorConfig!(cs, C)(p,
pattern[pi + 2 .. pattern.length]))
return true;
return true;
}
return false;
++pi;
}
else
{
if (pi + 1 == pattern.length)
return true;
for (; !path.empty; path.popFront())
{
auto p = path.save;
//if (p[0].to!dchar.isDirSeparator() && !pattern[pi+1].isDirSeparator())
// return false;
if (globMatchEditorConfig!(cs, C)(p,
pattern[pi + 1 .. pattern.length]))
return true;
if (p[0].to!dchar.isDirSeparator())
return false;
}
return false;
}
case '?':
if (path.empty)
return false;
path.popFront();
break;
case '[':
if (path.empty)
return false;
auto nc = path.front;
path.popFront();
auto not = false;
++pi;
if (pattern[pi] == '!')
{
not = true;
++pi;
}
auto anymatch = false;
while (1)
{
const pc2 = pattern[pi];
if (pc2 == ']')
break;
if (!anymatch && (filenameCharCmp!cs(nc, pc2) == 0))
anymatch = true;
++pi;
}
if (anymatch == not)
return false;
break;
case '{':
// find end of {} section
auto piRemain = pi;
for (; piRemain < pattern.length
&& pattern[piRemain] != '}'; ++piRemain)
{ }
if (piRemain < pattern.length)
++piRemain;
++pi;
while (pi < pattern.length)
{
const pi0 = pi;
C pc3 = pattern[pi];
// find end of current alternative
for (; pi < pattern.length && pc3 != '}' && pc3 != ','; ++pi)
{
pc3 = pattern[pi];
}
auto p = path.save;
if (pi0 == pi)
{
if (globMatchEditorConfig!(cs, C)(p, pattern[piRemain..$]))
{
return true;
}
++pi;
}
else
{
/* Match for:
/* Match for:
* pattern[pi0..pi-1] ~ pattern[piRemain..$]
*/
if (pattmp.ptr == null)
// Allocate this only once per function invocation.
// Should do it with malloc/free, but that would make it impure.
pattmp = new C[pattern.length];
if (pattmp.ptr == null) // Allocate this only once per function invocation.
// Should do it with malloc/free, but that would make it impure.
pattmp = new C[pattern.length];
const len1 = pi - 1 - pi0;
pattmp[0 .. len1] = pattern[pi0 .. pi - 1];
const len1 = pi - 1 - pi0;
pattmp[0 .. len1] = pattern[pi0 .. pi - 1];
const len2 = pattern.length - piRemain;
pattmp[len1 .. len1 + len2] = pattern[piRemain .. $];
const len2 = pattern.length - piRemain;
pattmp[len1 .. len1 + len2] = pattern[piRemain .. $];
if (globMatchEditorConfig!(cs, C)(p, pattmp[0 .. len1 + len2]))
{
return true;
}
}
if (pc3 == '}')
if (globMatchEditorConfig!(cs, C)(p, pattmp[0 .. len1 + len2]))
{
break;
return true;
}
}
return false;
if (pc3 == '}')
{
break;
}
}
return false;
default:
if (path.empty)
return false;
if (filenameCharCmp!cs(pc, path.front) != 0)
return false;
path.popFront();
break;
default:
if (path.empty)
return false;
if (filenameCharCmp!cs(pc, path.front) != 0)
return false;
path.popFront();
break;
}
}
return path.empty;
@ -180,8 +179,8 @@ body
unittest
{
assert (globMatchEditorConfig!(CaseSensitive.no)("foo", "Foo"));
assert (!globMatchEditorConfig!(CaseSensitive.yes)("foo", "Foo"));
assert(globMatchEditorConfig!(CaseSensitive.no)("foo", "Foo"));
assert(!globMatchEditorConfig!(CaseSensitive.yes)("foo", "Foo"));
assert(globMatchEditorConfig("foo", "*"));
assert(globMatchEditorConfig("foo.bar"w, "*"w));
@ -225,7 +224,7 @@ unittest
assert(!globMatchEditorConfig("foo", "foob"));
assert(!globMatchEditorConfig("foo", "foo{b}"));
assert (globMatchEditorConfig(`foo/foo\bar`, "f**b**r"));
assert(globMatchEditorConfig(`foo/foo\bar`, "f**b**r"));
assert(globMatchEditorConfig("foo", "**"));
assert(globMatchEditorConfig("foo/bar", "foo/bar"));
assert(globMatchEditorConfig("foo/bar", "foo/*"));
@ -235,6 +234,5 @@ unittest
assert(!globMatchEditorConfig("/foo/bar/gluu/sar.png", "*/sar.png"));
assert(!globMatchEditorConfig("/foo/bar/gluu/sar.png", "*/*.png"));
static assert(globMatchEditorConfig("foo.bar", "[!gh]*bar"));
}

View file

@ -12,8 +12,8 @@ import dparse.lexer;
*/
bool isWrapIndent(IdType type) pure nothrow @nogc @safe
{
return type != tok!"{" && type != tok!"case" && type != tok!"@"
&& type != tok!"]" && type != tok!"(" && isOperator(type);
return type != tok!"{" && type != tok!"case" && type != tok!"@"
&& type != tok!"]" && type != tok!"(" && isOperator(type);
}
/**
@ -151,6 +151,15 @@ struct IndentStack
return cast(int) index;
}
void dump()
{
/+import std.stdio : stderr;
import dparse.lexer : str;
import std.algorithm.iteration : map;
stderr.writefln("\033[31m%(%s %)\033[0m", arr[0 .. index].map!(a => str(a)));+/
}
private:
size_t index;
@ -163,12 +172,24 @@ private:
return 0;
immutable size_t j = k == size_t.max ? index : k;
int size = 0;
int parenCount;
foreach (i; 0 .. j)
{
if (i + 1 < index)
{
if (arr[i] == tok!"]")
if (arr[i] == tok!"(")
parenCount++;
else if (arr[i] == tok!"]")
continue;
else
{
if (isWrapIndent(arr[i]) && parenCount > 0)
{
parenCount = 0;
continue;
}
//parenCount = 0;
}
immutable currentIsNonWrapTemp = !isWrapIndent(arr[i]) && isTempIndent(arr[i]);
immutable nextIsParenOrSwitch = arr[i + 1] == tok!"("
|| arr[i + 1] == tok!"switch" || arr[i + 1] == tok!"{";

View file

@ -32,8 +32,10 @@ else
{
import dfmt.editorconfig : OptionalBoolean;
import std.exception : enforceEx;
enforceEx!GetOptException(value == "true" || value == "false", "Invalid argument");
immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t : OptionalBoolean.f;
immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t
: OptionalBoolean.f;
switch (option)
{
case "align_switch_statements":
@ -54,7 +56,8 @@ else
case "compact_labeled_statements":
optConfig.dfmt_compact_labeled_statements = optVal;
break;
default: assert(false, "Invalid command-line switch");
default:
assert(false, "Invalid command-line switch");
}
}
@ -113,17 +116,19 @@ else
return 1;
File output = stdout;
version(Windows)
version (Windows)
{
// On Windows, set stdout to binary mode (needed for correct EOL writing)
// See Phobos' stdio.File.rawWrite
{
import std.stdio;
immutable fd = fileno(output.getFP());
setmode(fd, _O_BINARY);
version(CRuntime_DigitalMars)
version (CRuntime_DigitalMars)
{
import core.atomic : atomicOp;
atomicOp!"&="(__fhnd_info[fd], ~FHND_TEXT);
}
}
@ -176,15 +181,18 @@ else
}
}
private string optionsToString(E)() if(is(E == enum)) {
import std.traits:EnumMembers;
import std.conv;
string result = "[";
foreach(i, option; EnumMembers!E) {
result ~= to!string(option) ~ "|";
}
result = result[0 .. $-1] ~ "]";
return result;
private string optionsToString(E)() if (is(E == enum))
{
import std.traits : EnumMembers;
import std.conv;
string result = "[";
foreach (i, option; EnumMembers!E)
{
result ~= to!string(option) ~ "|";
}
result = result[0 .. $ - 1] ~ "]";
return result;
}
private void printHelp()
@ -199,11 +207,13 @@ Options:
Formatting Options:
--align_switch_statements
--brace_style `, optionsToString!(typeof(Config.dfmt_brace_style))(), `
--brace_style `,
optionsToString!(typeof(Config.dfmt_brace_style))(), `
--end_of_line
--help|h
--indent_size
--indent_style|t `, optionsToString!(typeof(Config.indent_style))(), `
--indent_style|t `,
optionsToString!(typeof(Config.indent_style))(), `
--soft_max_line_length
--max_line_length
--outdent_attributes
@ -211,7 +221,8 @@ Formatting Options:
--selective_import_space
--split_operator_at_line_end
--compact_labeled_statements
--template_constraint_style `, optionsToString!(typeof(Config.dfmt_template_constraint_style))());
--template_constraint_style `,
optionsToString!(typeof(Config.dfmt_template_constraint_style))());
}
private string createFilePath(bool readFromStdin, string fileName)

View file

@ -195,7 +195,6 @@ pure nothrow @safe @nogc unittest
assert(breakCost(tok!".", u) != 1000);
}
private string generateFixedLengthCases()
{
import std.algorithm : map;
@ -205,11 +204,11 @@ private string generateFixedLengthCases()
assert(__ctfe);
string[] spacedOperatorTokens = [
",", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", "!>",
"!>=", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "+=", "-", "-=", ":",
";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>", ">", ">=",
">>", ">>=", ">>>", ">>>=", "?", "@", "^", "^=", "^^", "^^=", "|", "|=", "||",
"~", "~="
",", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=",
"!>", "!>=", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "+=", "-",
"-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>",
">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "^", "^=", "^^",
"^^=", "|", "|=", "||", "~", "~="
];
immutable spacedOperatorTokenCases = spacedOperatorTokens.map!(
a => format(`case tok!"%s": return %d + 1;`, a, a.length)).join("\n\t");
@ -219,20 +218,21 @@ private string generateFixedLengthCases()
"break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat",
"char", "class", "const", "continue", "creal", "dchar", "debug",
"default", "delegate", "delete", "deprecated", "do", "double", "else",
"enum", "export", "extern", "false", "final", "finally", "float", "for",
"foreach", "foreach_reverse", "function", "goto", "idouble", "if",
"ifloat", "immutable", "import", "in", "inout", "int", "interface",
"invariant", "ireal", "is", "lazy", "long", "macro", "mixin", "module",
"new", "nothrow", "null", "out", "override", "package", "pragma",
"private", "protected", "public", "pure", "real", "ref", "return",
"scope", "shared", "short", "static", "struct", "super", "switch",
"synchronized", "template", "this", "throw", "true", "try", "typedef",
"typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "union",
"unittest", "ushort", "version", "void", "volatile", "wchar", "while",
"with", "__DATE__", "__EOF__", "__FILE__", "__FUNCTION__", "__gshared",
"__LINE__", "__MODULE__", "__parameters", "__PRETTY_FUNCTION__",
"__TIME__", "__TIMESTAMP__", "__traits", "__vector", "__VENDOR__",
"__VERSION__", "$", "++", "--", ".", "[", "]", "(", ")", "{", "}"
"enum", "export", "extern", "false", "final", "finally", "float",
"for", "foreach", "foreach_reverse", "function", "goto", "idouble",
"if", "ifloat", "immutable", "import", "in", "inout", "int",
"interface", "invariant", "ireal", "is", "lazy", "long", "macro",
"mixin", "module", "new", "nothrow", "null", "out", "override",
"package", "pragma", "private", "protected", "public", "pure", "real",
"ref", "return", "scope", "shared", "short", "static", "struct",
"super", "switch", "synchronized", "template", "this", "throw", "true",
"try", "typedef", "typeid", "typeof", "ubyte", "ucent", "uint",
"ulong", "union", "unittest", "ushort", "version", "void", "volatile",
"wchar", "while", "with", "__DATE__", "__EOF__", "__FILE__",
"__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters",
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits",
"__vector", "__VENDOR__", "__VERSION__", "$", "++", "--", ".", "[",
"]", "(", ")", "{", "}"
];
immutable identifierTokenCases = identifierTokens.map!(
a => format(`case tok!"%s": return %d;`, a, a.length)).join("\n\t");

View file

@ -12,13 +12,14 @@ import dfmt.config;
struct State
{
this(uint breaks, const Token[] tokens, immutable short[] depths,
const Config* config, int currentLineLength, int indentLevel) pure @safe
const Config* config, int currentLineLength, int indentLevel) pure @safe
{
import std.math : abs;
import core.bitop : popcnt, bsf;
import std.algorithm : min, map, sum;
immutable int remainingCharsMultiplier = config.max_line_length - config.dfmt_soft_max_line_length;
immutable int remainingCharsMultiplier = config.max_line_length
- config.dfmt_soft_max_line_length;
immutable int newlinePenalty = remainingCharsMultiplier * 20;
this.breaks = breaks;
@ -119,7 +120,7 @@ private:
}
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
immutable short[] depths, const Config* config, int currentLineLength, int indentLevel)
immutable short[] depths, const Config* config, int currentLineLength, int indentLevel)
{
import std.container.rbtree : RedBlackTree;
import std.algorithm : filter, min;
@ -139,7 +140,7 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
auto open = new RedBlackTree!State;
open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], config,
currentLineLength, indentLevel));
currentLineLength, indentLevel));
State lowest;
while (!open.empty)
{
@ -152,7 +153,8 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
return genRetVal(current.breaks, index);
}
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd],
depths[0 .. tokensEnd], current.breaks, config, currentLineLength, indentLevel);
depths[0 .. tokensEnd], current.breaks, config, currentLineLength,
indentLevel);
}
if (open.empty)
return genRetVal(lowest.breaks, index);
@ -162,8 +164,8 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
}
void validMoves(OR)(auto ref OR output, const Token[] tokens,
immutable short[] depths, uint current, const Config* config,
int currentLineLength, int indentLevel)
immutable short[] depths, uint current, const Config* config,
int currentLineLength, int indentLevel)
{
import std.algorithm : sort, canFind;
import std.array : insertInPlace;

View file

@ -0,0 +1,36 @@
unittest
{
if (a)
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")
|| !peekIs(tok!"else")))
{
a();
}
}
if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in")
|| peekIs(tok!"out") || peekIs(tok!"body")))
writeToken();
{
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if"
&& indents.top != tok!"version") || !peekIs(tok!"else")))
{
indents.pop();
}
}
}
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")
|| !peekIs(tok!"else")))
{
indents.pop();
}
}
}

View file

@ -4,6 +4,6 @@ void main(string[] args)
{
addErrorMessage(line, column, KEY,
"Expression %s is true: already checked on line %d.".format(
expressions[prevLocation].formatted, expressions[prevLocation].line));
expressions[prevLocation].formatted, expressions[prevLocation].line));
}
}

View file

@ -0,0 +1,31 @@
unittest {
if (a) {
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")
|| !peekIs(tok!"else"))) {
a();
}
}
if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in")
|| peekIs(tok!"out") || peekIs(tok!"body")))
writeToken();
{
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if"
&& indents.top != tok!"version") || !peekIs(tok!"else"))) {
indents.pop();
}
}
}
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")
|| !peekIs(tok!"else"))) {
indents.pop();
}
}
}

View file

@ -2,6 +2,6 @@ void main(string[] args) {
if (prevLocation != size_t.max) {
addErrorMessage(line, column, KEY,
"Expression %s is true: already checked on line %d.".format(
expressions[prevLocation].formatted, expressions[prevLocation].line));
expressions[prevLocation].formatted, expressions[prevLocation].line));
}
}

32
tests/parenIndent.d Normal file
View file

@ -0,0 +1,32 @@
unittest
{
if (a)
{
while (sBraceDepth == 0 && indents.topIsTemp()
&& ((indents.top != tok!"if" && indents.top != tok!"version")|| !peekIs(tok!"else")))
{
a();
}
}
if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in")
|| peekIs(tok!"out") || peekIs(tok!"body")))
writeToken();
{
{
while (sBraceDepth == 0 && indents.topIsTemp()&& ((indents.top != tok!"if"
&& indents.top != tok!"version") || !peekIs(tok!"else")))
{
indents.pop();
}
}
}
{
while (sBraceDepth == 0 && indents.topIsTemp()&& ((indents.top != tok!"if" && indents.top != tok!"version") || !peekIs(tok!"else")))
{
indents.pop();
}
}
}