The Anise interpreter is available in three forms: the Anise.exe executable, the AniseEngine class, and a half-way in between solution, the AniseProgram class. The first is suitable for running scripts, the second for embedding Anise into an existing program, and the third for creating an Anise-based command-line program.

The Anise Executable

The Anise executable is both an interpreter for the Anise language as well as an interactive shell. In order to launch the interactive shell, simply run Anise.exe without any arguments. Once in the shell, you can enter any valid Anise script statement, or execute Anise shell commands. To use Anise as an interpreter, provide any combination of Anise shell commands as arguments. To see full documentation for the available shell commands, use the /help command either in the shell, or directly on the command line.

Here are a few examples of how you may want to invoke the Anise executable:

Console
    > Anise.exe /file MyScript.adi /build main


You may do something like this to run your own command line program defined in an Anise script. You would start by creating an Anise script containing an object called main . That object would implement a Run() method that performs the all the actions of the program (similar to the Main() method in a normal program). In your Anise script, you’d include a call to that method as part of the object’s definition. Using these arguments, you’re telling the Anise executable to first load the script which defines your program, and then to build the main object, thereby invoking the Run() method.

Console
    > Anise.exe /file MyScript.adi /text db-host=MYSQLHOST /build main


You might do something like this if your command line application needs to connect to a database, and you’d like to override the default host name. In this case, you’re telling Anise to load your script, then to parse a little snippet of Anise script, and then build your main object (still assuming that it is defined to call a Run() method). When Anise parses the little snippet included on the command-line, any values defined will override those defined in your script, and your application will connect to the database you specified instead of the one defined in the file.

Console
    > Anise.exe /file MyScript.adi /debug /test


You might do something like this if you had a failing unit test. You would start by implementing some unit test classes (by subclassing AniseUnitTest ), and then defining instances of them in your Anise script. Then, by using these arguments, you’re telling Anise to first load your script, then to break into a debugger (thus allowing you to define a breakpoint in the failing unit tests), and then execute your unit tests. The debugger would automatically stop when it hit your breakpoint.

The AniseEngine Class

In addition to the command-line executable, Anise may also be used as a software library embedded inside another program. Most of the functionality on the command-line is available directly through the AniseEngine class. In order to use it, simply create an instance of Microsoft.LiveLabs.Anise.API.AniseEngine and invoke it's methods. Here's a short summary of the most important methods on that class:

LoadConfigText(String configText)
Loads the given piece of text as an Anise script. This is most useful if you've aquired the Anise script through some source which isn't a regular file on disk. Once the method returns, all of the definitions in the given text will be available for subsequent use. If any #build directives were included, then those objects will have been created.
LoadFile(String fileName)
Loads the given file as an Anise script. This method works exactly like the LoadConfigText method, but is preferrable in cases where the Anise script is actually saved in a file since it allows Anise to provide much better error messages.
LoadStream(Stream stream)
Loads the contents of the given stream as an Anise script. This method functions just like the other load methods, but allow you to provide a generic stream in case you need to manage how the data is retrieved yourself.
GetObject(String name)
Returns an instance of the named object. If the object had already been created within an appropriate scope (i.e., container or singleton), that instance will be returned. Otherwise, a new instance will be created and connected with all of its other dependencies.
RunTest(TextWriter output, String testName)
Executes the named test, and writes the output to the given text writer. This method can be used to execute a specific test and capture its output.
PrintAll(TextWriter output, bool prettyPrint)
Writes out an Anise script containing all the definitions loaded in the AniseEngine at the time. You can use this to combine Anise script, or to save changes you've made.

The AniseProgram class

Finally, if you are creating a command-line program, and would like to make it completely dependency injected, you can use AniseProgram. This class will automatically parse command-line arguments based upon normal DOS conventions and make them available for dependency injection. For each group of arguments (i.e., sequence of arguments starting with one which begins with a / character), the AniseProgram object will create an argument group. It will then make those argument groups available through two built-in instances: a dictionary called args and a list called arg-list. The key in the args dictionary is the word in each group containing the /; the values are List<String>s containing the remaining words in that group. Each entry in arg-list is another List<String> containing all the words of that argument group (including the word containing the /). For example, the string: "/alpha bravo charlie /delta /echo foxtrot" would be parsed as three groups, and the following definitions would be added to the AniseEngine:

Anise
     1: args = {
     2:     alpha = [ bravo, charlie ];
     3:     delta = [ ];
     4:     echo = [ foxtrot ];
     5: };
     6: 
     7: arg-list = [
     8:     [ alpha, bravo, charlie ],
     9:     [ delta ],
    10:     [ echo, foxtrot ]
    11: ];


The recommended way to use this class is to start with Visual Studio's Console Application template. First, add something like the following to your Program.cs:

C#
     1:     public static void Main(String[] args)
     2:     {
     3:        AniseProgram program = new AniseProgram();
     4:        program.LoadEmbeddedResource(typeof(Program), "AniseConfig.adi");
     5:        program.Run("program", args);
     6:     }
     7:     
     8:     public void Run(List<List<String>> args)
     9:     {
    10:         // Implement your class here
    11:     }
    12: 
    13:     public String PropertyAlpha { get; set; }
    14: 
    15:     public String PropertyBravo { get; set; }


Then, create a new Anise script, and, in its properties, change its "Build Action" to "Embedded Resource". This will make it so that your script is included in the executable without needing to be a seperate file. Then, add something like this:

Anise
    1: program = {
    2:     _class = Program;
    3:     PropertyAlpha = @args.charlie.0;
    4:     PropertyBravo = @args.echo.1;
    5:     Run = [ @arg-list ];
    5: };


Now, let's assume that your application is called with the following arguments from the command line:

Console
    > ConsoleApplication1.exe /charlie delta /echo foxtrot golf


Here's the sequence of events which will occur:
  1. The AniseProgram object is created, asked to load your embedded Anise script, and then told to run the program.
  2. The AniseProgram will parse the arguments given to it and define the args and arg-list objects.
  3. The AniseProgram will use its AniseEngine to create an instance of your Program object.
  4. The PropertyAlpha property will be set to "delta".
  5. The PropertyBravo property will be set to "golf".
  6. The Run method will be called with arg-list as its argument.

Last edited Jun 28, 2010 at 1:36 AM by aminer, version 2

Comments

No comments yet.