1 module calcool.app; 2 3 version (CLI_APP) { 4 import std.stdio; 5 import std.getopt; 6 import std.file; 7 import std.format; 8 9 import calcool.parser; 10 import calcool.token; 11 import calcool.exceptions; 12 13 enum usage = q{Usage: calcool [OPTION] [ARGUMENT] 14 -h : Print this help message 15 -i : Set input file (each expression separated by newline) 16 -c : Calculate the given expression}; 17 18 enum quitIfTooManyArgs(int maxArgs) = format!q{ 19 if (argnum > %d) { 20 stderr.writeln( 21 "Too many arguments: use -c for an expression or -i for an input file"); 22 return 1; 23 } 24 }(maxArgs); 25 26 int main(string[] args) { 27 string inputPath = null; 28 string inputExpression = null; 29 const argnum = args.length; 30 31 GetoptResult opts; 32 try { 33 opts = getopt(args, "i", &inputPath, "c", &inputExpression); 34 } catch (Exception e) { 35 stderr.writefln("Error: %s\n", e.msg); 36 return 1; 37 } 38 39 auto p = new Parser(); 40 if (opts.helpWanted) { 41 writeln(usage); 42 } else if (inputPath !is null) { 43 mixin(quitIfTooManyArgs!3); 44 if (exists(inputPath) && isFile(inputPath)) { 45 p.setInput(File(inputPath)); 46 run(p); 47 } else { 48 stderr.writefln("Error: can't open file '%s'\n", inputPath); 49 return 1; 50 } 51 } else if (inputExpression !is null) { 52 mixin(quitIfTooManyArgs!3); 53 return run(p, inputExpression); 54 } else { 55 mixin(quitIfTooManyArgs!1); 56 run(p); 57 } 58 return 0; 59 } 60 61 void run(ref Parser p) { 62 import std.stdio : writeln, stderr; 63 64 while (true) { 65 try { 66 p.parseExpression().evaluate().writeln(); 67 } catch (CalcoolException ce) { 68 stderr.writeln(ce.msg); 69 } catch (EofException e) { 70 break; 71 } catch (Exception e) { 72 stderr.writefln("Error: %s", e.msg); 73 break; 74 } 75 } 76 } 77 78 int run(ref Parser p, string input) { 79 import std.stdio : writeln, stderr; 80 81 try { 82 p.evaluateFromString(input).writeln(); 83 } catch (CalcoolException ce) { 84 stderr.writefln(ce.msg); 85 return 1; 86 } catch (Exception e) { 87 return 2; 88 } 89 return 0; 90 } 91 }