Now no longer goes completely out of control with long expressions

This commit is contained in:
Hackerpilot 2015-02-19 16:14:55 -08:00
parent 96501f7418
commit 30c8134b93
1 changed files with 28 additions and 20 deletions

View File

@ -391,7 +391,8 @@ private:
writeToken(); writeToken();
break; break;
case tok!",": case tok!",":
if (linebreakHints.canFind(index)) if (linebreakHints.canFind(index) || (linebreakHints.length == 0
&& currentLineLength > config.columnSoftLimit))
{ {
writeToken(); writeToken();
pushIndent(); pushIndent();
@ -402,6 +403,9 @@ private:
writeToken(); writeToken();
write(" "); write(" ");
} }
immutable size_t i = expressionEndIndex();
linebreakHints = chooseLineBreakTokens(index, tokens[index .. i],
config, currentLineLength, indentLevel);
break; break;
case tok!"=": case tok!"=":
case tok!">=": case tok!">=":
@ -1141,11 +1145,11 @@ int breakCost(IdType t)
case tok!"-": case tok!"-":
case tok!"~": case tok!"~":
case tok!"+=": case tok!"+=":
return 55; return 100;
case tok!".": case tok!".":
return 89; return 200;
default: default:
return 144; return 1000;
} }
} }
@ -1158,7 +1162,7 @@ struct State
this.breaks = breaks; this.breaks = breaks;
this._depth = depth; this._depth = depth;
import std.algorithm : map, sum; import std.algorithm : map, sum;
this._cost = breaks.map!(b => breakCost(tokens[b].type)).sum() + ((depth - 1) * 50); this._cost = breaks.map!(b => breakCost(tokens[b].type)).sum() + ((depth - 1) * 200);
int ll = currentLineLength; int ll = currentLineLength;
size_t breakIndex = 0; size_t breakIndex = 0;
size_t i = 0; size_t i = 0;
@ -1166,7 +1170,8 @@ struct State
if (breaks.length == 0) if (breaks.length == 0)
{ {
_cost = int.max; _cost = int.max;
s = tokens.map!(a => tokenLength(a)).sum() < formatterConfig.columnSoftLimit; immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
s = l < formatterConfig.columnSoftLimit;
} }
else else
{ {
@ -1195,8 +1200,9 @@ struct State
int opCmp(ref const State other) const pure nothrow @safe int opCmp(ref const State other) const pure nothrow @safe
{ {
if (cost < other.cost if (cost < other.cost
|| (cost == other.cost && breaks.length && other.breaks.length && breaks[0] > other.breaks[0]) || (cost == other.cost
|| (cost == other.cost && _solved && !other.solved)) && ((breaks.length && other.breaks.length && breaks[0] > other.breaks[0])
|| (_solved && !other.solved))))
{ {
return -1; return -1;
} }
@ -1219,42 +1225,42 @@ private:
int _depth; int _depth;
bool _solved; bool _solved;
} }
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel) const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel)
{ {
import std.container.rbtree : RedBlackTree; import std.container.rbtree : RedBlackTree;
import std.algorithm : min;
enum ALGORITHMIC_COMPLEXITY_SUCKS = 20;
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
int depth = 0; int depth = 0;
auto open = new RedBlackTree!State; auto open = new RedBlackTree!State;
open.insert(State(cast(size_t[])[], tokens, depth, formatterConfig, currentLineLength, indentLevel)); open.insert(State(cast(size_t[])[], tokens[0 .. tokensEnd], depth, formatterConfig,
currentLineLength, indentLevel));
while (!open.empty) while (!open.empty)
{ {
State current = open.front(); State current = open.front();
open.removeFront(); open.removeFront();
if (current.solved) if (current.solved)
{ {
foreach (ref b; current.breaks) current.breaks[] += index;
b += index;
return current.breaks; return current.breaks;
} }
foreach (next; validMoves(tokens, current, formatterConfig, currentLineLength, indentLevel, depth)) foreach (next; validMoves(tokens[0 .. tokensEnd], current, formatterConfig,
currentLineLength, indentLevel, depth))
{ {
open.insert(next); open.insert(next);
} }
} }
size_t[] retVal = open.empty ? [] : open.front().breaks; size_t[] retVal = open.empty ? [] : open.front().breaks;
foreach (ref b; retVal) retVal[] += index;
b += index;
return retVal; return retVal;
} }
State[] validMoves(const Token[] tokens, ref const State current, State[] validMoves(const Token[] tokens, ref const State current,
const FormatterConfig* formatterConfig, int currentLineLength, const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth)
int indentLevel, int depth)
{ {
import std.algorithm : sort, canFind; import std.algorithm : sort, canFind;
import std.array:insertInPlace; import std.array : insertInPlace;
State[] states; State[] states;
foreach (i, token; tokens) foreach (i, token; tokens)
@ -1273,6 +1279,7 @@ State[] validMoves(const Token[] tokens, ref const State current,
unittest unittest
{ {
import std.string : format;
auto sourceCode = q{const Token[] tokens, ref const State current, const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth}; auto sourceCode = q{const Token[] tokens, ref const State current, const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth};
LexerConfig config; LexerConfig config;
config.stringBehavior = StringBehavior.source; config.stringBehavior = StringBehavior.source;
@ -1280,5 +1287,6 @@ unittest
StringCache cache = StringCache(StringCache.defaultBucketCount); StringCache cache = StringCache(StringCache.defaultBucketCount);
auto tokens = byToken(cast(ubyte[]) sourceCode, config, &cache).array(); auto tokens = byToken(cast(ubyte[]) sourceCode, config, &cache).array();
FormatterConfig formatterConfig; FormatterConfig formatterConfig;
assert ([15] == chooseLineBreakTokens(0, tokens, &formatterConfig, 0, 0)); auto result = chooseLineBreakTokens(0, tokens, &formatterConfig, 0, 0);
assert ([15] == result, "%s".format(result));
} }