diff --git a/makefile b/makefile index b4fccf0..deede85 100644 --- a/makefile +++ b/makefile @@ -3,8 +3,9 @@ INCLUDE_PATHS := -Ilibdparse/src DMD_FLAGS := -g -w $(INCLUDE_PATHS) LDC_FLAGS := -g -w -oq $(INCLUDE_PATHS) -dmd: $(SRC) - dmd $(DMD_FLAGS) $(SRC) -ofbin/dfmt +.PHONY: dmd ldc test + +dmd: bin/dfmt ldc: $(SRC) ldc2 $(LDC_FLAGS) $(SRC) -ofbin/dfmt @@ -12,3 +13,7 @@ ldc: $(SRC) test: bin/dfmt cd tests && ./test.sh + +bin/dfmt: $(SRC) + dmd $(DMD_FLAGS) $(SRC) -ofbin/dfmt + diff --git a/src/dfmt.d b/src/dfmt.d index 71944ae..341c91e 100644 --- a/src/dfmt.d +++ b/src/dfmt.d @@ -115,8 +115,25 @@ private: assert (index < tokens.length); if (current.type == tok!"comment") { + const i = index; + if (i > 0) + { + if (tokens[i-1].line < tokens[i].line) + { + if (tokens[i-1].type != tok!"comment" + && tokens[i-1].type != tok!"{") + newline(); + } + else + write(" "); + } writeToken(); - newline(); + if (i >= tokens.length-1) + newline(); + else if (tokens[i+1].line > tokens[i].line) + newline(); + else if (tokens[i+1].type != tok!"{") + write(" "); } else if (isStringLiteral(current.type) || isNumberLiteral(current.type) || current.type == tok!"characterLiteral") @@ -141,6 +158,11 @@ private: formatStep(); } } + else if (current.type == tok!"return") + { + writeToken(); + write(" "); + } else if (current.type == tok!"switch") formatSwitch(); else if (current.type == tok!"for" || current.type == tok!"foreach" @@ -240,7 +262,8 @@ private: case tok!";": tempIndent = 0; writeToken(); - newline(); + if (current.type != tok!"comment") + newline(); break; case tok!"{": writeBraces(); @@ -378,7 +401,7 @@ private: newline(); write("}"); depth--; - if (index < tokens.length && + if (index < tokens.length-1 && assumeSorted(astInformation.doubleNewlineLocations) .equalRange(tokens[index].index).length) { diff --git a/tests/comments.d b/tests/comments.d new file mode 100644 index 0000000..80f5313 --- /dev/null +++ b/tests/comments.d @@ -0,0 +1,6 @@ +int /*sneaky*/ foo( /*comments*/ ) /*everywhere*/ { + // comment on its own line + foo() // comment on same line + .bar(); // also on same line + /* again */ // same line +} diff --git a/tests/comments.d.ref b/tests/comments.d.ref new file mode 100644 index 0000000..3b0fb36 --- /dev/null +++ b/tests/comments.d.ref @@ -0,0 +1,7 @@ +int /*sneaky*/ foo( /*comments*/ ) /*everywhere*/ +{ + // comment on its own line + foo() // comment on same line + .bar(); // also on same line + /* again */ // same line +} diff --git a/tests/frontpage.d.ref b/tests/frontpage.d.ref index 654056d..640ab33 100644 --- a/tests/frontpage.d.ref +++ b/tests/frontpage.d.ref @@ -12,4 +12,3 @@ void main() } writeln("Average line length: ", lines ? sumLength / lines:0); } - diff --git a/tests/guessnumber.d b/tests/guessnumber.d new file mode 100644 index 0000000..45b470a --- /dev/null +++ b/tests/guessnumber.d @@ -0,0 +1,31 @@ +import std.stdio, std.random, std.typecons, std.conv, std.string, + std.range; + +void main() { + immutable interval = tuple(1, 100); + writefln("Guess my target number that is between " ~ + "%d and %d (inclusive).\n", interval[]); + immutable target = uniform!"[]"(interval[]); + + foreach (immutable i; sequence!q{n}) { + writef("Your guess #%d: ", i + 1); + immutable txt = stdin.readln.strip; + + Nullable!int answer; + try { + answer = txt.to!int; + } catch (ConvException e) { + writefln(" I don't understand your input '%s'", txt); + continue; + } + if (answer < interval[0] || answer > interval[1]) { + writeln(" Out of range!"); + continue; + } + if (answer == target) { + writeln(" Well guessed."); + break; + } + writeln(answer < target ? " Too low." : " Too high."); + } +} diff --git a/tests/guessnumber.d.ref b/tests/guessnumber.d.ref new file mode 100644 index 0000000..9ff51c1 --- /dev/null +++ b/tests/guessnumber.d.ref @@ -0,0 +1,36 @@ +import std.stdio, std.random, std.typecons, std.conv, std.string, std.range; + +void main() +{ + immutable interval = tuple(1, 100); + writefln("Guess my target number that is between " + ~ "%d and %d (inclusive).\n", + interval[]); + immutable target = uniform!"[]"(interval[]); + foreach (immutable i; sequence!q{n}) + { + writef("Your guess #%d: ", i + 1); + immutable txt = stdin.readln.strip; + Nullable!int answer; + try + { + answer = txt.to!int; + } + catch(ConvException e) + { + writefln(" I don't understand your input '%s'", txt); + continue; + } + if (answer < interval[0] || answer > interval[1]) + { + writeln(" Out of range!"); + continue; + } + if (answer == target) + { + writeln(" Well guessed."); + break; + } + writeln(answer < target ? " Too low.":" Too high."); + } +} diff --git a/tests/hello.d.ref b/tests/hello.d.ref index 3894114..0beb9aa 100644 --- a/tests/hello.d.ref +++ b/tests/hello.d.ref @@ -4,4 +4,3 @@ void main() { writeln("Hello, world without explicit compilations!"); } - diff --git a/tests/heronian.d b/tests/heronian.d new file mode 100644 index 0000000..ffe6334 --- /dev/null +++ b/tests/heronian.d @@ -0,0 +1,45 @@ +import std.stdio, std.math, std.range, std.algorithm, std.numeric, std.traits, std.typecons; + +double hero(in uint a, in uint b, in uint c) pure nothrow @safe @nogc { + immutable s = (a + b + c) / 2.0; + immutable a2 = s * (s - a) * (s - b) * (s - c); + return (a2 > 0) ? a2.sqrt : 0.0; +} + +bool isHeronian(in uint a, in uint b, in uint c) pure nothrow @safe @nogc { + immutable h = hero(a, b, c); + return h > 0 && h.floor == h.ceil; +} + +T gcd3(T)(in T x, in T y, in T z) pure nothrow @safe @nogc { + return gcd(gcd(x, y), z); +} + +void main() /*@safe*/ { + enum uint maxSide = 200; + + // Sort by increasing area, perimeter, then sides. + //auto h = cartesianProduct!3(iota(1, maxSide + 1)) + auto r = iota(1, maxSide + 1); + const h = cartesianProduct(r, r, r) + //.filter!({a, b, c} => ... + .filter!(t => t[0] <= t[1] && t[1] <= t[2] && + t[0] + t[1] > t[2] && + t[].gcd3 == 1 && t[].isHeronian) + .array + .schwartzSort!(t => tuple(t[].hero, t[].only.sum, t.reverse)) + .release; + + static void showTriangles(R)(R ts) @safe { + "Area Perimeter Sides".writeln; + foreach (immutable t; ts) + writefln("%3s %8d %3dx%dx%d", t[].hero, t[].only.sum, t[]); + } + + writefln("Primitive Heronian triangles with sides up to %d: %d", maxSide, h.length); + "\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:".writeln; + showTriangles(h.take(10)); + + "\nAll with area 210 subject to the previous ordering:".writeln; + showTriangles(h.filter!(t => t[].hero == 210)); +} diff --git a/tests/heronian.d.ref b/tests/heronian.d.ref new file mode 100644 index 0000000..f7334ff --- /dev/null +++ b/tests/heronian.d.ref @@ -0,0 +1,48 @@ +import std.stdio, std.math, std.range, std.algorithm, std.numeric, std.traits, + std.typecons; + +double hero(in uint a, in uint b, in uint c) pure nothrow @safe@nogc +{ + immutable s = (a + b + c) / 2.0; + immutable a2 = s * (s - a) * (s - b) * (s - c); + return (a2 > 0) ? a2.sqrt : 0.0; +} + +bool isHeronian(in uint a, in uint b, in uint c) pure nothrow @safe @nogc +{ + immutable h = hero(a, b, c); + return h > 0 && h.floor == h.ceil; +} + +T gcd3(T)(in T x, in T y, in T z) pure nothrow @safe @nogc +{ + return gcd(gcd(x, y), z); +} + +void main() /*@safe*/ +{ + enum uint maxSide = 200; + // Sort by increasing area, perimeter, then sides. + //auto h = cartesianProduct!3(iota(1, maxSide + 1)) + auto r = iota(1, maxSide + 1); + const h = cartesianProduct(r, r, r) + //.filter!({a, b, c} => ... + .filter!(t => t[0] <= t[1] && t[1] <= t[2] && t[0] + t[1] > t[2] && + t[].gcd3 == 1 && t[].isHeronian) + .array.schwartzSort!(t => tuple(t[].hero, t[].only.sum, t.reverse)) + .release; + + static void showTriangles(R)(R ts) @safe + { + "Area Perimeter Sides".writeln; + foreach (immutable t; ts) + writefln("%3s %8d %3dx%dx%d", t[].hero, t[].only.sum, t[]); + } + + writefln("Primitive Heronian triangles with sides up to %d: %d", maxSide, + h.length); + "\nFirst ten when ordered by increasing area, then perimeter,then maximum sides:".writeln; + showTriangles(h.take(10)); + "\nAll with area 210 subject to the previous ordering:".writeln; + showTriangles(h.filter!(t => t[].hero == 210)); +} diff --git a/tests/higherorder.d b/tests/higherorder.d new file mode 100644 index 0000000..56d2c35 --- /dev/null +++ b/tests/higherorder.d @@ -0,0 +1,9 @@ +int hof(int a, int b, int delegate(int, int) f) { + return f(a, b); +} + +void main() { + import std.stdio; + writeln("Add: ", hof(2, 3, (a, b) => a + b)); + writeln("Multiply: ", hof(2, 3, (a, b) => a * b)); +} diff --git a/tests/higherorder.d.ref b/tests/higherorder.d.ref new file mode 100644 index 0000000..be9b953 --- /dev/null +++ b/tests/higherorder.d.ref @@ -0,0 +1,12 @@ +int hof(int a, int b, int delegate(int, int) f) +{ + return f(a, b); +} + +void main() +{ + import std.stdio; + + writeln("Add: ", hof(2, 3, (a, b) => a + b)); + writeln("Multiply: ", hof(2, 3, (a, b) => a * b)); +}