At the last day of the PDC, Chris Anderson and Giovanni Della-Libera showed us how to build textual DSL’s with the Oslo modeling language. I wrote a blog post about this session and in that post you can find this image:

image

Normally you would use the MG.exe compiler or the MG Build Task to compile your languages. But as the slide above indicates, the MGrammar team provided us with an in-memory version of the MG build task. So let’s try this out!

For this exercise I reuse the language and instance data I created in my blog post: My First Language in MGrammar

Module

First, I created the Module class. This class represents the  MGrammar textual DSL. It also contains the name of the parser you want to create (more on that later on in this post) and the result bytes of the compiled DSL:

   1: public class Module
   2: {
   3:     public string MGrammar { get; set; }
   4:     public string ParserName { get; set; }
   5:     public byte[] Bytes { get; set; }
   6: }

 

DynamicMGrammarCompiler

The dynamic compiler class I created can be used in two scenarios:

  1. You compile the module, cache it in your host application and reuse this module when parsing data through your DSL. Compiling a module is an expensive operation; it burns quite some CPU cycles, so reusing it seems like a good idea.
  2. You compile the module and parse your data through your DSL every single call.

The above scenarios result in three methods: CompileModule, ParseData and CompileModuleAndParseData:

   1: public class DynamicMGrammarCompiler
   2: {
   3:  
   4:     /// <summary>
   5:     /// Compile the module, and store the graph in the byte[], so the 
   6:     /// client application can cache this compiled image
   7:     /// </summary>
   8:     /// <param name="module"></param>
   9:     /// <returns></returns>
  10:     public Module CompileModule(Module module) 
  11:     {
  12:  
  13:         MGrammarCompiler compiler = new MGrammarCompiler(); 
  14:         ErrorReporter reporter = ErrorReporter.Standard;
  15:         TextReader reader = new StringReader(module.MGrammar);
  16:         FileStream fs = null;
  17:         try
  18:         {
  19:             SourceItem item = new SourceItem(module.ParserName, reader);
  20:             item.ContentType = GContentType.Mg;
  21:             SourceItem[] items = new SourceItem[] { item };
  22:             compiler.SourceItems = items;
  23:             compiler.Target = Target.Mgx;
  24:             compiler.TypeCheckActions = true;
  25:             compiler.OutFile = Path.GetTempFileName();
  26:             compiler.Execute(reporter);
  27:             //read bytes 
  28:             string filepath = Path.Combine(Path.GetDirectoryName(compiler.OutFile), Path.GetFileNameWithoutExtension(compiler.OutFile) + ".mgx");
  29:             fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
  30:             byte[] bytes = new byte[fs.Length];
  31:             fs.Read(bytes, (int)0, (int)fs.Length);
  32:             fs.Close();
  33:             module.Bytes = bytes;
  34:         }
  35:         finally
  36:         {
  37:             if (null!=fs)
  38:             {
  39:                 fs.Close();
  40:             }
  41:             reader.Close();
  42:         }
  43:         return module; 
  44:     }
  45:  
  46:     /// <summary>
  47:     /// Parse the instancedata through the compiled image within the module
  48:     /// </summary>
  49:     /// <param name="module"></param>
  50:     /// <param name="instanceData"></param>
  51:     /// <returns></returns>
  52:     public object ParseData(Module module, string instanceData) 
  53:     {
  54:  
  55:         object result = null;
  56:         MemoryStream ms = null;
  57:         StringReader sr = new StringReader(instanceData);
  58:         try
  59:         {
  60:             ms = new MemoryStream(module.Bytes);
  61:             DynamicParser parser = MGrammarCompiler.LoadParserFromMgx(ms, module.ParserName);
  62:             if (null == parser)
  63:             {
  64:                 throw new NullReferenceException(string.Format("Language with name '{0}' not found in MGrammar image!", module.ParserName));
  65:             }
  66:             
  67:             result = parser.ParseObject(sr, ErrorReporter.Standard);
  68:         }
  69:         finally
  70:         {
  71:             if (null != ms)
  72:             {
  73:                 ms.Close();
  74:             }
  75:             sr.Close();
  76:         }
  77:         return result;
  78:     }
  79:  
  80:     /// <summary>
  81:     /// Both Compile and Parse.
  82:     /// </summary>
  83:     /// <param name="module"></param>
  84:     /// <param name="instanceData"></param>
  85:     /// <returns></returns>
  86:     public object CompileModuleAndParseData(Module module, string instanceData)
  87:     {
  88:         module = CompileModule(module);
  89:         return ParseData(module, instanceData);
  90:     }
  91: }

CompileModule creates a MGrammarCompiler instance and loads theMGrammar we want to compile in a TextReader. Then, I create a SourceItem instance which will tell the MGrammarCompiler what type of source it can expect and provides the source (textual DSL) itself.
Then, I tell the compiler that the target of the compilation should be a MGX file. I also provide a temporary file name to write the result to, and then call Execute!
The last step is opening the created file and reading its bytes and returning them within the module instance.

ParseData receives a module and some input instance data. I first read the instance data and create a stream of the module bytes. Then I create a DynamicParser using the stream and the provided ParserName. Important to know here is that the parser name should be the module name and the language name concatenated with a dot. As I’m using my RssLanguage from the inwit module, my parser name should be “inwit.RssLanguage”.
If a correct parser is created, we use it parse our instance data and create a graph. I just return this graph to the caller.

CompileModuleAndParseData just combines the above two steps in one call.

Test Application

As a test application I created a console App:

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         Console.WriteLine(">>Initializing...");
   6:         string filePathMGrammar =       @"C:\Users\Robert Jan\Desktop\My Documents\Oslo\MyOslo\RssLanguage.mg";
   7:         string filePathInstanceData =   @"C:\Users\Robert Jan\Desktop\My Documents\Oslo\MyOslo\FeedsInput.m";
   8:         
   9:         string mGrammar = File.ReadAllText(filePathMGrammar);
  10:         string instanceData = File.ReadAllText(filePathInstanceData);
  11:  
  12:         inwit.Module module = new inwit.Module();
  13:         module.MGrammar = mGrammar;
  14:         module.ParserName = "inwit.RssLanguage";
  15:  
  16:         inwit.DynamicMGrammarCompiler compiler = new inwit.DynamicMGrammarCompiler();
  17:         
  18:         //first compile and cache module
  19:         Console.WriteLine(">>Step 1: compiling module");
  20:         module = compiler.CompileModule(module);
  21:  
  22:         //second reuse module, and just parse instancedata
  23:         Console.WriteLine(">>Step 2a: parsing instance data");
  24:         object graph = compiler.ParseData(module, instanceData);
  25:         Console.WriteLine(">>Step 2b: Writing result:");
  26:         inwit.Helper.WalkMGraphTree(graph);
  27:         
  28:         //third, do all in one call
  29:         Console.WriteLine(">>Step 3a: compiling module and parsing data in one call...");
  30:         graph = compiler.CompileModuleAndParseData(module, instanceData);
  31:         Console.WriteLine(">>Step 3b: Writing result:");
  32:         inwit.Helper.WalkMGraphTree(graph);
  33:  
  34:         Console.ReadLine();
  35:     }
  36: }

I’m using the Helper.WalkMGraphTree method from my previous post again to output the result graph.

The result of the console app looks like:

image


Posted in: Oslo , MGrammar  Tags:

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Page List

    Calendar

    «  September 2010  »
    MoTuWeThFrSaSu
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910
    View posts in large calendar

    Recent Comments

    Feedburner Statistics 9/8/2010
    23 Readers ~ 58 hits ~ 0 reach

    Disclaimer
    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2010 Inwit.nl