View previous topic :: View next topic |
Author |
Message |
teqdruid
Joined: 11 May 2004 Posts: 390 Location: UMD
|
Posted: Wed Sep 12, 2007 9:03 pm Post subject: Embedded Command Line Patch |
|
|
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 |
|
|
JarrettBillingsley
Joined: 20 Jun 2006 Posts: 457 Location: Pennsylvania!
|
Posted: Thu Sep 13, 2007 9:12 am Post subject: |
|
|
I liek. |
|
Back to top |
|
|
teqdruid
Joined: 11 May 2004 Posts: 390 Location: UMD
|
Posted: Thu Sep 13, 2007 9:24 am Post subject: |
|
|
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 |
|
|
JarrettBillingsley
Joined: 20 Jun 2006 Posts: 457 Location: Pennsylvania!
|
Posted: Thu Sep 13, 2007 3:45 pm Post subject: |
|
|
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 |
|
|
|
|
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
|