From 34174badd0e3793ecf3d4d8acbc928971a91bfa6 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 22 Sep 2023 13:17:09 +0530 Subject: [PATCH 01/24] chore(deps): add dmd library Signed-off-by: Prajwal S N --- .gitmodules | 3 +++ README.md | 10 +++++----- dmd | 1 + dub.json | 3 ++- makefile | 36 ++++++++++++++++++++++++++++++++---- 5 files changed, 43 insertions(+), 10 deletions(-) create mode 160000 dmd diff --git a/.gitmodules b/.gitmodules index d493df0..5cf3ca7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "d-test-utils"] path = d-test-utils url = https://github.com/dlang-community/d-test-utils.git +[submodule "dmd"] + path = dmd + url = https://github.com/dlang/dmd.git diff --git a/README.md b/README.md index 6c3d766..7bd2503 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ when using the **--inplace** option. ### Building from source using Make * Clone the repository -* Run ```git submodule update --init --recursive``` 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/```. +* Run `git submodule update --init --recursive` 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/`. ### Building from source using dub * Clone the repository @@ -69,8 +69,8 @@ dfmt --inplace --space_after_cast=false --max_line_length=80 \ ``` ## Disabling formatting -Formatting can be temporarily disabled by placing the comments ```// dfmt off``` -and ```// dfmt on``` around code that you do not want formatted. +Formatting can be temporarily disabled by placing the comments `// dfmt off` +and `// dfmt on` around code that you do not want formatted. ```d void main(string[] args) diff --git a/dmd b/dmd new file mode 160000 index 0000000..b859107 --- /dev/null +++ b/dmd @@ -0,0 +1 @@ +Subproject commit b859107c37a948d0492fccb7a319f0a96b0eecb1 diff --git a/dub.json b/dub.json index a0d6357..09b59ee 100644 --- a/dub.json +++ b/dub.json @@ -4,7 +4,8 @@ "targetType": "autodetect", "license": "BSL-1.0", "dependencies": { - "libdparse": ">=0.19.2 <1.0.0" + "libdparse": ">=0.19.2 <1.0.0", + "dmd": "~>2.105.2" }, "targetPath" : "bin/", "targetName" : "dfmt", diff --git a/makefile b/makefile index d790c0c..2051b1d 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,36 @@ +DMD_ROOT_SRC := \ + $(shell find dmd/compiler/src/dmd/common -name "*.d")\ + $(shell find dmd/compiler/src/dmd/root -name "*.d") +DMD_LEXER_SRC := \ + dmd/compiler/src/dmd/console.d \ + dmd/compiler/src/dmd/entity.d \ + dmd/compiler/src/dmd/errors.d \ + dmd/compiler/src/dmd/errorsink.d \ + dmd/compiler/src/dmd/location.d \ + dmd/compiler/src/dmd/file_manager.d \ + dmd/compiler/src/dmd/globals.d \ + dmd/compiler/src/dmd/id.d \ + dmd/compiler/src/dmd/identifier.d \ + dmd/compiler/src/dmd/lexer.d \ + dmd/compiler/src/dmd/tokens.d \ + dmd/compiler/src/dmd/utils.d \ + $(DMD_ROOT_SRC) + +DMD_PARSER_SRC := \ + dmd/compiler/src/dmd/astbase.d \ + dmd/compiler/src/dmd/parse.d \ + dmd/compiler/src/dmd/parsetimevisitor.d \ + dmd/compiler/src/dmd/transitivevisitor.d \ + dmd/compiler/src/dmd/permissivevisitor.d \ + dmd/compiler/src/dmd/strictvisitor.d \ + dmd/compiler/src/dmd/astenums.d \ + $(DMD_LEXER_SRC) + SRC := $(shell find src -name "*.d") \ - $(shell find libdparse/src -name "*.d") \ - $(shell find stdx-allocator/source -name "*.d") -INCLUDE_PATHS := -Ilibdparse/src -Istdx-allocator/source -Isrc -Jbin -DMD_COMMON_FLAGS := -dip25 -w $(INCLUDE_PATHS) + $(shell find stdx-allocator/source -name "*.d") \ + $(DMD_PARSER_SRC) +INCLUDE_PATHS := -Ilibdparse/src -Istdx-allocator/source -Isrc -Idmd/compiler/src -Jbin -Jdmd +DMD_COMMON_FLAGS := -w $(INCLUDE_PATHS) DMD_DEBUG_FLAGS := -debug -g $(DMD_COMMON_FLAGS) DMD_FLAGS := -O -inline $(DMD_COMMON_FLAGS) DMD_TEST_FLAGS := -unittest -g $(DMD_COMMON_FLAGS) From 61206bc0ca3879d3e4b7d349c61c71d387e5179e Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 22 Sep 2023 13:17:29 +0530 Subject: [PATCH 02/24] refactor: lexer in `tokens.d` Signed-off-by: Prajwal S N --- src/dfmt/tokens.d | 348 +++++++++++++++++++++++----------------------- 1 file changed, 176 insertions(+), 172 deletions(-) diff --git a/src/dfmt/tokens.d b/src/dfmt/tokens.d index 0271fde..9d5c9b1 100644 --- a/src/dfmt/tokens.d +++ b/src/dfmt/tokens.d @@ -5,15 +5,15 @@ module dfmt.tokens; -import dparse.lexer; +import dmd.tokens; /// Length of an invalid token enum int INVALID_TOKEN_LENGTH = -1; -uint betweenParenLength(const Token[] tokens) pure @safe @nogc +uint betweenParenLength(const Token[] tokens) @safe in { - assert(tokens[0].type == tok!"("); + assert(tokens[0].value == TOK.leftParenthesis); } do { @@ -22,9 +22,9 @@ do int depth = 1; while (i < tokens.length && depth > 0) { - if (tokens[i].type == tok!"(") + if (tokens[i].value == TOK.leftParenthesis) depth++; - else if (tokens[i].type == tok!")") + else if (tokens[i].value == TOK.rightParenthesis) depth--; length += tokenLength(tokens[i]); i++; @@ -32,163 +32,208 @@ do return length; } -int tokenLength(ref const Token t) pure @safe @nogc +int tokenLength(ref const Token t) @safe { import std.algorithm : countUntil; + if (t.isKeyword()) + return cast(int) Token.toString(t.value).length; + int c; - switch (t.type) + switch (t.value) { - case tok!"doubleLiteral": - case tok!"floatLiteral": - case tok!"idoubleLiteral": - case tok!"ifloatLiteral": - case tok!"intLiteral": - case tok!"longLiteral": - case tok!"realLiteral": - case tok!"irealLiteral": - case tok!"uintLiteral": - case tok!"ulongLiteral": - case tok!"characterLiteral": - return cast(int) t.text.length; - case tok!"identifier": - case tok!"stringLiteral": - case tok!"wstringLiteral": - case tok!"dstringLiteral": + // Numeric literals + case TOK.int32Literal: + case TOK.uns32Literal: + case TOK.int64Literal: + case TOK.uns64Literal: + case TOK.int128Literal: + case TOK.uns128Literal: + case TOK.float32Literal: + case TOK.float64Literal: + case TOK.float80Literal: + case TOK.imaginary32Literal: + case TOK.imaginary64Literal: + case TOK.imaginary80Literal: + // Char constants + case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: + // Identifiers + case TOK.identifier: + return cast(int) Token.toString(t.value).length; + // Spaced operators + case TOK.add: + case TOK.addAssign: + case TOK.and: + case TOK.andAnd: + case TOK.andAssign: + case TOK.arrow: + case TOK.assign: + case TOK.colon: + case TOK.colonColon: + case TOK.comma: + case TOK.concatenateAssign: + case TOK.div: + case TOK.divAssign: + case TOK.dot: + case TOK.dotDotDot: + case TOK.equal: + case TOK.goesTo: + case TOK.greaterOrEqual: + case TOK.greaterThan: + case TOK.identity: + case TOK.is_: + case TOK.leftShift: + case TOK.leftShiftAssign: + case TOK.lessOrEqual: + case TOK.lessThan: + case TOK.min: + case TOK.minAssign: + case TOK.minusMinus: + case TOK.mod: + case TOK.modAssign: + case TOK.mul: + case TOK.mulAssign: + case TOK.not: + case TOK.notEqual: + case TOK.notIdentity: + case TOK.or: + case TOK.orAssign: + case TOK.orOr: + case TOK.plusPlus: + case TOK.pound: + case TOK.pow: + case TOK.powAssign: + case TOK.question: + case TOK.rightShift: + case TOK.rightShiftAssign: + case TOK.semicolon: + case TOK.slice: + case TOK.tilde: + case TOK.unsignedRightShift: + case TOK.unsignedRightShiftAssign: + case TOK.xor: + case TOK.xorAssign: + return cast(int) Token.toString(t.value).length + 1; + case TOK.string_: // TODO: Unicode line breaks and old-Mac line endings - c = cast(int) t.text.countUntil('\n'); + c = cast(int) Token.toString(t.value).countUntil('\n'); if (c == -1) - return cast(int) t.text.length; + return cast(int) Token.toString(t.value).length; else return c; - mixin(generateFixedLengthCases()); + default: return INVALID_TOKEN_LENGTH; } } -bool isBreakToken(IdType t) pure nothrow @safe @nogc +bool isBreakToken(TOK t) pure nothrow @safe @nogc { switch (t) { - 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!"*=": - case tok!"*": - case tok!"&=": - case tok!"%=": - case tok!"%": - case tok!"+=": - case tok!".": - case tok!"~": - case tok!"+": - case tok!"-": + case TOK.orOr: + case TOK.andAnd: + case TOK.leftParenthesis: + case TOK.leftBracket: + case TOK.comma: + case TOK.colon: + case TOK.semicolon: + case TOK.pow: + case TOK.powAssign: + case TOK.xor: + case TOK.concatenateAssign: + case TOK.leftShiftAssign: + case TOK.leftShift: + case TOK.lessOrEqual: + case TOK.lessThan: + case TOK.equal: + case TOK.goesTo: + case TOK.assign: + case TOK.greaterOrEqual: + case TOK.rightShiftAssign: + case TOK.unsignedRightShift: + case TOK.unsignedRightShiftAssign: + case TOK.rightShift: + case TOK.greaterThan: + case TOK.orAssign: + case TOK.or: + case TOK.minAssign: + case TOK.notEqual: + case TOK.question: + case TOK.divAssign: + case TOK.div: + case TOK.slice: + case TOK.mulAssign: + case TOK.mul: + case TOK.andAssign: + case TOK.modAssign: + case TOK.mod: + case TOK.addAssign: + case TOK.dot: + case TOK.tilde: + case TOK.add: + case TOK.min: return true; default: return false; } } -int breakCost(IdType p, IdType c) pure nothrow @safe @nogc +int breakCost(TOK p, TOK c) pure nothrow @safe @nogc { switch (c) { - case tok!"||": - case tok!"&&": - case tok!",": - case tok!"?": + case TOK.orOr: + case TOK.andAnd: + case TOK.comma: + case TOK.question: return 0; - case tok!"(": + case TOK.leftParenthesis: return 60; - case tok!"[": + case TOK.leftBracket: return 300; - 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!"~": - case tok!"+=": + case TOK.semicolon: + case TOK.pow: + case TOK.xorAssign: + case TOK.xor: + case TOK.concatenateAssign: + case TOK.leftShiftAssign: + case TOK.leftShift: + case TOK.lessOrEqual: + case TOK.lessThan: + case TOK.equal: + case TOK.goesTo: + case TOK.assign: + case TOK.greaterOrEqual: + case TOK.rightShiftAssign: + case TOK.unsignedRightShiftAssign: + case TOK.unsignedRightShift: + case TOK.rightShift: + case TOK.greaterThan: + case TOK.orAssign: + case TOK.or: + case TOK.minAssign: + case TOK.divAssign: + case TOK.div: + case TOK.slice: + case TOK.mulAssign: + case TOK.mul: + case TOK.andAssign: + case TOK.modAssign: + case TOK.mod: + case TOK.add: + case TOK.min: + case TOK.tilde: + case TOK.addAssign: return 200; - case tok!":": + case TOK.colon: // colon could be after a label or an import, where it should normally wrap like before // for everything else (associative arrays) try not breaking around colons - return p == tok!"identifier" ? 0 : 300; - case tok!".": - return p == tok!")" ? 0 : 300; + return p == TOK.identifier ? 0 : 300; + case TOK.dot: + return p == TOK.rightParenthesis ? 0 : 300; default: return 1000; } @@ -198,46 +243,5 @@ pure nothrow @safe @nogc unittest { foreach (ubyte u; 0 .. ubyte.max) if (isBreakToken(u)) - assert(breakCost(tok!".", u) != 1000); -} - -private string generateFixedLengthCases() -{ - import std.algorithm : map; - import std.string : format; - import std.array : join; - - assert(__ctfe); - - string[] spacedOperatorTokens = [ - ",", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", - "!>", "!>=", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "+=", "-", - "-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>", - ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "^", "^=", "^^", - "^^=", "|", "|=", "||", "~", "~=" - ]; - immutable spacedOperatorTokenCases = spacedOperatorTokens.map!( - a => format(`case tok!"%s": return %d + 1;`, a, a.length)).join("\n\t"); - - string[] identifierTokens = [ - "abstract", "alias", "align", "asm", "assert", "auto", "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", "wchar", - "while", "with", "__DATE__", "__EOF__", "__FILE__", - "__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters", - "__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", - "__traits", "__vector", "__VENDOR__", "__VERSION__", "$", "++", "--", - ".", "[", "]", "(", ")", "{", "}" - ]; - immutable identifierTokenCases = identifierTokens.map!( - a => format(`case tok!"%s": return %d;`, a, a.length)).join("\n\t"); - return spacedOperatorTokenCases ~ identifierTokenCases; + assert(breakCost(TOK.dot, u) != 1000); } From 806e7589c9d6eb03bf925b953b6a89e7496287ed Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Wed, 27 Sep 2023 23:22:47 +0530 Subject: [PATCH 03/24] refactor: lexer in `indentation.d` and `wrapping.d` Signed-off-by: Prajwal S N --- src/dfmt/indentation.d | 159 ++++++++++++++++++++++++++++------------- src/dfmt/wrapping.d | 16 ++--- 2 files changed, 117 insertions(+), 58 deletions(-) diff --git a/src/dfmt/indentation.d b/src/dfmt/indentation.d index cdd78e4..50d7ab8 100644 --- a/src/dfmt/indentation.d +++ b/src/dfmt/indentation.d @@ -7,25 +7,82 @@ module dfmt.indentation; import dfmt.config; import dfmt.editorconfig; -import dparse.lexer; +import dmd.tokens; import std.bitmanip : bitfields; /** * Returns: true if the given token type is a wrap indent type */ -bool isWrapIndent(IdType type) pure nothrow @nogc @safe +bool isWrapIndent(TOK type) pure nothrow @nogc @safe { - return type != tok!"{" && type != tok!"case" && type != tok!"@" - && type != tok!"]" && type != tok!"(" && type != tok!")" && isOperator(type); + switch (type) + { + case TOK.leftCurly: + case TOK.case_: + case TOK.at: + case TOK.rightBracket: + case TOK.leftParenthesis: + case TOK.rightParenthesis: + return false; + + // Operators + case TOK.lessThan: + case TOK.greaterThan: + case TOK.lessOrEqual: + case TOK.greaterOrEqual: + case TOK.equal: + case TOK.notEqual: + case TOK.identity: + case TOK.notIdentity: + case TOK.is_: + + case TOK.leftShift: + case TOK.rightShift: + case TOK.leftShiftAssign: + case TOK.rightShiftAssign: + case TOK.unsignedRightShift: + case TOK.unsignedRightShiftAssign: + case TOK.concatenateAssign: + case TOK.add: + case TOK.min: + case TOK.addAssign: + case TOK.minAssign: + case TOK.mul: + case TOK.div: + case TOK.mod: + case TOK.mulAssign: + case TOK.divAssign: + case TOK.modAssign: + case TOK.and: + case TOK.or: + case TOK.xor: + case TOK.andAssign: + case TOK.orAssign: + case TOK.xorAssign: + case TOK.assign: + case TOK.not: + case TOK.tilde: + case TOK.plusPlus: + case TOK.minusMinus: + case TOK.dot: + case TOK.comma: + case TOK.question: + case TOK.andAnd: + case TOK.orOr: + return true; + default: + return false; + } } /** * Returns: true if the given token type is a temporary indent type */ -bool isTempIndent(IdType type) pure nothrow @nogc @safe +bool isTempIndent(TOK type) pure nothrow @nogc @safe { - return type != tok!")" && type != tok!"{" && type != tok!"case" && type != tok!"@"; + return type != TOK.rightParenthesis && type != TOK.leftCurly && type != TOK.case_ && type != TOK + .at; } /** @@ -44,24 +101,20 @@ struct IndentStack static struct Details { mixin(bitfields!( - // generally true for all operators except {, case, @, ], (, ) - bool, "wrap", 1, - // temporary indentation which get's reverted when a block starts - // generally true for all tokens except ), {, case, @ - bool, "temp", 1, - // emit minimal newlines - bool, "mini", 1, - // for associative arrays or arrays containing them, break after every item - bool, "breakEveryItem", 1, - // when an item inside an array would break mid-item, definitely break at the comma first - bool, "preferLongBreaking", 1, - uint, "", 27)); + // generally true for all operators except {, case, @, ], (, ) + bool, "wrap", 1, // temporary indentation which get's reverted when a block starts + // generally true for all tokens except ), {, case, @ + bool, "temp", 1, // emit minimal newlines + bool, "mini", 1, // for associative arrays or arrays containing them, break after every item + bool, "breakEveryItem", 1, // when an item inside an array would break mid-item, definitely break at the comma first + bool, "preferLongBreaking", 1, + uint, "", 27)); } /** * Get the indent size at the most recent occurrence of the given indent type */ - int indentToMostRecent(IdType item) const + int indentToMostRecent(TOK item) const { if (index == 0) return -1; @@ -84,7 +137,7 @@ struct IndentStack int tempIndentCount = 0; for (size_t i = index; i > 0; i--) { - if (!details[i - 1].wrap && arr[i - 1] != tok!"]") + if (!details[i - 1].wrap && arr[i - 1] != TOK.rightBracket) break; tempIndentCount++; } @@ -94,7 +147,7 @@ struct IndentStack /** * Pushes the given indent type on to the stack. */ - void push(IdType item) pure nothrow + void push(TOK item) pure nothrow { Details detail; detail.wrap = isWrapIndent(item); @@ -105,7 +158,7 @@ struct IndentStack /** * Pushes the given indent type on to the stack. */ - void push(IdType item, Details detail) pure nothrow + void push(TOK item, Details detail) pure nothrow { arr[index] = item; details[index] = detail; @@ -145,7 +198,7 @@ struct IndentStack index--; } - bool topAre(IdType[] types...) + bool topAre(TOK[] types...) { if (types.length > index) return false; @@ -156,7 +209,7 @@ struct IndentStack /** * Returns: `true` if the top of the indent stack is the given indent type. */ - bool topIs(IdType type) const pure nothrow @safe @nogc + bool topIs(TOK type) const pure nothrow @safe @nogc { return index > 0 && index <= arr.length && arr[index - 1] == type; } @@ -172,9 +225,10 @@ struct IndentStack /** * Returns: `true` if the top of the indent stack is a temporary indent with the specified token */ - bool topIsTemp(IdType item) + bool topIsTemp(TOK item) { - return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1].temp; + return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1] + .temp; } /** @@ -188,16 +242,17 @@ struct IndentStack /** * Returns: `true` if the top of the indent stack is a temporary indent with the specified token */ - bool topIsWrap(IdType item) + bool topIsWrap(TOK item) { - return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1].wrap; + return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1] + .wrap; } /** * Returns: `true` if the top of the indent stack is one of the given token * types. */ - bool topIsOneOf(IdType[] types...) const pure nothrow @safe @nogc + bool topIsOneOf(TOK[] types...) const pure nothrow @safe @nogc { if (index == 0) return false; @@ -208,7 +263,7 @@ struct IndentStack return false; } - IdType top() const pure nothrow @property @safe @nogc + TOK top() const pure nothrow @property @safe @nogc { return arr[index - 1]; } @@ -233,26 +288,28 @@ struct IndentStack */ void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__) const { - import dparse.lexer : str; import std.algorithm.iteration : map; import std.stdio : stderr; if (pos == size_t.max) - stderr.writefln("\033[31m%s:%d %(%s %)\033[0m", file, line, arr[0 .. index].map!(a => str(a))); + stderr.writefln("\033[31m%s:%d %(%s %)\033[0m", file, line, arr[0 .. index].map!( + a => Token.toString(a))); else - stderr.writefln("\033[31m%s:%d at %d %(%s %)\033[0m", file, line, pos, arr[0 .. index].map!(a => str(a))); + stderr.writefln("\033[31m%s:%d at %d %(%s %)\033[0m", file, line, pos, arr[0 .. index].map!( + a => Token.toString(a))); } private: size_t index; - IdType[256] arr; + TOK[256] arr; Details[arr.length] details; int indentSize(const size_t k = size_t.max) const pure nothrow @safe @nogc { import std.algorithm : among; + if (index == 0 || k == 0) return 0; immutable size_t j = k == size_t.max ? index : k; @@ -260,9 +317,9 @@ private: int parenCount; foreach (i; 0 .. j) { - immutable int pc = (arr[i] == tok!"!" || arr[i] == tok!"(" || arr[i] == tok!")") ? parenCount + 1 - : parenCount; - if ((details[i].wrap || arr[i] == tok!"(") && parenCount > 1) + immutable int pc = (arr[i] == TOK.not || arr[i] == TOK.leftParenthesis || arr[i] == TOK + .rightParenthesis) ? parenCount + 1 : parenCount; + if ((details[i].wrap || arr[i] == TOK.leftParenthesis) && parenCount > 1) { parenCount = pc; continue; @@ -277,31 +334,33 @@ private: } immutable currentIsNonWrapTemp = !details[i].wrap - && details[i].temp && arr[i] != tok!")" && arr[i] != tok!"!"; + && details[i].temp && arr[i] != TOK.rightParenthesis && arr[i] != TOK.not; - if (currentIsNonWrapTemp && arr[i + 1] == tok!"]") + if (currentIsNonWrapTemp && arr[i + 1] == TOK.rightBracket) { parenCount = pc; continue; } - if (arr[i] == tok!"static" - && arr[i + 1].among!(tok!"if", tok!"else", tok!"foreach", tok!"foreach_reverse") - && (i + 2 >= index || arr[i + 2] != tok!"{")) + if (arr[i] == TOK.static_ + && arr[i + 1].among!(TOK.if_, TOK.else_, TOK.foreach_, TOK.foreach_reverse_) + && (i + 2 >= index || arr[i + 2] != TOK.leftCurly)) { parenCount = pc; continue; } - if (currentIsNonWrapTemp && (arr[i + 1] == tok!"switch" - || arr[i + 1] == tok!"{" || arr[i + 1] == tok!")")) + + if (currentIsNonWrapTemp && (arr[i + 1] == TOK.switch_ + || arr[i + 1] == TOK.leftCurly || arr[i + 1] == TOK.rightParenthesis)) { parenCount = pc; continue; } } - else if (parenCount == 0 && arr[i] == tok!"(" && config.dfmt_single_indent == OptionalBoolean.f) + else if (parenCount == 0 && arr[i] == TOK.leftParenthesis && config.dfmt_single_indent == OptionalBoolean + .f) size++; - if (arr[i] == tok!"!") + if (arr[i] == TOK.not) size++; parenCount = pc; @@ -312,21 +371,21 @@ private: bool skipDoubleIndent(size_t i, int parenCount) const pure nothrow @safe @nogc { - return (details[i + 1].wrap && arr[i] == tok!")") - || (parenCount == 0 && arr[i + 1] == tok!"," && arr[i] == tok!"("); + return (details[i + 1].wrap && arr[i] == TOK.rightParenthesis) + || (parenCount == 0 && arr[i + 1] == TOK.comma && arr[i] == TOK.leftParenthesis); } } unittest { IndentStack stack; - stack.push(tok!"{"); + stack.push(TOK.leftCurly); assert(stack.length == 1); assert(stack.indentLevel == 1); stack.pop(); assert(stack.length == 0); assert(stack.indentLevel == 0); - stack.push(tok!"if"); + stack.push(TOK.if_); assert(stack.topIsTemp()); stack.popTempIndents(); assert(stack.length == 0); diff --git a/src/dfmt/wrapping.d b/src/dfmt/wrapping.d index 79fb85f..1d3f436 100644 --- a/src/dfmt/wrapping.d +++ b/src/dfmt/wrapping.d @@ -5,14 +5,14 @@ module dfmt.wrapping; -import dparse.lexer; +import dmd.tokens; import dfmt.tokens; import dfmt.config; struct State { this(uint breaks, const Token[] tokens, immutable short[] depths, - const Config* config, int currentLineLength, int indentLevel) pure @safe + const Config* config, int currentLineLength, int indentLevel) @safe { import std.math : abs; import core.bitop : popcnt, bsf; @@ -42,8 +42,8 @@ struct State { if (((1 << i) & breaks) == 0) continue; - immutable prevType = i > 0 ? tokens[i - 1].type : tok!""; - immutable currentType = tokens[i].type; + immutable prevType = i > 0 ? tokens[i - 1].value : TOK.error; + immutable currentType = tokens[i].value; immutable p = abs(depths[i]); immutable bc = breakCost(prevType, currentType) * (p == 0 ? 1 : p * 2); this._cost += bc + newlinePenalty; @@ -126,7 +126,7 @@ private enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8; * continuation indents are reduced. This is used for array literals. */ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, - immutable short[] depths, const Config* config, int currentLineLength, int indentLevel) + immutable short[] depths, const Config* config, int currentLineLength, int indentLevel) { import std.container.rbtree : RedBlackTree; import std.algorithm : filter, min; @@ -159,7 +159,7 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, if (current < lowest) lowest = current; validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], - current.breaks, config, currentLineLength, indentLevel); + current.breaks, config, currentLineLength, indentLevel); } foreach (r; open[].filter!(a => a.solved)) return genRetVal(r.breaks, index); @@ -170,11 +170,11 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, } void validMoves(OR)(auto ref OR output, const Token[] tokens, immutable short[] depths, - uint current, const Config* config, int currentLineLength, int indentLevel) + uint current, const Config* config, int currentLineLength, int indentLevel) { foreach (i, token; tokens) { - if (!isBreakToken(token.type) || (((1 << i) & current) != 0)) + if (!isBreakToken(token.value) || (((1 << i) & current) != 0)) continue; immutable uint breaks = current | (1 << i); output.insert(State(breaks, tokens, depths, config, currentLineLength, indentLevel)); From 6c1c543194be2713d214313a460c8a4202d0a7f0 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Wed, 27 Sep 2023 23:27:16 +0530 Subject: [PATCH 04/24] feat: make it compile with dmd AST Signed-off-by: Prajwal S N --- src/dfmt/ast_info.d | 518 ++--- src/dfmt/formatter.d | 4365 +++++++++++++++++++++--------------------- 2 files changed, 2451 insertions(+), 2432 deletions(-) diff --git a/src/dfmt/ast_info.d b/src/dfmt/ast_info.d index 34a8ede..78f16d6 100644 --- a/src/dfmt/ast_info.d +++ b/src/dfmt/ast_info.d @@ -5,8 +5,8 @@ module dfmt.ast_info; -import dparse.lexer; -import dparse.ast; +import dmd.transitivevisitor; +import dmd.tokens; enum BraceIndentInfoFlags { @@ -57,10 +57,8 @@ struct ASTInformation sort(constructorDestructorLocations); sort(staticConstructorDestructorLocations); sort(sharedStaticConstructorDestructorLocations); - sort!((a,b) => a.endLocation < b.endLocation) - (indentInfoSortedByEndLocation); - sort!((a,b) => a.endLocation < b.endLocation) - (structInfoSortedByEndLocation); + sort!((a, b) => a.endLocation < b.endLocation)(indentInfoSortedByEndLocation); + sort!((a, b) => a.endLocation < b.endLocation)(structInfoSortedByEndLocation); sort(ufcsHintLocations); ufcsHintLocations = ufcsHintLocations.uniq().array(); sort(ternaryColonLocations); @@ -146,9 +144,9 @@ struct ASTInformation } /// Collects information from the AST that is useful for the formatter -final class FormatVisitor : ASTVisitor +extern (C++) class FormatVisitor(AST) : ParseTimeTransitiveVisitor!AST { - alias visit = ASTVisitor.visit; + alias visit = ParseTimeTransitiveVisitor!AST.visit; /** * Params: @@ -159,292 +157,298 @@ final class FormatVisitor : ASTVisitor this.astInformation = astInformation; } - override void visit(const ArrayInitializer arrayInitializer) - { - astInformation.arrayStartLocations ~= arrayInitializer.startLocation; - arrayInitializer.accept(this); - } + /* override void visit(const ArrayInitializer arrayInitializer) */ + /* { */ + /* astInformation.arrayStartLocations ~= arrayInitializer.startLocation; */ + /* arrayInitializer.accept(this); */ + /* } */ - override void visit(const ArrayLiteral arrayLiteral) - { - astInformation.arrayStartLocations ~= arrayLiteral.tokens[0].index; - arrayLiteral.accept(this); - } + /* override void visit(const ArrayLiteral arrayLiteral) */ + /* { */ + /* astInformation.arrayStartLocations ~= arrayLiteral.tokens[0].index; */ + /* arrayLiteral.accept(this); */ + /* } */ - override void visit(const AssocArrayLiteral assocArrayLiteral) - { - astInformation.arrayStartLocations ~= assocArrayLiteral.tokens[0].index; - astInformation.assocArrayStartLocations ~= assocArrayLiteral.tokens[0].index; - assocArrayLiteral.accept(this); - } + /* override void visit(const AssocArrayLiteral assocArrayLiteral) */ + /* { */ + /* astInformation.arrayStartLocations ~= assocArrayLiteral.tokens[0].index; */ + /* astInformation.assocArrayStartLocations ~= assocArrayLiteral.tokens[0].index; */ + /* assocArrayLiteral.accept(this); */ + /* } */ - override void visit (const SharedStaticConstructor sharedStaticConstructor) - { - astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticConstructor.location; - sharedStaticConstructor.accept(this); - } + /* override void visit(const SharedStaticConstructor sharedStaticConstructor) */ + /* { */ + /* astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticConstructor */ + /* .location; */ + /* sharedStaticConstructor.accept(this); */ + /* } */ - override void visit (const SharedStaticDestructor sharedStaticDestructor) - { - astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticDestructor.location; - sharedStaticDestructor.accept(this); - } + /* override void visit(const SharedStaticDestructor sharedStaticDestructor) */ + /* { */ + /* astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticDestructor */ + /* .location; */ + /* sharedStaticDestructor.accept(this); */ + /* } */ - override void visit (const StaticConstructor staticConstructor) - { - astInformation.staticConstructorDestructorLocations ~= staticConstructor.location; - staticConstructor.accept(this); - } + /* override void visit(const StaticConstructor staticConstructor) */ + /* { */ + /* astInformation.staticConstructorDestructorLocations ~= staticConstructor.location; */ + /* staticConstructor.accept(this); */ + /* } */ - override void visit (const StaticDestructor staticDestructor) - { - astInformation.staticConstructorDestructorLocations ~= staticDestructor.location; - staticDestructor.accept(this); - } + /* override void visit(const StaticDestructor staticDestructor) */ + /* { */ + /* astInformation.staticConstructorDestructorLocations ~= staticDestructor.location; */ + /* staticDestructor.accept(this); */ + /* } */ - override void visit (const Constructor constructor) - { - astInformation.constructorDestructorLocations ~= constructor.location; - constructor.accept(this); - } + /* override void visit(const Constructor constructor) */ + /* { */ + /* astInformation.constructorDestructorLocations ~= constructor.location; */ + /* constructor.accept(this); */ + /* } */ - override void visit (const Destructor destructor) - { - astInformation.constructorDestructorLocations ~= destructor.index; - destructor.accept(this); - } + /* override void visit(const Destructor destructor) */ + /* { */ + /* astInformation.constructorDestructorLocations ~= destructor.index; */ + /* destructor.accept(this); */ + /* } */ - override void visit (const FunctionBody functionBody) - { - if (auto bd = functionBody.specifiedFunctionBody) - { - if (bd.blockStatement) - { - astInformation.funBodyLocations ~= bd.blockStatement.startLocation; - } - } - functionBody.accept(this); - } + /* override void visit(const FunctionBody functionBody) */ + /* { */ + /* if (auto bd = functionBody.specifiedFunctionBody) */ + /* { */ + /* if (bd.blockStatement) */ + /* { */ + /* astInformation.funBodyLocations ~= bd.blockStatement.startLocation; */ + /* } */ + /* } */ + /* functionBody.accept(this); */ + /* } */ - override void visit(const ConditionalDeclaration dec) - { - if (dec.hasElse) - { - auto condition = dec.compileCondition; - if (condition.versionCondition !is null) - { - astInformation.conditionalWithElseLocations - ~= condition.versionCondition.versionIndex; - } - else if (condition.debugCondition !is null) - { - astInformation.conditionalWithElseLocations ~= condition.debugCondition.debugIndex; - } - // Skip "static if" because the formatting for normal "if" handles - // it properly - } - dec.accept(this); - } + /* override void visit(const ConditionalDeclaration dec) */ + /* { */ + /* if (dec.hasElse) */ + /* { */ + /* auto condition = dec.compileCondition; */ + /* if (condition.versionCondition !is null) */ + /* { */ + /* astInformation.conditionalWithElseLocations */ + /* ~= condition.versionCondition.versionIndex; */ + /* } */ + /* else if (condition.debugCondition !is null) */ + /* { */ + /* astInformation.conditionalWithElseLocations ~= condition.debugCondition.debugIndex; */ + /* } */ + /* // Skip "static if" because the formatting for normal "if" handles */ + /* // it properly */ + /* } */ + /* dec.accept(this); */ + /* } */ - override void visit(const Constraint constraint) - { - astInformation.constraintLocations ~= constraint.location; - constraint.accept(this); - } + /* override void visit(const Constraint constraint) */ + /* { */ + /* astInformation.constraintLocations ~= constraint.location; */ + /* constraint.accept(this); */ + /* } */ - override void visit(const ConditionalStatement statement) - { - auto condition = statement.compileCondition; - if (condition.versionCondition !is null) - { - astInformation.conditionalStatementLocations ~= condition.versionCondition.versionIndex; - } - else if (condition.debugCondition !is null) - { - astInformation.conditionalStatementLocations ~= condition.debugCondition.debugIndex; - } - statement.accept(this); - } + /* override void visit(const ConditionalStatement statement) */ + /* { */ + /* auto condition = statement.compileCondition; */ + /* if (condition.versionCondition !is null) */ + /* { */ + /* astInformation.conditionalStatementLocations ~= condition.versionCondition.versionIndex; */ + /* } */ + /* else if (condition.debugCondition !is null) */ + /* { */ + /* astInformation.conditionalStatementLocations ~= condition.debugCondition.debugIndex; */ + /* } */ + /* statement.accept(this); */ + /* } */ - override void visit(const FunctionLiteralExpression funcLit) - { - if (funcLit.specifiedFunctionBody !is null) - { - const bs = funcLit.specifiedFunctionBody.blockStatement; + /* override void visit(const FunctionLiteralExpression funcLit) */ + /* { */ + /* if (funcLit.specifiedFunctionBody !is null) */ + /* { */ + /* const bs = funcLit.specifiedFunctionBody.blockStatement; */ - astInformation.funLitStartLocations ~= bs.startLocation; - astInformation.funLitEndLocations ~= bs.endLocation; - astInformation.indentInfoSortedByEndLocation ~= - BraceIndentInfo(bs.startLocation, bs.endLocation); - } - funcLit.accept(this); - } + /* astInformation.funLitStartLocations ~= bs.startLocation; */ + /* astInformation.funLitEndLocations ~= bs.endLocation; */ + /* astInformation.indentInfoSortedByEndLocation ~= */ + /* BraceIndentInfo(bs.startLocation, bs.endLocation); */ + /* } */ + /* funcLit.accept(this); */ + /* } */ - override void visit(const DefaultStatement defaultStatement) - { - astInformation.caseEndLocations ~= defaultStatement.colonLocation; - defaultStatement.accept(this); - } + /* override void visit(const DefaultStatement defaultStatement) */ + /* { */ + /* astInformation.caseEndLocations ~= defaultStatement.colonLocation; */ + /* defaultStatement.accept(this); */ + /* } */ - override void visit(const CaseStatement caseStatement) - { - astInformation.caseEndLocations ~= caseStatement.colonLocation; - caseStatement.accept(this); - } + /* override void visit(const CaseStatement caseStatement) */ + /* { */ + /* astInformation.caseEndLocations ~= caseStatement.colonLocation; */ + /* caseStatement.accept(this); */ + /* } */ - override void visit(const CaseRangeStatement caseRangeStatement) - { - astInformation.caseEndLocations ~= caseRangeStatement.colonLocation; - caseRangeStatement.accept(this); - } + /* override void visit(const CaseRangeStatement caseRangeStatement) */ + /* { */ + /* astInformation.caseEndLocations ~= caseRangeStatement.colonLocation; */ + /* caseRangeStatement.accept(this); */ + /* } */ - override void visit(const SpecifiedFunctionBody specifiedFunctionBody) - { - if (specifiedFunctionBody.blockStatement !is null) - astInformation.doubleNewlineLocations ~= specifiedFunctionBody.blockStatement.endLocation; - specifiedFunctionBody.accept(this); - } + /* override void visit(const SpecifiedFunctionBody specifiedFunctionBody) */ + /* { */ + /* if (specifiedFunctionBody.blockStatement !is null) */ + /* astInformation.doubleNewlineLocations ~= specifiedFunctionBody */ + /* .blockStatement.endLocation; */ + /* specifiedFunctionBody.accept(this); */ + /* } */ - override void visit(const StructInitializer structInitializer) - { - astInformation.structInitStartLocations ~= structInitializer.startLocation; - astInformation.structInitEndLocations ~= structInitializer.endLocation; - astInformation.structInfoSortedByEndLocation ~= - StructInitializerInfo(structInitializer.startLocation, structInitializer.endLocation); - astInformation.indentInfoSortedByEndLocation ~= - BraceIndentInfo(structInitializer.startLocation, structInitializer.endLocation); + /* override void visit(const StructInitializer structInitializer) */ + /* { */ + /* astInformation.structInitStartLocations ~= structInitializer.startLocation; */ + /* astInformation.structInitEndLocations ~= structInitializer.endLocation; */ + /* astInformation.structInfoSortedByEndLocation ~= */ + /* StructInitializerInfo( */ + /* structInitializer.startLocation, structInitializer.endLocation); */ + /* astInformation.indentInfoSortedByEndLocation ~= */ + /* BraceIndentInfo( */ + /* structInitializer.startLocation, structInitializer.endLocation); */ - structInitializer.accept(this); - } + /* structInitializer.accept(this); */ + /* } */ - override void visit(const EnumBody enumBody) - { - astInformation.doubleNewlineLocations ~= enumBody.endLocation; - enumBody.accept(this); - } + /* override void visit(const EnumBody enumBody) */ + /* { */ + /* astInformation.doubleNewlineLocations ~= enumBody.endLocation; */ + /* enumBody.accept(this); */ + /* } */ - override void visit(const Unittest unittest_) - { - astInformation.doubleNewlineLocations ~= unittest_.blockStatement.endLocation; - unittest_.accept(this); - } + /* override void visit(const Unittest unittest_) */ + /* { */ + /* astInformation.doubleNewlineLocations ~= unittest_.blockStatement.endLocation; */ + /* unittest_.accept(this); */ + /* } */ - override void visit(const Invariant invariant_) - { - if (invariant_.blockStatement !is null) - astInformation.doubleNewlineLocations ~= invariant_.blockStatement.endLocation; - - invariant_.accept(this); - } + /* override void visit(const Invariant invariant_) */ + /* { */ + /* if (invariant_.blockStatement !is null) */ + /* astInformation.doubleNewlineLocations ~= invariant_.blockStatement.endLocation; */ - override void visit(const StructBody structBody) - { - astInformation.aggregateBodyLocations ~= structBody.startLocation; - astInformation.doubleNewlineLocations ~= structBody.endLocation; - structBody.accept(this); - } + /* invariant_.accept(this); */ + /* } */ - override void visit(const TemplateDeclaration templateDeclaration) - { - astInformation.doubleNewlineLocations ~= templateDeclaration.endLocation; - templateDeclaration.accept(this); - } + /* override void visit(const StructBody structBody) */ + /* { */ + /* astInformation.aggregateBodyLocations ~= structBody.startLocation; */ + /* astInformation.doubleNewlineLocations ~= structBody.endLocation; */ + /* structBody.accept(this); */ + /* } */ - override void visit(const TypeSuffix typeSuffix) - { - if (typeSuffix.star.type != tok!"") - astInformation.spaceAfterLocations ~= typeSuffix.star.index; - typeSuffix.accept(this); - } + /* override void visit(const TemplateDeclaration templateDeclaration) */ + /* { */ + /* astInformation.doubleNewlineLocations ~= templateDeclaration.endLocation; */ + /* templateDeclaration.accept(this); */ + /* } */ - override void visit(const UnaryExpression unary) - { - import std.typecons : rebindable; + /* override void visit(const TypeSuffix typeSuffix) */ + /* { */ + /* if (typeSuffix.star.type != TOK.error) */ + /* astInformation.spaceAfterLocations ~= typeSuffix.star.index; */ + /* typeSuffix.accept(this); */ + /* } */ - int chainLength; - auto u = rebindable(unary); - while (u !is null) - { - if (u.identifierOrTemplateInstance !is null - && u.identifierOrTemplateInstance.templateInstance !is null) - chainLength++; - u = u.unaryExpression; - } - if (chainLength > 1) - { - u = unary; - while (u.unaryExpression !is null) - { - astInformation.ufcsHintLocations ~= u.dotLocation; - u = u.unaryExpression; - } - } - if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&" - || unary.prefix.type == tok!"*" - || unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-") - { - astInformation.unaryLocations ~= unary.prefix.index; - } - unary.accept(this); - } + /* override void visit(const UnaryExpression unary) */ + /* { */ + /* import std.typecons : rebindable; */ - override void visit(const AttributeDeclaration attributeDeclaration) - { - astInformation.attributeDeclarationLines ~= attributeDeclaration.line; - attributeDeclaration.accept(this); - } + /* int chainLength; */ + /* auto u = rebindable(unary); */ + /* while (u !is null) */ + /* { */ + /* if (u.identifierOrTemplateInstance !is null */ + /* && u.identifierOrTemplateInstance.templateInstance !is null) */ + /* chainLength++; */ + /* u = u.unaryExpression; */ + /* } */ + /* if (chainLength > 1) */ + /* { */ + /* u = unary; */ + /* while (u.unaryExpression !is null) */ + /* { */ + /* astInformation.ufcsHintLocations ~= u.dotLocation; */ + /* u = u.unaryExpression; */ + /* } */ + /* } */ + /* if (unary.prefix.type == TOK.tilde || unary.prefix.type == TOK.and */ + /* || unary.prefix.type == TOK.mul */ + /* || unary.prefix.type == TOK.add || unary.prefix.type == TOK.min) */ + /* { */ + /* astInformation.unaryLocations ~= unary.prefix.index; */ + /* } */ + /* unary.accept(this); */ + /* } */ - override void visit(const FunctionAttribute functionAttribute) - { - if (functionAttribute.atAttribute !is null) - astInformation.atAttributeStartLocations ~= functionAttribute.atAttribute.startLocation; - functionAttribute.accept(this); - } + /* override void visit(const AttributeDeclaration attributeDeclaration) */ + /* { */ + /* astInformation.attributeDeclarationLines ~= attributeDeclaration.line; */ + /* attributeDeclaration.accept(this); */ + /* } */ - override void visit(const MemberFunctionAttribute memberFunctionAttribute) - { - if (memberFunctionAttribute.atAttribute !is null) - astInformation.atAttributeStartLocations ~= memberFunctionAttribute.atAttribute.startLocation; - memberFunctionAttribute.accept(this); - } + /* override void visit(const FunctionAttribute functionAttribute) */ + /* { */ + /* if (functionAttribute.atAttribute !is null) */ + /* astInformation.atAttributeStartLocations ~= functionAttribute.atAttribute.startLocation; */ + /* functionAttribute.accept(this); */ + /* } */ - override void visit(const Attribute attribute) - { - if (attribute.atAttribute !is null) - astInformation.atAttributeStartLocations ~= attribute.atAttribute.startLocation; - attribute.accept(this); - } + /* override void visit(const MemberFunctionAttribute memberFunctionAttribute) */ + /* { */ + /* if (memberFunctionAttribute.atAttribute !is null) */ + /* astInformation.atAttributeStartLocations ~= memberFunctionAttribute */ + /* .atAttribute.startLocation; */ + /* memberFunctionAttribute.accept(this); */ + /* } */ - override void visit(const StorageClass storageClass) - { - if (storageClass.atAttribute !is null) - astInformation.atAttributeStartLocations ~= storageClass.atAttribute.startLocation; - storageClass.accept(this); - } + /* override void visit(const Attribute attribute) */ + /* { */ + /* if (attribute.atAttribute !is null) */ + /* astInformation.atAttributeStartLocations ~= attribute.atAttribute.startLocation; */ + /* attribute.accept(this); */ + /* } */ - override void visit(const InContractExpression inContractExpression) - { - astInformation.contractLocations ~= inContractExpression.inTokenLocation; - inContractExpression.accept(this); - } + /* override void visit(const StorageClass storageClass) */ + /* { */ + /* if (storageClass.atAttribute !is null) */ + /* astInformation.atAttributeStartLocations ~= storageClass.atAttribute.startLocation; */ + /* storageClass.accept(this); */ + /* } */ - override void visit(const InStatement inStatement) - { - astInformation.contractLocations ~= inStatement.inTokenLocation; - inStatement.accept(this); - } + /* override void visit(const InContractExpression inContractExpression) */ + /* { */ + /* astInformation.contractLocations ~= inContractExpression.inTokenLocation; */ + /* inContractExpression.accept(this); */ + /* } */ - override void visit(const OutContractExpression outContractExpression) - { - astInformation.contractLocations ~= outContractExpression.outTokenLocation; - outContractExpression.accept(this); - } + /* override void visit(const InStatement inStatement) */ + /* { */ + /* astInformation.contractLocations ~= inStatement.inTokenLocation; */ + /* inStatement.accept(this); */ + /* } */ - override void visit(const OutStatement outStatement) - { - astInformation.contractLocations ~= outStatement.outTokenLocation; - outStatement.accept(this); - } + /* override void visit(const OutContractExpression outContractExpression) */ + /* { */ + /* astInformation.contractLocations ~= outContractExpression.outTokenLocation; */ + /* outContractExpression.accept(this); */ + /* } */ + + /* override void visit(const OutStatement outStatement) */ + /* { */ + /* astInformation.contractLocations ~= outStatement.outTokenLocation; */ + /* outStatement.accept(this); */ + /* } */ override void visit(const TernaryExpression ternaryExpression) { diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 0f7e821..ac0f283 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -1,4 +1,3 @@ - // Copyright Brian Schott 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at @@ -6,9 +5,14 @@ module dfmt.formatter; -import dparse.lexer; -import dparse.parser; -import dparse.rollback_allocator; +import dmd.tokens; +import dmd.parse; +import dmd.id; +import dmd.errorsink; +import dmd.identifier; +import dmd.astbase; +import dmd.transitivevisitor; +import dmd.permissivevisitor; import dfmt.ast_info; import dfmt.config; import dfmt.indentation; @@ -28,33 +32,36 @@ import std.algorithm.comparison : among, max; * function can return `true` if parsing failed. */ bool format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output, - Config* formatterConfig) + Config* formatterConfig) { - LexerConfig config; - config.stringBehavior = StringBehavior.source; - config.whitespaceBehavior = WhitespaceBehavior.skip; - LexerConfig parseConfig; - parseConfig.stringBehavior = StringBehavior.source; - parseConfig.whitespaceBehavior = WhitespaceBehavior.skip; - StringCache cache = StringCache(StringCache.defaultBucketCount); + Id.initialize(); + ASTBase.Type._init(); + + auto id = Identifier.idPool(source_desc); + auto m = new ASTBase.Module(&(source_desc.dup)[0], id, false, false); + import std.file : readText; + + auto input = readText(source_desc); + auto inp = cast(char[]) input; + + auto p = new Parser!ASTBase(m, inp, false, new ErrorSinkNull, null, false); + /* p.nextToken(); */ + m.members = p.parseModule(); + ASTInformation astInformation; - RollbackAllocator allocator; - auto parseTokens = getTokensForParser(buffer, parseConfig, &cache); - auto mod = parseModule(parseTokens, source_desc, &allocator); - auto visitor = new FormatVisitor(&astInformation); - visitor.visit(mod); - astInformation.cleanup(); - auto tokenRange = byToken(buffer, config, &cache); - auto app = appender!(Token[])(); - for (; !tokenRange.empty(); tokenRange.popFront()) - app.put(tokenRange.front()); - auto tokens = app.data; - if (!tokenRange.messages.empty) - return false; - auto depths = generateDepthInfo(tokens); - auto tokenFormatter = TokenFormatter!OutputRange(buffer, tokens, depths, - output, &astInformation, formatterConfig); - tokenFormatter.format(); + scope vis = new FormatVisitor!ASTBase(&astInformation); + m.accept(vis); + /* auto tokenRange = byToken(buffer, config, &cache); */ + /* auto app = appender!(Token[])(); */ + /* for (; !tokenRange.empty(); tokenRange.popFront()) */ + /* app.put(tokenRange.front()); */ + /* auto tokens = app.data; */ + /* if (!tokenRange.messages.empty) */ + /* return false; */ + /* auto depths = generateDepthInfo(tokens); */ + /* auto tokenFormatter = TokenFormatter!OutputRange(buffer, tokens, depths, */ + /* output, &astInformation, formatterConfig); */ + /* tokenFormatter.format(); */ return true; } @@ -66,20 +73,20 @@ immutable(short[]) generateDepthInfo(const Token[] tokens) pure nothrow @trusted short depth = 0; foreach (i, ref t; tokens) { - switch (t.type) + switch (t.value) { - case tok!"[": + case TOK.leftBracket: depth++; goto case; - case tok!"{": - case tok!"(": + case TOK.leftCurly: + case TOK.leftParenthesis: depth++; break; - case tok!"]": + case TOK.rightBracket: depth--; goto case; - case tok!"}": - case tok!")": + case TOK.rightCurly: + case TOK.rightParenthesis: depth--; break; default: @@ -103,7 +110,7 @@ struct TokenFormatter(OutputRange) * config = ? */ this(const ubyte[] rawSource, const(Token)[] tokens, immutable short[] depths, - OutputRange output, ASTInformation* astInformation, Config* config) + OutputRange output, ASTInformation* astInformation, Config* config) { this.rawSource = rawSource; this.tokens = tokens; @@ -125,7 +132,7 @@ struct TokenFormatter(OutputRange) assert(false, "config.end_of_line was unspecified"); else { - assert (eol == eol._default); + assert(eol == eol._default); this.eolString = eolStringFromInput; } } @@ -219,2176 +226,2184 @@ private: void formatStep() { - import std.range : assumeSorted; + return; - assert(hasCurrent); - if (currentIs(tok!"comment")) - { - formatComment(); - } - else if (isStringLiteral(current.type) - || isNumberLiteral(current.type) || currentIs(tok!"characterLiteral")) - { - writeToken(); - if (hasCurrent) - { - immutable t = tokens[index].type; - if (t == tok!"identifier" || isStringLiteral(t) - || isNumberLiteral(t) || t == tok!"characterLiteral" - // a!"b" function() - || t == tok!"function" || t == tok!"delegate") - write(" "); - } - } - else if (currentIs(tok!"module") || currentIs(tok!"import")) - { - formatModuleOrImport(); - } - else if (currentIs(tok!"return")) - { - writeToken(); - if (hasCurrent && (!currentIs(tok!";") && !currentIs(tok!")") && !currentIs(tok!"{") - && !currentIs(tok!"in") && !currentIs(tok!"out") && !currentIs(tok!"do") - && tokens[index].text != "body")) - write(" "); - } - else if (currentIs(tok!"with")) - { - if (indents.length == 0 || !indents.topIsOneOf(tok!"switch", tok!"with")) - indents.push(tok!"with"); - writeToken(); - if (config.dfmt_space_after_keywords) { - write(" "); - } - if (hasCurrent && currentIs(tok!"(")) - writeParens(false); - if (hasCurrent && !currentIs(tok!"switch") && !currentIs(tok!"with") - && !currentIs(tok!"{") && !(currentIs(tok!"final") && peekIs(tok!"switch"))) - { - newline(); - } - else if (hasCurrent && !currentIs(tok!"{")) - { - write(" "); - } - } - else if (currentIs(tok!"switch")) - { - formatSwitch(); - } - else if (currentIs(tok!"extern") && peekIs(tok!"(")) - { - writeToken(); - write(" "); - while (hasCurrent) - { - if (currentIs(tok!"(")) - formatLeftParenOrBracket(); - else if (currentIs(tok!")")) - { - formatRightParen(); - break; - } - else - writeToken(); - } - } - else if (((isBlockHeader() || currentIs(tok!"version")) && peekIs(tok!"(")) - || (currentIs(tok!"debug") && peekIs(tok!"{"))) - { - if (!assumeSorted(astInformation.constraintLocations).equalRange(current.index).empty) - formatConstraint(); - else - formatBlockHeader(); - } - else if ((current.text == "body" || current == tok!"do") && peekBackIsFunctionDeclarationEnding()) - { - formatKeyword(); - } - else if (currentIs(tok!"do")) - { - formatBlockHeader(); - } - else if (currentIs(tok!"else")) - { - formatElse(); - } - else if (currentIs(tok!"asm")) - { - formatKeyword(); - while (hasCurrent && !currentIs(tok!"{")) - formatStep(); - if (hasCurrent) - { - int depth = 1; - formatStep(); - inAsm = true; - while (hasCurrent && depth > 0) - { - if (currentIs(tok!"{")) - ++depth; - else if (currentIs(tok!"}")) - --depth; - formatStep(); - } - inAsm = false; - } - } - else if (currentIs(tok!"this")) - { - const thisIndex = current.index; - formatKeyword(); - if (config.dfmt_space_before_function_parameters - && (thisSpace || astInformation.constructorDestructorLocations - .canFindIndex(thisIndex))) - { - write(" "); - thisSpace = false; - } - } - else if (isKeyword(current.type)) - { - if (currentIs(tok!"debug")) - inlineElse = true; - formatKeyword(); - } - else if (isBasicType(current.type)) - { - writeToken(); - if (hasCurrent && (currentIs(tok!"identifier") || isKeyword(current.type) || inAsm)) - write(" "); - } - else if (isOperator(current.type)) - { - formatOperator(); - } - else if (currentIs(tok!"identifier")) - { - writeToken(); - //dfmt off - if (hasCurrent && ( currentIs(tok!"identifier") - || ( index > 1 && config.dfmt_space_before_function_parameters - && ( isBasicType(peekBack(2).type) - || peekBack2Is(tok!"identifier") - || peekBack2Is(tok!")") - || peekBack2Is(tok!"]") ) - && currentIs(tok!("(") ) - || isBasicType(current.type) || currentIs(tok!"@") - || isNumberLiteral(tokens[index].type) - || (inAsm && peekBack2Is(tok!";") && currentIs(tok!"[")) - ))) - //dfmt on - { - write(" "); - } - } - else if (currentIs(tok!"scriptLine") || currentIs(tok!"specialTokenSequence")) - { - writeToken(); - newline(); - } - else - writeToken(); + /* import std.range : assumeSorted; */ + + /* assert(hasCurrent); */ + /* if (currentIs(TOK.comment)) */ + /* { */ + /* formatComment(); */ + /* } */ + /* else if (isStringLiteral(current.value) */ + /* || isNumberLiteral(current.value) || currentIs(TOK.charLiteral)) */ + /* { */ + /* writeToken(); */ + /* if (hasCurrent) */ + /* { */ + /* immutable t = tokens[index].value; */ + /* if (t == TOK.identifier || isStringLiteral(t) */ + /* || isNumberLiteral(t) || t == TOK.charLiteral // a!"b" function() */ + /* || t == TOK.function_ || t == TOK.delegate_) */ + /* write(" "); */ + /* } */ + /* } */ + /* else if (currentIs(TOK.module_) || currentIs(TOK.import_)) */ + /* { */ + /* formatModuleOrImport(); */ + /* } */ + /* else if (currentIs(TOK.return_)) */ + /* { */ + /* writeToken(); */ + /* if (hasCurrent && (!currentIs(TOK.semicolon) && !currentIs(TOK.rightParenthesis) && !currentIs( */ + /* TOK.leftCurly) */ + /* && !currentIs(TOK.in_) && !currentIs(TOK.out_) && !currentIs(TOK.do_) */ + /* && tokens[index].text != "body")) */ + /* write(" "); */ + /* } */ + /* else if (currentIs(TOK.with_)) */ + /* { */ + /* if (indents.length == 0 || !indents.topIsOneOf(TOK.switch_, TOK.with_)) */ + /* indents.push(TOK.with_); */ + /* writeToken(); */ + /* if (config.dfmt_space_after_keywords) */ + /* { */ + /* write(" "); */ + /* } */ + /* if (hasCurrent && currentIs(TOK.leftParenthesis)) */ + /* writeParens(false); */ + /* if (hasCurrent && !currentIs(TOK.switch_) && !currentIs(TOK.with_) */ + /* && !currentIs(TOK.leftCurly) && !(currentIs(TOK.final_) && peekIs(TOK.switch_))) */ + /* { */ + /* newline(); */ + /* } */ + /* else if (hasCurrent && !currentIs(TOK.leftCurly)) */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + /* else if (currentIs(TOK.switch_)) */ + /* { */ + /* formatSwitch(); */ + /* } */ + /* else if (currentIs(TOK.extern_) && peekIs(TOK.leftParenthesis)) */ + /* { */ + /* writeToken(); */ + /* write(" "); */ + /* while (hasCurrent) */ + /* { */ + /* if (currentIs(TOK.leftParenthesis)) */ + /* formatLeftParenOrBracket(); */ + /* else if (currentIs(TOK.rightParenthesis)) */ + /* { */ + /* formatRightParen(); */ + /* break; */ + /* } */ + /* else */ + /* writeToken(); */ + /* } */ + /* } */ + /* else if (((isBlockHeader() || currentIs(TOK.version_)) && peekIs(TOK.leftParenthesis)) */ + /* || (currentIs(TOK.debug_) && peekIs(TOK.leftCurly))) */ + /* { */ + /* if (!assumeSorted(astInformation.constraintLocations).equalRange(current.index).empty) */ + /* formatConstraint(); */ + /* else */ + /* formatBlockHeader(); */ + /* } */ + /* else if ((current.text == "body" || current == TOK.do_) && peekBackIsFunctionDeclarationEnding()) */ + /* { */ + /* formatKeyword(); */ + /* } */ + /* else if (currentIs(TOK.do_)) */ + /* { */ + /* formatBlockHeader(); */ + /* } */ + /* else if (currentIs(TOK.else_)) */ + /* { */ + /* formatElse(); */ + /* } */ + /* else if (currentIs(TOK.asm_)) */ + /* { */ + /* formatKeyword(); */ + /* while (hasCurrent && !currentIs(TOK.leftCurly)) */ + /* formatStep(); */ + /* if (hasCurrent) */ + /* { */ + /* int depth = 1; */ + /* formatStep(); */ + /* inAsm = true; */ + /* while (hasCurrent && depth > 0) */ + /* { */ + /* if (currentIs(TOK.leftCurly)) */ + /* ++depth; */ + /* else if (currentIs(TOK.rightCurly)) */ + /* --depth; */ + /* formatStep(); */ + /* } */ + /* inAsm = false; */ + /* } */ + /* } */ + /* else if (currentIs(TOK.this_)) */ + /* { */ + /* const thisIndex = current.index; */ + /* formatKeyword(); */ + /* if (config.dfmt_space_before_function_parameters */ + /* && (thisSpace || astInformation.constructorDestructorLocations */ + /* .canFindIndex(thisIndex))) */ + /* { */ + /* write(" "); */ + /* thisSpace = false; */ + /* } */ + /* } */ + /* else if (isKeyword(current.value)) */ + /* { */ + /* if (currentIs(TOK.debug_)) */ + /* inlineElse = true; */ + /* formatKeyword(); */ + /* } */ + /* else if (isBasicType(current.value)) */ + /* { */ + /* writeToken(); */ + /* if (hasCurrent && (currentIs(TOK.identifier) || isKeyword(current.value) || inAsm)) */ + /* write(" "); */ + /* } */ + /* else if (isOperator(current.value)) */ + /* { */ + /* formatOperator(); */ + /* } */ + /* else if (currentIs(TOK.identifier)) */ + /* { */ + /* writeToken(); */ + /* //dfmt off */ + /* if (hasCurrent && ( currentIs(TOK.identifier) */ + /* || ( index > 1 && config.dfmt_space_before_function_parameters */ + /* && ( isBasicType(peekBack(2).value) */ + /* || peekBack2Is(TOK.identifier) */ + /* || peekBack2Is(TOK.rightParenthesis) */ + /* || peekBack2Is(TOK.rightBracket) ) */ + /* && currentIs(TOK.leftParenthesis) */ + /* || isBasicType(current.value) || currentIs(TOK.at) */ + /* || isNumberLiteral(tokens[index].value) */ + /* || (inAsm && peekBack2Is(TOK.semicolon) && currentIs(TOK.leftBracket)) */ + /* ))) */ + /* //dfmt on */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + /* else if (currentIs(TOK.line)) */ + /* { */ + /* writeToken(); */ + /* newline(); */ + /* } */ + /* else */ + /* writeToken(); */ } - void formatConstraint() - { - import dfmt.editorconfig : OB = OptionalBoolean; - with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style) - { - case _unspecified: - assert(false, "Config was not validated properly"); - case conditional_newline: - immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); - if (l > config.dfmt_soft_max_line_length) - newline(); - else if (peekBackIs(tok!")") || peekBackIs(tok!"identifier")) - write(" "); - break; - case always_newline: - newline(); - break; - case conditional_newline_indent: - immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); - if (l > config.dfmt_soft_max_line_length) - { - config.dfmt_single_template_constraint_indent == OB.t ? - pushWrapIndent() : pushWrapIndent(tok!"!"); - newline(); - } - else if (peekBackIs(tok!")") || peekBackIs(tok!"identifier")) - write(" "); - break; - case always_newline_indent: - { - config.dfmt_single_template_constraint_indent == OB.t ? - pushWrapIndent() : pushWrapIndent(tok!"!"); - newline(); - } - break; - } - // if - writeToken(); - // assume that the parens are present, otherwise the parser would not - // have told us there was a constraint here - write(" "); - writeParens(false); - } - - string commentText(size_t i) - { - import std.string : strip; - - assert(tokens[i].type == tok!"comment"); - string commentText = tokens[i].text; - if (commentText[0 .. 2] == "//") - commentText = commentText[2 .. $]; - else - { - if (commentText.length > 3) - commentText = commentText[2 .. $ - 2]; - else - commentText = commentText[2 .. $]; - } - return commentText.strip(); - } - - void skipFormatting() - { - size_t dfmtOff = index; - size_t dfmtOn = index; - foreach (i; dfmtOff + 1 .. tokens.length) - { - dfmtOn = i; - if (tokens[i].type != tok!"comment") - continue; - immutable string commentText = commentText(i); - if (commentText == "dfmt on") - break; - } - write(cast(string) rawSource[tokens[dfmtOff].index .. tokens[dfmtOn].index]); - index = dfmtOn; - } - - void formatComment() - { - if (commentText(index) == "dfmt off") - { - skipFormatting(); - return; - } - - immutable bool currIsSlashSlash = tokens[index].text[0 .. 2] == "//"; - immutable prevTokenEndLine = index == 0 ? size_t.max : tokenEndLine(tokens[index - 1]); - immutable size_t currTokenLine = tokens[index].line; - if (index > 0) - { - immutable t = tokens[index - 1].type; - immutable canAddNewline = currTokenLine - prevTokenEndLine < 1; - if (peekBackIsOperator() && !isSeparationToken(t)) - pushWrapIndent(t); - else if (peekBackIs(tok!",") && prevTokenEndLine == currTokenLine - && indents.indentToMostRecent(tok!"enum") == -1) - pushWrapIndent(tok!","); - if (peekBackIsOperator() && !peekBackIsOneOf(false, tok!"comment", - tok!"{", tok!"}", tok!":", tok!";", tok!",", tok!"[", tok!"(") - && !canAddNewline && prevTokenEndLine < currTokenLine) - write(" "); - else if (prevTokenEndLine == currTokenLine || (t == tok!")" && peekIs(tok!"{"))) - write(" "); - else if (peekBackIsOneOf(false, tok!"else", tok!"identifier")) - write(" "); - else if (canAddNewline || (peekIs(tok!"{") && t == tok!"}")) - newline(); - - if (peekIs(tok!"(") && (peekBackIs(tok!")") || peekBack2Is(tok!"!"))) - pushWrapIndent(tok!"("); - - if (peekIs(tok!".") && !indents.topIs(tok!".")) - indents.push(tok!"."); - } - writeToken(); - immutable j = justAddedExtraNewline; - if (currIsSlashSlash) - { - newline(); - justAddedExtraNewline = j; - } - else if (hasCurrent) - { - if (prevTokenEndLine == tokens[index].line) - { - if (currentIs(tok!"}")) - { - if (indents.topIs(tok!"{")) - indents.pop(); - write(" "); - } - else if (!currentIs(tok!"{")) - write(" "); - } - else if (!currentIs(tok!"{") && !currentIs(tok!"in") && !currentIs(tok!"out")) - { - if (currentIs(tok!")") && indents.topIs(tok!",")) - indents.pop(); - else if (peekBack2Is(tok!",") && !indents.topIs(tok!",") - && indents.indentToMostRecent(tok!"enum") == -1) - pushWrapIndent(tok!","); - newline(); - } - } - else - newline(); - } - - void formatModuleOrImport() - { - immutable t = current.type; - writeToken(); - if (currentIs(tok!"(")) - { - writeParens(false); - return; - } - write(" "); - while (hasCurrent) - { - if (currentIs(tok!";")) - { - indents.popWrapIndents(); - indentLevel = indents.indentLevel; - writeToken(); - if (index >= tokens.length) - { - newline(); - break; - } - if (currentIs(tok!"comment") && current.line == peekBack().line) - { - break; - } - else if (currentIs(tok!"{") && config.dfmt_brace_style == BraceStyle.allman) - break; - else if (t == tok!"import" && !currentIs(tok!"import") - && !currentIs(tok!"}") - && !((currentIs(tok!"public") - || currentIs(tok!"private") - || currentIs(tok!"static")) - && peekIs(tok!"import")) && !indents.topIsOneOf(tok!"if", - tok!"debug", tok!"version")) - { - simpleNewline(); - currentLineLength = 0; - justAddedExtraNewline = true; - newline(); - } - else - newline(); - break; - } - else if (currentIs(tok!":")) - { - if (config.dfmt_selective_import_space) - write(" "); - writeToken(); - if (!currentIs(tok!"comment")) - write(" "); - pushWrapIndent(tok!","); - } - else if (currentIs(tok!"comment")) - { - if (peekBack.line != current.line) - { - // The comment appears on its own line, keep it there. - if (!peekBackIs(tok!"comment")) - // Comments are already properly separated. - newline(); - } - formatStep(); - } - else - formatStep(); - } - } - - void formatLeftParenOrBracket() - in - { - assert(currentIs(tok!"(") || currentIs(tok!"[")); - } - do - { - import dfmt.editorconfig : OptionalBoolean; - - immutable p = current.type; - regenLineBreakHintsIfNecessary(index); - writeToken(); - if (p == tok!"(") - { - ++parenDepthOnLine; - // If the file starts with an open paren, just give up. This isn't - // valid D code. - if (index < 2) - return; - if (isBlockHeaderToken(tokens[index - 2].type)) - indents.push(tok!")"); - else - indents.push(p); - spaceAfterParens = true; - parenDepth++; - } - // No heuristics apply if we can't look before the opening paren/bracket - if (index < 1) - return; - immutable bool arrayInitializerStart = p == tok!"[" - && astInformation.arrayStartLocations.canFindIndex(tokens[index - 1].index); - - if (arrayInitializerStart && isMultilineAt(index - 1)) - { - revertParenIndentation(); - - // Use the close bracket as the indent token to distinguish - // the array initialiazer from an array index in the newline - // handling code - IndentStack.Details detail; - detail.wrap = false; - detail.temp = false; - - // wrap and temp are set manually to the values it would actually - // receive here because we want to set breakEveryItem for the ] token to know if - // we should definitely always new-line after every comma for a big AA - detail.breakEveryItem = astInformation.assocArrayStartLocations.canFindIndex( - tokens[index - 1].index); - detail.preferLongBreaking = true; - - indents.push(tok!"]", detail); - newline(); - immutable size_t j = expressionEndIndex(index); - linebreakHints = chooseLineBreakTokens(index, tokens[index .. j], - depths[index .. j], config, currentLineLength, indentLevel); - } - else if (p == tok!"[" && config.dfmt_keep_line_breaks == OptionalBoolean.t) - { - revertParenIndentation(); - IndentStack.Details detail; - - detail.wrap = false; - detail.temp = false; - detail.breakEveryItem = false; - detail.mini = tokens[index].line == tokens[index - 1].line; - - indents.push(tok!"]", detail); - if (!detail.mini) - { - newline(); - } - } - else if (arrayInitializerStart) - { - // This is a short (non-breaking) array/AA value - IndentStack.Details detail; - detail.wrap = false; - detail.temp = false; - - detail.breakEveryItem = astInformation.assocArrayStartLocations.canFindIndex(tokens[index - 1].index); - // array of (possibly associative) array, let's put each item on its own line - if (!detail.breakEveryItem && currentIs(tok!"[")) - detail.breakEveryItem = true; - - // the '[' is immediately followed by an item instead of a newline here so - // we set mini, that the ']' also follows an item immediately without newline. - detail.mini = true; - - indents.push(tok!"]", detail); - } - else if (p == tok!"[") - { - // array item access - IndentStack.Details detail; - detail.wrap = false; - detail.temp = true; - detail.mini = true; - indents.push(tok!"]", detail); - } - else if (!currentIs(tok!")") && !currentIs(tok!"]") - && (linebreakHints.canFindIndex(index - 1) || (linebreakHints.length == 0 - && currentLineLength > config.max_line_length))) - { - newline(); - } - else if (onNextLine) - { - newline(); - } - } - - void revertParenIndentation() - { - import std.algorithm.searching : canFind, until; - - if (tokens[index .. $].until!(tok => tok.line != current.line).canFind!(x => x.type == tok!"]")) - { - return; - } - if (parenDepthOnLine) - { - foreach (i; 0 .. parenDepthOnLine) - { - indents.pop(); - } - } - parenDepthOnLine = 0; - } - - void formatRightParen() - in - { - assert(currentIs(tok!")")); - } - do - { - parenDepthOnLine = max(parenDepthOnLine - 1, 0); - parenDepth--; - indents.popWrapIndents(); - while (indents.topIsOneOf(tok!"!", tok!")")) - indents.pop(); - if (indents.topIs(tok!"(")) - indents.pop(); - if (indents.topIs(tok!".")) - indents.pop(); - - if (onNextLine) - { - newline(); - } - if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in") - || peekIs(tok!"out") || peekIs(tok!"do") || peekIsBody)) - { - writeToken(); - } - else if (peekIsLiteralOrIdent() || peekIsBasicType()) - { - writeToken(); - if (spaceAfterParens || parenDepth > 0) - writeSpace(); - } - else if ((peekIsKeyword() || peekIs(tok!"@")) && spaceAfterParens - && !peekIs(tok!"in") && !peekIs(tok!"is") && !peekIs(tok!"if")) - { - writeToken(); - writeSpace(); - } - else - writeToken(); - } - - void formatRightBracket() - in - { - assert(currentIs(tok!"]")); - } - do - { - indents.popWrapIndents(); - if (indents.topIs(tok!"]")) - { - if (!indents.topDetails.mini && !indents.topDetails.temp) - newline(); - else - indents.pop(); - } - writeToken(); - if (currentIs(tok!"identifier")) - write(" "); - } - - void formatAt() - { - immutable size_t atIndex = tokens[index].index; - writeToken(); - if (currentIs(tok!"identifier")) - writeToken(); - if (currentIs(tok!"(")) - { - writeParens(false); - if (tokens[index].type == tok!"{") - return; - - if (hasCurrent && tokens[index - 1].line < tokens[index].line - && astInformation.atAttributeStartLocations.canFindIndex(atIndex)) - newline(); - else - write(" "); - } - else if (hasCurrent && (currentIs(tok!"@") - || isBasicType(tokens[index].type) - || currentIs(tok!"invariant") - || currentIs(tok!"extern") - || currentIs(tok!"identifier")) - && !currentIsIndentedTemplateConstraint()) - { - writeSpace(); - } - } - - void formatColon() - { - import dfmt.editorconfig : OptionalBoolean; - import std.algorithm : canFind, any; - immutable bool isCase = astInformation.caseEndLocations.canFindIndex(current.index); - immutable bool isAttribute = astInformation.attributeDeclarationLines.canFindIndex( - current.line); - immutable bool isStructInitializer = astInformation.structInfoSortedByEndLocation - .canFind!(st => st.startLocation < current.index && current.index < st.endLocation); - immutable bool isTernary = astInformation.ternaryColonLocations.canFindIndex(current.index); - immutable bool isNamedArg = astInformation.namedArgumentColonLocations.canFindIndex(current.index); - - if (isCase || isAttribute) - { - writeToken(); - if (!currentIs(tok!"{")) - { - if (isCase && !indents.topIs(tok!"case") - && config.dfmt_align_switch_statements == OptionalBoolean.f) - indents.push(tok!"case"); - else if (isAttribute && !indents.topIs(tok!"@") - && config.dfmt_outdent_attributes == OptionalBoolean.f) - indents.push(tok!"@"); - newline(); - } - } - else if (indents.topIs(tok!"]") && !isTernary) // Associative array - { - write(config.dfmt_space_before_aa_colon ? " : " : ": "); - ++index; - } - // Named function or struct constructor arguments. - else if (isNamedArg) - { - write(config.dfmt_space_before_named_arg_colon ? " : " : ": "); - ++index; - } - else if (peekBackIs(tok!"identifier") - && [tok!"{", tok!"}", tok!";", tok!":", tok!","] - .any!((ptrdiff_t token) => peekBack2Is(cast(IdType)token, true)) - && (!isBlockHeader(1) || peekIs(tok!"if"))) - { - writeToken(); - if (isStructInitializer) - write(" "); - else if (!currentIs(tok!"{")) - newline(); - } - else - { - regenLineBreakHintsIfNecessary(index); - if (peekIs(tok!"..")) - writeToken(); - else if (isBlockHeader(1) && !peekIs(tok!"if")) - { - writeToken(); - if (config.dfmt_compact_labeled_statements) - write(" "); - else - newline(); - } - else if (linebreakHints.canFindIndex(index)) - { - pushWrapIndent(); - newline(); - writeToken(); - write(" "); - } - else - { - write(" : "); - index++; - } - } - } - - void formatSemicolon() - { - if (inlineElse && !peekIs(tok!"else")) - inlineElse = false; - - if ((parenDepth > 0 && sBraceDepth == 0) || (sBraceDepth > 0 && niBraceDepth > 0)) - { - if (currentLineLength > config.dfmt_soft_max_line_length) - { - writeToken(); - pushWrapIndent(tok!";"); - newline(); - } - else - { - if (!(peekIs(tok!";") || peekIs(tok!")") || peekIs(tok!"}"))) - write("; "); - else - write(";"); - index++; - } - } - else - { - writeToken(); - indents.popWrapIndents(); - linebreakHints = []; - while (indents.topIsOneOf(tok!"enum", tok!"try", tok!"catch", tok!"finally", tok!"debug")) - indents.pop(); - if (indents.topAre(tok!"static", tok!"else")) - { - indents.pop(); - indents.pop(); - } - indentLevel = indents.indentLevel; - if (config.dfmt_brace_style == BraceStyle.allman) - { - if (!currentIs(tok!"{")) - newline(); - } - else - { - if (currentIs(tok!"{")) - indents.popTempIndents(); - indentLevel = indents.indentLevel; - newline(); - } - } - } - - void formatLeftBrace() - { - import std.algorithm : map, sum, canFind; - - auto tIndex = tokens[index].index; - - if (astInformation.structInitStartLocations.canFindIndex(tIndex)) - { - sBraceDepth++; - immutable bool multiline = isMultilineAt(index); - writeToken(); - if (multiline) - { - import std.algorithm.searching : find; - - auto indentInfo = astInformation.indentInfoSortedByEndLocation - .find!((a,b) => a.startLocation == b)(tIndex); - assert(indentInfo.length > 0); - cast()indentInfo[0].flags |= BraceIndentInfoFlags.tempIndent; - cast()indentInfo[0].beginIndentLevel = indents.indentLevel; - - indents.push(tok!"{"); - newline(); - } - else - niBraceDepth++; - } - else if (astInformation.funLitStartLocations.canFindIndex(tIndex)) - { - indents.popWrapIndents(); - - sBraceDepth++; - if (peekBackIsOneOf(true, tok!")", tok!"identifier")) - write(" "); - immutable bool multiline = isMultilineAt(index); - writeToken(); - if (multiline) - { - indents.push(tok!"{"); - newline(); - } - else - { - niBraceDepth++; - if (!currentIs(tok!"}")) - write(" "); - } - } - else - { - if (peekBackIsSlashSlash()) - { - if (peekBack2Is(tok!";")) - { - indents.popTempIndents(); - indentLevel = indents.indentLevel - 1; - } - writeToken(); - } - else - { - if (indents.topIsTemp && indents.indentToMostRecent(tok!"static") == -1) - indentLevel = indents.indentLevel - 1; - else - indentLevel = indents.indentLevel; - if (config.dfmt_brace_style == BraceStyle.allman - || peekBackIsOneOf(true, tok!"{", tok!"}")) - newline(); - else if (config.dfmt_brace_style == BraceStyle.knr - && astInformation.funBodyLocations.canFindIndex(tIndex) - && (peekBackIs(tok!")") || (!peekBackIs(tok!"do") && peekBack().text != "body"))) - newline(); - else if (!peekBackIsOneOf(true, tok!"{", tok!"}", tok!";")) - write(" "); - writeToken(); - } - indents.push(tok!"{"); - if (!currentIs(tok!"{")) - newline(); - linebreakHints = []; - } - } - - void formatRightBrace() - { - void popToBeginIndent(BraceIndentInfo indentInfo) - { - foreach(i; indentInfo.beginIndentLevel .. indents.indentLevel) - { - indents.pop(); - } - - indentLevel = indentInfo.beginIndentLevel; - } - - size_t pos; - if (astInformation.structInitEndLocations.canFindIndex(tokens[index].index, &pos)) - { - if (sBraceDepth > 0) - sBraceDepth--; - if (niBraceDepth > 0) - niBraceDepth--; - - // Account for possible function literals in this array which offset - // the previously set index (pos). Fixes issue #432. - size_t newPos = pos; - while(astInformation.indentInfoSortedByEndLocation[newPos].endLocation < - tokens[index].index) - { - newPos++; - } - - if (astInformation.indentInfoSortedByEndLocation[newPos].endLocation == - tokens[index].index) - { - pos = newPos; - } - - auto indentInfo = astInformation.indentInfoSortedByEndLocation[pos]; - if (indentInfo.flags & BraceIndentInfoFlags.tempIndent) - { - popToBeginIndent(indentInfo); - simpleNewline(); - indent(); - } - writeToken(); - } - else if (astInformation.funLitEndLocations.canFindIndex(tokens[index].index, &pos)) - { - if (niBraceDepth > 0) - { - if (!peekBackIsSlashSlash() && !peekBackIs(tok!"{")) - write(" "); - niBraceDepth--; - } - if (sBraceDepth > 0) - sBraceDepth--; - writeToken(); - } - else - { - // Silly hack to format enums better. - if ((peekBackIsLiteralOrIdent() || peekBackIsOneOf(true, tok!")", - tok!",")) && !peekBackIsSlashSlash()) - newline(); - write("}"); - if (index + 1 < tokens.length - && astInformation.doubleNewlineLocations.canFindIndex(tokens[index].index) - && !peekIs(tok!"}") && !peekIs(tok!"else") - && !peekIs(tok!";") && !peekIs(tok!"comment", false)) - { - simpleNewline(); - currentLineLength = 0; - justAddedExtraNewline = true; - } - if (config.dfmt_brace_style.among(BraceStyle.otbs, BraceStyle.knr) - && ((peekIs(tok!"else") - && !indents.topAre(tok!"static", tok!"if") - && !indents.topIs(tok!"foreach") && !indents.topIs(tok!"for") - && !indents.topIs(tok!"while") && !indents.topIs(tok!"do")) - || peekIs(tok!"catch") || peekIs(tok!"finally"))) - { - write(" "); - index++; - } - else - { - if (!peekIs(tok!",") && !peekIs(tok!")") - && !peekIs(tok!";") && !peekIs(tok!"{")) - { - index++; - if (indents.topIs(tok!"static")) - indents.pop(); - newline(); - } - else - index++; - } - } - } - - void formatSwitch() - { - while (indents.topIs(tok!"with")) - indents.pop(); - indents.push(tok!"switch"); - writeToken(); // switch - if (config.dfmt_space_after_keywords) - { - write(" "); - } - } - - void formatBlockHeader() - { - if (indents.topIs(tok!"!")) - indents.pop(); - immutable bool a = !currentIs(tok!"version") && !currentIs(tok!"debug"); - immutable bool b = a - || astInformation.conditionalWithElseLocations.canFindIndex(current.index); - immutable bool c = b - || astInformation.conditionalStatementLocations.canFindIndex(current.index); - immutable bool shouldPushIndent = (c || peekBackIs(tok!"else")) - && !(currentIs(tok!"if") && indents.topIsWrap()); - if (currentIs(tok!"out") && !peekBackIs(tok!"}")) - newline(); - if (shouldPushIndent) - { - if (peekBackIs(tok!"static")) - { - if (indents.topIs(tok!"else")) - indents.pop(); - if (!indents.topIs(tok!"static")) - indents.push(tok!"static"); - } - indents.push(current.type); - } - writeToken(); - - if (currentIs(tok!"(")) - { - if (config.dfmt_space_after_keywords) - { - write(" "); - } - writeParens(false); - } - - if (hasCurrent) - { - if (currentIs(tok!"switch") || (currentIs(tok!"final") && peekIs(tok!"switch"))) - { - if (config.dfmt_space_after_keywords) - { - write(" "); - } - } - else if (currentIs(tok!"comment")) - { - formatStep(); - } - else if (!shouldPushIndent) - { - if (!currentIs(tok!"{") && !currentIs(tok!";")) - write(" "); - } - else if (hasCurrent && !currentIs(tok!"{") && !currentIs(tok!";") && !currentIs(tok!"in") && - !currentIs(tok!"out") && !currentIs(tok!"do") && current.text != "body") - { - newline(); - } - else if (currentIs(tok!"{") && indents.topAre(tok!"static", tok!"if")) - { - // Hacks to format braced vs non-braced static if declarations. - indents.pop(); - indents.pop(); - indents.push(tok!"if"); - formatLeftBrace(); - } - else if (currentIs(tok!"{") && indents.topAre(tok!"static", tok!"foreach")) - { - indents.pop(); - indents.pop(); - indents.push(tok!"foreach"); - formatLeftBrace(); - } - else if (currentIs(tok!"{") && indents.topAre(tok!"static", tok!"foreach_reverse")) - { - indents.pop(); - indents.pop(); - indents.push(tok!"foreach_reverse"); - formatLeftBrace(); - } - } - } - - void formatElse() - { - writeToken(); - if (inlineElse || currentIs(tok!"if") || currentIs(tok!"version") - || (currentIs(tok!"static") && peekIs(tok!"if"))) - { - if (indents.topIs(tok!"if") || indents.topIs(tok!"version")) - indents.pop(); - inlineElse = false; - write(" "); - } - else if (currentIs(tok!":")) - { - writeToken(); - newline(); - } - else if (!currentIs(tok!"{") && !currentIs(tok!"comment")) - { - //indents.dump(); - while (indents.topIsOneOf(tok!"foreach", tok!"for", tok!"while")) - indents.pop(); - if (indents.topIsOneOf(tok!"if", tok!"version")) - indents.pop(); - indents.push(tok!"else"); - newline(); - } - else if (currentIs(tok!"{") && indents.topAre(tok!"static", tok!"if")) - { - indents.pop(); - indents.pop(); - indents.push(tok!"else"); - } - } - - void formatKeyword() - { - import dfmt.editorconfig : OptionalBoolean; - - switch (current.type) - { - case tok!"default": - writeToken(); - break; - case tok!"cast": - writeToken(); - if (hasCurrent && currentIs(tok!"(")) - writeParens(config.dfmt_space_after_cast == OptionalBoolean.t); - break; - case tok!"out": - if (!peekBackIsSlashSlash) { - if (!peekBackIs(tok!"}") - && astInformation.contractLocations.canFindIndex(current.index)) - newline(); - else if (peekBackIsKeyword) - write(" "); - } - writeToken(); - if (hasCurrent && !currentIs(tok!"{") && !currentIs(tok!"comment")) - write(" "); - break; - case tok!"try": - case tok!"finally": - indents.push(current.type); - writeToken(); - if (hasCurrent && !currentIs(tok!"{")) - newline(); - break; - case tok!"identifier": - if (current.text == "body") - goto case tok!"do"; - else - goto default; - case tok!"do": - if (!peekBackIs(tok!"}")) - newline(); - writeToken(); - break; - case tok!"in": - immutable isContract = astInformation.contractLocations.canFindIndex(current.index); - if (!peekBackIsSlashSlash) { - if (isContract) - { - indents.popTempIndents(); - newline(); - } - else if (!peekBackIsOneOf(false, tok!"(", tok!",", tok!"!")) - write(" "); - } - writeToken(); - if (!hasCurrent) - return; - immutable isFunctionLit = astInformation.funLitStartLocations.canFindIndex( - current.index); - if (isFunctionLit && config.dfmt_brace_style == BraceStyle.allman) - newline(); - else if (!isContract || currentIs(tok!"(")) - write(" "); - break; - case tok!"is": - if (!peekBackIsOneOf(false, tok!"!", tok!"(", tok!",", - tok!"}", tok!"=", tok!"&&", tok!"||") && !peekBackIsKeyword()) - write(" "); - writeToken(); - if (hasCurrent && !currentIs(tok!"(") && !currentIs(tok!"{") && !currentIs(tok!"comment")) - write(" "); - break; - case tok!"case": - writeToken(); - if (hasCurrent && !currentIs(tok!";")) - write(" "); - break; - case tok!"enum": - if (peekIs(tok!")") || peekIs(tok!"==")) - { - writeToken(); - } - else - { - if (peekBackIs(tok!"identifier")) - write(" "); - indents.push(tok!"enum"); - writeToken(); - if (hasCurrent && !currentIs(tok!":") && !currentIs(tok!"{")) - write(" "); - } - break; - case tok!"static": - { - if (astInformation.staticConstructorDestructorLocations - .canFindIndex(current.index)) - { - thisSpace = true; - } - } - goto default; - case tok!"shared": - { - if (astInformation.sharedStaticConstructorDestructorLocations - .canFindIndex(current.index)) - { - thisSpace = true; - } - } - goto default; - case tok!"invariant": - writeToken(); - if (hasCurrent && currentIs(tok!"(")) - write(" "); - break; - default: - if (peekBackIs(tok!"identifier")) - { - writeSpace(); - } - if (index + 1 < tokens.length) - { - if (!peekIs(tok!"@") && (peekIsOperator() - || peekIs(tok!"out") || peekIs(tok!"in"))) - { - writeToken(); - } - else - { - writeToken(); - if (!currentIsIndentedTemplateConstraint()) - { - writeSpace(); - } - } - } - else - writeToken(); - break; - } - } - - bool currentIsIndentedTemplateConstraint() - { - return hasCurrent - && astInformation.constraintLocations.canFindIndex(current.index) - && (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline - || config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent - || currentLineLength >= config.dfmt_soft_max_line_length); - } - - void formatOperator() - { - import dfmt.editorconfig : OptionalBoolean; - import std.algorithm : canFind; - - switch (current.type) - { - case tok!"*": - if (astInformation.spaceAfterLocations.canFindIndex(current.index)) - { - writeToken(); - if (!currentIs(tok!"*") && !currentIs(tok!")") - && !currentIs(tok!"[") && !currentIs(tok!",") && !currentIs(tok!";")) - { - write(" "); - } - break; - } - else if (astInformation.unaryLocations.canFindIndex(current.index)) - { - writeToken(); - break; - } - regenLineBreakHintsIfNecessary(index); - goto binary; - case tok!"~": - if (peekIs(tok!"this") && peek2Is(tok!"(")) - { - if (!(index == 0 || peekBackIs(tok!"{", true) - || peekBackIs(tok!"}", true) || peekBackIs(tok!";", true))) - { - write(" "); - } - writeToken(); - break; - } - goto case; - case tok!"&": - case tok!"+": - case tok!"-": - if (astInformation.unaryLocations.canFindIndex(current.index)) - { - writeToken(); - break; - } - regenLineBreakHintsIfNecessary(index); - goto binary; - case tok!"[": - case tok!"(": - formatLeftParenOrBracket(); - break; - case tok!")": - formatRightParen(); - break; - case tok!"@": - formatAt(); - break; - case tok!"!": - if (((peekIs(tok!"is") || peekIs(tok!"in")) - && !peekBackIsOperator()) || peekBackIs(tok!")")) - write(" "); - goto case; - case tok!"...": - case tok!"++": - case tok!"--": - case tok!"$": - writeToken(); - break; - case tok!":": - formatColon(); - break; - case tok!"]": - formatRightBracket(); - break; - case tok!";": - formatSemicolon(); - break; - case tok!"{": - formatLeftBrace(); - break; - case tok!"}": - formatRightBrace(); - break; - case tok!".": - regenLineBreakHintsIfNecessary(index); - immutable bool ufcsWrap = config.dfmt_reflow_property_chains == OptionalBoolean.t - && astInformation.ufcsHintLocations.canFindIndex(current.index); - if (ufcsWrap || linebreakHints.canFind(index) || onNextLine - || (linebreakHints.length == 0 && currentLineLength + nextTokenLength() > config.max_line_length)) - { - if (!indents.topIs(tok!".")) - indents.push(tok!"."); - if (!peekBackIs(tok!"comment")) - newline(); - if (ufcsWrap || onNextLine) - regenLineBreakHints(index); - } - writeToken(); - break; - case tok!",": - formatComma(); - break; - case tok!"&&": - case tok!"||": - case tok!"|": - regenLineBreakHintsIfNecessary(index); - goto case; - 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!"%": - binary: - immutable bool isWrapToken = linebreakHints.canFind(index); - if (config.dfmt_keep_line_breaks == OptionalBoolean.t && index > 0) - { - const operatorLine = tokens[index].line; - const rightOperandLine = tokens[index + 1].line; - - if (tokens[index - 1].line < operatorLine) - { - if (!indents.topIs(tok!"enum")) - pushWrapIndent(); - if (!peekBackIs(tok!"comment")) - newline(); - } - else - { - write(" "); - } - if (rightOperandLine > operatorLine - && !indents.topIs(tok!"enum")) - { - pushWrapIndent(); - } - writeToken(); - - if (rightOperandLine > operatorLine) - { - if (!peekBackIs(tok!"comment")) - newline(); - } - else - { - write(" "); - } - } - else if (config.dfmt_split_operator_at_line_end) - { - if (isWrapToken) - { - if (!indents.topIs(tok!"enum")) - pushWrapIndent(); - write(" "); - writeToken(); - newline(); - } - else - { - write(" "); - writeToken(); - if (!currentIs(tok!"comment")) - write(" "); - } - } - else - { - if (isWrapToken) - { - if (!indents.topIs(tok!"enum")) - pushWrapIndent(); - newline(); - writeToken(); - } - else - { - write(" "); - writeToken(); - } - if (!currentIs(tok!"comment")) - write(" "); - } - break; - default: - writeToken(); - break; - } - } - - void formatComma() - { - import dfmt.editorconfig : OptionalBoolean; - import std.algorithm : canFind; - - if (config.dfmt_keep_line_breaks == OptionalBoolean.f) - regenLineBreakHintsIfNecessary(index); - if (indents.indentToMostRecent(tok!"enum") != -1 - && !peekIs(tok!"}") && indents.topIs(tok!"{") && parenDepth == 0) - { - writeToken(); - newline(); - } - else if (indents.topIs(tok!"]") && indents.topDetails.breakEveryItem - && !indents.topDetails.mini) - { - writeToken(); - newline(); - regenLineBreakHints(index - 1); - } - else if (indents.topIs(tok!"]") && indents.topDetails.preferLongBreaking - && !currentIs(tok!")") && !currentIs(tok!"]") && !currentIs(tok!"}") - && !currentIs(tok!"comment") && index + 1 < tokens.length - && isMultilineAt(index + 1, true)) - { - writeToken(); - newline(); - regenLineBreakHints(index - 1); - } - else if (config.dfmt_keep_line_breaks == OptionalBoolean.t) - { - const commaLine = tokens[index].line; - - writeToken(); - if (indents.topIsWrap && !indents.topIs(tok!",")) - { - indents.pop; - } - if (!currentIs(tok!")") && !currentIs(tok!"]") - && !currentIs(tok!"}") && !currentIs(tok!"comment")) - { - if (tokens[index].line == commaLine) - { - write(" "); - } - else - { - newline(); - } - } - } - else if (!peekIs(tok!"}") && (linebreakHints.canFind(index) - || (linebreakHints.length == 0 && currentLineLength > config.max_line_length))) - { - pushWrapIndent(); - writeToken(); - if (indents.topIsWrap && !indents.topIs(tok!",")) - { - indents.pop; - } - newline(); - } - else - { - writeToken(); - if (!currentIs(tok!")") && !currentIs(tok!"]") - && !currentIs(tok!"}") && !currentIs(tok!"comment")) - { - write(" "); - } - } - regenLineBreakHintsIfNecessary(index - 1); - } - - void regenLineBreakHints(immutable size_t i) - { - import std.range : assumeSorted; - import std.algorithm.comparison : min; - import std.algorithm.searching : canFind, countUntil; - - // The end of the tokens considered by the line break algorithm is - // either the expression end index or the next mandatory line break - // or a newline inside a string literal, whichever is first. - auto r = assumeSorted(astInformation.ufcsHintLocations).upperBound(tokens[i].index); - immutable ufcsBreakLocation = r.empty - ? size_t.max - : tokens[i .. $].countUntil!(t => t.index == r.front) + i; - immutable multilineStringLocation = tokens[i .. $] - .countUntil!(t => t.text.canFind('\n')); - immutable size_t j = min( - expressionEndIndex(i), - ufcsBreakLocation, - multilineStringLocation == -1 ? size_t.max : multilineStringLocation + i + 1); - // Use magical negative value for array literals and wrap indents - immutable inLvl = (indents.topIsWrap() || indents.topIs(tok!"]")) ? -indentLevel - : indentLevel; - linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j], - config, currentLineLength, inLvl); - } - - void regenLineBreakHintsIfNecessary(immutable size_t i) - { - if (linebreakHints.length == 0 || linebreakHints[$ - 1] <= i - 1) - regenLineBreakHints(i); - } - - void simpleNewline() - { - import dfmt.editorconfig : EOL; - - output.put(eolString); - } - - void newline() - { - import std.range : assumeSorted; - import std.algorithm : max, canFind; - import dfmt.editorconfig : OptionalBoolean; - - if (currentIs(tok!"comment") && index > 0 && current.line == tokenEndLine(tokens[index - 1])) - return; - - immutable bool hasCurrent = this.hasCurrent; - - if (niBraceDepth > 0 && !peekBackIsSlashSlash() && hasCurrent && tokens[index].type == tok!"}" - && !assumeSorted(astInformation.funLitEndLocations).equalRange( - tokens[index].index).empty) - { - return; - } - - simpleNewline(); - - if (!justAddedExtraNewline && index > 0 && hasCurrent - && tokens[index].line - tokenEndLine(tokens[index - 1]) > 1) - { - simpleNewline(); - } - - justAddedExtraNewline = false; - currentLineLength = 0; - - if (hasCurrent) - { - if (currentIs(tok!"else")) - { - immutable i = indents.indentToMostRecent(tok!"if"); - immutable v = indents.indentToMostRecent(tok!"version"); - immutable mostRecent = max(i, v); - if (mostRecent != -1) - indentLevel = mostRecent; - } - else if (currentIs(tok!"identifier") && peekIs(tok!":")) - { - if (peekBackIs(tok!"}", true) || peekBackIs(tok!";", true)) - indents.popTempIndents(); - immutable l = indents.indentToMostRecent(tok!"switch"); - if (l != -1 && config.dfmt_align_switch_statements == OptionalBoolean.t) - indentLevel = l; - else if (astInformation.structInfoSortedByEndLocation - .canFind!(st => st.startLocation < current.index && current.index < st.endLocation)) { - immutable l2 = indents.indentToMostRecent(tok!"{"); - assert(l2 != -1, "Recent '{' is not found despite being in struct initializer"); - indentLevel = l2 + 1; - } - else if ((config.dfmt_compact_labeled_statements == OptionalBoolean.f - || !isBlockHeader(2) || peek2Is(tok!"if")) && !indents.topIs(tok!"]")) - { - immutable l2 = indents.indentToMostRecent(tok!"{"); - indentLevel = l2 != -1 ? l2 : indents.indentLevel - 1; - } - else - indentLevel = indents.indentLevel; - } - else if (currentIs(tok!"case") || currentIs(tok!"default")) - { - - if (peekBackIs(tok!"}", true) || peekBackIs(tok!";", true) - /** - * The following code is valid and should be indented flatly - * case A: - * case B: - */ - || peekBackIs(tok!":", true)) - { - indents.popTempIndents(); - if (indents.topIs(tok!"case")) - indents.pop(); - } - immutable l = indents.indentToMostRecent(tok!"switch"); - if (l != -1) - indentLevel = config.dfmt_align_switch_statements == OptionalBoolean.t - ? l : indents.indentLevel; - } - else if (currentIs(tok!")")) - { - if (indents.topIs(tok!"(")) - indents.pop(); - indentLevel = indents.indentLevel; - } - else if (currentIs(tok!"{")) - { - indents.popWrapIndents(); - if ((peekBackIsSlashSlash() && peekBack2Is(tok!";")) || indents.topIs(tok!"]")) - { - indents.popTempIndents(); - indentLevel = indents.indentLevel; - } - } - else if (currentIs(tok!"}")) - { - indents.popTempIndents(); - while (indents.topIsOneOf(tok!"case", tok!"@", tok!"static")) - indents.pop(); - if (indents.topIs(tok!"{")) - { - indentLevel = indents.indentToMostRecent(tok!"{"); - indents.pop(); - } - if (indents.topIsOneOf(tok!"try", tok!"catch")) - { - indents.pop(); - } - else while (sBraceDepth == 0 && indents.topIsTemp() - && ((!indents.topIsOneOf(tok!"else", tok!"if", - tok!"static", tok!"version")) || !peekIs(tok!"else"))) - { - indents.pop(); - } - } - else if (currentIs(tok!"]")) - { - indents.popWrapIndents(); - if (indents.topIs(tok!"]")) - { - indents.pop(); - } - // Find the initial indentation of constructs like "if" and - // "foreach" without removing them from the stack, since they - // still can be used later to indent "else". - auto savedIndents = IndentStack(config); - while (indents.length >= 0 && indents.topIsTemp) { - savedIndents.push(indents.top, indents.topDetails); - indents.pop; - } - indentLevel = indents.indentLevel; - while (savedIndents.length > 0) { - indents.push(savedIndents.top, savedIndents.topDetails); - savedIndents.pop; - } - } - else if (astInformation.attributeDeclarationLines.canFindIndex(current.line)) - { - if (config.dfmt_outdent_attributes == OptionalBoolean.t) - { - immutable l = indents.indentToMostRecent(tok!"{"); - if (l != -1) - indentLevel = l; - } - else - { - if (indents.topIs(tok!"@")) - indents.pop(); - indentLevel = indents.indentLevel; - } - } - else if (currentIs(tok!"catch") || currentIs(tok!"finally")) - { - indentLevel = indents.indentLevel; - } - else - { - if (indents.topIsTemp() && (peekBackIsOneOf(true, tok!"}", - tok!";") && !indents.topIs(tok!";"))) - indents.popTempIndents(); - indentLevel = indents.indentLevel; - } - indent(); - } - parenDepthOnLine = 0; - } - - void write(string str) - { - currentLineLength += str.length; - output.put(str); - } - - void writeToken() - { - import std.range:retro; - import std.algorithm.searching:countUntil; - import std.algorithm.iteration:joiner; - import std.string:lineSplitter; - - if (current.text is null) - { - immutable s = str(current.type); - currentLineLength += s.length; - output.put(str(current.type)); - } - else - { - output.put(current.text.lineSplitter.joiner(eolString)); - switch (current.type) - { - case tok!"stringLiteral": - case tok!"wstringLiteral": - case tok!"dstringLiteral": - immutable o = current.text.retro().countUntil('\n'); - if (o == -1) { - currentLineLength += current.text.length; - } else { - currentLineLength = cast(uint) o; - } - break; - default: - currentLineLength += current.text.length; - break; - } - } - index++; - } - - void writeParens(bool spaceAfter) - in - { - assert(currentIs(tok!"("), str(current.type)); - } - do - { - immutable int depth = parenDepth; - immutable int startingNiBraceDepth = niBraceDepth; - immutable int startingSBraceDepth = sBraceDepth; - parenDepth = 0; - - do - { - spaceAfterParens = spaceAfter; - if (currentIs(tok!";") && niBraceDepth <= startingNiBraceDepth - && sBraceDepth <= startingSBraceDepth) - { - if (currentLineLength >= config.dfmt_soft_max_line_length) - { - pushWrapIndent(); - writeToken(); - newline(); - } - else - { - writeToken(); - if (!currentIs(tok!")") && !currentIs(tok!";")) - write(" "); - } - } - else - formatStep(); - } - while (hasCurrent && parenDepth > 0); - - if (indents.topIs(tok!"!")) - indents.pop(); - parenDepth = depth; - spaceAfterParens = spaceAfter; - } - - void indent() - { - import dfmt.editorconfig : IndentStyle; - - if (config.indent_style == IndentStyle.tab) - { - foreach (i; 0 .. indentLevel) - { - currentLineLength += config.tab_width; - output.put("\t"); - } - } - else - { - foreach (i; 0 .. indentLevel) - foreach (j; 0 .. config.indent_size) - { - output.put(" "); - currentLineLength++; - } - } - } - - void pushWrapIndent(IdType type = tok!"") - { - immutable t = type == tok!"" ? tokens[index].type : type; - IndentStack.Details detail; - detail.wrap = isWrapIndent(t); - detail.temp = isTempIndent(t); - pushWrapIndent(t, detail); - } - - void pushWrapIndent(IdType type, IndentStack.Details detail) - { - if (parenDepth == 0) - { - if (indents.wrapIndents == 0) - indents.push(type, detail); - } - else if (indents.wrapIndents < 1) - indents.push(type, detail); - } - - void writeSpace() - { - if (onNextLine) - { - newline(); - } - else - { - write(" "); - } - } - -const pure @safe @nogc: - - size_t expressionEndIndex(size_t i, bool matchComma = false) nothrow - { - immutable bool braces = i < tokens.length && tokens[i].type == tok!"{"; - immutable bool brackets = i < tokens.length && tokens[i].type == tok!"["; - immutable d = depths[i]; - while (true) - { - if (i >= tokens.length) - break; - if (depths[i] < d) - break; - if (!braces && !brackets && matchComma && depths[i] == d && tokens[i].type == tok!",") - break; - if (!braces && !brackets && (tokens[i].type == tok!";" || tokens[i].type == tok!"{")) - break; - i++; - } - return i; - } - - /// Returns: true when the expression starting at index goes over the line length limit. - /// Uses matching `{}` or `[]` or otherwise takes everything up until a semicolon or opening brace using expressionEndIndex. - bool isMultilineAt(size_t i, bool matchComma = false) - { - import std.algorithm : map, sum, canFind; - - auto e = expressionEndIndex(i, matchComma); - immutable int l = currentLineLength + tokens[i .. e].map!(a => tokenLength(a)).sum(); - return l > config.dfmt_soft_max_line_length || tokens[i .. e].canFind!( - a => a.type == tok!"comment" || isBlockHeaderToken(a.type))(); - } - - bool peekIsKeyword() nothrow - { - return index + 1 < tokens.length && isKeyword(tokens[index + 1].type); - } - - bool peekIsBasicType() nothrow - { - return index + 1 < tokens.length && isBasicType(tokens[index + 1].type); - } - - bool peekIsLabel() nothrow - { - return peekIs(tok!"identifier") && peek2Is(tok!":"); - } - - int currentTokenLength() - { - return tokenLength(tokens[index]); - } - - int nextTokenLength() - { - immutable size_t i = index + 1; - if (i >= tokens.length) - return INVALID_TOKEN_LENGTH; - return tokenLength(tokens[i]); - } + /* void formatConstraint() */ + /* { */ + /* import dfmt.editorconfig : OB = OptionalBoolean; */ + + /* with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style) */ + /* { */ + /* case _unspecified: */ + /* assert(false, "Config was not validated properly"); */ + /* case conditional_newline: */ + /* immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); */ + /* if (l > config.dfmt_soft_max_line_length) */ + /* newline(); */ + /* else if (peekBackIs(TOK.rightParenthesis) || peekBackIs(TOK.identifier)) */ + /* write(" "); */ + /* break; */ + /* case always_newline: */ + /* newline(); */ + /* break; */ + /* case conditional_newline_indent: */ + /* immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); */ + /* if (l > config.dfmt_soft_max_line_length) */ + /* { */ + /* config.dfmt_single_template_constraint_indent == OB.t ? */ + /* pushWrapIndent() : pushWrapIndent(TOK.not); */ + /* newline(); */ + /* } */ + /* else if (peekBackIs(TOK.rightParenthesis) || peekBackIs(TOK.identifier)) */ + /* write(" "); */ + /* break; */ + /* case always_newline_indent: */ + /* { */ + /* config.dfmt_single_template_constraint_indent == OB.t ? */ + /* pushWrapIndent() : pushWrapIndent(TOK.not); */ + /* newline(); */ + /* } */ + /* break; */ + /* } */ + /* // if */ + /* writeToken(); */ + /* // assume that the parens are present, otherwise the parser would not */ + /* // have told us there was a constraint here */ + /* write(" "); */ + /* writeParens(false); */ + /* } */ + + /* string commentText(size_t i) */ + /* { */ + /* import std.string : strip; */ + + /* assert(tokens[i].value == TOK.comment); */ + /* string commentText = tokens[i].text; */ + /* if (commentText[0 .. 2] == "//") */ + /* commentText = commentText[2 .. $]; */ + /* else */ + /* { */ + /* if (commentText.length > 3) */ + /* commentText = commentText[2 .. $ - 2]; */ + /* else */ + /* commentText = commentText[2 .. $]; */ + /* } */ + /* return commentText.strip(); */ + /* } */ + + /* void skipFormatting() */ + /* { */ + /* size_t dfmtOff = index; */ + /* size_t dfmtOn = index; */ + /* foreach (i; dfmtOff + 1 .. tokens.length) */ + /* { */ + /* dfmtOn = i; */ + /* if (tokens[i].value != TOK.comment) */ + /* continue; */ + /* immutable string commentText = commentText(i); */ + /* if (commentText == "dfmt on") */ + /* break; */ + /* } */ + /* write(cast(string) rawSource[tokens[dfmtOff].index .. tokens[dfmtOn].index]); */ + /* index = dfmtOn; */ + /* } */ + + /* void formatComment() */ + /* { */ + /* if (commentText(index) == "dfmt off") */ + /* { */ + /* skipFormatting(); */ + /* return; */ + /* } */ + + /* immutable bool currIsSlashSlash = tokens[index].text[0 .. 2] == "//"; */ + /* immutable prevTokenEndLine = index == 0 ? size_t.max : tokenEndLine(tokens[index - 1]); */ + /* immutable size_t currTokenLine = tokens[index].line; */ + /* if (index > 0) */ + /* { */ + /* immutable t = tokens[index - 1].value; */ + /* immutable canAddNewline = currTokenLine - prevTokenEndLine < 1; */ + /* if (peekBackIsOperator() && !isSeparationToken(t)) */ + /* pushWrapIndent(t); */ + /* else if (peekBackIs(TOK.comma) && prevTokenEndLine == currTokenLine */ + /* && indents.indentToMostRecent(TOK.enum_) == -1) */ + /* pushWrapIndent(TOK.comma); */ + /* if (peekBackIsOperator() && !peekBackIsOneOf(false, TOK.comment, */ + /* TOK.leftCurly, TOK.rightCurly, TOK.colon, TOK.semicolon, TOK.comma, TOK.leftBracket, TOK */ + /* .leftParenthesis) */ + /* && !canAddNewline && prevTokenEndLine < currTokenLine) */ + /* write(" "); */ + /* else if (prevTokenEndLine == currTokenLine || (t == TOK.rightParenthesis && peekIs( */ + /* TOK.leftCurly))) */ + /* write(" "); */ + /* else if (peekBackIsOneOf(false, TOK.else_, TOK.identifier)) */ + /* write(" "); */ + /* else if (canAddNewline || (peekIs(TOK.leftCurly) && t == TOK.rightCurly)) */ + /* newline(); */ + + /* if (peekIs(TOK.leftParenthesis) && (peekBackIs(TOK.rightParenthesis) || peekBack2Is( */ + /* TOK.not))) */ + /* pushWrapIndent(TOK.leftParenthesis); */ + + /* if (peekIs(TOK.dot) && !indents.topIs(TOK.dot)) */ + /* indents.push(TOK.dot); */ + /* } */ + /* writeToken(); */ + /* immutable j = justAddedExtraNewline; */ + /* if (currIsSlashSlash) */ + /* { */ + /* newline(); */ + /* justAddedExtraNewline = j; */ + /* } */ + /* else if (hasCurrent) */ + /* { */ + /* if (prevTokenEndLine == tokens[index].line) */ + /* { */ + /* if (currentIs(TOK.rightCurly)) */ + /* { */ + /* if (indents.topIs(TOK.leftCurly)) */ + /* indents.pop(); */ + /* write(" "); */ + /* } */ + /* else if (!currentIs(TOK.leftCurly)) */ + /* write(" "); */ + /* } */ + /* else if (!currentIs(TOK.leftCurly) && !currentIs(TOK.in_) && !currentIs(TOK.out_)) */ + /* { */ + /* if (currentIs(TOK.rightParenthesis) && indents.topIs(TOK.comma)) */ + /* indents.pop(); */ + /* else if (peekBack2Is(TOK.comma) && !indents.topIs(TOK.comma) */ + /* && indents.indentToMostRecent(TOK.enum_) == -1) */ + /* pushWrapIndent(TOK.comma); */ + /* newline(); */ + /* } */ + /* } */ + /* else */ + /* newline(); */ + /* } */ + + /* void formatModuleOrImport() */ + /* { */ + /* immutable t = current.value; */ + /* writeToken(); */ + /* if (currentIs(TOK.leftParenthesis)) */ + /* { */ + /* writeParens(false); */ + /* return; */ + /* } */ + /* write(" "); */ + /* while (hasCurrent) */ + /* { */ + /* if (currentIs(TOK.semicolon)) */ + /* { */ + /* indents.popWrapIndents(); */ + /* indentLevel = indents.indentLevel; */ + /* writeToken(); */ + /* if (index >= tokens.length) */ + /* { */ + /* newline(); */ + /* break; */ + /* } */ + /* if (currentIs(TOK.comment) && current.line == peekBack().line) */ + /* { */ + /* break; */ + /* } */ + /* else if (currentIs(TOK.leftCurly) && config.dfmt_brace_style == BraceStyle.allman) */ + /* break; */ + /* else if (t == TOK.import_ && !currentIs(TOK.import_) */ + /* && !currentIs(TOK.rightCurly) */ + /* && !((currentIs(TOK.public_) */ + /* || currentIs(TOK.private_) */ + /* || currentIs(TOK.static_)) */ + /* && peekIs(TOK.import_)) && !indents.topIsOneOf(TOK.if_, */ + /* TOK.debug_, TOK.version_)) */ + /* { */ + /* simpleNewline(); */ + /* currentLineLength = 0; */ + /* justAddedExtraNewline = true; */ + /* newline(); */ + /* } */ + /* else */ + /* newline(); */ + /* break; */ + /* } */ + /* else if (currentIs(TOK.colon)) */ + /* { */ + /* if (config.dfmt_selective_import_space) */ + /* write(" "); */ + /* writeToken(); */ + /* if (!currentIs(TOK.comment)) */ + /* write(" "); */ + /* pushWrapIndent(TOK.comma); */ + /* } */ + /* else if (currentIs(TOK.comment)) */ + /* { */ + /* if (peekBack.line != current.line) */ + /* { */ + /* // The comment appears on its own line, keep it there. */ + /* if (!peekBackIs(TOK.comment)) // Comments are already properly separated. */ + /* newline(); */ + /* } */ + /* formatStep(); */ + /* } */ + /* else */ + /* formatStep(); */ + /* } */ + /* } */ + + /* void formatLeftParenOrBracket() */ + /* in */ + /* { */ + /* assert(currentIs(TOK.leftParenthesis) || currentIs(TOK.leftBracket)); */ + /* } */ + /* do */ + /* { */ + /* import dfmt.editorconfig : OptionalBoolean; */ + + /* immutable p = current.value; */ + /* regenLineBreakHintsIfNecessary(index); */ + /* writeToken(); */ + /* if (p == TOK.leftParenthesis) */ + /* { */ + /* ++parenDepthOnLine; */ + /* // If the file starts with an open paren, just give up. This isn't */ + /* // valid D code. */ + /* if (index < 2) */ + /* return; */ + /* if (isBlockHeaderToken(tokens[index - 2].value)) */ + /* indents.push(TOK.rightParenthesis); */ + /* else */ + /* indents.push(p); */ + /* spaceAfterParens = true; */ + /* parenDepth++; */ + /* } */ + /* // No heuristics apply if we can't look before the opening paren/bracket */ + /* if (index < 1) */ + /* return; */ + /* immutable bool arrayInitializerStart = p == TOK.leftBracket */ + /* && astInformation.arrayStartLocations.canFindIndex(tokens[index - 1].index); */ + + /* if (arrayInitializerStart && isMultilineAt(index - 1)) */ + /* { */ + /* revertParenIndentation(); */ + + /* // Use the close bracket as the indent token to distinguish */ + /* // the array initialiazer from an array index in the newline */ + /* // handling code */ + /* IndentStack.Details detail; */ + /* detail.wrap = false; */ + /* detail.temp = false; */ + + /* // wrap and temp are set manually to the values it would actually */ + /* // receive here because we want to set breakEveryItem for the ] token to know if */ + /* // we should definitely always new-line after every comma for a big AA */ + /* detail.breakEveryItem = astInformation.assocArrayStartLocations.canFindIndex( */ + /* tokens[index - 1].index); */ + /* detail.preferLongBreaking = true; */ + + /* indents.push(TOK.rightBracket, detail); */ + /* newline(); */ + /* immutable size_t j = expressionEndIndex(index); */ + /* linebreakHints = chooseLineBreakTokens(index, tokens[index .. j], */ + /* depths[index .. j], config, currentLineLength, indentLevel); */ + /* } */ + /* else if (p == TOK.leftBracket && config.dfmt_keep_line_breaks == OptionalBoolean.t) */ + /* { */ + /* revertParenIndentation(); */ + /* IndentStack.Details detail; */ + + /* detail.wrap = false; */ + /* detail.temp = false; */ + /* detail.breakEveryItem = false; */ + /* detail.mini = tokens[index].line == tokens[index - 1].line; */ + + /* indents.push(TOK.rightBracket, detail); */ + /* if (!detail.mini) */ + /* { */ + /* newline(); */ + /* } */ + /* } */ + /* else if (arrayInitializerStart) */ + /* { */ + /* // This is a short (non-breaking) array/AA value */ + /* IndentStack.Details detail; */ + /* detail.wrap = false; */ + /* detail.temp = false; */ + + /* detail.breakEveryItem = astInformation.assocArrayStartLocations.canFindIndex( */ + /* tokens[index - 1].index); */ + /* // array of (possibly associative) array, let's put each item on its own line */ + /* if (!detail.breakEveryItem && currentIs(TOK.leftBracket)) */ + /* detail.breakEveryItem = true; */ + + /* // the '[' is immediately followed by an item instead of a newline here so */ + /* // we set mini, that the ']' also follows an item immediately without newline. */ + /* detail.mini = true; */ + + /* indents.push(TOK.rightBracket, detail); */ + /* } */ + /* else if (p == TOK.leftBracket) */ + /* { */ + /* // array item access */ + /* IndentStack.Details detail; */ + /* detail.wrap = false; */ + /* detail.temp = true; */ + /* detail.mini = true; */ + /* indents.push(TOK.rightBracket, detail); */ + /* } */ + /* else if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) */ + /* && (linebreakHints.canFindIndex(index - 1) || (linebreakHints.length == 0 */ + /* && currentLineLength > config.max_line_length))) */ + /* { */ + /* newline(); */ + /* } */ + /* else if (onNextLine) */ + /* { */ + /* newline(); */ + /* } */ + /* } */ + + /* void revertParenIndentation() */ + /* { */ + /* import std.algorithm.searching : canFind, until; */ + + /* if (tokens[index .. $].until!(tok => tok.line != current.line) */ + /* .canFind!(x => x.value == TOK.rightBracket)) */ + /* { */ + /* return; */ + /* } */ + /* if (parenDepthOnLine) */ + /* { */ + /* foreach (i; 0 .. parenDepthOnLine) */ + /* { */ + /* indents.pop(); */ + /* } */ + /* } */ + /* parenDepthOnLine = 0; */ + /* } */ + + /* void formatRightParen() */ + /* in */ + /* { */ + /* assert(currentIs(TOK.rightParenthesis)); */ + /* } */ + /* do */ + /* { */ + /* parenDepthOnLine = max(parenDepthOnLine - 1, 0); */ + /* parenDepth--; */ + /* indents.popWrapIndents(); */ + /* while (indents.topIsOneOf(TOK.not, TOK.rightParenthesis)) */ + /* indents.pop(); */ + /* if (indents.topIs(TOK.leftParenthesis)) */ + /* indents.pop(); */ + /* if (indents.topIs(TOK.dot)) */ + /* indents.pop(); */ + + /* if (onNextLine) */ + /* { */ + /* newline(); */ + /* } */ + /* if (parenDepth == 0 && (peekIs(TOK.is_) || peekIs(TOK.in_) */ + /* || peekIs(TOK.out_) || peekIs(TOK.do_) || peekIsBody)) */ + /* { */ + /* writeToken(); */ + /* } */ + /* else if (peekIsLiteralOrIdent() || peekIsBasicType()) */ + /* { */ + /* writeToken(); */ + /* if (spaceAfterParens || parenDepth > 0) */ + /* writeSpace(); */ + /* } */ + /* else if ((peekIsKeyword() || peekIs(TOK.at)) && spaceAfterParens */ + /* && !peekIs(TOK.in_) && !peekIs(TOK.is_) && !peekIs(TOK.if_)) */ + /* { */ + /* writeToken(); */ + /* writeSpace(); */ + /* } */ + /* else */ + /* writeToken(); */ + /* } */ + + /* void formatRightBracket() */ + /* in */ + /* { */ + /* assert(currentIs(TOK.rightBracket)); */ + /* } */ + /* do */ + /* { */ + /* indents.popWrapIndents(); */ + /* if (indents.topIs(TOK.rightBracket)) */ + /* { */ + /* if (!indents.topDetails.mini && !indents.topDetails.temp) */ + /* newline(); */ + /* else */ + /* indents.pop(); */ + /* } */ + /* writeToken(); */ + /* if (currentIs(TOK.identifier)) */ + /* write(" "); */ + /* } */ + + /* void formatAt() */ + /* { */ + /* immutable size_t atIndex = tokens[index].index; */ + /* writeToken(); */ + /* if (currentIs(TOK.identifier)) */ + /* writeToken(); */ + /* if (currentIs(TOK.leftParenthesis)) */ + /* { */ + /* writeParens(false); */ + /* if (tokens[index].value == TOK.leftCurly) */ + /* return; */ + + /* if (hasCurrent && tokens[index - 1].line < tokens[index].line */ + /* && astInformation.atAttributeStartLocations.canFindIndex(atIndex)) */ + /* newline(); */ + /* else */ + /* write(" "); */ + /* } */ + /* else if (hasCurrent && (currentIs(TOK.at) */ + /* || isBasicType(tokens[index].value) */ + /* || currentIs(TOK.invariant_) */ + /* || currentIs(TOK.extern_) */ + /* || currentIs(TOK.identifier)) */ + /* && !currentIsIndentedTemplateConstraint()) */ + /* { */ + /* writeSpace(); */ + /* } */ + /* } */ + + /* void formatColon() */ + /* { */ + /* import dfmt.editorconfig : OptionalBoolean; */ + /* import std.algorithm : canFind, any; */ + + /* immutable bool isCase = astInformation.caseEndLocations.canFindIndex(current.index); */ + /* immutable bool isAttribute = astInformation.attributeDeclarationLines.canFindIndex( */ + /* current.line); */ + /* immutable bool isStructInitializer = astInformation.structInfoSortedByEndLocation */ + /* .canFind!(st => st.startLocation < current.index && current.index < st.endLocation); */ + + /* if (isCase || isAttribute) */ + /* { */ + /* writeToken(); */ + /* if (!currentIs(TOK.leftCurly)) */ + /* { */ + /* if (isCase && !indents.topIs(TOK.case_) */ + /* && config.dfmt_align_switch_statements == OptionalBoolean.f) */ + /* indents.push(TOK.case_); */ + /* else if (isAttribute && !indents.topIs(TOK.at) */ + /* && config.dfmt_outdent_attributes == OptionalBoolean.f) */ + /* indents.push(TOK.at); */ + /* newline(); */ + /* } */ + /* } */ + /* else if (indents.topIs(TOK.rightBracket)) // Associative array */ + /* { */ + /* write(config.dfmt_space_before_aa_colon ? " : " : ": "); */ + /* ++index; */ + /* } */ + /* else if (peekBackIs(TOK.identifier) */ + /* && [ */ + /* TOK.leftCurly, TOK.rightCurly, TOK.semicolon, TOK.colon, TOK.comma */ + /* ] */ + /* .any!((ptrdiff_t token) => peekBack2Is(cast(TOK) token, true)) */ + /* && (!isBlockHeader(1) || peekIs(TOK.if_))) */ + /* { */ + /* writeToken(); */ + /* if (isStructInitializer) */ + /* write(" "); */ + /* else if (!currentIs(TOK.leftCurly)) */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* regenLineBreakHintsIfNecessary(index); */ + /* if (peekIs(TOK.slice)) */ + /* writeToken(); */ + /* else if (isBlockHeader(1) && !peekIs(TOK.if_)) */ + /* { */ + /* writeToken(); */ + /* if (config.dfmt_compact_labeled_statements) */ + /* write(" "); */ + /* else */ + /* newline(); */ + /* } */ + /* else if (linebreakHints.canFindIndex(index)) */ + /* { */ + /* pushWrapIndent(); */ + /* newline(); */ + /* writeToken(); */ + /* write(" "); */ + /* } */ + /* else */ + /* { */ + /* write(" : "); */ + /* index++; */ + /* } */ + /* } */ + /* } */ + + /* void formatSemicolon() */ + /* { */ + /* if (inlineElse && !peekIs(TOK.else_)) */ + /* inlineElse = false; */ + + /* if ((parenDepth > 0 && sBraceDepth == 0) || (sBraceDepth > 0 && niBraceDepth > 0)) */ + /* { */ + /* if (currentLineLength > config.dfmt_soft_max_line_length) */ + /* { */ + /* writeToken(); */ + /* pushWrapIndent(TOK.semicolon); */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* if (!(peekIs(TOK.semicolon) || peekIs(TOK.rightParenthesis) || peekIs( */ + /* TOK.rightCurly))) */ + /* write("; "); */ + /* else */ + /* write(";"); */ + /* index++; */ + /* } */ + /* } */ + /* else */ + /* { */ + /* writeToken(); */ + /* indents.popWrapIndents(); */ + /* linebreakHints = []; */ + /* while (indents.topIsOneOf(TOK.enum_, TOK.try_, TOK.catch_, TOK.finally_, TOK.debug_)) */ + /* indents.pop(); */ + /* if (indents.topAre(TOK.static_, TOK.else_)) */ + /* { */ + /* indents.pop(); */ + /* indents.pop(); */ + /* } */ + /* indentLevel = indents.indentLevel; */ + /* if (config.dfmt_brace_style == BraceStyle.allman) */ + /* { */ + /* if (!currentIs(TOK.leftCurly)) */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* if (currentIs(TOK.leftCurly)) */ + /* indents.popTempIndents(); */ + /* indentLevel = indents.indentLevel; */ + /* newline(); */ + /* } */ + /* } */ + /* } */ + + /* void formatLeftBrace() */ + /* { */ + /* import std.algorithm : map, sum, canFind; */ + + /* auto tIndex = tokens[index].index; */ + + /* if (astInformation.structInitStartLocations.canFindIndex(tIndex)) */ + /* { */ + /* sBraceDepth++; */ + /* immutable bool multiline = isMultilineAt(index); */ + /* writeToken(); */ + /* if (multiline) */ + /* { */ + /* import std.algorithm.searching : find; */ + + /* auto indentInfo = astInformation.indentInfoSortedByEndLocation */ + /* .find!((a, b) => a.startLocation == b)(tIndex); */ + /* assert(indentInfo.length > 0); */ + /* cast() indentInfo[0].flags |= BraceIndentInfoFlags.tempIndent; */ + /* cast() indentInfo[0].beginIndentLevel = indents.indentLevel; */ + + /* indents.push(TOK.leftCurly); */ + /* newline(); */ + /* } */ + /* else */ + /* niBraceDepth++; */ + /* } */ + /* else if (astInformation.funLitStartLocations.canFindIndex(tIndex)) */ + /* { */ + /* indents.popWrapIndents(); */ + + /* sBraceDepth++; */ + /* if (peekBackIsOneOf(true, TOK.rightParenthesis, TOK.identifier)) */ + /* write(" "); */ + /* immutable bool multiline = isMultilineAt(index); */ + /* writeToken(); */ + /* if (multiline) */ + /* { */ + /* indents.push(TOK.leftCurly); */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* niBraceDepth++; */ + /* if (!currentIs(TOK.rightCurly)) */ + /* write(" "); */ + /* } */ + /* } */ + /* else */ + /* { */ + /* if (peekBackIsSlashSlash()) */ + /* { */ + /* if (peekBack2Is(TOK.semicolon)) */ + /* { */ + /* indents.popTempIndents(); */ + /* indentLevel = indents.indentLevel - 1; */ + /* } */ + /* writeToken(); */ + /* } */ + /* else */ + /* { */ + /* if (indents.topIsTemp && indents.indentToMostRecent(TOK.static_) == -1) */ + /* indentLevel = indents.indentLevel - 1; */ + /* else */ + /* indentLevel = indents.indentLevel; */ + /* if (config.dfmt_brace_style == BraceStyle.allman */ + /* || peekBackIsOneOf(true, TOK.leftCurly, TOK.rightCurly)) */ + /* newline(); */ + /* else if (config.dfmt_brace_style == BraceStyle.knr */ + /* && astInformation.funBodyLocations.canFindIndex(tIndex) */ + /* && (peekBackIs(TOK.rightParenthesis) || (!peekBackIs(TOK.do_) && peekBack().text != "body"))) */ + /* newline(); */ + /* else if (!peekBackIsOneOf(true, TOK.leftCurly, TOK.rightCurly, TOK.semicolon)) */ + /* write(" "); */ + /* writeToken(); */ + /* } */ + /* indents.push(TOK.leftCurly); */ + /* if (!currentIs(TOK.leftCurly)) */ + /* newline(); */ + /* linebreakHints = []; */ + /* } */ + /* } */ + + /* void formatRightBrace() */ + /* { */ + /* void popToBeginIndent(BraceIndentInfo indentInfo) */ + /* { */ + /* foreach (i; indentInfo.beginIndentLevel .. indents.indentLevel) */ + /* { */ + /* indents.pop(); */ + /* } */ + + /* indentLevel = indentInfo.beginIndentLevel; */ + /* } */ + + /* size_t pos; */ + /* if (astInformation.structInitEndLocations.canFindIndex(tokens[index].index, &pos)) */ + /* { */ + /* if (sBraceDepth > 0) */ + /* sBraceDepth--; */ + /* if (niBraceDepth > 0) */ + /* niBraceDepth--; */ + + /* auto indentInfo = astInformation.indentInfoSortedByEndLocation[pos]; */ + /* if (indentInfo.flags & BraceIndentInfoFlags.tempIndent) */ + /* { */ + /* popToBeginIndent(indentInfo); */ + /* simpleNewline(); */ + /* indent(); */ + /* } */ + /* writeToken(); */ + /* } */ + /* else if (astInformation.funLitEndLocations.canFindIndex(tokens[index].index, &pos)) */ + /* { */ + /* if (niBraceDepth > 0) */ + /* { */ + /* if (!peekBackIsSlashSlash() && !peekBackIs(TOK.leftCurly)) */ + /* write(" "); */ + /* niBraceDepth--; */ + /* } */ + /* if (sBraceDepth > 0) */ + /* sBraceDepth--; */ + /* writeToken(); */ + /* } */ + /* else */ + /* { */ + /* // Silly hack to format enums better. */ + /* if ((peekBackIsLiteralOrIdent() || peekBackIsOneOf(true, TOK.rightParenthesis, */ + /* TOK.comma)) && !peekBackIsSlashSlash()) */ + /* newline(); */ + /* write("}"); */ + /* if (index + 1 < tokens.length */ + /* && astInformation.doubleNewlineLocations.canFindIndex(tokens[index].index) */ + /* && !peekIs(TOK.rightCurly) && !peekIs(TOK.else_) */ + /* && !peekIs(TOK.semicolon) && !peekIs(TOK.comment, false)) */ + /* { */ + /* simpleNewline(); */ + /* currentLineLength = 0; */ + /* justAddedExtraNewline = true; */ + /* } */ + /* if (config.dfmt_brace_style.among(BraceStyle.otbs, BraceStyle.knr) */ + /* && ((peekIs(TOK.else_) */ + /* && !indents.topAre(TOK.static_, TOK.if_) */ + /* && !indents.topIs(TOK.foreach_) && !indents.topIs(TOK.for_) */ + /* && !indents.topIs(TOK.while_) && !indents.topIs(TOK.do_)) */ + /* || peekIs(TOK.catch_) || peekIs(TOK.finally_))) */ + /* { */ + /* write(" "); */ + /* index++; */ + /* } */ + /* else */ + /* { */ + /* if (!peekIs(TOK.comma) && !peekIs(TOK.rightParenthesis) */ + /* && !peekIs(TOK.semicolon) && !peekIs(TOK.leftCurly)) */ + /* { */ + /* index++; */ + /* if (indents.topIs(TOK.static_)) */ + /* indents.pop(); */ + /* newline(); */ + /* } */ + /* else */ + /* index++; */ + /* } */ + /* } */ + /* } */ + + /* void formatSwitch() */ + /* { */ + /* while (indents.topIs(TOK.with_)) */ + /* indents.pop(); */ + /* indents.push(TOK.switch_); */ + /* writeToken(); // switch */ + /* if (config.dfmt_space_after_keywords) */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + + /* void formatBlockHeader() */ + /* { */ + /* if (indents.topIs(TOK.not)) */ + /* indents.pop(); */ + /* immutable bool a = !currentIs(TOK.version_) && !currentIs(TOK.debug_); */ + /* immutable bool b = a */ + /* || astInformation.conditionalWithElseLocations.canFindIndex(current.index); */ + /* immutable bool c = b */ + /* || astInformation.conditionalStatementLocations.canFindIndex(current.index); */ + /* immutable bool shouldPushIndent = (c || peekBackIs(TOK.else_)) */ + /* && !(currentIs(TOK.if_) && indents.topIsWrap()); */ + /* if (currentIs(TOK.out_) && !peekBackIs(TOK.rightCurly)) */ + /* newline(); */ + /* if (shouldPushIndent) */ + /* { */ + /* if (peekBackIs(TOK.static_)) */ + /* { */ + /* if (indents.topIs(TOK.else_)) */ + /* indents.pop(); */ + /* if (!indents.topIs(TOK.static_)) */ + /* indents.push(TOK.static_); */ + /* } */ + /* indents.push(current.value); */ + /* } */ + /* writeToken(); */ + + /* if (currentIs(TOK.leftParenthesis)) */ + /* { */ + /* if (config.dfmt_space_after_keywords) */ + /* { */ + /* write(" "); */ + /* } */ + /* writeParens(false); */ + /* } */ + + /* if (hasCurrent) */ + /* { */ + /* if (currentIs(TOK.switch_) || (currentIs(TOK.final_) && peekIs(TOK.switch_))) */ + /* { */ + /* if (config.dfmt_space_after_keywords) */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + /* else if (currentIs(TOK.comment)) */ + /* { */ + /* formatStep(); */ + /* } */ + /* else if (!shouldPushIndent) */ + /* { */ + /* if (!currentIs(TOK.leftCurly) && !currentIs(TOK.semicolon)) */ + /* write(" "); */ + /* } */ + /* else if (hasCurrent && !currentIs(TOK.leftCurly) && !currentIs(TOK.semicolon) && !currentIs(TOK.in_) && */ + /* !currentIs(TOK.out_) && !currentIs(TOK.do_) && current.text != "body") */ + /* { */ + /* newline(); */ + /* } */ + /* else if (currentIs(TOK.leftCurly) && indents.topAre(tok.static_, TOK.if_)) */ + /* { */ + /* // Hacks to format braced vs non-braced static if declarations. */ + /* indents.pop(); */ + /* indents.pop(); */ + /* indents.push(TOK.if_); */ + /* formatLeftBrace(); */ + /* } */ + /* else if (currentIs(TOK.leftCurly) && indents.topAre(TOK.static_, TOK.foreach_)) */ + /* { */ + /* indents.pop(); */ + /* indents.pop(); */ + /* indents.push(TOK.foreach_); */ + /* formatLeftBrace(); */ + /* } */ + /* else if (currentIs(TOK.leftCurly) && indents.topAre(TOK.static_, TOK.foreach_reverse_)) */ + /* { */ + /* indents.pop(); */ + /* indents.pop(); */ + /* indents.push(TOK.foreach_reverse_); */ + /* formatLeftBrace(); */ + /* } */ + /* } */ + /* } */ + + /* void formatElse() */ + /* { */ + /* writeToken(); */ + /* if (inlineElse || currentIs(TOK.if_) || currentIs(TOK.version_) */ + /* || (currentIs(TOK.static_) && peekIs(TOK.if_))) */ + /* { */ + /* if (indents.topIs(TOK.if_) || indents.topIs(TOK.version_)) */ + /* indents.pop(); */ + /* inlineElse = false; */ + /* write(" "); */ + /* } */ + /* else if (currentIs(TOK.colon)) */ + /* { */ + /* writeToken(); */ + /* newline(); */ + /* } */ + /* else if (!currentIs(TOK.leftCurly) && !currentIs(TOK.comment)) */ + /* { */ + /* //indents.dump(); */ + /* while (indents.topIsOneOf(TOK.foreach_, TOK.for_, TOK.while_)) */ + /* indents.pop(); */ + /* if (indents.topIsOneOf(TOK.if_, TOK.version_)) */ + /* indents.pop(); */ + /* indents.push(TOK.else_); */ + /* newline(); */ + /* } */ + /* else if (currentIs(TOK.leftCurly) && indents.topAre(TOK.static_, TOK.if_)) */ + /* { */ + /* indents.pop(); */ + /* indents.pop(); */ + /* indents.push(TOK.else_); */ + /* } */ + /* } */ + + /* void formatKeyword() */ + /* { */ + /* import dfmt.editorconfig : OptionalBoolean; */ + + /* switch (current.value) */ + /* { */ + /* case TOK.default_: */ + /* writeToken(); */ + /* break; */ + /* case TOK.cast_: */ + /* writeToken(); */ + /* if (hasCurrent && currentIs(TOK.leftParenthesis)) */ + /* writeParens(config.dfmt_space_after_cast == OptionalBoolean.t); */ + /* break; */ + /* case TOK.out_: */ + /* if (!peekBackIsSlashSlash) */ + /* { */ + /* if (!peekBackIs(TOK.rightCurly) */ + /* && astInformation.contractLocations.canFindIndex(current.index)) */ + /* newline(); */ + /* else if (peekBackIsKeyword) */ + /* write(" "); */ + /* } */ + /* writeToken(); */ + /* if (hasCurrent && !currentIs(TOK.leftCurly) && !currentIs(TOK.comment)) */ + /* write(" "); */ + /* break; */ + /* case TOK.try_: */ + /* case TOK.finally_: */ + /* indents.push(current.value); */ + /* writeToken(); */ + /* if (hasCurrent && !currentIs(TOK.leftCurly)) */ + /* newline(); */ + /* break; */ + /* case TOK.identifier: */ + /* if (current.text == "body") */ + /* goto case TOK.do_; */ + /* else */ + /* goto default; */ + /* case TOK.do_: */ + /* if (!peekBackIs(TOK.rightCurly)) */ + /* newline(); */ + /* writeToken(); */ + /* break; */ + /* case TOK.in_: */ + /* immutable isContract = astInformation.contractLocations.canFindIndex(current.index); */ + /* if (!peekBackIsSlashSlash) */ + /* { */ + /* if (isContract) */ + /* { */ + /* indents.popTempIndents(); */ + /* newline(); */ + /* } */ + /* else if (!peekBackIsOneOf(false, TOK.leftParenthesis, TOK.comma, TOK.not)) */ + /* write(" "); */ + /* } */ + /* writeToken(); */ + /* if (!hasCurrent) */ + /* return; */ + /* immutable isFunctionLit = astInformation.funLitStartLocations.canFindIndex( */ + /* current.index); */ + /* if (isFunctionLit && config.dfmt_brace_style == BraceStyle.allman) */ + /* newline(); */ + /* else if (!isContract || currentIs(TOK.leftParenthesis)) */ + /* write(" "); */ + /* break; */ + /* case TOK.is_: */ + /* if (!peekBackIsOneOf(false, TOK.not, TOK.leftParenthesis, TOK.comma, */ + /* TOK.rightCurly, TOK.assign, TOK.andAnd, TOK.orOr) && !peekBackIsKeyword()) */ + /* write(" "); */ + /* writeToken(); */ + /* if (hasCurrent && !currentIs(TOK.leftParenthesis) && !currentIs(TOK.leftCurly) && !currentIs( */ + /* TOK.comment)) */ + /* write(" "); */ + /* break; */ + /* case TOK.case_: */ + /* writeToken(); */ + /* if (hasCurrent && !currentIs(TOK.semicolon)) */ + /* write(" "); */ + /* break; */ + /* case TOK.enum_: */ + /* if (peekIs(TOK.rightParenthesis) || peekIs(TOK.equal)) */ + /* { */ + /* writeToken(); */ + /* } */ + /* else */ + /* { */ + /* if (peekBackIs(TOK.identifier)) */ + /* write(" "); */ + /* indents.push(TOK.enum_); */ + /* writeToken(); */ + /* if (hasCurrent && !currentIs(TOK.colon) && !currentIs(TOK.leftCurly)) */ + /* write(" "); */ + /* } */ + /* break; */ + /* case TOK.static_: */ + /* { */ + /* if (astInformation.staticConstructorDestructorLocations */ + /* .canFindIndex(current.index)) */ + /* { */ + /* thisSpace = true; */ + /* } */ + /* } */ + /* goto default; */ + /* case TOK.shared_: */ + /* { */ + /* if (astInformation.sharedStaticConstructorDestructorLocations */ + /* .canFindIndex(current.index)) */ + /* { */ + /* thisSpace = true; */ + /* } */ + /* } */ + /* goto default; */ + /* case TOK.invariant_: */ + /* writeToken(); */ + /* if (hasCurrent && currentIs(TOK.leftParenthesis)) */ + /* write(" "); */ + /* break; */ + /* default: */ + /* if (peekBackIs(TOK.identifier)) */ + /* { */ + /* writeSpace(); */ + /* } */ + /* if (index + 1 < tokens.length) */ + /* { */ + /* if (!peekIs(TOK.at) && (peekIsOperator() */ + /* || peekIs(TOK.out_) || peekIs(TOK.in_))) */ + /* { */ + /* writeToken(); */ + /* } */ + /* else */ + /* { */ + /* writeToken(); */ + /* if (!currentIsIndentedTemplateConstraint()) */ + /* { */ + /* writeSpace(); */ + /* } */ + /* } */ + /* } */ + /* else */ + /* writeToken(); */ + /* break; */ + /* } */ + /* } */ + + /* bool currentIsIndentedTemplateConstraint() */ + /* { */ + /* return hasCurrent */ + /* && astInformation.constraintLocations.canFindIndex(current.index) */ + /* && (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline */ + /* || config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent */ + /* || currentLineLength >= config.dfmt_soft_max_line_length); */ + /* } */ + + /* void formatOperator() */ + /* { */ + /* import dfmt.editorconfig : OptionalBoolean; */ + /* import std.algorithm : canFind; */ + + /* switch (current.value) */ + /* { */ + /* case TOK.mul: */ + /* if (astInformation.spaceAfterLocations.canFindIndex(current.index)) */ + /* { */ + /* writeToken(); */ + /* if (!currentIs(TOK.mul) && !currentIs(TOK.rightParenthesis) */ + /* && !currentIs(TOK.leftBracket) && !currentIs(TOK.comma) && !currentIs( */ + /* TOK.semicolon)) */ + /* { */ + /* write(" "); */ + /* } */ + /* break; */ + /* } */ + /* else if (astInformation.unaryLocations.canFindIndex(current.index)) */ + /* { */ + /* writeToken(); */ + /* break; */ + /* } */ + /* regenLineBreakHintsIfNecessary(index); */ + /* goto binary; */ + /* case TOK.tilde: */ + /* if (peekIs(TOK.this_) && peek2Is(TOK.leftParenthesis)) */ + /* { */ + /* if (!(index == 0 || peekBackIs(TOK.leftCurly, true) */ + /* || peekBackIs(TOK.rightCurly, true) || peekBackIs(TOK.semicolon, true))) */ + /* { */ + /* write(" "); */ + /* } */ + /* writeToken(); */ + /* break; */ + /* } */ + /* goto case; */ + /* case TOK.and: */ + /* case TOK.add: */ + /* case TOK.min: */ + /* if (astInformation.unaryLocations.canFindIndex(current.index)) */ + /* { */ + /* writeToken(); */ + /* break; */ + /* } */ + /* regenLineBreakHintsIfNecessary(index); */ + /* goto binary; */ + /* case TOK.leftBracket: */ + /* case TOK.leftParenthesis: */ + /* formatLeftParenOrBracket(); */ + /* break; */ + /* case TOK.rightParenthesis: */ + /* formatRightParen(); */ + /* break; */ + /* case TOK.at: */ + /* formatAt(); */ + /* break; */ + /* case TOK.not: */ + /* if (((peekIs(TOK.is_) || peekIs(TOK.in_)) */ + /* && !peekBackIsOperator()) || peekBackIs(TOK.rightParenthesis)) */ + /* write(" "); */ + /* goto case; */ + /* case tok!"...": */ + /* case tok!"++": */ + /* case tok!"--": */ + /* case TOK.dollar: */ + /* writeToken(); */ + /* break; */ + /* case TOK.colon: */ + /* formatColon(); */ + /* break; */ + /* case TOK.rightBracket: */ + /* formatRightBracket(); */ + /* break; */ + /* case TOK.semicolon: */ + /* formatSemicolon(); */ + /* break; */ + /* case TOK.leftCurly: */ + /* formatLeftBrace(); */ + /* break; */ + /* case TOK.rightCurly: */ + /* formatRightBrace(); */ + /* break; */ + /* case TOK.dot: */ + /* regenLineBreakHintsIfNecessary(index); */ + /* immutable bool ufcsWrap = config.dfmt_reflow_property_chains == OptionalBoolean.t */ + /* && astInformation.ufcsHintLocations.canFindIndex(current.index); */ + /* if (ufcsWrap || linebreakHints.canFind(index) || onNextLine */ + /* || (linebreakHints.length == 0 && currentLineLength + nextTokenLength() > config */ + /* .max_line_length)) */ + /* { */ + /* if (!indents.topIs(TOK.dot)) */ + /* indents.push(TOK.dot); */ + /* if (!peekBackIs(TOK.comment)) */ + /* newline(); */ + /* if (ufcsWrap || onNextLine) */ + /* regenLineBreakHints(index); */ + /* } */ + /* writeToken(); */ + /* break; */ + /* case TOK.comma: */ + /* formatComma(); */ + /* break; */ + /* case tok!"&&": */ + /* case tok!"||": */ + /* case TOK.or: */ + /* regenLineBreakHintsIfNecessary(index); */ + /* goto case; */ + /* case TOK.assign: */ + /* 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.xor: */ + /* case tok!"~=": */ + /* case tok!"<<=": */ + /* case tok!"<<": */ + /* case tok!"<=": */ + /* case tok!"<>=": */ + /* case tok!"<>": */ + /* case TOK.lessThan: */ + /* case tok!"==": */ + /* case tok!"=>": */ + /* case tok!">>>": */ + /* case tok!">>": */ + /* case TOK.greaterThan: */ + /* case tok!"!<=": */ + /* case tok!"!<>=": */ + /* case tok!"!<>": */ + /* case tok!"!<": */ + /* case tok!"!=": */ + /* case tok!"!>=": */ + /* case tok!"!>": */ + /* case TOK.question: */ + /* case TOK.div: */ + /* case tok!"..": */ + /* case TOK.mod: */ + /* binary: */ + /* immutable bool isWrapToken = linebreakHints.canFind(index); */ + /* if (config.dfmt_keep_line_breaks == OptionalBoolean.t && index > 0) */ + /* { */ + /* const operatorLine = tokens[index].line; */ + /* const rightOperandLine = tokens[index + 1].line; */ + + /* if (tokens[index - 1].line < operatorLine) */ + /* { */ + /* if (!indents.topIs(tok!"enum")) */ + /* pushWrapIndent(); */ + /* if (!peekBackIs(TOK.comment)) */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* write(" "); */ + /* } */ + /* if (rightOperandLine > operatorLine */ + /* && !indents.topIs(tok!"enum")) */ + /* { */ + /* pushWrapIndent(); */ + /* } */ + /* writeToken(); */ + + /* if (rightOperandLine > operatorLine) */ + /* { */ + /* if (!peekBackIs(TOK.comment)) */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + /* else if (config.dfmt_split_operator_at_line_end) */ + /* { */ + /* if (isWrapToken) */ + /* { */ + /* if (!indents.topIs(tok!"enum")) */ + /* pushWrapIndent(); */ + /* write(" "); */ + /* writeToken(); */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* write(" "); */ + /* writeToken(); */ + /* if (!currentIs(TOK.comment)) */ + /* write(" "); */ + /* } */ + /* } */ + /* else */ + /* { */ + /* if (isWrapToken) */ + /* { */ + /* if (!indents.topIs(tok!"enum")) */ + /* pushWrapIndent(); */ + /* newline(); */ + /* writeToken(); */ + /* } */ + /* else */ + /* { */ + /* write(" "); */ + /* writeToken(); */ + /* } */ + /* if (!currentIs(TOK.comment)) */ + /* write(" "); */ + /* } */ + /* break; */ + /* default: */ + /* writeToken(); */ + /* break; */ + /* } */ + /* } */ + + /* void formatComma() */ + /* { */ + /* import dfmt.editorconfig : OptionalBoolean; */ + /* import std.algorithm : canFind; */ + + /* if (config.dfmt_keep_line_breaks == OptionalBoolean.f) */ + /* regenLineBreakHintsIfNecessary(index); */ + /* if (indents.indentToMostRecent(TOK.enum_) != -1 */ + /* && !peekIs(TOK.rightCurly) && indents.topIs(TOK.leftCurly) && parenDepth == 0) */ + /* { */ + /* writeToken(); */ + /* newline(); */ + /* } */ + /* else if (indents.topIs(TOK.rightBracket) && indents.topDetails.breakEveryItem */ + /* && !indents.topDetails.mini) */ + /* { */ + /* writeToken(); */ + /* newline(); */ + /* regenLineBreakHints(index - 1); */ + /* } */ + /* else if (indents.topIs(TOK.rightBracket) && indents.topDetails.preferLongBreaking */ + /* && !currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) && !currentIs( */ + /* TOK.rightCurly) */ + /* && !currentIs(TOK.comment) && index + 1 < tokens.length */ + /* && isMultilineAt(index + 1, true)) */ + /* { */ + /* writeToken(); */ + /* newline(); */ + /* regenLineBreakHints(index - 1); */ + /* } */ + /* else if (config.dfmt_keep_line_breaks == OptionalBoolean.t) */ + /* { */ + /* const commaLine = tokens[index].line; */ + + /* writeToken(); */ + /* if (indents.topIsWrap && !indents.topIs(TOK.comma)) */ + /* { */ + /* indents.pop; */ + /* } */ + /* if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) */ + /* && !currentIs(TOK.rightCurly) && !currentIs(TOK.comment)) */ + /* { */ + /* if (tokens[index].line == commaLine) */ + /* { */ + /* write(" "); */ + /* } */ + /* else */ + /* { */ + /* newline(); */ + /* } */ + /* } */ + /* } */ + /* else if (!peekIs(TOK.rightCurly) && (linebreakHints.canFind(index) */ + /* || (linebreakHints.length == 0 && currentLineLength > config.max_line_length))) */ + /* { */ + /* pushWrapIndent(); */ + /* writeToken(); */ + /* if (indents.topIsWrap && !indents.topIs(TOK.comma)) */ + /* { */ + /* indents.pop; */ + /* } */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* writeToken(); */ + /* if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) */ + /* && !currentIs(TOK.rightCurly) && !currentIs(TOK.comment)) */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + /* regenLineBreakHintsIfNecessary(index - 1); */ + /* } */ + + /* void regenLineBreakHints(immutable size_t i) */ + /* { */ + /* import std.range : assumeSorted; */ + /* import std.algorithm.comparison : min; */ + /* import std.algorithm.searching : canFind, countUntil; */ + + /* // The end of the tokens considered by the line break algorithm is */ + /* // either the expression end index or the next mandatory line break */ + /* // or a newline inside a string literal, whichever is first. */ + /* auto r = assumeSorted(astInformation.ufcsHintLocations).upperBound(tokens[i].index); */ + /* immutable ufcsBreakLocation = r.empty */ + /* ? size_t.max */ + /* : tokens[i .. $].countUntil!(t => t.index == r.front) + i; */ + /* immutable multilineStringLocation = tokens[i .. $] */ + /* .countUntil!(t => t.text.canFind('\n')); */ + /* immutable size_t j = min( */ + /* expressionEndIndex(i), */ + /* ufcsBreakLocation, */ + /* multilineStringLocation == -1 ? size_t.max : multilineStringLocation + i + 1); */ + /* // Use magical negative value for array literals and wrap indents */ + /* immutable inLvl = (indents.topIsWrap() || indents.topIs(TOK.rightBracket)) ? -indentLevel */ + /* : indentLevel; */ + /* linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j], */ + /* config, currentLineLength, inLvl); */ + /* } */ + + /* void regenLineBreakHintsIfNecessary(immutable size_t i) */ + /* { */ + /* if (linebreakHints.length == 0 || linebreakHints[$ - 1] <= i - 1) */ + /* regenLineBreakHints(i); */ + /* } */ + + /* void simpleNewline() */ + /* { */ + /* import dfmt.editorconfig : EOL; */ + + /* output.put(eolString); */ + /* } */ + + /* void newline() */ + /* { */ + /* import std.range : assumeSorted; */ + /* import std.algorithm : max, canFind; */ + /* import dfmt.editorconfig : OptionalBoolean; */ + + /* if (currentIs(TOK.comment) && index > 0 && current.line == tokenEndLine(tokens[index - 1])) */ + /* return; */ + + /* immutable bool hasCurrent = this.hasCurrent; */ + + /* if (niBraceDepth > 0 && !peekBackIsSlashSlash() && hasCurrent && tokens[index].value == TOK.rightCurly */ + /* && !assumeSorted(astInformation.funLitEndLocations).equalRange( */ + /* tokens[index].index) */ + /* .empty) */ + /* { */ + /* return; */ + /* } */ + + /* simpleNewline(); */ + + /* if (!justAddedExtraNewline && index > 0 && hasCurrent */ + /* && tokens[index].line - tokenEndLine(tokens[index - 1]) > 1) */ + /* { */ + /* simpleNewline(); */ + /* } */ + + /* justAddedExtraNewline = false; */ + /* currentLineLength = 0; */ + + /* if (hasCurrent) */ + /* { */ + /* if (currentIs(TOK.else_)) */ + /* { */ + /* immutable i = indents.indentToMostRecent(TOK.if_); */ + /* immutable v = indents.indentToMostRecent(TOK.version_); */ + /* immutable mostRecent = max(i, v); */ + /* if (mostRecent != -1) */ + /* indentLevel = mostRecent; */ + /* } */ + /* else if (currentIs(TOK.identifier) && peekIs(TOK.colon)) */ + /* { */ + /* if (peekBackIs(TOK.rightCurly, true) || peekBackIs(TOK.semicolon, true)) */ + /* indents.popTempIndents(); */ + /* immutable l = indents.indentToMostRecent(TOK.switch_); */ + /* if (l != -1 && config.dfmt_align_switch_statements == OptionalBoolean.t) */ + /* indentLevel = l; */ + /* else if (astInformation.structInfoSortedByEndLocation */ + /* .canFind!(st => st.startLocation < current.index && current.index < st */ + /* .endLocation)) */ + /* { */ + /* immutable l2 = indents.indentToMostRecent(TOK.leftCurly); */ + /* assert(l2 != -1, "Recent '{' is not found despite being in struct initializer"); */ + /* indentLevel = l2 + 1; */ + /* } */ + /* else if ((config.dfmt_compact_labeled_statements == OptionalBoolean.f */ + /* || !isBlockHeader(2) || peek2Is(TOK.if_)) && !indents.topIs( */ + /* TOK.rightBracket)) */ + /* { */ + /* immutable l2 = indents.indentToMostRecent(TOK.leftCurly); */ + /* indentLevel = l2 != -1 ? l2 : indents.indentLevel - 1; */ + /* } */ + /* else */ + /* indentLevel = indents.indentLevel; */ + /* } */ + /* else if (currentIs(TOK.case_) || currentIs(TOK.default_)) */ + /* { */ + + /* if (peekBackIs(TOK.rightCurly, true) || peekBackIs(TOK.semicolon, true) /** */ + /* * The following code is valid and should be indented flatly */ + /* * case A: */ + /* * case B: */ + /* *1/ */ + /* || peekBackIs(TOK.colon, true)) */ + /* { */ + /* indents.popTempIndents(); */ + /* if (indents.topIs(TOK.case_)) */ + /* indents.pop(); */ + /* } */ + /* immutable l = indents.indentToMostRecent(TOK.switch_); */ + /* if (l != -1) */ + /* indentLevel = config.dfmt_align_switch_statements == OptionalBoolean.t */ + /* ? l : indents.indentLevel; */ + /* } */ + /* else if (currentIs(TOK.rightParenthesis)) */ + /* { */ + /* if (indents.topIs(TOK.leftParenthesis)) */ + /* indents.pop(); */ + /* indentLevel = indents.indentLevel; */ + /* } */ + /* else if (currentIs(TOK.leftCurly)) */ + /* { */ + /* indents.popWrapIndents(); */ + /* if ((peekBackIsSlashSlash() && peekBack2Is(TOK.semicolon)) || indents.topIs( */ + /* TOK.rightBracket)) */ + /* { */ + /* indents.popTempIndents(); */ + /* indentLevel = indents.indentLevel; */ + /* } */ + /* } */ + /* else if (currentIs(TOK.rightCurly)) */ + /* { */ + /* indents.popTempIndents(); */ + /* while (indents.topIsOneOf(TOK.case_, TOK.at, tok.static_)) */ + /* indents.pop(); */ + /* if (indents.topIs(TOK.leftCurly)) */ + /* { */ + /* indentLevel = indents.indentToMostRecent(TOK.leftCurly); */ + /* indents.pop(); */ + /* } */ + /* if (indents.topIsOneOf(TOK.try_, TOK.catch_)) */ + /* { */ + /* indents.pop(); */ + /* } */ + /* else */ + /* while (sBraceDepth == 0 && indents.topIsTemp() */ + /* && ((!indents.topIsOneOf(TOK.else_, TOK.if_, */ + /* TOK.static_, TOK.version_)) || !peekIs(TOK.else_))) */ + /* { */ + /* indents.pop(); */ + /* } */ + /* } */ + /* else if (currentIs(TOK.rightBracket)) */ + /* { */ + /* indents.popWrapIndents(); */ + /* if (indents.topIs(TOK.rightBracket)) */ + /* { */ + /* indents.pop(); */ + /* } */ + /* // Find the initial indentation of constructs like "if" and */ + /* // "foreach" without removing them from the stack, since they */ + /* // still can be used later to indent "else". */ + /* auto savedIndents = IndentStack(config); */ + /* while (indents.length >= 0 && indents.topIsTemp) */ + /* { */ + /* savedIndents.push(indents.top, indents.topDetails); */ + /* indents.pop; */ + /* } */ + /* indentLevel = indents.indentLevel; */ + /* while (savedIndents.length > 0) */ + /* { */ + /* indents.push(savedIndents.top, savedIndents.topDetails); */ + /* savedIndents.pop; */ + /* } */ + /* } */ + /* else if (astInformation.attributeDeclarationLines.canFindIndex(current.line)) */ + /* { */ + /* if (config.dfmt_outdent_attributes == OptionalBoolean.t) */ + /* { */ + /* immutable l = indents.indentToMostRecent(TOK.leftCurly); */ + /* if (l != -1) */ + /* indentLevel = l; */ + /* } */ + /* else */ + /* { */ + /* if (indents.topIs(TOK.at)) */ + /* indents.pop(); */ + /* indentLevel = indents.indentLevel; */ + /* } */ + /* } */ + /* else if (currentIs(TOK.catch_) || currentIs(TOK.finally_)) */ + /* { */ + /* indentLevel = indents.indentLevel; */ + /* } */ + /* else */ + /* { */ + /* if (indents.topIsTemp() && (peekBackIsOneOf(true, TOK.rightCurly, */ + /* TOK.semicolon) && !indents.topIs(TOK.semicolon))) */ + /* indents.popTempIndents(); */ + /* indentLevel = indents.indentLevel; */ + /* } */ + /* indent(); */ + /* } */ + /* parenDepthOnLine = 0; */ + /* } */ + + /* void write(string str) */ + /* { */ + /* currentLineLength += str.length; */ + /* output.put(str); */ + /* } */ + + /* void writeToken() */ + /* { */ + /* import std.range : retro; */ + /* import std.algorithm.searching : countUntil; */ + /* import std.algorithm.iteration : joiner; */ + /* import std.string : lineSplitter; */ + + /* if (current.text is null) */ + /* { */ + /* immutable s = str(current.value); */ + /* currentLineLength += s.length; */ + /* output.put(str(current.value)); */ + /* } */ + /* else */ + /* { */ + /* output.put(current.text.lineSplitter.joiner(eolString)); */ + /* switch (current.value) */ + /* { */ + /* case TOK.string_: */ + /* immutable o = current.text.retro().countUntil('\n'); */ + /* if (o == -1) */ + /* { */ + /* currentLineLength += current.text.length; */ + /* } */ + /* else */ + /* { */ + /* currentLineLength = cast(uint) o; */ + /* } */ + /* break; */ + /* default: */ + /* currentLineLength += current.text.length; */ + /* break; */ + /* } */ + /* } */ + /* index++; */ + /* } */ + + /* void writeParens(bool spaceAfter) */ + /* in */ + /* { */ + /* assert(currentIs(TOK.leftParenthesis), str(current.value)); */ + /* } */ + /* do */ + /* { */ + /* immutable int depth = parenDepth; */ + /* immutable int startingNiBraceDepth = niBraceDepth; */ + /* immutable int startingSBraceDepth = sBraceDepth; */ + /* parenDepth = 0; */ + + /* do */ + /* { */ + /* spaceAfterParens = spaceAfter; */ + /* if (currentIs(TOK.semicolon) && niBraceDepth <= startingNiBraceDepth */ + /* && sBraceDepth <= startingSBraceDepth) */ + /* { */ + /* if (currentLineLength >= config.dfmt_soft_max_line_length) */ + /* { */ + /* pushWrapIndent(); */ + /* writeToken(); */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* writeToken(); */ + /* if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.semicolon)) */ + /* write(" "); */ + /* } */ + /* } */ + /* else */ + /* formatStep(); */ + /* } */ + /* while (hasCurrent && parenDepth > 0); */ + + /* if (indents.topIs(TOK.not)) */ + /* indents.pop(); */ + /* parenDepth = depth; */ + /* spaceAfterParens = spaceAfter; */ + /* } */ + + /* void indent() */ + /* { */ + /* import dfmt.editorconfig : IndentStyle; */ + + /* if (config.indent_style == IndentStyle.tab) */ + /* { */ + /* foreach (i; 0 .. indentLevel) */ + /* { */ + /* currentLineLength += config.tab_width; */ + /* output.put("\t"); */ + /* } */ + /* } */ + /* else */ + /* { */ + /* foreach (i; 0 .. indentLevel) */ + /* foreach (j; 0 .. config.indent_size) */ + /* { */ + /* output.put(" "); */ + /* currentLineLength++; */ + /* } */ + /* } */ + /* } */ + + /* void pushWrapIndent(TOK type = TOK.error) */ + /* { */ + /* immutable t = type == TOK.error ? tokens[index].value : type; */ + /* IndentStack.Details detail; */ + /* detail.wrap = isWrapIndent(t); */ + /* detail.temp = isTempIndent(t); */ + /* pushWrapIndent(t, detail); */ + /* } */ + + /* void pushWrapIndent(TOK type, IndentStack.Details detail) */ + /* { */ + /* if (parenDepth == 0) */ + /* { */ + /* if (indents.wrapIndents == 0) */ + /* indents.push(type, detail); */ + /* } */ + /* else if (indents.wrapIndents < 1) */ + /* indents.push(type, detail); */ + /* } */ + + /* void writeSpace() */ + /* { */ + /* if (onNextLine) */ + /* { */ + /* newline(); */ + /* } */ + /* else */ + /* { */ + /* write(" "); */ + /* } */ + /* } */ + + /* const pure @safe @nogc: */ + + /* size_t expressionEndIndex(size_t i, bool matchComma = false) nothrow */ + /* { */ + /* immutable bool braces = i < tokens.length && tokens[i].value == TOK.leftCurly; */ + /* immutable bool brackets = i < tokens.length && tokens[i].value == TOK.leftBracket; */ + /* immutable d = depths[i]; */ + /* while (true) */ + /* { */ + /* if (i >= tokens.length) */ + /* break; */ + /* if (depths[i] < d) */ + /* break; */ + /* if (!braces && !brackets && matchComma && depths[i] == d && tokens[i].value == TOK */ + /* .comma) */ + /* break; */ + /* if (!braces && !brackets && (tokens[i].value == TOK.semicolon || tokens[i].value == TOK */ + /* .leftCurly)) */ + /* break; */ + /* i++; */ + /* } */ + /* return i; */ + /* } */ + + /* /// Returns: true when the expression starting at index goes over the line length limit. */ + /* /// Uses matching `{}` or `[]` or otherwise takes everything up until a semicolon or opening brace using expressionEndIndex. */ + /* bool isMultilineAt(size_t i, bool matchComma = false) */ + /* { */ + /* import std.algorithm : map, sum, canFind; */ + + /* auto e = expressionEndIndex(i, matchComma); */ + /* immutable int l = currentLineLength + tokens[i .. e].map!(a => tokenLength(a)).sum(); */ + /* return l > config.dfmt_soft_max_line_length || tokens[i .. e].canFind!( */ + /* a => a.value == TOK.comment || isBlockHeaderToken(a.value))(); */ + /* } */ + + /* bool peekIsKeyword() nothrow */ + /* { */ + /* return index + 1 < tokens.length && isKeyword(tokens[index + 1].value); */ + /* } */ + + /* bool peekIsBasicType() nothrow */ + /* { */ + /* return index + 1 < tokens.length && isBasicType(tokens[index + 1].value); */ + /* } */ + + /* bool peekIsLabel() nothrow */ + /* { */ + /* return peekIs(TOK.identifier) && peek2Is(TOK.colon); */ + /* } */ + + /* int currentTokenLength() */ + /* { */ + /* return tokenLength(tokens[index]); */ + /* } */ + + /* int nextTokenLength() */ + /* { */ + /* immutable size_t i = index + 1; */ + /* if (i >= tokens.length) */ + /* return INVALID_TOKEN_LENGTH; */ + /* return tokenLength(tokens[i]); */ + /* } */ bool hasCurrent() nothrow const { return index < tokens.length; } - ref current() nothrow - in - { - assert(hasCurrent); - } - do - { - return tokens[index]; - } + /* ref current() nothrow */ + /* in */ + /* { */ + /* assert(hasCurrent); */ + /* } */ + /* do */ + /* { */ + /* return tokens[index]; */ + /* } */ - const(Token) peekBack(uint distance = 1) nothrow - { - assert(index >= distance, "Trying to peek before the first token"); - return tokens[index - distance]; - } + /* const(Token) peekBack(uint distance = 1) nothrow */ + /* { */ + /* assert(index >= distance, "Trying to peek before the first token"); */ + /* return tokens[index - distance]; */ + /* } */ - bool peekBackIsLiteralOrIdent() nothrow - { - if (index == 0) - return false; - switch (tokens[index - 1].type) - { - case tok!"doubleLiteral": - case tok!"floatLiteral": - case tok!"idoubleLiteral": - case tok!"ifloatLiteral": - case tok!"intLiteral": - case tok!"longLiteral": - case tok!"realLiteral": - case tok!"irealLiteral": - case tok!"uintLiteral": - case tok!"ulongLiteral": - case tok!"characterLiteral": - case tok!"identifier": - case tok!"stringLiteral": - case tok!"wstringLiteral": - case tok!"dstringLiteral": - case tok!"true": - case tok!"false": - return true; - default: - return false; - } - } + /* bool peekBackIsLiteralOrIdent() nothrow */ + /* { */ + /* if (index == 0) */ + /* return false; */ + /* switch (tokens[index - 1].value) */ + /* { */ + /* case TOK.int32Literal: */ + /* case TOK.uns32Literal: */ + /* case TOK.int64Literal: */ + /* case TOK.uns64Literal: */ + /* case TOK.int128Literal: */ + /* case TOK.uns128Literal: */ + /* case TOK.float32Literal: */ + /* case TOK.float64Literal: */ + /* case TOK.float80Literal: */ + /* case TOK.imaginary32Literal: */ + /* case TOK.imaginary64Literal: */ + /* case TOK.imaginary80Literal: */ + /* case TOK.charLiteral: */ + /* case TOK.wcharLiteral: */ + /* case TOK.dcharLiteral: */ + /* case TOK.identifier: */ + /* case TOK.string_: */ + /* return true; */ + /* default: */ + /* return false; */ + /* } */ + /* } */ - bool peekIsLiteralOrIdent() nothrow - { - if (index + 1 >= tokens.length) - return false; - switch (tokens[index + 1].type) - { - case tok!"doubleLiteral": - case tok!"floatLiteral": - case tok!"idoubleLiteral": - case tok!"ifloatLiteral": - case tok!"intLiteral": - case tok!"longLiteral": - case tok!"realLiteral": - case tok!"irealLiteral": - case tok!"uintLiteral": - case tok!"ulongLiteral": - case tok!"characterLiteral": - case tok!"identifier": - case tok!"stringLiteral": - case tok!"wstringLiteral": - case tok!"dstringLiteral": - return true; - default: - return false; - } - } + /* bool peekIsLiteralOrIdent() nothrow */ + /* { */ + /* if (index + 1 >= tokens.length) */ + /* return false; */ + /* switch (tokens[index + 1].value) */ + /* { */ + /* case TOK.int32Literal: */ + /* case TOK.uns32Literal: */ + /* case TOK.int64Literal: */ + /* case TOK.uns64Literal: */ + /* case TOK.int128Literal: */ + /* case TOK.uns128Literal: */ + /* case TOK.float32Literal: */ + /* case TOK.float64Literal: */ + /* case TOK.float80Literal: */ + /* case TOK.imaginary32Literal: */ + /* case TOK.imaginary64Literal: */ + /* case TOK.imaginary80Literal: */ + /* case TOK.charLiteral: */ + /* case TOK.wcharLiteral: */ + /* case TOK.dcharLiteral: */ + /* case TOK.identifier: */ + /* case TOK.string_: */ + /* return true; */ + /* default: */ + /* return false; */ + /* } */ + /* } */ - bool peekBackIs(IdType tokenType, bool ignoreComments = false) nothrow - { - return peekImplementation(tokenType, -1, ignoreComments); - } + /* bool peekBackIs(TOK tokenType, bool ignoreComments = false) nothrow */ + /* { */ + /* return peekImplementation(tokenType, -1, ignoreComments); */ + /* } */ - bool peekBackIsKeyword(bool ignoreComments = true) nothrow - { - if (index == 0) - return false; - auto i = index - 1; - if (ignoreComments) - while (tokens[i].type == tok!"comment") - { - if (i == 0) - return false; - i--; - } - return isKeyword(tokens[i].type); - } + /* bool peekBackIsKeyword(bool ignoreComments = true) nothrow */ + /* { */ + /* if (index == 0) */ + /* return false; */ + /* auto i = index - 1; */ + /* if (ignoreComments) */ + /* while (tokens[i].value == TOK.comment) */ + /* { */ + /* if (i == 0) */ + /* return false; */ + /* i--; */ + /* } */ + /* return isKeyword(tokens[i].value); */ + /* } */ - bool peekBackIsOperator() nothrow - { - return index == 0 ? false : isOperator(tokens[index - 1].type); - } + /* bool peekBackIsOperator() nothrow */ + /* { */ + /* return index == 0 ? false : isOperator(tokens[index - 1].value); */ + /* } */ - bool peekBackIsOneOf(bool ignoreComments, IdType[] tokenTypes...) nothrow - { - if (index == 0) - return false; - auto i = index - 1; - if (ignoreComments) - while (tokens[i].type == tok!"comment") - { - if (i == 0) - return false; - i--; - } - immutable t = tokens[i].type; - foreach (tt; tokenTypes) - if (tt == t) - return true; - return false; - } + /* bool peekBackIsOneOf(bool ignoreComments, TOK[] tokenTypes...) nothrow */ + /* { */ + /* if (index == 0) */ + /* return false; */ + /* auto i = index - 1; */ + /* if (ignoreComments) */ + /* while (tokens[i].value == TOK.comment) */ + /* { */ + /* if (i == 0) */ + /* return false; */ + /* i--; */ + /* } */ + /* immutable t = tokens[i].value; */ + /* foreach (tt; tokenTypes) */ + /* if (tt == t) */ + /* return true; */ + /* return false; */ + /* } */ - bool peekBack2Is(IdType tokenType, bool ignoreComments = false) nothrow - { - return peekImplementation(tokenType, -2, ignoreComments); - } + /* bool peekBack2Is(TOK tokenType, bool ignoreComments = false) nothrow */ + /* { */ + /* return peekImplementation(tokenType, -2, ignoreComments); */ + /* } */ - bool peekImplementation(IdType tokenType, int n, bool ignoreComments = true) nothrow - { - auto i = index + n; - if (ignoreComments) - while (n != 0 && i < tokens.length && tokens[i].type == tok!"comment") - i = n > 0 ? i + 1 : i - 1; - return i < tokens.length && tokens[i].type == tokenType; - } + /* bool peekImplementation(TOK tokenType, int n, bool ignoreComments = true) nothrow */ + /* { */ + /* auto i = index + n; */ + /* if (ignoreComments) */ + /* while (n != 0 && i < tokens.length && tokens[i].value == TOK.comment) */ + /* i = n > 0 ? i + 1 : i - 1; */ + /* return i < tokens.length && tokens[i].value == tokenType; */ + /* } */ - bool peek2Is(IdType tokenType, bool ignoreComments = true) nothrow - { - return peekImplementation(tokenType, 2, ignoreComments); - } + /* bool peek2Is(TOK tokenType, bool ignoreComments = true) nothrow */ + /* { */ + /* return peekImplementation(tokenType, 2, ignoreComments); */ + /* } */ - bool peekIsOperator() nothrow - { - return index + 1 < tokens.length && isOperator(tokens[index + 1].type); - } + /* bool peekIsOperator() nothrow */ + /* { */ + /* return index + 1 < tokens.length && isOperator(tokens[index + 1].value); */ + /* } */ - bool peekIs(IdType tokenType, bool ignoreComments = true) nothrow - { - return peekImplementation(tokenType, 1, ignoreComments); - } + /* bool peekIs(TOK tokenType, bool ignoreComments = true) nothrow */ + /* { */ + /* return peekImplementation(tokenType, 1, ignoreComments); */ + /* } */ - bool peekIsBody() nothrow - { - return index + 1 < tokens.length && tokens[index + 1].text == "body"; - } + /* bool peekIsBody() nothrow */ + /* { */ + /* return index + 1 < tokens.length && tokens[index + 1].text == "body"; */ + /* } */ - bool peekBackIsFunctionDeclarationEnding() nothrow - { - return peekBackIsOneOf(false, tok!")", tok!"const", tok!"immutable", - tok!"inout", tok!"shared", tok!"@", tok!"pure", tok!"nothrow", - tok!"return", tok!"scope"); - } + /* bool peekBackIsFunctionDeclarationEnding() nothrow */ + /* { */ + /* return peekBackIsOneOf(false, TOK.rightParenthesis, TOK.const_, TOK.immutable_, */ + /* TOK.inout_, TOK.shared_, TOK.at, TOK.pure_, TOK.nothrow_, */ + /* TOK.return_, TOK.scope_); */ + /* } */ - bool peekBackIsSlashSlash() nothrow - { - return index > 0 && tokens[index - 1].type == tok!"comment" - && tokens[index - 1].text[0 .. 2] == "//"; - } + /* bool peekBackIsSlashSlash() nothrow */ + /* { */ + /* return index > 0 && tokens[index - 1].value == TOK.comment */ + /* && tokens[index - 1].text[0 .. 2] == "//"; */ + /* } */ - bool currentIs(IdType tokenType) nothrow - { - return hasCurrent && tokens[index].type == tokenType; - } + /* bool currentIs(TOK tokenType) nothrow */ + /* { */ + /* return hasCurrent && tokens[index].value == tokenType; */ + /* } */ - bool onNextLine() @nogc nothrow pure @safe - { - import dfmt.editorconfig : OptionalBoolean; - import std.algorithm.searching : count; - import std.string : representation; + /* bool onNextLine() @nogc nothrow pure @safe */ + /* { */ + /* import dfmt.editorconfig : OptionalBoolean; */ + /* import std.algorithm.searching : count; */ + /* import std.string : representation; */ - if (config.dfmt_keep_line_breaks == OptionalBoolean.f || index <= 0) - { - return false; - } - // To compare whether 2 tokens are on same line, we need the end line - // of the first token (tokens[index - 1]) and the start line of the - // second one (tokens[index]). If a token takes multiple lines (e.g. a - // multi-line string), we can sum the number of the newlines in the - // token and tokens[index - 1].line, the start line. - const previousTokenEndLineNo = tokens[index - 1].line - + tokens[index - 1].text.representation.count('\n'); + /* if (config.dfmt_keep_line_breaks == OptionalBoolean.f || index <= 0) */ + /* { */ + /* return false; */ + /* } */ + /* // To compare whether 2 tokens are on same line, we need the end line */ + /* // of the first token (tokens[index - 1]) and the start line of the */ + /* // second one (tokens[index]). If a token takes multiple lines (e.g. a */ + /* // multi-line string), we can sum the number of the newlines in the */ + /* // token and tokens[index - 1].line, the start line. */ + /* const previousTokenEndLineNo = tokens[index - 1].line */ + /* + tokens[index - 1].text.representation.count('\n'); */ - return previousTokenEndLineNo < tokens[index].line; - } + /* return previousTokenEndLineNo < tokens[index].line; */ + /* } */ - /// Bugs: not unicode correct - size_t tokenEndLine(const Token t) - { - import std.algorithm : count; + /* /// Bugs: not unicode correct */ + /* size_t tokenEndLine(const Token t) */ + /* { */ + /* import std.algorithm : count; */ - switch (t.type) - { - case tok!"comment": - case tok!"stringLiteral": - case tok!"wstringLiteral": - case tok!"dstringLiteral": - return t.line + t.text.count('\n'); - default: - return t.line; - } - } + /* switch (t.value) */ + /* { */ + /* case TOK.comment: */ + /* case TOK.string_: */ + /* return t.line + t.text.count('\n'); */ + /* default: */ + /* return t.line; */ + /* } */ + /* } */ - bool isBlockHeaderToken(const IdType t) - { - return t == tok!"for" || t == tok!"foreach" || t == tok!"foreach_reverse" - || t == tok!"while" || t == tok!"if" || t == tok!"in"|| t == tok!"out" - || t == tok!"do" || t == tok!"catch" || t == tok!"with" - || t == tok!"synchronized" || t == tok!"scope" || t == tok!"debug"; - } + /* bool isBlockHeaderToken(const TOK t) */ + /* { */ + /* return t == TOK.for_ || t == TOK.foreach_ || t == TOK.foreach_reverse_ */ + /* || t == TOK.while_ || t == TOK.if_ || t == TOK.in_ || t == TOK.out_ */ + /* || t == TOK.do_ || t == TOK.catch_ || t == TOK.with_ */ + /* || t == TOK.synchronized_ || t == TOK.scope_ || t == TOK.debug_; */ + /* } */ - bool isBlockHeader(int i = 0) nothrow - { - if (i + index < 0 || i + index >= tokens.length) - return false; - const t = tokens[i + index].type; - bool isExpressionContract; + /* bool isBlockHeader(int i = 0) nothrow */ + /* { */ + /* if (i + index < 0 || i + index >= tokens.length) */ + /* return false; */ + /* const t = tokens[i + index].value; */ + /* bool isExpressionContract; */ - if (i + index + 3 < tokens.length) - { - isExpressionContract = (t == tok!"in" && peekImplementation(tok!"(", i + 1, true)) - || (t == tok!"out" && (peekImplementation(tok!"(", i + 1, true) - && (peekImplementation(tok!";", i + 2, true) - || (peekImplementation(tok!"identifier", i + 2, true) - && peekImplementation(tok!";", i + 3, true))))); - } + /* if (i + index + 3 < tokens.length) */ + /* { */ + /* isExpressionContract = (t == TOK.in_ && peekImplementation(TOK.leftParenthesis, i + 1, true)) */ + /* || (t == TOK.out_ && (peekImplementation(TOK.leftParenthesis, i + 1, true) */ + /* && (peekImplementation(TOK.semicolon, i + 2, true) */ + /* || (peekImplementation(TOK.identifier, i + 2, true) */ + /* && peekImplementation(TOK.semicolon, i + 3, true))))); */ + /* } */ - return isBlockHeaderToken(t) && !isExpressionContract; - } + /* return isBlockHeaderToken(t) && !isExpressionContract; */ + /* } */ - bool isSeparationToken(IdType t) nothrow - { - return t == tok!"," || t == tok!";" || t == tok!":" || t == tok!"(" - || t == tok!")" || t == tok!"[" || t == tok!"]" || t == tok!"{" || t == tok!"}"; - } -} - -bool canFindIndex(const size_t[] items, size_t index, size_t* pos = null) pure @safe @nogc -{ - import std.range : assumeSorted; - if (!pos) - { - return !assumeSorted(items).equalRange(index).empty; - } - else - { - auto trisection_result = assumeSorted(items).trisect(index); - if (trisection_result[1].length == 1) - { - *pos = trisection_result[0].length; - return true; - } - else if (trisection_result[1].length == 0) - { - return false; - } - else - { - assert(0, "the constraint of having unique locations has been violated"); - } - } + /* bool isSeparationToken(TOK t) nothrow */ + /* { */ + /* return t == TOK.comma || t == TOK.semicolon || t == TOK.colon */ + /* || t == TOK.leftParenthesis || t == TOK.rightParenthesis */ + /* || t == TOK.leftBracket || t == TOK.rightBracket */ + /* || t == TOK.leftCurly || t == TOK.rightCurly; */ + /* } */ + /* } */ + + /* bool canFindIndex(const size_t[] items, size_t index, size_t* pos = null) pure @safe @nogc */ + /* { */ + /* import std.range : assumeSorted; */ + + /* if (!pos) */ + /* { */ + /* return !assumeSorted(items).equalRange(index).empty; */ + /* } */ + /* else */ + /* { */ + /* auto trisection_result = assumeSorted(items).trisect(index); */ + /* if (trisection_result[1].length == 1) */ + /* { */ + /* *pos = trisection_result[0].length; */ + /* return true; */ + /* } */ + /* else if (trisection_result[1].length == 0) */ + /* { */ + /* return false; */ + /* } */ + /* else */ + /* { */ + /* assert(0, "the constraint of having unique locations has been violated"); */ + /* } */ + /* } */ } From 3ac8e5afa6e4ead138f11a9e3d03fc4614793c43 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 19 Oct 2023 21:27:17 +0530 Subject: [PATCH 05/24] feat: implement visitors and writers Signed-off-by: Prajwal S N --- .gitmodules | 3 - dub.json | 17 +- libdparse | 1 - src/dfmt/ast.d | 3656 ++++++++++++++++++++++++++++++++++++++++ src/dfmt/ast_info.d | 492 ------ src/dfmt/formatter.d | 2388 +------------------------- src/dfmt/indentation.d | 392 ----- src/dfmt/main.d | 399 +++-- src/dfmt/tokens.d | 247 --- src/dfmt/wrapping.d | 182 -- 10 files changed, 3870 insertions(+), 3907 deletions(-) delete mode 160000 libdparse create mode 100644 src/dfmt/ast.d delete mode 100644 src/dfmt/ast_info.d delete mode 100644 src/dfmt/indentation.d delete mode 100644 src/dfmt/tokens.d delete mode 100644 src/dfmt/wrapping.d diff --git a/.gitmodules b/.gitmodules index 5cf3ca7..4e983f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "libdparse"] - path = libdparse - url = https://github.com/dlang-community/libdparse.git [submodule "stdx-allocator"] path = stdx-allocator url = https://github.com/dlang-community/stdx-allocator diff --git a/dub.json b/dub.json index 09b59ee..515d64d 100644 --- a/dub.json +++ b/dub.json @@ -4,18 +4,17 @@ "targetType": "autodetect", "license": "BSL-1.0", "dependencies": { - "libdparse": ">=0.19.2 <1.0.0", - "dmd": "~>2.105.2" + "dmd": "~>2.106.0-beta.1" }, - "targetPath" : "bin/", - "targetName" : "dfmt", - "stringImportPaths" : [ - "bin" + "targetPath": "bin/", + "targetName": "dfmt", + "stringImportPaths": [ + "bin" ], - "versions" : [ + "versions": [ "built_with_dub" ], - "preBuildCommands" : [ - "$DC -run \"$PACKAGE_DIR/dubhash.d\"" + "preBuildCommands": [ + "$DC -run \"$PACKAGE_DIR/dubhash.d\"" ] } diff --git a/libdparse b/libdparse deleted file mode 160000 index fe6d1e3..0000000 --- a/libdparse +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fe6d1e38fb4fc04323170389cfec67ed7fd4e24a diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d new file mode 100644 index 0000000..737debd --- /dev/null +++ b/src/dfmt/ast.d @@ -0,0 +1,3656 @@ +module dfmt.ast; + +import dmd.visitor; +import dmd.astcodegen; +import dmd.astenums; +import dmd.tokens; +import dmd.parse; +import dmd.mtype; +import dmd.identifier; +import dmd.hdrgen; +import dmd.init; +import dmd.rootobject; +import dmd.target; +import dmd.root.string : toDString; +import dfmt.config; +import dfmt.editorconfig; +import std.range; +import std.format : format; +import std.stdio : writeln, File; + +extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor +{ + File.LockingTextWriter buf; + const Config* config; + string eol; + uint depth; + bool declstring; // set while declaring alias for string,wstring or dstring + + this(File.LockingTextWriter buf, Config* config) + { + this.buf = buf; + this.config = config; + // Set newline character + final switch (config.end_of_line) + { + case EOL.lf: + eol = "\n"; + break; + case EOL.cr: + eol = "\r"; + break; + case EOL.crlf: + eol = "\r\n"; + break; + case EOL._default: + version (Windows) + { + eol = "\r\n"; + } + else + { + eol = "\n"; + } + break; + case EOL._unspecified: + assert(false, "end of line character is unspecified"); + } + } + + alias visit = SemanticTimeTransitiveVisitor.visit; + + void indent() + { + if (depth) + { + auto indent = config.indent_style == IndentStyle.space ? ' '.repeat() + .take(depth * 4) : '\t'.repeat().take(depth); + buf.put(indent.array); + } + } + + pragma(inline) + void newline() + { + buf.put(eol); + } + + /******************************************* + * Helpers to write different AST nodes to buffer + */ + void writeStc(StorageClass stc) + { + bool writeSpace = false; + + if (stc & ASTCodegen.STC.scopeinferred) + { + stc &= ~(ASTCodegen.STC.scope_ | ASTCodegen.STC.scopeinferred); + } + if (stc & ASTCodegen.STC.returninferred) + { + stc &= ~(ASTCodegen.STC.return_ | ASTCodegen.STC.returninferred); + } + + // Put scope ref return into a standard order + string rrs; + const isout = (stc & ASTCodegen.STC.out_) != 0; + final switch (buildScopeRef(stc)) + { + case ScopeRef.None: + case ScopeRef.Scope: + case ScopeRef.Ref: + case ScopeRef.Return: + break; + + case ScopeRef.ReturnScope: + rrs = "return scope"; + goto L1; + case ScopeRef.ReturnRef: + rrs = isout ? "return out" : "return ref"; + goto L1; + case ScopeRef.RefScope: + rrs = isout ? "out scope" : "ref scope"; + goto L1; + case ScopeRef.ReturnRef_Scope: + rrs = isout ? "return out scope" : "return ref scope"; + goto L1; + case ScopeRef.Ref_ReturnScope: + rrs = isout ? "out return scope" : "ref return scope"; + goto L1; + L1: + buf.put(rrs); + writeSpace = true; + stc &= ~( + ASTCodegen.STC.out_ | ASTCodegen.STC.scope_ | ASTCodegen.STC.ref_ | ASTCodegen + .STC.return_); + break; + } + + while (stc) + { + const s = stcToString(stc); + if (!s.length) + break; + if (writeSpace) + buf.put(' '); + writeSpace = true; + buf.put(s); + } + + if (writeSpace) + buf.put(' '); + + } + + void writeFloat(Type type, real value) + { + import dmd.root.ctfloat; + import core.stdc.string : strlen; + + /** sizeof(value)*3 is because each byte of mantissa is max + of 256 (3 characters). The string will be "-M.MMMMe-4932". + (ie, 8 chars more than mantissa). Plus one for trailing \0. + Plus one for rounding. */ + const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; + char[BUFFER_LEN] buffer = void; + CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'g', value); + assert(strlen(buffer.ptr) < BUFFER_LEN); + if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') + buffer.ptr[strlen(buffer.ptr) - 1] = char.init; + buf.put(buffer.array); + + if (type) + { + Type t = type.toBasetype(); + switch (t.ty) + { + case Tfloat32: + case Timaginary32: + case Tcomplex32: + buf.put('F'); + break; + case Tfloat80: + case Timaginary80: + case Tcomplex80: + buf.put('L'); + break; + default: + break; + } + if (t.isimaginary()) + buf.put('i'); + } + } + + void writeExpr(ASTCodegen.Expression e) + { + import dmd.hdrgen : EXPtoString; + + void visit(ASTCodegen.Expression e) + { + buf.put(EXPtoString(e.op)); + } + + void visitInteger(ASTCodegen.IntegerExp e) + { + auto v = e.toInteger(); + if (e.type) + { + Type t = e.type; + L1: + switch (t.ty) + { + case Tenum: + { + TypeEnum te = cast(TypeEnum) t; + auto sym = te.sym; + if (sym && sym.members) + { + foreach (em; *sym.members) + { + if ((cast(ASTCodegen.EnumMember) em).value.toInteger == v) + { + buf.put(format("%s.%s", sym.toString(), em.ident.toString())); + return; + } + } + } + + buf.put(format("cast(%s)", te.sym.toString())); + t = te.sym.memtype; + goto L1; + } + case Tchar: + case Twchar: + case Tdchar: + { + buf.put(cast(dchar) v); + break; + } + case Tint8: + buf.put("cast(byte)"); + goto L2; + case Tint16: + buf.put("cast(short)"); + goto L2; + case Tint32: + L2: + buf.put(format("%d", cast(int) v)); + break; + case Tuns8: + buf.put("cast(ubyte)"); + goto case Tuns32; + case Tuns16: + buf.put("cast(ushort)"); + goto case Tuns32; + case Tuns32: + buf.put(format("%uu", cast(uint) v)); + break; + case Tint64: + if (v == long.min) + { + // https://issues.dlang.org/show_bug.cgi?id=23173 + // This is a special case because - is not part of the + // integer literal and 9223372036854775808L overflows a long + buf.put("cast(long)-9223372036854775808"); + } + else + { + buf.put(format("%lldL", v)); + } + break; + case Tuns64: + buf.put(format("%lluLU", v)); + break; + case Tbool: + buf.put(v ? "true" : "false"); + break; + case Tpointer: + buf.put("cast("); + buf.put(t.toString()); + buf.put(')'); + if (target.ptrsize == 8) + goto case Tuns64; + else if (target.ptrsize == 4 || + target.ptrsize == 2) + goto case Tuns32; + else + assert(0); + + case Tvoid: + buf.put("cast(void)0"); + break; + default: + break; + } + } + else if (v & 0x8000000000000000L) + buf.put(format("0x%llx", v)); + else + buf.put(format("%lu", v)); + } + + void visitError(ASTCodegen.ErrorExp _) + { + buf.put("__error"); + } + + void visitVoidInit(ASTCodegen.VoidInitExp _) + { + buf.put("void"); + } + + void visitReal(ASTCodegen.RealExp e) + { + writeFloat(e.type, e.value); + } + + void visitComplex(ASTCodegen.ComplexExp e) + { + /* Print as: + * (re+imi) + */ + buf.put('('); + writeFloat(e.type, e.value.re); + buf.put('+'); + writeFloat(e.type, e.value.im); + buf.put("i)"); + } + + void visitIdentifier(ASTCodegen.IdentifierExp e) + { + /* writeln("writing ident"); */ + buf.put(e.ident.toString()); + } + + void visitDsymbol(ASTCodegen.DsymbolExp e) + { + buf.put(e.s.toString()); + } + + void visitThis(ASTCodegen.ThisExp _) + { + buf.put("this"); + } + + void visitSuper(ASTCodegen.SuperExp _) + { + buf.put("super"); + } + + void visitNull(ASTCodegen.NullExp _) + { + buf.put("null"); + } + + void visitString(ASTCodegen.StringExp e) + { + buf.put('"'); + foreach (i; 0 .. e.len) + { + buf.put(e.getCodeUnit(i)); + } + buf.put('"'); + if (e.postfix) + buf.put(e.postfix); + } + + void visitArrayLiteral(ASTCodegen.ArrayLiteralExp e) + { + buf.put('['); + writeArgs(e.elements, e.basis); + buf.put(']'); + } + + void visitAssocArrayLiteral(ASTCodegen.AssocArrayLiteralExp e) + { + buf.put('['); + foreach (i, key; *e.keys) + { + if (i) + buf.put(", "); + writeExprWithPrecedence(key, PREC.assign); + buf.put(':'); + auto value = (*e.values)[i]; + writeExprWithPrecedence(value, PREC.assign); + } + buf.put(']'); + } + + void visitStructLiteral(ASTCodegen.StructLiteralExp e) + { + import dmd.expression; + + buf.put(e.sd.toString()); + buf.put('('); + // CTFE can generate struct literals that contain an AddrExp pointing + // to themselves, need to avoid infinite recursion: + // struct S { this(int){ this.s = &this; } S* s; } + // const foo = new S(0); + if (e.stageflags & stageToCBuffer) + buf.put(""); + else + { + const old = e.stageflags; + e.stageflags |= stageToCBuffer; + writeArgs(e.elements); + e.stageflags = old; + } + buf.put(')'); + } + + void visitCompoundLiteral(ASTCodegen.CompoundLiteralExp e) + { + buf.put('('); + writeTypeWithIdent(e.type, null); + buf.put(')'); + writeInitializer(e.initializer); + } + + void visitType(ASTCodegen.TypeExp e) + { + writeTypeWithIdent(e.type, null); + } + + void visitScope(ASTCodegen.ScopeExp e) + { + import core.stdc.string : strlen; + + if (e.sds.isTemplateInstance()) + { + e.sds.accept(this); + } + else + { + buf.put(e.sds.kind().toDString()); + buf.put(' '); + buf.put(e.sds.toString()); + } + } + + void visitTemplate(ASTCodegen.TemplateExp e) + { + buf.put(e.td.toString()); + } + + void visitNew(ASTCodegen.NewExp e) + { + if (e.thisexp) + { + writeExprWithPrecedence(e.thisexp, PREC.primary); + buf.put('.'); + } + buf.put("new "); + writeTypeWithIdent(e.newtype, null); + if (e.arguments && e.arguments.length) + { + buf.put('('); + writeArgs(e.arguments, null, e.names); + buf.put(')'); + } + } + + void visitNewAnonClass(ASTCodegen.NewAnonClassExp e) + { + if (e.thisexp) + { + writeExprWithPrecedence(e.thisexp, PREC.primary); + buf.put('.'); + } + buf.put("new"); + buf.put(" class "); + if (e.arguments && e.arguments.length) + { + buf.put('('); + writeArgs(e.arguments); + buf.put(')'); + } + if (e.cd) + e.cd.accept(this); + } + + void visitSymOff(ASTCodegen.SymOffExp e) + { + if (e.offset) + buf.put(format("(& %s%+lld)", e.var.toString(), e.offset)); + else if (e.var.isTypeInfoDeclaration()) + buf.put(e.var.toString()); + else + buf.put(format("& %s", e.var.toString())); + } + + void visitVar(ASTCodegen.VarExp e) + { + buf.put(e.var.toString()); + } + + void visitOver(ASTCodegen.OverExp e) + { + buf.put(e.vars.ident.toString()); + } + + void visitTuple(ASTCodegen.TupleExp e) + { + if (e.e0) + { + buf.put('('); + writeExpr(e.e0); + buf.put(", AliasSeq!("); + writeArgs(e.exps); + buf.put("))"); + } + else + { + buf.put("AliasSeq!("); + writeArgs(e.exps); + buf.put(')'); + } + } + + void visitFunc(ASTCodegen.FuncExp e) + { + /* writeln("stringifying func literal"); */ + e.fd.accept(this); + } + + void visitDeclaration(ASTCodegen.DeclarationExp e) + { + /* Normal dmd execution won't reach here - regular variable declarations + * are handled in visit(ASTCodegen.ExpStatement), so here would be used only when + * we'll directly call Expression.toString() for debugging. + */ + if (e.declaration) + { + if (auto var = e.declaration.isVarDeclaration()) + { + // For debugging use: + // - Avoid printing newline. + // - Intentionally use the format (Type var;) + // which isn't correct as regular D code. + buf.put('('); + + writeVarDecl(var, false); + + buf.put(';'); + buf.put(')'); + } + else + e.declaration.accept(this); + } + } + + void visitTypeid(ASTCodegen.TypeidExp e) + { + buf.put("typeid("); + writeObject(e.obj); + buf.put(')'); + } + + void visitTraits(ASTCodegen.TraitsExp e) + { + buf.put("__traits("); + if (e.ident) + buf.put(e.ident.toString()); + if (e.args) + { + foreach (arg; *e.args) + { + buf.put(", "); + writeObject(arg); + } + } + buf.put(')'); + } + + void visitHalt(ASTCodegen.HaltExp _) + { + buf.put("halt"); + } + + void visitIs(ASTCodegen.IsExp e) + { + buf.put("is("); + writeTypeWithIdent(e.targ, e.id); + if (e.tok2 != TOK.reserved) + { + buf.put(format(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2))); + } + else if (e.tspec) + { + if (e.tok == TOK.colon) + buf.put(" : "); + else + buf.put(" == "); + writeTypeWithIdent(e.tspec, null); + } + if (e.parameters && e.parameters.length) + { + buf.put(", "); + visitTemplateParameters(e.parameters); + } + buf.put(')'); + } + + void visitUna(ASTCodegen.UnaExp e) + { + buf.put(EXPtoString(e.op)); + writeExprWithPrecedence(e.e1, precedence[e.op]); + } + + void visitLoweredAssignExp(ASTCodegen.LoweredAssignExp e) + { + visit(cast(ASTCodegen.BinExp) e); + } + + void visitBin(ASTCodegen.BinExp e) + { + writeExprWithPrecedence(e.e1, precedence[e.op]); + buf.put(' '); + buf.put(EXPtoString(e.op)); + buf.put(' '); + writeExprWithPrecedence(e.e2, cast(PREC)(precedence[e.op] + 1)); + } + + void visitComma(ASTCodegen.CommaExp e) + { + // CommaExp is generated by the compiler so it shouldn't + // appear in error messages or header files. + // For now, this treats the case where the compiler + // generates CommaExp for temporaries by calling + // the `sideeffect.copyToTemp` function. + auto ve = e.e2.isVarExp(); + + // not a CommaExp introduced for temporaries, go on + // the old path + if (!ve || !(ve.var.storage_class & STC.temp)) + { + visitBin(cast(ASTCodegen.BinExp) e); + return; + } + + // CommaExp that contain temporaries inserted via + // `copyToTemp` are usually of the form + // ((T __temp = exp), __tmp). + // Asserts are here to easily spot + // missing cases where CommaExp + // are used for other constructs + auto vd = ve.var.isVarDeclaration(); + assert(vd && vd._init); + + if (auto ei = vd._init.isExpInitializer()) + { + ASTCodegen.Expression commaExtract; + auto exp = ei.exp; + if (auto ce = exp.isConstructExp()) + commaExtract = ce.e2; + else if (auto se = exp.isStructLiteralExp()) + commaExtract = se; + + if (commaExtract) + { + writeExprWithPrecedence(commaExtract, precedence[exp.op]); + return; + } + } + + // not one of the known cases, go on the old path + visitBin(cast(ASTCodegen.BinExp) e); + return; + } + + void visitMixin(ASTCodegen.MixinExp e) + { + buf.put("mixin("); + writeArgs(e.exps); + buf.put(')'); + } + + void visitImport(ASTCodegen.ImportExp e) + { + buf.put("import("); + writeExprWithPrecedence(e.e1, PREC.assign); + buf.put(')'); + } + + void visitAssert(ASTCodegen.AssertExp e) + { + buf.put("assert("); + writeExprWithPrecedence(e.e1, PREC.assign); + if (e.msg) + { + buf.put(", "); + writeExprWithPrecedence(e.msg, PREC.assign); + } + buf.put(')'); + } + + void visitThrow(ASTCodegen.ThrowExp e) + { + buf.put("throw "); + writeExprWithPrecedence(e.e1, PREC.unary); + } + + void visitDotId(ASTCodegen.DotIdExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + if (e.arrow) + buf.put("->"); + else + buf.put('.'); + buf.put(e.ident.toString()); + } + + void visitDotTemplate(ASTCodegen.DotTemplateExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('.'); + buf.put(e.td.toString()); + } + + void visitDotVar(ASTCodegen.DotVarExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('.'); + buf.put(e.var.toString()); + } + + void visitDotTemplateInstance(ASTCodegen.DotTemplateInstanceExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('.'); + e.ti.accept(this); + } + + void visitDelegate(ASTCodegen.DelegateExp e) + { + buf.put('&'); + if (!e.func.isNested() || e.func.needThis()) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('.'); + } + buf.put(e.func.toString()); + } + + void visitDotType(ASTCodegen.DotTypeExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('.'); + buf.put(e.sym.toString()); + } + + void visitCall(ASTCodegen.CallExp e) + { + /* writeln("stringifying func call"); */ + if (e.e1.op == EXP.type) + { + /* Avoid parens around type to prevent forbidden cast syntax: + * (sometype)(arg1) + * This is ok since types in constructor calls + * can never depend on parens anyway + */ + /* writeln("stringifying func e1 expr"); */ + writeExpr(e.e1); + } + else /* writeln("stringifying func e1 expr with precedence"); */ + writeExprWithPrecedence(e.e1, precedence[e.op]); + /* writeln("writing brace at indent level: ", depth); */ + buf.put('('); + writeArgs(e.arguments, null, e.names); + buf.put(')'); + } + + void visitPtr(ASTCodegen.PtrExp e) + { + buf.put('*'); + writeExprWithPrecedence(e.e1, precedence[e.op]); + } + + void visitDelete(ASTCodegen.DeleteExp e) + { + buf.put("delete "); + writeExprWithPrecedence(e.e1, precedence[e.op]); + } + + void visitCast(ASTCodegen.CastExp e) + { + buf.put("cast("); + if (e.to) + writeTypeWithIdent(e.to, null); + else + { + buf.put(MODtoString(e.mod)); + } + buf.put(')'); + writeExprWithPrecedence(e.e1, precedence[e.op]); + } + + void visitVector(ASTCodegen.VectorExp e) + { + buf.put("cast("); + writeTypeWithIdent(e.to, null); + buf.put(')'); + writeExprWithPrecedence(e.e1, precedence[e.op]); + } + + void visitVectorArray(ASTCodegen.VectorArrayExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put(".array"); + } + + void visitSlice(ASTCodegen.SliceExp e) + { + writeExprWithPrecedence(e.e1, precedence[e.op]); + buf.put('['); + if (e.upr || e.lwr) + { + if (e.lwr) + writeSize(e.lwr); + else + buf.put('0'); + buf.put(".."); + if (e.upr) + writeSize(e.upr); + else + buf.put('$'); + } + buf.put(']'); + } + + void visitArrayLength(ASTCodegen.ArrayLengthExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put(".length"); + } + + void visitInterval(ASTCodegen.IntervalExp e) + { + writeExprWithPrecedence(e.lwr, PREC.assign); + buf.put(".."); + writeExprWithPrecedence(e.upr, PREC.assign); + } + + void visitDelegatePtr(ASTCodegen.DelegatePtrExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put(".ptr"); + } + + void visitDelegateFuncptr(ASTCodegen.DelegateFuncptrExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put(".funcptr"); + } + + void visitArray(ASTCodegen.ArrayExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('['); + writeArgs(e.arguments); + buf.put(']'); + } + + void visitDot(ASTCodegen.DotExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('.'); + writeExprWithPrecedence(e.e2, PREC.primary); + } + + void visitIndex(ASTCodegen.IndexExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put('['); + writeSize(e.e2); + buf.put(']'); + } + + void visitPost(ASTCodegen.PostExp e) + { + writeExprWithPrecedence(e.e1, precedence[e.op]); + buf.put(EXPtoString(e.op)); + } + + void visitPre(ASTCodegen.PreExp e) + { + buf.put(EXPtoString(e.op)); + writeExprWithPrecedence(e.e1, precedence[e.op]); + } + + void visitRemove(ASTCodegen.RemoveExp e) + { + writeExprWithPrecedence(e.e1, PREC.primary); + buf.put(".remove("); + writeExprWithPrecedence(e.e2, PREC.assign); + buf.put(')'); + } + + void visitCond(ASTCodegen.CondExp e) + { + writeExprWithPrecedence(e.econd, PREC.oror); + buf.put(" ? "); + writeExprWithPrecedence(e.e1, PREC.expr); + buf.put(" : "); + writeExprWithPrecedence(e.e2, PREC.cond); + } + + void visitDefaultInit(ASTCodegen.DefaultInitExp e) + { + buf.put(EXPtoString(e.op)); + } + + void visitClassReference(ASTCodegen.ClassReferenceExp e) + { + buf.put(e.value.toString()); + } + + switch (e.op) + { + default: + if (auto be = e.isBinExp()) + return visitBin(be); + else if (auto ue = e.isUnaExp()) + return visitUna(ue); + else if (auto de = e.isDefaultInitExp()) + return visitDefaultInit(e.isDefaultInitExp()); + return visit(e); + + case EXP.int64: + return visitInteger(e.isIntegerExp()); + case EXP.error: + return visitError(e.isErrorExp()); + case EXP.void_: + return visitVoidInit(e.isVoidInitExp()); + case EXP.float64: + return visitReal(e.isRealExp()); + case EXP.complex80: + return visitComplex(e.isComplexExp()); + case EXP.identifier: + return visitIdentifier(e.isIdentifierExp()); + case EXP.dSymbol: + return visitDsymbol(e.isDsymbolExp()); + case EXP.this_: + return visitThis(e.isThisExp()); + case EXP.super_: + return visitSuper(e.isSuperExp()); + case EXP.null_: + return visitNull(e.isNullExp()); + case EXP.string_: + return visitString(e.isStringExp()); + case EXP.arrayLiteral: + return visitArrayLiteral(e.isArrayLiteralExp()); + case EXP.assocArrayLiteral: + return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); + case EXP.structLiteral: + return visitStructLiteral(e.isStructLiteralExp()); + case EXP.compoundLiteral: + return visitCompoundLiteral(e.isCompoundLiteralExp()); + case EXP.type: + return visitType(e.isTypeExp()); + case EXP.scope_: + return visitScope(e.isScopeExp()); + case EXP.template_: + return visitTemplate(e.isTemplateExp()); + case EXP.new_: + return visitNew(e.isNewExp()); + case EXP.newAnonymousClass: + return visitNewAnonClass(e.isNewAnonClassExp()); + case EXP.symbolOffset: + return visitSymOff(e.isSymOffExp()); + case EXP.variable: + return visitVar(e.isVarExp()); + case EXP.overloadSet: + return visitOver(e.isOverExp()); + case EXP.tuple: + return visitTuple(e.isTupleExp()); + case EXP.function_: + return visitFunc(e.isFuncExp()); + case EXP.declaration: + return visitDeclaration(e.isDeclarationExp()); + case EXP.typeid_: + return visitTypeid(e.isTypeidExp()); + case EXP.traits: + return visitTraits(e.isTraitsExp()); + case EXP.halt: + return visitHalt(e.isHaltExp()); + case EXP.is_: + return visitIs(e.isExp()); + case EXP.comma: + return visitComma(e.isCommaExp()); + case EXP.mixin_: + return visitMixin(e.isMixinExp()); + case EXP.import_: + return visitImport(e.isImportExp()); + case EXP.assert_: + return visitAssert(e.isAssertExp()); + case EXP.throw_: + return visitThrow(e.isThrowExp()); + case EXP.dotIdentifier: + return visitDotId(e.isDotIdExp()); + case EXP.dotTemplateDeclaration: + return visitDotTemplate(e.isDotTemplateExp()); + case EXP.dotVariable: + return visitDotVar(e.isDotVarExp()); + case EXP.dotTemplateInstance: + return visitDotTemplateInstance(e.isDotTemplateInstanceExp()); + case EXP.delegate_: + return visitDelegate(e.isDelegateExp()); + case EXP.dotType: + return visitDotType(e.isDotTypeExp()); + case EXP.call: + return visitCall(e.isCallExp()); + case EXP.star: + return visitPtr(e.isPtrExp()); + case EXP.delete_: + return visitDelete(e.isDeleteExp()); + case EXP.cast_: + return visitCast(e.isCastExp()); + case EXP.vector: + return visitVector(e.isVectorExp()); + case EXP.vectorArray: + return visitVectorArray(e.isVectorArrayExp()); + case EXP.slice: + return visitSlice(e.isSliceExp()); + case EXP.arrayLength: + return visitArrayLength(e.isArrayLengthExp()); + case EXP.interval: + return visitInterval(e.isIntervalExp()); + case EXP.delegatePointer: + return visitDelegatePtr(e.isDelegatePtrExp()); + case EXP.delegateFunctionPointer: + return visitDelegateFuncptr(e.isDelegateFuncptrExp()); + case EXP.array: + return visitArray(e.isArrayExp()); + case EXP.dot: + return visitDot(e.isDotExp()); + case EXP.index: + return visitIndex(e.isIndexExp()); + case EXP.minusMinus: + case EXP.plusPlus: + return visitPost(e.isPostExp()); + case EXP.preMinusMinus: + case EXP.prePlusPlus: + return visitPre(e.isPreExp()); + case EXP.remove: + return visitRemove(e.isRemoveExp()); + case EXP.question: + return visitCond(e.isCondExp()); + case EXP.classReference: + return visitClassReference(e.isClassReferenceExp()); + case EXP.loweredAssignExp: + return visitLoweredAssignExp(e.isLoweredAssignExp()); + } + } + + void writeArgs( + ASTCodegen.Expressions* expressions, + ASTCodegen.Expression basis = null, + ASTCodegen.Identifiers* names = null) + { + if (!expressions || !expressions.length) + return; + version (all) + { + foreach (i, el; *expressions) + { + if (i) + buf.put(", "); + + if (names && i < names.length && (*names)[i]) + { + buf.put((*names)[i].toString()); + buf.put(": "); + } + if (!el) + el = basis; + if (el) + writeExprWithPrecedence(el, PREC.assign); + } + } + else + { + // Sparse style formatting, for debug use only + // [0..length: basis, 1: e1, 5: e5] + if (basis) + { + buf.put("0.."); + buf.print(expressions.length); + buf.put(": "); + writeExprWithPrecedence(basis, PREC.assign); + } + foreach (i, el; *expressions) + { + if (el) + { + if (basis) + { + buf.put(", "); + buf.put(i); + buf.put(": "); + } + else if (i) + buf.put(", "); + writeExprWithPrecedence(el, PREC.assign); + } + } + } + } + + void writeExprWithPrecedence(ASTCodegen.Expression e, PREC pr) + { + if (e.op == 0xFF) + { + buf.put(""); + return; + } + assert(precedence[e.op] != PREC.zero); + assert(pr != PREC.zero); + /* Despite precedence, we don't allow a= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) + { + buf.put('('); + writeExpr(e); + buf.put(')'); + } + else + { + writeExpr(e); + } + } + + void writeTypeWithIdent(ASTCodegen.Type t, const Identifier ident, ubyte modMask = 0) + { + if (auto tf = t.isTypeFunction()) + { + writeFuncIdentWithPrefix(tf, ident, null); + return; + } + writeWithMask(t, modMask); + if (ident) + { + buf.put(' '); + buf.put(ident.toString()); + } + } + + void writeWithMask(Type t, ubyte modMask) + { + // Tuples and functions don't use the type constructor syntax + if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) + { + writeType(t); + } + else + { + ubyte m = t.mod & ~(t.mod & modMask); + if (m & MODFlags.shared_) + { + buf.put(MODtoString(MODFlags.shared_)); + buf.put('('); + } + if (m & MODFlags.wild) + { + buf.put(MODtoString(MODFlags.wild)); + buf.put('('); + } + if (m & (MODFlags.const_ | MODFlags.immutable_)) + { + buf.put(MODtoString(m & (MODFlags.const_ | MODFlags.immutable_))); + buf.put('('); + } + writeType(t); + if (m & (MODFlags.const_ | MODFlags.immutable_)) + buf.put(')'); + if (m & MODFlags.wild) + buf.put(')'); + if (m & MODFlags.shared_) + buf.put(')'); + } + } + + void writeStatement(ASTCodegen.Statement s) + { + void visitDefaultCase(ASTCodegen.Statement _) + { + assert(0, "unrecognized statement in writeStatement()"); + } + + void visitError(ASTCodegen.ErrorStatement _) + { + buf.put("__error__"); + newline(); + } + + void visitExp(ASTCodegen.ExpStatement s) + { + /* writeln("visiting exp decl"); */ + if (s.exp && s.exp.op == EXP.declaration && + (cast(ASTCodegen.DeclarationExp) s.exp).declaration) + { + (cast(ASTCodegen.DeclarationExp) s.exp).declaration.accept(this); + return; + } + /* writeln("writing exp: ", s.exp.stringof); */ + if (s.exp) + writeExpr(s.exp); + buf.put(';'); + newline(); + } + + void visitDtorExp(ASTCodegen.DtorExpStatement s) + { + visitExp(s); + } + + void visitMixin(ASTCodegen.MixinStatement s) + { + buf.put("mixin("); + writeArgs(s.exps); + buf.put(");"); + } + + void visitCompound(ASTCodegen.CompoundStatement s) + { + foreach (sx; *s.statements) + { + if (sx) + { + writeStatement(sx); + } + } + } + + void visitCompoundAsm(ASTCodegen.CompoundAsmStatement s) + { + visitCompound(s); + } + + void visitCompoundDeclaration(ASTCodegen.CompoundDeclarationStatement s) + { + bool anywritten = false; + foreach (sx; *s.statements) + { + auto ds = sx ? sx.isExpStatement() : null; + if (ds && ds.exp.isDeclarationExp()) + { + auto d = ds.exp.isDeclarationExp().declaration; + if (auto v = d.isVarDeclaration()) + { + writeVarDecl(v, anywritten); + } + else + d.accept(this); + anywritten = true; + } + } + buf.put(';'); + } + + void visitUnrolledLoop(ASTCodegen.UnrolledLoopStatement s) + { + buf.put("/*unrolled*/ {"); + newline(); + depth++; + foreach (sx; *s.statements) + { + if (sx) + writeStatement(sx); + } + depth--; + buf.put('}'); + newline(); + } + + void visitScope(ASTCodegen.ScopeStatement s) + { + buf.put('{'); + newline(); + depth++; + if (s.statement) + writeStatement(s.statement); + depth--; + buf.put('}'); + newline(); + } + + void visitWhile(ASTCodegen.WhileStatement s) + { + buf.put("while ("); + if (auto p = s.param) + { + // Print condition assignment + StorageClass stc = p.storageClass; + if (!p.type && !stc) + stc = STC.auto_; + writeStc(stc); + if (p.type) + writeTypeWithIdent(p.type, p.ident); + else + buf.put(p.ident.toString()); + buf.put(" = "); + } + writeExpr(s.condition); + buf.put(')'); + newline(); + if (s._body) + writeStatement(s._body); + } + + void visitDo(ASTCodegen.DoStatement s) + { + buf.put("do"); + newline(); + if (s._body) + writeStatement(s._body); + buf.put("while ("); + writeExpr(s.condition); + buf.put(");"); + newline(); + } + + void visitFor(ASTCodegen.ForStatement s) + { + buf.put("for ("); + if (s._init) + { + writeStatement(s._init); + } + else + buf.put(';'); + if (s.condition) + { + buf.put(' '); + writeExpr(s.condition); + } + buf.put(';'); + if (s.increment) + { + buf.put(' '); + writeExpr(s.increment); + } + buf.put(')'); + newline(); + buf.put('{'); + newline(); + depth++; + if (s._body) + writeStatement(s._body); + depth--; + buf.put('}'); + newline(); + } + + void visitForeachWithoutBody(ASTCodegen.ForeachStatement s) + { + buf.put(Token.toString(s.op)); + buf.put(" ("); + foreach (i, p; *s.parameters) + { + if (i) + buf.put(", "); + writeStc(p.storageClass); + if (p.type) + writeTypeWithIdent(p.type, p.ident); + else + buf.put(p.ident.toString()); + } + buf.put("; "); + writeExpr(s.aggr); + buf.put(')'); + newline(); + } + + void visitForeach(ASTCodegen.ForeachStatement s) + { + visitForeachWithoutBody(s); + buf.put('{'); + newline(); + depth++; + if (s._body) + writeStatement(s._body); + depth--; + buf.put('}'); + newline(); + } + + void visitForeachRangeWithoutBody(ASTCodegen.ForeachRangeStatement s) + { + buf.put(Token.toString(s.op)); + buf.put(" ("); + if (s.prm.type) + writeTypeWithIdent(s.prm.type, s.prm.ident); + else + buf.put(s.prm.ident.toString()); + buf.put("; "); + writeExpr(s.lwr); + buf.put(" .. "); + writeExpr(s.upr); + buf.put(')'); + newline(); + } + + void visitForeachRange(ASTCodegen.ForeachRangeStatement s) + { + visitForeachRangeWithoutBody(s); + buf.put('{'); + newline(); + depth++; + if (s._body) + writeStatement(s._body); + depth--; + buf.put('}'); + newline(); + } + + void visitStaticForeach(ASTCodegen.StaticForeachStatement s) + { + indent(); + buf.put("static "); + if (s.sfe.aggrfe) + { + visitForeach(s.sfe.aggrfe); + } + else + { + assert(s.sfe.rangefe); + visitForeachRange(s.sfe.rangefe); + } + } + + void visitForwarding(ASTCodegen.ForwardingStatement s) + { + writeStatement(s.statement); + } + + void visitIf(ASTCodegen.IfStatement s) + { + buf.put("if ("); + if (Parameter p = s.prm) + { + StorageClass stc = p.storageClass; + if (!p.type && !stc) + stc = STC.auto_; + writeStc(stc); + if (p.type) + writeTypeWithIdent(p.type, p.ident); + else + buf.put(p.ident.toString()); + buf.put(" = "); + } + writeExpr(s.condition); + buf.put(')'); + newline(); + if (s.ifbody.isScopeStatement()) + { + writeStatement(s.ifbody); + } + else + { + depth++; + writeStatement(s.ifbody); + depth--; + } + if (s.elsebody) + { + buf.put("else"); + if (!s.elsebody.isIfStatement()) + { + newline(); + } + else + { + buf.put(' '); + } + if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) + { + writeStatement(s.elsebody); + } + else + { + depth++; + writeStatement(s.elsebody); + depth--; + } + } + } + + void visitConditional(ASTCodegen.ConditionalStatement s) + { + s.condition.accept(this); + newline(); + buf.put('{'); + newline(); + depth++; + if (s.ifbody) + writeStatement(s.ifbody); + depth--; + buf.put('}'); + newline(); + if (s.elsebody) + { + buf.put("else"); + newline(); + buf.put('{'); + depth++; + newline(); + writeStatement(s.elsebody); + depth--; + buf.put('}'); + } + newline(); + } + + void visitPragma(ASTCodegen.PragmaStatement s) + { + buf.put("pragma ("); + buf.put(s.ident.toString()); + if (s.args && s.args.length) + { + buf.put(", "); + writeArgs(s.args); + } + buf.put(')'); + if (s._body) + { + newline(); + buf.put('{'); + newline(); + depth++; + writeStatement(s._body); + depth--; + buf.put('}'); + newline(); + } + else + { + buf.put(';'); + newline(); + } + } + + void visitStaticAssert(ASTCodegen.StaticAssertStatement s) + { + s.sa.accept(this); + } + + void visitSwitch(ASTCodegen.SwitchStatement s) + { + buf.put(s.isFinal ? "final switch (" : "switch ("); + if (auto p = s.param) + { + // Print condition assignment + StorageClass stc = p.storageClass; + if (!p.type && !stc) + stc = STC.auto_; + writeStc(stc); + if (p.type) + writeTypeWithIdent(p.type, p.ident); + else + buf.put(p.ident.toString()); + buf.put(" = "); + } + writeExpr(s.condition); + buf.put(')'); + newline(); + if (s._body) + { + if (!s._body.isScopeStatement()) + { + buf.put('{'); + newline(); + depth++; + writeStatement(s._body); + depth--; + buf.put('}'); + newline(); + } + else + { + writeStatement(s._body); + } + } + } + + void visitCase(ASTCodegen.CaseStatement s) + { + buf.put("case "); + writeExpr(s.exp); + buf.put(':'); + newline(); + writeStatement(s.statement); + } + + void visitCaseRange(ASTCodegen.CaseRangeStatement s) + { + buf.put("case "); + writeExpr(s.first); + buf.put(": .. case "); + writeExpr(s.last); + buf.put(':'); + newline(); + writeStatement(s.statement); + } + + void visitDefault(ASTCodegen.DefaultStatement s) + { + buf.put("default:"); + newline(); + writeStatement(s.statement); + } + + void visitGotoDefault(ASTCodegen.GotoDefaultStatement _) + { + buf.put("goto default;"); + newline(); + } + + void visitGotoCase(ASTCodegen.GotoCaseStatement s) + { + buf.put("goto case"); + if (s.exp) + { + buf.put(' '); + writeExpr(s.exp); + } + buf.put(';'); + newline(); + } + + void visitSwitchError(ASTCodegen.SwitchErrorStatement _) + { + buf.put("SwitchErrorStatement::toCBuffer()"); + newline(); + } + + void visitReturn(ASTCodegen.ReturnStatement s) + { + buf.put("return "); + if (s.exp) + writeExpr(s.exp); + buf.put(';'); + newline(); + } + + void visitBreak(ASTCodegen.BreakStatement s) + { + buf.put("break"); + if (s.ident) + { + buf.put(' '); + buf.put(s.ident.toString()); + } + buf.put(';'); + newline(); + } + + void visitContinue(ASTCodegen.ContinueStatement s) + { + buf.put("continue"); + if (s.ident) + { + buf.put(' '); + buf.put(s.ident.toString()); + } + buf.put(';'); + newline(); + } + + void visitSynchronized(ASTCodegen.SynchronizedStatement s) + { + buf.put("synchronized"); + if (s.exp) + { + buf.put('('); + writeExpr(s.exp); + buf.put(')'); + } + if (s._body) + { + buf.put(' '); + writeStatement(s._body); + } + } + + void visitWith(ASTCodegen.WithStatement s) + { + buf.put("with ("); + writeExpr(s.exp); + buf.put(")"); + newline(); + if (s._body) + writeStatement(s._body); + } + + void visitTryCatch(ASTCodegen.TryCatchStatement s) + { + buf.put("try"); + newline(); + if (s._body) + { + if (s._body.isScopeStatement()) + { + writeStatement(s._body); + } + else + { + depth++; + writeStatement(s._body); + depth--; + } + } + foreach (c; *s.catches) + { + buf.put("catch"); + if (c.type) + { + buf.put('('); + writeTypeWithIdent(c.type, c.ident); + buf.put(')'); + } + newline(); + buf.put('{'); + newline(); + depth++; + if (c.handler) + writeStatement(c.handler); + depth--; + buf.put('}'); + newline(); + } + } + + void visitTryFinally(ASTCodegen.TryFinallyStatement s) + { + buf.put("try"); + newline(); + buf.put('{'); + newline(); + depth++; + writeStatement(s._body); + depth--; + buf.put('}'); + newline(); + buf.put("finally"); + newline(); + if (s.finalbody.isScopeStatement()) + { + writeStatement(s.finalbody); + } + else + { + depth++; + writeStatement(s.finalbody); + depth--; + } + } + + void visitScopeGuard(ASTCodegen.ScopeGuardStatement s) + { + buf.put(Token.toString(s.tok)); + buf.put(' '); + if (s.statement) + writeStatement(s.statement); + } + + void visitThrow(ASTCodegen.ThrowStatement s) + { + buf.put("throw "); + writeExpr(s.exp); + buf.put(';'); + newline(); + } + + void visitDebug(ASTCodegen.DebugStatement s) + { + if (s.statement) + { + writeStatement(s.statement); + } + } + + void visitGoto(ASTCodegen.GotoStatement s) + { + buf.put("goto "); + buf.put(s.ident.toString()); + buf.put(';'); + newline(); + } + + void visitLabel(ASTCodegen.LabelStatement s) + { + buf.put(s.ident.toString()); + buf.put(':'); + newline(); + if (s.statement) + writeStatement(s.statement); + } + + void visitAsm(ASTCodegen.AsmStatement s) + { + buf.put("asm { "); + Token* t = s.tokens; + depth++; + while (t) + { + buf.put(Token.toString(t.value)); + if (t.next && + t.value != TOK.min && + t.value != TOK.comma && t.next.value != TOK.comma && + t.value != TOK.leftBracket && t.next.value != TOK.leftBracket && + t.next.value != TOK.rightBracket && + t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis && + t.next.value != TOK.rightParenthesis && + t.value != TOK.dot && t.next.value != TOK.dot) + { + buf.put(' '); + } + t = t.next; + } + depth--; + buf.put("; }"); + newline(); + } + + void visitInlineAsm(ASTCodegen.InlineAsmStatement s) + { + visitAsm(s); + } + + void visitGccAsm(ASTCodegen.GccAsmStatement s) + { + visitAsm(s); + } + + void visitImport(ASTCodegen.ImportStatement s) + { + foreach (imp; *s.imports) + { + imp.accept(this); + } + } + + import dmd.statement; + + mixin VisitStatement!void visit; + visit.VisitStatement(s); + } + + void writeFuncBody(ASTCodegen.FuncDeclaration f) + { + if (!f.fbody) + { + if (f.fensures || f.frequires) + { + newline(); + writeContracts(f); + } + buf.put(';'); + newline(); + return; + } + + newline(); + bool requireDo = writeContracts(f); + + if (requireDo) + { + buf.put("do"); + newline(); + } + buf.put('{'); + newline(); + depth++; + /* writeln("writing at depth ", depth); */ + writeStatement(f.fbody); + depth--; + /* writeln("finished writing, now depth ", depth); */ + buf.put('}'); + newline(); + } + + // Returns: whether `do` is needed to write the function body + bool writeContracts(ASTCodegen.FuncDeclaration f) + { + bool requireDo = false; + // in{} + if (f.frequires) + { + foreach (frequire; *f.frequires) + { + buf.put("in"); + if (auto es = frequire.isExpStatement()) + { + assert(es.exp && es.exp.op == EXP.assert_); + buf.put(" ("); + writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); + buf.put(')'); + newline(); + requireDo = false; + } + else + { + newline(); + writeStatement(frequire); + requireDo = true; + } + } + } + // out{} + if (f.fensures) + { + foreach (fensure; *f.fensures) + { + buf.put("out"); + if (auto es = fensure.ensure.isExpStatement()) + { + assert(es.exp && es.exp.op == EXP.assert_); + buf.put(" ("); + if (fensure.id) + { + buf.put(fensure.id.toString()); + } + buf.put("; "); + writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); + buf.put(')'); + newline(); + requireDo = false; + } + else + { + if (fensure.id) + { + buf.put('('); + buf.put(fensure.id.toString()); + buf.put(')'); + } + newline(); + writeStatement(fensure.ensure); + requireDo = true; + } + } + } + return requireDo; + } + + void writeInitializer(Initializer inx) + { + void visitError(ErrorInitializer _) + { + buf.put("__error__"); + } + + void visitVoid(VoidInitializer _) + { + buf.put("void"); + } + + void visitStruct(StructInitializer si) + { + //printf("StructInitializer::toCBuffer()\n"); + buf.put('{'); + foreach (i, const id; si.field) + { + if (i) + buf.put(", "); + if (id) + { + buf.put(id.toString()); + buf.put(':'); + } + if (auto iz = si.value[i]) + writeInitializer(iz); + } + buf.put('}'); + } + + void visitArray(ArrayInitializer ai) + { + buf.put('['); + foreach (i, ex; ai.index) + { + if (i) + buf.put(", "); + if (ex) + { + writeExpr(ex); + buf.put(':'); + } + if (auto iz = ai.value[i]) + writeInitializer(iz); + } + buf.put(']'); + } + + void visitExp(ExpInitializer ei) + { + writeExpr(ei.exp); + } + + void visitC(CInitializer ci) + { + buf.put('{'); + foreach (i, ref DesigInit di; ci.initializerList) + { + if (i) + buf.put(", "); + if (di.designatorList) + { + foreach (ref Designator d; (*di.designatorList)[]) + { + if (d.exp) + { + buf.put('['); + d.exp.accept(this); + buf.put(']'); + } + else + { + buf.put('.'); + buf.put(d.ident.toString()); + } + } + buf.put('='); + } + writeInitializer(di.initializer); + } + buf.put('}'); + } + + mixin VisitInitializer!void visit; + visit.VisitInitializer(inx); + } + + void writeObject(RootObject oarg) + { + /* The logic of this should match what genIdent() does. The _dynamic_cast() + * function relies on all the pretty strings to be unique for different classes + * See https://issues.dlang.org/show_bug.cgi?id=7375 + * Perhaps it would be better to demangle what genIdent() does. + */ + import dmd.dtemplate; + import dmd.expression : WANTvalue; + + if (auto t = isType(oarg)) + { + writeTypeWithIdent(t, null); + } + else if (auto e = isExpression(oarg)) + { + if (e.op == EXP.variable) + e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 + writeExprWithPrecedence(e, PREC.assign); + } + else if (ASTCodegen.Dsymbol s = isDsymbol(oarg)) + { + const p = s.ident ? s.ident.toString() : s.toString(); + buf.put(p); + } + else if (auto v = isTuple(oarg)) + { + auto args = &v.objects; + foreach (i, arg; *args) + { + if (i) + buf.put(", "); + writeObject(arg); + } + } + else if (auto p = isParameter(oarg)) + { + writeParam(p); + } + else if (!oarg) + { + buf.put("NULL"); + } + else + { + assert(0); + } + } + + void writeVarDecl(ASTCodegen.VarDeclaration v, bool anywritten) + { + void vinit(ASTCodegen.VarDeclaration v) + { + auto ie = v._init.isExpInitializer(); + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) + writeExpr((cast(ASTCodegen.AssignExp) ie.exp).e2); + else + writeInitializer(v._init); + } + + if (anywritten) + { + buf.put(", "); + buf.put(v.ident.toString()); + } + else + { + auto stc = v.storage_class; + writeStc(stc); + if (v.type) + writeTypeWithIdent(v.type, v.ident); + else + buf.put(v.ident.toString()); + } + if (v._init) + { + buf.put(" = "); + vinit(v); + } + } + + void writeSize(ASTCodegen.Expression e) + { + import dmd.expression : WANTvalue; + + if (e.type == Type.tsize_t) + { + ASTCodegen.Expression ex = (e.op == EXP.cast_ ? (cast(ASTCodegen.CastExp) e).e1 : e); + ex = ex.optimize(WANTvalue); + const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; + if (cast(long) uval >= 0) + { + ulong sizemax = void; + if (target.ptrsize == 8) + sizemax = 0xFFFFFFFFFFFFFFFFUL; + else if (target.ptrsize == 4) + sizemax = 0xFFFFFFFFU; + else if (target.ptrsize == 2) + sizemax = 0xFFFFU; + else + assert(0); + if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) + { + buf.put(format("%lu", uval)); + return; + } + } + } + writeExprWithPrecedence(e, PREC.assign); + } + + void writeFuncIdentWithPrefix(TypeFunction t, const Identifier ident, ASTCodegen + .TemplateDeclaration td) + { + if (t.inuse) + { + t.inuse = 2; // flag error to caller + return; + } + t.inuse++; + + /* Use 'storage class' (prefix) style for attributes + */ + if (t.mod) + { + buf.put(MODtoString(t.mod)); + buf.put(' '); + } + + void ignoreReturn(string str) + { + import dmd.id : Id; + + if (str != "return") + { + // don't write 'ref' for ctors + if ((ident == Id.ctor) && str == "ref") + return; + buf.put(str); + buf.put(' '); + } + } + + t.attributesApply(&ignoreReturn); + + if (t.linkage > LINK.d) + { + writeLinkage(t.linkage); + buf.put(' '); + } + if (ident && ident.toHChars2() != ident.toChars()) + { + // Don't print return type for ctor, dtor, unittest, etc + } + else if (t.next) + { + writeTypeWithIdent(t.next, null); + if (ident) + buf.put(' '); + } + if (ident) + buf.put(ident.toString()); + if (td) + { + buf.put('('); + foreach (i, p; *td.origParameters) + { + if (i) + buf.put(", "); + p.accept(this); + } + buf.put(')'); + } + writeParamList(t.parameterList); + if (t.isreturn) + { + buf.put(" return"); + } + t.inuse--; + } + + extern (D) void writeFuncIdentWithPostfix(TypeFunction t, const char[] ident, bool isStatic) + { + if (t.inuse) + { + t.inuse = 2; // flag error to caller + return; + } + t.inuse++; + if (t.linkage > LINK.d) + { + writeLinkage(t.linkage); + buf.put(' '); + } + if (t.linkage == LINK.objc && isStatic) + buf.put("static "); + if (t.next) + { + writeTypeWithIdent(t.next, null); + if (ident) + buf.put(' '); + } + if (ident) + buf.put(ident); + writeParamList(t.parameterList); + /* Use postfix style for attributes */ + if (t.mod) + { + buf.put(' '); + buf.put(MODtoString(t.mod)); + } + + void dg(string str) + { + buf.put(' '); + buf.put(str); + } + + t.attributesApply(&dg); + + t.inuse--; + } + + void writeType(Type t) + { + void visitType(Type _) + { + assert(0); + } + + void visitError(TypeError _) + { + buf.put("_error_"); + } + + void visitBasic(TypeBasic t) + { + buf.put(t.toString()); + } + + void visitTraits(TypeTraits t) + { + writeExpr(t.exp); + } + + void visitVector(TypeVector t) + { + buf.put("__vector("); + writeWithMask(t.basetype, t.mod); + buf.put(")"); + } + + void visitSArray(TypeSArray t) + { + writeWithMask(t.next, t.mod); + buf.put('['); + writeSize(t.dim); + buf.put(']'); + } + + void visitDArray(TypeDArray t) + { + Type ut = t.castMod(0); + if (declstring) + goto L1; + if (ut.equals(Type.tstring)) + buf.put("string"); + else if (ut.equals(Type.twstring)) + buf.put("wstring"); + else if (ut.equals(Type.tdstring)) + buf.put("dstring"); + else + { + L1: + writeWithMask(t.next, t.mod); + buf.put("[]"); + } + } + + void visitAArray(TypeAArray t) + { + writeWithMask(t.next, t.mod); + buf.put('['); + writeWithMask(t.index, 0); + buf.put(']'); + } + + void visitPointer(TypePointer t) + { + if (t.next.ty == Tfunction) + writeFuncIdentWithPostfix(cast(TypeFunction) t.next, "function", false); + else + { + writeWithMask(t.next, t.mod); + buf.put('*'); + } + } + + void visitReference(TypeReference t) + { + writeWithMask(t.next, t.mod); + buf.put('&'); + } + + void visitFunction(TypeFunction t) + { + writeFuncIdentWithPostfix(t, null, false); + } + + void visitDelegate(TypeDelegate t) + { + writeFuncIdentWithPostfix(cast(TypeFunction) t.next, "delegate", false); + } + + void visitTypeQualifiedHelper(TypeQualified t) + { + foreach (id; t.idents) + { + switch (id.dyncast()) with (DYNCAST) + { + case dsymbol: + buf.put('.'); + ASTCodegen.TemplateInstance ti = cast(ASTCodegen.TemplateInstance) id; + ti.accept(this); + break; + case expression: + buf.put('['); + writeExpr(cast(ASTCodegen.Expression) id); + buf.put(']'); + break; + case type: + buf.put('['); + writeType(cast(Type) id); + buf.put(']'); + break; + default: + buf.put('.'); + buf.put(id.toString()); + } + } + } + + void visitIdentifier(TypeIdentifier t) + { + buf.put(t.ident.toString()); + visitTypeQualifiedHelper(t); + } + + void visitInstance(TypeInstance t) + { + t.tempinst.accept(this); + visitTypeQualifiedHelper(t); + } + + void visitTypeof(TypeTypeof t) + { + buf.put("typeof("); + writeExpr(t.exp); + buf.put(')'); + visitTypeQualifiedHelper(t); + } + + void visitReturn(TypeReturn t) + { + buf.put("typeof(return)"); + visitTypeQualifiedHelper(t); + } + + void visitEnum(TypeEnum t) + { + buf.put(t.sym.toString()); + } + + void visitStruct(TypeStruct t) + { + // https://issues.dlang.org/show_bug.cgi?id=13776 + // Don't use ti.toAlias() to avoid forward reference error + // while printing messages. + ASTCodegen.TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; + if (ti && ti.aliasdecl == t.sym) + buf.put(ti.toString()); + else + buf.put(t.sym.toString()); + } + + void visitClass(TypeClass t) + { + // https://issues.dlang.org/show_bug.cgi?id=13776 + // Don't use ti.toAlias() to avoid forward reference error + // while printing messages. + ASTCodegen.TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; + if (ti && ti.aliasdecl == t.sym) + buf.put(ti.toString()); + else + buf.put(t.sym.toString()); + } + + void visitTag(TypeTag t) + { + if (t.mod & MODFlags.const_) + buf.put("const "); + buf.put(Token.toString(t.tok)); + buf.put(' '); + if (t.id) + buf.put(t.id.toString()); + if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) + { + buf.put(" : "); + writeWithMask(t.base, t.mod); + } + } + + void visitTuple(TypeTuple t) + { + writeParamList(ParameterList(t.arguments, VarArg.none)); + } + + void visitSlice(TypeSlice t) + { + writeWithMask(t.next, t.mod); + buf.put('['); + writeSize(t.lwr); + buf.put(" .. "); + writeSize(t.upr); + buf.put(']'); + } + + void visitNull(TypeNull _) + { + buf.put("typeof(null)"); + } + + void visitMixin(TypeMixin t) + { + buf.put("mixin("); + writeArgs(t.exps); + buf.put(')'); + } + + void visitNoreturn(TypeNoreturn _) + { + buf.put("noreturn"); + } + + switch (t.ty) + { + default: + return t.isTypeBasic() ? + visitBasic(cast(TypeBasic) t) : visitType(t); + + case Terror: + return visitError(cast(TypeError) t); + case Ttraits: + return visitTraits(cast(TypeTraits) t); + case Tvector: + return visitVector(cast(TypeVector) t); + case Tsarray: + return visitSArray(cast(TypeSArray) t); + case Tarray: + return visitDArray(cast(TypeDArray) t); + case Taarray: + return visitAArray(cast(TypeAArray) t); + case Tpointer: + return visitPointer(cast(TypePointer) t); + case Treference: + return visitReference(cast(TypeReference) t); + case Tfunction: + return visitFunction(cast(TypeFunction) t); + case Tdelegate: + return visitDelegate(cast(TypeDelegate) t); + case Tident: + return visitIdentifier(cast(TypeIdentifier) t); + case Tinstance: + return visitInstance(cast(TypeInstance) t); + case Ttypeof: + return visitTypeof(cast(TypeTypeof) t); + case Treturn: + return visitReturn(cast(TypeReturn) t); + case Tenum: + return visitEnum(cast(TypeEnum) t); + case Tstruct: + return visitStruct(cast(TypeStruct) t); + case Tclass: + return visitClass(cast(TypeClass) t); + case Ttuple: + return visitTuple(cast(TypeTuple) t); + case Tslice: + return visitSlice(cast(TypeSlice) t); + case Tnull: + return visitNull(cast(TypeNull) t); + case Tmixin: + return visitMixin(cast(TypeMixin) t); + case Tnoreturn: + return visitNoreturn(cast(TypeNoreturn) t); + case Ttag: + return visitTag(cast(TypeTag) t); + } + } + + void writeLinkage(LINK linkage) + { + const s = linkageToString(linkage); + if (s.length) + { + buf.put("extern ("); + buf.put(s); + buf.put(')'); + } + } + + void writeParam(Parameter p) + { + if (p.userAttribDecl) + { + buf.put('@'); + + bool isAnonymous = p.userAttribDecl.atts.length > 0 && !(*p.userAttribDecl.atts)[0].isCallExp(); + if (isAnonymous) + buf.put('('); + + writeArgs(p.userAttribDecl.atts); + + if (isAnonymous) + buf.put(')'); + buf.put(' '); + } + if (p.storageClass & STC.auto_) + buf.put("auto "); + + StorageClass stc = p.storageClass; + if (p.storageClass & STC.in_) + { + buf.put("in "); + } + else if (p.storageClass & STC.lazy_) + buf.put("lazy "); + else if (p.storageClass & STC.alias_) + buf.put("alias "); + + if (p.type && p.type.mod & MODFlags.shared_) + stc &= ~STC.shared_; + + writeStc(stc & ( + STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | + STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC + .returnScope)); + + import core.stdc.string : strncmp; + + if (p.storageClass & STC.alias_) + { + if (p.ident) + buf.put(p.ident.toString()); + } + else if (p.type.ty == Tident && + (cast(TypeIdentifier) p.type) + .ident.toString().length > 3 && + strncmp((cast(TypeIdentifier) p.type) + .ident.toChars(), "__T", 3) == 0) + { + // print parameter name, instead of undetermined type parameter + buf.put(p.ident.toString()); + } + else + { + writeTypeWithIdent(p.type, p.ident, (stc & STC.in_) ? MODFlags.const_ : 0); + } + + if (p.defaultArg) + { + buf.put(" = "); + writeExprWithPrecedence(p.defaultArg, PREC.assign); + } + } + + void writeParamList(ParameterList pl) + { + buf.put('('); + foreach (i; 0 .. pl.length) + { + if (i) + buf.put(", "); + writeParam(pl[i]); + } + final switch (pl.varargs) + { + case VarArg.none: + break; + + case VarArg.variadic: + if (pl.length) + buf.put(", "); + + writeStc(pl.stc); + goto case VarArg.typesafe; + + case VarArg.typesafe: + buf.put("..."); + break; + + case VarArg.KRvariadic: + break; + } + buf.put(')'); + } + + void writeVisibility(ASTCodegen.Visibility vis) + { + buf.put(visibilityToString(vis.kind)); + if (vis.kind == ASTCodegen.Visibility.Kind.package_ && vis.pkg) + { + buf.put('('); + buf.put(vis.pkg.toPrettyChars(true).toDString()); + buf.put(')'); + } + } + + extern (D) string visibilityToString(ASTCodegen.Visibility.Kind kind) nothrow pure @safe + { + with (ASTCodegen.Visibility.Kind) + { + immutable string[7] a = [ + none: "none", + private_: "private", + package_: "package", + protected_: "protected", + public_: "public", + export_: "export" + ]; + return a[kind]; + } + } + + void writeTiArgs(ASTCodegen.TemplateInstance ti) + { + buf.put('!'); + if (ti.nest) + { + buf.put("(...)"); + return; + } + if (!ti.tiargs) + { + buf.put("()"); + return; + } + if (ti.tiargs.length == 1) + { + import dmd.dtemplate; + + RootObject oarg = (*ti.tiargs)[0]; + if (Type t = isType(oarg)) + { + if ((t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0) && ( + (t.isTypeBasic() || t.ty == Tident) && (cast(TypeIdentifier) t).idents.length == 0)) + { + buf.put(t.toString()); + return; + } + } + else if (ASTCodegen.Expression e = isExpression(oarg)) + { + if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP + .this_) + { + buf.put(e.toString()); + return; + } + } + } + buf.put('('); + ti.nestUp(); + foreach (i, arg; *ti.tiargs) + { + if (i) + buf.put(", "); + writeObject(arg); + } + ti.nestDown(); + buf.put(')'); + } + /******************************************* + * Visitors for AST nodes + */ + void visitDsymbol(ASTCodegen.Dsymbol s) + { + /* writeln("visiting dsymbol"); */ + buf.put(s.toString()); + } + + void visitStaticAssert(ASTCodegen.StaticAssert s) + { + buf.put(s.kind().toDString()); + buf.put('('); + writeExpr(s.exp); + if (s.msgs) + { + foreach (m; (*s.msgs)[]) + { + buf.put(", "); + writeExpr(m); + } + } + buf.put(");"); + newline(); + } + + void visitDebugSymbol(ASTCodegen.DebugSymbol s) + { + buf.put("debug = "); + if (s.ident) + buf.put(s.ident.toString()); + else + buf.put(format("%d", s.level)); + buf.put(';'); + newline(); + } + + void visitVersionSymbol(ASTCodegen.VersionSymbol s) + { + buf.put("version = "); + if (s.ident) + buf.put(s.ident.toString()); + else + buf.put(format("%d", s.level)); + buf.put(';'); + newline(); + } + + void visitEnumMember(ASTCodegen.EnumMember em) + { + if (em.type) + writeTypeWithIdent(em.type, em.ident); + else + buf.put(em.ident.toString()); + if (em.value) + { + buf.put(" = "); + writeExpr(em.value); + } + } + + void visitImport(ASTCodegen.Import imp) + { + if (imp.isstatic) + buf.put("static "); + buf.put("import "); + if (imp.aliasId) + { + buf.put(imp.aliasId.toString()); + buf.put(" = "); + } + foreach (const pid; imp.packages) + { + buf.put(pid.toString()); + buf.put("."); + } + buf.put(imp.id.toString()); + if (imp.names.length) + { + buf.put(" : "); + foreach (const i, const name; imp.names) + { + if (i) + buf.put(", "); + const _alias = imp.aliases[i]; + if (_alias) + { + buf.put(_alias.toString()); + buf.put(" = "); + buf.put(name.toString()); + } + else + buf.put(name.toString()); + } + } + + buf.put(';'); + newline(); + } + + void visitAliasThis(ASTCodegen.AliasThis d) + { + buf.put("alias "); + buf.put(d.ident.toString()); + buf.put(" this;"); + newline(); + } + + override void visitAttribDeclaration(ASTCodegen.AttribDeclaration d) + { + if (auto stcd = d.isStorageClassDeclaration) + { + writeStc(stcd.stc); + } + + if (!d.decl) + { + buf.put(';'); + newline(); + return; + } + if (d.decl.length == 0) + { + buf.put("{}"); + } + else if (d.decl.length == 1) + { + (*d.decl)[0].accept(this); + return; + } + else + { + newline(); + buf.put('{'); + newline(); + depth++; + foreach (de; *d.decl) + de.accept(this); + depth--; + buf.put('}'); + } + newline(); + } + + void visitStorageClassDeclaration(ASTCodegen.StorageClassDeclaration d) + { + visitAttribDeclaration(d); + } + + void visitDeprecatedDeclaration(ASTCodegen.DeprecatedDeclaration d) + { + buf.put("deprecated("); + writeExpr(d.msg); + buf.put(") "); + visitAttribDeclaration(d); + } + + void visitLinkDeclaration(ASTCodegen.LinkDeclaration d) + { + buf.put("extern ("); + buf.put(linkageToString(d.linkage)); + buf.put(") "); + visitAttribDeclaration(d); + } + + void visitCPPMangleDeclaration(ASTCodegen.CPPMangleDeclaration d) + { + string s; + final switch (d.cppmangle) + { + case CPPMANGLE.asClass: + s = "class"; + break; + case CPPMANGLE.asStruct: + s = "struct"; + break; + case CPPMANGLE.def: + break; + } + buf.put("extern (C++, "); + buf.put(s); + buf.put(") "); + visitAttribDeclaration(d); + } + + void visitVisibilityDeclaration(ASTCodegen.VisibilityDeclaration d) + { + writeVisibility(d.visibility); + ASTCodegen.AttribDeclaration ad = cast(ASTCodegen.AttribDeclaration) d; + if (ad.decl.length <= 1) + buf.put(' '); + if (ad.decl.length == 1 && (*ad.decl)[0].isVisibilityDeclaration) + visitAttribDeclaration((*ad.decl)[0].isVisibilityDeclaration); + else + visitAttribDeclaration(d); + } + + void visitAlignDeclaration(ASTCodegen.AlignDeclaration d) + { + if (d.exps) + { + foreach (i, exp; (*d.exps)[]) + { + if (i) + buf.put(' '); + buf.put(format("align (%s)", exp.toString())); + } + if (d.decl && d.decl.length < 2) + buf.put(' '); + } + else + buf.put("align "); + + visitAttribDeclaration(d.isAttribDeclaration()); + } + + void visitAnonDeclaration(ASTCodegen.AnonDeclaration d) + { + buf.put(d.isunion ? "union" : "struct"); + newline(); + buf.put("{"); + newline(); + depth++; + if (d.decl) + { + foreach (de; *d.decl) + de.accept(this); + } + depth--; + buf.put("}"); + newline(); + } + + void visitPragmaDeclaration(ASTCodegen.PragmaDeclaration d) + { + buf.put("pragma ("); + buf.put(d.ident.toString()); + if (d.args && d.args.length) + { + buf.put(", "); + writeArgs(d.args); + } + + buf.put(')'); + visitAttribDeclaration(d); + } + + void visitConditionalDeclaration(ASTCodegen.ConditionalDeclaration d) + { + d.condition.accept(this); + if (d.decl || d.elsedecl) + { + newline(); + buf.put('{'); + newline(); + depth++; + if (d.decl) + { + foreach (de; *d.decl) + de.accept(this); + } + depth--; + buf.put('}'); + if (d.elsedecl) + { + newline(); + buf.put("else"); + newline(); + buf.put('{'); + newline(); + depth++; + foreach (de; *d.elsedecl) + de.accept(this); + depth--; + buf.put('}'); + } + } + else + buf.put(':'); + newline(); + } + + void visitStaticForeachDeclaration(ASTCodegen.StaticForeachDeclaration s) + { + void foreachWithoutBody(ASTCodegen.ForeachStatement s) + { + buf.put(Token.toString(s.op)); + buf.put(" ("); + foreach (i, p; *s.parameters) + { + if (i) + buf.put(", "); + writeStc(p.storageClass); + if (p.type) + writeTypeWithIdent(p.type, p.ident); + else + buf.put(p.ident.toString()); + } + buf.put("; "); + writeExpr(s.aggr); + buf.put(')'); + newline(); + } + + void foreachRangeWithoutBody(ASTCodegen.ForeachRangeStatement s) + { + /* s.op ( prm ; lwr .. upr ) + */ + buf.put(Token.toString(s.op)); + buf.put(" ("); + if (s.prm.type) + writeTypeWithIdent(s.prm.type, s.prm.ident); + else + buf.put(s.prm.ident.toString()); + buf.put("; "); + writeExpr(s.lwr); + buf.put(" .. "); + writeExpr(s.upr); + buf.put(')'); + newline(); + } + + buf.put("static "); + if (s.sfe.aggrfe) + { + foreachWithoutBody(s.sfe.aggrfe); + } + else + { + assert(s.sfe.rangefe); + foreachRangeWithoutBody(s.sfe.rangefe); + } + buf.put('{'); + newline(); + depth++; + visitAttribDeclaration(s); + depth--; + buf.put('}'); + newline(); + + } + + void visitMixinDeclaration(ASTCodegen.MixinDeclaration d) + { + buf.put("mixin("); + writeArgs(d.exps); + buf.put(");"); + newline(); + } + + void visitUserAttributeDeclaration(ASTCodegen.UserAttributeDeclaration d) + { + buf.put("@("); + writeArgs(d.atts); + buf.put(')'); + visitAttribDeclaration(d); + } + + void visitTemplateConstraint(ASTCodegen.Expression constraint) + { + if (!constraint) + return; + buf.put(" if ("); + writeExpr(constraint); + buf.put(')'); + } + + override void visitBaseClasses(ASTCodegen.ClassDeclaration d) + { + if (!d || !d.baseclasses.length) + return; + if (!d.isAnonymous()) + buf.put(" : "); + foreach (i, b; *d.baseclasses) + { + if (i) + buf.put(", "); + writeTypeWithIdent(b.type, null); + } + } + + override bool visitEponymousMember(ASTCodegen.TemplateDeclaration d) + { + if (!d.members || d.members.length != 1) + return false; + ASTCodegen.Dsymbol onemember = (*d.members)[0]; + if (onemember.ident != d.ident) + return false; + if (ASTCodegen.FuncDeclaration fd = onemember.isFuncDeclaration()) + { + assert(fd.type); + writeStc(fd.storage_class); + writeFuncIdentWithPrefix(cast(TypeFunction) fd.type, d.ident, d); + visitTemplateConstraint(d.constraint); + writeFuncBody(fd); + return true; + } + if (ASTCodegen.AggregateDeclaration ad = onemember.isAggregateDeclaration()) + { + buf.put(ad.kind().toDString()); + buf.put(' '); + buf.put(ad.ident.toString()); + buf.put('('); + visitTemplateParameters(d.parameters); + buf.put(')'); + visitTemplateConstraint(d.constraint); + visitBaseClasses(ad.isClassDeclaration()); + if (ad.members) + { + newline(); + buf.put('{'); + newline(); + depth++; + foreach (s; *ad.members) + s.accept(this); + depth--; + buf.put('}'); + } + else + buf.put(';'); + newline(); + return true; + } + if (ASTCodegen.VarDeclaration vd = onemember.isVarDeclaration()) + { + if (d.constraint) + return false; + writeStc(vd.storage_class); + if (vd.type) + writeTypeWithIdent(vd.type, vd.ident); + else + buf.put(vd.ident.toString()); + buf.put('('); + visitTemplateParameters(d.parameters); + buf.put(')'); + if (vd._init) + { + buf.put(" = "); + ExpInitializer ie = vd._init.isExpInitializer(); + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) + writeExpr((cast(ASTCodegen.AssignExp) ie.exp).e2); + else + writeInitializer(vd._init); + } + buf.put(';'); + newline(); + return true; + } + return false; + } + + void visitTemplateDeclaration(ASTCodegen.TemplateDeclaration d) + { + buf.put("template"); + buf.put(' '); + buf.put(d.ident.toString()); + buf.put('('); + visitTemplateParameters(d.parameters); + buf.put(')'); + visitTemplateConstraint(d.constraint); + } + + void visitTemplateInstance(ASTCodegen.TemplateInstance ti) + { + buf.put(ti.name.toString()); + writeTiArgs(ti); + } + + void visitTemplateMixin(ASTCodegen.TemplateMixin tm) + { + buf.put("mixin "); + writeTypeWithIdent(tm.tqual, null); + writeTiArgs(tm); + if (tm.ident && tm.ident.toString() != "__mixin") + { + buf.put(' '); + buf.put(tm.ident.toString()); + } + buf.put(';'); + newline(); + } + + void visitEnumDeclaration(ASTCodegen.EnumDeclaration d) + { + buf.put("enum "); + if (d.ident) + { + buf.put(d.ident.toString()); + } + if (d.memtype) + { + buf.put(" : "); + writeTypeWithIdent(d.memtype, null); + } + if (!d.members) + { + buf.put(';'); + newline(); + return; + } + newline(); + buf.put('{'); + newline(); + depth++; + foreach (em; *d.members) + { + if (!em) + continue; + em.accept(this); + buf.put(','); + newline(); + } + depth--; + buf.put('}'); + newline(); + } + + void visitNspace(ASTCodegen.Nspace d) + { + buf.put("extern (C++, "); + buf.put(d.ident.toString()); + buf.put(')'); + newline(); + buf.put('{'); + newline(); + depth++; + foreach (s; *d.members) + s.accept(this); + depth--; + buf.put('}'); + newline(); + } + + void visitStructDeclaration(ASTCodegen.StructDeclaration d) + { + buf.put(d.kind().toDString()); + buf.put(' '); + if (!d.isAnonymous()) + buf.put(d.toString()); + if (!d.members) + { + buf.put(';'); + newline(); + return; + } + newline(); + buf.put('{'); + newline(); + depth++; + foreach (s; *d.members) + s.accept(this); + depth--; + buf.put('}'); + newline(); + } + + void visitClassDeclaration(ASTCodegen.ClassDeclaration d) + { + if (!d.isAnonymous()) + { + buf.put(d.kind().toDString()); + buf.put(' '); + buf.put(d.ident.toString()); + } + visitBaseClasses(d); + if (d.members) + { + newline(); + buf.put('{'); + newline(); + depth++; + foreach (s; *d.members) + s.accept(this); + depth--; + buf.put('}'); + } + else + buf.put(';'); + newline(); + } + + void visitAliasDeclaration(ASTCodegen.AliasDeclaration d) + { + if (d.storage_class & STC.local) + return; + buf.put("alias "); + if (d.aliassym) + { + buf.put(d.ident.toString()); + buf.put(" = "); + writeStc(d.storage_class); + /* + https://issues.dlang.org/show_bug.cgi?id=23223 + https://issues.dlang.org/show_bug.cgi?id=23222 + This special case (initially just for modules) avoids some segfaults + and nicer -vcg-ast output. + */ + if (d.aliassym.isModule()) + { + buf.put(d.aliassym.ident.toString()); + } + else + { + d.aliassym.accept(this); + } + } + else if (d.type.ty == Tfunction) + { + writeStc(d.storage_class); + writeTypeWithIdent(d.type, d.ident); + } + else if (d.ident) + { + import dmd.id : Id; + + declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id + .dstring); + buf.put(d.ident.toString()); + buf.put(" = "); + writeStc(d.storage_class); + writeTypeWithIdent(d.type, null); + declstring = false; + } + buf.put(';'); + newline(); + } + + void visitAliasAssign(ASTCodegen.AliasAssign d) + { + buf.put(d.ident.toString()); + buf.put(" = "); + if (d.aliassym) + d.aliassym.accept(this); + else // d.type + writeTypeWithIdent(d.type, null); + buf.put(';'); + newline(); + } + + void visitVarDeclaration(ASTCodegen.VarDeclaration d) + { + if (d.storage_class & STC.local) + return; + writeVarDecl(d, false); + buf.put(';'); + newline(); + } + + void visitFuncDeclaration(ASTCodegen.FuncDeclaration f) + { + newline(); + writeStc(f.storage_class); + auto tf = cast(TypeFunction) f.type; + writeTypeWithIdent(tf, f.ident); + writeFuncBody(f); + /* writeln("Wrote body"); */ + } + + void visitFuncLiteralDeclaration(ASTCodegen.FuncLiteralDeclaration f) + { + if (f.type.ty == Terror) + { + buf.put("__error"); + return; + } + if (f.tok != TOK.reserved) + { + buf.put(f.kind().toDString()); + buf.put(' '); + } + TypeFunction tf = cast(TypeFunction) f.type; + + if (!f.inferRetType && tf.next) + writeTypeWithIdent(tf.next, null); + writeParamList(tf.parameterList); + + // https://issues.dlang.org/show_bug.cgi?id=20074 + void printAttribute(string str) + { + buf.put(' '); + buf.put(str); + } + + tf.attributesApply(&printAttribute); + + ASTCodegen.CompoundStatement cs = f.fbody.isCompoundStatement(); + ASTCodegen.Statement s1; + s1 = !cs ? f.fbody : null; + ASTCodegen.ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null; + if (rs && rs.exp) + { + buf.put(" => "); + writeExpr(rs.exp); + } + else + { + writeFuncBody(f); + } + } + + void visitPostBlitDeclaration(ASTCodegen.PostBlitDeclaration d) + { + writeStc(d.storage_class); + buf.put("this(this)"); + writeFuncBody(d); + } + + void visitDtorDeclaration(ASTCodegen.DtorDeclaration d) + { + writeStc(d.storage_class); + buf.put("~this()"); + writeFuncBody(d); + } + + void visitStaticCtorDeclaration(ASTCodegen.StaticCtorDeclaration d) + { + writeStc(d.storage_class & ~STC.static_); + if (d.isSharedStaticCtorDeclaration()) + buf.put("shared "); + buf.put("static this()"); + writeFuncBody(d); + } + + void visitStaticDtorDeclaration(ASTCodegen.StaticDtorDeclaration d) + { + writeStc(d.storage_class & ~STC.static_); + if (d.isSharedStaticDtorDeclaration()) + buf.put("shared "); + buf.put("static ~this()"); + writeFuncBody(d); + } + + void visitInvariantDeclaration(ASTCodegen.InvariantDeclaration d) + { + writeStc(d.storage_class); + buf.put("invariant"); + if (auto es = d.fbody.isExpStatement()) + { + assert(es.exp && es.exp.op == EXP.assert_); + buf.put(" ("); + writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); + buf.put(");"); + newline(); + } + else + { + writeFuncBody(d); + } + } + + void visitUnitTestDeclaration(ASTCodegen.UnitTestDeclaration d) + { + writeStc(d.storage_class); + buf.put("unittest"); + writeFuncBody(d); + } + + void visitBitFieldDeclaration(ASTCodegen.BitFieldDeclaration d) + { + writeStc(d.storage_class); + Identifier id = d.isAnonymous() ? null : d.ident; + writeTypeWithIdent(d.type, id); + buf.put(" : "); + writeExpr(d.width); + buf.put(';'); + newline(); + } + + void visitNewDeclaration(ASTCodegen.NewDeclaration d) + { + writeStc(d.storage_class & ~STC.static_); + buf.put("new();"); + } + + void visitModule(ASTCodegen.Module m) + { + if (m.md) + { + if (m.userAttribDecl) + { + buf.put("@("); + writeArgs(m.userAttribDecl.atts); + buf.put(')'); + newline(); + } + if (m.md.isdeprecated) + { + if (m.md.msg) + { + buf.put("deprecated("); + writeExpr(m.md.msg); + buf.put(") "); + } + else + buf.put("deprecated "); + } + buf.put("module "); + buf.put(m.md.toString()); + buf.put(';'); + newline(); + } + + foreach (s; *m.members) + { + s.accept(this); + } + } + + void visitDebugCondition(ASTCodegen.DebugCondition c) + { + buf.put("debug ("); + if (c.ident) + buf.put(c.ident.toString()); + else + buf.put(format("%d", c.level)); + buf.put(')'); + } + + void visitVersionCondition(ASTCodegen.VersionCondition c) + { + buf.put("version ("); + if (c.ident) + buf.put(c.ident.toString()); + else + buf.put(format("%d", c.level)); + buf.put(')'); + } + + void visitStaticIfCondition(ASTCodegen.StaticIfCondition c) + { + buf.put("static if ("); + writeExpr(c.exp); + buf.put(')'); + } + + void visitTemplateTypeParameter(ASTCodegen.TemplateTypeParameter tp) + { + buf.put(tp.ident.toString()); + if (tp.specType) + { + buf.put(" : "); + writeTypeWithIdent(tp.specType, null); + } + if (tp.defaultType) + { + buf.put(" = "); + writeTypeWithIdent(tp.defaultType, null); + } + } + + void visitTemplateThisParameter(ASTCodegen.TemplateThisParameter tp) + { + buf.put("this "); + visit(cast(ASTCodegen.TemplateTypeParameter) tp); + } + + void visitTemplateAliasParameter(ASTCodegen.TemplateAliasParameter tp) + { + buf.put("alias "); + if (tp.specType) + writeTypeWithIdent(tp.specType, tp.ident); + else + buf.put(tp.ident.toString()); + if (tp.specAlias) + { + buf.put(" : "); + writeObject(tp.specAlias); + } + if (tp.defaultAlias) + { + buf.put(" = "); + writeObject(tp.defaultAlias); + } + } + + void visitTemplateValueParameter(ASTCodegen.TemplateValueParameter tp) + { + writeTypeWithIdent(tp.valType, tp.ident); + if (tp.specValue) + { + buf.put(" : "); + writeExpr(tp.specValue); + } + if (tp.defaultValue) + { + buf.put(" = "); + writeExpr(tp.defaultValue); + } + } + + void visitTemplateTupleParameter(ASTCodegen.TemplateTupleParameter tp) + { + buf.put(tp.ident.toString()); + buf.put("..."); + } + +override: + // dfmt off + void visit(ASTCodegen.Dsymbol s) { visitDsymbol(s); } + void visit(ASTCodegen.StaticAssert s) { visitStaticAssert(s); } + void visit(ASTCodegen.DebugSymbol s) { visitDebugSymbol(s); } + void visit(ASTCodegen.VersionSymbol s) { visitVersionSymbol(s); } + void visit(ASTCodegen.EnumMember em) { visitEnumMember(em); } + void visit(ASTCodegen.Import imp) { visitImport(imp); } + void visit(ASTCodegen.AliasThis d) { visitAliasThis(d); } + void visit(ASTCodegen.AttribDeclaration d) { visitAttribDeclaration(d); } + void visit(ASTCodegen.StorageClassDeclaration d) { visitStorageClassDeclaration(d); } + void visit(ASTCodegen.DeprecatedDeclaration d) { visitDeprecatedDeclaration(d); } + void visit(ASTCodegen.LinkDeclaration d) { visitLinkDeclaration(d); } + void visit(ASTCodegen.CPPMangleDeclaration d) { visitCPPMangleDeclaration(d); } + void visit(ASTCodegen.VisibilityDeclaration d) { visitVisibilityDeclaration(d); } + void visit(ASTCodegen.AlignDeclaration d) { visitAlignDeclaration(d); } + void visit(ASTCodegen.AnonDeclaration d) { visitAnonDeclaration(d); } + void visit(ASTCodegen.PragmaDeclaration d) { visitPragmaDeclaration(d); } + void visit(ASTCodegen.ConditionalDeclaration d) { visitConditionalDeclaration(d); } + void visit(ASTCodegen.StaticForeachDeclaration s) { visitStaticForeachDeclaration(s); } + void visit(ASTCodegen.MixinDeclaration d) { visitMixinDeclaration(d); } + void visit(ASTCodegen.UserAttributeDeclaration d) { visitUserAttributeDeclaration(d); } + void visit(ASTCodegen.TemplateDeclaration d) { visitTemplateDeclaration(d); } + void visit(ASTCodegen.TemplateInstance ti) { visitTemplateInstance(ti); } + void visit(ASTCodegen.TemplateMixin tm) { visitTemplateMixin(tm); } + void visit(ASTCodegen.EnumDeclaration d) { visitEnumDeclaration(d); } + void visit(ASTCodegen.Nspace d) { visitNspace(d); } + void visit(ASTCodegen.StructDeclaration d) { visitStructDeclaration(d); } + void visit(ASTCodegen.ClassDeclaration d) { visitClassDeclaration(d); } + void visit(ASTCodegen.AliasDeclaration d) { visitAliasDeclaration(d); } + void visit(ASTCodegen.AliasAssign d) { visitAliasAssign(d); } + void visit(ASTCodegen.VarDeclaration d) { visitVarDeclaration(d); } + void visit(ASTCodegen.FuncDeclaration f) { visitFuncDeclaration(f); } + void visit(ASTCodegen.FuncLiteralDeclaration f) { visitFuncLiteralDeclaration(f); } + void visit(ASTCodegen.PostBlitDeclaration d) { visitPostBlitDeclaration(d); } + void visit(ASTCodegen.DtorDeclaration d) { visitDtorDeclaration(d); } + void visit(ASTCodegen.StaticCtorDeclaration d) { visitStaticCtorDeclaration(d); } + void visit(ASTCodegen.StaticDtorDeclaration d) { visitStaticDtorDeclaration(d); } + void visit(ASTCodegen.InvariantDeclaration d) { visitInvariantDeclaration(d); } + void visit(ASTCodegen.UnitTestDeclaration d) { visitUnitTestDeclaration(d); } + void visit(ASTCodegen.BitFieldDeclaration d) { visitBitFieldDeclaration(d); } + void visit(ASTCodegen.NewDeclaration d) { visitNewDeclaration(d); } + void visit(ASTCodegen.Module m) { visitModule(m); } + void visit(ASTCodegen.DebugCondition m) { visitDebugCondition(m); } + void visit(ASTCodegen.VersionCondition m) { visitVersionCondition(m); } + void visit(ASTCodegen.StaticIfCondition m) { visitStaticIfCondition(m); } + void visit(ASTCodegen.TemplateTypeParameter m) { visitTemplateTypeParameter(m); } + void visit(ASTCodegen.TemplateThisParameter m) { visitTemplateThisParameter(m); } + void visit(ASTCodegen.TemplateAliasParameter m) { visitTemplateAliasParameter(m); } + void visit(ASTCodegen.TemplateValueParameter m) { visitTemplateValueParameter(m); } + void visit(ASTCodegen.TemplateTupleParameter m) { visitTemplateTupleParameter(m); } + // dfmt on +} diff --git a/src/dfmt/ast_info.d b/src/dfmt/ast_info.d deleted file mode 100644 index 78f16d6..0000000 --- a/src/dfmt/ast_info.d +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright Brian Schott 2015. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -module dfmt.ast_info; - -import dmd.transitivevisitor; -import dmd.tokens; - -enum BraceIndentInfoFlags -{ - tempIndent = 1 << 0, -} - -struct BraceIndentInfo -{ - size_t startLocation; - size_t endLocation; - - uint flags; - - uint beginIndentLevel; -} - -struct StructInitializerInfo -{ - size_t startLocation; - size_t endLocation; -} - -/// AST information that is needed by the formatter. -struct ASTInformation -{ - /// Sorts the arrays so that binary search will work on them - void cleanup() - { - import std.algorithm : sort, uniq; - import std.array : array; - - sort(doubleNewlineLocations); - sort(spaceAfterLocations); - sort(unaryLocations); - sort(attributeDeclarationLines); - sort(atAttributeStartLocations); - sort(caseEndLocations); - sort(structInitStartLocations); - sort(structInitEndLocations); - sort(funLitStartLocations); - sort(funLitEndLocations); - sort(conditionalWithElseLocations); - sort(conditionalStatementLocations); - sort(arrayStartLocations); - sort(assocArrayStartLocations); - sort(contractLocations); - sort(constraintLocations); - sort(constructorDestructorLocations); - sort(staticConstructorDestructorLocations); - sort(sharedStaticConstructorDestructorLocations); - sort!((a, b) => a.endLocation < b.endLocation)(indentInfoSortedByEndLocation); - sort!((a, b) => a.endLocation < b.endLocation)(structInfoSortedByEndLocation); - sort(ufcsHintLocations); - ufcsHintLocations = ufcsHintLocations.uniq().array(); - sort(ternaryColonLocations); - sort(namedArgumentColonLocations); - } - - /// Locations of end braces for struct bodies - size_t[] doubleNewlineLocations; - - /// Locations of tokens where a space is needed (such as the '*' in a type) - size_t[] spaceAfterLocations; - - /// Locations of unary operators - size_t[] unaryLocations; - - /// Lines containing attribute declarations - size_t[] attributeDeclarationLines; - - /// Lines containing attribute declarations that can be followed by a new line - size_t[] atAttributeStartLocations; - - /// Case statement colon locations - size_t[] caseEndLocations; - - /// Opening braces of struct initializers - size_t[] structInitStartLocations; - - /// Closing braces of struct initializers - size_t[] structInitEndLocations; - - /// Opening braces of function literals - size_t[] funLitStartLocations; - - /// Closing braces of function literals - size_t[] funLitEndLocations; - - /// Locations of aggregate bodies (struct, class, union) - size_t[] aggregateBodyLocations; - - /// Locations of function bodies - size_t[] funBodyLocations; - - /// Conditional statements that have matching "else" statements - size_t[] conditionalWithElseLocations; - - /// Conditional statement locations - size_t[] conditionalStatementLocations; - - /// Locations of start locations of array initializers - size_t[] arrayStartLocations; - - /// Locations of start locations of associative array initializers - size_t[] assocArrayStartLocations; - - /// Locations of "in" and "out" tokens that begin contracts - size_t[] contractLocations; - - /// Locations of template constraint "if" tokens - size_t[] constraintLocations; - - /// Locations of constructor/destructor "shared" tokens ? - size_t[] sharedStaticConstructorDestructorLocations; - - /// Locations of constructor/destructor "static" tokens ? - size_t[] staticConstructorDestructorLocations; - - /// Locations of constructor/destructor "this" tokens ? - size_t[] constructorDestructorLocations; - - /// Locations of '.' characters that might be UFCS chains. - size_t[] ufcsHintLocations; - - BraceIndentInfo[] indentInfoSortedByEndLocation; - - /// Opening & closing braces of struct initializers - StructInitializerInfo[] structInfoSortedByEndLocation; - - /// Locations ternary expression colons. - size_t[] ternaryColonLocations; - - /// Locations of named arguments of function call or struct constructor. - size_t[] namedArgumentColonLocations; -} - -/// Collects information from the AST that is useful for the formatter -extern (C++) class FormatVisitor(AST) : ParseTimeTransitiveVisitor!AST -{ - alias visit = ParseTimeTransitiveVisitor!AST.visit; - - /** - * Params: - * astInformation = the AST information that will be filled in - */ - this(ASTInformation* astInformation) - { - this.astInformation = astInformation; - } - - /* override void visit(const ArrayInitializer arrayInitializer) */ - /* { */ - /* astInformation.arrayStartLocations ~= arrayInitializer.startLocation; */ - /* arrayInitializer.accept(this); */ - /* } */ - - /* override void visit(const ArrayLiteral arrayLiteral) */ - /* { */ - /* astInformation.arrayStartLocations ~= arrayLiteral.tokens[0].index; */ - /* arrayLiteral.accept(this); */ - /* } */ - - /* override void visit(const AssocArrayLiteral assocArrayLiteral) */ - /* { */ - /* astInformation.arrayStartLocations ~= assocArrayLiteral.tokens[0].index; */ - /* astInformation.assocArrayStartLocations ~= assocArrayLiteral.tokens[0].index; */ - /* assocArrayLiteral.accept(this); */ - /* } */ - - /* override void visit(const SharedStaticConstructor sharedStaticConstructor) */ - /* { */ - /* astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticConstructor */ - /* .location; */ - /* sharedStaticConstructor.accept(this); */ - /* } */ - - /* override void visit(const SharedStaticDestructor sharedStaticDestructor) */ - /* { */ - /* astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticDestructor */ - /* .location; */ - /* sharedStaticDestructor.accept(this); */ - /* } */ - - /* override void visit(const StaticConstructor staticConstructor) */ - /* { */ - /* astInformation.staticConstructorDestructorLocations ~= staticConstructor.location; */ - /* staticConstructor.accept(this); */ - /* } */ - - /* override void visit(const StaticDestructor staticDestructor) */ - /* { */ - /* astInformation.staticConstructorDestructorLocations ~= staticDestructor.location; */ - /* staticDestructor.accept(this); */ - /* } */ - - /* override void visit(const Constructor constructor) */ - /* { */ - /* astInformation.constructorDestructorLocations ~= constructor.location; */ - /* constructor.accept(this); */ - /* } */ - - /* override void visit(const Destructor destructor) */ - /* { */ - /* astInformation.constructorDestructorLocations ~= destructor.index; */ - /* destructor.accept(this); */ - /* } */ - - /* override void visit(const FunctionBody functionBody) */ - /* { */ - /* if (auto bd = functionBody.specifiedFunctionBody) */ - /* { */ - /* if (bd.blockStatement) */ - /* { */ - /* astInformation.funBodyLocations ~= bd.blockStatement.startLocation; */ - /* } */ - /* } */ - /* functionBody.accept(this); */ - /* } */ - - /* override void visit(const ConditionalDeclaration dec) */ - /* { */ - /* if (dec.hasElse) */ - /* { */ - /* auto condition = dec.compileCondition; */ - /* if (condition.versionCondition !is null) */ - /* { */ - /* astInformation.conditionalWithElseLocations */ - /* ~= condition.versionCondition.versionIndex; */ - /* } */ - /* else if (condition.debugCondition !is null) */ - /* { */ - /* astInformation.conditionalWithElseLocations ~= condition.debugCondition.debugIndex; */ - /* } */ - /* // Skip "static if" because the formatting for normal "if" handles */ - /* // it properly */ - /* } */ - /* dec.accept(this); */ - /* } */ - - /* override void visit(const Constraint constraint) */ - /* { */ - /* astInformation.constraintLocations ~= constraint.location; */ - /* constraint.accept(this); */ - /* } */ - - /* override void visit(const ConditionalStatement statement) */ - /* { */ - /* auto condition = statement.compileCondition; */ - /* if (condition.versionCondition !is null) */ - /* { */ - /* astInformation.conditionalStatementLocations ~= condition.versionCondition.versionIndex; */ - /* } */ - /* else if (condition.debugCondition !is null) */ - /* { */ - /* astInformation.conditionalStatementLocations ~= condition.debugCondition.debugIndex; */ - /* } */ - /* statement.accept(this); */ - /* } */ - - /* override void visit(const FunctionLiteralExpression funcLit) */ - /* { */ - /* if (funcLit.specifiedFunctionBody !is null) */ - /* { */ - /* const bs = funcLit.specifiedFunctionBody.blockStatement; */ - - /* astInformation.funLitStartLocations ~= bs.startLocation; */ - /* astInformation.funLitEndLocations ~= bs.endLocation; */ - /* astInformation.indentInfoSortedByEndLocation ~= */ - /* BraceIndentInfo(bs.startLocation, bs.endLocation); */ - /* } */ - /* funcLit.accept(this); */ - /* } */ - - /* override void visit(const DefaultStatement defaultStatement) */ - /* { */ - /* astInformation.caseEndLocations ~= defaultStatement.colonLocation; */ - /* defaultStatement.accept(this); */ - /* } */ - - /* override void visit(const CaseStatement caseStatement) */ - /* { */ - /* astInformation.caseEndLocations ~= caseStatement.colonLocation; */ - /* caseStatement.accept(this); */ - /* } */ - - /* override void visit(const CaseRangeStatement caseRangeStatement) */ - /* { */ - /* astInformation.caseEndLocations ~= caseRangeStatement.colonLocation; */ - /* caseRangeStatement.accept(this); */ - /* } */ - - /* override void visit(const SpecifiedFunctionBody specifiedFunctionBody) */ - /* { */ - /* if (specifiedFunctionBody.blockStatement !is null) */ - /* astInformation.doubleNewlineLocations ~= specifiedFunctionBody */ - /* .blockStatement.endLocation; */ - /* specifiedFunctionBody.accept(this); */ - /* } */ - - /* override void visit(const StructInitializer structInitializer) */ - /* { */ - /* astInformation.structInitStartLocations ~= structInitializer.startLocation; */ - /* astInformation.structInitEndLocations ~= structInitializer.endLocation; */ - /* astInformation.structInfoSortedByEndLocation ~= */ - /* StructInitializerInfo( */ - /* structInitializer.startLocation, structInitializer.endLocation); */ - /* astInformation.indentInfoSortedByEndLocation ~= */ - /* BraceIndentInfo( */ - /* structInitializer.startLocation, structInitializer.endLocation); */ - - /* structInitializer.accept(this); */ - /* } */ - - /* override void visit(const EnumBody enumBody) */ - /* { */ - /* astInformation.doubleNewlineLocations ~= enumBody.endLocation; */ - /* enumBody.accept(this); */ - /* } */ - - /* override void visit(const Unittest unittest_) */ - /* { */ - /* astInformation.doubleNewlineLocations ~= unittest_.blockStatement.endLocation; */ - /* unittest_.accept(this); */ - /* } */ - - /* override void visit(const Invariant invariant_) */ - /* { */ - /* if (invariant_.blockStatement !is null) */ - /* astInformation.doubleNewlineLocations ~= invariant_.blockStatement.endLocation; */ - - /* invariant_.accept(this); */ - /* } */ - - /* override void visit(const StructBody structBody) */ - /* { */ - /* astInformation.aggregateBodyLocations ~= structBody.startLocation; */ - /* astInformation.doubleNewlineLocations ~= structBody.endLocation; */ - /* structBody.accept(this); */ - /* } */ - - /* override void visit(const TemplateDeclaration templateDeclaration) */ - /* { */ - /* astInformation.doubleNewlineLocations ~= templateDeclaration.endLocation; */ - /* templateDeclaration.accept(this); */ - /* } */ - - /* override void visit(const TypeSuffix typeSuffix) */ - /* { */ - /* if (typeSuffix.star.type != TOK.error) */ - /* astInformation.spaceAfterLocations ~= typeSuffix.star.index; */ - /* typeSuffix.accept(this); */ - /* } */ - - /* override void visit(const UnaryExpression unary) */ - /* { */ - /* import std.typecons : rebindable; */ - - /* int chainLength; */ - /* auto u = rebindable(unary); */ - /* while (u !is null) */ - /* { */ - /* if (u.identifierOrTemplateInstance !is null */ - /* && u.identifierOrTemplateInstance.templateInstance !is null) */ - /* chainLength++; */ - /* u = u.unaryExpression; */ - /* } */ - /* if (chainLength > 1) */ - /* { */ - /* u = unary; */ - /* while (u.unaryExpression !is null) */ - /* { */ - /* astInformation.ufcsHintLocations ~= u.dotLocation; */ - /* u = u.unaryExpression; */ - /* } */ - /* } */ - /* if (unary.prefix.type == TOK.tilde || unary.prefix.type == TOK.and */ - /* || unary.prefix.type == TOK.mul */ - /* || unary.prefix.type == TOK.add || unary.prefix.type == TOK.min) */ - /* { */ - /* astInformation.unaryLocations ~= unary.prefix.index; */ - /* } */ - /* unary.accept(this); */ - /* } */ - - /* override void visit(const AttributeDeclaration attributeDeclaration) */ - /* { */ - /* astInformation.attributeDeclarationLines ~= attributeDeclaration.line; */ - /* attributeDeclaration.accept(this); */ - /* } */ - - /* override void visit(const FunctionAttribute functionAttribute) */ - /* { */ - /* if (functionAttribute.atAttribute !is null) */ - /* astInformation.atAttributeStartLocations ~= functionAttribute.atAttribute.startLocation; */ - /* functionAttribute.accept(this); */ - /* } */ - - /* override void visit(const MemberFunctionAttribute memberFunctionAttribute) */ - /* { */ - /* if (memberFunctionAttribute.atAttribute !is null) */ - /* astInformation.atAttributeStartLocations ~= memberFunctionAttribute */ - /* .atAttribute.startLocation; */ - /* memberFunctionAttribute.accept(this); */ - /* } */ - - /* override void visit(const Attribute attribute) */ - /* { */ - /* if (attribute.atAttribute !is null) */ - /* astInformation.atAttributeStartLocations ~= attribute.atAttribute.startLocation; */ - /* attribute.accept(this); */ - /* } */ - - /* override void visit(const StorageClass storageClass) */ - /* { */ - /* if (storageClass.atAttribute !is null) */ - /* astInformation.atAttributeStartLocations ~= storageClass.atAttribute.startLocation; */ - /* storageClass.accept(this); */ - /* } */ - - /* override void visit(const InContractExpression inContractExpression) */ - /* { */ - /* astInformation.contractLocations ~= inContractExpression.inTokenLocation; */ - /* inContractExpression.accept(this); */ - /* } */ - - /* override void visit(const InStatement inStatement) */ - /* { */ - /* astInformation.contractLocations ~= inStatement.inTokenLocation; */ - /* inStatement.accept(this); */ - /* } */ - - /* override void visit(const OutContractExpression outContractExpression) */ - /* { */ - /* astInformation.contractLocations ~= outContractExpression.outTokenLocation; */ - /* outContractExpression.accept(this); */ - /* } */ - - /* override void visit(const OutStatement outStatement) */ - /* { */ - /* astInformation.contractLocations ~= outStatement.outTokenLocation; */ - /* outStatement.accept(this); */ - /* } */ - - override void visit(const TernaryExpression ternaryExpression) - { - astInformation.ternaryColonLocations ~= ternaryExpression.colon.index; - ternaryExpression.accept(this); - } - - override void visit(const FunctionCallExpression functionCall) - { - // Check if function has any arguments. - if (functionCall.arguments.namedArgumentList is null) - { - functionCall.accept(this); - return; - } - - foreach (item; functionCall.arguments.namedArgumentList.items) - { - // Do nothing if not a named argument. - if (item.name == tok!"") - { - continue; - } - - // Find first colon if named argument. - foreach (t; item.tokens) - { - if (t.type == tok!":") - { - astInformation.namedArgumentColonLocations ~= t.index; - break; - } - } - } - - functionCall.accept(this); - } - -private: - ASTInformation* astInformation; -} diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index ac0f283..d17ccfc 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -10,16 +10,15 @@ import dmd.parse; import dmd.id; import dmd.errorsink; import dmd.identifier; -import dmd.astbase; +import dmd.astcodegen; import dmd.transitivevisitor; import dmd.permissivevisitor; -import dfmt.ast_info; +import dmd.frontend; +import dfmt.ast; import dfmt.config; -import dfmt.indentation; -import dfmt.tokens; -import dfmt.wrapping; import std.array; import std.algorithm.comparison : among, max; +import std.stdio : File; /** * Formats the code contained in `buffer` into `output`. @@ -28,2382 +27,15 @@ import std.algorithm.comparison : among, max; * buffer = The raw source code. * output = The output range that will have the formatted code written to it. * formatterConfig = Formatter configuration. - * Returns: `true` if the formatting succeeded, `false` of a lexing error. This - * function can return `true` if parsing failed. + * Returns: `true` if the formatting succeeded, `false` if any error */ -bool format(OutputRange)(string source_desc, ubyte[] buffer, OutputRange output, +bool format(string source_desc, ubyte[] buffer, File.LockingTextWriter output, Config* formatterConfig) { - Id.initialize(); - ASTBase.Type._init(); + initDMD(); + auto module_ = parseModule(source_desc); + scope v = new FormatVisitor(output, formatterConfig); + v.visit(module_[0]); - auto id = Identifier.idPool(source_desc); - auto m = new ASTBase.Module(&(source_desc.dup)[0], id, false, false); - import std.file : readText; - - auto input = readText(source_desc); - auto inp = cast(char[]) input; - - auto p = new Parser!ASTBase(m, inp, false, new ErrorSinkNull, null, false); - /* p.nextToken(); */ - m.members = p.parseModule(); - - ASTInformation astInformation; - scope vis = new FormatVisitor!ASTBase(&astInformation); - m.accept(vis); - /* auto tokenRange = byToken(buffer, config, &cache); */ - /* auto app = appender!(Token[])(); */ - /* for (; !tokenRange.empty(); tokenRange.popFront()) */ - /* app.put(tokenRange.front()); */ - /* auto tokens = app.data; */ - /* if (!tokenRange.messages.empty) */ - /* return false; */ - /* auto depths = generateDepthInfo(tokens); */ - /* auto tokenFormatter = TokenFormatter!OutputRange(buffer, tokens, depths, */ - /* output, &astInformation, formatterConfig); */ - /* tokenFormatter.format(); */ return true; } - -immutable(short[]) generateDepthInfo(const Token[] tokens) pure nothrow @trusted -{ - import std.exception : assumeUnique; - - short[] retVal = new short[](tokens.length); - short depth = 0; - foreach (i, ref t; tokens) - { - switch (t.value) - { - case TOK.leftBracket: - depth++; - goto case; - case TOK.leftCurly: - case TOK.leftParenthesis: - depth++; - break; - case TOK.rightBracket: - depth--; - goto case; - case TOK.rightCurly: - case TOK.rightParenthesis: - depth--; - break; - default: - break; - } - retVal[i] = depth; - } - return cast(immutable) retVal; -} - -struct TokenFormatter(OutputRange) -{ - /** - * Params: - * rawSource = ? - * tokens = the tokens to format - * depths = ? - * output = the output range that the code will be formatted to - * astInformation = information about the AST used to inform formatting - * decisions. - * config = ? - */ - this(const ubyte[] rawSource, const(Token)[] tokens, immutable short[] depths, - OutputRange output, ASTInformation* astInformation, Config* config) - { - this.rawSource = rawSource; - this.tokens = tokens; - this.depths = depths; - this.output = output; - this.astInformation = astInformation; - this.config = config; - this.indents = IndentStack(config); - - { - auto eol = config.end_of_line; - if (eol == eol.cr) - this.eolString = "\r"; - else if (eol == eol.lf) - this.eolString = "\n"; - else if (eol == eol.crlf) - this.eolString = "\r\n"; - else if (eol == eol._unspecified) - assert(false, "config.end_of_line was unspecified"); - else - { - assert(eol == eol._default); - this.eolString = eolStringFromInput; - } - } - } - - /// Runs the formatting process - void format() - { - while (hasCurrent) - formatStep(); - } - -private: - - /// Current indentation level - int indentLevel; - - /// Current index into the tokens array - size_t index; - - /// Length of the current line (so far) - uint currentLineLength = 0; - - /// Output to write output to - OutputRange output; - - /// Used for skipping parts of the file with `dfmt off` and `dfmt on` comments - const ubyte[] rawSource; - - /// Tokens being formatted - const Token[] tokens; - - /// Paren depth info - immutable short[] depths; - - /// Information about the AST - const ASTInformation* astInformation; - - /// Token indices where line breaks should be placed - size_t[] linebreakHints; - - /// Current indentation stack for the file - IndentStack indents; - - /// Configuration - const Config* config; - - /// chached end of line string - const string eolString; - - /// Keep track of whether or not an extra newline was just added because of - /// an import statement. - bool justAddedExtraNewline; - - /// Current paren depth - int parenDepth; - - /// Current special brace depth. Used for struct initializers and lambdas. - int sBraceDepth; - - /// Current non-indented brace depth. Used for struct initializers and lambdas. - int niBraceDepth; - - /// True if a space should be placed when parenDepth reaches zero - bool spaceAfterParens; - - /// True if we're in an ASM block - bool inAsm; - - /// True if the next "this" should have a space behind it - bool thisSpace; - - /// True if the next "else" should be formatted as a single line - bool inlineElse; - - /// Tracks paren depth on a single line. This information can be used to - /// indent array literals inside parens, since arrays are indented only once - /// and paren indentation is ignored. Line breaks and "[" reset the counter. - int parenDepthOnLine; - - string eolStringFromInput() const - { - import std.algorithm : countUntil; - - // Intentional wraparound, -1 turns into uint.max when not found: - const firstCR = cast(uint) rawSource.countUntil("\r"); - if (firstCR < cast(uint) rawSource.countUntil("\n")) - return firstCR == rawSource.countUntil("\r\n") ? "\r\n" : "\r"; - return "\n"; - } - - void formatStep() - { - return; - - /* import std.range : assumeSorted; */ - - /* assert(hasCurrent); */ - /* if (currentIs(TOK.comment)) */ - /* { */ - /* formatComment(); */ - /* } */ - /* else if (isStringLiteral(current.value) */ - /* || isNumberLiteral(current.value) || currentIs(TOK.charLiteral)) */ - /* { */ - /* writeToken(); */ - /* if (hasCurrent) */ - /* { */ - /* immutable t = tokens[index].value; */ - /* if (t == TOK.identifier || isStringLiteral(t) */ - /* || isNumberLiteral(t) || t == TOK.charLiteral // a!"b" function() */ - /* || t == TOK.function_ || t == TOK.delegate_) */ - /* write(" "); */ - /* } */ - /* } */ - /* else if (currentIs(TOK.module_) || currentIs(TOK.import_)) */ - /* { */ - /* formatModuleOrImport(); */ - /* } */ - /* else if (currentIs(TOK.return_)) */ - /* { */ - /* writeToken(); */ - /* if (hasCurrent && (!currentIs(TOK.semicolon) && !currentIs(TOK.rightParenthesis) && !currentIs( */ - /* TOK.leftCurly) */ - /* && !currentIs(TOK.in_) && !currentIs(TOK.out_) && !currentIs(TOK.do_) */ - /* && tokens[index].text != "body")) */ - /* write(" "); */ - /* } */ - /* else if (currentIs(TOK.with_)) */ - /* { */ - /* if (indents.length == 0 || !indents.topIsOneOf(TOK.switch_, TOK.with_)) */ - /* indents.push(TOK.with_); */ - /* writeToken(); */ - /* if (config.dfmt_space_after_keywords) */ - /* { */ - /* write(" "); */ - /* } */ - /* if (hasCurrent && currentIs(TOK.leftParenthesis)) */ - /* writeParens(false); */ - /* if (hasCurrent && !currentIs(TOK.switch_) && !currentIs(TOK.with_) */ - /* && !currentIs(TOK.leftCurly) && !(currentIs(TOK.final_) && peekIs(TOK.switch_))) */ - /* { */ - /* newline(); */ - /* } */ - /* else if (hasCurrent && !currentIs(TOK.leftCurly)) */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - /* else if (currentIs(TOK.switch_)) */ - /* { */ - /* formatSwitch(); */ - /* } */ - /* else if (currentIs(TOK.extern_) && peekIs(TOK.leftParenthesis)) */ - /* { */ - /* writeToken(); */ - /* write(" "); */ - /* while (hasCurrent) */ - /* { */ - /* if (currentIs(TOK.leftParenthesis)) */ - /* formatLeftParenOrBracket(); */ - /* else if (currentIs(TOK.rightParenthesis)) */ - /* { */ - /* formatRightParen(); */ - /* break; */ - /* } */ - /* else */ - /* writeToken(); */ - /* } */ - /* } */ - /* else if (((isBlockHeader() || currentIs(TOK.version_)) && peekIs(TOK.leftParenthesis)) */ - /* || (currentIs(TOK.debug_) && peekIs(TOK.leftCurly))) */ - /* { */ - /* if (!assumeSorted(astInformation.constraintLocations).equalRange(current.index).empty) */ - /* formatConstraint(); */ - /* else */ - /* formatBlockHeader(); */ - /* } */ - /* else if ((current.text == "body" || current == TOK.do_) && peekBackIsFunctionDeclarationEnding()) */ - /* { */ - /* formatKeyword(); */ - /* } */ - /* else if (currentIs(TOK.do_)) */ - /* { */ - /* formatBlockHeader(); */ - /* } */ - /* else if (currentIs(TOK.else_)) */ - /* { */ - /* formatElse(); */ - /* } */ - /* else if (currentIs(TOK.asm_)) */ - /* { */ - /* formatKeyword(); */ - /* while (hasCurrent && !currentIs(TOK.leftCurly)) */ - /* formatStep(); */ - /* if (hasCurrent) */ - /* { */ - /* int depth = 1; */ - /* formatStep(); */ - /* inAsm = true; */ - /* while (hasCurrent && depth > 0) */ - /* { */ - /* if (currentIs(TOK.leftCurly)) */ - /* ++depth; */ - /* else if (currentIs(TOK.rightCurly)) */ - /* --depth; */ - /* formatStep(); */ - /* } */ - /* inAsm = false; */ - /* } */ - /* } */ - /* else if (currentIs(TOK.this_)) */ - /* { */ - /* const thisIndex = current.index; */ - /* formatKeyword(); */ - /* if (config.dfmt_space_before_function_parameters */ - /* && (thisSpace || astInformation.constructorDestructorLocations */ - /* .canFindIndex(thisIndex))) */ - /* { */ - /* write(" "); */ - /* thisSpace = false; */ - /* } */ - /* } */ - /* else if (isKeyword(current.value)) */ - /* { */ - /* if (currentIs(TOK.debug_)) */ - /* inlineElse = true; */ - /* formatKeyword(); */ - /* } */ - /* else if (isBasicType(current.value)) */ - /* { */ - /* writeToken(); */ - /* if (hasCurrent && (currentIs(TOK.identifier) || isKeyword(current.value) || inAsm)) */ - /* write(" "); */ - /* } */ - /* else if (isOperator(current.value)) */ - /* { */ - /* formatOperator(); */ - /* } */ - /* else if (currentIs(TOK.identifier)) */ - /* { */ - /* writeToken(); */ - /* //dfmt off */ - /* if (hasCurrent && ( currentIs(TOK.identifier) */ - /* || ( index > 1 && config.dfmt_space_before_function_parameters */ - /* && ( isBasicType(peekBack(2).value) */ - /* || peekBack2Is(TOK.identifier) */ - /* || peekBack2Is(TOK.rightParenthesis) */ - /* || peekBack2Is(TOK.rightBracket) ) */ - /* && currentIs(TOK.leftParenthesis) */ - /* || isBasicType(current.value) || currentIs(TOK.at) */ - /* || isNumberLiteral(tokens[index].value) */ - /* || (inAsm && peekBack2Is(TOK.semicolon) && currentIs(TOK.leftBracket)) */ - /* ))) */ - /* //dfmt on */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - /* else if (currentIs(TOK.line)) */ - /* { */ - /* writeToken(); */ - /* newline(); */ - /* } */ - /* else */ - /* writeToken(); */ - } - - /* void formatConstraint() */ - /* { */ - /* import dfmt.editorconfig : OB = OptionalBoolean; */ - - /* with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style) */ - /* { */ - /* case _unspecified: */ - /* assert(false, "Config was not validated properly"); */ - /* case conditional_newline: */ - /* immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); */ - /* if (l > config.dfmt_soft_max_line_length) */ - /* newline(); */ - /* else if (peekBackIs(TOK.rightParenthesis) || peekBackIs(TOK.identifier)) */ - /* write(" "); */ - /* break; */ - /* case always_newline: */ - /* newline(); */ - /* break; */ - /* case conditional_newline_indent: */ - /* immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); */ - /* if (l > config.dfmt_soft_max_line_length) */ - /* { */ - /* config.dfmt_single_template_constraint_indent == OB.t ? */ - /* pushWrapIndent() : pushWrapIndent(TOK.not); */ - /* newline(); */ - /* } */ - /* else if (peekBackIs(TOK.rightParenthesis) || peekBackIs(TOK.identifier)) */ - /* write(" "); */ - /* break; */ - /* case always_newline_indent: */ - /* { */ - /* config.dfmt_single_template_constraint_indent == OB.t ? */ - /* pushWrapIndent() : pushWrapIndent(TOK.not); */ - /* newline(); */ - /* } */ - /* break; */ - /* } */ - /* // if */ - /* writeToken(); */ - /* // assume that the parens are present, otherwise the parser would not */ - /* // have told us there was a constraint here */ - /* write(" "); */ - /* writeParens(false); */ - /* } */ - - /* string commentText(size_t i) */ - /* { */ - /* import std.string : strip; */ - - /* assert(tokens[i].value == TOK.comment); */ - /* string commentText = tokens[i].text; */ - /* if (commentText[0 .. 2] == "//") */ - /* commentText = commentText[2 .. $]; */ - /* else */ - /* { */ - /* if (commentText.length > 3) */ - /* commentText = commentText[2 .. $ - 2]; */ - /* else */ - /* commentText = commentText[2 .. $]; */ - /* } */ - /* return commentText.strip(); */ - /* } */ - - /* void skipFormatting() */ - /* { */ - /* size_t dfmtOff = index; */ - /* size_t dfmtOn = index; */ - /* foreach (i; dfmtOff + 1 .. tokens.length) */ - /* { */ - /* dfmtOn = i; */ - /* if (tokens[i].value != TOK.comment) */ - /* continue; */ - /* immutable string commentText = commentText(i); */ - /* if (commentText == "dfmt on") */ - /* break; */ - /* } */ - /* write(cast(string) rawSource[tokens[dfmtOff].index .. tokens[dfmtOn].index]); */ - /* index = dfmtOn; */ - /* } */ - - /* void formatComment() */ - /* { */ - /* if (commentText(index) == "dfmt off") */ - /* { */ - /* skipFormatting(); */ - /* return; */ - /* } */ - - /* immutable bool currIsSlashSlash = tokens[index].text[0 .. 2] == "//"; */ - /* immutable prevTokenEndLine = index == 0 ? size_t.max : tokenEndLine(tokens[index - 1]); */ - /* immutable size_t currTokenLine = tokens[index].line; */ - /* if (index > 0) */ - /* { */ - /* immutable t = tokens[index - 1].value; */ - /* immutable canAddNewline = currTokenLine - prevTokenEndLine < 1; */ - /* if (peekBackIsOperator() && !isSeparationToken(t)) */ - /* pushWrapIndent(t); */ - /* else if (peekBackIs(TOK.comma) && prevTokenEndLine == currTokenLine */ - /* && indents.indentToMostRecent(TOK.enum_) == -1) */ - /* pushWrapIndent(TOK.comma); */ - /* if (peekBackIsOperator() && !peekBackIsOneOf(false, TOK.comment, */ - /* TOK.leftCurly, TOK.rightCurly, TOK.colon, TOK.semicolon, TOK.comma, TOK.leftBracket, TOK */ - /* .leftParenthesis) */ - /* && !canAddNewline && prevTokenEndLine < currTokenLine) */ - /* write(" "); */ - /* else if (prevTokenEndLine == currTokenLine || (t == TOK.rightParenthesis && peekIs( */ - /* TOK.leftCurly))) */ - /* write(" "); */ - /* else if (peekBackIsOneOf(false, TOK.else_, TOK.identifier)) */ - /* write(" "); */ - /* else if (canAddNewline || (peekIs(TOK.leftCurly) && t == TOK.rightCurly)) */ - /* newline(); */ - - /* if (peekIs(TOK.leftParenthesis) && (peekBackIs(TOK.rightParenthesis) || peekBack2Is( */ - /* TOK.not))) */ - /* pushWrapIndent(TOK.leftParenthesis); */ - - /* if (peekIs(TOK.dot) && !indents.topIs(TOK.dot)) */ - /* indents.push(TOK.dot); */ - /* } */ - /* writeToken(); */ - /* immutable j = justAddedExtraNewline; */ - /* if (currIsSlashSlash) */ - /* { */ - /* newline(); */ - /* justAddedExtraNewline = j; */ - /* } */ - /* else if (hasCurrent) */ - /* { */ - /* if (prevTokenEndLine == tokens[index].line) */ - /* { */ - /* if (currentIs(TOK.rightCurly)) */ - /* { */ - /* if (indents.topIs(TOK.leftCurly)) */ - /* indents.pop(); */ - /* write(" "); */ - /* } */ - /* else if (!currentIs(TOK.leftCurly)) */ - /* write(" "); */ - /* } */ - /* else if (!currentIs(TOK.leftCurly) && !currentIs(TOK.in_) && !currentIs(TOK.out_)) */ - /* { */ - /* if (currentIs(TOK.rightParenthesis) && indents.topIs(TOK.comma)) */ - /* indents.pop(); */ - /* else if (peekBack2Is(TOK.comma) && !indents.topIs(TOK.comma) */ - /* && indents.indentToMostRecent(TOK.enum_) == -1) */ - /* pushWrapIndent(TOK.comma); */ - /* newline(); */ - /* } */ - /* } */ - /* else */ - /* newline(); */ - /* } */ - - /* void formatModuleOrImport() */ - /* { */ - /* immutable t = current.value; */ - /* writeToken(); */ - /* if (currentIs(TOK.leftParenthesis)) */ - /* { */ - /* writeParens(false); */ - /* return; */ - /* } */ - /* write(" "); */ - /* while (hasCurrent) */ - /* { */ - /* if (currentIs(TOK.semicolon)) */ - /* { */ - /* indents.popWrapIndents(); */ - /* indentLevel = indents.indentLevel; */ - /* writeToken(); */ - /* if (index >= tokens.length) */ - /* { */ - /* newline(); */ - /* break; */ - /* } */ - /* if (currentIs(TOK.comment) && current.line == peekBack().line) */ - /* { */ - /* break; */ - /* } */ - /* else if (currentIs(TOK.leftCurly) && config.dfmt_brace_style == BraceStyle.allman) */ - /* break; */ - /* else if (t == TOK.import_ && !currentIs(TOK.import_) */ - /* && !currentIs(TOK.rightCurly) */ - /* && !((currentIs(TOK.public_) */ - /* || currentIs(TOK.private_) */ - /* || currentIs(TOK.static_)) */ - /* && peekIs(TOK.import_)) && !indents.topIsOneOf(TOK.if_, */ - /* TOK.debug_, TOK.version_)) */ - /* { */ - /* simpleNewline(); */ - /* currentLineLength = 0; */ - /* justAddedExtraNewline = true; */ - /* newline(); */ - /* } */ - /* else */ - /* newline(); */ - /* break; */ - /* } */ - /* else if (currentIs(TOK.colon)) */ - /* { */ - /* if (config.dfmt_selective_import_space) */ - /* write(" "); */ - /* writeToken(); */ - /* if (!currentIs(TOK.comment)) */ - /* write(" "); */ - /* pushWrapIndent(TOK.comma); */ - /* } */ - /* else if (currentIs(TOK.comment)) */ - /* { */ - /* if (peekBack.line != current.line) */ - /* { */ - /* // The comment appears on its own line, keep it there. */ - /* if (!peekBackIs(TOK.comment)) // Comments are already properly separated. */ - /* newline(); */ - /* } */ - /* formatStep(); */ - /* } */ - /* else */ - /* formatStep(); */ - /* } */ - /* } */ - - /* void formatLeftParenOrBracket() */ - /* in */ - /* { */ - /* assert(currentIs(TOK.leftParenthesis) || currentIs(TOK.leftBracket)); */ - /* } */ - /* do */ - /* { */ - /* import dfmt.editorconfig : OptionalBoolean; */ - - /* immutable p = current.value; */ - /* regenLineBreakHintsIfNecessary(index); */ - /* writeToken(); */ - /* if (p == TOK.leftParenthesis) */ - /* { */ - /* ++parenDepthOnLine; */ - /* // If the file starts with an open paren, just give up. This isn't */ - /* // valid D code. */ - /* if (index < 2) */ - /* return; */ - /* if (isBlockHeaderToken(tokens[index - 2].value)) */ - /* indents.push(TOK.rightParenthesis); */ - /* else */ - /* indents.push(p); */ - /* spaceAfterParens = true; */ - /* parenDepth++; */ - /* } */ - /* // No heuristics apply if we can't look before the opening paren/bracket */ - /* if (index < 1) */ - /* return; */ - /* immutable bool arrayInitializerStart = p == TOK.leftBracket */ - /* && astInformation.arrayStartLocations.canFindIndex(tokens[index - 1].index); */ - - /* if (arrayInitializerStart && isMultilineAt(index - 1)) */ - /* { */ - /* revertParenIndentation(); */ - - /* // Use the close bracket as the indent token to distinguish */ - /* // the array initialiazer from an array index in the newline */ - /* // handling code */ - /* IndentStack.Details detail; */ - /* detail.wrap = false; */ - /* detail.temp = false; */ - - /* // wrap and temp are set manually to the values it would actually */ - /* // receive here because we want to set breakEveryItem for the ] token to know if */ - /* // we should definitely always new-line after every comma for a big AA */ - /* detail.breakEveryItem = astInformation.assocArrayStartLocations.canFindIndex( */ - /* tokens[index - 1].index); */ - /* detail.preferLongBreaking = true; */ - - /* indents.push(TOK.rightBracket, detail); */ - /* newline(); */ - /* immutable size_t j = expressionEndIndex(index); */ - /* linebreakHints = chooseLineBreakTokens(index, tokens[index .. j], */ - /* depths[index .. j], config, currentLineLength, indentLevel); */ - /* } */ - /* else if (p == TOK.leftBracket && config.dfmt_keep_line_breaks == OptionalBoolean.t) */ - /* { */ - /* revertParenIndentation(); */ - /* IndentStack.Details detail; */ - - /* detail.wrap = false; */ - /* detail.temp = false; */ - /* detail.breakEveryItem = false; */ - /* detail.mini = tokens[index].line == tokens[index - 1].line; */ - - /* indents.push(TOK.rightBracket, detail); */ - /* if (!detail.mini) */ - /* { */ - /* newline(); */ - /* } */ - /* } */ - /* else if (arrayInitializerStart) */ - /* { */ - /* // This is a short (non-breaking) array/AA value */ - /* IndentStack.Details detail; */ - /* detail.wrap = false; */ - /* detail.temp = false; */ - - /* detail.breakEveryItem = astInformation.assocArrayStartLocations.canFindIndex( */ - /* tokens[index - 1].index); */ - /* // array of (possibly associative) array, let's put each item on its own line */ - /* if (!detail.breakEveryItem && currentIs(TOK.leftBracket)) */ - /* detail.breakEveryItem = true; */ - - /* // the '[' is immediately followed by an item instead of a newline here so */ - /* // we set mini, that the ']' also follows an item immediately without newline. */ - /* detail.mini = true; */ - - /* indents.push(TOK.rightBracket, detail); */ - /* } */ - /* else if (p == TOK.leftBracket) */ - /* { */ - /* // array item access */ - /* IndentStack.Details detail; */ - /* detail.wrap = false; */ - /* detail.temp = true; */ - /* detail.mini = true; */ - /* indents.push(TOK.rightBracket, detail); */ - /* } */ - /* else if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) */ - /* && (linebreakHints.canFindIndex(index - 1) || (linebreakHints.length == 0 */ - /* && currentLineLength > config.max_line_length))) */ - /* { */ - /* newline(); */ - /* } */ - /* else if (onNextLine) */ - /* { */ - /* newline(); */ - /* } */ - /* } */ - - /* void revertParenIndentation() */ - /* { */ - /* import std.algorithm.searching : canFind, until; */ - - /* if (tokens[index .. $].until!(tok => tok.line != current.line) */ - /* .canFind!(x => x.value == TOK.rightBracket)) */ - /* { */ - /* return; */ - /* } */ - /* if (parenDepthOnLine) */ - /* { */ - /* foreach (i; 0 .. parenDepthOnLine) */ - /* { */ - /* indents.pop(); */ - /* } */ - /* } */ - /* parenDepthOnLine = 0; */ - /* } */ - - /* void formatRightParen() */ - /* in */ - /* { */ - /* assert(currentIs(TOK.rightParenthesis)); */ - /* } */ - /* do */ - /* { */ - /* parenDepthOnLine = max(parenDepthOnLine - 1, 0); */ - /* parenDepth--; */ - /* indents.popWrapIndents(); */ - /* while (indents.topIsOneOf(TOK.not, TOK.rightParenthesis)) */ - /* indents.pop(); */ - /* if (indents.topIs(TOK.leftParenthesis)) */ - /* indents.pop(); */ - /* if (indents.topIs(TOK.dot)) */ - /* indents.pop(); */ - - /* if (onNextLine) */ - /* { */ - /* newline(); */ - /* } */ - /* if (parenDepth == 0 && (peekIs(TOK.is_) || peekIs(TOK.in_) */ - /* || peekIs(TOK.out_) || peekIs(TOK.do_) || peekIsBody)) */ - /* { */ - /* writeToken(); */ - /* } */ - /* else if (peekIsLiteralOrIdent() || peekIsBasicType()) */ - /* { */ - /* writeToken(); */ - /* if (spaceAfterParens || parenDepth > 0) */ - /* writeSpace(); */ - /* } */ - /* else if ((peekIsKeyword() || peekIs(TOK.at)) && spaceAfterParens */ - /* && !peekIs(TOK.in_) && !peekIs(TOK.is_) && !peekIs(TOK.if_)) */ - /* { */ - /* writeToken(); */ - /* writeSpace(); */ - /* } */ - /* else */ - /* writeToken(); */ - /* } */ - - /* void formatRightBracket() */ - /* in */ - /* { */ - /* assert(currentIs(TOK.rightBracket)); */ - /* } */ - /* do */ - /* { */ - /* indents.popWrapIndents(); */ - /* if (indents.topIs(TOK.rightBracket)) */ - /* { */ - /* if (!indents.topDetails.mini && !indents.topDetails.temp) */ - /* newline(); */ - /* else */ - /* indents.pop(); */ - /* } */ - /* writeToken(); */ - /* if (currentIs(TOK.identifier)) */ - /* write(" "); */ - /* } */ - - /* void formatAt() */ - /* { */ - /* immutable size_t atIndex = tokens[index].index; */ - /* writeToken(); */ - /* if (currentIs(TOK.identifier)) */ - /* writeToken(); */ - /* if (currentIs(TOK.leftParenthesis)) */ - /* { */ - /* writeParens(false); */ - /* if (tokens[index].value == TOK.leftCurly) */ - /* return; */ - - /* if (hasCurrent && tokens[index - 1].line < tokens[index].line */ - /* && astInformation.atAttributeStartLocations.canFindIndex(atIndex)) */ - /* newline(); */ - /* else */ - /* write(" "); */ - /* } */ - /* else if (hasCurrent && (currentIs(TOK.at) */ - /* || isBasicType(tokens[index].value) */ - /* || currentIs(TOK.invariant_) */ - /* || currentIs(TOK.extern_) */ - /* || currentIs(TOK.identifier)) */ - /* && !currentIsIndentedTemplateConstraint()) */ - /* { */ - /* writeSpace(); */ - /* } */ - /* } */ - - /* void formatColon() */ - /* { */ - /* import dfmt.editorconfig : OptionalBoolean; */ - /* import std.algorithm : canFind, any; */ - - /* immutable bool isCase = astInformation.caseEndLocations.canFindIndex(current.index); */ - /* immutable bool isAttribute = astInformation.attributeDeclarationLines.canFindIndex( */ - /* current.line); */ - /* immutable bool isStructInitializer = astInformation.structInfoSortedByEndLocation */ - /* .canFind!(st => st.startLocation < current.index && current.index < st.endLocation); */ - - /* if (isCase || isAttribute) */ - /* { */ - /* writeToken(); */ - /* if (!currentIs(TOK.leftCurly)) */ - /* { */ - /* if (isCase && !indents.topIs(TOK.case_) */ - /* && config.dfmt_align_switch_statements == OptionalBoolean.f) */ - /* indents.push(TOK.case_); */ - /* else if (isAttribute && !indents.topIs(TOK.at) */ - /* && config.dfmt_outdent_attributes == OptionalBoolean.f) */ - /* indents.push(TOK.at); */ - /* newline(); */ - /* } */ - /* } */ - /* else if (indents.topIs(TOK.rightBracket)) // Associative array */ - /* { */ - /* write(config.dfmt_space_before_aa_colon ? " : " : ": "); */ - /* ++index; */ - /* } */ - /* else if (peekBackIs(TOK.identifier) */ - /* && [ */ - /* TOK.leftCurly, TOK.rightCurly, TOK.semicolon, TOK.colon, TOK.comma */ - /* ] */ - /* .any!((ptrdiff_t token) => peekBack2Is(cast(TOK) token, true)) */ - /* && (!isBlockHeader(1) || peekIs(TOK.if_))) */ - /* { */ - /* writeToken(); */ - /* if (isStructInitializer) */ - /* write(" "); */ - /* else if (!currentIs(TOK.leftCurly)) */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* regenLineBreakHintsIfNecessary(index); */ - /* if (peekIs(TOK.slice)) */ - /* writeToken(); */ - /* else if (isBlockHeader(1) && !peekIs(TOK.if_)) */ - /* { */ - /* writeToken(); */ - /* if (config.dfmt_compact_labeled_statements) */ - /* write(" "); */ - /* else */ - /* newline(); */ - /* } */ - /* else if (linebreakHints.canFindIndex(index)) */ - /* { */ - /* pushWrapIndent(); */ - /* newline(); */ - /* writeToken(); */ - /* write(" "); */ - /* } */ - /* else */ - /* { */ - /* write(" : "); */ - /* index++; */ - /* } */ - /* } */ - /* } */ - - /* void formatSemicolon() */ - /* { */ - /* if (inlineElse && !peekIs(TOK.else_)) */ - /* inlineElse = false; */ - - /* if ((parenDepth > 0 && sBraceDepth == 0) || (sBraceDepth > 0 && niBraceDepth > 0)) */ - /* { */ - /* if (currentLineLength > config.dfmt_soft_max_line_length) */ - /* { */ - /* writeToken(); */ - /* pushWrapIndent(TOK.semicolon); */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* if (!(peekIs(TOK.semicolon) || peekIs(TOK.rightParenthesis) || peekIs( */ - /* TOK.rightCurly))) */ - /* write("; "); */ - /* else */ - /* write(";"); */ - /* index++; */ - /* } */ - /* } */ - /* else */ - /* { */ - /* writeToken(); */ - /* indents.popWrapIndents(); */ - /* linebreakHints = []; */ - /* while (indents.topIsOneOf(TOK.enum_, TOK.try_, TOK.catch_, TOK.finally_, TOK.debug_)) */ - /* indents.pop(); */ - /* if (indents.topAre(TOK.static_, TOK.else_)) */ - /* { */ - /* indents.pop(); */ - /* indents.pop(); */ - /* } */ - /* indentLevel = indents.indentLevel; */ - /* if (config.dfmt_brace_style == BraceStyle.allman) */ - /* { */ - /* if (!currentIs(TOK.leftCurly)) */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* if (currentIs(TOK.leftCurly)) */ - /* indents.popTempIndents(); */ - /* indentLevel = indents.indentLevel; */ - /* newline(); */ - /* } */ - /* } */ - /* } */ - - /* void formatLeftBrace() */ - /* { */ - /* import std.algorithm : map, sum, canFind; */ - - /* auto tIndex = tokens[index].index; */ - - /* if (astInformation.structInitStartLocations.canFindIndex(tIndex)) */ - /* { */ - /* sBraceDepth++; */ - /* immutable bool multiline = isMultilineAt(index); */ - /* writeToken(); */ - /* if (multiline) */ - /* { */ - /* import std.algorithm.searching : find; */ - - /* auto indentInfo = astInformation.indentInfoSortedByEndLocation */ - /* .find!((a, b) => a.startLocation == b)(tIndex); */ - /* assert(indentInfo.length > 0); */ - /* cast() indentInfo[0].flags |= BraceIndentInfoFlags.tempIndent; */ - /* cast() indentInfo[0].beginIndentLevel = indents.indentLevel; */ - - /* indents.push(TOK.leftCurly); */ - /* newline(); */ - /* } */ - /* else */ - /* niBraceDepth++; */ - /* } */ - /* else if (astInformation.funLitStartLocations.canFindIndex(tIndex)) */ - /* { */ - /* indents.popWrapIndents(); */ - - /* sBraceDepth++; */ - /* if (peekBackIsOneOf(true, TOK.rightParenthesis, TOK.identifier)) */ - /* write(" "); */ - /* immutable bool multiline = isMultilineAt(index); */ - /* writeToken(); */ - /* if (multiline) */ - /* { */ - /* indents.push(TOK.leftCurly); */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* niBraceDepth++; */ - /* if (!currentIs(TOK.rightCurly)) */ - /* write(" "); */ - /* } */ - /* } */ - /* else */ - /* { */ - /* if (peekBackIsSlashSlash()) */ - /* { */ - /* if (peekBack2Is(TOK.semicolon)) */ - /* { */ - /* indents.popTempIndents(); */ - /* indentLevel = indents.indentLevel - 1; */ - /* } */ - /* writeToken(); */ - /* } */ - /* else */ - /* { */ - /* if (indents.topIsTemp && indents.indentToMostRecent(TOK.static_) == -1) */ - /* indentLevel = indents.indentLevel - 1; */ - /* else */ - /* indentLevel = indents.indentLevel; */ - /* if (config.dfmt_brace_style == BraceStyle.allman */ - /* || peekBackIsOneOf(true, TOK.leftCurly, TOK.rightCurly)) */ - /* newline(); */ - /* else if (config.dfmt_brace_style == BraceStyle.knr */ - /* && astInformation.funBodyLocations.canFindIndex(tIndex) */ - /* && (peekBackIs(TOK.rightParenthesis) || (!peekBackIs(TOK.do_) && peekBack().text != "body"))) */ - /* newline(); */ - /* else if (!peekBackIsOneOf(true, TOK.leftCurly, TOK.rightCurly, TOK.semicolon)) */ - /* write(" "); */ - /* writeToken(); */ - /* } */ - /* indents.push(TOK.leftCurly); */ - /* if (!currentIs(TOK.leftCurly)) */ - /* newline(); */ - /* linebreakHints = []; */ - /* } */ - /* } */ - - /* void formatRightBrace() */ - /* { */ - /* void popToBeginIndent(BraceIndentInfo indentInfo) */ - /* { */ - /* foreach (i; indentInfo.beginIndentLevel .. indents.indentLevel) */ - /* { */ - /* indents.pop(); */ - /* } */ - - /* indentLevel = indentInfo.beginIndentLevel; */ - /* } */ - - /* size_t pos; */ - /* if (astInformation.structInitEndLocations.canFindIndex(tokens[index].index, &pos)) */ - /* { */ - /* if (sBraceDepth > 0) */ - /* sBraceDepth--; */ - /* if (niBraceDepth > 0) */ - /* niBraceDepth--; */ - - /* auto indentInfo = astInformation.indentInfoSortedByEndLocation[pos]; */ - /* if (indentInfo.flags & BraceIndentInfoFlags.tempIndent) */ - /* { */ - /* popToBeginIndent(indentInfo); */ - /* simpleNewline(); */ - /* indent(); */ - /* } */ - /* writeToken(); */ - /* } */ - /* else if (astInformation.funLitEndLocations.canFindIndex(tokens[index].index, &pos)) */ - /* { */ - /* if (niBraceDepth > 0) */ - /* { */ - /* if (!peekBackIsSlashSlash() && !peekBackIs(TOK.leftCurly)) */ - /* write(" "); */ - /* niBraceDepth--; */ - /* } */ - /* if (sBraceDepth > 0) */ - /* sBraceDepth--; */ - /* writeToken(); */ - /* } */ - /* else */ - /* { */ - /* // Silly hack to format enums better. */ - /* if ((peekBackIsLiteralOrIdent() || peekBackIsOneOf(true, TOK.rightParenthesis, */ - /* TOK.comma)) && !peekBackIsSlashSlash()) */ - /* newline(); */ - /* write("}"); */ - /* if (index + 1 < tokens.length */ - /* && astInformation.doubleNewlineLocations.canFindIndex(tokens[index].index) */ - /* && !peekIs(TOK.rightCurly) && !peekIs(TOK.else_) */ - /* && !peekIs(TOK.semicolon) && !peekIs(TOK.comment, false)) */ - /* { */ - /* simpleNewline(); */ - /* currentLineLength = 0; */ - /* justAddedExtraNewline = true; */ - /* } */ - /* if (config.dfmt_brace_style.among(BraceStyle.otbs, BraceStyle.knr) */ - /* && ((peekIs(TOK.else_) */ - /* && !indents.topAre(TOK.static_, TOK.if_) */ - /* && !indents.topIs(TOK.foreach_) && !indents.topIs(TOK.for_) */ - /* && !indents.topIs(TOK.while_) && !indents.topIs(TOK.do_)) */ - /* || peekIs(TOK.catch_) || peekIs(TOK.finally_))) */ - /* { */ - /* write(" "); */ - /* index++; */ - /* } */ - /* else */ - /* { */ - /* if (!peekIs(TOK.comma) && !peekIs(TOK.rightParenthesis) */ - /* && !peekIs(TOK.semicolon) && !peekIs(TOK.leftCurly)) */ - /* { */ - /* index++; */ - /* if (indents.topIs(TOK.static_)) */ - /* indents.pop(); */ - /* newline(); */ - /* } */ - /* else */ - /* index++; */ - /* } */ - /* } */ - /* } */ - - /* void formatSwitch() */ - /* { */ - /* while (indents.topIs(TOK.with_)) */ - /* indents.pop(); */ - /* indents.push(TOK.switch_); */ - /* writeToken(); // switch */ - /* if (config.dfmt_space_after_keywords) */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - - /* void formatBlockHeader() */ - /* { */ - /* if (indents.topIs(TOK.not)) */ - /* indents.pop(); */ - /* immutable bool a = !currentIs(TOK.version_) && !currentIs(TOK.debug_); */ - /* immutable bool b = a */ - /* || astInformation.conditionalWithElseLocations.canFindIndex(current.index); */ - /* immutable bool c = b */ - /* || astInformation.conditionalStatementLocations.canFindIndex(current.index); */ - /* immutable bool shouldPushIndent = (c || peekBackIs(TOK.else_)) */ - /* && !(currentIs(TOK.if_) && indents.topIsWrap()); */ - /* if (currentIs(TOK.out_) && !peekBackIs(TOK.rightCurly)) */ - /* newline(); */ - /* if (shouldPushIndent) */ - /* { */ - /* if (peekBackIs(TOK.static_)) */ - /* { */ - /* if (indents.topIs(TOK.else_)) */ - /* indents.pop(); */ - /* if (!indents.topIs(TOK.static_)) */ - /* indents.push(TOK.static_); */ - /* } */ - /* indents.push(current.value); */ - /* } */ - /* writeToken(); */ - - /* if (currentIs(TOK.leftParenthesis)) */ - /* { */ - /* if (config.dfmt_space_after_keywords) */ - /* { */ - /* write(" "); */ - /* } */ - /* writeParens(false); */ - /* } */ - - /* if (hasCurrent) */ - /* { */ - /* if (currentIs(TOK.switch_) || (currentIs(TOK.final_) && peekIs(TOK.switch_))) */ - /* { */ - /* if (config.dfmt_space_after_keywords) */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - /* else if (currentIs(TOK.comment)) */ - /* { */ - /* formatStep(); */ - /* } */ - /* else if (!shouldPushIndent) */ - /* { */ - /* if (!currentIs(TOK.leftCurly) && !currentIs(TOK.semicolon)) */ - /* write(" "); */ - /* } */ - /* else if (hasCurrent && !currentIs(TOK.leftCurly) && !currentIs(TOK.semicolon) && !currentIs(TOK.in_) && */ - /* !currentIs(TOK.out_) && !currentIs(TOK.do_) && current.text != "body") */ - /* { */ - /* newline(); */ - /* } */ - /* else if (currentIs(TOK.leftCurly) && indents.topAre(tok.static_, TOK.if_)) */ - /* { */ - /* // Hacks to format braced vs non-braced static if declarations. */ - /* indents.pop(); */ - /* indents.pop(); */ - /* indents.push(TOK.if_); */ - /* formatLeftBrace(); */ - /* } */ - /* else if (currentIs(TOK.leftCurly) && indents.topAre(TOK.static_, TOK.foreach_)) */ - /* { */ - /* indents.pop(); */ - /* indents.pop(); */ - /* indents.push(TOK.foreach_); */ - /* formatLeftBrace(); */ - /* } */ - /* else if (currentIs(TOK.leftCurly) && indents.topAre(TOK.static_, TOK.foreach_reverse_)) */ - /* { */ - /* indents.pop(); */ - /* indents.pop(); */ - /* indents.push(TOK.foreach_reverse_); */ - /* formatLeftBrace(); */ - /* } */ - /* } */ - /* } */ - - /* void formatElse() */ - /* { */ - /* writeToken(); */ - /* if (inlineElse || currentIs(TOK.if_) || currentIs(TOK.version_) */ - /* || (currentIs(TOK.static_) && peekIs(TOK.if_))) */ - /* { */ - /* if (indents.topIs(TOK.if_) || indents.topIs(TOK.version_)) */ - /* indents.pop(); */ - /* inlineElse = false; */ - /* write(" "); */ - /* } */ - /* else if (currentIs(TOK.colon)) */ - /* { */ - /* writeToken(); */ - /* newline(); */ - /* } */ - /* else if (!currentIs(TOK.leftCurly) && !currentIs(TOK.comment)) */ - /* { */ - /* //indents.dump(); */ - /* while (indents.topIsOneOf(TOK.foreach_, TOK.for_, TOK.while_)) */ - /* indents.pop(); */ - /* if (indents.topIsOneOf(TOK.if_, TOK.version_)) */ - /* indents.pop(); */ - /* indents.push(TOK.else_); */ - /* newline(); */ - /* } */ - /* else if (currentIs(TOK.leftCurly) && indents.topAre(TOK.static_, TOK.if_)) */ - /* { */ - /* indents.pop(); */ - /* indents.pop(); */ - /* indents.push(TOK.else_); */ - /* } */ - /* } */ - - /* void formatKeyword() */ - /* { */ - /* import dfmt.editorconfig : OptionalBoolean; */ - - /* switch (current.value) */ - /* { */ - /* case TOK.default_: */ - /* writeToken(); */ - /* break; */ - /* case TOK.cast_: */ - /* writeToken(); */ - /* if (hasCurrent && currentIs(TOK.leftParenthesis)) */ - /* writeParens(config.dfmt_space_after_cast == OptionalBoolean.t); */ - /* break; */ - /* case TOK.out_: */ - /* if (!peekBackIsSlashSlash) */ - /* { */ - /* if (!peekBackIs(TOK.rightCurly) */ - /* && astInformation.contractLocations.canFindIndex(current.index)) */ - /* newline(); */ - /* else if (peekBackIsKeyword) */ - /* write(" "); */ - /* } */ - /* writeToken(); */ - /* if (hasCurrent && !currentIs(TOK.leftCurly) && !currentIs(TOK.comment)) */ - /* write(" "); */ - /* break; */ - /* case TOK.try_: */ - /* case TOK.finally_: */ - /* indents.push(current.value); */ - /* writeToken(); */ - /* if (hasCurrent && !currentIs(TOK.leftCurly)) */ - /* newline(); */ - /* break; */ - /* case TOK.identifier: */ - /* if (current.text == "body") */ - /* goto case TOK.do_; */ - /* else */ - /* goto default; */ - /* case TOK.do_: */ - /* if (!peekBackIs(TOK.rightCurly)) */ - /* newline(); */ - /* writeToken(); */ - /* break; */ - /* case TOK.in_: */ - /* immutable isContract = astInformation.contractLocations.canFindIndex(current.index); */ - /* if (!peekBackIsSlashSlash) */ - /* { */ - /* if (isContract) */ - /* { */ - /* indents.popTempIndents(); */ - /* newline(); */ - /* } */ - /* else if (!peekBackIsOneOf(false, TOK.leftParenthesis, TOK.comma, TOK.not)) */ - /* write(" "); */ - /* } */ - /* writeToken(); */ - /* if (!hasCurrent) */ - /* return; */ - /* immutable isFunctionLit = astInformation.funLitStartLocations.canFindIndex( */ - /* current.index); */ - /* if (isFunctionLit && config.dfmt_brace_style == BraceStyle.allman) */ - /* newline(); */ - /* else if (!isContract || currentIs(TOK.leftParenthesis)) */ - /* write(" "); */ - /* break; */ - /* case TOK.is_: */ - /* if (!peekBackIsOneOf(false, TOK.not, TOK.leftParenthesis, TOK.comma, */ - /* TOK.rightCurly, TOK.assign, TOK.andAnd, TOK.orOr) && !peekBackIsKeyword()) */ - /* write(" "); */ - /* writeToken(); */ - /* if (hasCurrent && !currentIs(TOK.leftParenthesis) && !currentIs(TOK.leftCurly) && !currentIs( */ - /* TOK.comment)) */ - /* write(" "); */ - /* break; */ - /* case TOK.case_: */ - /* writeToken(); */ - /* if (hasCurrent && !currentIs(TOK.semicolon)) */ - /* write(" "); */ - /* break; */ - /* case TOK.enum_: */ - /* if (peekIs(TOK.rightParenthesis) || peekIs(TOK.equal)) */ - /* { */ - /* writeToken(); */ - /* } */ - /* else */ - /* { */ - /* if (peekBackIs(TOK.identifier)) */ - /* write(" "); */ - /* indents.push(TOK.enum_); */ - /* writeToken(); */ - /* if (hasCurrent && !currentIs(TOK.colon) && !currentIs(TOK.leftCurly)) */ - /* write(" "); */ - /* } */ - /* break; */ - /* case TOK.static_: */ - /* { */ - /* if (astInformation.staticConstructorDestructorLocations */ - /* .canFindIndex(current.index)) */ - /* { */ - /* thisSpace = true; */ - /* } */ - /* } */ - /* goto default; */ - /* case TOK.shared_: */ - /* { */ - /* if (astInformation.sharedStaticConstructorDestructorLocations */ - /* .canFindIndex(current.index)) */ - /* { */ - /* thisSpace = true; */ - /* } */ - /* } */ - /* goto default; */ - /* case TOK.invariant_: */ - /* writeToken(); */ - /* if (hasCurrent && currentIs(TOK.leftParenthesis)) */ - /* write(" "); */ - /* break; */ - /* default: */ - /* if (peekBackIs(TOK.identifier)) */ - /* { */ - /* writeSpace(); */ - /* } */ - /* if (index + 1 < tokens.length) */ - /* { */ - /* if (!peekIs(TOK.at) && (peekIsOperator() */ - /* || peekIs(TOK.out_) || peekIs(TOK.in_))) */ - /* { */ - /* writeToken(); */ - /* } */ - /* else */ - /* { */ - /* writeToken(); */ - /* if (!currentIsIndentedTemplateConstraint()) */ - /* { */ - /* writeSpace(); */ - /* } */ - /* } */ - /* } */ - /* else */ - /* writeToken(); */ - /* break; */ - /* } */ - /* } */ - - /* bool currentIsIndentedTemplateConstraint() */ - /* { */ - /* return hasCurrent */ - /* && astInformation.constraintLocations.canFindIndex(current.index) */ - /* && (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline */ - /* || config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent */ - /* || currentLineLength >= config.dfmt_soft_max_line_length); */ - /* } */ - - /* void formatOperator() */ - /* { */ - /* import dfmt.editorconfig : OptionalBoolean; */ - /* import std.algorithm : canFind; */ - - /* switch (current.value) */ - /* { */ - /* case TOK.mul: */ - /* if (astInformation.spaceAfterLocations.canFindIndex(current.index)) */ - /* { */ - /* writeToken(); */ - /* if (!currentIs(TOK.mul) && !currentIs(TOK.rightParenthesis) */ - /* && !currentIs(TOK.leftBracket) && !currentIs(TOK.comma) && !currentIs( */ - /* TOK.semicolon)) */ - /* { */ - /* write(" "); */ - /* } */ - /* break; */ - /* } */ - /* else if (astInformation.unaryLocations.canFindIndex(current.index)) */ - /* { */ - /* writeToken(); */ - /* break; */ - /* } */ - /* regenLineBreakHintsIfNecessary(index); */ - /* goto binary; */ - /* case TOK.tilde: */ - /* if (peekIs(TOK.this_) && peek2Is(TOK.leftParenthesis)) */ - /* { */ - /* if (!(index == 0 || peekBackIs(TOK.leftCurly, true) */ - /* || peekBackIs(TOK.rightCurly, true) || peekBackIs(TOK.semicolon, true))) */ - /* { */ - /* write(" "); */ - /* } */ - /* writeToken(); */ - /* break; */ - /* } */ - /* goto case; */ - /* case TOK.and: */ - /* case TOK.add: */ - /* case TOK.min: */ - /* if (astInformation.unaryLocations.canFindIndex(current.index)) */ - /* { */ - /* writeToken(); */ - /* break; */ - /* } */ - /* regenLineBreakHintsIfNecessary(index); */ - /* goto binary; */ - /* case TOK.leftBracket: */ - /* case TOK.leftParenthesis: */ - /* formatLeftParenOrBracket(); */ - /* break; */ - /* case TOK.rightParenthesis: */ - /* formatRightParen(); */ - /* break; */ - /* case TOK.at: */ - /* formatAt(); */ - /* break; */ - /* case TOK.not: */ - /* if (((peekIs(TOK.is_) || peekIs(TOK.in_)) */ - /* && !peekBackIsOperator()) || peekBackIs(TOK.rightParenthesis)) */ - /* write(" "); */ - /* goto case; */ - /* case tok!"...": */ - /* case tok!"++": */ - /* case tok!"--": */ - /* case TOK.dollar: */ - /* writeToken(); */ - /* break; */ - /* case TOK.colon: */ - /* formatColon(); */ - /* break; */ - /* case TOK.rightBracket: */ - /* formatRightBracket(); */ - /* break; */ - /* case TOK.semicolon: */ - /* formatSemicolon(); */ - /* break; */ - /* case TOK.leftCurly: */ - /* formatLeftBrace(); */ - /* break; */ - /* case TOK.rightCurly: */ - /* formatRightBrace(); */ - /* break; */ - /* case TOK.dot: */ - /* regenLineBreakHintsIfNecessary(index); */ - /* immutable bool ufcsWrap = config.dfmt_reflow_property_chains == OptionalBoolean.t */ - /* && astInformation.ufcsHintLocations.canFindIndex(current.index); */ - /* if (ufcsWrap || linebreakHints.canFind(index) || onNextLine */ - /* || (linebreakHints.length == 0 && currentLineLength + nextTokenLength() > config */ - /* .max_line_length)) */ - /* { */ - /* if (!indents.topIs(TOK.dot)) */ - /* indents.push(TOK.dot); */ - /* if (!peekBackIs(TOK.comment)) */ - /* newline(); */ - /* if (ufcsWrap || onNextLine) */ - /* regenLineBreakHints(index); */ - /* } */ - /* writeToken(); */ - /* break; */ - /* case TOK.comma: */ - /* formatComma(); */ - /* break; */ - /* case tok!"&&": */ - /* case tok!"||": */ - /* case TOK.or: */ - /* regenLineBreakHintsIfNecessary(index); */ - /* goto case; */ - /* case TOK.assign: */ - /* 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.xor: */ - /* case tok!"~=": */ - /* case tok!"<<=": */ - /* case tok!"<<": */ - /* case tok!"<=": */ - /* case tok!"<>=": */ - /* case tok!"<>": */ - /* case TOK.lessThan: */ - /* case tok!"==": */ - /* case tok!"=>": */ - /* case tok!">>>": */ - /* case tok!">>": */ - /* case TOK.greaterThan: */ - /* case tok!"!<=": */ - /* case tok!"!<>=": */ - /* case tok!"!<>": */ - /* case tok!"!<": */ - /* case tok!"!=": */ - /* case tok!"!>=": */ - /* case tok!"!>": */ - /* case TOK.question: */ - /* case TOK.div: */ - /* case tok!"..": */ - /* case TOK.mod: */ - /* binary: */ - /* immutable bool isWrapToken = linebreakHints.canFind(index); */ - /* if (config.dfmt_keep_line_breaks == OptionalBoolean.t && index > 0) */ - /* { */ - /* const operatorLine = tokens[index].line; */ - /* const rightOperandLine = tokens[index + 1].line; */ - - /* if (tokens[index - 1].line < operatorLine) */ - /* { */ - /* if (!indents.topIs(tok!"enum")) */ - /* pushWrapIndent(); */ - /* if (!peekBackIs(TOK.comment)) */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* write(" "); */ - /* } */ - /* if (rightOperandLine > operatorLine */ - /* && !indents.topIs(tok!"enum")) */ - /* { */ - /* pushWrapIndent(); */ - /* } */ - /* writeToken(); */ - - /* if (rightOperandLine > operatorLine) */ - /* { */ - /* if (!peekBackIs(TOK.comment)) */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - /* else if (config.dfmt_split_operator_at_line_end) */ - /* { */ - /* if (isWrapToken) */ - /* { */ - /* if (!indents.topIs(tok!"enum")) */ - /* pushWrapIndent(); */ - /* write(" "); */ - /* writeToken(); */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* write(" "); */ - /* writeToken(); */ - /* if (!currentIs(TOK.comment)) */ - /* write(" "); */ - /* } */ - /* } */ - /* else */ - /* { */ - /* if (isWrapToken) */ - /* { */ - /* if (!indents.topIs(tok!"enum")) */ - /* pushWrapIndent(); */ - /* newline(); */ - /* writeToken(); */ - /* } */ - /* else */ - /* { */ - /* write(" "); */ - /* writeToken(); */ - /* } */ - /* if (!currentIs(TOK.comment)) */ - /* write(" "); */ - /* } */ - /* break; */ - /* default: */ - /* writeToken(); */ - /* break; */ - /* } */ - /* } */ - - /* void formatComma() */ - /* { */ - /* import dfmt.editorconfig : OptionalBoolean; */ - /* import std.algorithm : canFind; */ - - /* if (config.dfmt_keep_line_breaks == OptionalBoolean.f) */ - /* regenLineBreakHintsIfNecessary(index); */ - /* if (indents.indentToMostRecent(TOK.enum_) != -1 */ - /* && !peekIs(TOK.rightCurly) && indents.topIs(TOK.leftCurly) && parenDepth == 0) */ - /* { */ - /* writeToken(); */ - /* newline(); */ - /* } */ - /* else if (indents.topIs(TOK.rightBracket) && indents.topDetails.breakEveryItem */ - /* && !indents.topDetails.mini) */ - /* { */ - /* writeToken(); */ - /* newline(); */ - /* regenLineBreakHints(index - 1); */ - /* } */ - /* else if (indents.topIs(TOK.rightBracket) && indents.topDetails.preferLongBreaking */ - /* && !currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) && !currentIs( */ - /* TOK.rightCurly) */ - /* && !currentIs(TOK.comment) && index + 1 < tokens.length */ - /* && isMultilineAt(index + 1, true)) */ - /* { */ - /* writeToken(); */ - /* newline(); */ - /* regenLineBreakHints(index - 1); */ - /* } */ - /* else if (config.dfmt_keep_line_breaks == OptionalBoolean.t) */ - /* { */ - /* const commaLine = tokens[index].line; */ - - /* writeToken(); */ - /* if (indents.topIsWrap && !indents.topIs(TOK.comma)) */ - /* { */ - /* indents.pop; */ - /* } */ - /* if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) */ - /* && !currentIs(TOK.rightCurly) && !currentIs(TOK.comment)) */ - /* { */ - /* if (tokens[index].line == commaLine) */ - /* { */ - /* write(" "); */ - /* } */ - /* else */ - /* { */ - /* newline(); */ - /* } */ - /* } */ - /* } */ - /* else if (!peekIs(TOK.rightCurly) && (linebreakHints.canFind(index) */ - /* || (linebreakHints.length == 0 && currentLineLength > config.max_line_length))) */ - /* { */ - /* pushWrapIndent(); */ - /* writeToken(); */ - /* if (indents.topIsWrap && !indents.topIs(TOK.comma)) */ - /* { */ - /* indents.pop; */ - /* } */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* writeToken(); */ - /* if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.rightBracket) */ - /* && !currentIs(TOK.rightCurly) && !currentIs(TOK.comment)) */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - /* regenLineBreakHintsIfNecessary(index - 1); */ - /* } */ - - /* void regenLineBreakHints(immutable size_t i) */ - /* { */ - /* import std.range : assumeSorted; */ - /* import std.algorithm.comparison : min; */ - /* import std.algorithm.searching : canFind, countUntil; */ - - /* // The end of the tokens considered by the line break algorithm is */ - /* // either the expression end index or the next mandatory line break */ - /* // or a newline inside a string literal, whichever is first. */ - /* auto r = assumeSorted(astInformation.ufcsHintLocations).upperBound(tokens[i].index); */ - /* immutable ufcsBreakLocation = r.empty */ - /* ? size_t.max */ - /* : tokens[i .. $].countUntil!(t => t.index == r.front) + i; */ - /* immutable multilineStringLocation = tokens[i .. $] */ - /* .countUntil!(t => t.text.canFind('\n')); */ - /* immutable size_t j = min( */ - /* expressionEndIndex(i), */ - /* ufcsBreakLocation, */ - /* multilineStringLocation == -1 ? size_t.max : multilineStringLocation + i + 1); */ - /* // Use magical negative value for array literals and wrap indents */ - /* immutable inLvl = (indents.topIsWrap() || indents.topIs(TOK.rightBracket)) ? -indentLevel */ - /* : indentLevel; */ - /* linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j], */ - /* config, currentLineLength, inLvl); */ - /* } */ - - /* void regenLineBreakHintsIfNecessary(immutable size_t i) */ - /* { */ - /* if (linebreakHints.length == 0 || linebreakHints[$ - 1] <= i - 1) */ - /* regenLineBreakHints(i); */ - /* } */ - - /* void simpleNewline() */ - /* { */ - /* import dfmt.editorconfig : EOL; */ - - /* output.put(eolString); */ - /* } */ - - /* void newline() */ - /* { */ - /* import std.range : assumeSorted; */ - /* import std.algorithm : max, canFind; */ - /* import dfmt.editorconfig : OptionalBoolean; */ - - /* if (currentIs(TOK.comment) && index > 0 && current.line == tokenEndLine(tokens[index - 1])) */ - /* return; */ - - /* immutable bool hasCurrent = this.hasCurrent; */ - - /* if (niBraceDepth > 0 && !peekBackIsSlashSlash() && hasCurrent && tokens[index].value == TOK.rightCurly */ - /* && !assumeSorted(astInformation.funLitEndLocations).equalRange( */ - /* tokens[index].index) */ - /* .empty) */ - /* { */ - /* return; */ - /* } */ - - /* simpleNewline(); */ - - /* if (!justAddedExtraNewline && index > 0 && hasCurrent */ - /* && tokens[index].line - tokenEndLine(tokens[index - 1]) > 1) */ - /* { */ - /* simpleNewline(); */ - /* } */ - - /* justAddedExtraNewline = false; */ - /* currentLineLength = 0; */ - - /* if (hasCurrent) */ - /* { */ - /* if (currentIs(TOK.else_)) */ - /* { */ - /* immutable i = indents.indentToMostRecent(TOK.if_); */ - /* immutable v = indents.indentToMostRecent(TOK.version_); */ - /* immutable mostRecent = max(i, v); */ - /* if (mostRecent != -1) */ - /* indentLevel = mostRecent; */ - /* } */ - /* else if (currentIs(TOK.identifier) && peekIs(TOK.colon)) */ - /* { */ - /* if (peekBackIs(TOK.rightCurly, true) || peekBackIs(TOK.semicolon, true)) */ - /* indents.popTempIndents(); */ - /* immutable l = indents.indentToMostRecent(TOK.switch_); */ - /* if (l != -1 && config.dfmt_align_switch_statements == OptionalBoolean.t) */ - /* indentLevel = l; */ - /* else if (astInformation.structInfoSortedByEndLocation */ - /* .canFind!(st => st.startLocation < current.index && current.index < st */ - /* .endLocation)) */ - /* { */ - /* immutable l2 = indents.indentToMostRecent(TOK.leftCurly); */ - /* assert(l2 != -1, "Recent '{' is not found despite being in struct initializer"); */ - /* indentLevel = l2 + 1; */ - /* } */ - /* else if ((config.dfmt_compact_labeled_statements == OptionalBoolean.f */ - /* || !isBlockHeader(2) || peek2Is(TOK.if_)) && !indents.topIs( */ - /* TOK.rightBracket)) */ - /* { */ - /* immutable l2 = indents.indentToMostRecent(TOK.leftCurly); */ - /* indentLevel = l2 != -1 ? l2 : indents.indentLevel - 1; */ - /* } */ - /* else */ - /* indentLevel = indents.indentLevel; */ - /* } */ - /* else if (currentIs(TOK.case_) || currentIs(TOK.default_)) */ - /* { */ - - /* if (peekBackIs(TOK.rightCurly, true) || peekBackIs(TOK.semicolon, true) /** */ - /* * The following code is valid and should be indented flatly */ - /* * case A: */ - /* * case B: */ - /* *1/ */ - /* || peekBackIs(TOK.colon, true)) */ - /* { */ - /* indents.popTempIndents(); */ - /* if (indents.topIs(TOK.case_)) */ - /* indents.pop(); */ - /* } */ - /* immutable l = indents.indentToMostRecent(TOK.switch_); */ - /* if (l != -1) */ - /* indentLevel = config.dfmt_align_switch_statements == OptionalBoolean.t */ - /* ? l : indents.indentLevel; */ - /* } */ - /* else if (currentIs(TOK.rightParenthesis)) */ - /* { */ - /* if (indents.topIs(TOK.leftParenthesis)) */ - /* indents.pop(); */ - /* indentLevel = indents.indentLevel; */ - /* } */ - /* else if (currentIs(TOK.leftCurly)) */ - /* { */ - /* indents.popWrapIndents(); */ - /* if ((peekBackIsSlashSlash() && peekBack2Is(TOK.semicolon)) || indents.topIs( */ - /* TOK.rightBracket)) */ - /* { */ - /* indents.popTempIndents(); */ - /* indentLevel = indents.indentLevel; */ - /* } */ - /* } */ - /* else if (currentIs(TOK.rightCurly)) */ - /* { */ - /* indents.popTempIndents(); */ - /* while (indents.topIsOneOf(TOK.case_, TOK.at, tok.static_)) */ - /* indents.pop(); */ - /* if (indents.topIs(TOK.leftCurly)) */ - /* { */ - /* indentLevel = indents.indentToMostRecent(TOK.leftCurly); */ - /* indents.pop(); */ - /* } */ - /* if (indents.topIsOneOf(TOK.try_, TOK.catch_)) */ - /* { */ - /* indents.pop(); */ - /* } */ - /* else */ - /* while (sBraceDepth == 0 && indents.topIsTemp() */ - /* && ((!indents.topIsOneOf(TOK.else_, TOK.if_, */ - /* TOK.static_, TOK.version_)) || !peekIs(TOK.else_))) */ - /* { */ - /* indents.pop(); */ - /* } */ - /* } */ - /* else if (currentIs(TOK.rightBracket)) */ - /* { */ - /* indents.popWrapIndents(); */ - /* if (indents.topIs(TOK.rightBracket)) */ - /* { */ - /* indents.pop(); */ - /* } */ - /* // Find the initial indentation of constructs like "if" and */ - /* // "foreach" without removing them from the stack, since they */ - /* // still can be used later to indent "else". */ - /* auto savedIndents = IndentStack(config); */ - /* while (indents.length >= 0 && indents.topIsTemp) */ - /* { */ - /* savedIndents.push(indents.top, indents.topDetails); */ - /* indents.pop; */ - /* } */ - /* indentLevel = indents.indentLevel; */ - /* while (savedIndents.length > 0) */ - /* { */ - /* indents.push(savedIndents.top, savedIndents.topDetails); */ - /* savedIndents.pop; */ - /* } */ - /* } */ - /* else if (astInformation.attributeDeclarationLines.canFindIndex(current.line)) */ - /* { */ - /* if (config.dfmt_outdent_attributes == OptionalBoolean.t) */ - /* { */ - /* immutable l = indents.indentToMostRecent(TOK.leftCurly); */ - /* if (l != -1) */ - /* indentLevel = l; */ - /* } */ - /* else */ - /* { */ - /* if (indents.topIs(TOK.at)) */ - /* indents.pop(); */ - /* indentLevel = indents.indentLevel; */ - /* } */ - /* } */ - /* else if (currentIs(TOK.catch_) || currentIs(TOK.finally_)) */ - /* { */ - /* indentLevel = indents.indentLevel; */ - /* } */ - /* else */ - /* { */ - /* if (indents.topIsTemp() && (peekBackIsOneOf(true, TOK.rightCurly, */ - /* TOK.semicolon) && !indents.topIs(TOK.semicolon))) */ - /* indents.popTempIndents(); */ - /* indentLevel = indents.indentLevel; */ - /* } */ - /* indent(); */ - /* } */ - /* parenDepthOnLine = 0; */ - /* } */ - - /* void write(string str) */ - /* { */ - /* currentLineLength += str.length; */ - /* output.put(str); */ - /* } */ - - /* void writeToken() */ - /* { */ - /* import std.range : retro; */ - /* import std.algorithm.searching : countUntil; */ - /* import std.algorithm.iteration : joiner; */ - /* import std.string : lineSplitter; */ - - /* if (current.text is null) */ - /* { */ - /* immutable s = str(current.value); */ - /* currentLineLength += s.length; */ - /* output.put(str(current.value)); */ - /* } */ - /* else */ - /* { */ - /* output.put(current.text.lineSplitter.joiner(eolString)); */ - /* switch (current.value) */ - /* { */ - /* case TOK.string_: */ - /* immutable o = current.text.retro().countUntil('\n'); */ - /* if (o == -1) */ - /* { */ - /* currentLineLength += current.text.length; */ - /* } */ - /* else */ - /* { */ - /* currentLineLength = cast(uint) o; */ - /* } */ - /* break; */ - /* default: */ - /* currentLineLength += current.text.length; */ - /* break; */ - /* } */ - /* } */ - /* index++; */ - /* } */ - - /* void writeParens(bool spaceAfter) */ - /* in */ - /* { */ - /* assert(currentIs(TOK.leftParenthesis), str(current.value)); */ - /* } */ - /* do */ - /* { */ - /* immutable int depth = parenDepth; */ - /* immutable int startingNiBraceDepth = niBraceDepth; */ - /* immutable int startingSBraceDepth = sBraceDepth; */ - /* parenDepth = 0; */ - - /* do */ - /* { */ - /* spaceAfterParens = spaceAfter; */ - /* if (currentIs(TOK.semicolon) && niBraceDepth <= startingNiBraceDepth */ - /* && sBraceDepth <= startingSBraceDepth) */ - /* { */ - /* if (currentLineLength >= config.dfmt_soft_max_line_length) */ - /* { */ - /* pushWrapIndent(); */ - /* writeToken(); */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* writeToken(); */ - /* if (!currentIs(TOK.rightParenthesis) && !currentIs(TOK.semicolon)) */ - /* write(" "); */ - /* } */ - /* } */ - /* else */ - /* formatStep(); */ - /* } */ - /* while (hasCurrent && parenDepth > 0); */ - - /* if (indents.topIs(TOK.not)) */ - /* indents.pop(); */ - /* parenDepth = depth; */ - /* spaceAfterParens = spaceAfter; */ - /* } */ - - /* void indent() */ - /* { */ - /* import dfmt.editorconfig : IndentStyle; */ - - /* if (config.indent_style == IndentStyle.tab) */ - /* { */ - /* foreach (i; 0 .. indentLevel) */ - /* { */ - /* currentLineLength += config.tab_width; */ - /* output.put("\t"); */ - /* } */ - /* } */ - /* else */ - /* { */ - /* foreach (i; 0 .. indentLevel) */ - /* foreach (j; 0 .. config.indent_size) */ - /* { */ - /* output.put(" "); */ - /* currentLineLength++; */ - /* } */ - /* } */ - /* } */ - - /* void pushWrapIndent(TOK type = TOK.error) */ - /* { */ - /* immutable t = type == TOK.error ? tokens[index].value : type; */ - /* IndentStack.Details detail; */ - /* detail.wrap = isWrapIndent(t); */ - /* detail.temp = isTempIndent(t); */ - /* pushWrapIndent(t, detail); */ - /* } */ - - /* void pushWrapIndent(TOK type, IndentStack.Details detail) */ - /* { */ - /* if (parenDepth == 0) */ - /* { */ - /* if (indents.wrapIndents == 0) */ - /* indents.push(type, detail); */ - /* } */ - /* else if (indents.wrapIndents < 1) */ - /* indents.push(type, detail); */ - /* } */ - - /* void writeSpace() */ - /* { */ - /* if (onNextLine) */ - /* { */ - /* newline(); */ - /* } */ - /* else */ - /* { */ - /* write(" "); */ - /* } */ - /* } */ - - /* const pure @safe @nogc: */ - - /* size_t expressionEndIndex(size_t i, bool matchComma = false) nothrow */ - /* { */ - /* immutable bool braces = i < tokens.length && tokens[i].value == TOK.leftCurly; */ - /* immutable bool brackets = i < tokens.length && tokens[i].value == TOK.leftBracket; */ - /* immutable d = depths[i]; */ - /* while (true) */ - /* { */ - /* if (i >= tokens.length) */ - /* break; */ - /* if (depths[i] < d) */ - /* break; */ - /* if (!braces && !brackets && matchComma && depths[i] == d && tokens[i].value == TOK */ - /* .comma) */ - /* break; */ - /* if (!braces && !brackets && (tokens[i].value == TOK.semicolon || tokens[i].value == TOK */ - /* .leftCurly)) */ - /* break; */ - /* i++; */ - /* } */ - /* return i; */ - /* } */ - - /* /// Returns: true when the expression starting at index goes over the line length limit. */ - /* /// Uses matching `{}` or `[]` or otherwise takes everything up until a semicolon or opening brace using expressionEndIndex. */ - /* bool isMultilineAt(size_t i, bool matchComma = false) */ - /* { */ - /* import std.algorithm : map, sum, canFind; */ - - /* auto e = expressionEndIndex(i, matchComma); */ - /* immutable int l = currentLineLength + tokens[i .. e].map!(a => tokenLength(a)).sum(); */ - /* return l > config.dfmt_soft_max_line_length || tokens[i .. e].canFind!( */ - /* a => a.value == TOK.comment || isBlockHeaderToken(a.value))(); */ - /* } */ - - /* bool peekIsKeyword() nothrow */ - /* { */ - /* return index + 1 < tokens.length && isKeyword(tokens[index + 1].value); */ - /* } */ - - /* bool peekIsBasicType() nothrow */ - /* { */ - /* return index + 1 < tokens.length && isBasicType(tokens[index + 1].value); */ - /* } */ - - /* bool peekIsLabel() nothrow */ - /* { */ - /* return peekIs(TOK.identifier) && peek2Is(TOK.colon); */ - /* } */ - - /* int currentTokenLength() */ - /* { */ - /* return tokenLength(tokens[index]); */ - /* } */ - - /* int nextTokenLength() */ - /* { */ - /* immutable size_t i = index + 1; */ - /* if (i >= tokens.length) */ - /* return INVALID_TOKEN_LENGTH; */ - /* return tokenLength(tokens[i]); */ - /* } */ - - bool hasCurrent() nothrow const - { - return index < tokens.length; - } - - /* ref current() nothrow */ - /* in */ - /* { */ - /* assert(hasCurrent); */ - /* } */ - /* do */ - /* { */ - /* return tokens[index]; */ - /* } */ - - /* const(Token) peekBack(uint distance = 1) nothrow */ - /* { */ - /* assert(index >= distance, "Trying to peek before the first token"); */ - /* return tokens[index - distance]; */ - /* } */ - - /* bool peekBackIsLiteralOrIdent() nothrow */ - /* { */ - /* if (index == 0) */ - /* return false; */ - /* switch (tokens[index - 1].value) */ - /* { */ - /* case TOK.int32Literal: */ - /* case TOK.uns32Literal: */ - /* case TOK.int64Literal: */ - /* case TOK.uns64Literal: */ - /* case TOK.int128Literal: */ - /* case TOK.uns128Literal: */ - /* case TOK.float32Literal: */ - /* case TOK.float64Literal: */ - /* case TOK.float80Literal: */ - /* case TOK.imaginary32Literal: */ - /* case TOK.imaginary64Literal: */ - /* case TOK.imaginary80Literal: */ - /* case TOK.charLiteral: */ - /* case TOK.wcharLiteral: */ - /* case TOK.dcharLiteral: */ - /* case TOK.identifier: */ - /* case TOK.string_: */ - /* return true; */ - /* default: */ - /* return false; */ - /* } */ - /* } */ - - /* bool peekIsLiteralOrIdent() nothrow */ - /* { */ - /* if (index + 1 >= tokens.length) */ - /* return false; */ - /* switch (tokens[index + 1].value) */ - /* { */ - /* case TOK.int32Literal: */ - /* case TOK.uns32Literal: */ - /* case TOK.int64Literal: */ - /* case TOK.uns64Literal: */ - /* case TOK.int128Literal: */ - /* case TOK.uns128Literal: */ - /* case TOK.float32Literal: */ - /* case TOK.float64Literal: */ - /* case TOK.float80Literal: */ - /* case TOK.imaginary32Literal: */ - /* case TOK.imaginary64Literal: */ - /* case TOK.imaginary80Literal: */ - /* case TOK.charLiteral: */ - /* case TOK.wcharLiteral: */ - /* case TOK.dcharLiteral: */ - /* case TOK.identifier: */ - /* case TOK.string_: */ - /* return true; */ - /* default: */ - /* return false; */ - /* } */ - /* } */ - - /* bool peekBackIs(TOK tokenType, bool ignoreComments = false) nothrow */ - /* { */ - /* return peekImplementation(tokenType, -1, ignoreComments); */ - /* } */ - - /* bool peekBackIsKeyword(bool ignoreComments = true) nothrow */ - /* { */ - /* if (index == 0) */ - /* return false; */ - /* auto i = index - 1; */ - /* if (ignoreComments) */ - /* while (tokens[i].value == TOK.comment) */ - /* { */ - /* if (i == 0) */ - /* return false; */ - /* i--; */ - /* } */ - /* return isKeyword(tokens[i].value); */ - /* } */ - - /* bool peekBackIsOperator() nothrow */ - /* { */ - /* return index == 0 ? false : isOperator(tokens[index - 1].value); */ - /* } */ - - /* bool peekBackIsOneOf(bool ignoreComments, TOK[] tokenTypes...) nothrow */ - /* { */ - /* if (index == 0) */ - /* return false; */ - /* auto i = index - 1; */ - /* if (ignoreComments) */ - /* while (tokens[i].value == TOK.comment) */ - /* { */ - /* if (i == 0) */ - /* return false; */ - /* i--; */ - /* } */ - /* immutable t = tokens[i].value; */ - /* foreach (tt; tokenTypes) */ - /* if (tt == t) */ - /* return true; */ - /* return false; */ - /* } */ - - /* bool peekBack2Is(TOK tokenType, bool ignoreComments = false) nothrow */ - /* { */ - /* return peekImplementation(tokenType, -2, ignoreComments); */ - /* } */ - - /* bool peekImplementation(TOK tokenType, int n, bool ignoreComments = true) nothrow */ - /* { */ - /* auto i = index + n; */ - /* if (ignoreComments) */ - /* while (n != 0 && i < tokens.length && tokens[i].value == TOK.comment) */ - /* i = n > 0 ? i + 1 : i - 1; */ - /* return i < tokens.length && tokens[i].value == tokenType; */ - /* } */ - - /* bool peek2Is(TOK tokenType, bool ignoreComments = true) nothrow */ - /* { */ - /* return peekImplementation(tokenType, 2, ignoreComments); */ - /* } */ - - /* bool peekIsOperator() nothrow */ - /* { */ - /* return index + 1 < tokens.length && isOperator(tokens[index + 1].value); */ - /* } */ - - /* bool peekIs(TOK tokenType, bool ignoreComments = true) nothrow */ - /* { */ - /* return peekImplementation(tokenType, 1, ignoreComments); */ - /* } */ - - /* bool peekIsBody() nothrow */ - /* { */ - /* return index + 1 < tokens.length && tokens[index + 1].text == "body"; */ - /* } */ - - /* bool peekBackIsFunctionDeclarationEnding() nothrow */ - /* { */ - /* return peekBackIsOneOf(false, TOK.rightParenthesis, TOK.const_, TOK.immutable_, */ - /* TOK.inout_, TOK.shared_, TOK.at, TOK.pure_, TOK.nothrow_, */ - /* TOK.return_, TOK.scope_); */ - /* } */ - - /* bool peekBackIsSlashSlash() nothrow */ - /* { */ - /* return index > 0 && tokens[index - 1].value == TOK.comment */ - /* && tokens[index - 1].text[0 .. 2] == "//"; */ - /* } */ - - /* bool currentIs(TOK tokenType) nothrow */ - /* { */ - /* return hasCurrent && tokens[index].value == tokenType; */ - /* } */ - - /* bool onNextLine() @nogc nothrow pure @safe */ - /* { */ - /* import dfmt.editorconfig : OptionalBoolean; */ - /* import std.algorithm.searching : count; */ - /* import std.string : representation; */ - - /* if (config.dfmt_keep_line_breaks == OptionalBoolean.f || index <= 0) */ - /* { */ - /* return false; */ - /* } */ - /* // To compare whether 2 tokens are on same line, we need the end line */ - /* // of the first token (tokens[index - 1]) and the start line of the */ - /* // second one (tokens[index]). If a token takes multiple lines (e.g. a */ - /* // multi-line string), we can sum the number of the newlines in the */ - /* // token and tokens[index - 1].line, the start line. */ - /* const previousTokenEndLineNo = tokens[index - 1].line */ - /* + tokens[index - 1].text.representation.count('\n'); */ - - /* return previousTokenEndLineNo < tokens[index].line; */ - /* } */ - - /* /// Bugs: not unicode correct */ - /* size_t tokenEndLine(const Token t) */ - /* { */ - /* import std.algorithm : count; */ - - /* switch (t.value) */ - /* { */ - /* case TOK.comment: */ - /* case TOK.string_: */ - /* return t.line + t.text.count('\n'); */ - /* default: */ - /* return t.line; */ - /* } */ - /* } */ - - /* bool isBlockHeaderToken(const TOK t) */ - /* { */ - /* return t == TOK.for_ || t == TOK.foreach_ || t == TOK.foreach_reverse_ */ - /* || t == TOK.while_ || t == TOK.if_ || t == TOK.in_ || t == TOK.out_ */ - /* || t == TOK.do_ || t == TOK.catch_ || t == TOK.with_ */ - /* || t == TOK.synchronized_ || t == TOK.scope_ || t == TOK.debug_; */ - /* } */ - - /* bool isBlockHeader(int i = 0) nothrow */ - /* { */ - /* if (i + index < 0 || i + index >= tokens.length) */ - /* return false; */ - /* const t = tokens[i + index].value; */ - /* bool isExpressionContract; */ - - /* if (i + index + 3 < tokens.length) */ - /* { */ - /* isExpressionContract = (t == TOK.in_ && peekImplementation(TOK.leftParenthesis, i + 1, true)) */ - /* || (t == TOK.out_ && (peekImplementation(TOK.leftParenthesis, i + 1, true) */ - /* && (peekImplementation(TOK.semicolon, i + 2, true) */ - /* || (peekImplementation(TOK.identifier, i + 2, true) */ - /* && peekImplementation(TOK.semicolon, i + 3, true))))); */ - /* } */ - - /* return isBlockHeaderToken(t) && !isExpressionContract; */ - /* } */ - - /* bool isSeparationToken(TOK t) nothrow */ - /* { */ - /* return t == TOK.comma || t == TOK.semicolon || t == TOK.colon */ - /* || t == TOK.leftParenthesis || t == TOK.rightParenthesis */ - /* || t == TOK.leftBracket || t == TOK.rightBracket */ - /* || t == TOK.leftCurly || t == TOK.rightCurly; */ - /* } */ - /* } */ - - /* bool canFindIndex(const size_t[] items, size_t index, size_t* pos = null) pure @safe @nogc */ - /* { */ - /* import std.range : assumeSorted; */ - - /* if (!pos) */ - /* { */ - /* return !assumeSorted(items).equalRange(index).empty; */ - /* } */ - /* else */ - /* { */ - /* auto trisection_result = assumeSorted(items).trisect(index); */ - /* if (trisection_result[1].length == 1) */ - /* { */ - /* *pos = trisection_result[0].length; */ - /* return true; */ - /* } */ - /* else if (trisection_result[1].length == 0) */ - /* { */ - /* return false; */ - /* } */ - /* else */ - /* { */ - /* assert(0, "the constraint of having unique locations has been violated"); */ - /* } */ - /* } */ -} diff --git a/src/dfmt/indentation.d b/src/dfmt/indentation.d deleted file mode 100644 index 50d7ab8..0000000 --- a/src/dfmt/indentation.d +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright Brian Schott 2015. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -module dfmt.indentation; - -import dfmt.config; -import dfmt.editorconfig; -import dmd.tokens; - -import std.bitmanip : bitfields; - -/** - * Returns: true if the given token type is a wrap indent type - */ -bool isWrapIndent(TOK type) pure nothrow @nogc @safe -{ - switch (type) - { - case TOK.leftCurly: - case TOK.case_: - case TOK.at: - case TOK.rightBracket: - case TOK.leftParenthesis: - case TOK.rightParenthesis: - return false; - - // Operators - case TOK.lessThan: - case TOK.greaterThan: - case TOK.lessOrEqual: - case TOK.greaterOrEqual: - case TOK.equal: - case TOK.notEqual: - case TOK.identity: - case TOK.notIdentity: - case TOK.is_: - - case TOK.leftShift: - case TOK.rightShift: - case TOK.leftShiftAssign: - case TOK.rightShiftAssign: - case TOK.unsignedRightShift: - case TOK.unsignedRightShiftAssign: - case TOK.concatenateAssign: - case TOK.add: - case TOK.min: - case TOK.addAssign: - case TOK.minAssign: - case TOK.mul: - case TOK.div: - case TOK.mod: - case TOK.mulAssign: - case TOK.divAssign: - case TOK.modAssign: - case TOK.and: - case TOK.or: - case TOK.xor: - case TOK.andAssign: - case TOK.orAssign: - case TOK.xorAssign: - case TOK.assign: - case TOK.not: - case TOK.tilde: - case TOK.plusPlus: - case TOK.minusMinus: - case TOK.dot: - case TOK.comma: - case TOK.question: - case TOK.andAnd: - case TOK.orOr: - return true; - default: - return false; - } -} - -/** - * Returns: true if the given token type is a temporary indent type - */ -bool isTempIndent(TOK type) pure nothrow @nogc @safe -{ - return type != TOK.rightParenthesis && type != TOK.leftCurly && type != TOK.case_ && type != TOK - .at; -} - -/** - * Stack for managing indent levels. - */ -struct IndentStack -{ - /// Configuration - private const Config* config; - - this(const Config* config) - { - this.config = config; - } - - static struct Details - { - mixin(bitfields!( - // generally true for all operators except {, case, @, ], (, ) - bool, "wrap", 1, // temporary indentation which get's reverted when a block starts - // generally true for all tokens except ), {, case, @ - bool, "temp", 1, // emit minimal newlines - bool, "mini", 1, // for associative arrays or arrays containing them, break after every item - bool, "breakEveryItem", 1, // when an item inside an array would break mid-item, definitely break at the comma first - bool, "preferLongBreaking", 1, - uint, "", 27)); - } - - /** - * Get the indent size at the most recent occurrence of the given indent type - */ - int indentToMostRecent(TOK item) const - { - if (index == 0) - return -1; - size_t i = index - 1; - while (true) - { - if (arr[i] == item) - return indentSize(i); - if (i > 0) - i--; - else - return -1; - } - } - - int wrapIndents() const pure nothrow @property - { - if (index == 0) - return 0; - int tempIndentCount = 0; - for (size_t i = index; i > 0; i--) - { - if (!details[i - 1].wrap && arr[i - 1] != TOK.rightBracket) - break; - tempIndentCount++; - } - return tempIndentCount; - } - - /** - * Pushes the given indent type on to the stack. - */ - void push(TOK item) pure nothrow - { - Details detail; - detail.wrap = isWrapIndent(item); - detail.temp = isTempIndent(item); - push(item, detail); - } - - /** - * Pushes the given indent type on to the stack. - */ - void push(TOK item, Details detail) pure nothrow - { - arr[index] = item; - details[index] = detail; - //FIXME this is actually a bad thing to do, - //we should not just override when the stack is - //at it's limit - if (index < arr.length) - { - index++; - } - } - - /** - * Pops the top indent from the stack. - */ - void pop() pure nothrow - { - if (index) - index--; - } - - /** - * Pops all wrapping indents from the top of the stack. - */ - void popWrapIndents() pure nothrow @safe @nogc - { - while (index > 0 && details[index - 1].wrap) - index--; - } - - /** - * Pops all temporary indents from the top of the stack. - */ - void popTempIndents() pure nothrow @safe @nogc - { - while (index > 0 && details[index - 1].temp) - index--; - } - - bool topAre(TOK[] types...) - { - if (types.length > index) - return false; - return arr[index - types.length .. index] == types; - - } - - /** - * Returns: `true` if the top of the indent stack is the given indent type. - */ - bool topIs(TOK type) const pure nothrow @safe @nogc - { - return index > 0 && index <= arr.length && arr[index - 1] == type; - } - - /** - * Returns: `true` if the top of the indent stack is a temporary indent - */ - bool topIsTemp() - { - return index > 0 && index <= arr.length && details[index - 1].temp; - } - - /** - * Returns: `true` if the top of the indent stack is a temporary indent with the specified token - */ - bool topIsTemp(TOK item) - { - return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1] - .temp; - } - - /** - * Returns: `true` if the top of the indent stack is a wrapping indent - */ - bool topIsWrap() - { - return index > 0 && index <= arr.length && details[index - 1].wrap; - } - - /** - * Returns: `true` if the top of the indent stack is a temporary indent with the specified token - */ - bool topIsWrap(TOK item) - { - return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1] - .wrap; - } - - /** - * Returns: `true` if the top of the indent stack is one of the given token - * types. - */ - bool topIsOneOf(TOK[] types...) const pure nothrow @safe @nogc - { - if (index == 0) - return false; - immutable topType = arr[index - 1]; - foreach (t; types) - if (t == topType) - return true; - return false; - } - - TOK top() const pure nothrow @property @safe @nogc - { - return arr[index - 1]; - } - - Details topDetails() const pure nothrow @property @safe @nogc - { - return details[index - 1]; - } - - int indentLevel() const pure nothrow @property @safe @nogc - { - return indentSize(); - } - - int length() const pure nothrow @property @safe @nogc - { - return cast(int) index; - } - - /** - * Dumps the current state of the indentation stack to `stderr`. Used for debugging. - */ - void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__) const - { - import std.algorithm.iteration : map; - import std.stdio : stderr; - - if (pos == size_t.max) - stderr.writefln("\033[31m%s:%d %(%s %)\033[0m", file, line, arr[0 .. index].map!( - a => Token.toString(a))); - else - stderr.writefln("\033[31m%s:%d at %d %(%s %)\033[0m", file, line, pos, arr[0 .. index].map!( - a => Token.toString(a))); - } - -private: - - size_t index; - - TOK[256] arr; - Details[arr.length] details; - - int indentSize(const size_t k = size_t.max) const pure nothrow @safe @nogc - { - import std.algorithm : among; - - if (index == 0 || k == 0) - return 0; - immutable size_t j = k == size_t.max ? index : k; - int size = 0; - int parenCount; - foreach (i; 0 .. j) - { - immutable int pc = (arr[i] == TOK.not || arr[i] == TOK.leftParenthesis || arr[i] == TOK - .rightParenthesis) ? parenCount + 1 : parenCount; - if ((details[i].wrap || arr[i] == TOK.leftParenthesis) && parenCount > 1) - { - parenCount = pc; - continue; - } - - if (i + 1 < index) - { - if (config.dfmt_single_indent == OptionalBoolean.t && skipDoubleIndent(i, parenCount)) - { - parenCount = pc; - continue; - } - - immutable currentIsNonWrapTemp = !details[i].wrap - && details[i].temp && arr[i] != TOK.rightParenthesis && arr[i] != TOK.not; - - if (currentIsNonWrapTemp && arr[i + 1] == TOK.rightBracket) - { - parenCount = pc; - continue; - } - if (arr[i] == TOK.static_ - && arr[i + 1].among!(TOK.if_, TOK.else_, TOK.foreach_, TOK.foreach_reverse_) - && (i + 2 >= index || arr[i + 2] != TOK.leftCurly)) - { - parenCount = pc; - continue; - } - - if (currentIsNonWrapTemp && (arr[i + 1] == TOK.switch_ - || arr[i + 1] == TOK.leftCurly || arr[i + 1] == TOK.rightParenthesis)) - { - parenCount = pc; - continue; - } - } - else if (parenCount == 0 && arr[i] == TOK.leftParenthesis && config.dfmt_single_indent == OptionalBoolean - .f) - size++; - - if (arr[i] == TOK.not) - size++; - - parenCount = pc; - size++; - } - return size; - } - - bool skipDoubleIndent(size_t i, int parenCount) const pure nothrow @safe @nogc - { - return (details[i + 1].wrap && arr[i] == TOK.rightParenthesis) - || (parenCount == 0 && arr[i + 1] == TOK.comma && arr[i] == TOK.leftParenthesis); - } -} - -unittest -{ - IndentStack stack; - stack.push(TOK.leftCurly); - assert(stack.length == 1); - assert(stack.indentLevel == 1); - stack.pop(); - assert(stack.length == 0); - assert(stack.indentLevel == 0); - stack.push(TOK.if_); - assert(stack.topIsTemp()); - stack.popTempIndents(); - assert(stack.length == 0); -} diff --git a/src/dfmt/main.d b/src/dfmt/main.d index c5a5577..941e5d7 100644 --- a/src/dfmt/main.d +++ b/src/dfmt/main.d @@ -30,91 +30,85 @@ static immutable VERSION = () { } return DFMT_VERSION ~ DEBUG_SUFFIX; -} (); +}(); +import dfmt.config : Config; +import dfmt.editorconfig : getConfigFor; +import dfmt.formatter : format; +import std.array : appender, front, popFront; +import std.getopt : getopt, GetOptException; +import std.path : buildPath, dirName, expandTilde; +import std.stdio : File, stderr, stdin, stdout, writeln; -version (NoMain) +int main(string[] args) { -} -else -{ - import dfmt.config : Config; - import dfmt.editorconfig : getConfigFor; - import dfmt.formatter : format; - import std.array : appender, front, popFront; - import std.getopt : getopt, GetOptException; - import std.path : buildPath, dirName, expandTilde; - import std.stdio : File, stderr, stdin, stdout, writeln; + bool inplace = false; + Config optConfig; + optConfig.pattern = "*.d"; + bool showHelp; + bool showVersion; + string explicitConfigDir; - int main(string[] args) + void handleBooleans(string option, string value) { - bool inplace = false; - Config optConfig; - optConfig.pattern = "*.d"; - bool showHelp; - bool showVersion; - string explicitConfigDir; + import dfmt.editorconfig : OptionalBoolean; + import std.exception : enforce; - void handleBooleans(string option, string value) + enforce!GetOptException(value == "true" || value == "false", "Invalid argument"); + immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t + : OptionalBoolean.f; + switch (option) { - import dfmt.editorconfig : OptionalBoolean; - import std.exception : enforce; - - enforce!GetOptException(value == "true" || value == "false", "Invalid argument"); - immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t - : OptionalBoolean.f; - switch (option) - { - case "align_switch_statements": - optConfig.dfmt_align_switch_statements = optVal; - break; - case "outdent_attributes": - optConfig.dfmt_outdent_attributes = optVal; - break; - case "space_after_cast": - optConfig.dfmt_space_after_cast = optVal; - break; - case "space_before_function_parameters": - optConfig.dfmt_space_before_function_parameters = optVal; - break; - case "split_operator_at_line_end": - optConfig.dfmt_split_operator_at_line_end = optVal; - break; - case "selective_import_space": - optConfig.dfmt_selective_import_space = optVal; - break; - case "compact_labeled_statements": - optConfig.dfmt_compact_labeled_statements = optVal; - break; - case "single_template_constraint_indent": - optConfig.dfmt_single_template_constraint_indent = optVal; - break; - case "space_before_aa_colon": - optConfig.dfmt_space_before_aa_colon = optVal; - break; - case "space_before_named_arg_colon": - optConfig.dfmt_space_before_named_arg_colon = optVal; - break; - case "keep_line_breaks": - optConfig.dfmt_keep_line_breaks = optVal; - break; - case "single_indent": - optConfig.dfmt_single_indent = optVal; - break; - case "reflow_property_chains": - optConfig.dfmt_reflow_property_chains = optVal; - break; - case "space_after_keywords": - optConfig.dfmt_space_after_keywords = optVal; - break; - default: - assert(false, "Invalid command-line switch"); - } + case "align_switch_statements": + optConfig.dfmt_align_switch_statements = optVal; + break; + case "outdent_attributes": + optConfig.dfmt_outdent_attributes = optVal; + break; + case "space_after_cast": + optConfig.dfmt_space_after_cast = optVal; + break; + case "space_before_function_parameters": + optConfig.dfmt_space_before_function_parameters = optVal; + break; + case "split_operator_at_line_end": + optConfig.dfmt_split_operator_at_line_end = optVal; + break; + case "selective_import_space": + optConfig.dfmt_selective_import_space = optVal; + break; + case "compact_labeled_statements": + optConfig.dfmt_compact_labeled_statements = optVal; + break; + case "single_template_constraint_indent": + optConfig.dfmt_single_template_constraint_indent = optVal; + break; + case "space_before_aa_colon": + optConfig.dfmt_space_before_aa_colon = optVal; + break; + case "space_before_named_arg_colon": + optConfig.dfmt_space_before_named_arg_colon = optVal; + break; + case "keep_line_breaks": + optConfig.dfmt_keep_line_breaks = optVal; + break; + case "single_indent": + optConfig.dfmt_single_indent = optVal; + break; + case "reflow_property_chains": + optConfig.dfmt_reflow_property_chains = optVal; + break; + case "space_after_keywords": + optConfig.dfmt_space_after_keywords = optVal; + break; + default: + assert(false, "Invalid command-line switch"); } + } - try - { - // dfmt off + try + { + // dfmt off getopt(args, "version", &showVersion, "align_switch_statements", &handleBooleans, @@ -143,68 +137,116 @@ else "single_indent", &handleBooleans, "reflow_property_chains", &handleBooleans); // dfmt on - } - catch (GetOptException e) + } + catch (GetOptException e) + { + stderr.writeln(e.msg); + return 1; + } + + if (showVersion) + { + writeln(VERSION); + return 0; + } + + if (showHelp) + { + printHelp(); + return 0; + } + + args.popFront(); + immutable bool readFromStdin = args.length == 0; + + version (Windows) + { + // On Windows, set stdout to binary mode (needed for correct EOL writing) + // See Phobos' stdio.File.rawWrite { - stderr.writeln(e.msg); + import std.stdio : _O_BINARY; + + immutable fd = stdout.fileno; + _setmode(fd, _O_BINARY); + version (CRuntime_DigitalMars) + { + import core.atomic : atomicOp; + import core.stdc.stdio : __fhnd_info, FHND_TEXT; + + atomicOp!"&="(__fhnd_info[fd], ~FHND_TEXT); + } + } + } + + ubyte[] buffer; + + Config explicitConfig; + if (explicitConfigDir) + { + import std.file : exists, isDir; + + if (!exists(explicitConfigDir) || !isDir(explicitConfigDir)) + { + stderr.writeln("--config|c must specify existing directory path"); return 1; } + explicitConfig = getConfigFor!Config(explicitConfigDir); + explicitConfig.pattern = "*.d"; + } - if (showVersion) + if (readFromStdin) + { + import std.file : getcwd; + + auto cwdDummyPath = buildPath(getcwd(), "dummy.d"); + + Config config; + config.initializeWithDefaults(); + if (explicitConfigDir != "") { - writeln(VERSION); - return 0; + config.merge(explicitConfig, buildPath(explicitConfigDir, "dummy.d")); } - - if (showHelp) + else { - printHelp(); - return 0; + Config fileConfig = getConfigFor!Config(getcwd()); + fileConfig.pattern = "*.d"; + config.merge(fileConfig, cwdDummyPath); } - - args.popFront(); - immutable bool readFromStdin = args.length == 0; - - version (Windows) + config.merge(optConfig, cwdDummyPath); + if (!config.isValid()) + return 1; + ubyte[4096] inputBuffer; + ubyte[] b; + while (true) { - // On Windows, set stdout to binary mode (needed for correct EOL writing) - // See Phobos' stdio.File.rawWrite + b = stdin.rawRead(inputBuffer); + if (b.length) + buffer ~= b; + else + break; + } + immutable bool formatSuccess = format("stdin", buffer, + stdout.lockingTextWriter(), &config); + return formatSuccess ? 0 : 1; + } + else + { + import std.file : dirEntries, isDir, SpanMode; + + if (args.length >= 2) + inplace = true; + int retVal; + while (args.length > 0) + { + const path = args.front; + args.popFront(); + if (isDir(path)) { - import std.stdio : _O_BINARY; - immutable fd = stdout.fileno; - _setmode(fd, _O_BINARY); - version (CRuntime_DigitalMars) - { - import core.atomic : atomicOp; - import core.stdc.stdio : __fhnd_info, FHND_TEXT; - - atomicOp!"&="(__fhnd_info[fd], ~FHND_TEXT); - } + inplace = true; + foreach (string name; dirEntries(path, "*.d", SpanMode.depth)) + args ~= name; + continue; } - } - - ubyte[] buffer; - - Config explicitConfig; - if (explicitConfigDir) - { - import std.file : exists, isDir; - - if (!exists(explicitConfigDir) || !isDir(explicitConfigDir)) - { - stderr.writeln("--config|c must specify existing directory path"); - return 1; - } - explicitConfig = getConfigFor!Config(explicitConfigDir); - explicitConfig.pattern = "*.d"; - } - - if (readFromStdin) - { - import std.file : getcwd; - - auto cwdDummyPath = buildPath(getcwd(), "dummy.d"); - Config config; config.initializeWithDefaults(); if (explicitConfigDir != "") @@ -213,94 +255,42 @@ else } else { - Config fileConfig = getConfigFor!Config(getcwd()); + Config fileConfig = getConfigFor!Config(path); fileConfig.pattern = "*.d"; - config.merge(fileConfig, cwdDummyPath); + config.merge(fileConfig, path); } - config.merge(optConfig, cwdDummyPath); + config.merge(optConfig, path); if (!config.isValid()) return 1; - ubyte[4096] inputBuffer; - ubyte[] b; - while (true) + File f = File(path); + // ignore empty files + if (f.size) { - b = stdin.rawRead(inputBuffer); - if (b.length) - buffer ~= b; + buffer = new ubyte[](cast(size_t) f.size); + f.rawRead(buffer); + File.LockingTextWriter output; + if (inplace) + output = File(path, "wb").lockingTextWriter(); else - break; + output = stdout.lockingTextWriter(); + immutable bool formatSuccess = format(path, buffer, output, &config); + retVal = formatSuccess ? 0 : 1; } - immutable bool formatSuccess = format("stdin", buffer, - stdout.lockingTextWriter(), &config); - return formatSuccess ? 0 : 1; - } - else - { - import std.file : dirEntries, isDir, SpanMode; - - if (args.length >= 2) - inplace = true; - int retVal; - while (args.length > 0) - { - const path = args.front; - args.popFront(); - if (isDir(path)) - { - inplace = true; - foreach (string name; dirEntries(path, "*.d", SpanMode.depth)) - args ~= name; - continue; - } - Config config; - config.initializeWithDefaults(); - if (explicitConfigDir != "") - { - config.merge(explicitConfig, buildPath(explicitConfigDir, "dummy.d")); - } - else - { - Config fileConfig = getConfigFor!Config(path); - fileConfig.pattern = "*.d"; - config.merge(fileConfig, path); - } - config.merge(optConfig, path); - if (!config.isValid()) - return 1; - File f = File(path); - // ignore empty files - if (f.size) - { - buffer = new ubyte[](cast(size_t) f.size); - f.rawRead(buffer); - auto output = appender!string; - immutable bool formatSuccess = format(path, buffer, output, &config); - if (formatSuccess) - { - if (inplace) - File(path, "wb").rawWrite(output.data); - else - stdout.rawWrite(output.data); - } - else - retVal = 1; - } - } - return retVal; } + return retVal; } } private version (Windows) { - version(CRuntime_DigitalMars) + version (CRuntime_DigitalMars) { - extern(C) int setmode(int, int) nothrow @nogc; + extern (C) int setmode(int, int) nothrow @nogc; alias _setmode = setmode; } - else version(CRuntime_Microsoft) + else version (CRuntime_Microsoft) { - extern(C) int _setmode(int, int) nothrow @nogc; + extern (C) int _setmode(int, int) nothrow @nogc; } } @@ -318,11 +308,14 @@ template optionsToString(E) if (is(E == enum)) } result = result[0 .. $ - 1] ~ ")"; return result; - } (); + }(); } private void printHelp() { + import std.stdio : writeln; + import dfmt.config; + writeln(`dfmt `, VERSION, ` https://github.com/dlang-community/dfmt @@ -335,11 +328,11 @@ Options: Formatting Options: --align_switch_statements --brace_style `, optionsToString!(typeof(Config.dfmt_brace_style)), - ` + ` --end_of_line `, optionsToString!(typeof(Config.end_of_line)), ` --indent_size --indent_style, -t `, - optionsToString!(typeof(Config.indent_style)), ` + optionsToString!(typeof(Config.indent_style)), ` --keep_line_breaks --soft_max_line_length --max_line_length @@ -357,13 +350,13 @@ Formatting Options: --single_indent --reflow_property_chains `, - optionsToString!(typeof(Config.dfmt_template_constraint_style))); + optionsToString!(typeof(Config.dfmt_template_constraint_style))); } private string createFilePath(bool readFromStdin, string fileName) { import std.file : getcwd; - import std.path : isRooted; + import std.path : isRooted, buildPath; immutable string cwd = getcwd(); if (readFromStdin) diff --git a/src/dfmt/tokens.d b/src/dfmt/tokens.d deleted file mode 100644 index 9d5c9b1..0000000 --- a/src/dfmt/tokens.d +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright Brian Schott 2015. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -module dfmt.tokens; - -import dmd.tokens; - -/// Length of an invalid token -enum int INVALID_TOKEN_LENGTH = -1; - -uint betweenParenLength(const Token[] tokens) @safe -in -{ - assert(tokens[0].value == TOK.leftParenthesis); -} -do -{ - uint length = 0; - size_t i = 1; - int depth = 1; - while (i < tokens.length && depth > 0) - { - if (tokens[i].value == TOK.leftParenthesis) - depth++; - else if (tokens[i].value == TOK.rightParenthesis) - depth--; - length += tokenLength(tokens[i]); - i++; - } - return length; -} - -int tokenLength(ref const Token t) @safe -{ - import std.algorithm : countUntil; - - if (t.isKeyword()) - return cast(int) Token.toString(t.value).length; - - int c; - switch (t.value) - { - // Numeric literals - case TOK.int32Literal: - case TOK.uns32Literal: - case TOK.int64Literal: - case TOK.uns64Literal: - case TOK.int128Literal: - case TOK.uns128Literal: - case TOK.float32Literal: - case TOK.float64Literal: - case TOK.float80Literal: - case TOK.imaginary32Literal: - case TOK.imaginary64Literal: - case TOK.imaginary80Literal: - // Char constants - case TOK.charLiteral: - case TOK.wcharLiteral: - case TOK.dcharLiteral: - // Identifiers - case TOK.identifier: - return cast(int) Token.toString(t.value).length; - // Spaced operators - case TOK.add: - case TOK.addAssign: - case TOK.and: - case TOK.andAnd: - case TOK.andAssign: - case TOK.arrow: - case TOK.assign: - case TOK.colon: - case TOK.colonColon: - case TOK.comma: - case TOK.concatenateAssign: - case TOK.div: - case TOK.divAssign: - case TOK.dot: - case TOK.dotDotDot: - case TOK.equal: - case TOK.goesTo: - case TOK.greaterOrEqual: - case TOK.greaterThan: - case TOK.identity: - case TOK.is_: - case TOK.leftShift: - case TOK.leftShiftAssign: - case TOK.lessOrEqual: - case TOK.lessThan: - case TOK.min: - case TOK.minAssign: - case TOK.minusMinus: - case TOK.mod: - case TOK.modAssign: - case TOK.mul: - case TOK.mulAssign: - case TOK.not: - case TOK.notEqual: - case TOK.notIdentity: - case TOK.or: - case TOK.orAssign: - case TOK.orOr: - case TOK.plusPlus: - case TOK.pound: - case TOK.pow: - case TOK.powAssign: - case TOK.question: - case TOK.rightShift: - case TOK.rightShiftAssign: - case TOK.semicolon: - case TOK.slice: - case TOK.tilde: - case TOK.unsignedRightShift: - case TOK.unsignedRightShiftAssign: - case TOK.xor: - case TOK.xorAssign: - return cast(int) Token.toString(t.value).length + 1; - case TOK.string_: - // TODO: Unicode line breaks and old-Mac line endings - c = cast(int) Token.toString(t.value).countUntil('\n'); - if (c == -1) - return cast(int) Token.toString(t.value).length; - else - return c; - - default: - return INVALID_TOKEN_LENGTH; - } -} - -bool isBreakToken(TOK t) pure nothrow @safe @nogc -{ - switch (t) - { - case TOK.orOr: - case TOK.andAnd: - case TOK.leftParenthesis: - case TOK.leftBracket: - case TOK.comma: - case TOK.colon: - case TOK.semicolon: - case TOK.pow: - case TOK.powAssign: - case TOK.xor: - case TOK.concatenateAssign: - case TOK.leftShiftAssign: - case TOK.leftShift: - case TOK.lessOrEqual: - case TOK.lessThan: - case TOK.equal: - case TOK.goesTo: - case TOK.assign: - case TOK.greaterOrEqual: - case TOK.rightShiftAssign: - case TOK.unsignedRightShift: - case TOK.unsignedRightShiftAssign: - case TOK.rightShift: - case TOK.greaterThan: - case TOK.orAssign: - case TOK.or: - case TOK.minAssign: - case TOK.notEqual: - case TOK.question: - case TOK.divAssign: - case TOK.div: - case TOK.slice: - case TOK.mulAssign: - case TOK.mul: - case TOK.andAssign: - case TOK.modAssign: - case TOK.mod: - case TOK.addAssign: - case TOK.dot: - case TOK.tilde: - case TOK.add: - case TOK.min: - return true; - default: - return false; - } -} - -int breakCost(TOK p, TOK c) pure nothrow @safe @nogc -{ - switch (c) - { - case TOK.orOr: - case TOK.andAnd: - case TOK.comma: - case TOK.question: - return 0; - case TOK.leftParenthesis: - return 60; - case TOK.leftBracket: - return 300; - case TOK.semicolon: - case TOK.pow: - case TOK.xorAssign: - case TOK.xor: - case TOK.concatenateAssign: - case TOK.leftShiftAssign: - case TOK.leftShift: - case TOK.lessOrEqual: - case TOK.lessThan: - case TOK.equal: - case TOK.goesTo: - case TOK.assign: - case TOK.greaterOrEqual: - case TOK.rightShiftAssign: - case TOK.unsignedRightShiftAssign: - case TOK.unsignedRightShift: - case TOK.rightShift: - case TOK.greaterThan: - case TOK.orAssign: - case TOK.or: - case TOK.minAssign: - case TOK.divAssign: - case TOK.div: - case TOK.slice: - case TOK.mulAssign: - case TOK.mul: - case TOK.andAssign: - case TOK.modAssign: - case TOK.mod: - case TOK.add: - case TOK.min: - case TOK.tilde: - case TOK.addAssign: - return 200; - case TOK.colon: - // colon could be after a label or an import, where it should normally wrap like before - // for everything else (associative arrays) try not breaking around colons - return p == TOK.identifier ? 0 : 300; - case TOK.dot: - return p == TOK.rightParenthesis ? 0 : 300; - default: - return 1000; - } -} - -pure nothrow @safe @nogc unittest -{ - foreach (ubyte u; 0 .. ubyte.max) - if (isBreakToken(u)) - assert(breakCost(TOK.dot, u) != 1000); -} diff --git a/src/dfmt/wrapping.d b/src/dfmt/wrapping.d deleted file mode 100644 index 1d3f436..0000000 --- a/src/dfmt/wrapping.d +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright Brian Schott 2015. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -module dfmt.wrapping; - -import dmd.tokens; -import dfmt.tokens; -import dfmt.config; - -struct State -{ - this(uint breaks, const Token[] tokens, immutable short[] depths, - const Config* config, int currentLineLength, int indentLevel) @safe - { - import std.math : abs; - import core.bitop : popcnt, bsf; - import std.algorithm : min, map, sum; - - immutable int remainingCharsMultiplier = 25; - immutable int newlinePenalty = 480; - - this.breaks = breaks; - this._cost = 0; - this._solved = true; - - if (breaks == 0) - { - immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum(); - if (l > config.dfmt_soft_max_line_length) - { - immutable int longPenalty = (l - config.dfmt_soft_max_line_length) - * remainingCharsMultiplier; - this._cost += longPenalty; - this._solved = longPenalty < newlinePenalty; - } - } - else - { - foreach (size_t i; 0 .. (uint.sizeof * 8)) - { - if (((1 << i) & breaks) == 0) - continue; - immutable prevType = i > 0 ? tokens[i - 1].value : TOK.error; - immutable currentType = tokens[i].value; - immutable p = abs(depths[i]); - immutable bc = breakCost(prevType, currentType) * (p == 0 ? 1 : p * 2); - this._cost += bc + newlinePenalty; - } - - int ll = currentLineLength; - size_t i = 0; - foreach (_; 0 .. uint.sizeof * 8) - { - immutable uint k = breaks >>> i; - immutable bool b = k == 0; - immutable uint bits = b ? ALGORITHMIC_COMPLEXITY_SUCKS : bsf(k); - immutable size_t j = min(i + bits + 1, tokens.length); - ll += tokens[i .. j].map!(a => tokenLength(a)).sum(); - if (ll > config.dfmt_soft_max_line_length) - { - immutable int longPenalty = (ll - config.dfmt_soft_max_line_length) - * remainingCharsMultiplier; - this._cost += longPenalty; - } - if (ll > config.max_line_length) - { - this._solved = false; - break; - } - i = j; - if (indentLevel < 0) - ll = (abs(indentLevel) + 1) * config.indent_size; - else - ll = (indentLevel + (i == 0 ? 0 : 1)) * config.indent_size; - if (b) - break; - } - } - } - - int cost() const pure nothrow @safe @property - { - return _cost; - } - - int solved() const pure nothrow @safe @property - { - return _solved; - } - - int opCmp(ref const State other) const pure nothrow @safe - { - import core.bitop : bsf, popcnt; - - if (_cost < other._cost) - return -1; - if (_cost == other._cost && (breaks != 0 && other.breaks != 0 - && bsf(breaks) > bsf(other.breaks))) - return -1; - return _cost > other._cost; - } - - bool opEquals(ref const State other) const pure nothrow @safe - { - return other.breaks == breaks; - } - - size_t toHash() const pure nothrow @safe - { - return breaks; - } - - uint breaks; - -private: - int _cost; - bool _solved; -} - -private enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8; - -/** - * Note: Negative values for `indentLevel` are treated specially: costs for - * continuation indents are reduced. This is used for array literals. - */ -size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, - immutable short[] depths, const Config* config, int currentLineLength, int indentLevel) -{ - import std.container.rbtree : RedBlackTree; - import std.algorithm : filter, min; - import core.bitop : popcnt; - - static size_t[] genRetVal(uint breaks, size_t index) pure nothrow @safe - { - auto retVal = new size_t[](popcnt(breaks)); - size_t j = 0; - foreach (uint i; 0 .. uint.sizeof * 8) - if ((1 << i) & breaks) - retVal[j++] = index + i; - return retVal; - } - - immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS); - auto open = new RedBlackTree!State; - open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], config, - currentLineLength, indentLevel)); - State lowest; - lowest._solved = false; - int tries = 0; - while (!open.empty && tries < 10_00) - { - tries++; - State current = open.front(); - open.removeFront(); - if (current.solved) - return genRetVal(current.breaks, index); - if (current < lowest) - lowest = current; - validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], - current.breaks, config, currentLineLength, indentLevel); - } - foreach (r; open[].filter!(a => a.solved)) - return genRetVal(r.breaks, index); - if (open[].front < lowest) - return genRetVal(open[].front.breaks, index); - else - return genRetVal(lowest.breaks, index); -} - -void validMoves(OR)(auto ref OR output, const Token[] tokens, immutable short[] depths, - uint current, const Config* config, int currentLineLength, int indentLevel) -{ - foreach (i, token; tokens) - { - if (!isBreakToken(token.value) || (((1 << i) & current) != 0)) - continue; - immutable uint breaks = current | (1 << i); - output.insert(State(breaks, tokens, depths, config, currentLineLength, indentLevel)); - } -} From decdc79445bd95c67c4357fcbfd490983177b914 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Wed, 8 Nov 2023 18:10:36 +0530 Subject: [PATCH 06/24] fix: add indentation logic Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 1265 ++++++++++++++++++++++++------------------------ 1 file changed, 631 insertions(+), 634 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 737debd..80594ca 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -25,6 +25,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor string eol; uint depth; bool declstring; // set while declaring alias for string,wstring or dstring + bool doindent; // insert indentation before writing the string this(File.LockingTextWriter buf, Config* config) { @@ -69,10 +70,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } } - pragma(inline) void newline() { buf.put(eol); + // Indicate that the next write should be indented + doindent = true; + } + + extern (D) void write(T)(T data) + { + if (doindent) + { + indent(); + doindent = false; + } + buf.put(data); } /******************************************* @@ -86,6 +98,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { stc &= ~(ASTCodegen.STC.scope_ | ASTCodegen.STC.scopeinferred); } + if (stc & ASTCodegen.STC.returninferred) { stc &= ~(ASTCodegen.STC.return_ | ASTCodegen.STC.returninferred); @@ -118,7 +131,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor rrs = isout ? "out return scope" : "ref return scope"; goto L1; L1: - buf.put(rrs); + write(rrs); writeSpace = true; stc &= ~( ASTCodegen.STC.out_ | ASTCodegen.STC.scope_ | ASTCodegen.STC.ref_ | ASTCodegen @@ -132,13 +145,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (!s.length) break; if (writeSpace) - buf.put(' '); + write(' '); writeSpace = true; - buf.put(s); + write(s); } if (writeSpace) - buf.put(' '); + write(' '); } @@ -157,7 +170,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor assert(strlen(buffer.ptr) < BUFFER_LEN); if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') buffer.ptr[strlen(buffer.ptr) - 1] = char.init; - buf.put(buffer.array); + write(buffer.array); if (type) { @@ -167,18 +180,18 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case Tfloat32: case Timaginary32: case Tcomplex32: - buf.put('F'); + write('F'); break; case Tfloat80: case Timaginary80: case Tcomplex80: - buf.put('L'); + write('L'); break; default: break; } if (t.isimaginary()) - buf.put('i'); + write('i'); } } @@ -188,11 +201,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visit(ASTCodegen.Expression e) { - buf.put(EXPtoString(e.op)); + write(EXPtoString(e.op)); } void visitInteger(ASTCodegen.IntegerExp e) { + import core.stdc.stdio : sprintf; + auto v = e.toInteger(); if (e.type) { @@ -210,13 +225,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if ((cast(ASTCodegen.EnumMember) em).value.toInteger == v) { - buf.put(format("%s.%s", sym.toString(), em.ident.toString())); + write(format("%s.%s", sym.toString(), em.ident.toString())); return; } } } - buf.put(format("cast(%s)", te.sym.toString())); + write(format("cast(%s)", te.sym.toString())); t = te.sym.memtype; goto L1; } @@ -224,27 +239,27 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case Twchar: case Tdchar: { - buf.put(cast(dchar) v); + write(cast(dchar) v); break; } case Tint8: - buf.put("cast(byte)"); + write("cast(byte)"); goto L2; case Tint16: - buf.put("cast(short)"); + write("cast(short)"); goto L2; case Tint32: L2: - buf.put(format("%d", cast(int) v)); + write(format("%d", cast(int) v)); break; case Tuns8: - buf.put("cast(ubyte)"); + write("cast(ubyte)"); goto case Tuns32; case Tuns16: - buf.put("cast(ushort)"); + write("cast(ushort)"); goto case Tuns32; case Tuns32: - buf.put(format("%uu", cast(uint) v)); + write(format("%uu", cast(uint) v)); break; case Tint64: if (v == long.min) @@ -252,23 +267,23 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // https://issues.dlang.org/show_bug.cgi?id=23173 // This is a special case because - is not part of the // integer literal and 9223372036854775808L overflows a long - buf.put("cast(long)-9223372036854775808"); + write("cast(long)-9223372036854775808"); } else { - buf.put(format("%lldL", v)); + write(format("%uL", v)); } break; case Tuns64: - buf.put(format("%lluLU", v)); + write(format("%uLU", v)); break; case Tbool: - buf.put(v ? "true" : "false"); + write(v ? "true" : "false"); break; case Tpointer: - buf.put("cast("); - buf.put(t.toString()); - buf.put(')'); + write("cast("); + write(t.toString()); + write(')'); if (target.ptrsize == 8) goto case Tuns64; else if (target.ptrsize == 4 || @@ -278,26 +293,26 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor assert(0); case Tvoid: - buf.put("cast(void)0"); + write("cast(void)0"); break; default: break; } } else if (v & 0x8000000000000000L) - buf.put(format("0x%llx", v)); + write(format("0x%u", v)); else - buf.put(format("%lu", v)); + write(format("%u", v)); } void visitError(ASTCodegen.ErrorExp _) { - buf.put("__error"); + write("__error"); } void visitVoidInit(ASTCodegen.VoidInitExp _) { - buf.put("void"); + write("void"); } void visitReal(ASTCodegen.RealExp e) @@ -310,85 +325,84 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor /* Print as: * (re+imi) */ - buf.put('('); + write('('); writeFloat(e.type, e.value.re); - buf.put('+'); + write('+'); writeFloat(e.type, e.value.im); - buf.put("i)"); + write("i)"); } void visitIdentifier(ASTCodegen.IdentifierExp e) { - /* writeln("writing ident"); */ - buf.put(e.ident.toString()); + write(e.ident.toString()); } void visitDsymbol(ASTCodegen.DsymbolExp e) { - buf.put(e.s.toString()); + write(e.s.toString()); } void visitThis(ASTCodegen.ThisExp _) { - buf.put("this"); + write("this"); } void visitSuper(ASTCodegen.SuperExp _) { - buf.put("super"); + write("super"); } void visitNull(ASTCodegen.NullExp _) { - buf.put("null"); + write("null"); } void visitString(ASTCodegen.StringExp e) { - buf.put('"'); + write('"'); foreach (i; 0 .. e.len) { - buf.put(e.getCodeUnit(i)); + write(e.getCodeUnit(i)); } - buf.put('"'); + write('"'); if (e.postfix) - buf.put(e.postfix); + write(e.postfix); } void visitArrayLiteral(ASTCodegen.ArrayLiteralExp e) { - buf.put('['); + write('['); writeArgs(e.elements, e.basis); - buf.put(']'); + write(']'); } void visitAssocArrayLiteral(ASTCodegen.AssocArrayLiteralExp e) { - buf.put('['); + write('['); foreach (i, key; *e.keys) { if (i) - buf.put(", "); + write(", "); writeExprWithPrecedence(key, PREC.assign); - buf.put(':'); + write(": "); auto value = (*e.values)[i]; writeExprWithPrecedence(value, PREC.assign); } - buf.put(']'); + write(']'); } void visitStructLiteral(ASTCodegen.StructLiteralExp e) { import dmd.expression; - buf.put(e.sd.toString()); - buf.put('('); + write(e.sd.toString()); + write('('); // CTFE can generate struct literals that contain an AddrExp pointing // to themselves, need to avoid infinite recursion: // struct S { this(int){ this.s = &this; } S* s; } // const foo = new S(0); if (e.stageflags & stageToCBuffer) - buf.put(""); + write(""); else { const old = e.stageflags; @@ -396,14 +410,14 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeArgs(e.elements); e.stageflags = old; } - buf.put(')'); + write(')'); } void visitCompoundLiteral(ASTCodegen.CompoundLiteralExp e) { - buf.put('('); + write('('); writeTypeWithIdent(e.type, null); - buf.put(')'); + write(')'); writeInitializer(e.initializer); } @@ -422,15 +436,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } else { - buf.put(e.sds.kind().toDString()); - buf.put(' '); - buf.put(e.sds.toString()); + write(e.sds.kind().toDString()); + write(' '); + write(e.sds.toString()); } } void visitTemplate(ASTCodegen.TemplateExp e) { - buf.put(e.td.toString()); + write(e.td.toString()); } void visitNew(ASTCodegen.NewExp e) @@ -438,15 +452,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (e.thisexp) { writeExprWithPrecedence(e.thisexp, PREC.primary); - buf.put('.'); + write('.'); } - buf.put("new "); + write("new "); writeTypeWithIdent(e.newtype, null); if (e.arguments && e.arguments.length) { - buf.put('('); + write('('); writeArgs(e.arguments, null, e.names); - buf.put(')'); + write(')'); } } @@ -455,15 +469,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (e.thisexp) { writeExprWithPrecedence(e.thisexp, PREC.primary); - buf.put('.'); + write('.'); } - buf.put("new"); - buf.put(" class "); + write("new"); + write(" class "); if (e.arguments && e.arguments.length) { - buf.put('('); + write('('); writeArgs(e.arguments); - buf.put(')'); + write(')'); } if (e.cd) e.cd.accept(this); @@ -472,44 +486,43 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitSymOff(ASTCodegen.SymOffExp e) { if (e.offset) - buf.put(format("(& %s%+lld)", e.var.toString(), e.offset)); + write(format("(& %s%+lld)", e.var.toString(), e.offset)); else if (e.var.isTypeInfoDeclaration()) - buf.put(e.var.toString()); + write(e.var.toString()); else - buf.put(format("& %s", e.var.toString())); + write(format("& %s", e.var.toString())); } void visitVar(ASTCodegen.VarExp e) { - buf.put(e.var.toString()); + write(e.var.toString()); } void visitOver(ASTCodegen.OverExp e) { - buf.put(e.vars.ident.toString()); + write(e.vars.ident.toString()); } void visitTuple(ASTCodegen.TupleExp e) { if (e.e0) { - buf.put('('); + write('('); writeExpr(e.e0); - buf.put(", AliasSeq!("); + write(", AliasSeq!("); writeArgs(e.exps); - buf.put("))"); + write("))"); } else { - buf.put("AliasSeq!("); + write("AliasSeq!("); writeArgs(e.exps); - buf.put(')'); + write(')'); } } void visitFunc(ASTCodegen.FuncExp e) { - /* writeln("stringifying func literal"); */ e.fd.accept(this); } @@ -527,12 +540,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // - Avoid printing newline. // - Intentionally use the format (Type var;) // which isn't correct as regular D code. - buf.put('('); + write('('); writeVarDecl(var, false); - buf.put(';'); - buf.put(')'); + write(';'); + write(')'); } else e.declaration.accept(this); @@ -541,59 +554,59 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitTypeid(ASTCodegen.TypeidExp e) { - buf.put("typeid("); + write("typeid("); writeObject(e.obj); - buf.put(')'); + write(')'); } void visitTraits(ASTCodegen.TraitsExp e) { - buf.put("__traits("); + write("__traits("); if (e.ident) - buf.put(e.ident.toString()); + write(e.ident.toString()); if (e.args) { foreach (arg; *e.args) { - buf.put(", "); + write(", "); writeObject(arg); } } - buf.put(')'); + write(')'); } void visitHalt(ASTCodegen.HaltExp _) { - buf.put("halt"); + write("halt"); } void visitIs(ASTCodegen.IsExp e) { - buf.put("is("); + write("is("); writeTypeWithIdent(e.targ, e.id); if (e.tok2 != TOK.reserved) { - buf.put(format(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2))); + write(format(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2))); } else if (e.tspec) { if (e.tok == TOK.colon) - buf.put(" : "); + write(" : "); else - buf.put(" == "); + write(" == "); writeTypeWithIdent(e.tspec, null); } if (e.parameters && e.parameters.length) { - buf.put(", "); + write(", "); visitTemplateParameters(e.parameters); } - buf.put(')'); + write(')'); } void visitUna(ASTCodegen.UnaExp e) { - buf.put(EXPtoString(e.op)); + write(EXPtoString(e.op)); writeExprWithPrecedence(e.e1, precedence[e.op]); } @@ -605,9 +618,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitBin(ASTCodegen.BinExp e) { writeExprWithPrecedence(e.e1, precedence[e.op]); - buf.put(' '); - buf.put(EXPtoString(e.op)); - buf.put(' '); + write(' '); + write(EXPtoString(e.op)); + write(' '); writeExprWithPrecedence(e.e2, cast(PREC)(precedence[e.op] + 1)); } @@ -660,33 +673,33 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitMixin(ASTCodegen.MixinExp e) { - buf.put("mixin("); + write("mixin("); writeArgs(e.exps); - buf.put(')'); + write(')'); } void visitImport(ASTCodegen.ImportExp e) { - buf.put("import("); + write("import("); writeExprWithPrecedence(e.e1, PREC.assign); - buf.put(')'); + write(')'); } void visitAssert(ASTCodegen.AssertExp e) { - buf.put("assert("); + write("assert("); writeExprWithPrecedence(e.e1, PREC.assign); if (e.msg) { - buf.put(", "); + write(", "); writeExprWithPrecedence(e.msg, PREC.assign); } - buf.put(')'); + write(')'); } void visitThrow(ASTCodegen.ThrowExp e) { - buf.put("throw "); + write("throw "); writeExprWithPrecedence(e.e1, PREC.unary); } @@ -694,54 +707,53 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { writeExprWithPrecedence(e.e1, PREC.primary); if (e.arrow) - buf.put("->"); + write("->"); else - buf.put('.'); - buf.put(e.ident.toString()); + write('.'); + write(e.ident.toString()); } void visitDotTemplate(ASTCodegen.DotTemplateExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('.'); - buf.put(e.td.toString()); + write('.'); + write(e.td.toString()); } void visitDotVar(ASTCodegen.DotVarExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('.'); - buf.put(e.var.toString()); + write('.'); + write(e.var.toString()); } void visitDotTemplateInstance(ASTCodegen.DotTemplateInstanceExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('.'); + write('.'); e.ti.accept(this); } void visitDelegate(ASTCodegen.DelegateExp e) { - buf.put('&'); + write('&'); if (!e.func.isNested() || e.func.needThis()) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('.'); + write('.'); } - buf.put(e.func.toString()); + write(e.func.toString()); } void visitDotType(ASTCodegen.DotTypeExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('.'); - buf.put(e.sym.toString()); + write('.'); + write(e.sym.toString()); } void visitCall(ASTCodegen.CallExp e) { - /* writeln("stringifying func call"); */ if (e.e1.op == EXP.type) { /* Avoid parens around type to prevent forbidden cast syntax: @@ -749,160 +761,157 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor * This is ok since types in constructor calls * can never depend on parens anyway */ - /* writeln("stringifying func e1 expr"); */ writeExpr(e.e1); } - else /* writeln("stringifying func e1 expr with precedence"); */ - writeExprWithPrecedence(e.e1, precedence[e.op]); - /* writeln("writing brace at indent level: ", depth); */ - buf.put('('); + writeExprWithPrecedence(e.e1, precedence[e.op]); + write('('); writeArgs(e.arguments, null, e.names); - buf.put(')'); + write(')'); } void visitPtr(ASTCodegen.PtrExp e) { - buf.put('*'); + write('*'); writeExprWithPrecedence(e.e1, precedence[e.op]); } void visitDelete(ASTCodegen.DeleteExp e) { - buf.put("delete "); + write("delete "); writeExprWithPrecedence(e.e1, precedence[e.op]); } void visitCast(ASTCodegen.CastExp e) { - buf.put("cast("); + write("cast("); if (e.to) writeTypeWithIdent(e.to, null); else { - buf.put(MODtoString(e.mod)); + write(MODtoString(e.mod)); } - buf.put(')'); + write(')'); writeExprWithPrecedence(e.e1, precedence[e.op]); } void visitVector(ASTCodegen.VectorExp e) { - buf.put("cast("); + write("cast("); writeTypeWithIdent(e.to, null); - buf.put(')'); + write(')'); writeExprWithPrecedence(e.e1, precedence[e.op]); } void visitVectorArray(ASTCodegen.VectorArrayExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put(".array"); + write(".array"); } void visitSlice(ASTCodegen.SliceExp e) { writeExprWithPrecedence(e.e1, precedence[e.op]); - buf.put('['); + write('['); if (e.upr || e.lwr) { if (e.lwr) writeSize(e.lwr); else - buf.put('0'); - buf.put(".."); + write('0'); + write(".."); if (e.upr) writeSize(e.upr); else - buf.put('$'); + write('$'); } - buf.put(']'); + write(']'); } void visitArrayLength(ASTCodegen.ArrayLengthExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put(".length"); + write(".length"); } void visitInterval(ASTCodegen.IntervalExp e) { writeExprWithPrecedence(e.lwr, PREC.assign); - buf.put(".."); + write(".."); writeExprWithPrecedence(e.upr, PREC.assign); } void visitDelegatePtr(ASTCodegen.DelegatePtrExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put(".ptr"); + write(".ptr"); } void visitDelegateFuncptr(ASTCodegen.DelegateFuncptrExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put(".funcptr"); + write(".funcptr"); } void visitArray(ASTCodegen.ArrayExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('['); + write('['); writeArgs(e.arguments); - buf.put(']'); + write(']'); } void visitDot(ASTCodegen.DotExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('.'); + write('.'); writeExprWithPrecedence(e.e2, PREC.primary); } void visitIndex(ASTCodegen.IndexExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put('['); + write('['); writeSize(e.e2); - buf.put(']'); + write(']'); } void visitPost(ASTCodegen.PostExp e) { writeExprWithPrecedence(e.e1, precedence[e.op]); - buf.put(EXPtoString(e.op)); + write(EXPtoString(e.op)); } void visitPre(ASTCodegen.PreExp e) { - buf.put(EXPtoString(e.op)); + write(EXPtoString(e.op)); writeExprWithPrecedence(e.e1, precedence[e.op]); } void visitRemove(ASTCodegen.RemoveExp e) { writeExprWithPrecedence(e.e1, PREC.primary); - buf.put(".remove("); + write(".remove("); writeExprWithPrecedence(e.e2, PREC.assign); - buf.put(')'); + write(')'); } void visitCond(ASTCodegen.CondExp e) { writeExprWithPrecedence(e.econd, PREC.oror); - buf.put(" ? "); + write(" ? "); writeExprWithPrecedence(e.e1, PREC.expr); - buf.put(" : "); + write(" : "); writeExprWithPrecedence(e.e2, PREC.cond); } void visitDefaultInit(ASTCodegen.DefaultInitExp e) { - buf.put(EXPtoString(e.op)); + write(EXPtoString(e.op)); } void visitClassReference(ASTCodegen.ClassReferenceExp e) { - buf.put(e.value.toString()); + write(e.value.toString()); } switch (e.op) @@ -1055,12 +1064,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor foreach (i, el; *expressions) { if (i) - buf.put(", "); + write(", "); if (names && i < names.length && (*names)[i]) { - buf.put((*names)[i].toString()); - buf.put(": "); + write((*names)[i].toString()); + write(": "); } if (!el) el = basis; @@ -1074,9 +1083,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // [0..length: basis, 1: e1, 5: e5] if (basis) { - buf.put("0.."); + write("0.."); buf.print(expressions.length); - buf.put(": "); + write(": "); writeExprWithPrecedence(basis, PREC.assign); } foreach (i, el; *expressions) @@ -1085,12 +1094,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (basis) { - buf.put(", "); - buf.put(i); - buf.put(": "); + write(", "); + write(i); + write(": "); } else if (i) - buf.put(", "); + write(", "); writeExprWithPrecedence(el, PREC.assign); } } @@ -1101,7 +1110,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (e.op == 0xFF) { - buf.put(""); + write(""); return; } assert(precedence[e.op] != PREC.zero); @@ -1112,9 +1121,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr) || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) { - buf.put('('); + write('('); writeExpr(e); - buf.put(')'); + write(')'); } else { @@ -1132,8 +1141,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeWithMask(t, modMask); if (ident) { - buf.put(' '); - buf.put(ident.toString()); + write(' '); + write(ident.toString()); } } @@ -1149,26 +1158,26 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor ubyte m = t.mod & ~(t.mod & modMask); if (m & MODFlags.shared_) { - buf.put(MODtoString(MODFlags.shared_)); - buf.put('('); + write(MODtoString(MODFlags.shared_)); + write('('); } if (m & MODFlags.wild) { - buf.put(MODtoString(MODFlags.wild)); - buf.put('('); + write(MODtoString(MODFlags.wild)); + write('('); } if (m & (MODFlags.const_ | MODFlags.immutable_)) { - buf.put(MODtoString(m & (MODFlags.const_ | MODFlags.immutable_))); - buf.put('('); + write(MODtoString(m & (MODFlags.const_ | MODFlags.immutable_))); + write('('); } writeType(t); if (m & (MODFlags.const_ | MODFlags.immutable_)) - buf.put(')'); + write(')'); if (m & MODFlags.wild) - buf.put(')'); + write(')'); if (m & MODFlags.shared_) - buf.put(')'); + write(')'); } } @@ -1181,23 +1190,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitError(ASTCodegen.ErrorStatement _) { - buf.put("__error__"); + write("__error__"); newline(); } void visitExp(ASTCodegen.ExpStatement s) { - /* writeln("visiting exp decl"); */ if (s.exp && s.exp.op == EXP.declaration && (cast(ASTCodegen.DeclarationExp) s.exp).declaration) { (cast(ASTCodegen.DeclarationExp) s.exp).declaration.accept(this); return; } - /* writeln("writing exp: ", s.exp.stringof); */ if (s.exp) writeExpr(s.exp); - buf.put(';'); + write(';'); newline(); } @@ -1208,9 +1215,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitMixin(ASTCodegen.MixinStatement s) { - buf.put("mixin("); + write("mixin("); writeArgs(s.exps); - buf.put(");"); + write(");"); } void visitCompound(ASTCodegen.CompoundStatement s) @@ -1247,12 +1254,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor anywritten = true; } } - buf.put(';'); + write(';'); } void visitUnrolledLoop(ASTCodegen.UnrolledLoopStatement s) { - buf.put("/*unrolled*/ {"); + write("/*unrolled*/ {"); newline(); depth++; foreach (sx; *s.statements) @@ -1261,25 +1268,25 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeStatement(sx); } depth--; - buf.put('}'); + write('}'); newline(); } void visitScope(ASTCodegen.ScopeStatement s) { - buf.put('{'); + write('{'); newline(); depth++; if (s.statement) writeStatement(s.statement); depth--; - buf.put('}'); + write('}'); newline(); } void visitWhile(ASTCodegen.WhileStatement s) { - buf.put("while ("); + write("while ("); if (auto p = s.param) { // Print condition assignment @@ -1290,11 +1297,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (p.type) writeTypeWithIdent(p.type, p.ident); else - buf.put(p.ident.toString()); - buf.put(" = "); + write(p.ident.toString()); + write(" = "); } writeExpr(s.condition); - buf.put(')'); + write(')'); newline(); if (s._body) writeStatement(s._body); @@ -1302,114 +1309,114 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDo(ASTCodegen.DoStatement s) { - buf.put("do"); + write("do"); newline(); if (s._body) writeStatement(s._body); - buf.put("while ("); + write("while ("); writeExpr(s.condition); - buf.put(");"); + write(");"); newline(); } void visitFor(ASTCodegen.ForStatement s) { - buf.put("for ("); + write("for ("); if (s._init) { writeStatement(s._init); } else - buf.put(';'); + write(';'); if (s.condition) { - buf.put(' '); + write(' '); writeExpr(s.condition); } - buf.put(';'); + write(';'); if (s.increment) { - buf.put(' '); + write(' '); writeExpr(s.increment); } - buf.put(')'); + write(')'); newline(); - buf.put('{'); + write('{'); newline(); depth++; if (s._body) writeStatement(s._body); depth--; - buf.put('}'); + write('}'); newline(); } void visitForeachWithoutBody(ASTCodegen.ForeachStatement s) { - buf.put(Token.toString(s.op)); - buf.put(" ("); + write(Token.toString(s.op)); + write(" ("); foreach (i, p; *s.parameters) { if (i) - buf.put(", "); + write(", "); writeStc(p.storageClass); if (p.type) writeTypeWithIdent(p.type, p.ident); else - buf.put(p.ident.toString()); + write(p.ident.toString()); } - buf.put("; "); + write("; "); writeExpr(s.aggr); - buf.put(')'); + write(')'); newline(); } void visitForeach(ASTCodegen.ForeachStatement s) { visitForeachWithoutBody(s); - buf.put('{'); + write('{'); newline(); depth++; if (s._body) writeStatement(s._body); depth--; - buf.put('}'); + write('}'); newline(); } void visitForeachRangeWithoutBody(ASTCodegen.ForeachRangeStatement s) { - buf.put(Token.toString(s.op)); - buf.put(" ("); + write(Token.toString(s.op)); + write(" ("); if (s.prm.type) writeTypeWithIdent(s.prm.type, s.prm.ident); else - buf.put(s.prm.ident.toString()); - buf.put("; "); + write(s.prm.ident.toString()); + write("; "); writeExpr(s.lwr); - buf.put(" .. "); + write(" .. "); writeExpr(s.upr); - buf.put(')'); + write(')'); newline(); } void visitForeachRange(ASTCodegen.ForeachRangeStatement s) { visitForeachRangeWithoutBody(s); - buf.put('{'); + write('{'); newline(); depth++; if (s._body) writeStatement(s._body); depth--; - buf.put('}'); + write('}'); newline(); } void visitStaticForeach(ASTCodegen.StaticForeachStatement s) { indent(); - buf.put("static "); + write("static "); if (s.sfe.aggrfe) { visitForeach(s.sfe.aggrfe); @@ -1428,7 +1435,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitIf(ASTCodegen.IfStatement s) { - buf.put("if ("); + write("if ("); if (Parameter p = s.prm) { StorageClass stc = p.storageClass; @@ -1438,11 +1445,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (p.type) writeTypeWithIdent(p.type, p.ident); else - buf.put(p.ident.toString()); - buf.put(" = "); + write(p.ident.toString()); + write(" = "); } writeExpr(s.condition); - buf.put(')'); + write(')'); newline(); if (s.ifbody.isScopeStatement()) { @@ -1456,14 +1463,14 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } if (s.elsebody) { - buf.put("else"); + write("else"); if (!s.elsebody.isIfStatement()) { newline(); } else { - buf.put(' '); + write(' '); } if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) { @@ -1482,52 +1489,52 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { s.condition.accept(this); newline(); - buf.put('{'); + write('{'); newline(); depth++; if (s.ifbody) writeStatement(s.ifbody); depth--; - buf.put('}'); + write('}'); newline(); if (s.elsebody) { - buf.put("else"); + write("else"); newline(); - buf.put('{'); + write('{'); depth++; newline(); writeStatement(s.elsebody); depth--; - buf.put('}'); + write('}'); } newline(); } void visitPragma(ASTCodegen.PragmaStatement s) { - buf.put("pragma ("); - buf.put(s.ident.toString()); + write("pragma ("); + write(s.ident.toString()); if (s.args && s.args.length) { - buf.put(", "); + write(", "); writeArgs(s.args); } - buf.put(')'); + write(')'); if (s._body) { newline(); - buf.put('{'); + write('{'); newline(); depth++; writeStatement(s._body); depth--; - buf.put('}'); + write('}'); newline(); } else { - buf.put(';'); + write(';'); newline(); } } @@ -1539,7 +1546,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitSwitch(ASTCodegen.SwitchStatement s) { - buf.put(s.isFinal ? "final switch (" : "switch ("); + write(s.isFinal ? "final switch (" : "switch ("); if (auto p = s.param) { // Print condition assignment @@ -1550,22 +1557,22 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (p.type) writeTypeWithIdent(p.type, p.ident); else - buf.put(p.ident.toString()); - buf.put(" = "); + write(p.ident.toString()); + write(" = "); } writeExpr(s.condition); - buf.put(')'); + write(')'); newline(); if (s._body) { if (!s._body.isScopeStatement()) { - buf.put('{'); + write('{'); newline(); depth++; writeStatement(s._body); depth--; - buf.put('}'); + write('}'); newline(); } else @@ -1577,109 +1584,103 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitCase(ASTCodegen.CaseStatement s) { - buf.put("case "); + write("case "); writeExpr(s.exp); - buf.put(':'); + write(':'); newline(); writeStatement(s.statement); } void visitCaseRange(ASTCodegen.CaseRangeStatement s) { - buf.put("case "); + write("case "); writeExpr(s.first); - buf.put(": .. case "); + write(": .. case "); writeExpr(s.last); - buf.put(':'); + write(':'); newline(); writeStatement(s.statement); } void visitDefault(ASTCodegen.DefaultStatement s) { - buf.put("default:"); + write("default:"); newline(); writeStatement(s.statement); } void visitGotoDefault(ASTCodegen.GotoDefaultStatement _) { - buf.put("goto default;"); + write("goto default;"); newline(); } void visitGotoCase(ASTCodegen.GotoCaseStatement s) { - buf.put("goto case"); + write("goto case"); if (s.exp) { - buf.put(' '); + write(' '); writeExpr(s.exp); } - buf.put(';'); - newline(); - } - - void visitSwitchError(ASTCodegen.SwitchErrorStatement _) - { - buf.put("SwitchErrorStatement::toCBuffer()"); + write(';'); newline(); } void visitReturn(ASTCodegen.ReturnStatement s) { - buf.put("return "); + write("return "); if (s.exp) writeExpr(s.exp); - buf.put(';'); + write(';'); newline(); } void visitBreak(ASTCodegen.BreakStatement s) { - buf.put("break"); + write("break"); if (s.ident) { - buf.put(' '); - buf.put(s.ident.toString()); + write(' '); + write(s.ident.toString()); } - buf.put(';'); + write(';'); newline(); } void visitContinue(ASTCodegen.ContinueStatement s) { - buf.put("continue"); + write("continue"); if (s.ident) { - buf.put(' '); - buf.put(s.ident.toString()); + write(' '); + write(s.ident.toString()); } - buf.put(';'); + write(';'); newline(); } void visitSynchronized(ASTCodegen.SynchronizedStatement s) { - buf.put("synchronized"); + write("synchronized"); if (s.exp) { - buf.put('('); + write('('); writeExpr(s.exp); - buf.put(')'); + write(')'); } if (s._body) { - buf.put(' '); + write(' '); writeStatement(s._body); } } void visitWith(ASTCodegen.WithStatement s) { - buf.put("with ("); + write("with ("); writeExpr(s.exp); - buf.put(")"); + write(")"); newline(); if (s._body) writeStatement(s._body); @@ -1687,7 +1688,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitTryCatch(ASTCodegen.TryCatchStatement s) { - buf.put("try"); + write("try"); newline(); if (s._body) { @@ -1704,37 +1705,37 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } foreach (c; *s.catches) { - buf.put("catch"); + write("catch"); if (c.type) { - buf.put('('); + write('('); writeTypeWithIdent(c.type, c.ident); - buf.put(')'); + write(')'); } newline(); - buf.put('{'); + write('{'); newline(); depth++; if (c.handler) writeStatement(c.handler); depth--; - buf.put('}'); + write('}'); newline(); } } void visitTryFinally(ASTCodegen.TryFinallyStatement s) { - buf.put("try"); + write("try"); newline(); - buf.put('{'); + write('{'); newline(); depth++; writeStatement(s._body); depth--; - buf.put('}'); + write('}'); newline(); - buf.put("finally"); + write("finally"); newline(); if (s.finalbody.isScopeStatement()) { @@ -1750,17 +1751,17 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitScopeGuard(ASTCodegen.ScopeGuardStatement s) { - buf.put(Token.toString(s.tok)); - buf.put(' '); + write(Token.toString(s.tok)); + write(' '); if (s.statement) writeStatement(s.statement); } void visitThrow(ASTCodegen.ThrowStatement s) { - buf.put("throw "); + write("throw "); writeExpr(s.exp); - buf.put(';'); + write(';'); newline(); } @@ -1774,16 +1775,16 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitGoto(ASTCodegen.GotoStatement s) { - buf.put("goto "); - buf.put(s.ident.toString()); - buf.put(';'); + write("goto "); + write(s.ident.toString()); + write(';'); newline(); } void visitLabel(ASTCodegen.LabelStatement s) { - buf.put(s.ident.toString()); - buf.put(':'); + write(s.ident.toString()); + write(':'); newline(); if (s.statement) writeStatement(s.statement); @@ -1791,12 +1792,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitAsm(ASTCodegen.AsmStatement s) { - buf.put("asm { "); + write("asm { "); Token* t = s.tokens; depth++; while (t) { - buf.put(Token.toString(t.value)); + write(Token.toString(t.value)); if (t.next && t.value != TOK.min && t.value != TOK.comma && t.next.value != TOK.comma && @@ -1806,12 +1807,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor t.next.value != TOK.rightParenthesis && t.value != TOK.dot && t.next.value != TOK.dot) { - buf.put(' '); + write(' '); } t = t.next; } depth--; - buf.put("; }"); + write("; }"); newline(); } @@ -1848,7 +1849,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor newline(); writeContracts(f); } - buf.put(';'); + write(';'); newline(); return; } @@ -1858,17 +1859,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (requireDo) { - buf.put("do"); + write("do"); newline(); } - buf.put('{'); + write('{'); newline(); depth++; - /* writeln("writing at depth ", depth); */ writeStatement(f.fbody); depth--; - /* writeln("finished writing, now depth ", depth); */ - buf.put('}'); + write('}'); newline(); } @@ -1881,13 +1880,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { foreach (frequire; *f.frequires) { - buf.put("in"); + write("in"); if (auto es = frequire.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); - buf.put(" ("); + write(" ("); writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); - buf.put(')'); + write(')'); newline(); requireDo = false; } @@ -1904,18 +1903,18 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { foreach (fensure; *f.fensures) { - buf.put("out"); + write("out"); if (auto es = fensure.ensure.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); - buf.put(" ("); + write(" ("); if (fensure.id) { - buf.put(fensure.id.toString()); + write(fensure.id.toString()); } - buf.put("; "); + write("; "); writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); - buf.put(')'); + write(')'); newline(); requireDo = false; } @@ -1923,9 +1922,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (fensure.id) { - buf.put('('); - buf.put(fensure.id.toString()); - buf.put(')'); + write('('); + write(fensure.id.toString()); + write(')'); } newline(); writeStatement(fensure.ensure); @@ -1940,49 +1939,49 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { void visitError(ErrorInitializer _) { - buf.put("__error__"); + write("__error__"); } void visitVoid(VoidInitializer _) { - buf.put("void"); + write("void"); } void visitStruct(StructInitializer si) { //printf("StructInitializer::toCBuffer()\n"); - buf.put('{'); + write('{'); foreach (i, const id; si.field) { if (i) - buf.put(", "); + write(", "); if (id) { - buf.put(id.toString()); - buf.put(':'); + write(id.toString()); + write(':'); } if (auto iz = si.value[i]) writeInitializer(iz); } - buf.put('}'); + write('}'); } void visitArray(ArrayInitializer ai) { - buf.put('['); + write('['); foreach (i, ex; ai.index) { if (i) - buf.put(", "); + write(", "); if (ex) { writeExpr(ex); - buf.put(':'); + write(':'); } if (auto iz = ai.value[i]) writeInitializer(iz); } - buf.put(']'); + write(']'); } void visitExp(ExpInitializer ei) @@ -1992,32 +1991,32 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitC(CInitializer ci) { - buf.put('{'); + write('{'); foreach (i, ref DesigInit di; ci.initializerList) { if (i) - buf.put(", "); + write(", "); if (di.designatorList) { foreach (ref Designator d; (*di.designatorList)[]) { if (d.exp) { - buf.put('['); + write('['); d.exp.accept(this); - buf.put(']'); + write(']'); } else { - buf.put('.'); - buf.put(d.ident.toString()); + write('.'); + write(d.ident.toString()); } } - buf.put('='); + write('='); } writeInitializer(di.initializer); } - buf.put('}'); + write('}'); } mixin VisitInitializer!void visit; @@ -2047,7 +2046,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor else if (ASTCodegen.Dsymbol s = isDsymbol(oarg)) { const p = s.ident ? s.ident.toString() : s.toString(); - buf.put(p); + write(p); } else if (auto v = isTuple(oarg)) { @@ -2055,7 +2054,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor foreach (i, arg; *args) { if (i) - buf.put(", "); + write(", "); writeObject(arg); } } @@ -2065,7 +2064,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } else if (!oarg) { - buf.put("NULL"); + write("NULL"); } else { @@ -2086,8 +2085,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (anywritten) { - buf.put(", "); - buf.put(v.ident.toString()); + write(", "); + write(v.ident.toString()); } else { @@ -2096,11 +2095,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (v.type) writeTypeWithIdent(v.type, v.ident); else - buf.put(v.ident.toString()); + write(v.ident.toString()); } if (v._init) { - buf.put(" = "); + write(" = "); vinit(v); } } @@ -2127,7 +2126,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor assert(0); if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) { - buf.put(format("%lu", uval)); + write(format("%lu", uval)); return; } } @@ -2149,8 +2148,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor */ if (t.mod) { - buf.put(MODtoString(t.mod)); - buf.put(' '); + write(MODtoString(t.mod)); + write(' '); } void ignoreReturn(string str) @@ -2162,8 +2161,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // don't write 'ref' for ctors if ((ident == Id.ctor) && str == "ref") return; - buf.put(str); - buf.put(' '); + write(str); + write(' '); } } @@ -2172,7 +2171,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (t.linkage > LINK.d) { writeLinkage(t.linkage); - buf.put(' '); + write(' '); } if (ident && ident.toHChars2() != ident.toChars()) { @@ -2182,25 +2181,25 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { writeTypeWithIdent(t.next, null); if (ident) - buf.put(' '); + write(' '); } if (ident) - buf.put(ident.toString()); + write(ident.toString()); if (td) { - buf.put('('); + write('('); foreach (i, p; *td.origParameters) { if (i) - buf.put(", "); + write(", "); p.accept(this); } - buf.put(')'); + write(')'); } writeParamList(t.parameterList); if (t.isreturn) { - buf.put(" return"); + write(" return"); } t.inuse--; } @@ -2216,30 +2215,30 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (t.linkage > LINK.d) { writeLinkage(t.linkage); - buf.put(' '); + write(' '); } if (t.linkage == LINK.objc && isStatic) - buf.put("static "); + write("static "); if (t.next) { writeTypeWithIdent(t.next, null); if (ident) - buf.put(' '); + write(' '); } if (ident) - buf.put(ident); + write(ident); writeParamList(t.parameterList); /* Use postfix style for attributes */ if (t.mod) { - buf.put(' '); - buf.put(MODtoString(t.mod)); + write(' '); + write(MODtoString(t.mod)); } void dg(string str) { - buf.put(' '); - buf.put(str); + write(' '); + write(str); } t.attributesApply(&dg); @@ -2256,12 +2255,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitError(TypeError _) { - buf.put("_error_"); + write("_error_"); } void visitBasic(TypeBasic t) { - buf.put(t.toString()); + write(t.toString()); } void visitTraits(TypeTraits t) @@ -2271,17 +2270,17 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitVector(TypeVector t) { - buf.put("__vector("); + write("__vector("); writeWithMask(t.basetype, t.mod); - buf.put(")"); + write(")"); } void visitSArray(TypeSArray t) { writeWithMask(t.next, t.mod); - buf.put('['); + write('['); writeSize(t.dim); - buf.put(']'); + write(']'); } void visitDArray(TypeDArray t) @@ -2290,25 +2289,25 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (declstring) goto L1; if (ut.equals(Type.tstring)) - buf.put("string"); + write("string"); else if (ut.equals(Type.twstring)) - buf.put("wstring"); + write("wstring"); else if (ut.equals(Type.tdstring)) - buf.put("dstring"); + write("dstring"); else { L1: writeWithMask(t.next, t.mod); - buf.put("[]"); + write("[]"); } } void visitAArray(TypeAArray t) { writeWithMask(t.next, t.mod); - buf.put('['); + write('['); writeWithMask(t.index, 0); - buf.put(']'); + write(']'); } void visitPointer(TypePointer t) @@ -2318,14 +2317,14 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor else { writeWithMask(t.next, t.mod); - buf.put('*'); + write('*'); } } void visitReference(TypeReference t) { writeWithMask(t.next, t.mod); - buf.put('&'); + write('&'); } void visitFunction(TypeFunction t) @@ -2345,30 +2344,30 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor switch (id.dyncast()) with (DYNCAST) { case dsymbol: - buf.put('.'); + write('.'); ASTCodegen.TemplateInstance ti = cast(ASTCodegen.TemplateInstance) id; ti.accept(this); break; case expression: - buf.put('['); + write('['); writeExpr(cast(ASTCodegen.Expression) id); - buf.put(']'); + write(']'); break; case type: - buf.put('['); + write('['); writeType(cast(Type) id); - buf.put(']'); + write(']'); break; default: - buf.put('.'); - buf.put(id.toString()); + write('.'); + write(id.toString()); } } } void visitIdentifier(TypeIdentifier t) { - buf.put(t.ident.toString()); + write(t.ident.toString()); visitTypeQualifiedHelper(t); } @@ -2380,21 +2379,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitTypeof(TypeTypeof t) { - buf.put("typeof("); + write("typeof("); writeExpr(t.exp); - buf.put(')'); + write(')'); visitTypeQualifiedHelper(t); } void visitReturn(TypeReturn t) { - buf.put("typeof(return)"); + write("typeof(return)"); visitTypeQualifiedHelper(t); } void visitEnum(TypeEnum t) { - buf.put(t.sym.toString()); + write(t.sym.toString()); } void visitStruct(TypeStruct t) @@ -2404,9 +2403,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // while printing messages. ASTCodegen.TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; if (ti && ti.aliasdecl == t.sym) - buf.put(ti.toString()); + write(ti.toString()); else - buf.put(t.sym.toString()); + write(t.sym.toString()); } void visitClass(TypeClass t) @@ -2416,22 +2415,22 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // while printing messages. ASTCodegen.TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; if (ti && ti.aliasdecl == t.sym) - buf.put(ti.toString()); + write(ti.toString()); else - buf.put(t.sym.toString()); + write(t.sym.toString()); } void visitTag(TypeTag t) { if (t.mod & MODFlags.const_) - buf.put("const "); - buf.put(Token.toString(t.tok)); - buf.put(' '); + write("const "); + write(Token.toString(t.tok)); + write(' '); if (t.id) - buf.put(t.id.toString()); + write(t.id.toString()); if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) { - buf.put(" : "); + write(" : "); writeWithMask(t.base, t.mod); } } @@ -2444,28 +2443,28 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitSlice(TypeSlice t) { writeWithMask(t.next, t.mod); - buf.put('['); + write('['); writeSize(t.lwr); - buf.put(" .. "); + write(" .. "); writeSize(t.upr); - buf.put(']'); + write(']'); } void visitNull(TypeNull _) { - buf.put("typeof(null)"); + write("typeof(null)"); } void visitMixin(TypeMixin t) { - buf.put("mixin("); + write("mixin("); writeArgs(t.exps); - buf.put(')'); + write(')'); } void visitNoreturn(TypeNoreturn _) { - buf.put("noreturn"); + write("noreturn"); } switch (t.ty) @@ -2528,9 +2527,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor const s = linkageToString(linkage); if (s.length) { - buf.put("extern ("); - buf.put(s); - buf.put(')'); + write("extern ("); + write(s); + write(')'); } } @@ -2538,30 +2537,30 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (p.userAttribDecl) { - buf.put('@'); + write('@'); bool isAnonymous = p.userAttribDecl.atts.length > 0 && !(*p.userAttribDecl.atts)[0].isCallExp(); if (isAnonymous) - buf.put('('); + write('('); writeArgs(p.userAttribDecl.atts); if (isAnonymous) - buf.put(')'); - buf.put(' '); + write(')'); + write(' '); } if (p.storageClass & STC.auto_) - buf.put("auto "); + write("auto "); StorageClass stc = p.storageClass; if (p.storageClass & STC.in_) { - buf.put("in "); + write("in "); } else if (p.storageClass & STC.lazy_) - buf.put("lazy "); + write("lazy "); else if (p.storageClass & STC.alias_) - buf.put("alias "); + write("alias "); if (p.type && p.type.mod & MODFlags.shared_) stc &= ~STC.shared_; @@ -2576,7 +2575,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (p.storageClass & STC.alias_) { if (p.ident) - buf.put(p.ident.toString()); + write(p.ident.toString()); } else if (p.type.ty == Tident && (cast(TypeIdentifier) p.type) @@ -2585,7 +2584,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor .ident.toChars(), "__T", 3) == 0) { // print parameter name, instead of undetermined type parameter - buf.put(p.ident.toString()); + write(p.ident.toString()); } else { @@ -2594,18 +2593,18 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (p.defaultArg) { - buf.put(" = "); + write(" = "); writeExprWithPrecedence(p.defaultArg, PREC.assign); } } void writeParamList(ParameterList pl) { - buf.put('('); + write('('); foreach (i; 0 .. pl.length) { if (i) - buf.put(", "); + write(", "); writeParam(pl[i]); } final switch (pl.varargs) @@ -2615,29 +2614,29 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case VarArg.variadic: if (pl.length) - buf.put(", "); + write(", "); writeStc(pl.stc); goto case VarArg.typesafe; case VarArg.typesafe: - buf.put("..."); + write("..."); break; case VarArg.KRvariadic: break; } - buf.put(')'); + write(')'); } void writeVisibility(ASTCodegen.Visibility vis) { - buf.put(visibilityToString(vis.kind)); + write(visibilityToString(vis.kind)); if (vis.kind == ASTCodegen.Visibility.Kind.package_ && vis.pkg) { - buf.put('('); - buf.put(vis.pkg.toPrettyChars(true).toDString()); - buf.put(')'); + write('('); + write(vis.pkg.toPrettyChars(true).toDString()); + write(')'); } } @@ -2659,15 +2658,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void writeTiArgs(ASTCodegen.TemplateInstance ti) { - buf.put('!'); + write('!'); if (ti.nest) { - buf.put("(...)"); + write("(...)"); return; } if (!ti.tiargs) { - buf.put("()"); + write("()"); return; } if (ti.tiargs.length == 1) @@ -2680,7 +2679,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if ((t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0) && ( (t.isTypeBasic() || t.ty == Tident) && (cast(TypeIdentifier) t).idents.length == 0)) { - buf.put(t.toString()); + write(t.toString()); return; } } @@ -2689,67 +2688,66 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP .this_) { - buf.put(e.toString()); + write(e.toString()); return; } } } - buf.put('('); + write('('); ti.nestUp(); foreach (i, arg; *ti.tiargs) { if (i) - buf.put(", "); + write(", "); writeObject(arg); } ti.nestDown(); - buf.put(')'); + write(')'); } /******************************************* * Visitors for AST nodes */ void visitDsymbol(ASTCodegen.Dsymbol s) { - /* writeln("visiting dsymbol"); */ - buf.put(s.toString()); + write(s.toString()); } void visitStaticAssert(ASTCodegen.StaticAssert s) { - buf.put(s.kind().toDString()); - buf.put('('); + write(s.kind().toDString()); + write('('); writeExpr(s.exp); if (s.msgs) { foreach (m; (*s.msgs)[]) { - buf.put(", "); + write(", "); writeExpr(m); } } - buf.put(");"); + write(");"); newline(); } void visitDebugSymbol(ASTCodegen.DebugSymbol s) { - buf.put("debug = "); + write("debug = "); if (s.ident) - buf.put(s.ident.toString()); + write(s.ident.toString()); else - buf.put(format("%d", s.level)); - buf.put(';'); + write(format("%d", s.level)); + write(';'); newline(); } void visitVersionSymbol(ASTCodegen.VersionSymbol s) { - buf.put("version = "); + write("version = "); if (s.ident) - buf.put(s.ident.toString()); + write(s.ident.toString()); else - buf.put(format("%d", s.level)); - buf.put(';'); + write(format("%d", s.level)); + write(';'); newline(); } @@ -2758,10 +2756,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (em.type) writeTypeWithIdent(em.type, em.ident); else - buf.put(em.ident.toString()); + write(em.ident.toString()); if (em.value) { - buf.put(" = "); + write(" = "); writeExpr(em.value); } } @@ -2769,47 +2767,47 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitImport(ASTCodegen.Import imp) { if (imp.isstatic) - buf.put("static "); - buf.put("import "); + write("static "); + write("import "); if (imp.aliasId) { - buf.put(imp.aliasId.toString()); - buf.put(" = "); + write(imp.aliasId.toString()); + write(" = "); } foreach (const pid; imp.packages) { - buf.put(pid.toString()); - buf.put("."); + write(pid.toString()); + write("."); } - buf.put(imp.id.toString()); + write(imp.id.toString()); if (imp.names.length) { - buf.put(" : "); + write(" : "); foreach (const i, const name; imp.names) { if (i) - buf.put(", "); + write(", "); const _alias = imp.aliases[i]; if (_alias) { - buf.put(_alias.toString()); - buf.put(" = "); - buf.put(name.toString()); + write(_alias.toString()); + write(" = "); + write(name.toString()); } else - buf.put(name.toString()); + write(name.toString()); } } - buf.put(';'); + write(';'); newline(); } void visitAliasThis(ASTCodegen.AliasThis d) { - buf.put("alias "); - buf.put(d.ident.toString()); - buf.put(" this;"); + write("alias "); + write(d.ident.toString()); + write(" this;"); newline(); } @@ -2822,13 +2820,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (!d.decl) { - buf.put(';'); + write(';'); newline(); return; } if (d.decl.length == 0) { - buf.put("{}"); + write("{}"); } else if (d.decl.length == 1) { @@ -2838,13 +2836,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor else { newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (de; *d.decl) de.accept(this); depth--; - buf.put('}'); + write('}'); } newline(); } @@ -2856,17 +2854,17 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDeprecatedDeclaration(ASTCodegen.DeprecatedDeclaration d) { - buf.put("deprecated("); + write("deprecated("); writeExpr(d.msg); - buf.put(") "); + write(") "); visitAttribDeclaration(d); } void visitLinkDeclaration(ASTCodegen.LinkDeclaration d) { - buf.put("extern ("); - buf.put(linkageToString(d.linkage)); - buf.put(") "); + write("extern ("); + write(linkageToString(d.linkage)); + write(") "); visitAttribDeclaration(d); } @@ -2884,9 +2882,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case CPPMANGLE.def: break; } - buf.put("extern (C++, "); - buf.put(s); - buf.put(") "); + write("extern (C++, "); + write(s); + write(") "); visitAttribDeclaration(d); } @@ -2895,7 +2893,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeVisibility(d.visibility); ASTCodegen.AttribDeclaration ad = cast(ASTCodegen.AttribDeclaration) d; if (ad.decl.length <= 1) - buf.put(' '); + write(' '); if (ad.decl.length == 1 && (*ad.decl)[0].isVisibilityDeclaration) visitAttribDeclaration((*ad.decl)[0].isVisibilityDeclaration); else @@ -2909,23 +2907,23 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor foreach (i, exp; (*d.exps)[]) { if (i) - buf.put(' '); - buf.put(format("align (%s)", exp.toString())); + write(' '); + write(format("align (%s)", exp.toString())); } if (d.decl && d.decl.length < 2) - buf.put(' '); + write(' '); } else - buf.put("align "); + write("align "); visitAttribDeclaration(d.isAttribDeclaration()); } void visitAnonDeclaration(ASTCodegen.AnonDeclaration d) { - buf.put(d.isunion ? "union" : "struct"); + write(d.isunion ? "union" : "struct"); newline(); - buf.put("{"); + write("{"); newline(); depth++; if (d.decl) @@ -2934,21 +2932,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor de.accept(this); } depth--; - buf.put("}"); + write("}"); newline(); } void visitPragmaDeclaration(ASTCodegen.PragmaDeclaration d) { - buf.put("pragma ("); - buf.put(d.ident.toString()); + write("pragma ("); + write(d.ident.toString()); if (d.args && d.args.length) { - buf.put(", "); + write(", "); writeArgs(d.args); } - buf.put(')'); + write(')'); visitAttribDeclaration(d); } @@ -2958,7 +2956,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (d.decl || d.elsedecl) { newline(); - buf.put('{'); + write('{'); newline(); depth++; if (d.decl) @@ -2967,23 +2965,23 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor de.accept(this); } depth--; - buf.put('}'); + write('}'); if (d.elsedecl) { newline(); - buf.put("else"); + write("else"); newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (de; *d.elsedecl) de.accept(this); depth--; - buf.put('}'); + write('}'); } } else - buf.put(':'); + write(':'); newline(); } @@ -2991,21 +2989,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { void foreachWithoutBody(ASTCodegen.ForeachStatement s) { - buf.put(Token.toString(s.op)); - buf.put(" ("); + write(Token.toString(s.op)); + write(" ("); foreach (i, p; *s.parameters) { if (i) - buf.put(", "); + write(", "); writeStc(p.storageClass); if (p.type) writeTypeWithIdent(p.type, p.ident); else - buf.put(p.ident.toString()); + write(p.ident.toString()); } - buf.put("; "); + write("; "); writeExpr(s.aggr); - buf.put(')'); + write(')'); newline(); } @@ -3013,21 +3011,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { /* s.op ( prm ; lwr .. upr ) */ - buf.put(Token.toString(s.op)); - buf.put(" ("); + write(Token.toString(s.op)); + write(" ("); if (s.prm.type) writeTypeWithIdent(s.prm.type, s.prm.ident); else - buf.put(s.prm.ident.toString()); - buf.put("; "); + write(s.prm.ident.toString()); + write("; "); writeExpr(s.lwr); - buf.put(" .. "); + write(" .. "); writeExpr(s.upr); - buf.put(')'); + write(')'); newline(); } - buf.put("static "); + write("static "); if (s.sfe.aggrfe) { foreachWithoutBody(s.sfe.aggrfe); @@ -3037,29 +3035,29 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor assert(s.sfe.rangefe); foreachRangeWithoutBody(s.sfe.rangefe); } - buf.put('{'); + write('{'); newline(); depth++; visitAttribDeclaration(s); depth--; - buf.put('}'); + write('}'); newline(); } void visitMixinDeclaration(ASTCodegen.MixinDeclaration d) { - buf.put("mixin("); + write("mixin("); writeArgs(d.exps); - buf.put(");"); + write(");"); newline(); } void visitUserAttributeDeclaration(ASTCodegen.UserAttributeDeclaration d) { - buf.put("@("); + write("@("); writeArgs(d.atts); - buf.put(')'); + write(')'); visitAttribDeclaration(d); } @@ -3067,9 +3065,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (!constraint) return; - buf.put(" if ("); + write(" if ("); writeExpr(constraint); - buf.put(')'); + write(')'); } override void visitBaseClasses(ASTCodegen.ClassDeclaration d) @@ -3077,11 +3075,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (!d || !d.baseclasses.length) return; if (!d.isAnonymous()) - buf.put(" : "); + write(" : "); foreach (i, b; *d.baseclasses) { if (i) - buf.put(", "); + write(", "); writeTypeWithIdent(b.type, null); } } @@ -3104,27 +3102,27 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } if (ASTCodegen.AggregateDeclaration ad = onemember.isAggregateDeclaration()) { - buf.put(ad.kind().toDString()); - buf.put(' '); - buf.put(ad.ident.toString()); - buf.put('('); + write(ad.kind().toDString()); + write(' '); + write(ad.ident.toString()); + write('('); visitTemplateParameters(d.parameters); - buf.put(')'); + write(')'); visitTemplateConstraint(d.constraint); visitBaseClasses(ad.isClassDeclaration()); if (ad.members) { newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (s; *ad.members) s.accept(this); depth--; - buf.put('}'); + write('}'); } else - buf.put(';'); + write(';'); newline(); return true; } @@ -3136,20 +3134,20 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (vd.type) writeTypeWithIdent(vd.type, vd.ident); else - buf.put(vd.ident.toString()); - buf.put('('); + write(vd.ident.toString()); + write('('); visitTemplateParameters(d.parameters); - buf.put(')'); + write(')'); if (vd._init) { - buf.put(" = "); + write(" = "); ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) writeExpr((cast(ASTCodegen.AssignExp) ie.exp).e2); else writeInitializer(vd._init); } - buf.put(';'); + write(';'); newline(); return true; } @@ -3158,55 +3156,55 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitTemplateDeclaration(ASTCodegen.TemplateDeclaration d) { - buf.put("template"); - buf.put(' '); - buf.put(d.ident.toString()); - buf.put('('); + write("template"); + write(' '); + write(d.ident.toString()); + write('('); visitTemplateParameters(d.parameters); - buf.put(')'); + write(')'); visitTemplateConstraint(d.constraint); } void visitTemplateInstance(ASTCodegen.TemplateInstance ti) { - buf.put(ti.name.toString()); + write(ti.name.toString()); writeTiArgs(ti); } void visitTemplateMixin(ASTCodegen.TemplateMixin tm) { - buf.put("mixin "); + write("mixin "); writeTypeWithIdent(tm.tqual, null); writeTiArgs(tm); if (tm.ident && tm.ident.toString() != "__mixin") { - buf.put(' '); - buf.put(tm.ident.toString()); + write(' '); + write(tm.ident.toString()); } - buf.put(';'); + write(';'); newline(); } void visitEnumDeclaration(ASTCodegen.EnumDeclaration d) { - buf.put("enum "); + write("enum "); if (d.ident) { - buf.put(d.ident.toString()); + write(d.ident.toString()); } if (d.memtype) { - buf.put(" : "); + write(" : "); writeTypeWithIdent(d.memtype, null); } if (!d.members) { - buf.put(';'); + write(';'); newline(); return; } newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (em; *d.members) @@ -3214,50 +3212,50 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (!em) continue; em.accept(this); - buf.put(','); + write(','); newline(); } depth--; - buf.put('}'); + write('}'); newline(); } void visitNspace(ASTCodegen.Nspace d) { - buf.put("extern (C++, "); - buf.put(d.ident.toString()); - buf.put(')'); + write("extern (C++, "); + write(d.ident.toString()); + write(')'); newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (s; *d.members) s.accept(this); depth--; - buf.put('}'); + write('}'); newline(); } void visitStructDeclaration(ASTCodegen.StructDeclaration d) { - buf.put(d.kind().toDString()); - buf.put(' '); + write(d.kind().toDString()); + write(' '); if (!d.isAnonymous()) - buf.put(d.toString()); + write(d.toString()); if (!d.members) { - buf.put(';'); + write(';'); newline(); return; } newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (s; *d.members) s.accept(this); depth--; - buf.put('}'); + write('}'); newline(); } @@ -3265,24 +3263,24 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (!d.isAnonymous()) { - buf.put(d.kind().toDString()); - buf.put(' '); - buf.put(d.ident.toString()); + write(d.kind().toDString()); + write(' '); + write(d.ident.toString()); } visitBaseClasses(d); if (d.members) { newline(); - buf.put('{'); + write('{'); newline(); depth++; foreach (s; *d.members) s.accept(this); depth--; - buf.put('}'); + write('}'); } else - buf.put(';'); + write(';'); newline(); } @@ -3290,11 +3288,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (d.storage_class & STC.local) return; - buf.put("alias "); + write("alias "); if (d.aliassym) { - buf.put(d.ident.toString()); - buf.put(" = "); + write(d.ident.toString()); + write(" = "); writeStc(d.storage_class); /* https://issues.dlang.org/show_bug.cgi?id=23223 @@ -3304,7 +3302,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor */ if (d.aliassym.isModule()) { - buf.put(d.aliassym.ident.toString()); + write(d.aliassym.ident.toString()); } else { @@ -3322,25 +3320,25 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id .dstring); - buf.put(d.ident.toString()); - buf.put(" = "); + write(d.ident.toString()); + write(" = "); writeStc(d.storage_class); writeTypeWithIdent(d.type, null); declstring = false; } - buf.put(';'); + write(';'); newline(); } void visitAliasAssign(ASTCodegen.AliasAssign d) { - buf.put(d.ident.toString()); - buf.put(" = "); + write(d.ident.toString()); + write(" = "); if (d.aliassym) d.aliassym.accept(this); else // d.type writeTypeWithIdent(d.type, null); - buf.put(';'); + write(';'); newline(); } @@ -3349,31 +3347,29 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (d.storage_class & STC.local) return; writeVarDecl(d, false); - buf.put(';'); + write(';'); newline(); } void visitFuncDeclaration(ASTCodegen.FuncDeclaration f) { - newline(); writeStc(f.storage_class); auto tf = cast(TypeFunction) f.type; writeTypeWithIdent(tf, f.ident); writeFuncBody(f); - /* writeln("Wrote body"); */ } void visitFuncLiteralDeclaration(ASTCodegen.FuncLiteralDeclaration f) { if (f.type.ty == Terror) { - buf.put("__error"); + write("__error"); return; } if (f.tok != TOK.reserved) { - buf.put(f.kind().toDString()); - buf.put(' '); + write(f.kind().toDString()); + write(' '); } TypeFunction tf = cast(TypeFunction) f.type; @@ -3384,8 +3380,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // https://issues.dlang.org/show_bug.cgi?id=20074 void printAttribute(string str) { - buf.put(' '); - buf.put(str); + write(' '); + write(str); } tf.attributesApply(&printAttribute); @@ -3396,7 +3392,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor ASTCodegen.ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null; if (rs && rs.exp) { - buf.put(" => "); + write(" => "); writeExpr(rs.exp); } else @@ -3408,14 +3404,14 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitPostBlitDeclaration(ASTCodegen.PostBlitDeclaration d) { writeStc(d.storage_class); - buf.put("this(this)"); + write("this(this)"); writeFuncBody(d); } void visitDtorDeclaration(ASTCodegen.DtorDeclaration d) { writeStc(d.storage_class); - buf.put("~this()"); + write("~this()"); writeFuncBody(d); } @@ -3423,8 +3419,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { writeStc(d.storage_class & ~STC.static_); if (d.isSharedStaticCtorDeclaration()) - buf.put("shared "); - buf.put("static this()"); + write("shared "); + write("static this()"); writeFuncBody(d); } @@ -3432,21 +3428,21 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { writeStc(d.storage_class & ~STC.static_); if (d.isSharedStaticDtorDeclaration()) - buf.put("shared "); - buf.put("static ~this()"); + write("shared "); + write("static ~this()"); writeFuncBody(d); } void visitInvariantDeclaration(ASTCodegen.InvariantDeclaration d) { writeStc(d.storage_class); - buf.put("invariant"); + write("invariant"); if (auto es = d.fbody.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); - buf.put(" ("); + write(" ("); writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); - buf.put(");"); + write(");"); newline(); } else @@ -3458,7 +3454,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitUnitTestDeclaration(ASTCodegen.UnitTestDeclaration d) { writeStc(d.storage_class); - buf.put("unittest"); + write("unittest"); writeFuncBody(d); } @@ -3467,16 +3463,16 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeStc(d.storage_class); Identifier id = d.isAnonymous() ? null : d.ident; writeTypeWithIdent(d.type, id); - buf.put(" : "); + write(" : "); writeExpr(d.width); - buf.put(';'); + write(';'); newline(); } void visitNewDeclaration(ASTCodegen.NewDeclaration d) { writeStc(d.storage_class & ~STC.static_); - buf.put("new();"); + write("new();"); } void visitModule(ASTCodegen.Module m) @@ -3485,25 +3481,26 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (m.userAttribDecl) { - buf.put("@("); + write("@("); writeArgs(m.userAttribDecl.atts); - buf.put(')'); + write(')'); newline(); } if (m.md.isdeprecated) { if (m.md.msg) { - buf.put("deprecated("); + write("deprecated("); writeExpr(m.md.msg); - buf.put(") "); + write(") "); } else - buf.put("deprecated "); + write("deprecated "); } - buf.put("module "); - buf.put(m.md.toString()); - buf.put(';'); + write("module "); + write(m.md.toString()); + write(';'); + newline(); newline(); } @@ -3515,67 +3512,67 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDebugCondition(ASTCodegen.DebugCondition c) { - buf.put("debug ("); + write("debug ("); if (c.ident) - buf.put(c.ident.toString()); + write(c.ident.toString()); else - buf.put(format("%d", c.level)); - buf.put(')'); + write(format("%d", c.level)); + write(')'); } void visitVersionCondition(ASTCodegen.VersionCondition c) { - buf.put("version ("); + write("version ("); if (c.ident) - buf.put(c.ident.toString()); + write(c.ident.toString()); else - buf.put(format("%d", c.level)); - buf.put(')'); + write(format("%d", c.level)); + write(')'); } void visitStaticIfCondition(ASTCodegen.StaticIfCondition c) { - buf.put("static if ("); + write("static if ("); writeExpr(c.exp); - buf.put(')'); + write(')'); } void visitTemplateTypeParameter(ASTCodegen.TemplateTypeParameter tp) { - buf.put(tp.ident.toString()); + write(tp.ident.toString()); if (tp.specType) { - buf.put(" : "); + write(" : "); writeTypeWithIdent(tp.specType, null); } if (tp.defaultType) { - buf.put(" = "); + write(" = "); writeTypeWithIdent(tp.defaultType, null); } } void visitTemplateThisParameter(ASTCodegen.TemplateThisParameter tp) { - buf.put("this "); + write("this "); visit(cast(ASTCodegen.TemplateTypeParameter) tp); } void visitTemplateAliasParameter(ASTCodegen.TemplateAliasParameter tp) { - buf.put("alias "); + write("alias "); if (tp.specType) writeTypeWithIdent(tp.specType, tp.ident); else - buf.put(tp.ident.toString()); + write(tp.ident.toString()); if (tp.specAlias) { - buf.put(" : "); + write(" : "); writeObject(tp.specAlias); } if (tp.defaultAlias) { - buf.put(" = "); + write(" = "); writeObject(tp.defaultAlias); } } @@ -3585,20 +3582,20 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeTypeWithIdent(tp.valType, tp.ident); if (tp.specValue) { - buf.put(" : "); + write(" : "); writeExpr(tp.specValue); } if (tp.defaultValue) { - buf.put(" = "); + write(" = "); writeExpr(tp.defaultValue); } } void visitTemplateTupleParameter(ASTCodegen.TemplateTupleParameter tp) { - buf.put(tp.ident.toString()); - buf.put("..."); + write(tp.ident.toString()); + write("..."); } override: From ded6e8d37baac3dd035519df84f433bff5c43ec2 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 9 Nov 2023 23:23:51 +0530 Subject: [PATCH 07/24] fix: iron out some bugs Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 119 ++++++++++++++++-------------- src/dfmt/globmatch_editorconfig.d | 2 +- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 80594ca..f45a4be 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -24,8 +24,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor const Config* config; string eol; uint depth; - bool declstring; // set while declaring alias for string,wstring or dstring - bool doindent; // insert indentation before writing the string + bool declString; // set while declaring alias for string,wstring or dstring + bool isNewline; // used to indent before writing the line + bool insideCase; // true if the node a child of a CaseStatement this(File.LockingTextWriter buf, Config* config) { @@ -74,15 +75,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { buf.put(eol); // Indicate that the next write should be indented - doindent = true; + isNewline = true; } extern (D) void write(T)(T data) { - if (doindent) + if (isNewline) { indent(); - doindent = false; + isNewline = false; } buf.put(data); } @@ -1079,8 +1080,6 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } else { - // Sparse style formatting, for debug use only - // [0..length: basis, 1: e1, 5: e5] if (basis) { write("0.."); @@ -1274,14 +1273,20 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitScope(ASTCodegen.ScopeStatement s) { - write('{'); - newline(); + if (!insideCase) + { + write('{'); + newline(); + } depth++; if (s.statement) writeStatement(s.statement); depth--; - write('}'); - newline(); + if (!insideCase) + { + write('}'); + newline(); + } } void visitWhile(ASTCodegen.WhileStatement s) @@ -1507,8 +1512,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeStatement(s.elsebody); depth--; write('}'); + newline(); } - newline(); } void visitPragma(ASTCodegen.PragmaStatement s) @@ -1588,7 +1593,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeExpr(s.exp); write(':'); newline(); + insideCase = true; writeStatement(s.statement); + insideCase = false; } void visitCaseRange(ASTCodegen.CaseRangeStatement s) @@ -1842,37 +1849,28 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void writeFuncBody(ASTCodegen.FuncDeclaration f) { - if (!f.fbody) - { - if (f.fensures || f.frequires) - { - newline(); - writeContracts(f); - } - write(';'); - newline(); - return; - } - newline(); - bool requireDo = writeContracts(f); - - if (requireDo) - { - write("do"); - newline(); - } + writeContracts(f); write('{'); newline(); depth++; - writeStatement(f.fbody); + if (f.fbody) + { + writeStatement(f.fbody); + } + else + { + write('{'); + newline(); + write('}'); + newline(); + } depth--; write('}'); newline(); } - // Returns: whether `do` is needed to write the function body - bool writeContracts(ASTCodegen.FuncDeclaration f) + void writeContracts(ASTCodegen.FuncDeclaration f) { bool requireDo = false; // in{} @@ -1932,7 +1930,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } } } - return requireDo; + + if (requireDo) + { + write("do"); + newline(); + } } void writeInitializer(Initializer inx) @@ -1949,7 +1952,6 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitStruct(StructInitializer si) { - //printf("StructInitializer::toCBuffer()\n"); write('{'); foreach (i, const id; si.field) { @@ -2286,7 +2288,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDArray(TypeDArray t) { Type ut = t.castMod(0); - if (declstring) + if (declString) goto L1; if (ut.equals(Type.tstring)) write("string"); @@ -2732,10 +2734,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDebugSymbol(ASTCodegen.DebugSymbol s) { write("debug = "); - if (s.ident) - write(s.ident.toString()); - else - write(format("%d", s.level)); + write(s.ident.toString()); write(';'); newline(); } @@ -2743,10 +2742,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitVersionSymbol(ASTCodegen.VersionSymbol s) { write("version = "); - if (s.ident) - write(s.ident.toString()); - else - write(format("%d", s.level)); + write(s.ident.toString()); write(';'); newline(); } @@ -2813,6 +2809,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor override void visitAttribDeclaration(ASTCodegen.AttribDeclaration d) { + if (isNewline) + { + newline(); + } if (auto stcd = d.isStorageClassDeclaration) { writeStc(stcd.stc); @@ -2824,6 +2824,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor newline(); return; } + if (d.decl.length == 0) { write("{}"); @@ -2890,6 +2891,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitVisibilityDeclaration(ASTCodegen.VisibilityDeclaration d) { + if (isNewline) + { + newline(); + } writeVisibility(d.visibility); ASTCodegen.AttribDeclaration ad = cast(ASTCodegen.AttribDeclaration) d; if (ad.decl.length <= 1) @@ -3318,13 +3323,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { import dmd.id : Id; - declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id + declString = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id .dstring); write(d.ident.toString()); write(" = "); writeStc(d.storage_class); writeTypeWithIdent(d.type, null); - declstring = false; + declString = false; } write(';'); newline(); @@ -3353,6 +3358,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitFuncDeclaration(ASTCodegen.FuncDeclaration f) { + if (isNewline) + { + newline(); + } writeStc(f.storage_class); auto tf = cast(TypeFunction) f.type; writeTypeWithIdent(tf, f.ident); @@ -3512,22 +3521,24 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDebugCondition(ASTCodegen.DebugCondition c) { - write("debug ("); + write("debug "); if (c.ident) + { + write('('); write(c.ident.toString()); - else - write(format("%d", c.level)); - write(')'); + write(')'); + } } void visitVersionCondition(ASTCodegen.VersionCondition c) { write("version ("); if (c.ident) + { + write('('); write(c.ident.toString()); - else - write(format("%d", c.level)); - write(')'); + write(')'); + } } void visitStaticIfCondition(ASTCodegen.StaticIfCondition c) diff --git a/src/dfmt/globmatch_editorconfig.d b/src/dfmt/globmatch_editorconfig.d index eff1b79..576915c 100644 --- a/src/dfmt/globmatch_editorconfig.d +++ b/src/dfmt/globmatch_editorconfig.d @@ -12,7 +12,7 @@ import std.path : filenameCharCmp, isDirSeparator; // * changes meaning to match all characters except '/' // ** added to take over the old meaning of * bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)( - Range path, const(C)[] pattern) @safe pure nothrow + Range path, const(C)[] pattern) @safe pure if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range))) in From 90c9040898b39e36cb4a8108751646eecf0cd25a Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 10 Nov 2023 17:12:58 +0530 Subject: [PATCH 08/24] feat: add 4 transformations - dfmt_space_before_function_parameters - dfmt_space_after_cast - dfmt_align_switch_statements - dfmt_space_before_aa_colon Signed-off-by: Prajwal S N --- README.md | 3 +-- src/dfmt/ast.d | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7bd2503..e7aa906 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ dfmt_align_switch_statements | **`true`**, `false` | Align labels, cases, and de dfmt_outdent_attributes (Not yet implemented) | **`true`**, `false`| Decrease the indentation level of attributes. dfmt_split_operator_at_line_end | `true`, **`false`** | Place operators on the end of the previous line when splitting lines. dfmt_space_after_cast | **`true`**, `false` | Insert space after the closing paren of a `cast` expression. -dfmt_space_after_keywords (Not yet implemented) | **`true`**, `false` | Insert space after `if`, `while`, `foreach`, etc, and before the `(`. +dfmt_space_after_keywords | **`true`**, `false` | Insert space after `if`, `while`, `foreach`, etc, and before the `(`. dfmt_space_before_function_parameters | `true`, **`false`** | Insert space before the opening paren of a function parameter list. dfmt_selective_import_space | **`true`**, `false` | Insert space after the module name and before the `:` for selective imports. dfmt_compact_labeled_statements | **`true`**, `false` | Place labels on the same line as the labeled `switch`, `for`, `foreach`, or `while` statement. @@ -124,7 +124,6 @@ dfmt_space_before_named_arg_colon | `true`, **`false`** | Adds a space after a n dfmt_keep_line_breaks | `true`, **`false`** | Keep existing line breaks if these don't violate other formatting rules. dfmt_single_indent | `true`, **`false`** | Set if the code in parens is indented by a single tab instead of two. dfmt_reflow_property_chains | **`true`**, `false` | Recalculate the splitting of property chains into multiple lines. -dfmt_space_after_keywords | **`true`**, `false` | Insert space after keywords (if,while,foreach,for, etc.). ## Terminology * Braces - `{` and `}` diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index f45a4be..f7a970f 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -385,6 +385,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (i) write(", "); writeExprWithPrecedence(key, PREC.assign); + if (config.dfmt_space_before_aa_colon == OptionalBoolean.t) + write(' '); write(": "); auto value = (*e.values)[i]; writeExprWithPrecedence(value, PREC.assign); @@ -792,6 +794,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(MODtoString(e.mod)); } write(')'); + if (config.dfmt_space_after_cast) + { + write(' '); + } writeExprWithPrecedence(e.e1, precedence[e.op]); } @@ -1589,6 +1595,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitCase(ASTCodegen.CaseStatement s) { + if (config.dfmt_align_switch_statements) + depth--; write("case "); writeExpr(s.exp); write(':'); @@ -1596,6 +1604,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor insideCase = true; writeStatement(s.statement); insideCase = false; + if (config.dfmt_align_switch_statements) + depth++; } void visitCaseRange(ASTCodegen.CaseRangeStatement s) @@ -1611,9 +1621,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDefault(ASTCodegen.DefaultStatement s) { + if (config.dfmt_align_switch_statements) + depth--; write("default:"); newline(); writeStatement(s.statement); + if (config.dfmt_align_switch_statements) + depth++; } void visitGotoDefault(ASTCodegen.GotoDefaultStatement _) @@ -1978,7 +1992,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (ex) { writeExpr(ex); - write(':'); + if (config.dfmt_space_before_aa_colon == OptionalBoolean.t) + write(' '); + write(": "); } if (auto iz = ai.value[i]) writeInitializer(iz); @@ -2602,6 +2618,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void writeParamList(ParameterList pl) { + if (config.dfmt_space_before_function_parameters) + write(' '); write('('); foreach (i; 0 .. pl.length) { From 62e47bb5d4cc543de97797403216fe7932008d58 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 23 Nov 2023 00:11:00 +0530 Subject: [PATCH 09/24] feat: add `dfmt_space_after_keywords` Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 91 ++++++++++++++++++++++++++++++++++++----------- src/dfmt/config.d | 4 +-- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index f7a970f..31884d5 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -1297,7 +1297,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitWhile(ASTCodegen.WhileStatement s) { - write("while ("); + write("while"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (auto p = s.param) { // Print condition assignment @@ -1324,7 +1327,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor newline(); if (s._body) writeStatement(s._body); - write("while ("); + write("while"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); writeExpr(s.condition); write(");"); newline(); @@ -1332,7 +1338,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitFor(ASTCodegen.ForStatement s) { - write("for ("); + write("for"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (s._init) { writeStatement(s._init); @@ -1365,7 +1374,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitForeachWithoutBody(ASTCodegen.ForeachStatement s) { write(Token.toString(s.op)); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); foreach (i, p; *s.parameters) { if (i) @@ -1398,7 +1409,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitForeachRangeWithoutBody(ASTCodegen.ForeachRangeStatement s) { write(Token.toString(s.op)); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (s.prm.type) writeTypeWithIdent(s.prm.type, s.prm.ident); else @@ -1446,7 +1459,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitIf(ASTCodegen.IfStatement s) { - write("if ("); + write("if"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (Parameter p = s.prm) { StorageClass stc = p.storageClass; @@ -1524,7 +1540,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitPragma(ASTCodegen.PragmaStatement s) { - write("pragma ("); + write("pragma"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); write(s.ident.toString()); if (s.args && s.args.length) { @@ -1557,7 +1576,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitSwitch(ASTCodegen.SwitchStatement s) { - write(s.isFinal ? "final switch (" : "switch ("); + write(s.isFinal ? "final switch" : "switch"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (auto p = s.param) { // Print condition assignment @@ -1699,7 +1721,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitWith(ASTCodegen.WithStatement s) { - write("with ("); + write("with"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); writeExpr(s.exp); write(")"); newline(); @@ -1896,7 +1921,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (auto es = frequire.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); write(')'); newline(); @@ -1919,7 +1946,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (auto es = fensure.ensure.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (fensure.id) { write(fensure.id.toString()); @@ -2545,7 +2574,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor const s = linkageToString(linkage); if (s.length) { - write("extern ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); write(s); write(')'); } @@ -2881,7 +2912,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitLinkDeclaration(ASTCodegen.LinkDeclaration d) { - write("extern ("); + write("extern"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); write(linkageToString(d.linkage)); write(") "); visitAttribDeclaration(d); @@ -2961,7 +2995,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitPragmaDeclaration(ASTCodegen.PragmaDeclaration d) { - write("pragma ("); + write("pragma"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); write(d.ident.toString()); if (d.args && d.args.length) { @@ -3013,7 +3050,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void foreachWithoutBody(ASTCodegen.ForeachStatement s) { write(Token.toString(s.op)); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); foreach (i, p; *s.parameters) { if (i) @@ -3035,7 +3074,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor /* s.op ( prm ; lwr .. upr ) */ write(Token.toString(s.op)); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); if (s.prm.type) writeTypeWithIdent(s.prm.type, s.prm.ident); else @@ -3088,7 +3129,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (!constraint) return; - write(" if ("); + write(" if"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); writeExpr(constraint); write(')'); } @@ -3467,7 +3511,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (auto es = d.fbody.isExpStatement()) { assert(es.exp && es.exp.op == EXP.assert_); - write(" ("); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); writeExpr((cast(ASTCodegen.AssertExp) es.exp).e1); write(");"); newline(); @@ -3550,9 +3596,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitVersionCondition(ASTCodegen.VersionCondition c) { - write("version ("); + write("version"); if (c.ident) { + if (config.dfmt_space_after_keywords) + write(' '); write('('); write(c.ident.toString()); write(')'); @@ -3561,7 +3609,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitStaticIfCondition(ASTCodegen.StaticIfCondition c) { - write("static if ("); + write("static if"); + if (config.dfmt_space_after_keywords) + write(' '); + write('('); writeExpr(c.exp); write(')'); } diff --git a/src/dfmt/config.d b/src/dfmt/config.d index 6b41d4a..5aa0d43 100644 --- a/src/dfmt/config.d +++ b/src/dfmt/config.d @@ -66,8 +66,6 @@ struct Config /// OptionalBoolean dfmt_reflow_property_chains; /// - OptionalBoolean dfmt_space_after_statement_keyword; - /// OptionalBoolean dfmt_space_before_named_arg_colon; mixin StandardEditorConfigFields; @@ -114,7 +112,7 @@ struct Config if (dfmt_soft_max_line_length > max_line_length) { stderr.writefln("Column hard limit (%d) must be greater than or equal to column soft limit (%d)", - max_line_length, dfmt_soft_max_line_length); + max_line_length, dfmt_soft_max_line_length); return false; } return true; From b4e36d998b80d07a0ca3fe6bdd4c6f2573bda291 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 23 Nov 2023 00:11:24 +0530 Subject: [PATCH 10/24] feat: add `dfmt_selective_import_space` Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 31884d5..ce7fe06 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -2827,7 +2827,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(imp.id.toString()); if (imp.names.length) { - write(" : "); + if (config.dfmt_selective_import_space) + write(' '); + write(": "); foreach (const i, const name; imp.names) { if (i) From 07bfe5c2086386de9fd272dc8ac4ba63c45b49af Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 1 Dec 2023 17:45:33 +0530 Subject: [PATCH 11/24] feat: add brace styles Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 173 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 139 insertions(+), 34 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index ce7fe06..1d530ae 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -26,7 +26,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor uint depth; bool declString; // set while declaring alias for string,wstring or dstring bool isNewline; // used to indent before writing the line - bool insideCase; // true if the node a child of a CaseStatement + bool insideCase; // true if the node is a child of a CaseStatement + bool insideIfOrDo; // true if the node is a child of an IfStatement or DoStatement this(File.LockingTextWriter buf, Config* config) { @@ -385,7 +386,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (i) write(", "); writeExprWithPrecedence(key, PREC.assign); - if (config.dfmt_space_before_aa_colon == OptionalBoolean.t) + if (config.dfmt_space_before_aa_colon) write(' '); write(": "); auto value = (*e.values)[i]; @@ -1281,7 +1282,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (!insideCase) { - write('{'); + if (config.dfmt_brace_style != BraceStyle.knr || s.statement.isCompoundStatement.statements.length != 1) + write('{'); newline(); } depth++; @@ -1290,8 +1292,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor depth--; if (!insideCase) { - write('}'); - newline(); + if (config.dfmt_brace_style != BraceStyle.knr || s.statement.isCompoundStatement.statements.length != 1) + { + write('}'); + if (!insideIfOrDo) + newline(); + } } } @@ -1324,9 +1330,27 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDo(ASTCodegen.DoStatement s) { write("do"); - newline(); - if (s._body) + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); + if (s._body.isScopeStatement) + { + insideIfOrDo = true; writeStatement(s._body); + insideIfOrDo = false; + } + else + { + depth++; + writeStatement(s._body); + depth--; + } + if (config.dfmt_brace_style == BraceStyle.otbs) + write(' '); + else if (config.dfmt_brace_style != BraceStyle.knr || s._body + .isScopeStatement.statement.isCompoundStatement.statements.length > 1) + newline(); write("while"); if (config.dfmt_space_after_keywords) write(' '); @@ -1360,7 +1384,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeExpr(s.increment); } write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -1390,7 +1417,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write("; "); writeExpr(s.aggr); write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); } void visitForeach(ASTCodegen.ForeachStatement s) @@ -1421,7 +1451,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(" .. "); writeExpr(s.upr); write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); } void visitForeachRange(ASTCodegen.ForeachRangeStatement s) @@ -1477,10 +1510,15 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } writeExpr(s.condition); write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); if (s.ifbody.isScopeStatement()) { + insideIfOrDo = true; writeStatement(s.ifbody); + insideIfOrDo = false; } else { @@ -1490,8 +1528,13 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } if (s.elsebody) { + if (config.dfmt_brace_style == BraceStyle.otbs) + write(' '); + else if (config.dfmt_brace_style != BraceStyle.knr || + s.ifbody.isScopeStatement.statement.isCompoundStatement.statements.length > 1) + newline(); write("else"); - if (!s.elsebody.isIfStatement()) + if (!s.elsebody.isIfStatement() && config.dfmt_brace_style == BraceStyle.allman) { newline(); } @@ -1510,12 +1553,19 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor depth--; } } + else + { + newline(); + } } void visitConditional(ASTCodegen.ConditionalStatement s) { s.condition.accept(this); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -1527,7 +1577,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (s.elsebody) { write("else"); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); depth++; newline(); @@ -1553,7 +1606,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(')'); if (s._body) { - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -1595,7 +1651,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } writeExpr(s.condition); write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); if (s._body) { if (!s._body.isScopeStatement()) @@ -1758,7 +1817,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeTypeWithIdent(c.type, c.ident); write(')'); } - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -1773,7 +1835,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitTryFinally(ASTCodegen.TryFinallyStatement s) { write("try"); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -1888,7 +1953,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void writeFuncBody(ASTCodegen.FuncDeclaration f) { - newline(); + if (config.dfmt_brace_style == BraceStyle.allman || config.dfmt_brace_style == BraceStyle + .knr) + newline(); + else + write(' '); writeContracts(f); write('{'); newline(); @@ -1977,7 +2046,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (requireDo) { write("do"); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman || config.dfmt_brace_style == BraceStyle + .knr) + newline(); + else + write(' '); } } @@ -2021,7 +2094,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (ex) { writeExpr(ex); - if (config.dfmt_space_before_aa_colon == OptionalBoolean.t) + if (config.dfmt_space_before_aa_colon) write(' '); write(": "); } @@ -2887,7 +2960,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } else { - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -2981,8 +3057,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitAnonDeclaration(ASTCodegen.AnonDeclaration d) { write(d.isunion ? "union" : "struct"); - newline(); - write("{"); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); + write('{'); newline(); depth++; if (d.decl) @@ -2991,7 +3070,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor de.accept(this); } depth--; - write("}"); + write('}'); newline(); } @@ -3017,7 +3096,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor d.condition.accept(this); if (d.decl || d.elsedecl) { - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3032,7 +3114,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { newline(); write("else"); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3088,7 +3173,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(" .. "); writeExpr(s.upr); write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); } write("static "); @@ -3181,7 +3269,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor visitBaseClasses(ad.isClassDeclaration()); if (ad.members) { - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3272,7 +3363,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor newline(); return; } - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3294,7 +3388,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write("extern (C++, "); write(d.ident.toString()); write(')'); - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3317,7 +3414,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor newline(); return; } - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3339,7 +3439,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor visitBaseClasses(d); if (d.members) { - newline(); + if (config.dfmt_brace_style == BraceStyle.allman) + newline(); + else + write(' '); write('{'); newline(); depth++; @@ -3587,9 +3690,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitDebugCondition(ASTCodegen.DebugCondition c) { - write("debug "); + write("debug"); if (c.ident) { + if (config.dfmt_space_after_keywords) + write(' '); write('('); write(c.ident.toString()); write(')'); From 14024a57252afdd7008646c5780421f22ee07bf8 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Wed, 13 Dec 2023 18:40:26 +0530 Subject: [PATCH 12/24] feat: add `dfmt_compact_labeled_statements` Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 5 ++++- src/dfmt/formatter.d | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 1d530ae..a2055d1 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -1896,7 +1896,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { write(s.ident.toString()); write(':'); - newline(); + if (config.dfmt_compact_labeled_statements) + write(' '); + else + newline(); if (s.statement) writeStatement(s.statement); } diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index d17ccfc..7081c03 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -33,9 +33,9 @@ bool format(string source_desc, ubyte[] buffer, File.LockingTextWriter output, Config* formatterConfig) { initDMD(); - auto module_ = parseModule(source_desc); + auto module_ = parseModule(source_desc)[0]; scope v = new FormatVisitor(output, formatterConfig); - v.visit(module_[0]); + v.visit(module_); return true; } From 0259887791a2f0982e416357e4780ba6c98f1a9f Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Wed, 13 Dec 2023 18:59:19 +0530 Subject: [PATCH 13/24] feat: add `dfmt_space_before_named_arg_colon` Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index a2055d1..7b3b150 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -1077,6 +1077,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (names && i < names.length && (*names)[i]) { write((*names)[i].toString()); + if (config.dfmt_space_before_named_arg_colon) + write(' '); write(": "); } if (!el) From 0897c83e86c1f21aa842f98eaf9e6a348b7426c4 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 14 Dec 2023 00:14:54 +0530 Subject: [PATCH 14/24] feat: non-conditional template constraints styles The non-conditional styles for `dfmt_template_constraint_style` are supported for now. The conditional ones will require line length tracking, which is yet to be implmented. Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 7b3b150..649973f 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -3224,12 +3224,38 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (!constraint) return; + + final switch (config.dfmt_template_constraint_style) + { + case TemplateConstraintStyle._unspecified: + // Fallthrough to the default case + case TemplateConstraintStyle.conditional_newline_indent: + // This will be updated later on + goto case; + case TemplateConstraintStyle.always_newline_indent: + newline(); + depth++; + break; + case TemplateConstraintStyle.conditional_newline: + // This will be updated later on + goto case; + case TemplateConstraintStyle.always_newline: + newline(); + break; + } + write(" if"); if (config.dfmt_space_after_keywords) write(' '); write('('); writeExpr(constraint); write(')'); + + if (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent || + // This condition will be updated later on + config.dfmt_template_constraint_style == TemplateConstraintStyle + .conditional_newline_indent) + depth--; } override void visitBaseClasses(ASTCodegen.ClassDeclaration d) From 3b80011673adda0183998b01217859a3645c1dcb Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 29 Dec 2023 13:22:59 +0530 Subject: [PATCH 15/24] chore: make it compile with latest DMD Some breaking changes in upstream borked the AST walker, it's been fixed in this commit. Signed-off-by: Prajwal S N --- dub.json | 2 +- src/dfmt/ast.d | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dub.json b/dub.json index 515d64d..c3bfe47 100644 --- a/dub.json +++ b/dub.json @@ -4,7 +4,7 @@ "targetType": "autodetect", "license": "BSL-1.0", "dependencies": { - "dmd": "~>2.106.0-beta.1" + "dmd": "~>2.107.0-beta.1" }, "targetPath": "bin/", "targetName": "dfmt", diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 649973f..aa2f9a2 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -2144,6 +2144,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write('}'); } + void visitDefault(DefaultInitializer di) + { + write("{ }"); + } + mixin VisitInitializer!void visit; visit.VisitInitializer(inx); } @@ -2164,8 +2169,6 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } else if (auto e = isExpression(oarg)) { - if (e.op == EXP.variable) - e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 writeExprWithPrecedence(e, PREC.assign); } else if (ASTCodegen.Dsymbol s = isDsymbol(oarg)) @@ -2236,7 +2239,6 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (e.type == Type.tsize_t) { ASTCodegen.Expression ex = (e.op == EXP.cast_ ? (cast(ASTCodegen.CastExp) e).e1 : e); - ex = ex.optimize(WANTvalue); const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; if (cast(long) uval >= 0) { From 16028a8f62436750857f2320617176cadfbb3d6a Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 29 Dec 2023 13:24:03 +0530 Subject: [PATCH 16/24] fix: store unit tests in AST Signed-off-by: Prajwal S N --- src/dfmt/formatter.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 7081c03..329407a 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -14,6 +14,7 @@ import dmd.astcodegen; import dmd.transitivevisitor; import dmd.permissivevisitor; import dmd.frontend; +import dmd.globals; import dfmt.ast; import dfmt.config; import std.array; @@ -33,6 +34,7 @@ bool format(string source_desc, ubyte[] buffer, File.LockingTextWriter output, Config* formatterConfig) { initDMD(); + global.params.useUnitTests = true; auto module_ = parseModule(source_desc)[0]; scope v = new FormatVisitor(output, formatterConfig); v.visit(module_); From 6e97ea81d1ec51b000e5f68142327cecc6e8e28e Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 29 Dec 2023 13:29:48 +0530 Subject: [PATCH 17/24] feat: track line length Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index aa2f9a2..13cfb3d 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -23,7 +23,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor File.LockingTextWriter buf; const Config* config; string eol; - uint depth; + uint depth; // the current indentation level + uint length; // the length of the current line of code bool declString; // set while declaring alias for string,wstring or dstring bool isNewline; // used to indent before writing the line bool insideCase; // true if the node is a child of a CaseStatement @@ -69,17 +70,20 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor auto indent = config.indent_style == IndentStyle.space ? ' '.repeat() .take(depth * 4) : '\t'.repeat().take(depth); buf.put(indent.array); + length += indent.length; } } void newline() { buf.put(eol); + length = 0; // Indicate that the next write should be indented isNewline = true; } - extern (D) void write(T)(T data) + void write(T)(T data) + if (is(T : char) || is(T : dchar)) { if (isNewline) { @@ -87,8 +91,22 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor isNewline = false; } buf.put(data); + length += 1; } + extern (D) void write(T)(T data) + if (!(is(T : char) || is(T : dchar))) + { + if (isNewline) + { + indent(); + isNewline = false; + } + buf.put(data); + length += data.length; + } + + /******************************************* * Helpers to write different AST nodes to buffer */ From 7f81285c1f38c916dae29e9ec0adf17e92e6f627 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 29 Dec 2023 14:06:43 +0530 Subject: [PATCH 18/24] feat: conditional template constraint style Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 13cfb3d..cd59e51 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -65,13 +65,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void indent() { - if (depth) - { - auto indent = config.indent_style == IndentStyle.space ? ' '.repeat() - .take(depth * 4) : '\t'.repeat().take(depth); - buf.put(indent.array); - length += indent.length; - } + if (!depth) + return; + auto indent = config.indent_style == IndentStyle.space ? ' '.repeat() + .take(depth * 4) : '\t'.repeat().take(depth); + buf.put(indent.array); + length += indent.length; } void newline() @@ -82,8 +81,17 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor isNewline = true; } - void write(T)(T data) - if (is(T : char) || is(T : dchar)) + void conditionalNewline(T)(T data) + { + // If the current length is crosses the soft limit OR + // if the current length + data length crosses the hard limit, + // insert a newline. + if (length > config.dfmt_soft_max_line_length + || (length + data.length) > config.max_line_length) + newline(); + } + + void write(T)(T data) if (is(T : char) || is(T : dchar)) { if (isNewline) { @@ -94,8 +102,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor length += 1; } - extern (D) void write(T)(T data) - if (!(is(T : char) || is(T : dchar))) + extern (D) void write(T)(T data) if (!(is(T : char) || is(T : dchar))) { if (isNewline) { @@ -106,7 +113,6 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor length += data.length; } - /******************************************* * Helpers to write different AST nodes to buffer */ @@ -3250,15 +3256,16 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case TemplateConstraintStyle._unspecified: // Fallthrough to the default case case TemplateConstraintStyle.conditional_newline_indent: - // This will be updated later on - goto case; + conditionalNewline(); + depth++; + break; case TemplateConstraintStyle.always_newline_indent: newline(); depth++; break; case TemplateConstraintStyle.conditional_newline: - // This will be updated later on - goto case; + conditionalNewline(); + break; case TemplateConstraintStyle.always_newline: newline(); break; @@ -3271,10 +3278,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeExpr(constraint); write(')'); - if (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent || - // This condition will be updated later on - config.dfmt_template_constraint_style == TemplateConstraintStyle - .conditional_newline_indent) + if (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent + || config.dfmt_template_constraint_style + == TemplateConstraintStyle.conditional_newline_indent) depth--; } From 3eb09287b2bee05c9c8b029a28883c95e994d9a7 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 29 Dec 2023 14:14:32 +0530 Subject: [PATCH 19/24] chore: run dfmt on all files _sigh_ should've done this at the beginning, but better late than never. Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 102 ++++++++++++++---------------- src/dfmt/config.d | 2 +- src/dfmt/editorconfig.d | 9 +-- src/dfmt/formatter.d | 2 +- src/dfmt/globmatch_editorconfig.d | 4 +- src/dfmt/main.d | 14 ++-- 6 files changed, 61 insertions(+), 72 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index cd59e51..a3b894f 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -160,8 +160,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(rrs); writeSpace = true; stc &= ~( - ASTCodegen.STC.out_ | ASTCodegen.STC.scope_ | ASTCodegen.STC.ref_ | ASTCodegen - .STC.return_); + ASTCodegen.STC.out_ | ASTCodegen.STC.scope_ + | ASTCodegen.STC.ref_ | ASTCodegen.STC.return_); break; } @@ -312,8 +312,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(')'); if (target.ptrsize == 8) goto case Tuns64; - else if (target.ptrsize == 4 || - target.ptrsize == 2) + else if (target.ptrsize == 4 || target.ptrsize == 2) goto case Tuns32; else assert(0); @@ -1084,10 +1083,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } } - void writeArgs( - ASTCodegen.Expressions* expressions, - ASTCodegen.Expression basis = null, - ASTCodegen.Identifiers* names = null) + void writeArgs(ASTCodegen.Expressions* expressions, + ASTCodegen.Expression basis = null, ASTCodegen.Identifiers* names = null) { if (!expressions || !expressions.length) return; @@ -1151,7 +1148,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor * They must be parenthesized. */ if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr) - || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) + || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) { write('('); writeExpr(e); @@ -1228,8 +1225,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitExp(ASTCodegen.ExpStatement s) { - if (s.exp && s.exp.op == EXP.declaration && - (cast(ASTCodegen.DeclarationExp) s.exp).declaration) + if (s.exp && s.exp.op == EXP.declaration + && (cast(ASTCodegen.DeclarationExp) s.exp).declaration) { (cast(ASTCodegen.DeclarationExp) s.exp).declaration.accept(this); return; @@ -1308,7 +1305,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (!insideCase) { - if (config.dfmt_brace_style != BraceStyle.knr || s.statement.isCompoundStatement.statements.length != 1) + if (config.dfmt_brace_style != BraceStyle.knr + || s.statement.isCompoundStatement.statements.length != 1) write('{'); newline(); } @@ -1318,7 +1316,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor depth--; if (!insideCase) { - if (config.dfmt_brace_style != BraceStyle.knr || s.statement.isCompoundStatement.statements.length != 1) + if (config.dfmt_brace_style != BraceStyle.knr + || s.statement.isCompoundStatement.statements.length != 1) { write('}'); if (!insideIfOrDo) @@ -1374,8 +1373,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } if (config.dfmt_brace_style == BraceStyle.otbs) write(' '); - else if (config.dfmt_brace_style != BraceStyle.knr || s._body - .isScopeStatement.statement.isCompoundStatement.statements.length > 1) + else if (config.dfmt_brace_style != BraceStyle.knr + || s._body.isScopeStatement.statement.isCompoundStatement.statements.length > 1) newline(); write("while"); if (config.dfmt_space_after_keywords) @@ -1556,8 +1555,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { if (config.dfmt_brace_style == BraceStyle.otbs) write(' '); - else if (config.dfmt_brace_style != BraceStyle.knr || - s.ifbody.isScopeStatement.statement.isCompoundStatement.statements.length > 1) + else if (config.dfmt_brace_style != BraceStyle.knr + || s.ifbody.isScopeStatement.statement.isCompoundStatement.statements.length + > 1) newline(); write("else"); if (!s.elsebody.isIfStatement() && config.dfmt_brace_style == BraceStyle.allman) @@ -1938,14 +1938,12 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor while (t) { write(Token.toString(t.value)); - if (t.next && - t.value != TOK.min && - t.value != TOK.comma && t.next.value != TOK.comma && - t.value != TOK.leftBracket && t.next.value != TOK.leftBracket && - t.next.value != TOK.rightBracket && - t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis && - t.next.value != TOK.rightParenthesis && - t.value != TOK.dot && t.next.value != TOK.dot) + if (t.next && t.value != TOK.min && t.value != TOK.comma + && t.next.value != TOK.comma && t.value != TOK.leftBracket + && t.next.value != TOK.leftBracket && t.next.value != TOK.rightBracket + && t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis + && t.next.value != TOK.rightParenthesis + && t.value != TOK.dot && t.next.value != TOK.dot) { write(' '); } @@ -1982,8 +1980,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void writeFuncBody(ASTCodegen.FuncDeclaration f) { - if (config.dfmt_brace_style == BraceStyle.allman || config.dfmt_brace_style == BraceStyle - .knr) + if (config.dfmt_brace_style == BraceStyle.allman || config.dfmt_brace_style + == BraceStyle.knr) newline(); else write(' '); @@ -2075,8 +2073,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (requireDo) { write("do"); - if (config.dfmt_brace_style == BraceStyle.allman || config.dfmt_brace_style == BraceStyle - .knr) + if (config.dfmt_brace_style == BraceStyle.allman + || config.dfmt_brace_style == BraceStyle.knr) newline(); else write(' '); @@ -2285,8 +2283,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor writeExprWithPrecedence(e, PREC.assign); } - void writeFuncIdentWithPrefix(TypeFunction t, const Identifier ident, ASTCodegen - .TemplateDeclaration td) + void writeFuncIdentWithPrefix(TypeFunction t, const Identifier ident, + ASTCodegen.TemplateDeclaration td) { if (t.inuse) { @@ -2621,8 +2619,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor switch (t.ty) { default: - return t.isTypeBasic() ? - visitBasic(cast(TypeBasic) t) : visitType(t); + return t.isTypeBasic() ? visitBasic(cast(TypeBasic) t) : visitType(t); case Terror: return visitError(cast(TypeError) t); @@ -2692,7 +2689,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { write('@'); - bool isAnonymous = p.userAttribDecl.atts.length > 0 && !(*p.userAttribDecl.atts)[0].isCallExp(); + bool isAnonymous = p.userAttribDecl.atts.length > 0 + && !(*p.userAttribDecl.atts)[0].isCallExp(); if (isAnonymous) write('('); @@ -2719,9 +2717,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor stc &= ~STC.shared_; writeStc(stc & ( - STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | - STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC - .returnScope)); + STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | STC.return_ + | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ + | STC.ref_ | STC.returnScope)); import core.stdc.string : strncmp; @@ -2730,10 +2728,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (p.ident) write(p.ident.toString()); } - else if (p.type.ty == Tident && - (cast(TypeIdentifier) p.type) - .ident.toString().length > 3 && - strncmp((cast(TypeIdentifier) p.type) + else if (p.type.ty == Tident && (cast(TypeIdentifier) p.type) + .ident.toString().length > 3 && strncmp((cast(TypeIdentifier) p.type) .ident.toChars(), "__T", 3) == 0) { // print parameter name, instead of undetermined type parameter @@ -2800,12 +2796,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor with (ASTCodegen.Visibility.Kind) { immutable string[7] a = [ - none: "none", - private_: "private", - package_: "package", - protected_: "protected", - public_: "public", - export_: "export" + none: "none", private_: "private", package_: "package", + protected_: "protected", public_: "public", export_: "export" ]; return a[kind]; } @@ -2831,8 +2823,9 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor RootObject oarg = (*ti.tiargs)[0]; if (Type t = isType(oarg)) { - if ((t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0) && ( - (t.isTypeBasic() || t.ty == Tident) && (cast(TypeIdentifier) t).idents.length == 0)) + if ((t.equals(Type.tstring) || t.equals(Type.twstring) + || t.equals(Type.tdstring) || t.mod == 0) && ((t.isTypeBasic() + || t.ty == Tident) && (cast(TypeIdentifier) t).idents.length == 0)) { write(t.toString()); return; @@ -2840,8 +2833,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor } else if (ASTCodegen.Expression e = isExpression(oarg)) { - if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP - .this_) + if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ + || e.op == EXP.string_ || e.op == EXP.this_) { write(e.toString()); return; @@ -3279,8 +3272,8 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor write(')'); if (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent - || config.dfmt_template_constraint_style - == TemplateConstraintStyle.conditional_newline_indent) + || config.dfmt_template_constraint_style + == TemplateConstraintStyle.conditional_newline_indent) depth--; } @@ -3547,8 +3540,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { import dmd.id : Id; - declString = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id - .dstring); + declString = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring); write(d.ident.toString()); write(" = "); writeStc(d.storage_class); diff --git a/src/dfmt/config.d b/src/dfmt/config.d index 5aa0d43..f8ba9cf 100644 --- a/src/dfmt/config.d +++ b/src/dfmt/config.d @@ -112,7 +112,7 @@ struct Config if (dfmt_soft_max_line_length > max_line_length) { stderr.writefln("Column hard limit (%d) must be greater than or equal to column soft limit (%d)", - max_line_length, dfmt_soft_max_line_length); + max_line_length, dfmt_soft_max_line_length); return false; } return true; diff --git a/src/dfmt/editorconfig.d b/src/dfmt/editorconfig.d index ce79f7c..b23ab7f 100644 --- a/src/dfmt/editorconfig.d +++ b/src/dfmt/editorconfig.d @@ -123,8 +123,7 @@ EC getConfigFor(EC)(string path) { import std.stdio : File; import std.regex : regex, match; - import std.path : globMatch, dirName, baseName, pathSplitter, buildPath, - absolutePath; + import std.path : globMatch, dirName, baseName, pathSplitter, buildPath, absolutePath; import std.algorithm : reverse, map, filter; import std.array : array; import std.file : isDir; @@ -141,7 +140,9 @@ EC getConfigFor(EC)(string path) EC[] sections = parseConfig!EC(buildPath(pathParts[0 .. i])); if (sections.length) configs ~= sections; - if (!sections.map!(a => a.root).filter!(a => a == OptionalBoolean.t).empty) + if (!sections.map!(a => a.root) + .filter!(a => a == OptionalBoolean.t) + .empty) break; } reverse(configs); @@ -208,7 +209,7 @@ private EC[] parseConfig(EC)(string dir) mixin(configDot) = propertyValue == "true" ? OptionalBoolean.t : OptionalBoolean.f; else - mixin(configDot) = to!(FieldType)(propertyValue); + mixin(configDot) = to!(FieldType)(propertyValue); } } } diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 329407a..1fc9ff1 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -31,7 +31,7 @@ import std.stdio : File; * Returns: `true` if the formatting succeeded, `false` if any error */ bool format(string source_desc, ubyte[] buffer, File.LockingTextWriter output, - Config* formatterConfig) + Config* formatterConfig) { initDMD(); global.params.useUnitTests = true; diff --git a/src/dfmt/globmatch_editorconfig.d b/src/dfmt/globmatch_editorconfig.d index 576915c..f1a2a67 100644 --- a/src/dfmt/globmatch_editorconfig.d +++ b/src/dfmt/globmatch_editorconfig.d @@ -3,7 +3,7 @@ module dfmt.globmatch_editorconfig; import std.path : CaseSensitive; import std.range : isForwardRange, ElementEncodingType; import std.traits : isSomeChar, isSomeString; -import std.range.primitives : empty, save, front, popFront; +import std.range.primitives : empty, save, front, popFront; import std.traits : Unqual; import std.conv : to; import std.path : filenameCharCmp, isDirSeparator; @@ -12,7 +12,7 @@ import std.path : filenameCharCmp, isDirSeparator; // * changes meaning to match all characters except '/' // ** added to take over the old meaning of * bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)( - Range path, const(C)[] pattern) @safe pure + Range path, const(C)[] pattern) @safe pure if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) && isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range))) in diff --git a/src/dfmt/main.d b/src/dfmt/main.d index 941e5d7..8a99175 100644 --- a/src/dfmt/main.d +++ b/src/dfmt/main.d @@ -55,8 +55,7 @@ int main(string[] args) import std.exception : enforce; enforce!GetOptException(value == "true" || value == "false", "Invalid argument"); - immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t - : OptionalBoolean.f; + immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t : OptionalBoolean.f; switch (option) { case "align_switch_statements": @@ -226,7 +225,7 @@ int main(string[] args) break; } immutable bool formatSuccess = format("stdin", buffer, - stdout.lockingTextWriter(), &config); + stdout.lockingTextWriter(), &config); return formatSuccess ? 0 : 1; } else @@ -327,12 +326,10 @@ Options: Formatting Options: --align_switch_statements - --brace_style `, optionsToString!(typeof(Config.dfmt_brace_style)), - ` + --brace_style `, optionsToString!(typeof(Config.dfmt_brace_style)), ` --end_of_line `, optionsToString!(typeof(Config.end_of_line)), ` --indent_size - --indent_style, -t `, - optionsToString!(typeof(Config.indent_style)), ` + --indent_style, -t `, optionsToString!(typeof(Config.indent_style)), ` --keep_line_breaks --soft_max_line_length --max_line_length @@ -349,8 +346,7 @@ Formatting Options: --space_before_named_arg_colon --single_indent --reflow_property_chains - `, - optionsToString!(typeof(Config.dfmt_template_constraint_style))); + `, optionsToString!(typeof(Config.dfmt_template_constraint_style))); } private string createFilePath(bool readFromStdin, string fileName) From 90bb91d2c670b05eb9290d9e8ad163f1f59c67b3 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Tue, 2 Jan 2024 14:47:20 +0530 Subject: [PATCH 20/24] fix: use temporary buffer for conditional newline Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 62 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index a3b894f..4152dfb 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -16,13 +16,15 @@ import dfmt.config; import dfmt.editorconfig; import std.range; import std.format : format; -import std.stdio : writeln, File; +import std.stdio : File; extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor { File.LockingTextWriter buf; const Config* config; string eol; + string tempBuf; // a string buffer to temporarily store data for line splitting + bool useTempBuf; // toggles the buffer being written to uint depth; // the current indentation level uint length; // the length of the current line of code bool declString; // set while declaring alias for string,wstring or dstring @@ -81,14 +83,24 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor isNewline = true; } - void conditionalNewline(T)(T data) + // Writes a newline only if the data will exceed the maximum allowed line length + bool conditionalNewline() { - // If the current length is crosses the soft limit OR + // If the current length crosses the soft limit OR // if the current length + data length crosses the hard limit, // insert a newline. if (length > config.dfmt_soft_max_line_length - || (length + data.length) > config.max_line_length) + || (length + tempBuf.length) > config.max_line_length) { newline(); + return true; + } + return false; + } + + void writeTempBuf() { + useTempBuf = false; + write(tempBuf); + tempBuf = ""; } void write(T)(T data) if (is(T : char) || is(T : dchar)) @@ -98,7 +110,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor indent(); isNewline = false; } - buf.put(data); + if (useTempBuf) + tempBuf ~= data; + else + buf.put(data); length += 1; } @@ -109,7 +124,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor indent(); isNewline = false; } - buf.put(data); + if (useTempBuf) + tempBuf ~= data; + else + buf.put(data); length += data.length; } @@ -232,8 +250,6 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitInteger(ASTCodegen.IntegerExp e) { - import core.stdc.stdio : sprintf; - auto v = e.toInteger(); if (e.type) { @@ -3241,6 +3257,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitTemplateConstraint(ASTCodegen.Expression constraint) { + if (!constraint) return; @@ -3249,7 +3266,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case TemplateConstraintStyle._unspecified: // Fallthrough to the default case case TemplateConstraintStyle.conditional_newline_indent: - conditionalNewline(); + useTempBuf = true; depth++; break; case TemplateConstraintStyle.always_newline_indent: @@ -3257,24 +3274,41 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor depth++; break; case TemplateConstraintStyle.conditional_newline: - conditionalNewline(); + useTempBuf = true; break; case TemplateConstraintStyle.always_newline: newline(); break; } - write(" if"); + write("if"); if (config.dfmt_space_after_keywords) write(' '); write('('); writeExpr(constraint); write(')'); - if (config.dfmt_template_constraint_style == TemplateConstraintStyle.always_newline_indent - || config.dfmt_template_constraint_style - == TemplateConstraintStyle.conditional_newline_indent) + final switch (config.dfmt_template_constraint_style) + { + case TemplateConstraintStyle._unspecified: + // Fallthrough to the default case + case TemplateConstraintStyle.conditional_newline_indent: + if (!conditionalNewline()) + buf.put(' '); + writeTempBuf(); depth--; + break; + case TemplateConstraintStyle.always_newline_indent: + depth--; + break; + case TemplateConstraintStyle.conditional_newline: + if (!conditionalNewline()) + buf.put(' '); + writeTempBuf(); + break; + case TemplateConstraintStyle.always_newline: + break; + } } override void visitBaseClasses(ASTCodegen.ClassDeclaration d) From 6ef9fba442120255f9fd64378405fa96708ff84c Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Thu, 4 Jan 2024 21:18:43 +0530 Subject: [PATCH 21/24] chore: revert changes to README Signed-off-by: Prajwal S N --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e7aa906..6c3d766 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ when using the **--inplace** option. ### Building from source using Make * Clone the repository -* Run `git submodule update --init --recursive` 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/`. +* Run ```git submodule update --init --recursive``` 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/```. ### Building from source using dub * Clone the repository @@ -69,8 +69,8 @@ dfmt --inplace --space_after_cast=false --max_line_length=80 \ ``` ## Disabling formatting -Formatting can be temporarily disabled by placing the comments `// dfmt off` -and `// dfmt on` around code that you do not want formatted. +Formatting can be temporarily disabled by placing the comments ```// dfmt off``` +and ```// dfmt on``` around code that you do not want formatted. ```d void main(string[] args) @@ -113,7 +113,7 @@ dfmt_align_switch_statements | **`true`**, `false` | Align labels, cases, and de dfmt_outdent_attributes (Not yet implemented) | **`true`**, `false`| Decrease the indentation level of attributes. dfmt_split_operator_at_line_end | `true`, **`false`** | Place operators on the end of the previous line when splitting lines. dfmt_space_after_cast | **`true`**, `false` | Insert space after the closing paren of a `cast` expression. -dfmt_space_after_keywords | **`true`**, `false` | Insert space after `if`, `while`, `foreach`, etc, and before the `(`. +dfmt_space_after_keywords (Not yet implemented) | **`true`**, `false` | Insert space after `if`, `while`, `foreach`, etc, and before the `(`. dfmt_space_before_function_parameters | `true`, **`false`** | Insert space before the opening paren of a function parameter list. dfmt_selective_import_space | **`true`**, `false` | Insert space after the module name and before the `:` for selective imports. dfmt_compact_labeled_statements | **`true`**, `false` | Place labels on the same line as the labeled `switch`, `for`, `foreach`, or `while` statement. @@ -124,6 +124,7 @@ dfmt_space_before_named_arg_colon | `true`, **`false`** | Adds a space after a n dfmt_keep_line_breaks | `true`, **`false`** | Keep existing line breaks if these don't violate other formatting rules. dfmt_single_indent | `true`, **`false`** | Set if the code in parens is indented by a single tab instead of two. dfmt_reflow_property_chains | **`true`**, `false` | Recalculate the splitting of property chains into multiple lines. +dfmt_space_after_keywords | **`true`**, `false` | Insert space after keywords (if,while,foreach,for, etc.). ## Terminology * Braces - `{` and `}` From 325f093091eae73a51ff3e306ddec0c5e72b01ad Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 12 Jan 2024 12:22:45 +0530 Subject: [PATCH 22/24] feat: add `dfmt_split_operator_at_line_end` Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 54 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 4152dfb..5b5b9d1 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -90,14 +90,16 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor // if the current length + data length crosses the hard limit, // insert a newline. if (length > config.dfmt_soft_max_line_length - || (length + tempBuf.length) > config.max_line_length) { + || (length + tempBuf.length) > config.max_line_length) + { newline(); return true; } return false; } - void writeTempBuf() { + void writeTempBuf() + { useTempBuf = false; write(tempBuf); tempBuf = ""; @@ -131,7 +133,7 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor length += data.length; } - /******************************************* + /*********************************************** * Helpers to write different AST nodes to buffer */ void writeStc(StorageClass stc) @@ -204,10 +206,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor import dmd.root.ctfloat; import core.stdc.string : strlen; - /** sizeof(value)*3 is because each byte of mantissa is max - of 256 (3 characters). The string will be "-M.MMMMe-4932". - (ie, 8 chars more than mantissa). Plus one for trailing \0. - Plus one for rounding. */ + /* sizeof(value)*3 is because each byte of mantissa is max + of 256 (3 characters). The string will be "-M.MMMMe-4932". + (ie, 8 chars more than mantissa). Plus one for trailing \0. + Plus one for rounding. */ const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; char[BUFFER_LEN] buffer = void; CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'g', value); @@ -658,12 +660,46 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor visit(cast(ASTCodegen.BinExp) e); } + static bool[EXP] operators = [ + EXP.lessThan: true, EXP.greaterThan: true, EXP.lessOrEqual: true, + EXP.greaterOrEqual: true, EXP.equal: true, EXP.notEqual: true, + EXP.identity: true, EXP.notIdentity: true, EXP.index: true, + EXP.is_: true, EXP.leftShift: true, EXP.rightShift: true, + EXP.leftShiftAssign: true, EXP.rightShiftAssign: true, + EXP.unsignedRightShift: true, EXP.unsignedRightShiftAssign: true, + EXP.concatenate: true, EXP.concatenateAssign: true, // ~= + EXP.concatenateElemAssign: true, + EXP.concatenateDcharAssign: true, EXP.add: true, EXP.min: true, + EXP.addAssign: true, EXP.minAssign: true, EXP.mul: true, EXP.div: true, + EXP.mod: true, EXP.mulAssign: true, EXP.divAssign: true, + EXP.modAssign: true, EXP.and: true, EXP.or: true, EXP.xor: true, + EXP.andAssign: true, EXP.orAssign: true, EXP.xorAssign: true, + EXP.assign: true, EXP.not: true, EXP.tilde: true, EXP.plusPlus: true, + EXP.minusMinus: true, EXP.construct: true, EXP.blit: true, + EXP.dot: true, EXP.comma: true, EXP.question: true, EXP.andAnd: true, + EXP.orOr: true, EXP.prePlusPlus: true, EXP.preMinusMinus: true, + ]; + void visitBin(ASTCodegen.BinExp e) { writeExprWithPrecedence(e.e1, precedence[e.op]); - write(' '); + if (!config.dfmt_split_operator_at_line_end && e.op in operators && conditionalNewline()) + { + // This block is left empty to ensure conditionalNewline() + // is called and not optimised away by the compiler while + // simplifying boolean expressions. + } + else + write(' '); write(EXPtoString(e.op)); - write(' '); + if (config.dfmt_split_operator_at_line_end && e.op in operators && conditionalNewline()) + { + // This block is left empty to ensure conditionalNewline() + // is called and not optimised away by the compiler while + // simplifying boolean expressions. + } + else + write(' '); writeExprWithPrecedence(e.e2, cast(PREC)(precedence[e.op] + 1)); } From 864caada43c4b5379401a1479d12caefa35d5116 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 12 Jan 2024 12:23:31 +0530 Subject: [PATCH 23/24] feat: add `dfmt_single_template_constraint_indent` Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 5b5b9d1..76964ab 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -3304,10 +3304,14 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor case TemplateConstraintStyle.conditional_newline_indent: useTempBuf = true; depth++; + if (config.dfmt_single_template_constraint_indent) + depth++; break; case TemplateConstraintStyle.always_newline_indent: newline(); depth++; + if (config.dfmt_single_template_constraint_indent) + depth++; break; case TemplateConstraintStyle.conditional_newline: useTempBuf = true; @@ -3332,10 +3336,11 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor if (!conditionalNewline()) buf.put(' '); writeTempBuf(); - depth--; - break; + goto case; case TemplateConstraintStyle.always_newline_indent: depth--; + if (config.dfmt_single_template_constraint_indent) + depth--; break; case TemplateConstraintStyle.conditional_newline: if (!conditionalNewline()) From b845d96ee29e783f6fbc12d3167ae8b81dfff419 Mon Sep 17 00:00:00 2001 From: Prajwal S N Date: Fri, 12 Jan 2024 13:00:39 +0530 Subject: [PATCH 24/24] fix: boolean logic for line split Signed-off-by: Prajwal S N --- src/dfmt/ast.d | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/dfmt/ast.d b/src/dfmt/ast.d index 76964ab..eef2c99 100644 --- a/src/dfmt/ast.d +++ b/src/dfmt/ast.d @@ -683,22 +683,10 @@ extern (C++) class FormatVisitor : SemanticTimeTransitiveVisitor void visitBin(ASTCodegen.BinExp e) { writeExprWithPrecedence(e.e1, precedence[e.op]); - if (!config.dfmt_split_operator_at_line_end && e.op in operators && conditionalNewline()) - { - // This block is left empty to ensure conditionalNewline() - // is called and not optimised away by the compiler while - // simplifying boolean expressions. - } - else + if (!(!config.dfmt_split_operator_at_line_end && e.op in operators && conditionalNewline())) write(' '); write(EXPtoString(e.op)); - if (config.dfmt_split_operator_at_line_end && e.op in operators && conditionalNewline()) - { - // This block is left empty to ensure conditionalNewline() - // is called and not optimised away by the compiler while - // simplifying boolean expressions. - } - else + if (!(config.dfmt_split_operator_at_line_end && e.op in operators && conditionalNewline())) write(' '); writeExprWithPrecedence(e.e2, cast(PREC)(precedence[e.op] + 1)); }