Changeset 936

Show
Ignore:
Timestamp:
02/23/09 12:39:02 (3 years ago)
Author:
andrei
Message:

Added --shebang, --eval, and --loop options

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tools/rdmd.d

    r885 r936  
    3030private string exe, compiler = "dmd"; 
    3131 
     32// For --eval 
     33immutable string importWorld = " 
     34import std.stdio, std.algorithm, std.array, std.atomics, std.base64,  
     35    std.bigint, std.bind, /*std.bitarray,*/ std.bitmanip, std.boxer,  
     36    std.compiler, std.complex, std.contracts, std.conv, std.cpuid, std.cstream, 
     37    std.ctype, std.date, std.dateparse, std.demangle, std.encoding, std.file,  
     38    std.format, std.functional, std.getopt, std.intrinsic, std.iterator,  
     39    /*std.loader,*/ std.math, std.md5, std.metastrings, std.mmfile,  
     40    std.numeric, std.openrj, std.outbuffer, std.path, std.perf, std.process,  
     41    std.random, std.range, std.regex, std.regexp, std.signals, std.socket,  
     42    std.socketstream, std.stdint, std.stdio, std.stdiobase, std.stream,  
     43    std.string, std.syserror, std.system, std.traits, std.typecons,  
     44    std.typetuple, std.uni, std.uri, std.utf, std.variant, std.xml, std.zip, 
     45    std.zlib;"; 
     46 
    3247int main(string[] args) 
    3348{ 
    3449    //writeln("Invoked with: ", map!(q{a ~ ", "})(args)); 
     50    if (args.length > 1 && std.string.startsWith(args[1], "--shebang ")) 
     51    { 
     52        // multiple options wrapped in one 
     53        auto a = args[1]["--shebang ".length .. $]; 
     54        args = args[0 .. 1] ~ split(a) ~ args[2 .. $]; 
     55    } 
    3556     
    36     // Parse the #! line of the root module 
    37     // Not used yet; not sure whether it's a good idea 
    38     // completeFlagsFromShebang(root, args); 
    39  
    4057    // Continue parsing the command line; now get rdmd's own arguments 
    4158    // parse the -o option 
     
    5269            // add a trailing path separator to clarify it's a dir 
    5370            exe = std.path.join(value[1 .. $], ""); 
    54             assert(exe.endsWith(std.path.sep)); 
     71            assert(std.string.endsWith(exe, std.path.sep)); 
    5572        } 
    5673        else if (value[0] == '-') 
     
    7794 
    7895    // set by functions called in getopt if program should exit 
    79     bool bailout; 
     96    bool bailout, loop; 
     97    string eval; 
    8098    getopt(args, 
    8199            std.getopt.config.caseSensitive, 
     
    88106            "help", (string) { writeln(helpString); bailout = true; }, 
    89107            "man", (string) { man; bailout = true; }, 
     108            "eval", &eval, 
     109            "loop", &loop, 
    90110            "o", &dashOh, 
    91111            "compiler", &compiler); 
     
    93113    if (dryRun) chatty = true; // dry-run implies chatty 
    94114 
     115    if (eval) 
     116    { 
     117        // Just evaluate this program! 
     118        if (loop) 
     119        { 
     120            return .eval(importWorld ~ "void main(string[] args) { " 
     121                ~ "foreach (line; stdin.byLine()) { " ~ eval ~ "; } }"); 
     122        } 
     123        else 
     124        { 
     125            return .eval(importWorld ~ "void main(string[] args) { " 
     126                    ~ eval ~ "; }"); 
     127        } 
     128    } 
     129     
    95130    // Parse the program line - first find the program to run 
    96     invariant programPos = find!("a.length && a[0] != '-'")(args[1 .. $]) 
    97         - begin(args); 
    98     if (programPos == args.length) 
    99     { 
    100         write(helpString); 
    101         return 1; 
     131    uint programPos = 1; 
     132    for (;; ++programPos) 
     133    { 
     134        if (programPos == args.length) 
     135        { 
     136            write(helpString); 
     137            return 1; 
     138        } 
     139        if (args[programPos].length && args[programPos][0] != '-') break; 
    102140    } 
    103141    const 
     
    125163    { 
    126164        // user-specified exe name 
    127         if (endsWith(exe, std.path.sep)) 
     165        if (std.string.endsWith(exe, std.path.sep)) 
    128166        { 
    129167            // user specified a directory, complete it to a file 
     
    151189{ 
    152190    // Heuristics: if source starts with "std.", it's in a library 
    153     return startsWith(source, "std.") || startsWith(source, "core.") 
     191    return std.string.startsWith(source, "std.") 
     192        || std.string.startsWith(source, "core.") 
    154193        || source == "object" || source == "gcstats"; 
    155194    // another crude heuristic: if a module's path is absolute, it's 
     
    209248        in string[] compilerFlags) 
    210249{ 
    211     invariant todo = compiler~" "~join(compilerFlags, " ") 
     250    auto todo = compiler~" "~join(compilerFlags, " ") 
    212251        ~" -of"~shellQuote(fullExe) 
    213252        ~" -od"~shellQuote(objDir) 
    214         ~" "~shellQuote(root)~" " 
    215         ~join(map!(shellQuote)(myModules.keys), " "); 
     253        ~" "~shellQuote(root)~" "; 
     254    foreach (k; map!(shellQuote)(myModules.keys)) { 
     255        todo ~= k ~ " "; 
     256    } 
    216257    invariant result = run(todo); 
    217258    if (result)  
     
    225266    rmdirRecurse(objDir); 
    226267    return 0; 
    227 } 
    228  
    229 void completeFlagsFromShebang(string root, ref string[] args) 
    230 { 
    231     auto f = File(root); 
    232     auto sheBang = f.readln; 
    233     auto cmd = std.regexp.split(strip(sheBang), r"\s+"); 
    234     if (cmd.length <= 1 || !cmd[0].startsWith("#!")) return; 
    235     invariant prog = cmd[0][2 .. $]; 
    236  
    237     // Allowed shebangs: 
    238     // #!/path/to/rdmd --stuff 
    239     // or 
    240     // #!/usr/bin/env rdmd --stuff 
    241     // or 
    242     // #!/bin/env rdmd --stuff 
    243     if (basename(prog) != "rdmd") 
    244     { 
    245         if (prog != "/bin/env" && prog != "/usr/bin/env" || cmd[1] != "rdmd") 
    246             return; 
    247         // Discard the "[/usr]/bin/env" thing 
    248         cmd = cmd[1 .. $]; 
    249     } 
    250     // Ok, found a command with maybe some parms. Put those in front so 
    251     // they are overridden by the true command-line arguments 
    252     args = args[0] ~ cmd[1 .. $] ~ args[1 .. $]; 
    253268} 
    254269 
     
    326341                      (implies --chatty) 
    327342  --force           force a rebuild even if apparently not necessary 
     343  --eval=code       evaluate program a la perl -e 
     344  --loop            assume \"foreach (line; stdin.byLine()) { ... }\" for eval 
    328345  --help            this message 
    329346  --man             open web browser on manual page 
     347  --shebang         rdmd is in a shebang line (put as first argument) 
    330348"; 
    331349} 
     350 
     351int eval(string todo) 
     352{ 
     353    auto progname = tmpDir~"/eval.d"; 
     354    std.file.write(progname, todo); 
     355    scope(exit) std.file.remove(progname); 
     356    run("dmd -run " ~ progname); 
     357    return 0; 
     358}