FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Embedded Command Line Patch

 
Post new topic   Reply to topic     Forum Index -> MiniD
View previous topic :: View next topic  
Author Message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Wed Sep 12, 2007 9:03 pm    Post subject: Embedded Command Line Patch Reply with quote

I wanted to embed a command line in my application, so I refactored mdcl.d as follows. I'd like this functionality (or similar) to be in minid trunk. Thoughts?

~John

Code:
Index: mdcl.d
===================================================================
--- mdcl.d   (revision 196)
+++ mdcl.d   (working copy)
@@ -23,239 +23,12 @@
 
 module mdcl;
 
-import minid.compiler;
-import minid.minid;
-import minid.types;
+import minid.commandline;
 
 import tango.io.Stdout;
 import tango.io.Console;
-import utf = tango.text.convert.Utf;
 
-void printVersion()
-{
-   Stdout("MiniD Command-Line interpreter beta").newline;
-}
-
-void printUsage()
-{
-   printVersion();
-   Stdout("Usage:").newline;
-   Stdout("\tmdcl [flags] [filename [args]]").newline;
-   Stdout.newline;
-   Stdout("Flags:").newline;
-   Stdout("\t-i      Enter interactive mode, after executing any script file.").newline;
-   Stdout("\t-v      Print the version of the CLI.").newline;
-   Stdout("\t-h      Print this message and end.").newline;
-   Stdout("\t-I path Specifies an import path to search when importing modules.").newline;
-   Stdout.newline;
-   Stdout("If mdcl is called without any arguments, it will be as if you passed it").newline;
-   Stdout("the -v and -i arguments (it will print the version and enter interactive").newline;
-   Stdout("mode).").newline;
-   Stdout.newline;
-   Stdout("If the filename has no extension, it will be treated as a MiniD import-").newline;
-   Stdout("style module name.  So \"a.b\" will look for a module named b in the a").newline;
-   Stdout("directory.  The -I flag also affects the search paths used for this.").newline;
-   Stdout.newline;
-   Stdout("When passing a filename followed by args, all the args will be available").newline;
-   Stdout("to the script by using the vararg expression.  The arguments will all be").newline;
-   Stdout("strings.").newline;
-   Stdout.newline;
-   Stdout("In interactive mode, you will be given a >>> prompt.  When you hit enter,").newline;
-   Stdout("you may be given a ... prompt.  That means you need to type more to make").newline;
-   Stdout("the code complete.  Once you enter enough code to make it complete, the").newline;
-   Stdout("code will be run.  If there is an error, the code buffer is cleared.").newline;
-
-
-   version(Windows)
-   {
-      Stdout("To end interactive mode, either use the function \"exit();\", or force").newline;
-      Stdout("exit by hitting Ctrl-C.").newline;
-   }
-   else
-   {
-      Stdout("To end interactive mode, use the function \"exit();\".").newline;
-   }
-}
-
-const char[] Prompt1 = ">>> ";
-const char[] Prompt2 = "... ";
-
 void main(char[][] args)
 {
-   bool printedVersion = false;
-   bool interactive = false;
-   char[] inputFile;
-   char[][] scriptArgs;
-   char[][] importPaths;
-
-   if(args.length == 1)
-   {
-      printVersion();
-      interactive = true;
-   }
-
-   _argLoop: for(int i = 1; i < args.length; i++)
-   {
-      switch(args[i])
-      {
-         case "-i":
-            interactive = true;
-            break;
-
-         case "-v":
-            if(printedVersion == false)
-            {
-               printedVersion = true;
-               printVersion();
-            }
-            break;
-            
-         case "-h":
-            printUsage();
-            return;
-            
-         case "-I":
-            i++;
-            
-            if(i >= args.length)
-            {
-               Stdout("-I must be followed by a path").newline;
-               printUsage();
-               return;
-            }
-            
-            importPaths ~= args[i];
-            break;
-
-         default:
-            if(args[i][0] == '-')
-            {
-               Stdout("Invalid flag '%s'", args[i]).newline;
-               printUsage();
-               return;
-            }
-
-            inputFile = args[i];
-            scriptArgs = args[i + 1 .. $];
-            break _argLoop;
-      }
-   }
-
-   MDContext ctx = NewContext();
-   MDState state = ctx.mainThread;
-
-   foreach(path; importPaths)
-      ctx.addImportPath(path);
-
-   if(inputFile.length > 0)
-   {
-      MDModuleDef def;
-
-      if(inputFile.length >= 3 && inputFile[$ - 3 .. $] == ".md")
-         def = compileModule(inputFile);
-      else if(inputFile.length >= 4 && inputFile[$ - 4 .. $] == ".mdm")
-         def = MDModuleDef.loadFromFile(inputFile);
-
-      MDValue[] params = new MDValue[scriptArgs.length];
-
-      foreach(i, arg; scriptArgs)
-         params[i] = arg;
-
-      if(def is null)
-      {
-         try
-         {
-            if(ctx.loadModuleFromFile(state, utf.toUtf32(inputFile), params) is null)
-               Stdout.formatln("Error: could not find module '{}'", inputFile);
-         }
-         catch(MDException e)
-         {
-            Stdout.formatln("Error: {}", e);
-            Stdout.formatln("{}", MDState.getTracebackString());
-         }
-      }
-      else
-      {
-         try
-            ctx.initializeModule(state, def, params);
-         catch(MDException e)
-         {
-            Stdout.formatln("Error: {}", e);
-            Stdout.formatln("{}", MDState.getTracebackString());
-         }
-      }
-   }
-
-   if(interactive)
-   {
-      char[] buffer;
-      bool run = true;
-
-      ctx.globals["exit"d] = ctx.newClosure
-      (
-         (MDState s, uint numParams)
-         {
-            run = false;
-            return 0;
-         }, "exit"
-      );
-
-      version(Windows)
-      {
-         Stdout("Use the \"exit();\" function to end, or hit Ctrl-C.").newline;
-      }
-      else
-      {
-         Stdout("Use the \"exit();\" function to end.").newline;
-      }
-
-      Stdout(Prompt1)();
-
-      while(run)
-      {
-         char[] line;
-         
-         if(Cin.readln(line) == false)
-            break;
-
-         buffer ~= line;
-
-         bool atEOF = false;
-         MDFuncDef def;
-
-         try
-            def = compileStatements(utf.toUtf32(buffer), "stdin", atEOF);
-         catch(MDCompileException e)
-         {
-            if(atEOF)
-            {
-               Stdout(Prompt2)();
-            }
-            else
-            {
-               Stdout.formatln("{}", e);
-               Stdout.newline;
-               Stdout(Prompt1)();
-               buffer.length = 0;
-            }
-
-            continue;
-         }
-
-         try
-         {
-            scope closure = ctx.newClosure(def);
-            state.easyCall(closure, 0, MDValue(ctx.globals.ns));
-         }
-         catch(MDException e)
-         {
-            Stdout.formatln("Error: {}", e);
-            Stdout.formatln("{}", MDState.getTracebackString());
-            Stdout.newline;
-         }
-
-         Stdout(Prompt1)();
-         buffer.length = 0;
-      }
-   }
-}
\ No newline at end of file
+   (new CommandLine(Stdout, Cin.stream)).run(args);
+}
Index: minid/commandline.d
===================================================================
--- minid/commandline.d   (revision 0)
+++ minid/commandline.d   (revision 0)
@@ -0,0 +1,277 @@
+/******************************************************************************
+License:
+Copyright (c) 2007 Jarrett Billingsley
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the
+use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software in a
+   product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+    2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+
+    3. This notice may not be removed or altered from any source distribution.
+******************************************************************************/
+
+module minid.commandline;
+
+private import minid.compiler;
+private import minid.minid;
+private import minid.types;
+
+private import tango.io.Print;
+private import tango.io.model.IConduit;
+private import tango.text.convert.Layout;
+private import tango.text.stream.LineIterator;
+       
+private import utf = tango.text.convert.Utf;
+
+const char[] Prompt1 = ">>> ";
+const char[] Prompt2 = "... ";
+
+public class CommandLine {
+
+   private Print!(char) output;
+   private LineIterator!(char) input;
+
+   public this(Print!(char) output, InputStream inputStream) {
+      this.output = output;
+      this.input = new LineIterator!(char)(inputStream);
+   }
+
+   public this(OutputStream outputStream, InputStream inputStream) {
+      this(new Print!(char)(new Layout!(char), outputStream), inputStream);
+   }
+
+   private void printVersion()
+   {
+      output("MiniD Command-Line interpreter beta").newline;
+   }
+   
+   private void printUsage(char[] progname)
+   {
+      printVersion();
+      output("Usage:").newline;
+      output("\t")(progname)(" [flags] [filename [args]]").newline;
+      output.newline;
+      output("Flags:").newline;
+      output("\t-i      Enter interactive mode, after executing any script file.").newline;
+      output("\t-v      Print the version of the CLI.").newline;
+      output("\t-h      Print this message and end.").newline;
+      output("\t-I path Specifies an import path to search when importing modules.").newline;
+      output.newline;
+      output("If mdcl is called without any arguments, it will be as if you passed it").newline;
+      output("the -v and -i arguments (it will print the version and enter interactive").newline;
+      output("mode).").newline;
+      output.newline;
+      output("If the filename has no extension, it will be treated as a MiniD import-").newline;
+      output("style module name.  So \"a.b\" will look for a module named b in the a").newline;
+      output("directory.  The -I flag also affects the search paths used for this.").newline;
+      output.newline;
+      output("When passing a filename followed by args, all the args will be available").newline;
+      output("to the script by using the vararg expression.  The arguments will all be").newline;
+      output("strings.").newline;
+      output.newline;
+      output("In interactive mode, you will be given a >>> prompt.  When you hit enter,").newline;
+      output("you may be given a ... prompt.  That means you need to type more to make").newline;
+      output("the code complete.  Once you enter enough code to make it complete, the").newline;
+      output("code will be run.  If there is an error, the code buffer is cleared.").newline;
+
+
+      version(Windows)
+      {
+         output("To end interactive mode, either use the function \"exit();\", or force").newline;
+         output("exit by hitting Ctrl-C.").newline;
+      }
+      else
+      {
+         output("To end interactive mode, use the function \"exit();\".").newline;
+      }
+   }
+
+   void run(char[][] args = null, MDContext ctx = null) {
+      bool printedVersion = false;
+      bool interactive = false;
+      char[] inputFile;
+      char[][] scriptArgs;
+      char[][] importPaths;
+      char[] progname = (args.length > 0) ? args[0] : "";
+
+      if(args.length == 1 || args == null)
+      {
+         interactive = true;
+      }
+      
+   _argLoop: for(int i = 1; i < args.length; i++)
+      {
+         switch(args[i])
+         {
+         case "-i":
+            interactive = true;
+            break;
+
+         case "-v":
+            if(printedVersion == false)
+            {
+               printedVersion = true;
+               printVersion();
+            }
+            break;
+            
+         case "-h":
+            printUsage(progname);
+            return;
+            
+         case "-I":
+            i++;
+            
+            if(i >= args.length)
+            {
+               output("-I must be followed by a path").newline;
+               printUsage(progname);
+               return;
+            }
+            
+            importPaths ~= args[i];
+            break;
+
+         default:
+            if(args[i][0] == '-')
+            {
+               return;
+            }
+
+            inputFile = args[i];
+            scriptArgs = args[i + 1 .. $];
+            break _argLoop;
+         }
+      }
+
+      if (ctx is null)
+         ctx = NewContext();
+      MDState state = ctx.mainThread;
+
+      foreach(path; importPaths)
+         ctx.addImportPath(path);
+
+      if(inputFile.length > 0)
+      {
+         MDModuleDef def;
+
+         if(inputFile.length >= 3 && inputFile[$ - 3 .. $] == ".md")
+            def = compileModule(inputFile);
+         else if(inputFile.length >= 4 && inputFile[$ - 4 .. $] == ".mdm")
+            def = MDModuleDef.loadFromFile(inputFile);
+
+         MDValue[] params = new MDValue[scriptArgs.length];
+
+         foreach(i, arg; scriptArgs)
+            params[i] = arg;
+
+         if(def is null)
+         {
+            try
+            {
+               if(ctx.loadModuleFromFile(state, utf.toUtf32(inputFile), params) is null)
+                  output.formatln("Error: could not find module '{}'", inputFile);
+            }
+            catch(MDException e)
+            {
+               output.formatln("Error: {}", e);
+               output.formatln("{}", MDState.getTracebackString());
+            }
+         }
+         else
+         {
+            try
+               ctx.initializeModule(state, def, params);
+            catch(MDException e)
+            {
+               output.formatln("Error: {}", e);
+               output.formatln("{}", MDState.getTracebackString());
+            }
+         }
+      }
+
+      if(interactive)
+      {
+         char[] buffer;
+         bool run = true;
+
+         ctx.globals["exit"d] = ctx.newClosure
+            (
+               (MDState s, uint numParams)
+               {
+                  run = false;
+                  return 0;
+               }, "exit"
+               );
+
+         version(Windows)
+         {
+            output("Use the \"exit();\" function to end, or hit Ctrl-C.").newline;
+         }
+         else
+         {
+            output("Use the \"exit();\" function to end.").newline;
+         }
+
+         output(Prompt1)();
+
+         while(run)
+         {
+            char[] line;
+         
+            if((line = input.next()) == null)
+               break;
+
+            buffer ~= line;
+
+            bool atEOF = false;
+            MDFuncDef def;
+
+            try
+               def = compileStatements(utf.toUtf32(buffer), "stdin", atEOF);
+            catch(MDCompileException e)
+            {
+               if(atEOF)
+               {
+                  output(Prompt2)();
+               }
+               else
+               {
+                  output.formatln("{}", e);
+                  output.newline;
+                  output(Prompt1)();
+                  buffer.length = 0;
+               }
+
+               continue;
+            }
+
+            try
+            {
+               scope closure = ctx.newClosure(def);
+               state.easyCall(closure, 0, MDValue(ctx.globals.ns));
+            }
+            catch(MDException e)
+            {
+               output.formatln("Error: {}", e);
+               output.formatln("{}", MDState.getTracebackString());
+               output.newline;
+            }
+
+            output(Prompt1)();
+            buffer.length = 0;
+         }
+      }
+   }
+}
Back to top
View user's profile Send private message Send e-mail AIM Address
JarrettBillingsley



Joined: 20 Jun 2006
Posts: 457
Location: Pennsylvania!

PostPosted: Thu Sep 13, 2007 9:12 am    Post subject: Reply with quote

I liek. Smile
Back to top
View user's profile Send private message
teqdruid



Joined: 11 May 2004
Posts: 390
Location: UMD

PostPosted: Thu Sep 13, 2007 9:24 am    Post subject: Reply with quote

I was a bit tired last night, and I forgot a further request: I'd like, when in interactive mode, for the return values of everything to be printed back, and for expressions to be evaluated. I.E. "5 + 3" returns 8. For a second, I thought it'd be as simple as adding "writefln("{}", " to the beginning of every typed line, but that won't deal with multi-line or non-running lines (function/class definitions) correctly.

This is what pretty much every other interactive-mode scripting language does, and it's very convenient.

~John
Back to top
View user's profile Send private message Send e-mail AIM Address
JarrettBillingsley



Joined: 20 Jun 2006
Posts: 457
Location: Pennsylvania!

PostPosted: Thu Sep 13, 2007 3:45 pm    Post subject: Reply with quote

I'd like that too. It's tedious to have to type out "writefln(...);" every time. Course MiniD doesn't allow for this in the grammar (no no-op statements), so it'd have to be done like the Lua interpreter does it: just prefix the line with an equals sign and it'll parse it as an expression. Like "=5 + 8" gives "13".
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> MiniD All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group