Merge branch 'master' of https://github.com/Hackerpilot/dfmt
Conflicts: src/dfmt.d
This commit is contained in:
commit
506e150eea
|
@ -3,3 +3,4 @@ bin
|
||||||
*.d.out
|
*.d.out
|
||||||
.dub
|
.dub
|
||||||
dfmt
|
dfmt
|
||||||
|
dub.selections.json
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
language: d
|
||||||
|
script: make test
|
23
README.md
23
README.md
|
@ -1,2 +1,23 @@
|
||||||
# dfmt
|
# dfmt
|
||||||
Dfmt is a formatter for D source code
|
**dfmt** is a formatter for D source code
|
||||||
|
|
||||||
|
[](https://travis-ci.org/Hackerpilot/dfmt)
|
||||||
|
|
||||||
|
## Status
|
||||||
|
**dfmt** is alpha-quality. Make backups of your files or use source control.
|
||||||
|
|
||||||
|
|
||||||
|
## Building
|
||||||
|
### Using Make
|
||||||
|
* Clone the repository
|
||||||
|
* Run ```git submodule update --init``` in the dfmt directory
|
||||||
|
* To compile with DMD, run ```make``` in the dfmt directory. To compile with
|
||||||
|
LDC, run ```make ldc``` instead. The generated binary will be placed in ```dfmt/bin/```.
|
||||||
|
|
||||||
|
|
||||||
|
## Using
|
||||||
|
By default, dfmt reads its input from ```stdin``` and writes to ```stdout```.
|
||||||
|
If a file name is specified on the command line, input will be read from the
|
||||||
|
file instead, and output will be written to ```stdout```. If the ```--inplace```
|
||||||
|
option is specified a file name is required and the file will be edited
|
||||||
|
in-place.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit bce47174cc2ea6cfd26d007a9c41108e4fb28f0e
|
Subproject commit f73bed9279602a228933b21156d8f1f2ec5e4fdd
|
304
src/dfmt.d
304
src/dfmt.d
|
@ -34,37 +34,24 @@ import std.d.formatter;
|
||||||
import std.d.ast;
|
import std.d.ast;
|
||||||
import std.array;
|
import std.array;
|
||||||
|
|
||||||
/// Help text
|
version (NoMain)
|
||||||
immutable USAGE = "usage: %s [--inplace] [<path>...]
|
{ }
|
||||||
Formats D code.
|
else
|
||||||
|
|
||||||
--inplace change file in-place instead of outputing to stdout
|
|
||||||
(implicit in case of multiple files)
|
|
||||||
-h, --help display this help and exit
|
|
||||||
";
|
|
||||||
|
|
||||||
int main(string[] args)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
import std.getopt : getopt;
|
import std.getopt : getopt;
|
||||||
import std.path: baseName;
|
|
||||||
import std.file : isDir, dirEntries, SpanMode;
|
|
||||||
|
|
||||||
bool inplace = false;
|
bool inplace = false;
|
||||||
bool show_usage = false;
|
bool show_usage = false;
|
||||||
|
FormatterConfig formatterConfig;
|
||||||
try
|
|
||||||
{
|
|
||||||
getopt(args,
|
getopt(args,
|
||||||
"help|h", &show_usage,
|
"help|h", &show_usage,
|
||||||
"inplace", &inplace);
|
"inplace", &inplace,
|
||||||
}
|
"tabs|t", &formatterConfig.useTabs,
|
||||||
catch (Exception e)
|
"braces", &formatterConfig.braceStyle);
|
||||||
{
|
|
||||||
writef(USAGE, baseName(args[0]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (show_usage)
|
if (show_usage)
|
||||||
{
|
{
|
||||||
|
import std.path: baseName;
|
||||||
writef(USAGE, baseName(args[0]));
|
writef(USAGE, baseName(args[0]));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -83,10 +70,11 @@ int main(string[] args)
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
format("stdin", buffer, output);
|
format("stdin", buffer, output.lockingTextWriter(), &formatterConfig);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
import std.file : dirEntries, isDir, SpanMode;
|
||||||
if (args.length >= 2)
|
if (args.length >= 2)
|
||||||
inplace = true;
|
inplace = true;
|
||||||
while (args.length > 0)
|
while (args.length > 0)
|
||||||
|
@ -107,19 +95,27 @@ int main(string[] args)
|
||||||
f.rawRead(buffer);
|
f.rawRead(buffer);
|
||||||
if (inplace)
|
if (inplace)
|
||||||
output = File(path, "w");
|
output = File(path, "w");
|
||||||
format(path, buffer, output);
|
format(path, buffer, output.lockingTextWriter(), &formatterConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private:
|
||||||
* Params:
|
|
||||||
* source_desc =
|
immutable USAGE = "usage: %s [--inplace] [<path>...]
|
||||||
* buffer =
|
Formats D code.
|
||||||
* output =
|
|
||||||
*/
|
--inplace Change file in-place instead of outputing to stdout
|
||||||
void format(string source_desc, ubyte[] buffer, File output)
|
(implicit in case of multiple files)
|
||||||
|
--tabs | -t Use tabs instead of spaces for indentation
|
||||||
|
--braces=allman Use Allman indent style (default)
|
||||||
|
--braces=otbs Use the One True Brace Style
|
||||||
|
--help | -h Display this help and exit
|
||||||
|
";
|
||||||
|
|
||||||
|
void format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output,
|
||||||
|
FormatterConfig* formatterConfig)
|
||||||
{
|
{
|
||||||
LexerConfig config;
|
LexerConfig config;
|
||||||
config.stringBehavior = StringBehavior.source;
|
config.stringBehavior = StringBehavior.source;
|
||||||
|
@ -129,29 +125,27 @@ void format(string source_desc, ubyte[] buffer, File output)
|
||||||
parseConfig.whitespaceBehavior = WhitespaceBehavior.skip;
|
parseConfig.whitespaceBehavior = WhitespaceBehavior.skip;
|
||||||
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
||||||
ASTInformation astInformation;
|
ASTInformation astInformation;
|
||||||
FormatterConfig formatterConfig;
|
|
||||||
auto parseTokens = getTokensForParser(buffer, parseConfig, &cache);
|
auto parseTokens = getTokensForParser(buffer, parseConfig, &cache);
|
||||||
auto mod = parseModule(parseTokens, source_desc);
|
auto mod = parseModule(parseTokens, source_desc);
|
||||||
auto visitor = new FormatVisitor(&astInformation);
|
auto visitor = new FormatVisitor(&astInformation);
|
||||||
visitor.visit(mod);
|
visitor.visit(mod);
|
||||||
astInformation.cleanup();
|
astInformation.cleanup();
|
||||||
auto tokens = byToken(buffer, config, &cache).array();
|
auto tokens = byToken(buffer, config, &cache).array();
|
||||||
auto tokenFormatter = TokenFormatter(tokens, output, &astInformation,
|
auto tokenFormatter = TokenFormatter!OutputRange(tokens, output, &astInformation,
|
||||||
&formatterConfig);
|
formatterConfig);
|
||||||
tokenFormatter.format();
|
tokenFormatter.format();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains formatting logic
|
struct TokenFormatter(OutputRange)
|
||||||
struct TokenFormatter
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* tokens = the tokens to format
|
* tokens = the tokens to format
|
||||||
* output = the file that the code will be formatted to
|
* output = the output range that the code will be formatted to
|
||||||
* astInformation = information about the AST used to inform formatting
|
* astInformation = information about the AST used to inform formatting
|
||||||
* decisions.
|
* decisions.
|
||||||
*/
|
*/
|
||||||
this(const(Token)[] tokens, File output, ASTInformation* astInformation,
|
this(const(Token)[] tokens, OutputRange output, ASTInformation* astInformation,
|
||||||
FormatterConfig* config)
|
FormatterConfig* config)
|
||||||
{
|
{
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
|
@ -184,7 +178,7 @@ private:
|
||||||
const i = index;
|
const i = index;
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
if (tokens[i-1].line < tokens[i].line)
|
if (tokens[i-1].line < current.line)
|
||||||
{
|
{
|
||||||
if (tokens[i-1].type != tok!"comment"
|
if (tokens[i-1].type != tok!"comment"
|
||||||
&& tokens[i-1].type != tok!"{")
|
&& tokens[i-1].type != tok!"{")
|
||||||
|
@ -194,11 +188,16 @@ private:
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
}
|
||||||
writeToken();
|
writeToken();
|
||||||
if (i + 1 >= tokens.length)
|
if (i >= tokens.length-1)
|
||||||
newline();
|
newline();
|
||||||
else if (tokens[i + 1].line > tokens[i].line)
|
else if (tokens[i+1].line-1 > tokens[i].line)
|
||||||
|
{
|
||||||
newline();
|
newline();
|
||||||
else if (tokens[i + 1].type != tok!"{")
|
newline();
|
||||||
|
}
|
||||||
|
else if (tokens[i+1].line > tokens[i].line)
|
||||||
|
newline();
|
||||||
|
else if (tokens[i+1].type != tok!"{")
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
}
|
||||||
else if (isStringLiteral(current.type) || isNumberLiteral(current.type)
|
else if (isStringLiteral(current.type) || isNumberLiteral(current.type)
|
||||||
|
@ -217,11 +216,40 @@ private:
|
||||||
{
|
{
|
||||||
writeToken();
|
writeToken();
|
||||||
tempIndent = 0;
|
tempIndent = 0;
|
||||||
|
if (index >= tokens.length)
|
||||||
|
{
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current.type == tok!"comment")
|
||||||
|
break;
|
||||||
if (!(t == tok!"import" && current.type == tok!"import"))
|
if (!(t == tok!"import" && current.type == tok!"import"))
|
||||||
write("\n");
|
write("\n");
|
||||||
newline();
|
newline();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (current.type == tok!",")
|
||||||
|
{
|
||||||
|
// compute length until next , or ;
|
||||||
|
int length_of_next_chunk = INVALID_TOKEN_LENGTH;
|
||||||
|
for (size_t i=index+1; i<tokens.length; i++)
|
||||||
|
{
|
||||||
|
if (tokens[i].type == tok!"," || tokens[i].type == tok!";")
|
||||||
|
break;
|
||||||
|
const len = tokenLength(i);
|
||||||
|
assert (len >= 0);
|
||||||
|
length_of_next_chunk += len;
|
||||||
|
}
|
||||||
|
assert (length_of_next_chunk > 0);
|
||||||
|
writeToken();
|
||||||
|
if (currentLineLength + 1 + length_of_next_chunk >= config.columnSoftLimit)
|
||||||
|
{
|
||||||
|
pushIndent();
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
write(" ");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
formatStep();
|
formatStep();
|
||||||
}
|
}
|
||||||
|
@ -229,10 +257,17 @@ private:
|
||||||
else if (current.type == tok!"return")
|
else if (current.type == tok!"return")
|
||||||
{
|
{
|
||||||
writeToken();
|
writeToken();
|
||||||
|
if (current.type != tok!";")
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
}
|
||||||
else if (current.type == tok!"switch")
|
else if (current.type == tok!"switch")
|
||||||
formatSwitch();
|
formatSwitch();
|
||||||
|
else if (current.type == tok!"version" && peekIs(tok!"("))
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
write(" ");
|
||||||
|
writeParens(false);
|
||||||
|
}
|
||||||
else if (current.type == tok!"for" || current.type == tok!"foreach"
|
else if (current.type == tok!"for" || current.type == tok!"foreach"
|
||||||
|| current.type == tok!"foreach_reverse" || current.type == tok!"while"
|
|| current.type == tok!"foreach_reverse" || current.type == tok!"while"
|
||||||
|| current.type == tok!"if")
|
|| current.type == tok!"if")
|
||||||
|
@ -240,7 +275,7 @@ private:
|
||||||
currentLineLength += currentTokenLength() + 1;
|
currentLineLength += currentTokenLength() + 1;
|
||||||
writeToken();
|
writeToken();
|
||||||
write(" ");
|
write(" ");
|
||||||
writeParens();
|
writeParens(false);
|
||||||
if (current.type != tok!"{" && current.type != tok!";")
|
if (current.type != tok!"{" && current.type != tok!";")
|
||||||
{
|
{
|
||||||
pushIndent();
|
pushIndent();
|
||||||
|
@ -311,18 +346,7 @@ private:
|
||||||
}
|
}
|
||||||
goto binary;
|
goto binary;
|
||||||
case tok!"(":
|
case tok!"(":
|
||||||
writeParens();
|
writeParens(true);
|
||||||
break;
|
|
||||||
case tok!":":
|
|
||||||
if (!assumeSorted(astInformation.ternaryColonLocations)
|
|
||||||
.equalRange(current.index).empty)
|
|
||||||
{
|
|
||||||
write(" ");
|
|
||||||
writeToken();
|
|
||||||
write(" ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
writeToken();
|
|
||||||
break;
|
break;
|
||||||
case tok!"@":
|
case tok!"@":
|
||||||
case tok!"!":
|
case tok!"!":
|
||||||
|
@ -333,6 +357,10 @@ private:
|
||||||
case tok!"$":
|
case tok!"$":
|
||||||
writeToken();
|
writeToken();
|
||||||
break;
|
break;
|
||||||
|
case tok!":":
|
||||||
|
write(" : ");
|
||||||
|
index += 1;
|
||||||
|
break;
|
||||||
case tok!"]":
|
case tok!"]":
|
||||||
writeToken();
|
writeToken();
|
||||||
if (current.type == tok!"identifier")
|
if (current.type == tok!"identifier")
|
||||||
|
@ -341,7 +369,9 @@ private:
|
||||||
case tok!";":
|
case tok!";":
|
||||||
tempIndent = 0;
|
tempIndent = 0;
|
||||||
writeToken();
|
writeToken();
|
||||||
if (current.type != tok!"comment")
|
if (index >= tokens.length || current.type != tok!"comment")
|
||||||
|
newline();
|
||||||
|
if (peekImplementation(tok!"class",0))
|
||||||
newline();
|
newline();
|
||||||
break;
|
break;
|
||||||
case tok!"{":
|
case tok!"{":
|
||||||
|
@ -358,17 +388,14 @@ private:
|
||||||
writeToken();
|
writeToken();
|
||||||
break;
|
break;
|
||||||
case tok!",":
|
case tok!",":
|
||||||
if (currentLineLength + nextTokenLength() >= config.columnSoftLimit)
|
writeToken();
|
||||||
|
if (currentLineLength + expressionLength() >= config.columnSoftLimit)
|
||||||
{
|
{
|
||||||
pushIndent();
|
pushIndent();
|
||||||
writeToken();
|
|
||||||
newline();
|
newline();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
writeToken();
|
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case tok!"^^":
|
case tok!"^^":
|
||||||
case tok!"^=":
|
case tok!"^=":
|
||||||
|
@ -428,9 +455,13 @@ private:
|
||||||
else if (current.type == tok!"identifier")
|
else if (current.type == tok!"identifier")
|
||||||
{
|
{
|
||||||
writeToken();
|
writeToken();
|
||||||
if (current.type == tok!"identifier" || isKeyword(current.type))
|
if (index < tokens.length && (current.type == tok!"identifier"
|
||||||
|
|| isKeyword(current.type) || isBasicType(current.type)
|
||||||
|
|| current.type == tok!"@"))
|
||||||
|
{
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
assert (false, str(current.type));
|
assert (false, str(current.type));
|
||||||
}
|
}
|
||||||
|
@ -449,6 +480,37 @@ private:
|
||||||
tempIndent--;
|
tempIndent--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t expressionLength() const pure @safe @nogc
|
||||||
|
{
|
||||||
|
size_t i = index;
|
||||||
|
size_t l = 0;
|
||||||
|
int parenDepth = 0;
|
||||||
|
loop: while (i < tokens.length) switch (tokens[i].type)
|
||||||
|
{
|
||||||
|
case tok!"(":
|
||||||
|
parenDepth++;
|
||||||
|
l++;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
case tok!")":
|
||||||
|
parenDepth--;
|
||||||
|
if (parenDepth == 0)
|
||||||
|
break loop;
|
||||||
|
l++;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
case tok!";":
|
||||||
|
case tok!",":
|
||||||
|
break loop;
|
||||||
|
default:
|
||||||
|
l += tokenLength(i);
|
||||||
|
if (isBasicType(tokens[i].type) || tokens[i].type == tok!"identifier")
|
||||||
|
l++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes balanced braces
|
/// Writes balanced braces
|
||||||
void writeBraces()
|
void writeBraces()
|
||||||
{
|
{
|
||||||
|
@ -480,11 +542,11 @@ private:
|
||||||
newline();
|
newline();
|
||||||
write("}");
|
write("}");
|
||||||
depth--;
|
depth--;
|
||||||
if (index + 1 < tokens.length &&
|
if (index < tokens.length - 1 &&
|
||||||
assumeSorted(astInformation.doubleNewlineLocations)
|
assumeSorted(astInformation.doubleNewlineLocations)
|
||||||
.equalRange(tokens[index].index).length)
|
.equalRange(tokens[index].index).length)
|
||||||
{
|
{
|
||||||
output.write("\n");
|
output.put("\n");
|
||||||
}
|
}
|
||||||
if (config.braceStyle == BraceStyle.otbs)
|
if (config.braceStyle == BraceStyle.otbs)
|
||||||
{
|
{
|
||||||
|
@ -513,7 +575,7 @@ private:
|
||||||
popIndent();
|
popIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeParens()
|
void writeParens(bool space_afterwards)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert (current.type == tok!"(", str(current.type));
|
assert (current.type == tok!"(", str(current.type));
|
||||||
|
@ -540,9 +602,11 @@ private:
|
||||||
else if (current.type == tok!")")
|
else if (current.type == tok!")")
|
||||||
{
|
{
|
||||||
if (peekIs(tok!"identifier") || (index + 1 < tokens.length
|
if (peekIs(tok!"identifier") || (index + 1 < tokens.length
|
||||||
&& isKeyword(tokens[index + 1].type)))
|
&& (isKeyword(tokens[index + 1].type)
|
||||||
|
|| tokens[index + 1].type == tok!"@")))
|
||||||
{
|
{
|
||||||
writeToken();
|
writeToken();
|
||||||
|
if (space_afterwards)
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -567,7 +631,7 @@ private:
|
||||||
immutable l = indentLevel;
|
immutable l = indentLevel;
|
||||||
writeToken(); // switch
|
writeToken(); // switch
|
||||||
write(" ");
|
write(" ");
|
||||||
writeParens();
|
writeParens(true);
|
||||||
if (current.type != tok!"{")
|
if (current.type != tok!"{")
|
||||||
return;
|
return;
|
||||||
if (config.braceStyle == BraceStyle.otbs)
|
if (config.braceStyle == BraceStyle.otbs)
|
||||||
|
@ -622,33 +686,38 @@ private:
|
||||||
newline();
|
newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentTokenLength()
|
int tokenLength(size_t i) const pure @safe @nogc
|
||||||
{
|
|
||||||
switch (current.type)
|
|
||||||
{
|
|
||||||
mixin (generateFixedLengthCases());
|
|
||||||
default: return cast(int) current.text.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int nextTokenLength()
|
|
||||||
{
|
{
|
||||||
import std.algorithm : countUntil;
|
import std.algorithm : countUntil;
|
||||||
if (index + 1 >= tokens.length)
|
|
||||||
return INVALID_TOKEN_LENGTH;
|
assert(i + 1 <= tokens.length);
|
||||||
auto nextToken = tokens[index + 1];
|
switch (tokens[i].type)
|
||||||
switch (nextToken.type)
|
|
||||||
{
|
{
|
||||||
case tok!"identifier":
|
case tok!"identifier":
|
||||||
case tok!"stringLiteral":
|
case tok!"stringLiteral":
|
||||||
case tok!"wstringLiteral":
|
case tok!"wstringLiteral":
|
||||||
case tok!"dstringLiteral":
|
case tok!"dstringLiteral":
|
||||||
return cast(int) nextToken.text.countUntil('\n');
|
auto c = cast(int) tokens[i].text.countUntil('\n');
|
||||||
|
if (c == -1)
|
||||||
|
return cast(int) tokens[i].text.length;
|
||||||
mixin (generateFixedLengthCases());
|
mixin (generateFixedLengthCases());
|
||||||
default: return -1;
|
default :
|
||||||
|
return INVALID_TOKEN_LENGTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int currentTokenLength() pure @safe @nogc
|
||||||
|
{
|
||||||
|
return tokenLength(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextTokenLength() pure @safe @nogc
|
||||||
|
{
|
||||||
|
if (index + 1 >= tokens.length)
|
||||||
|
return INVALID_TOKEN_LENGTH;
|
||||||
|
return tokenLength(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
ref current() const @property
|
ref current() const @property
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -684,7 +753,7 @@ private:
|
||||||
|
|
||||||
void newline()
|
void newline()
|
||||||
{
|
{
|
||||||
output.write("\n");
|
output.put("\n");
|
||||||
currentLineLength = 0;
|
currentLineLength = 0;
|
||||||
if (index < tokens.length)
|
if (index < tokens.length)
|
||||||
{
|
{
|
||||||
|
@ -697,16 +766,16 @@ private:
|
||||||
void write(string str)
|
void write(string str)
|
||||||
{
|
{
|
||||||
currentLineLength += str.length;
|
currentLineLength += str.length;
|
||||||
output.write(str);
|
output.put(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeToken()
|
void writeToken()
|
||||||
{
|
{
|
||||||
currentLineLength += currentTokenLength();
|
currentLineLength += currentTokenLength();
|
||||||
if (current.text is null)
|
if (current.text is null)
|
||||||
output.write(str(current.type));
|
output.put(str(current.type));
|
||||||
else
|
else
|
||||||
output.write(current.text);
|
output.put(current.text);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,13 +786,13 @@ private:
|
||||||
foreach (i; 0 .. indentLevel + tempIndent)
|
foreach (i; 0 .. indentLevel + tempIndent)
|
||||||
{
|
{
|
||||||
currentLineLength += config.tabSize;
|
currentLineLength += config.tabSize;
|
||||||
output.write("\t");
|
output.put("\t");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
foreach (i; 0 .. indentLevel + tempIndent)
|
foreach (i; 0 .. indentLevel + tempIndent)
|
||||||
foreach (j; 0 .. config.indentSize)
|
foreach (j; 0 .. config.indentSize)
|
||||||
{
|
{
|
||||||
output.write(" ");
|
output.put(" ");
|
||||||
currentLineLength++;
|
currentLineLength++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -743,8 +812,8 @@ private:
|
||||||
/// Length of the current line (so far)
|
/// Length of the current line (so far)
|
||||||
uint currentLineLength = 0;
|
uint currentLineLength = 0;
|
||||||
|
|
||||||
/// File to output to
|
/// Output to write output to
|
||||||
File output;
|
OutputRange output;
|
||||||
|
|
||||||
/// Tokens being formatted
|
/// Tokens being formatted
|
||||||
const(Token)[] tokens;
|
const(Token)[] tokens;
|
||||||
|
@ -895,33 +964,32 @@ private:
|
||||||
|
|
||||||
string generateFixedLengthCases()
|
string generateFixedLengthCases()
|
||||||
{
|
{
|
||||||
import std.algorithm:map;
|
import std.algorithm : map;
|
||||||
import std.string:format;
|
import std.string : format;
|
||||||
|
|
||||||
string[] fixedLengthTokens = [
|
string[] fixedLengthTokens = ["abstract", "alias", "align", "asm", "assert",
|
||||||
"abstract", "alias", "align", "asm", "assert", "auto", "body", "bool",
|
"auto", "body", "bool", "break", "byte", "case", "cast", "catch",
|
||||||
"break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat",
|
"cdouble", "cent", "cfloat", "char", "class", "const", "continue",
|
||||||
"char", "class", "const", "continue", "creal", "dchar", "debug", "default",
|
"creal", "dchar", "debug", "default", "delegate", "delete", "deprecated",
|
||||||
"delegate", "delete", "deprecated", "do", "double", "else", "enum",
|
"do", "double", "else", "enum", "export", "extern", "false", "final",
|
||||||
"export", "extern", "false", "final", "finally", "float", "for", "foreach",
|
"finally", "float", "for", "foreach", "foreach_reverse", "function",
|
||||||
"foreach_reverse", "function", "goto", "idouble", "if", "ifloat",
|
"goto", "idouble", "if", "ifloat", "immutable", "import", "in", "inout",
|
||||||
"immutable", "import", "in", "inout", "int", "interface", "invariant",
|
"int", "interface", "invariant", "ireal", "is", "lazy", "long", "macro",
|
||||||
"ireal", "is", "lazy", "long", "macro", "mixin", "module", "new", "nothrow",
|
"mixin", "module", "new", "nothrow", "null", "out", "override",
|
||||||
"null", "out", "override", "package", "pragma", "private", "protected",
|
"package", "pragma", "private", "protected", "public", "pure", "real",
|
||||||
"public", "pure", "real", "ref", "return", "scope", "shared", "short",
|
"ref", "return", "scope", "shared", "short", "static", "struct", "super",
|
||||||
"static", "struct", "super", "switch", "synchronized", "template", "this",
|
"switch", "synchronized", "template", "this", "throw", "true", "try",
|
||||||
"throw", "true", "try", "typedef", "typeid", "typeof", "ubyte", "ucent",
|
"typedef", "typeid", "typeof", "ubyte", "ucent", "uint", "ulong",
|
||||||
"uint", "ulong", "union", "unittest", "ushort", "version", "void",
|
"union", "unittest", "ushort", "version", "void", "volatile", "wchar",
|
||||||
"volatile", "wchar", "while", "with", "__DATE__", "__EOF__", "__FILE__",
|
"while", "with", "__DATE__", "__EOF__", "__FILE__", "__FUNCTION__",
|
||||||
"__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters",
|
"__gshared", "__LINE__", "__MODULE__", "__parameters",
|
||||||
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits", "__vector",
|
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits",
|
||||||
"__VENDOR__", "__VERSION__", ",", ".", "..", "...", "/", "/=", "!", "!<",
|
"__vector", "__VENDOR__", "__VERSION__", ",", ".", "..", "...", "/",
|
||||||
"!<=", "!<>", "!<>=", "!=", "!>", "!>=", "$", "%", "%=", "&", "&&", "&=",
|
"/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", "!>", "!>=", "$", "%", "%=",
|
||||||
"(", ")", "*", "*=", "+", "++", "+=", "-", "--", "-=", ":", ";", "<", "<<",
|
"&", "&&", "&=", "(", ")", "*", "*=", "+", "++", "+=", "-", "--", "-=",
|
||||||
"<<=", "<=", "<>", "<>=", "=", "==", "=>", ">", ">=", ">>", ">>=", ">>>",
|
":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>", ">",
|
||||||
">>>=", "?", "@", "[", "]", "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
|
">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", "]", "^", "^=", "^^",
|
||||||
"}", "~", "~="
|
"^^=", "{", "|", "|=", "||", "}", "~", "~="];
|
||||||
];
|
return fixedLengthTokens.map!(a => format(`case tok!"%s": return %d;`, a,
|
||||||
|
a.length)).join("\n\t");
|
||||||
return fixedLengthTokens.map!(a => format(`case tok!"%s": return %d;`, a, a.length)).join("\n\t");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import std.stdio;
|
||||||
|
class Foo {}
|
||||||
|
import std.conv;
|
||||||
|
void main() {return;}
|
||||||
|
const baz = 11;
|
||||||
|
class Foo2:Foo {}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
import std.conv;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baz = 11;
|
||||||
|
|
||||||
|
class Foo2 : Foo
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
class U0 : Exception {
|
||||||
|
this() @safe pure nothrow { super("U0 error message"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class U1 : Exception {
|
||||||
|
this() @safe pure nothrow { super("U1 error message"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo() {
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
foreach (immutable i; 0 .. 2) {
|
||||||
|
try {
|
||||||
|
i.bar;
|
||||||
|
} catch (U0) {
|
||||||
|
"Function foo caught exception U0".writeln;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bar(in int i) @safe pure {
|
||||||
|
i.baz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void baz(in int i) @safe pure {
|
||||||
|
throw i ? new U1 : new U0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
foo;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
class U0 : Exception
|
||||||
|
{
|
||||||
|
this() @safe pure nothrow
|
||||||
|
{
|
||||||
|
super("U0 error message");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class U1 : Exception
|
||||||
|
{
|
||||||
|
this() @safe pure nothrow
|
||||||
|
{
|
||||||
|
super("U1 error message");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
foreach (immutable i; 0 .. 2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
i.bar;
|
||||||
|
}
|
||||||
|
catch(U0)
|
||||||
|
{
|
||||||
|
"Function foo caught exception U0".writeln;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bar(in int i) @safe pure
|
||||||
|
{
|
||||||
|
i.baz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void baz(in int i) @safe pure
|
||||||
|
{
|
||||||
|
throw i ? new U1 : new U0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
foo;
|
||||||
|
}
|
|
@ -10,5 +10,5 @@ void main()
|
||||||
++lines;
|
++lines;
|
||||||
sumLength += line.length;
|
sumLength += line.length;
|
||||||
}
|
}
|
||||||
writeln("Average line length: ", lines ? sumLength / lines:0);
|
writeln("Average line length: ", lines ? sumLength / lines : 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@ void main()
|
||||||
{
|
{
|
||||||
immutable interval = tuple(1, 100);
|
immutable interval = tuple(1, 100);
|
||||||
writefln("Guess my target number that is between "
|
writefln("Guess my target number that is between "
|
||||||
~ "%d and %d (inclusive).\n",
|
~ "%d and %d (inclusive).\n", interval[]);
|
||||||
interval[]);
|
|
||||||
immutable target = uniform!"[]"(interval[]);
|
immutable target = uniform!"[]"(interval[]);
|
||||||
foreach (immutable i; sequence!q{n})
|
foreach (immutable i; sequence!q{n})
|
||||||
{
|
{
|
||||||
|
@ -31,6 +30,6 @@ void main()
|
||||||
writeln(" Well guessed.");
|
writeln(" Well guessed.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
writeln(answer < target ? " Too low.":" Too high.");
|
writeln(answer < target ? " Too low." : " Too high.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import std.stdio, std.math, std.range, std.algorithm, std.numeric, std.traits, std.typecons;
|
|
||||||
|
|
||||||
double hero(in uint a, in uint b, in uint c) pure nothrow @safe @nogc {
|
|
||||||
immutable s = (a + b + c) / 2.0;
|
|
||||||
immutable a2 = s * (s - a) * (s - b) * (s - c);
|
|
||||||
return (a2 > 0) ? a2.sqrt : 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isHeronian(in uint a, in uint b, in uint c) pure nothrow @safe @nogc {
|
|
||||||
immutable h = hero(a, b, c);
|
|
||||||
return h > 0 && h.floor == h.ceil;
|
|
||||||
}
|
|
||||||
|
|
||||||
T gcd3(T)(in T x, in T y, in T z) pure nothrow @safe @nogc {
|
|
||||||
return gcd(gcd(x, y), z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() /*@safe*/ {
|
|
||||||
enum uint maxSide = 200;
|
|
||||||
|
|
||||||
// Sort by increasing area, perimeter, then sides.
|
|
||||||
//auto h = cartesianProduct!3(iota(1, maxSide + 1))
|
|
||||||
auto r = iota(1, maxSide + 1);
|
|
||||||
const h = cartesianProduct(r, r, r)
|
|
||||||
//.filter!({a, b, c} => ...
|
|
||||||
.filter!(t => t[0] <= t[1] && t[1] <= t[2] &&
|
|
||||||
t[0] + t[1] > t[2] &&
|
|
||||||
t[].gcd3 == 1 && t[].isHeronian)
|
|
||||||
.array
|
|
||||||
.schwartzSort!(t => tuple(t[].hero, t[].only.sum, t.reverse))
|
|
||||||
.release;
|
|
||||||
|
|
||||||
static void showTriangles(R)(R ts) @safe {
|
|
||||||
"Area Perimeter Sides".writeln;
|
|
||||||
foreach (immutable t; ts)
|
|
||||||
writefln("%3s %8d %3dx%dx%d", t[].hero, t[].only.sum, t[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
writefln("Primitive Heronian triangles with sides up to %d: %d", maxSide, h.length);
|
|
||||||
"\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:".writeln;
|
|
||||||
showTriangles(h.take(10));
|
|
||||||
|
|
||||||
"\nAll with area 210 subject to the previous ordering:".writeln;
|
|
||||||
showTriangles(h.filter!(t => t[].hero == 210));
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
import std.stdio, std.math, std.range, std.algorithm, std.numeric, std.traits,
|
|
||||||
std.typecons;
|
|
||||||
|
|
||||||
double hero(in uint a, in uint b, in uint c) pure nothrow @safe@nogc
|
|
||||||
{
|
|
||||||
immutable s = (a + b + c) / 2.0;
|
|
||||||
immutable a2 = s * (s - a) * (s - b) * (s - c);
|
|
||||||
return (a2 > 0) ? a2.sqrt : 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isHeronian(in uint a, in uint b, in uint c) pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
immutable h = hero(a, b, c);
|
|
||||||
return h > 0 && h.floor == h.ceil;
|
|
||||||
}
|
|
||||||
|
|
||||||
T gcd3(T)(in T x, in T y, in T z) pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
return gcd(gcd(x, y), z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() /*@safe*/
|
|
||||||
{
|
|
||||||
enum uint maxSide = 200;
|
|
||||||
// Sort by increasing area, perimeter, then sides.
|
|
||||||
//auto h = cartesianProduct!3(iota(1, maxSide + 1))
|
|
||||||
auto r = iota(1, maxSide + 1);
|
|
||||||
const h = cartesianProduct(r, r, r)
|
|
||||||
//.filter!({a, b, c} => ...
|
|
||||||
.filter!(t => t[0] <= t[1] && t[1] <= t[2] && t[0] + t[1] > t[2] &&
|
|
||||||
t[].gcd3 == 1 && t[].isHeronian)
|
|
||||||
.array.schwartzSort!(t => tuple(t[].hero, t[].only.sum, t.reverse))
|
|
||||||
.release;
|
|
||||||
|
|
||||||
static void showTriangles(R)(R ts) @safe
|
|
||||||
{
|
|
||||||
"Area Perimeter Sides".writeln;
|
|
||||||
foreach (immutable t; ts)
|
|
||||||
writefln("%3s %8d %3dx%dx%d", t[].hero, t[].only.sum, t[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
writefln("Primitive Heronian triangles with sides up to %d: %d", maxSide,
|
|
||||||
h.length);
|
|
||||||
"\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:".writeln;
|
|
||||||
showTriangles(h.take(10));
|
|
||||||
"\nAll with area 210 subject to the previous ordering:".writeln;
|
|
||||||
showTriangles(h.filter!(t => t[].hero == 210));
|
|
||||||
}
|
|
|
@ -0,0 +1 @@
|
||||||
|
@property double y();
|
|
@ -0,0 +1 @@
|
||||||
|
@property double y();
|
|
@ -0,0 +1,24 @@
|
||||||
|
import std.algorithm: swap; // from Phobos standard library
|
||||||
|
|
||||||
|
// The D solution uses templates and it's similar to the C++ one:
|
||||||
|
void mySwap(T)(ref T left, ref T right) {
|
||||||
|
auto temp = left;
|
||||||
|
left = right;
|
||||||
|
right = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
int[] a = [10, 20];
|
||||||
|
writeln(a);
|
||||||
|
|
||||||
|
// The std.algorithm standard library module
|
||||||
|
// contains a generic swap:
|
||||||
|
swap(a[0], a[1]);
|
||||||
|
writeln(a);
|
||||||
|
|
||||||
|
// Using mySwap:
|
||||||
|
mySwap(a[0], a[1]);
|
||||||
|
writeln(a);
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import std.algorithm : swap; // from Phobos standard library
|
||||||
|
|
||||||
|
// The D solution uses templates and it's similar to the C++ one:
|
||||||
|
void mySwap(T)(ref T left, ref T right)
|
||||||
|
{
|
||||||
|
auto temp = left;
|
||||||
|
left = right;
|
||||||
|
right = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
int[] a = [10, 20];
|
||||||
|
writeln(a);
|
||||||
|
// The std.algorithm standard library module
|
||||||
|
// contains a generic swap:
|
||||||
|
swap(a[0], a[1]);
|
||||||
|
writeln(a);
|
||||||
|
// Using mySwap:
|
||||||
|
mySwap(a[0], a[1]);
|
||||||
|
writeln(a);
|
||||||
|
}
|
|
@ -4,5 +4,5 @@ set -e
|
||||||
for source in *.d
|
for source in *.d
|
||||||
do
|
do
|
||||||
../bin/dfmt "${source}" >"${source}.out"
|
../bin/dfmt "${source}" >"${source}.out"
|
||||||
diff -u "${source}.ref" "${source}.out" || echo "fail ${source}"
|
diff -u "${source}.ref" "${source}.out"
|
||||||
done
|
done
|
||||||
|
|
Loading…
Reference in New Issue