import std.conv; import std.stdio; import std.string; import std.ascii; import std.file; class ShellException : Exception { string command; string message; this(string command, string message, string file = __FILE__, int line = __LINE__) { this.command = command; this.message = message; super(command ~ ": " ~ message, file, line); } } class CommandShell { CommandWrapper[string] _builtins; const: ProgramData eval(string line) { auto commands = parseCommands(line); ProgramData newestResult; foreach(command; commands) { if(command.app in _builtins) { newestResult = _builtins[command.app](command, newestResult); } else { throw new ShellException(command.app, "no such command"); } } return newestResult; } auto ls(string pattern) { if(pattern.length == 0) pattern = "*"; return dirEntries(".", pattern, SpanMode.shallow); } string echo(string[] argv) { return argv.join(" "); } int[] numbers() { return [1, 2, 3, 4]; } int sum(ProgramData input) { int s = 0; foreach(num; originalProgramData!(int[])(input)) { s += num; } return s; } ProgramData cat(ProgramData input) { return input; } } struct ProgramDataByLine { ProgramData base; this(ProgramData b) { assert(b !is null); this.base = b; if(!empty) currentString = base.getFrontAsString(); } string currentString; @property bool empty() { return base.empty(); } @property string front() { return currentString; } void popFront() { base.popFront(); if(!empty()) currentString = base.getFrontAsString(); } } interface ProgramData { bool empty(); void popFront(); string getFrontAsString(); /* front is implemented however you want in the derived classes this lets you do them with other type for more static goodness as long as you can convert to a string in getFrontAsString we'll be ok for the simpler stuffs. */ // formatting to the user string header(); string footer(); string itemSeperator(); string item(); } import std.range; class ProgramDataImpl(T) if(!(is(T == string) || is(T == int))) : ProgramData { T range; this(T r) { this.range = r; } override bool empty() { return range.empty(); } override void popFront() { range.popFront(); } auto front() { return range.front(); } override string getFrontAsString() { static if(is(typeof(range.front()) == DirEntry)) return range.front().name; else return to!string(range.front()); } string header() { return ""; } string footer() { return ""; } string itemSeperator() { return "\n"; } string item() { return getFrontAsString(); } } class ProgramDataImpl(T) if(is(T == string) || is(T == int)) : ProgramData { T s; bool consumed; this(T r) { this.s = r; } override bool empty() { return consumed; } override void popFront() { consumed = true; } auto front() { return s; } override string getFrontAsString() { return to!string(s); } string header() { return ""; } string footer() { return ""; } string itemSeperator() { return "\n"; } string item() { return getFrontAsString(); } } ProgramDataImpl!T originalProgramData(T)(ProgramData t) { auto data = cast(ProgramDataImpl!T) t; if(data is null) throw new Exception("can't do it"); return data; } ProgramData makeProgramData(T)() if(is(T == void)) { return makeProgramData(""); } ProgramData makeProgramData(T)(T t) { static if(is(T : ProgramData)) return t; else return new ProgramDataImpl!T(t); } extern(C) { char* readline(const char* prompt); void using_history(); void add_history(const char* s); } string[] lex(string line) { auto specialCharacters = `|`;//"'{}[]()|>