1 module repl;
2 private {// import
3   import std.stdio;
4   import std.range;
5   import std.string;
6   import std.algorithm;
7   import std.functional;
8   import std.typetuple;
9   import std.conv;
10   import std.concurrency;
11 }
12 
13 class Repl
14 {
15   private string delegate(string[])[string] actions;
16 
17   void opIndexAssign(B, A...)(B delegate(A) action, string name)
18   {
19     actions[name] = (string[] argStrs)
20     {
21       if(argStrs.length != A.length)
22         return text(
23           name, " expects ", A.stringof,
24           ", got (", argStrs.join(", "), ")"
25         );
26 
27       A args;
28 
29       foreach(i,_; args)
30         args[i] = argStrs[i].to!(A[i]);
31 
32       static if(is(B == void))
33       {
34         action(args);
35         return "";
36       }
37       else
38       {
39         return action(args).text;
40       }
41     };
42   }
43   void opIndexAssign(typeof(null), string name)
44   {
45     actions.remove(name);
46   }
47 
48   string read()
49   {
50     return stdin.readln!string;
51   }
52   string eval(string command)
53   {
54     auto cmd = command.split(" ").map!strip.filter!(not!empty);
55 
56     if(cmd.empty)
57       return help;
58     if(auto action = cmd.front in actions)
59       try 
60         return (*action)(cmd.dropOne.array);
61       catch(Exception ex)
62         return ex.msg;
63     else
64       return help;
65   }
66   void print(string result)
67   {
68     result.writeln;
69   }
70   void loop()
71   {
72     while(1)
73       print(eval(read));
74   }
75   string help()
76   {
77     return text("commands: ", actions.keys.join(", "));
78   }
79 }