A year has passed as the first prototype of integration of Virtual World Framework & Ometa was presented at SPLASH'14 Future Programming Workshop. In 2015 the new version or "subling" of an Object-Oriented Language for Pattern Matching Ometa was publicly introduced with the name Ohm. As OMeta, it supports the same object-oriented grammar extension and allows pattern matching on structured data as well as strings, but now it also features a complete separation of grammars from semantic actions and a lot more.

In this post I want to present an updated prototype, which now uses the new language Ohm!

To try out, just open this link in the web browser and enter the virtual world containing a simple L-System generator. To modify the world, you could clone it or create your own and use the "Content Library" from the left side GUI for dragging L-System's entities.

You could modify any parameters of a selected L-System's entity in realtime, like: angle, iteration, axioms. Even more, you could redefine a grammar using the Script Editor, while not disrupting other entities.


First steps tutorial

Here is a simple tutorial on how to attach your own grammar with corresponding semantics actions to an entity inside virtual world using ADL Sandbox and Ohm language integration prototype. As an example we will use the Arithmetic calculator grammar from the Ohm language tutorial.
So, in this tutorial we'll define the grammar for parsing simple arithmetic expressions from string; add an operation to it's semantics that can be used to evaluate the provided arithmetic expressions; attach it to the virtual worlds's entity and show the result of evaluation in itself.
The working tutorial for cloning is here: http://live.net.ru/adl/sandbox/world/WRpbHEuHfYGmUm54

At first, please register at http://live.net.ru the project of http://www.krestianstvo.org.
Being registered you could create your own virtual worlds or clone an existed ones to experiment with.

1. Create a world using web interface and enter it:

2. Inside a virtual world create a 3D Text entity for matching grammar and showing our calculator's result:

3. Open Script Editor for the selected object (3D text) and create a new property for it with the name: ohmCalc. The name of the grammar should be necessarily starts with the 'ohm' prefix! As it points the Virtual World Framework model driver to provide ohm language stuff for the selected entity (actually Ohm language driver is loaded at world startup and makes an access to Ohm trough _ohm global variable). In this tutorial the grammar object is automatically generated and stored in Calc property.
Copy the provided Arithmetic grammar's source code into the property ohmCalc:

Arithmetic grammar's source code:

Arithmetic {
  Exp
    = AddExp
    
  AddExp
    = AddExp "+" MulExp  -- plus
    | AddExp "-" MulExp  -- minus
    | MulExp

  MulExp
    = MulExp "*" ExpExp  -- times
    | MulExp "/" ExpExp  -- divide
    | ExpExp

  ExpExp
    = PriExp "^" ExpExp  -- power
    | PriExp

  PriExp
    = "(" Exp ")"  -- paren
    | "+" PriExp   -- pos
    | "-" PriExp   -- neg
    | ident
    | number
    
  ident  (an identifier)
    = letter alnum*

  number  (a number)
    = digit* "." digit+  -- fract
    | digit+             -- whole
}

4. Create new method, in which we will define an operation for our calculator semantics. The semantics is accessible trough automatic generated entity's property at Engine.getProperty(this.id, 'semanticsCalc'). Copy the provided code of 'interpret' operation into the new method with the name addOperationCalc

addOperationCalc source code:

function addOperationCalc()
{   
 
    var constants = {pi: Math.PI, e: Math.E};
    var s = _LangManager.ohmLangs[this.id]["Calc"]["semantics"];

s.addOperation('interpret', {
      Exp: function(e) {
        return e.interpret();  
      },
      AddExp: function(e) {
        return e.interpret();
      },
      AddExp_plus: function(x, _, y) {
        return x.interpret() + y.interpret();
      },
      AddExp_minus: function(x, _, y) {
        return x.interpret() - y.interpret();
      },
      MulExp:        function(e)       { return e.interpret(); },
      MulExp_times:  function(x, _, y) { return x.interpret() * y.interpret(); },
      MulExp_divide: function(x, _, y) { return x.interpret() / y.interpret(); },
      ExpExp:        function(e)       { return e.interpret(); },
      ExpExp_power:  function(x, _, y) { return Math.pow(x.interpret(), y.interpret()); },
      PriExp:        function(e)       { return e.interpret(); },
      PriExp_paren:  function(_, e, _) { return e.interpret(); },
      PriExp_pos:    function(_, e)    { return e.interpret(); },
      PriExp_neg:    function(_, e)    { return -e.interpret(); },
      ident: function(_, _) {
        return constants[this.interval.contents] || 0;
      },
      number: function(_) {
        return parseFloat(this.interval.contents);
      }
    });
}

5. Next, we need to add the function call to addOperationCalc() from initGrammarCalc() and call it. After adding, press Call Method button.

function initGrammarCalc()
{
    //console.log('Init grammar: Calc');
    this.addOperationCalc();
}

6. Now, we are ready to test our grammar and it semantic's operation 'interpret()'. Create the new method with following source code and press Call Method button.

function test()
{
    var str = '(5+7)*4';
    var gram = _LangManager.ohmLangs[this.id]["Calc"]["grammar"];
    var sem = _LangManager.ohmLangs[this.id]["Calc"]["semantics"];
    var r = gram.match(str);
    var n = sem(r);
    this.text = n.interpret();
}

If everything is ok, you should see the string expression evaluation in 3d Text entity.

If something is not working in provided steps, please look at working tutorial here

Thanks for reading!