Merge pull request #303 from WebDrake/prevent-eval-loop-empty-statements

Prevent empty statements at the end of --eval or --loop code
This commit is contained in:
Sebastian Wilzbach 2018-02-04 16:23:31 +01:00 committed by GitHub
commit a8d282e618
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

105
rdmd.d
View file

@ -17,7 +17,7 @@
import std.algorithm, std.array, core.stdc.stdlib, std.datetime,
std.digest.md, std.exception, std.file, std.getopt,
std.parallelism, std.path, std.process, std.range, std.regex,
std.stdio, std.string, std.typetuple;
std.stdio, std.string, std.typecons, std.typetuple;
version (Posix)
{
@ -180,18 +180,14 @@ int main(string[] args)
{
enforce(programPos == args.length, "Cannot have both --loop and a " ~
"program file ('" ~ args[programPos] ~ "').");
root = makeEvalFile(importWorld ~ "void main(char[][] args) { "
~ "foreach (line; std.stdio.stdin.byLine()) {\n"
~ std.string.join(loop, "\n")
~ ";\n} }");
root = makeEvalFile(makeEvalCode(loop, Yes.loop));
argsBeforeProgram ~= "-d";
}
else if (eval.ptr)
{
enforce(programPos == args.length, "Cannot have both --eval and a " ~
"program file ('" ~ args[programPos] ~ "').");
root = makeEvalFile(importWorld ~ "void main(char[][] args) {\n"
~ std.string.join(eval, "\n") ~ ";\n}");
root = makeEvalFile(makeEvalCode(eval, No.loop));
argsBeforeProgram ~= "-d";
}
else if (programPos < args.length)
@ -839,6 +835,101 @@ import std.stdio, std.algorithm, std.array, std.ascii, std.base64,
std.zlib;
";
/**
Joins together the code provided via an `--eval` or `--loop`
flag, ensuring a trailing `;` is added if not already provided
by the user
Params:
eval = array of strings generated by the `--eval`
or `--loop` rdmd flags
Returns:
string of code to be evaluated, corresponding to the
inner code of either the program or the loop
*/
string innerEvalCode(string[] eval)
{
import std.string : join, stripRight;
// assumeSafeAppend just to avoid unnecessary reallocation
string code = eval.join("\n").stripRight.assumeSafeAppend;
if (code.length > 0 && code[$ - 1] != ';')
code ~= ';';
return code;
}
unittest
{
assert(innerEvalCode([`writeln("Hello!")`]) == `writeln("Hello!");`);
assert(innerEvalCode([`writeln("Hello!");`]) == `writeln("Hello!");`);
// test with trailing whitespace
assert(innerEvalCode([`writeln("Hello!") `]) == `writeln("Hello!");`);
assert(innerEvalCode([`writeln("Hello!"); `]) == `writeln("Hello!");`);
// test with multiple entries
assert(innerEvalCode([`writeln("Hello!"); `, `writeln("You!") `])
== "writeln(\"Hello!\"); \nwriteln(\"You!\");");
assert(innerEvalCode([`writeln("Hello!"); `, `writeln("You!"); `])
== "writeln(\"Hello!\"); \nwriteln(\"You!\");");
}
/**
Formats the code provided via `--eval` or `--loop` flags into a
string of complete program code that can be written to a file
and then compiled
Params:
eval = array of strings generated by the `--eval` or
`--loop` rdmd flags
loop = set to `Yes.loop` if this code comes from a
`--loop` flag, `No.loop` if it comes from an
`--eval` flag
Returns:
string of code to be evaluated, corresponding to the
inner code of either the program or the loop
*/
string makeEvalCode(string[] eval, Flag!"loop" loop)
{
import std.format : format;
immutable codeFormat = importWorld
~ "void main(char[][] args) {%s%s\n%s}";
immutable innerCodeOpening =
loop ? " foreach (line; std.stdio.stdin.byLine()) {\n"
: "\n";
immutable innerCodeClosing = loop ? "} " : "";
return format(codeFormat,
innerCodeOpening,
innerEvalCode(eval),
innerCodeClosing);
}
unittest
{
// innerEvalCode already tests the cases for different
// contents in `eval` array, so let's focus on testing
// the difference based on the `loop` flag
assert(makeEvalCode([`writeln("Hello!") `], No.loop) ==
importWorld
~ "void main(char[][] args) {\n"
~ "writeln(\"Hello!\");\n}");
assert(makeEvalCode([`writeln("What!"); `], No.loop) ==
importWorld
~ "void main(char[][] args) {\n"
~ "writeln(\"What!\");\n}");
assert(makeEvalCode([`writeln("Loop!") ; `], Yes.loop) ==
importWorld
~ "void main(char[][] args) { "
~ "foreach (line; std.stdio.stdin.byLine()) {\n"
~ "writeln(\"Loop!\") ;\n} }");
}
string makeEvalFile(string todo)
{
auto pathname = myOwnTmpDir;