|
17 | 17 | import std.algorithm, std.array, core.stdc.stdlib, std.datetime, |
18 | 18 | std.digest.md, std.exception, std.file, std.getopt, |
19 | 19 | std.parallelism, std.path, std.process, std.range, std.regex, |
20 | | - std.stdio, std.string, std.typetuple; |
| 20 | + std.stdio, std.string, std.typecons, std.typetuple; |
21 | 21 |
|
22 | 22 | version (Posix) |
23 | 23 | { |
@@ -180,18 +180,14 @@ int main(string[] args) |
180 | 180 | { |
181 | 181 | enforce(programPos == args.length, "Cannot have both --loop and a " ~ |
182 | 182 | "program file ('" ~ args[programPos] ~ "')."); |
183 | | - root = makeEvalFile(importWorld ~ "void main(char[][] args) { " |
184 | | - ~ "foreach (line; std.stdio.stdin.byLine()) {\n" |
185 | | - ~ std.string.join(loop, "\n") |
186 | | - ~ ";\n} }"); |
| 183 | + root = makeEvalFile(makeEvalCode(loop, Yes.loop)); |
187 | 184 | argsBeforeProgram ~= "-d"; |
188 | 185 | } |
189 | 186 | else if (eval.ptr) |
190 | 187 | { |
191 | 188 | enforce(programPos == args.length, "Cannot have both --eval and a " ~ |
192 | 189 | "program file ('" ~ args[programPos] ~ "')."); |
193 | | - root = makeEvalFile(importWorld ~ "void main(char[][] args) {\n" |
194 | | - ~ std.string.join(eval, "\n") ~ ";\n}"); |
| 190 | + root = makeEvalFile(makeEvalCode(eval, No.loop)); |
195 | 191 | argsBeforeProgram ~= "-d"; |
196 | 192 | } |
197 | 193 | else if (programPos < args.length) |
@@ -839,6 +835,101 @@ import std.stdio, std.algorithm, std.array, std.ascii, std.base64, |
839 | 835 | std.zlib; |
840 | 836 | "; |
841 | 837 |
|
| 838 | +/** |
| 839 | +Joins together the code provided via an `--eval` or `--loop` |
| 840 | +flag, ensuring a trailing `;` is added if not already provided |
| 841 | +by the user |
| 842 | +
|
| 843 | +Params: |
| 844 | + eval = array of strings generated by the `--eval` |
| 845 | + or `--loop` rdmd flags |
| 846 | +
|
| 847 | +Returns: |
| 848 | + string of code to be evaluated, corresponding to the |
| 849 | + inner code of either the program or the loop |
| 850 | +*/ |
| 851 | +string innerEvalCode(string[] eval) |
| 852 | +{ |
| 853 | + import std.string : join, stripRight; |
| 854 | + // assumeSafeAppend just to avoid unnecessary reallocation |
| 855 | + string code = eval.join("\n").stripRight.assumeSafeAppend; |
| 856 | + if (code.length > 0 && code[$ - 1] != ';') |
| 857 | + code ~= ';'; |
| 858 | + return code; |
| 859 | +} |
| 860 | + |
| 861 | +unittest |
| 862 | +{ |
| 863 | + assert(innerEvalCode([`writeln("Hello!")`]) == `writeln("Hello!");`); |
| 864 | + assert(innerEvalCode([`writeln("Hello!");`]) == `writeln("Hello!");`); |
| 865 | + |
| 866 | + // test with trailing whitespace |
| 867 | + assert(innerEvalCode([`writeln("Hello!") `]) == `writeln("Hello!");`); |
| 868 | + assert(innerEvalCode([`writeln("Hello!"); `]) == `writeln("Hello!");`); |
| 869 | + |
| 870 | + // test with multiple entries |
| 871 | + assert(innerEvalCode([`writeln("Hello!"); `, `writeln("You!") `]) |
| 872 | + == "writeln(\"Hello!\"); \nwriteln(\"You!\");"); |
| 873 | + assert(innerEvalCode([`writeln("Hello!"); `, `writeln("You!"); `]) |
| 874 | + == "writeln(\"Hello!\"); \nwriteln(\"You!\");"); |
| 875 | +} |
| 876 | + |
| 877 | +/** |
| 878 | +Formats the code provided via `--eval` or `--loop` flags into a |
| 879 | +string of complete program code that can be written to a file |
| 880 | +and then compiled |
| 881 | +
|
| 882 | +Params: |
| 883 | + eval = array of strings generated by the `--eval` or |
| 884 | + `--loop` rdmd flags |
| 885 | + loop = set to `Yes.loop` if this code comes from a |
| 886 | + `--loop` flag, `No.loop` if it comes from an |
| 887 | + `--eval` flag |
| 888 | +
|
| 889 | +Returns: |
| 890 | + string of code to be evaluated, corresponding to the |
| 891 | + inner code of either the program or the loop |
| 892 | +*/ |
| 893 | +string makeEvalCode(string[] eval, Flag!"loop" loop) |
| 894 | +{ |
| 895 | + import std.format : format; |
| 896 | + immutable codeFormat = importWorld |
| 897 | + ~ "void main(char[][] args) {%s%s\n%s}"; |
| 898 | + |
| 899 | + immutable innerCodeOpening = |
| 900 | + loop ? " foreach (line; std.stdio.stdin.byLine()) {\n" |
| 901 | + : "\n"; |
| 902 | + |
| 903 | + immutable innerCodeClosing = loop ? "} " : ""; |
| 904 | + |
| 905 | + return format(codeFormat, |
| 906 | + innerCodeOpening, |
| 907 | + innerEvalCode(eval), |
| 908 | + innerCodeClosing); |
| 909 | +} |
| 910 | + |
| 911 | +unittest |
| 912 | +{ |
| 913 | + // innerEvalCode already tests the cases for different |
| 914 | + // contents in `eval` array, so let's focus on testing |
| 915 | + // the difference based on the `loop` flag |
| 916 | + assert(makeEvalCode([`writeln("Hello!") `], No.loop) == |
| 917 | + importWorld |
| 918 | + ~ "void main(char[][] args) {\n" |
| 919 | + ~ "writeln(\"Hello!\");\n}"); |
| 920 | + |
| 921 | + assert(makeEvalCode([`writeln("What!"); `], No.loop) == |
| 922 | + importWorld |
| 923 | + ~ "void main(char[][] args) {\n" |
| 924 | + ~ "writeln(\"What!\");\n}"); |
| 925 | + |
| 926 | + assert(makeEvalCode([`writeln("Loop!") ; `], Yes.loop) == |
| 927 | + importWorld |
| 928 | + ~ "void main(char[][] args) { " |
| 929 | + ~ "foreach (line; std.stdio.stdin.byLine()) {\n" |
| 930 | + ~ "writeln(\"Loop!\") ;\n} }"); |
| 931 | +} |
| 932 | + |
842 | 933 | string makeEvalFile(string todo) |
843 | 934 | { |
844 | 935 | auto pathname = myOwnTmpDir; |
|
0 commit comments