MGrammar Quick Challenge 2 – Unordered and optional multi-projections

Given this grammar:

module test
{
    language test
    {
        syntax Main = OneTwo*;
        
        syntax OneTwo
            =  o:One t:Two "\r\n"
            => Result { One => true, Two => true }
            |  Two One "\r\n"
            => Result { One => true, Two => true }
            |  One "\r\n"
            => Result { One => true, Two => false }
            |  Two "\r\n"
            => Result { One => false, Two => true };
                
        token One = "one";
        token Two = "two";
        
        interleave Ignore = " ";
    }
}

How could I refactor the syntax “OneTwo” to have only a single projection?

dynamic C# in unit tests

I’ve been writing some unit tests lately that require quite a bit of casting. This gets tiring pretty fast so I went ahead and decided to give the dynamic keyword a try. I’ll show the before and after examples and let you decide.

Here is the non-dynamic version.

[Test]
public void InvokeWithAddPlusInvokeTest()
{
    string code = "f(1 + 2) + g()";
    var b1 = (BinaryExpression)this.pipeline.Compile(code);

    var f = (MethodInvokeExpression)b1.Left;
    var g = (MethodInvokeExpression)b1.Right;

    var b2 = (BinaryExpression)f.Parameters.Single();

    var one = (PrimitiveExpression)b2.Left;
    var two = (PrimitiveExpression)b2.Right;

    Assert.That(b1.Operator == BinaryOperator.Add);
    Assert.That(b2.Operator == BinaryOperator.Add);

    Assert.That(((ReferenceExpression)f.Target).Name == "f");
    Assert.That(((ReferenceExpression)g.Target).Name == "g");
    Assert.That(one.Value == "1");
    Assert.That(two.Value == "2");
}

In this test I am compiling an expression into an AST and digging around to verify that the correct nodes were created in the right places in the tree.

Here is the dynamic version.

[Test]
public void InvokeWithAddPlusInvokeTest()
{
    string code = "f(1 + 2) + g()";
    dynamic b1 = this.pipeline.Compile(code);
    dynamic b2 = Enumerable.Single(b1.Left.Parameters);

    Assert.That(b1.Operator == BinaryOperator.Add);
    Assert.That(b2.Operator == BinaryOperator.Add);

    Assert.That(b1.Left.Target.Name == "f");
    Assert.That(b1.Right.Target.Name == "g");
    Assert.That(b2.Left.Value == "1");
    Assert.That(b2.Right.Value == "2");
}

A lot shorter that’s for sure. The only downside is that if I change the nodes I will no longer get compile time warnings… but I will get unit test errors so this shouldn’t theoretically matter. I also no longer get intellisense so I either have to just know the structure of the objects or use the debugger to figure it out. Still the simplicity is looking good.