Initial commit
This commit is contained in:
parent
139a43922d
commit
5d324e81be
|
@ -0,0 +1,7 @@
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
|
@ -0,0 +1,2 @@
|
||||||
|
*.o
|
||||||
|
bin
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "libdparse"]
|
||||||
|
path = libdparse
|
||||||
|
url = https://github.com/Hackerpilot/libdparse.git
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5d5c6b161e6b90621ac58c8402629b99ac7e83e1
|
|
@ -0,0 +1,8 @@
|
||||||
|
SRC := $(shell find src -name "*.d") $(shell find libdparse/src -name "*.d")
|
||||||
|
COMPILER := dmd
|
||||||
|
INCLUDE_PATHS := -Ilibdparse/src
|
||||||
|
FLAGS := -g -w $(INCLUDE_PATHS)
|
||||||
|
|
||||||
|
all: $(SRC)
|
||||||
|
$(COMPILER) $(FLAGS) $(SRC) -ofbin/dfmt
|
||||||
|
|
|
@ -0,0 +1,474 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
* obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
* this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
* execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
* Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
* do so, all subject to the following:
|
||||||
|
*
|
||||||
|
* The copyright notices in the Software and this entire statement, including
|
||||||
|
* the above license grant, this restriction and the following disclaimer,
|
||||||
|
* must be included in all copies of the Software, in whole or in part, and
|
||||||
|
* all derivative works of the Software, unless such copies or derivative
|
||||||
|
* works are solely in the form of machine-executable object code generated by
|
||||||
|
* a source language processor.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
module dfmt;
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
import std.d.lexer;
|
||||||
|
import std.d.parser;
|
||||||
|
import std.d.formatter;
|
||||||
|
import std.array;
|
||||||
|
|
||||||
|
int main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.length < 2)
|
||||||
|
{
|
||||||
|
writeln("File name is a required argument");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
File f = File(args[1]);
|
||||||
|
ubyte[] buffer = new ubyte[](f.size);
|
||||||
|
f.rawRead(buffer);
|
||||||
|
LexerConfig config;
|
||||||
|
config.stringBehavior = StringBehavior.source;
|
||||||
|
config.whitespaceBehavior = WhitespaceBehavior.skip;
|
||||||
|
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
||||||
|
auto tokens = byToken(buffer, config, &cache).array();
|
||||||
|
auto tokenFormatter = TokenFormatter(tokens, stdout);
|
||||||
|
tokenFormatter.format();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TokenFormatter
|
||||||
|
{
|
||||||
|
this(const(Token)[] tokens, File output)
|
||||||
|
{
|
||||||
|
this.tokens = tokens;
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void format()
|
||||||
|
{
|
||||||
|
while (index < tokens.length)
|
||||||
|
formatStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
invariant
|
||||||
|
{
|
||||||
|
assert (indentLevel >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatStep()
|
||||||
|
{
|
||||||
|
assert (index < tokens.length);
|
||||||
|
if (current.type == tok!"comment")
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
else if (isStringLiteral(current.type) || isNumberLiteral(current.type))
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
}
|
||||||
|
else if (current.type == tok!"case" || current.type == tok!"default")
|
||||||
|
{
|
||||||
|
if (current.type == tok!"case")
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
write(" ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
writeToken();
|
||||||
|
auto i = indentLevel;
|
||||||
|
int braceLevel = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (current.type == tok!":")
|
||||||
|
{
|
||||||
|
if (peekIs(tok!"case") || peekIs(tok!"default"))
|
||||||
|
{
|
||||||
|
indentLevel = i;
|
||||||
|
writeToken();
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indentLevel++;
|
||||||
|
writeToken();
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekIs(tok!"case") || peekIs(tok!"default"))
|
||||||
|
{
|
||||||
|
indentLevel = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (current.type == tok!"{") braceLevel++;
|
||||||
|
else if (peekIs(tok!"}"))
|
||||||
|
{
|
||||||
|
braceLevel--;
|
||||||
|
if (braceLevel < 0)
|
||||||
|
{
|
||||||
|
indentLevel = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatStep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (current.type == tok!"if" || current.type == tok!"while" || current.type == tok!"for"
|
||||||
|
|| current.type == tok!"foreach" || current.type == tok!"foreach_reverse")
|
||||||
|
{
|
||||||
|
currentLineLength += currentTokenLength() + 1;
|
||||||
|
writeToken();
|
||||||
|
write(" ");
|
||||||
|
int parenMatch = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (current.type == tok!";")
|
||||||
|
{
|
||||||
|
write("; ");
|
||||||
|
currentLineLength += 2;
|
||||||
|
index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (current.type == tok!"(")
|
||||||
|
parenMatch++;
|
||||||
|
else if (current.type == tok!")")
|
||||||
|
parenMatch--;
|
||||||
|
formatStep();
|
||||||
|
}
|
||||||
|
while (parenMatch > 0);
|
||||||
|
if (current.type != tok!"{" && current.type != tok!";")
|
||||||
|
{
|
||||||
|
indentLevel++;
|
||||||
|
newline();
|
||||||
|
deIndentOnNewline++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isKeyword(current.type))
|
||||||
|
{
|
||||||
|
if (current.type != tok!"default" && current.type != tok!"cast"
|
||||||
|
&& !peekIs(tok!"."))
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
write(" ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
writeToken();
|
||||||
|
}
|
||||||
|
else if (isBasicType(current.type))
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
if (current.type == tok!"identifier")
|
||||||
|
write(" ");
|
||||||
|
}
|
||||||
|
else if (isOperator(current.type))
|
||||||
|
{
|
||||||
|
switch (current.type)
|
||||||
|
{
|
||||||
|
case tok!"*":
|
||||||
|
case tok!"~":
|
||||||
|
case tok!"&":
|
||||||
|
case tok!"+":
|
||||||
|
case tok!"-":
|
||||||
|
// TODO: unary
|
||||||
|
case tok!"@":
|
||||||
|
case tok!"!":
|
||||||
|
case tok!".":
|
||||||
|
case tok!"...":
|
||||||
|
case tok!"(":
|
||||||
|
case tok!")":
|
||||||
|
case tok!"[":
|
||||||
|
case tok!"++":
|
||||||
|
case tok!"--":
|
||||||
|
case tok!"$":
|
||||||
|
writeToken();
|
||||||
|
break;
|
||||||
|
case tok!"]":
|
||||||
|
writeToken();
|
||||||
|
if (current.type == tok!"identifier")
|
||||||
|
write(" ");
|
||||||
|
break;
|
||||||
|
case tok!";":
|
||||||
|
writeToken();
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case tok!"{":
|
||||||
|
if (otbs)
|
||||||
|
write(" {");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newline();
|
||||||
|
write("{");
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
indentLevel++;
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case tok!"}":
|
||||||
|
write("}");
|
||||||
|
index++;
|
||||||
|
if (otbs && current.type == tok!"else")
|
||||||
|
write(" ");
|
||||||
|
else
|
||||||
|
newline();
|
||||||
|
break;
|
||||||
|
case tok!",":
|
||||||
|
if (currentLineLength + nextTokenLength() >= columnSoftLimit)
|
||||||
|
{
|
||||||
|
write(",");
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
write(", ");
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
case tok!"^^":
|
||||||
|
case tok!"^=":
|
||||||
|
case tok!"^":
|
||||||
|
case tok!"~=":
|
||||||
|
case tok!"<<=":
|
||||||
|
case tok!"<<":
|
||||||
|
case tok!"<=":
|
||||||
|
case tok!"<>=":
|
||||||
|
case tok!"<>":
|
||||||
|
case tok!"<":
|
||||||
|
case tok!"==":
|
||||||
|
case tok!"=>":
|
||||||
|
case tok!"=":
|
||||||
|
case tok!">=":
|
||||||
|
case tok!">>=":
|
||||||
|
case tok!">>>=":
|
||||||
|
case tok!">>>":
|
||||||
|
case tok!">>":
|
||||||
|
case tok!">":
|
||||||
|
case tok!"|=":
|
||||||
|
case tok!"||":
|
||||||
|
case tok!"|":
|
||||||
|
case tok!"-=":
|
||||||
|
case tok!"!<=":
|
||||||
|
case tok!"!<>=":
|
||||||
|
case tok!"!<>":
|
||||||
|
case tok!"!<":
|
||||||
|
case tok!"!=":
|
||||||
|
case tok!"!>=":
|
||||||
|
case tok!"!>":
|
||||||
|
case tok!"?":
|
||||||
|
case tok!"/=":
|
||||||
|
case tok!"/":
|
||||||
|
case tok!"..":
|
||||||
|
case tok!"*=":
|
||||||
|
case tok!"&=":
|
||||||
|
case tok!"&&":
|
||||||
|
case tok!"%=":
|
||||||
|
case tok!"%":
|
||||||
|
case tok!"+=":
|
||||||
|
case tok!":":
|
||||||
|
if (currentLineLength + nextTokenLength() >= columnSoftLimit)
|
||||||
|
newline();
|
||||||
|
else
|
||||||
|
write(" ");
|
||||||
|
writeToken();
|
||||||
|
write(" ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert (false, str(current.type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (current.type == tok!"identifier")
|
||||||
|
{
|
||||||
|
writeToken();
|
||||||
|
if (current.type == tok!"identifier")
|
||||||
|
write(" ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentTokenLength()
|
||||||
|
{
|
||||||
|
switch (current.type)
|
||||||
|
{
|
||||||
|
mixin (generateFixedLengthCases());
|
||||||
|
default: return cast(int) current.text.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextTokenLength()
|
||||||
|
{
|
||||||
|
if (index + 1 >= tokens.length)
|
||||||
|
return INVALID_TOKEN_LENGTH;
|
||||||
|
auto nextToken = tokens[index + 1];
|
||||||
|
switch (nextToken.type)
|
||||||
|
{
|
||||||
|
case tok!"identifier":
|
||||||
|
case tok!"stringLiteral":
|
||||||
|
case tok!"wstringLiteral":
|
||||||
|
case tok!"dstringLiteral":
|
||||||
|
return cast(int) nextToken.text.length;
|
||||||
|
mixin (generateFixedLengthCases());
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ref current() const @property
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert (index < tokens.length);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
return tokens[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peekBackIs(IdType tokenType)
|
||||||
|
{
|
||||||
|
return (index >= 1) && tokens[index - 1].type == tokenType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peekIs(IdType tokenType)
|
||||||
|
{
|
||||||
|
auto i = index + 1;
|
||||||
|
while (i < tokens.length && tokens[i].type == tok!"comment")
|
||||||
|
i++;
|
||||||
|
return i < tokens.length && tokens[i].type == tokenType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void newline()
|
||||||
|
{
|
||||||
|
output.write("\n");
|
||||||
|
currentLineLength = 0;
|
||||||
|
if (deIndentOnNewline)
|
||||||
|
{
|
||||||
|
deIndentOnNewline--;
|
||||||
|
indentLevel--;
|
||||||
|
}
|
||||||
|
if (index < tokens.length)
|
||||||
|
{
|
||||||
|
if (current.type == tok!"}")
|
||||||
|
indentLevel--;
|
||||||
|
indent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(string str)
|
||||||
|
{
|
||||||
|
currentLineLength += str.length;
|
||||||
|
output.write(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToken()
|
||||||
|
{
|
||||||
|
currentLineLength += currentTokenLength();
|
||||||
|
if (current.text is null)
|
||||||
|
output.write(str(current.type));
|
||||||
|
else
|
||||||
|
output.write(current.text);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void indent()
|
||||||
|
{
|
||||||
|
import std.range : repeat, take;
|
||||||
|
if (useTabs)
|
||||||
|
foreach (i; 0 .. indentLevel)
|
||||||
|
{
|
||||||
|
currentLineLength += tabSize;
|
||||||
|
output.write("\t");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
foreach (i; 0 .. indentLevel)
|
||||||
|
foreach (j; 0 .. indentSize)
|
||||||
|
{
|
||||||
|
output.write(" ");
|
||||||
|
currentLineLength++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Length of an invalid token
|
||||||
|
enum int INVALID_TOKEN_LENGTH = -1;
|
||||||
|
|
||||||
|
/// Current index into the tokens array
|
||||||
|
size_t index;
|
||||||
|
|
||||||
|
/// Current indent level
|
||||||
|
int indentLevel;
|
||||||
|
|
||||||
|
/// Number of spaces used for indentation
|
||||||
|
uint indentSize = 4;
|
||||||
|
|
||||||
|
/// Use tabs or spaces
|
||||||
|
bool useTabs = false;
|
||||||
|
|
||||||
|
/// Size of a tab character
|
||||||
|
uint tabSize = 8;
|
||||||
|
|
||||||
|
/// Soft line wrap limit
|
||||||
|
uint columnSoftLimit = 80;
|
||||||
|
|
||||||
|
/// Hard line wrap limit
|
||||||
|
uint columnHardLimit = 120;
|
||||||
|
|
||||||
|
/// Length of the current line (so far)
|
||||||
|
uint currentLineLength = 0;
|
||||||
|
|
||||||
|
/// Use the One True Brace Style
|
||||||
|
bool otbs = false;
|
||||||
|
|
||||||
|
int deIndentOnNewline = 0;
|
||||||
|
|
||||||
|
/// File to output to
|
||||||
|
File output;
|
||||||
|
|
||||||
|
/// Tokens being formatted
|
||||||
|
const(Token)[] tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
string generateFixedLengthCases()
|
||||||
|
{
|
||||||
|
import std.algorithm:map;
|
||||||
|
import std.string:format;
|
||||||
|
|
||||||
|
string[] fixedLengthTokens = [
|
||||||
|
"abstract", "alias", "align", "asm", "assert", "auto", "body", "bool",
|
||||||
|
"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__", ",", ".", "..", "...", "/", "/=", "!", "!<",
|
||||||
|
"!<=", "!<>", "!<>=", "!=", "!>", "!>=", "$", "%", "%=", "&", "&&", "&=",
|
||||||
|
"(", ")", "*", "*=", "+", "++", "+=", "-", "--", "-=", ":", ";", "<", "<<",
|
||||||
|
"<<=", "<=", "<>", "<>=", "=", "==", "=>", ">", ">=", ">>", ">>=", ">>>",
|
||||||
|
">>>=", "?", "@", "[", "]", "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
|
||||||
|
"}", "~", "~="
|
||||||
|
];
|
||||||
|
|
||||||
|
return fixedLengthTokens.map!(a => format(`case tok!"%s": return %d;`, a, a.length)).join("\n\t");
|
||||||
|
}
|
Loading…
Reference in New Issue