D-Scanner/formatter.d

3918 lines
96 KiB
D

module formatter;
import std.algorithm;
import std.range;
import std.stdio;
import std.typetuple;
import std.d.ast;
import std.d.lexer;
//debug = verbose;
/**
* The only brace styles worth using.
*/
enum IndentStyle
{
/**
* ---
* if (something)
* {
* foo();
* bar();
* }
* else
* {
* bar();
* baz();
* }
* ---
*/
allman,
/**
* ---
* if (something) {
* foo();
* bar();
* } else {
* bar();
* baz();
* }
* ---
*/
otbs,
}
/**
*
*/
void format(Sink)(Sink sink, Module mod, bool useTabs = false,
IndentStyle style = IndentStyle.allman, uint indentWith = 4)
{
Formatter!Sink formatter = new Formatter!(Sink)(sink, useTabs, style, indentWith);
formatter.format(mod);
}
class Formatter(Sink)
{
/**
* Parameters:
* sink = the output range that the formatted source code is placed in
* useTabs = if true, tabs are used for indent levels instead of spaces
* style = the brace style
* indenteWidth = the number of spaces used for indentation if useTabs is false
*/
this(Sink sink, bool useTabs = false, IndentStyle style = IndentStyle.allman, uint indentWidth = 4)
{
this.sink = sink;
this.useTabs = useTabs;
this.indentWidth = indentWidth;
this.style = style;
}
void format(const AddExpression addExpression)
{
debug(verbose) writeln("AddExpression");
mixin(binary("addExpression"));
}
void format(const AliasDeclaration aliasDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("AliasDeclaration");
/**
LinkageAttribute linkageAttribute;
Type type;
Token name;
AliasInitializer[] initializers;
string comment;
**/
with(aliasDeclaration)
{
newThing(What.other);
putComment(comment);
putAttrs(attrs);
put("alias ");
if (initializers.length) // alias ident = a, ident2 = b, etc
{
foreach(count, init; initializers)
{
if (count)
put(", ");
format(init);
}
}
else
{
if (linkageAttribute)
{
format(linkageAttribute);
space();
}
if (type)
{
format(type);
space();
}
format(name);
}
put(";");
}
}
void format(const AliasInitializer aliasInitializer)
{
debug(verbose) writeln("AliasInitializer");
/**
Token name;
Type type;
**/
with(aliasInitializer)
{
format(name);
put(" = ");
format(type);
}
}
void format(const AliasThisDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("AliasThisDeclaration");
/**
Token identifier;
**/
putAttrs(attrs);
put("alias ");
format(decl.identifier);
put(" this;");
}
void format(const AlignAttribute alignAttribute)
{
debug(verbose) writeln("AlignAttribute");
/**
Token intLiteral;
**/
put("align");
if (alignAttribute.intLiteral.text)
{
put("(");
format(alignAttribute.intLiteral);
put(")");
}
}
void format(const AndAndExpression andAndExpression)
{
debug(verbose) writeln("AndAndExpression");
with(andAndExpression)
{
format(left);
if (right)
{
put(" && ");
format(right);
}
}
}
void format(const AndExpression andExpression)
{
debug(verbose) writeln("AndExpression");
with(andExpression)
{
format(left);
if (right)
{
put(" & ");
format(right);
}
}
}
void format(const ArgumentList argumentList)
{
debug(verbose) writeln("ArgumentList");
foreach(count, arg; argumentList.items)
{
if (count) put(", ");
format(arg);
}
}
void format(const Arguments arguments)
{
debug(verbose) writeln("Arguments");
put("(");
if (arguments.argumentList) format(arguments.argumentList);
put(")");
}
void format(const ArrayInitializer arrayInitializer)
{
debug(verbose) writeln("ArrayInitializer");
/**
ArrayMemberInitialization[] arrayMemberInitializations;
**/
put("[");
foreach(count, init; arrayInitializer.arrayMemberInitializations)
{
format(init);
if (count < arrayInitializer.arrayMemberInitializations.length - 1)
put(", ");
}
put("]");
}
void format(const ArrayLiteral arrayLiteral)
{
debug(verbose) writeln("ArrayLiteral");
/**
ArgumentList argumentList;
**/
put("[");
if (arrayLiteral.argumentList)
format(arrayLiteral.argumentList);
put("]");
}
void format(const ArrayMemberInitialization arrayMemberInitialization)
{
debug(verbose) writeln("ArrayMemberInitialization");
/**
AssignExpression assignExpression;
NonVoidInitializer nonVoidInitializer;
**/
with(arrayMemberInitialization)
{
if (assignExpression)
{
format(assignExpression);
put(":");
}
if (nonVoidInitializer)
format(nonVoidInitializer);
}
}
void format(const AsmAddExp asmAddExp)
{
assert(false);
}
void format(const AsmAndExp asmAndExp)
{
assert(false);
}
void format(const AsmBrExp asmBrExp)
{
assert(false);
}
void format(const AsmEqualExp asmEqualExp)
{
assert(false);
}
void format(const AsmExp asmExp)
{
assert(false);
}
void format(const AsmInstruction asmInstruction)
{
assert(false);
}
void format(const AsmLogAndExp asmLogAndExp)
{
assert(false);
}
void format(const AsmLogOrExp asmLogOrExp)
{
assert(false);
}
void format(const AsmMulExp asmMulExp)
{
assert(false);
}
void format(const AsmOrExp asmOrExp)
{
assert(false);
}
void format(const AsmPrimaryExp asmPrimaryExp)
{
assert(false);
}
void format(const AsmRelExp asmRelExp)
{
assert(false);
}
void format(const AsmShiftExp asmShiftExp)
{
assert(false);
}
void format(const AsmStatement asmStatement)
{
assert(false);
}
void format(const AsmTypePrefix asmTypePrefix)
{
assert(false);
}
void format(const AsmUnaExp asmUnaExp)
{
assert(false);
}
void format(const AsmXorExp asmXorExp)
{
assert(false);
}
void format(const AssertExpression assertExpression)
{
debug(verbose) writeln("AssertExpression");
/**
AssignExpression assertion;
AssignExpression message;
**/
with(assertExpression)
{
newThing(What.expr);
put("assert(");
format(assertion);
if (message)
{
put(", ");
format(message);
}
put(")");
}
}
void format(const AssignExpression assignExpression)
{
debug(verbose) writeln("AssignExpression");
/**
ExpressionNode ternaryExpression;
ExpressionNode assignExpression;
IdType operator;
**/
if (assignExpression.ternaryExpression)
format(assignExpression.ternaryExpression);
if(assignExpression.assignExpression)
{
space();
put(tokenRep(assignExpression.operator));
space();
format(assignExpression.assignExpression);
}
}
void format(const AssocArrayLiteral assocArrayLiteral)
{
debug(verbose) writeln("AssocArrayLiteral");
/**
KeyValuePairs keyValuePairs;
**/
put("[");
format(assocArrayLiteral.keyValuePairs);
put("]");
}
void format(const AtAttribute atAttribute)
{
debug(verbose) writeln("AtAttribute");
/**
FunctionCallExpression functionCallExpression;
ArgumentList argumentList;
Token identifier;
**/
with(atAttribute)
{
put("@");
format(identifier);
if (functionCallExpression) format(functionCallExpression);
else if(argumentList) format(argumentList);
}
}
void format(const Attribute att)
{
debug(verbose) writeln("Attribute");
/**
LinkageAttribute linkageAttribute;
AlignAttribute alignAttribute;
PragmaExpression pragmaExpression;
StorageClass storageClass;
IdType attribute;
**/
with(att)
{
if (linkageAttribute) format(linkageAttribute);
if (alignAttribute) format(alignAttribute);
if (pragmaExpression) format(pragmaExpression);
if (storageClass) format(storageClass);
if (attribute) put(tokenRep(attribute));
}
}
void format(const AttributeDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("AttributeDeclaration");
auto cIndent = indentLevel;
outdent();
newThing(What.attributeDecl);
putAttrs(attrs);
format(decl.attribute);
put(":");
indentLevel = cIndent;
}
void format(const AutoDeclaration decl)
{
debug(verbose) writeln("AutoDeclaration");
/**
Token[] identifiers;
Initializer[] initializers;
**/
// zip doesn't work here, dmd 2.064.2
assert(decl.identifiers.length == decl.initializers.length);
foreach(i; 0..decl.identifiers.length)
{
if (i) put(", ");
format(decl.identifiers[i]);
put(" = ");
format(decl.initializers[i]);
}
}
void format(const BlockStatement blockStatement)
{
debug(verbose) writeln("BlockStatement");
if (blockStatement.declarationsAndStatements is null)
{
space();
put("{}");
}
else
{
startBlock();
format(blockStatement.declarationsAndStatements);
endBlock();
}
}
void format(const BodyStatement bodyStatement)
{
debug(verbose) writeln("BodyStatement");
onNewline();
put("body");
format(bodyStatement.blockStatement);
}
void format(const BreakStatement breakStatement)
{
debug(verbose) writeln("BreakStatement");
put("break");
if (breakStatement.label != tok!"")
{
space();
format(breakStatement.label);
}
put(";");
}
void format(const BaseClass baseClass)
{
debug(verbose) writeln("BaseClass");
/**
IdentifierOrTemplateChain identifierOrTemplateChain;
TypeofExpression typeofExpression;
**/
with(baseClass)
{
if (identifierOrTemplateChain) format(identifierOrTemplateChain);
else if (typeofExpression) format(typeofExpression);
}
}
void format(const BaseClassList baseClassList)
{
debug(verbose) writeln("BaseClassList");
foreach(count, item; baseClassList.items)
{
format(item);
if (count < baseClassList.items.length - 1)
put(", ");
}
}
void format(const CaseRangeStatement caseRangeStatement)
{
debug(verbose) writeln("CaseRangeStatement");
/**
AssignExpression low;
AssignExpression high;
DeclarationsAndStatements declarationsAndStatements;
**/
with(caseRangeStatement)
{
if (low)
{
put("case ");
format(low);
put(": .. ");
}
put("case ");
format(high);
put(":");
formatCaseDecls(declarationsAndStatements);
}
}
void format(const CaseStatement caseStatement)
{
debug(verbose) writeln("CaseStatement");
/**
ArgumentList argumentList;
DeclarationsAndStatements declarationsAndStatements;
**/
with(caseStatement)
{
if (argumentList)
{
put("case ");
format(argumentList);
put(":");
}
formatCaseDecls(declarationsAndStatements);
}
}
void format(const CastExpression castExpression)
{
debug(verbose) writeln("CastExpression");
/**
Type type;
CastQualifier castQualifier;
UnaryExpression unaryExpression;
**/
with(castExpression)
{
put("cast(");
if (castQualifier)
{
format(castQualifier);
space();
}
if (type) format(type);
put(")");
if (unaryExpression) format(unaryExpression);
}
}
void format(const CastQualifier qual)
{
debug(verbose) writeln("CastQualifier");
/**
Token first;
Token second;
**/
format(qual.first);
if (qual.second != tok!"")
{
space();
format(qual.second);
}
}
void format(const Catch catch_)
{
debug(verbose) writeln("Catch");
/**
Type type;
Token identifier;
DeclarationOrStatement declarationOrStatement;
**/
with(catch_)
{
newThing(What.catch_);
put("catch(");
format(type);
if (identifier != tok!"")
{
space();
format(identifier);
}
put(")");
if (declarationOrStatement) maybeIndent(declarationOrStatement);
}
}
void format(const Catches catches)
{
debug(verbose) writeln("Catches");
/**
Catch[] catches;
LastCatch lastCatch;
**/
foreach(c; catches.catches)
format(c);
if (catches.lastCatch)
format(catches.lastCatch);
}
void format(const ClassDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("ClassDeclaration");
/**
Token name;
TemplateParameters templateParameters;
Constraint constraint;
BaseClassList baseClassList;
StructBody structBody;
string comment;
**/
newThing(What.aggregateDecl);
putComment(decl.comment);
putAttrs(attrs);
put("class ");
format(decl.name);
if (decl.templateParameters)
format(decl.templateParameters);
if (decl.constraint)
{
space();
format(decl.constraint);
}
if (decl.baseClassList)
{
put(": ");
format(decl.baseClassList);
}
format(decl.structBody);
}
void format(const CmpExpression cmpExpression)
{
debug(verbose) writeln("CmpExpression");
/**
ExpressionNode shiftExpression;
ExpressionNode equalExpression;
ExpressionNode identityExpression;
ExpressionNode relExpression;
ExpressionNode inExpression;
**/
with(cmpExpression)
{
if (shiftExpression) format(shiftExpression);
else if (equalExpression) format(equalExpression);
else if (identityExpression) format(identityExpression);
else if (relExpression) format(relExpression);
else if (inExpression) format(inExpression);
}
}
void format(const CompileCondition compileCondition)
{
debug(verbose) writeln("CompileCondition");
/**
VersionCondition versionCondition;
DebugCondition debugCondition;
StaticIfCondition staticIfCondition;
**/
with(compileCondition)
{
if (versionCondition) format(versionCondition);
else if (debugCondition) format(debugCondition);
else if (staticIfCondition) format(staticIfCondition);
}
}
void format(const ConditionalDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("ConditionalDeclaration");
/**
CompileCondition compileCondition;
Declaration[] trueDeclarations;
Declaration falseDeclaration;
**/
newThing(What.conditionalDecl);
putAttrs(attrs);
format(decl.compileCondition);
assert(decl.trueDeclarations.length <= 1); // spec bug?
if (decl.trueDeclarations.length)
{
if (isEmptyDeclaration(decl.trueDeclarations[0]))
{
space();
put("{}");
}
else
maybeIndent(decl.trueDeclarations[0]);
}
if (decl.falseDeclaration)
{
newThing(What.else_);
sink.put("else ");
if (isEmptyDeclaration(decl.falseDeclaration))
{
space();
put("{}");
return;
}
if (decl.falseDeclaration.conditionalDeclaration)
format(decl.falseDeclaration);
else
maybeIndent(decl.falseDeclaration);
}
}
void format(const ConditionalStatement stmnt)
{
debug(verbose) writeln("ConditionalStatement");
/**
CompileCondition compileCondition;
DeclarationOrStatement trueStatement;
DeclarationOrStatement falseStatement;
**/
newThing(What.other);
if (stmnt.compileCondition)
format(stmnt.compileCondition);
if (stmnt.trueStatement)
maybeIndent(stmnt.trueStatement);
if (stmnt.falseStatement)
{
newThing(What.else_);
put("else ");
// else if...
if (stmnt.falseStatement.statement &&
stmnt.falseStatement.statement.statementNoCaseNoDefault &&
stmnt.falseStatement.statement.statementNoCaseNoDefault.conditionalStatement)
{
format(stmnt.falseStatement.statement.statementNoCaseNoDefault.conditionalStatement);
return;
}
maybeIndent(stmnt.falseStatement);
}
}
void format(const Constraint constraint)
{
debug(verbose) writeln("Constraint");
if (constraint.expression)
{
indent();
onNewline();
put("if(");
format(constraint.expression);
put(")");
outdent();
}
}
void format(const Constructor constructor, const Attribute[] attrs = null)
{
debug(verbose) writeln("Constructor");
/**
Parameters parameters;
FunctionBody functionBody;
Constraint constraint;
MemberFunctionAttribute[] memberFunctionAttributes;
TemplateParameters templateParameters;
size_t location;
string comment;
**/
newThing(What.functionDecl);
putComment(constructor.comment);
putAttrs(attrs);
put("this");
if (constructor.templateParameters)
format(constructor.templateParameters);
if (constructor.parameters)
format(constructor.parameters);
foreach(att; constructor.memberFunctionAttributes)
{
space();
format(att);
}
if (constructor.constraint)
{
space();
format(constructor.constraint);
}
if (constructor.functionBody)
format(constructor.functionBody);
else
put(";");
}
void format(const ContinueStatement continueStatement)
{
debug(verbose) writeln("ContinueStatement");
put("continue");
if (continueStatement.label != tok!"")
{
space();
format(continueStatement.label);
}
put(";");
}
void format(const DebugCondition debugCondition)
{
debug(verbose) writeln("DebugCondition");
put("debug");
if (debugCondition.identifierOrInteger != tok!"")
{
put("(");
format(debugCondition.identifierOrInteger);
put(")");
}
}
void format(const DebugSpecification debugSpecification)
{
debug(verbose) writeln("DebugSpecification");
newThing(What.other);
put("debug = ");
format(debugSpecification.identifierOrInteger);
put(";");
}
void format(const Declaration declaration)
{
debug(verbose) writeln("Declaration");
with(declaration)
{
string mix(string[] s) {
string r;
foreach(c, d; s)
r ~= (c > 0 ? "else " : "") ~ "if (" ~ d ~ ") { format(" ~ d ~ ", attributes); }";
return r;
}
mixin(mix(possibleDeclarations));
if (declarations.length)
{
putAttrs(attributes);
startBlock();
foreach(d; declarations)
format(d);
endBlock();
}
}
}
void format(const DeclarationOrStatement declarationsOrStatement)
{
debug(verbose) writeln("DeclarationOrStatement");
with(declarationsOrStatement)
declaration !is null ? format(declaration) : format(statement);
}
void format(const DeclarationsAndStatements declarationsAndStatements)
{
debug(verbose) writeln("DeclarationsAndStatements");
foreach(ds; declarationsAndStatements.declarationsAndStatements)
format(ds);
}
void format(const Declarator declarator)
{
debug(verbose) writeln("Declarator");
/**
Token name;
Initializer initializer;
**/
format(declarator.name);
foreach(suffix; declarator.cstyle)
format(suffix);
if (declarator.initializer)
{
put(" = ");
format(declarator.initializer);
}
}
void format(const DefaultStatement defaultStatement)
{
debug(verbose) writeln("DefaultStatement");
/**
DeclarationsAndStatements declarationsAndStatements;
**/
put("default:");
formatCaseDecls(defaultStatement.declarationsAndStatements);
}
void format(const DeleteExpression deleteExpression)
{
debug(verbose) writeln("DeleteExpression");
put("delete ");
format(deleteExpression.unaryExpression);
}
void format(const DeleteStatement deleteStatement)
{
debug(verbose) writeln("DeleteStatement");
format(deleteStatement.deleteExpression);
put(";");
}
void format(const Deprecated deprecated_)
{
debug(verbose) writeln("Deprecated");
put("deprecated");
if (deprecated_.assignExpression)
{
put("(");
format(deprecated_.assignExpression);
put(")");
newline();
}
}
void format(const Destructor destructor, const Attribute[] attrs = null)
{
debug(verbose) writeln("Destructor");
/**
FunctionBody functionBody;
**/
newThing(What.functionDecl);
putAttrs(attrs);
put("~this()");
if (destructor.functionBody)
format(destructor.functionBody);
else
put(";");
}
void format(const DoStatement doStatement)
{
debug(verbose) writeln("DoStatement");
/**
StatementNoCaseNoDefault statementNoCaseNoDefault;
Expression expression;
**/
with(doStatement)
{
newThing(What.other);
put("do");
if (statementNoCaseNoDefault) format(statementNoCaseNoDefault);
space();
put("while(");
format(expression);
put(");");
}
}
void format(const EnumBody enumBody)
{
debug(verbose) writeln("EnumBody");
onNewline();
startBlock();
foreach(count, member; enumBody.enumMembers)
{
format(member);
if (count < enumBody.enumMembers.length - 1)
put(",");
if (member.comment.length)
{
space();
put(member.comment);
}
}
endBlock();
}
void format(const EnumDeclaration enumDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("EnumDeclaration");
/**
Token name;
Type type;
EnumBody enumBody;
string comment;
**/
with(enumDeclaration)
{
newThing(What.aggregateDecl);
putComment(comment);
putAttrs(attrs);
put("enum ");
if (name != tok!"")
{
format(name);
space();
}
if (type)
{
put(": ");
format(type);
space();
}
if (enumBody) format(enumBody);
}
}
void format(const EnumMember enumMember)
{
debug(verbose) writeln("EnumMember");
/**
Token name;
Type type;
AssignExpression assignExpression;
string comment;
**/
with(enumMember)
{
onNewline();
if (type) format(type);
format(name);
if (assignExpression)
{
put(" = ");
format(assignExpression);
}
}
}
void format(const EponymousTemplateDeclaration decl)
{
debug(verbose) writeln("EponymousTemplateDeclaration");
/**
Token name;
TemplateParameters templateParameters;
AssignExpression assignExpression;
**/
put("enum ");
put(tokenRep(decl.name));
if (decl.templateParameters)
format(decl.templateParameters);
if (decl.assignExpression)
{
put(" = ");
format(decl.assignExpression);
}
put(";");
}
void format(const EqualExpression equalExpression)
{
debug(verbose) writeln("EqualExpression");
mixin(binary("equalExpression"));
}
void format(const Expression expression)
{
debug(verbose) writeln("Expression");
foreach(count, item; expression.items)
{
if (count)
put(", ");
format(item);
}
}
void format(const ExpressionNode n)
{
debug(verbose) writeln("ExpressionNode");
if (cast(AddExpression) n) format(cast(AddExpression) n);
else if (cast(AndAndExpression) n) format(cast(AndAndExpression) n);
else if (cast(AndExpression) n) format(cast(AndExpression) n);
else if (cast(AsmAddExp) n) format(cast(AsmAddExp) n);
else if (cast(AsmAndExp) n) format(cast(AsmAndExp) n);
else if (cast(AsmEqualExp) n) format(cast(AsmEqualExp) n);
else if (cast(AsmLogAndExp) n) format(cast(AsmLogAndExp) n);
else if (cast(AsmLogOrExp) n) format(cast(AsmLogOrExp) n);
else if (cast(AsmMulExp) n) format(cast(AsmMulExp) n);
else if (cast(AsmOrExp) n) format(cast(AsmOrExp) n);
else if (cast(AsmRelExp) n) format(cast(AsmRelExp) n);
else if (cast(AsmShiftExp) n) format(cast(AsmShiftExp) n);
else if (cast(AssertExpression) n) format(cast(AssertExpression) n);
else if (cast(AssignExpression) n) format(cast(AssignExpression) n);
else if (cast(CmpExpression) n) format(cast(CmpExpression) n);
else if (cast(DeleteExpression) n) format(cast(DeleteExpression) n);
else if (cast(EqualExpression) n) format(cast(EqualExpression) n);
else if (cast(Expression) n) format(cast(Expression) n);
else if (cast(FunctionCallExpression) n) format(cast(FunctionCallExpression) n);
else if (cast(FunctionLiteralExpression) n) format(cast(FunctionLiteralExpression) n);
else if (cast(IdentityExpression) n) format(cast(IdentityExpression) n);
else if (cast(ImportExpression) n) format(cast(ImportExpression) n);
else if (cast(IndexExpression) n) format(cast(IndexExpression) n);
else if (cast(InExpression) n) format(cast(InExpression) n);
else if (cast(IsExpression) n) format(cast(IsExpression) n);
else if (cast(LambdaExpression) n) format(cast(LambdaExpression) n);
else if (cast(MixinExpression) n) format(cast(MixinExpression) n);
else if (cast(MulExpression) n) format(cast(MulExpression) n);
else if (cast(NewAnonClassExpression) n) format(cast(NewAnonClassExpression) n);
else if (cast(NewExpression) n) format(cast(NewExpression) n);
else if (cast(OrExpression) n) format(cast(OrExpression) n);
else if (cast(OrOrExpression) n) format(cast(OrOrExpression) n);
else if (cast(PostIncDecExpression) n) format(cast(PostIncDecExpression) n);
else if (cast(PowExpression) n) format(cast(PowExpression) n);
else if (cast(PragmaExpression) n) format(cast(PragmaExpression) n);
else if (cast(PreIncDecExpression) n) format(cast(PreIncDecExpression) n);
else if (cast(PrimaryExpression) n) format(cast(PrimaryExpression) n);
else if (cast(RelExpression) n) format(cast(RelExpression) n);
else if (cast(ShiftExpression) n) format(cast(ShiftExpression) n);
else if (cast(SliceExpression) n) format(cast(SliceExpression) n);
else if (cast(TemplateMixinExpression) n) format(cast(TemplateMixinExpression) n);
else if (cast(TernaryExpression) n) format(cast(TernaryExpression) n);
else if (cast(TraitsExpression) n) format(cast(TraitsExpression) n);
else if (cast(TypeidExpression) n) format(cast(TypeidExpression) n);
else if (cast(TypeofExpression) n) format(cast(TypeofExpression) n);
else if (cast(UnaryExpression) n) format(cast(UnaryExpression) n);
else if (cast(XorExpression) n) format(cast(XorExpression) n);
}
void format(const ExpressionStatement expressionStatement)
{
debug(verbose) writeln("ExpressionStatement");
if (expressionStatement.expression)
format(expressionStatement.expression);
put(";");
}
void format(const FinalSwitchStatement finalSwitchStatement)
{
debug(verbose) writeln("FinalSwitchStatement");
format(finalSwitchStatement.switchStatement, true);
}
void format(const Finally finally_)
{
debug(verbose) writeln("Finally");
put("finally");
format(finally_.declarationOrStatement);
}
void format(const ForStatement forStatement)
{
debug(verbose) writeln("ForStatement");
/**
DeclarationOrStatement initialization;
ExpressionStatement test;
Expression increment;
DeclarationOrStatement declarationOrStatement;
**/
with(forStatement)
{
newThing(What.other);
put("for(");
if (initialization) format(initialization);
else put(";");
space();
if (test) format(test);
else put(";");
space();
if (increment) format(increment);
put(")");
if (declarationOrStatement) maybeIndent(declarationOrStatement);
}
}
void format(const ForeachStatement foreachStatement)
{
debug(verbose) writeln("ForeachStatement");
/**
IdType type;
ForeachTypeList foreachTypeList;
ForeachType foreachType;
Expression low;
Expression high;
DeclarationOrStatement declarationOrStatement;
size_t startIndex;
**/
with(foreachStatement)
{
newThing(What.loop);
if (type) put(tokenRep(type));
else assert(false);
put("(");
if (foreachTypeList) format(foreachTypeList);
else if (foreachType) format(foreachType);
put("; ");
if (low) format(low);
if (high)
{
put("..");
format(high);
}
put(")");
format(declarationOrStatement);
}
}
void format(const ForeachType foreachType)
{
debug(verbose) writeln("ForeachType");
/**
IdType[] typeConstructors;
Type type;
Token identifier;
**/
with(foreachType)
{
foreach(tp; typeConstructors)
{
if (tp) put(tokenRep(tp));
space();
}
if (type)
{
format(type);
space();
}
format(identifier);
}
}
void format(const ForeachTypeList foreachTypeList)
{
debug(verbose) writeln("ForeachTypeList");
/**
ForeachType[] items;
**/
foreach(count, item; foreachTypeList.items)
{
format(item);
if (count < foreachTypeList.items.length - 1)
put(", ");
}
}
void format(const FunctionAttribute functionAttribute)
{
debug(verbose) writeln("FunctionAttribute");
/**
Token token;
AtAttribute atAttribute;
**/
with(functionAttribute)
{
if (token != tok!"")
{
format(token);
space();
}
if (atAttribute) format(atAttribute);
}
}
void format(const FunctionBody functionBody)
{
debug(verbose) writeln("FunctionBody");
with(functionBody)
{
if (blockStatement)
{
format(blockStatement);
return;
}
if (inStatement)
format(inStatement);
if (outStatement)
format(outStatement);
if (bodyStatement)
format(bodyStatement);
}
}
void format(const FunctionCallExpression functionCallExpression)
{
debug(verbose) writeln("FunctionCallExpression");
/**
Type type;
UnaryExpression unaryExpression;
TemplateArguments templateArguments;
Arguments arguments;
**/
with(functionCallExpression)
{
if (type) format(type);
if (unaryExpression) format(unaryExpression);
if (templateArguments) format(templateArguments);
if (arguments) format(arguments);
}
}
void format(const FunctionCallStatement functionCallStatement)
{
debug(verbose) writeln("FunctionCallStatement");
format(functionCallStatement.functionCallExpression);
put(";");
}
void format(const FunctionDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("FunctionDeclaration");
/**
bool hasAuto;
bool hasRef;
**/
newThing(What.functionDecl);
putComment(decl.comment);
putAttrs(attrs);
if (decl.returnType)
format(decl.returnType);
space();
format(decl.name);
if (decl.templateParameters)
format(decl.templateParameters);
if (decl.parameters)
format(decl.parameters);
foreach(attr; decl.memberFunctionAttributes)
{
space();
format(attr);
}
if (decl.constraint)
{
space();
format(decl.constraint);
}
if (decl.functionBody)
format(decl.functionBody);
else
put(";");
}
void format(const FunctionLiteralExpression functionLiteralExpression)
{
debug(verbose) writeln("FunctionLiteralExpression");
/**
IdType functionOrDelegate;
Type type;
Parameters parameters;
FunctionAttribute[] functionAttributes;
FunctionBody functionBody;
**/
with(functionLiteralExpression)
{
put(tokenRep(functionOrDelegate));
space();
if (type) format(type);
if (parameters) format(parameters);
foreach(att; functionAttributes)
{
space();
format(att);
}
ignoreNewlines = true;
format(functionBody);
ignoreNewlines = false;
}
}
void format(const GotoStatement gotoStatement)
{
debug(verbose) writeln("GotoStatement");
put("goto ");
gotoStatement.label != tok!"" ?
put(tokenRep(gotoStatement.label)) :
format(gotoStatement.expression);
put(";");
}
void format(const IdentifierChain identifierChain)
{
debug(verbose) writeln("IdentifierChain");
foreach(count, ident; identifierChain.identifiers)
{
if (count) put(".");
put(ident.text);
}
}
void format(const IdentifierList identifierList)
{
debug(verbose) writeln("IdentifierList");
assert(false);
}
void format(const IdentifierOrTemplateChain identifierOrTemplateChain)
{
debug(verbose) writeln("IdentifierOrTemplateChain");
with(identifierOrTemplateChain)
{
foreach(count, ident; identifiersOrTemplateInstances)
{
if (count) put(".");
format(ident);
}
}
}
void format(const IdentifierOrTemplateInstance identifierOrTemplateInstance)
{
debug(verbose) writeln("IdentifierOrTemplateInstance");
with(identifierOrTemplateInstance)
{
format(identifier);
if (templateInstance)
format(templateInstance);
}
}
void format(const IdentityExpression identityExpression)
{
debug(verbose) writeln("IdentityExpression");
with(identityExpression)
{
if (left) format(left);
put(negated ? " !is " : " is ");
if (right) format(right);
}
}
void format(const IfStatement ifStatement)
{
debug(verbose) writeln("IfStatement");
/**
Token identifier;
Type type;
Expression expression;
DeclarationOrStatement thenStatement;
DeclarationOrStatement elseStatement;
**/
with(ifStatement)
{
bool isAuto = identifier != tok!"" && !type;
bool isAssign = isAuto || type;
put("if(");
if (isAuto) put("auto ");
if (type)
{
format(type);
space();
}
if (identifier != tok!"")
{
format(identifier);
space();
}
if (isAssign) put("= ");
if (expression) format(expression);
put(")");
if (thenStatement)
maybeIndent(thenStatement);
if (elseStatement)
{
newThing(What.else_);
put("else ");
if (elseStatement.statement &&
elseStatement.statement.statementNoCaseNoDefault &&
elseStatement.statement.statementNoCaseNoDefault.ifStatement)
{
// this is to stop automatic newline
format(elseStatement.statement.statementNoCaseNoDefault.ifStatement);
}
else
maybeIndent(elseStatement);
}
}
}
void format(const ImportBind importBind)
{
debug(verbose) writeln("ImportBind");
format(importBind.left);
if (importBind.right != tok!"")
{
put(" = ");
format(importBind.right);
}
}
void format(const ImportBindings importBindings)
{
debug(verbose) writeln("ImportBindings");
/**
SingleImport singleImport;
ImportBind[] importBinds;
**/
with(importBindings)
{
format(singleImport);
put(" : ");
foreach(count, bind; importBinds)
{
if (count) put(", ");
format(bind);
}
}
}
void format(const ImportDeclaration importDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("ImportDeclaration");
/**
SingleImport[] singleImports;
ImportBindings importBindings;
**/
with(importDeclaration)
{
newThing(What.importDecl);
putAttrs(attrs);
put("import ");
if (singleImports.length == 1)
{
format(singleImports[0]);
}
else if (singleImports.length > 1)
{
indent();
newline();
foreach(count, imp; singleImports)
{
format(imp);
if (count < singleImports.length - 1)
{
put(", ");
newline();
}
}
outdent();
}
if (importBindings)
{
if (singleImports.length)
put(", ");
format(importBindings);
}
put(";");
}
}
void format(const ImportExpression importExpression)
{
debug(verbose) writeln("ImportExpression");
put("import (");
format(importExpression.assignExpression);
put(");");
}
void format(const IndexExpression indexExpression)
{
debug(verbose) writeln("IndexExpression");
/**
UnaryExpression unaryExpression;
ArgumentList argumentList;
**/
with(indexExpression)
{
format(indexExpression.unaryExpression);
put("[");
format(argumentList);
put("]");
}
}
void format(const InExpression inExpression)
{
debug(verbose) writeln("InExpression");
with(inExpression)
{
if (left) format(left);
put(negated ? " !in " : " in ");
if (right) format(right);
}
}
void format(const InStatement inStatement)
{
debug(verbose) writeln("InStatement");
onNewline();
put("in");
format(inStatement.blockStatement);
}
void format(const Initialize initialize)
{
debug(verbose) writeln("Initialize");
assert(false);
}
void format(const Initializer initializer)
{
debug(verbose) writeln("Initializer");
initializer.nonVoidInitializer ? format(initializer.nonVoidInitializer) : put("void");
}
void format(const InterfaceDeclaration interfaceDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("InterfaceDeclaration");
/**
Token name;
TemplateParameters templateParameters;
Constraint constraint;
BaseClassList baseClassList;
StructBody structBody;
string comment;
**/
with(interfaceDeclaration)
{
newThing(What.aggregateDecl);
putComment(comment);
putAttrs(attrs);
put("interface ");
format(name);
if (templateParameters) format(templateParameters);
if (constraint)
{
space();
format(constraint);
}
if (baseClassList)
{
put(": ");
format(baseClassList);
}
if (structBody)
format(structBody);
else
put(";");
}
}
void format(const Invariant invariant_, const Attribute[] attrs = null)
{
debug(verbose) writeln("Invariant");
/**
BlockStatement blockStatement;
string comment;
**/
putComment(invariant_.comment);
putAttrs(attrs);
put("invariant()");
format(invariant_.blockStatement);
}
void format(const IsExpression isExpression)
{
debug(verbose) writeln("IsExpression");
/**
Type type;
Token identifier;
TypeSpecialization typeSpecialization;
TemplateParameterList templateParameterList;
IdType equalsOrColon;
**/
with(isExpression)
{
put("is(");
if (type) format(type);
if (identifier != tok!"")
{
space();
format(identifier);
}
if (equalsOrColon)
{
space();
put(tokenRep(equalsOrColon));
space();
}
if (typeSpecialization) format(typeSpecialization);
if (templateParameterList)
{
put(", ");
format(templateParameterList);
}
put(")");
}
}
void format(const KeyValuePair keyValuePair)
{
debug(verbose) writeln("KeyValuePair");
/**
AssignExpression key;
AssignExpression value;
**/
format(keyValuePair.key);
put(":");
format(keyValuePair.value);
}
void format(const KeyValuePairs keyValuePairs)
{
debug(verbose) writeln("KeyValuePairs");
/**
KeyValuePair[] keyValuePairs;
**/
foreach(count, pair; keyValuePairs.keyValuePairs)
{
format(pair);
if (count < keyValuePairs.keyValuePairs.length - 1)
put(", ");
}
}
void format(const LabeledStatement stmt)
{
debug(verbose) writeln("LabeledStatement");
/**
Token identifier;
DeclarationOrStatement declarationOrStatement;
**/
format(stmt.identifier);
put(":");
if (stmt.declarationOrStatement)
format(stmt.declarationOrStatement);
}
void format(const LambdaExpression lambdaExpression)
{
debug(verbose) writeln("LambdaExpression");
/**
IdType functionType;
Token identifier;
Parameters parameters;
FunctionAttribute[] functionAttributes;
AssignExpression assignExpression;
**/
with(lambdaExpression)
{
if (identifier != tok!"")
format(identifier);
else
{
if (functionType) put(tokenRep(functionType));
format(parameters);
foreach(count, attr; functionAttributes)
{
space();
format(attr);
}
}
put(" => ");
format(assignExpression);
}
}
void format(const LastCatch lastCatch)
{
debug(verbose) writeln("LastCatch");
put("catch");
format(lastCatch.statementNoCaseNoDefault);
}
void format(const LinkageAttribute linkageAttribute)
{
debug(verbose) writeln("LinkageAttribute");
/**
Token identifier;
bool hasPlusPlus;
**/
put("extern(");
format(linkageAttribute.identifier);
if (linkageAttribute.hasPlusPlus)
put("++");
put(")");
}
void format(const MemberFunctionAttribute memberFunctionAttribute)
{
debug(verbose) writeln("MemberFunctionAttribute");
/**
IdType tokenType;
AtAttribute atAttribute;
**/
with(memberFunctionAttribute)
{
if (tokenType) put(tokenRep(tokenType));
else format(atAttribute);
}
}
void format(const MixinDeclaration mixinDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("MixinDeclaration");
/**
MixinExpression mixinExpression;
TemplateMixinExpression templateMixinExpression;
**/
with(mixinDeclaration)
{
putAttrs(attrs);
if (mixinExpression) format(mixinExpression);
else format(templateMixinExpression);
put(";");
}
}
void format(const MixinExpression mixinExpression)
{
debug(verbose) writeln("MixinExpression");
put("mixin(");
format(mixinExpression.assignExpression);
put(")");
}
void format(const MixinTemplateDeclaration mixinTemplateDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("MixinTemplateDeclaration");
putAttrs(attrs);
put("mixin ");
format(mixinTemplateDeclaration.templateDeclaration);
}
void format(const MixinTemplateName mixinTemplateName)
{
debug(verbose) writeln("MixinTemplateName");
/**
Symbol symbol;
IdentifierOrTemplateChain identifierOrTemplateChain;
TypeofExpression typeofExpression;
**/
with(mixinTemplateName)
{
if (symbol) format(symbol);
else
{
format(typeofExpression);
put(".");
format(identifierOrTemplateChain);
}
}
}
void format(const Module module_)
{
debug(verbose) writeln("Module");
/**
ModuleDeclaration moduleDeclaration;
Declaration[] declarations;
**/
format(module_.moduleDeclaration);
foreach(decl; module_.declarations)
format(decl);
}
void format(const ModuleDeclaration moduleDeclaration)
{
debug(verbose) writeln("ModuleDeclaration");
/**
IdentifierChain moduleName;
**/
put("module ");
format(moduleDeclaration.moduleName);
put(";");
newline();
newline();
}
void format(const MulExpression mulExpression)
{
debug(verbose) writeln("MulExpression");
mixin(binary("mulExpression"));
}
void format(const NewAnonClassExpression newAnonClassExpression)
{
debug(verbose) writeln("NewAnonClassExpression");
/**
Arguments allocatorArguments;
Arguments constructorArguments;
BaseClassList baseClassList;
StructBody structBody;
**/
with(newAnonClassExpression)
{
if (allocatorArguments)
{
format(allocatorArguments);
space();
}
put("class");
if (constructorArguments)
format(constructorArguments);
if (baseClassList)
{
space();
format(baseClassList);
}
format(structBody);
}
}
void format(const NewExpression newExpression)
{
debug(verbose) writeln("NewExpression");
/**
Type type;
NewAnonClassExpression newAnonClassExpression;
Arguments arguments;
AssignExpression assignExpression;
**/
with(newExpression)
{
put("new ");
if (newAnonClassExpression) format(newAnonClassExpression);
else
{
if (type) format(type);
if (arguments) format(arguments);
if (assignExpression)
{
put("[");
format(assignExpression);
put("]");
}
}
}
}
void format(const NonVoidInitializer nonVoidInitializer)
{
debug(verbose) writeln("NonVoidInitializer");
/**
AssignExpression assignExpression;
ArrayInitializer arrayInitializer;
StructInitializer structInitializer;
**/
with(nonVoidInitializer)
{
if (assignExpression) format(assignExpression);
else if (arrayInitializer) format(arrayInitializer);
else if (structInitializer) format(structInitializer);
}
}
void format(const Operand operand)
{
debug(verbose) writeln("Operand");
assert(false);
}
void format(const Operands operands)
{
debug(verbose) writeln("Operands");
assert(false);
}
void format(const OrExpression orExpression)
{
debug(verbose) writeln("OrExpression");
mixin(binary("orExpression", "|"));
}
void format(const OrOrExpression orOrExpression)
{
debug(verbose) writeln("OrOrExpression");
mixin(binary("orOrExpression", "||"));
}
void format(const OutStatement stmnt)
{
debug(verbose) writeln("OutStatement");
/**
Token parameter;
BlockStatement blockStatement;
**/
onNewline();
put("out");
if (stmnt.parameter != tok!"")
{
put("(");
format(stmnt.parameter);
put(")");
}
format(stmnt.blockStatement);
}
void format(const Parameter parameter)
{
debug(verbose) writeln("Parameter");
/**
IdType[] parameterAttributes;
Type type;
Token name;
bool vararg;
AssignExpression default_;
TypeSuffix[] cstyle;
**/
foreach (count, attribute; parameter.parameterAttributes)
{
if (count) space();
put(tokenRep(attribute));
}
if (parameter.parameterAttributes.length > 0)
space();
if (parameter.type !is null)
format(parameter.type);
if (parameter.name.type != tok!"")
{
space();
put(parameter.name.text);
}
foreach(suffix; parameter.cstyle)
format(suffix);
if (parameter.default_)
{
put(" = ");
format(parameter.default_);
}
if (parameter.vararg)
put("...");
}
void format(const Parameters parameters)
{
debug(verbose) writeln("Parameters");
/**
Parameter[] parameters;
bool hasVarargs;
**/
put("(");
foreach (count, param; parameters.parameters)
{
if (count) put(", ");
format(param);
}
if (parameters.hasVarargs)
{
if (parameters.parameters.length)
put(", ");
put("...");
}
put(")");
}
void format(const Postblit postblit, const Attribute[] attrs = null)
{
debug(verbose) writeln("Postblit");
/**
FunctionBody functionBody;
**/
newThing(What.functionDecl);
putAttrs(attrs);
put("this(this)");
foreach(attr; postblit.memberFunctionAttributes)
{
space();
format(attr);
}
if (postblit.functionBody)
format(postblit.functionBody);
else
put(";");
}
void format(const PostIncDecExpression postIncDecExpression)
{
debug(verbose) writeln("PostIncDecExpression");
assert(false); // parsePostIncDecExpression never gets called??
}
void format(const PowExpression powExpression)
{
debug(verbose) writeln("PowExpression");
mixin(binary("powExpression", "^^", true));
}
void format(const PragmaDeclaration pragmaDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("PragmaDeclaration");
/**
PragmaExpression pragmaExpression;
**/
putAttrs(attrs);
format(pragmaDeclaration.pragmaExpression);
put(";");
}
void format(const PragmaExpression pragmaExpression)
{
debug(verbose) writeln("PragmaExpression");
/**
Token identifier;
ArgumentList argumentList;
**/
put("pragma(");
format(pragmaExpression.identifier);
if (pragmaExpression.argumentList)
{
put(", ");
format(pragmaExpression.argumentList);
}
put(")");
}
void format(const PreIncDecExpression preIncDecExpression)
{
debug(verbose) writeln("PreIncDecExpression");
assert(false); // parsePreIncDecExpression never called ??
}
void format(const PrimaryExpression primaryExpression)
{
debug(verbose) writeln("PrimaryExpression");
/**
Token dot;
Token primary;
IdentifierOrTemplateInstance identifierOrTemplateInstance;
Token basicType;
TypeofExpression typeofExpression;
TypeidExpression typeidExpression;
ArrayLiteral arrayLiteral;
AssocArrayLiteral assocArrayLiteral;
Expression expression;
IsExpression isExpression;
LambdaExpression lambdaExpression;
FunctionLiteralExpression functionLiteralExpression;
TraitsExpression traitsExpression;
MixinExpression mixinExpression;
ImportExpression importExpression;
Vector vector;
**/
with(primaryExpression)
{
if (dot != tok!"") put(".");
if (basicType != tok!"") format(basicType);
if (primary != tok!"")
{
if (basicType != tok!"") put("."); // i.e. : uint.max
format(primary);
}
if (expression)
{
put("(");
format(expression);
put(")");
}
else if (identifierOrTemplateInstance)
{
format(identifierOrTemplateInstance);
}
else if (typeofExpression) format(typeofExpression);
else if (typeidExpression) format(typeidExpression);
else if (arrayLiteral) format(arrayLiteral);
else if (assocArrayLiteral) format(assocArrayLiteral);
else if (isExpression) format(isExpression);
else if (lambdaExpression) format(lambdaExpression);
else if (functionLiteralExpression) format(functionLiteralExpression);
else if (traitsExpression) format(traitsExpression);
else if (mixinExpression) format(mixinExpression);
else if (importExpression) format(importExpression);
else if (vector) format(vector);
}
}
void format(const Register register)
{
debug(verbose) writeln("Register");
assert(false);
}
void format(const RelExpression relExpression)
{
debug(verbose) writeln("RelExpression");
mixin(binary("relExpression"));
}
void format(const ReturnStatement returnStatement)
{
debug(verbose) writeln("ReturnStatement");
put("return");
if (returnStatement.expression)
{
space();
format(returnStatement.expression);
}
put(";");
}
void format(const ScopeGuardStatement scopeGuardStatement)
{
debug(verbose) writeln("ScopeGuardStatement");
/**
Token identifier;
StatementNoCaseNoDefault statementNoCaseNoDefault;
**/
with(scopeGuardStatement)
{
put("scope(");
format(identifier);
put(")");
indent();
format(statementNoCaseNoDefault);
outdent();
}
}
void format(const SharedStaticConstructor sharedStaticConstructor, const Attribute[] attrs = null)
{
debug(verbose) writeln("SharedStaticConstructor");
with(sharedStaticConstructor)
{
newThing(What.functionDecl);
putComment(comment);
putAttrs(attrs);
put("shared static this()");
format(functionBody);
}
}
void format(const SharedStaticDestructor sharedStaticDestructor, const Attribute[] attrs = null)
{
debug(verbose) writeln("SharedStaticDestructor");
with(sharedStaticDestructor)
{
newThing(What.functionDecl);
putComment(comment);
putAttrs(attrs);
put("shared static ~this()");
format(functionBody);
}
}
void format(const ShiftExpression shiftExpression)
{
debug(verbose) writeln("ShiftExpression");
mixin(binary("shiftExpression"));
}
void format(const SingleImport singleImport)
{
debug(verbose) writeln("SingleImport");
/**
Token rename;
IdentifierChain identifierChain;
**/
if (singleImport.rename != tok!"")
{
format(singleImport.rename);
put(" = ");
}
format(singleImport.identifierChain);
}
void format(const SliceExpression sliceExpression)
{
debug(verbose) writeln("SliceExpression");
/**
UnaryExpression unaryExpression;
AssignExpression lower;
AssignExpression upper;
**/
with(sliceExpression)
{
format(unaryExpression);
put("[");
if (lower && upper)
{
format(lower);
put("..");
format(upper);
}
put("]");
}
}
void format(const Statement statement)
{
debug(verbose) writeln("Statement");
/**
StatementNoCaseNoDefault statementNoCaseNoDefault;
CaseStatement caseStatement;
CaseRangeStatement caseRangeStatement;
DefaultStatement defaultStatement;
**/
with(statement)
{
if (statementNoCaseNoDefault)
{
format(statementNoCaseNoDefault);
return;
}
onNewline();
if (caseStatement) format(caseStatement);
else if (caseRangeStatement) format(caseRangeStatement);
else if (defaultStatement) format(defaultStatement);
}
}
void format(const StatementNoCaseNoDefault statementNoCaseNoDefault)
{
debug(verbose) writeln("StatementNoCaseNoDefault");
string mix(string s) { return "if (" ~ s ~ ") format(" ~ s ~ ");"; }
with(statementNoCaseNoDefault)
{
if (!blockStatement) onNewline();
enum stmnts = TypeTuple!(
"labeledStatement",
"blockStatement",
"ifStatement",
"whileStatement",
"doStatement",
"forStatement",
"foreachStatement",
"switchStatement",
"finalSwitchStatement",
"continueStatement",
"breakStatement",
"returnStatement",
"gotoStatement",
"withStatement",
"synchronizedStatement",
"tryStatement",
"throwStatement",
"scopeGuardStatement",
"asmStatement",
"conditionalStatement",
"staticAssertStatement",
"versionSpecification",
"debugSpecification",
"functionCallStatement",
"expressionStatement"
);
foreach(s; stmnts)
mixin(mix(s));
}
}
void format(const StaticAssertDeclaration staticAssertDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("StaticAssertDeclaration");
newThing(What.other);
putAttrs(attrs);
format(staticAssertDeclaration.staticAssertStatement);
put(";");
}
void format(const StaticAssertStatement staticAssertStatement)
{
debug(verbose) writeln("StaticAssertStatement");
put("static ");
format(staticAssertStatement.assertExpression);
}
void format(const StaticConstructor staticConstructor, const Attribute[] attrs = null)
{
debug(verbose) writeln("StaticConstructor");
putAttrs(attrs);
put("static this()");
format(staticConstructor.functionBody);
}
void format(const StaticDestructor staticDestructor, const Attribute[] attrs = null)
{
debug(verbose) writeln("StaticDestructor");
putAttrs(attrs);
put("static ~this()");
format(staticDestructor.functionBody);
}
void format(const StaticIfCondition staticIfCondition)
{
debug(verbose) writeln("StaticIfCondition");
put("static if (");
format(staticIfCondition.assignExpression);
put(")");
}
void format(const StorageClass storageClass)
{
debug(verbose) writeln("StorageClass");
/**
AtAttribute atAttribute;
Deprecated deprecated_;
Token token;
**/
with(storageClass)
{
if (atAttribute) format(atAttribute);
else if (deprecated_) format(deprecated_);
else format(token);
}
}
void format(const StructBody structBody)
{
debug(verbose) writeln("StructBody");
if (structBody.declarations.length > 0)
{
startBlock();
foreach(count, decl; structBody.declarations)
format(decl);
endBlock();
}
else
{
space();
put("{}");
}
}
void format(const StructDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("StructDeclaration");
/**
Token name;
TemplateParameters templateParameters;
Constraint constraint;
StructBody structBody;
string comment;
**/
newThing(What.aggregateDecl);
putComment(decl.comment);
putAttrs(attrs);
put("struct ");
format(decl.name);
if (decl.templateParameters)
format(decl.templateParameters);
if (decl.constraint)
{
space();
format(decl.constraint);
}
if (decl.structBody)
format(decl.structBody);
else
put(";");
}
void format(const StructInitializer structInitializer)
{
debug(verbose) writeln("StructInitializer");
put("{");
format(structInitializer.structMemberInitializers);
put("}");
}
void format(const StructMemberInitializer structMemberInitializer)
{
debug(verbose) writeln("StructMemberInitializer");
/**
Token identifier;
NonVoidInitializer nonVoidInitializer;
**/
with(structMemberInitializer)
{
if (identifier != tok!"")
{
format(identifier);
put(":");
}
format(nonVoidInitializer);
}
}
void format(const StructMemberInitializers structMemberInitializers)
{
debug(verbose) writeln("StructMemberInitializers");
foreach(count, mem; structMemberInitializers.structMemberInitializers)
{
if (count) put(", ");
format(mem);
}
}
void format(const SwitchStatement switchStatement, bool isFinal = false)
{
debug(verbose) writeln("SwitchStatement");
/**
Expression expression;
Statement statement;
**/
with(switchStatement)
{
newThing(What.other);
isFinal ? put(" final switch(") : put("switch(");
format(expression);
put(")");
bool needBlock = statement.statementNoCaseNoDefault &&
!(statement.statementNoCaseNoDefault.withStatement ||
statement.statementNoCaseNoDefault.blockStatement );
if (needBlock)
startBlock();
format(statement);
if (needBlock)
endBlock();
}
}
void format(const Symbol symbol)
{
debug(verbose) writeln("Symbol");
if (symbol.dot != tok!"")
put(".");
format(symbol.identifierOrTemplateChain);
}
void format(const SynchronizedStatement synchronizedStatement)
{
debug(verbose) writeln("SynchronizedStatement");
/**
Expression expression;
StatementNoCaseNoDefault statementNoCaseNoDefault;
**/
with(synchronizedStatement)
{
put("synchronized");
if (expression)
{
put("(");
format(expression);
put(")");
}
format(statementNoCaseNoDefault);
}
}
void format(const TemplateAliasParameter templateAliasParameter)
{
debug(verbose) writeln("TemplateAliasParameter");
/**
Type type;
Token identifier;
Type colonType;
AssignExpression colonExpression;
Type assignType;
AssignExpression assignExpression;
**/
with(templateAliasParameter)
{
put("alias ");
if (type)
{
format(type);
space();
}
format(identifier);
if (colonType)
{
put(" : ");
format(colonType);
}
else if (colonExpression)
{
put(" : ");
format(colonExpression);
}
if (assignType)
{
put(" = ");
format(assignType);
}
else if (assignExpression)
{
put(" = ");
format(assignExpression);
}
}
}
void format(const TemplateArgument templateArgument)
{
debug(verbose) writeln("TemplateArgument");
/**
Type type;
AssignExpression assignExpression;
**/
with(templateArgument)
{
if (type) format(type);
if (assignExpression) format(assignExpression);
}
}
void format(const TemplateArgumentList templateArgumentList, bool parens = true)
{
debug(verbose) writeln("TemplateArgumentList");
if (parens) put("!(");
foreach(count, arg; templateArgumentList.items)
{
if (count) put(", ");
format(arg);
}
if (parens) put(")");
}
void format(const TemplateArguments templateArguments)
{
debug(verbose) writeln("TemplateArguments");
/**
TemplateArgumentList templateArgumentList;
TemplateSingleArgument templateSingleArgument;
**/
with(templateArguments)
{
if (templateArgumentList) format(templateArgumentList);
else if (templateSingleArgument) format(templateSingleArgument);
else put("!()");
}
}
void format(const TemplateDeclaration templateDeclaration, const Attribute[] attrs = null)
{
debug(verbose) writeln("TemplateDeclaration");
/**
Token name;
TemplateParameters templateParameters;
Constraint constraint;
Declaration[] declarations;
EponymousTemplateDeclaration eponymousTemplateDeclaration;
string comment;
**/
with(templateDeclaration)
{
newThing(What.other);
putComment(comment);
putAttrs(attrs);
if (eponymousTemplateDeclaration)
{
format(eponymousTemplateDeclaration);
}
else
{
put("template ");
format(name);
if (templateParameters)
format(templateParameters);
if (constraint)
{
space();
format(constraint);
}
startBlock();
foreach(d; declarations)
format(d);
endBlock();
}
}
}
void format(const TemplateInstance templateInstance)
{
debug(verbose) writeln("TemplateInstance");
/**
Token identifier;
TemplateArguments templateArguments;
**/
with(templateInstance)
{
format(identifier);
if (templateArguments) format(templateArguments);
}
}
void format(const TemplateMixinExpression templateMixinExpression)
{
debug(verbose) writeln("TemplateMixinExpression");
/**
Token identifier;
TemplateArguments templateArguments;
MixinTemplateName mixinTemplateName;
**/
with(templateMixinExpression)
{
put("mixin ");
format(mixinTemplateName);
if (templateArguments) format(templateArguments);
space();
format(identifier);
}
}
void format(const TemplateParameter templateParameter)
{
debug(verbose) writeln("TemplateParameter");
with(templateParameter)
{
if (templateTypeParameter)
format(templateTypeParameter);
else if (templateValueParameter)
format(templateValueParameter);
else if (templateAliasParameter)
format(templateAliasParameter);
else if (templateTupleParameter)
format(templateTupleParameter);
else if (templateThisParameter)
format(templateThisParameter);
}
}
void format(const TemplateParameterList templateParameterList)
{
debug(verbose) writeln("TemplateParameterList");
foreach(i, param; templateParameterList.items)
{
if (i) put(", ");
format(param);
}
}
void format(const TemplateParameters templateParameters)
{
debug(verbose) writeln("TemplateParameters");
with(templateParameters)
{
put("(");
if (templateParameterList)
format(templateParameterList);
put(")");
}
}
void format(const TemplateSingleArgument templateSingleArgument)
{
debug(verbose) writeln("TemplateSingleArgument");
/**
Token token;
**/
put("!");
format(templateSingleArgument.token);
}
void format(const TemplateThisParameter templateThisParameter)
{
debug(verbose) writeln("TemplateThisParameter");
with(templateThisParameter)
{
put("this ");
if (templateTypeParameter)
format(templateTypeParameter);
}
}
void format(const TemplateTupleParameter templateTupleParameter)
{
debug(verbose) writeln("TemplateTupleParameter");
format(templateTupleParameter.identifier);
put("...");
}
void format(const TemplateTypeParameter templateTypeParameter)
{
debug(verbose) writeln("TemplateTypeParameter");
/**
Token identifier;
Type colonType;
Type assignType;
**/
with(templateTypeParameter)
{
format(identifier);
if (colonType)
{
put(" : ");
format(colonType);
}
if (assignType)
{
put(" = ");
format(assignType);
}
}
}
void format(const TemplateValueParameter templateValueParameter)
{
debug(verbose) writeln("TemplateValueParameter");
/**
Type type;
Token identifier;
Expression expression;
TemplateValueParameterDefault templateValueParameterDefault;
**/
with(templateValueParameter)
{
if (type) format(type);
space();
format(identifier);
if (expression)
{
put(" : ");
format(expression);
}
if (templateValueParameterDefault)
{
put(" = ");
format(templateValueParameterDefault);
}
}
}
void format(const TemplateValueParameterDefault templateValueParameterDefault)
{
debug(verbose) writeln("TemplateValueParameterDefault");
with(templateValueParameterDefault)
assignExpression ? format(assignExpression) : format(token);
}
void format(const TernaryExpression expr)
{
debug(verbose) writeln("TernaryExpression");
/**
ExpressionNode orOrExpression;
ExpressionNode expression;
ExpressionNode ternaryExpression;
**/
format(expr.orOrExpression);
if (expr.expression && expr.ternaryExpression)
{
put(" ? ");
format(expr.expression);
put(" : ");
format(expr.ternaryExpression);
}
}
void format(const ThrowStatement throwStatement)
{
debug(verbose) writeln("ThrowStatement");
put("throw ");
assert(throwStatement.expression);
format(throwStatement.expression);
put(";");
}
void format(const Token token)
{
debug(verbose) writeln("Token ", tokenRep(token));
put(tokenRep(token));
}
void format(const TraitsExpression traitExpr)
{
debug(verbose) writeln("TraitsExpression");
/**
Token identifier;
TemplateArgumentList templateArgumentList;
**/
put("__traits(");
format(traitExpr.identifier);
put(", ");
format(traitExpr.templateArgumentList, false);
put(")");
}
void format(const TryStatement tryStatement)
{
debug(verbose) writeln("TryStatement");
/**
DeclarationOrStatement declarationOrStatement;
Catches catches;
Finally finally_;
**/
with(tryStatement)
{
newThing(What.other);
put("try");
maybeIndent(declarationOrStatement);
if (catches) format(catches);
if (finally_) format(finally_);
}
}
void format(const Type type)
{
debug(verbose) writeln("Type(");
/**
IdType[] typeConstructors;
TypeSuffix[] typeSuffixes;
Type2 type2;
**/
foreach (count, constructor; type.typeConstructors)
{
if (count) space();
put(tokenRep(constructor));
}
if (type.typeConstructors.length) space();
format(type.type2);
foreach (suffix; type.typeSuffixes)
format(suffix);
debug(verbose) writeln(")");
}
void format(const Type2 type2)
{
debug(verbose) writeln("Type2");
/**
IdType builtinType;
Symbol symbol;
TypeofExpression typeofExpression;
IdentifierOrTemplateChain identifierOrTemplateChain;
IdType typeConstructor;
Type type;
**/
if (type2.symbol !is null)
{
format(type2.symbol);
}
else if (type2.typeofExpression !is null)
{
format(type2.typeofExpression);
return;
}
else if (type2.typeConstructor != tok!"")
{
put(tokenRep(type2.typeConstructor));
put("(");
format(type2.type);
put(")");
}
else
{
put(tokenRep(type2.builtinType));
}
if (type2.identifierOrTemplateChain)
{
put(".");
format(type2.identifierOrTemplateChain);
}
}
void format(const TypeSpecialization typeSpecialization)
{
debug(verbose) writeln("TypeSpecialization");
/**
Token token;
Type type;
**/
with(typeSpecialization)
{
format(token);
if (type) format(type);
}
}
void format(const TypeSuffix typeSuffix)
{
debug(verbose) writeln("TypeSuffix");
/**
Token delegateOrFunction;
bool star;
bool array;
Type type;
AssignExpression low;
AssignExpression high;
Parameters parameters;
MemberFunctionAttribute[] memberFunctionAttributes;
**/
if (typeSuffix.star)
{
put("*");
return;
}
else if (typeSuffix.array)
{
if (typeSuffix.type is null)
{
if (typeSuffix.low is null)
{
put("[]");
return;
}
else
{
if (typeSuffix.high is null)
{
put("[");
format(typeSuffix.low);
put("]");
return;
}
else
{
put("[");
format(typeSuffix.low);
put("..");
format(typeSuffix.high);
put("]");
return;
}
}
}
else
{
put("[");
format(typeSuffix.type);
put("]");
return;
}
}
else
{
space();
format(typeSuffix.delegateOrFunction);
if (typeSuffix.parameters) format(typeSuffix.parameters);
foreach(attr; typeSuffix.memberFunctionAttributes)
{
space();
format(attr);
}
return;
}
}
void format(const TypeidExpression idExpr)
{
debug(verbose) writeln("TypeidExpression");
/**
Type type;
Expression expression;
**/
put("typeid(");
idExpr.type ? format(idExpr.type) : format(idExpr.expression);
put(")");
}
void format(const TypeofExpression typeofExpr)
{
debug(verbose) writeln("TypeofExpression");
/**
Expression expression;
Token return_;
**/
put("typeof(");
typeofExpr.expression ? format(typeofExpr.expression) : format(typeofExpr.return_);
put(")");
}
void format(const UnaryExpression unary)
{
debug(verbose) writeln("UnaryExpression(");
/**
Type type;
PrimaryExpression primaryExpression;
Token prefix;
Token suffix;
UnaryExpression unaryExpression;
NewExpression newExpression;
DeleteExpression deleteExpression;
CastExpression castExpression;
FunctionCallExpression functionCallExpression;
ArgumentList argumentList;
IdentifierOrTemplateInstance identifierOrTemplateInstance;
AssertExpression assertExpression;
SliceExpression sliceExpression;
IndexExpression indexExpression;
**/
with(unary)
{
if (prefix != tok!"") format(prefix);
if (type)
{
// handle things like (void*).sizeof
if (identifierOrTemplateInstance)
{
put("(");
format(type);
put(")");
}
else
{
format(type);
put("(");
if (argumentList)
format(argumentList);
put(")");
}
}
if (primaryExpression) format(primaryExpression);
if (newExpression) format(newExpression);
if (deleteExpression) format(deleteExpression);
if (castExpression) format(castExpression);
if (functionCallExpression) format(functionCallExpression);
if (assertExpression) format(assertExpression);
if (sliceExpression) format(sliceExpression);
if (indexExpression) format(indexExpression);
if (unaryExpression) format(unaryExpression);
if (suffix != tok!"") format(suffix);
if (identifierOrTemplateInstance)
{
put(".");
format(identifierOrTemplateInstance);
}
}
debug(verbose) writeln(")");
}
void format(const UnionDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("UnionDeclaration");
/**
Token name;
TemplateParameters templateParameters;
Constraint constraint;
StructBody structBody;
string comment;
**/
newThing(What.aggregateDecl);
putComment(decl.comment);
putAttrs(attrs);
put("union ");
format(decl.name);
if (decl.templateParameters)
format(decl.templateParameters);
if (decl.constraint)
{
space();
format(decl.constraint);
}
format(decl.structBody);
}
void format(const Unittest unittest_, const Attribute[] attrs = null)
{
debug(verbose) writeln("Unittest");
/**
BlockStatement blockStatement;
string comment;
**/
newThing(What.functionDecl);
putComment(unittest_.comment);
putAttrs(attrs);
put("unittest");
format(unittest_.blockStatement);
}
void format(const VariableDeclaration decl, const Attribute[] attrs = null)
{
debug(verbose) writeln("VariableDeclaration");
/**
Type type;
Declarator[] declarators;
StorageClass storageClass;
AutoDeclaration autoDeclaration;
string comment;
**/
newThing(What.variableDecl);
putComment(decl.comment);
putAttrs(attrs);
if (decl.autoDeclaration)
format(decl.autoDeclaration);
else
{
if (decl.storageClass)
{
format(decl.storageClass);
space();
}
if (decl.type) format(decl.type);
if (decl.declarators.length) space();
foreach(count, d; decl.declarators)
{
if (count) put(", ");
format(d);
}
}
put(";");
}
void format(const Vector vector)
{
debug(verbose) writeln("Vector");
put("__vector(");
format(vector.type);
put(")");
}
void format(const VersionCondition versionCondition)
{
debug(verbose) writeln("VersionCondition");
put("version(");
format(versionCondition.token);
put(")");
}
void format(const VersionSpecification ver, const Attribute[] attrs = null)
{
debug(verbose) writeln("VersionSpecification");
newThing(What.other);
putAttrs(attrs);
put("version = ");
format(ver.token);
put(";");
}
void format(const WhileStatement stmt)
{
debug(verbose) writeln("WhileStatement");
/**
Expression expression;
DeclarationOrStatement declarationOrStatement;
**/
newThing(What.other);
put("while(");
format(stmt.expression);
put(")");
maybeIndent(stmt.declarationOrStatement);
}
void format(const WithStatement stmt)
{
debug(verbose) writeln("WithStatement");
/**
Expression expression;
StatementNoCaseNoDefault statementNoCaseNoDefault;
**/
space();
put("with(");
format(stmt.expression);
put(")");
format(stmt.statementNoCaseNoDefault);
}
void format(const XorExpression xorExpression)
{
debug(verbose) writeln("XorExpression");
mixin(binary("xorExpression", "^"));
}
private:
import std.uni : isWhite;
void indent()
{
indentLevel++;
}
void outdent()
{
if (indentLevel == 0)
return;
indentLevel--;
}
void putIndent()
{
if (!indentLevel) return;
auto i = getIndent();
sink.put(i);
lineLength += i.length;
}
string getIndent()
{
return useTabs ? iota(indentLevel).map!(a => "\t").join : iota(indentLevel*indentWidth).map!(a => " ").join;
}
enum What
{
functionDecl,
aggregateDecl,
attributeDecl,
conditionalDecl,
variableDecl,
importDecl,
expr,
loop,
else_,
catch_,
other
}
void newThing(What thing)
{
lastThing = currentThing;
currentThing = thing;
dchar last() {
auto r = sink.data;
while(!r.empty && r.back.isWhite) r.popBack();
return r.empty ? ' ' : r.back;
}
with(What) {
if (last() == '{')
{
onNewline();
return;
}
if (lastThing == importDecl && thing != importDecl)
lineGap(1);
if (lastThing == loop && last() == '}')
lineGap(1);
switch(thing)
{
case other:
onNewline();
break;
case aggregateDecl: goto case;
case attributeDecl: goto case;
case functionDecl:
lineGap(1);
break;
case conditionalDecl:
if (last() == ';' || last() == '}') lineGap(1);
break;
case variableDecl:
if (last() == '}') lineGap(1);
onNewline();
break;
case importDecl:
onNewline();
break;
case expr: break;
case catch_: goto case;
case else_:
final switch(style) with(IndentStyle)
{
case allman: onNewline(); break;
case otbs: space(); break;
}
break;
default: break;
}
}
}
void lineGap(int gap)
{
int count;
auto r = sink.data;
while(!r.empty && r.back.isWhite)
{
if (r.back == '\n') count++;
r.popBack();
}
if (r.empty) return;
int need = gap - count + 1;
while(need--) newline();
}
void newline()
{
if (ignoreNewlines)
{
space(); // don't do this when splitting lines
}
else
{
sink.put("\n");
lineLength = 0;
putIndent();
}
}
void onNewline()
{
auto r = sink.data;
while(!r.empty && r.back.isWhite())
{
if (r.back == '\n') return;
r.popBack();
}
if (r.empty) return;
newline();
}
void space()
{
if (!sink.data.empty && !sink.data.back.isWhite() && sink.data.back != '(')
put(" ");
}
static string binary(string symbol, string operator = null, bool nospace = false)
{
return "with(" ~ symbol ~ "){"
~ "format(left); if (right is null) return;"
~ (nospace ? "" : "put(` `);")
~ (operator ? "put(`" ~ operator ~ "`);" : "put(tokenRep(operator));")
~ (nospace ? "" : "put(` `);")
~ "format(right);}";
}
void startBlock()
{
final switch(style) with(IndentStyle)
{
case allman: onNewline(); break;
case otbs: space(); break;
}
put("{");
indent();
}
void endBlock()
{
outdent();
onNewline();
put("}");
}
string tokenRep(Token t)
{
return t.text.length ? t.text : tokenRep(t.type);
}
string tokenRep(IdType t)
{
return t ? str(t) : "";
}
void putComment(string c)
{
import std.string : splitLines;
if (!c.length) return;
lineGap(1);
put(c.splitLines().map!(l => getIndent() ~ l).join("\n"));
newline();
}
void putAttrs(const Attribute[] attrs)
{
if (attrs !is null)
{
foreach(count, attr; attrs)
{
space();
format(attr);
space();
}
}
}
void put(string s)
{
sink.put(s);
lineLength += s.length; // TODO: tabs / spaces?
}
void formatCaseDecls(const DeclarationsAndStatements declsAndStmnts)
{
bool seenBlock = false;
auto items = declsAndStmnts.declarationsAndStatements;
foreach(item; items)
{
bool _indent = false;
if (item.declaration) _indent = true;
if (item.statement && item.statement.statementNoCaseNoDefault)
{
if (item.statement.statementNoCaseNoDefault.blockStatement)
seenBlock = true;
else if (!item.statement.statementNoCaseNoDefault.labeledStatement)
_indent = true;
}
if (seenBlock) _indent = false;
if (_indent) indent();
format(item);
if (_indent) outdent();
}
}
bool needIndent(const Statement s)
{
return s.statementNoCaseNoDefault &&
!s.statementNoCaseNoDefault.blockStatement;
}
bool needIndent(const Declaration d)
{
return !d.declarations.length;
}
bool needIndent(const DeclarationOrStatement dors)
{
return (dors.declaration && needIndent(dors.declaration)) ||
(dors.statement && needIndent(dors.statement));
}
void maybeIndent(T)(const T t)
{
auto _indent = needIndent(t);
if (_indent) indent();
format(t);
if (_indent) outdent();
}
bool isEmptyDeclaration(const Declaration decl)
{
with(decl)
{
string mix(string[] s) {
string r;
foreach(c, d; s)
r ~= (c > 0 ? "else " : "") ~ "if (" ~ d ~ ") return false;";
return r;
}
mixin(mix(possibleDeclarations));
return attributes.length == 0 &&
declarations.length == 0;
}
}
bool ignoreNewlines = false;
bool useTabs;
uint caseDepth;
uint indentWidth;
uint indentLevel;
IndentStyle style;
Sink sink;
What lastThing, currentThing;
uint lineLength;
uint maxLineLength = 80;
enum possibleDeclarations = [
"attributeDeclaration",
"importDeclaration",
"functionDeclaration",
"variableDeclaration",
"aliasThisDeclaration",
"structDeclaration",
"classDeclaration",
"interfaceDeclaration",
"unionDeclaration",
"enumDeclaration",
"aliasDeclaration",
"mixinDeclaration",
"mixinTemplateDeclaration",
"unittest_",
"staticAssertDeclaration",
"templateDeclaration",
"constructor",
"destructor",
"staticConstructor",
"staticDestructor",
"sharedStaticDestructor",
"sharedStaticConstructor",
"conditionalDeclaration",
"pragmaDeclaration",
"versionSpecification",
"invariant_",
"postblit"
];
}