Skip to content

Commit

Permalink
rdmd: --loop and --eval with a last statement without effect shou…
Browse files Browse the repository at this point in the history
…ld print it
  • Loading branch information
wilzbach committed Feb 13, 2018
1 parent 8df8eb7 commit b988788
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 15 deletions.
47 changes: 47 additions & 0 deletions changelog/rdmd-writeln.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
In rdmd `--eval` and `--loop` the last statement without effect will be printed

`--eval` and `--loop` are two convenience features of `rdmd` that allow quick experimentation with D code.
However, until

$(CONSOLE
rdmd --eval='"hello"'
/tmp/.rdmd-1000/eval.CFD785092747553A81673B51A318D6AE.d(18): $(RED Error): "hello" has no effect
)

The new behavior will default to writeln if the last statement would have no effect:

$(CONSOLE
rdmd --eval="hello"
hello
)

A few more examples of `rdmd` in action:

$(H4 Use `rdmd` as your calculator)

$(CONSOLE
rdmd --eval="2 + 2"
4
)

$(CONSOLE
rdmd --eval="2.pow(4)"
16
)

$(H4 Select the first column in a CSV file)

$(CONSOLE
rdmd --loop='line.splitter(",").take(1)'
16
)

$(H4 Use `rdmd` as drop-in for Unix tools)

$(CONSOLE
seq 5 | rdmd --loop='stdin.byLine.drop(2).joiner(newline)'
2
3
4
5
)
19 changes: 18 additions & 1 deletion rdmd.d
Original file line number Diff line number Diff line change
Expand Up @@ -828,11 +828,20 @@ Returns:
*/
string innerEvalCode(string[] eval)
{
import std.conv : text;
import std.string : join, stripRight;
// assumeSafeAppend just to avoid unnecessary reallocation
string code = eval.join("\n").stripRight.assumeSafeAppend;
auto lastSemicolon = code.lastIndexOf(";");
if (code.length > 0 && code[$ - 1] != ';')
code ~= ';';
{
if (code[lastSemicolon + 1 .. $].canFind("write"))
code ~= ';';
else if (lastSemicolon == -1)
code = text("writeln(", code, ");");
else
code = text(code[0 .. lastSemicolon + 1], "writeln(", code[lastSemicolon + 1 .. $], ");");
}
return code;
}

Expand All @@ -852,6 +861,14 @@ unittest
== "writeln(\"Hello!\"); \nwriteln(\"You!\");");
}

unittest
{
assert(innerEvalCode(["2"]) == "writeln(2);");
assert(innerEvalCode(["2 + 2"]) == "writeln(2 + 2);");
assert(innerEvalCode(["2 + 2;"]) == "2 + 2;");
assert(innerEvalCode(["2.pow(4)"]) == "writeln(2.pow(4));");
}

/**
Formats the code provided via `--eval` or `--loop` flags into a
string of complete program code that can be written to a file
Expand Down
43 changes: 29 additions & 14 deletions rdmd_test.d
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ void runTests(string rdmdApp, string compiler, string model)
assert(res.status == 0, res.output);
assert(res.output.canFind("eval_works")); // there could be a "DMD v2.xxx header in the output"

// Test automatic .writeln for --eval
import std.conv : text;
import std.typecons : tuple;
foreach (t; [tuple(`"eval_works"`, "eval_works"),
tuple("2 + 2", "4"),
tuple("2.write; 2 + 2", "24")])
{
res = execute(rdmdArgs ~ ["--force", "-de", text("--eval=", t[0])]);
assert(res.status == 0, res.output);
// there could be a "DMD v2.xxx header in the output" (NB: only seems to be the case for GDC)
assert(res.output.canFind(t[1]), text("got:", res.output, " expected:", t[1]));
}

// compiler flags
res = execute(rdmdArgs ~ ["--force", "-debug",
"--eval=debug {} else assert(false);"]);
Expand Down Expand Up @@ -256,22 +269,24 @@ void runTests(string rdmdApp, string compiler, string model)
{
auto testLines = "foo\nbar\ndoo".split("\n");

auto pipes = pipeProcess(rdmdArgs ~ ["--force", "--loop=writeln(line);"], Redirect.stdin | Redirect.stdout);
foreach (input; testLines)
pipes.stdin.writeln(input);
pipes.stdin.close();

while (!testLines.empty)
// Test --loop with automatic writeln
foreach (loopArg; ["--loop=writeln(line);", "--loop=line"])
{
auto line = pipes.stdout.readln.strip;
if (line.empty || line.startsWith("DMD v")) continue; // git-head header
assert(line == testLines.front, "Expected %s, got %s".format(testLines.front, line));
testLines.popFront;
}
auto status = pipes.pid.wait();
assert(status == 0);
}
auto pipes = pipeProcess(rdmdArgs ~ ["--force", loopArg], Redirect.stdin | Redirect.stdout);
foreach (input; testLines)
pipes.stdin.writeln(input);
pipes.stdin.close();

while (!testLines.empty)
{
auto line = pipes.stdout.readln.strip;
if (line.empty || line.startsWith("DMD v")) continue; // git-head header
assert(line == testLines.front, "Expected %s, got %s".format(testLines.front, line));
testLines.popFront;
}
auto status = pipes.pid.wait();
assert(status == 0);
}}
// vs program file
res = execute(rdmdArgs ~ ["--force",
"--loop=assert(true);", voidMain]);
Expand Down

0 comments on commit b988788

Please sign in to comment.