Language Workbench Competition

I’m actually pretty close to having all of the MetaSharp grammars translated into .g files and Attila is working on the msbuild compiler components. Once we have them both done and merged we will have achieved dogfood status. There are plenty of Grammar and Lang features I want to work on still but the next major feature will be the Language Workbench, or in other words the interactive editor (I want to have some type of grammar REPL for the tclangug presentation I will be giving next month at least).

I just recently learned about the Code Generation Conference and now I am learning that there was also a Language Workbench website and that they sponsored a competition that went along with the conference. The most interesting part of this is the description of what a language workbench should do and how to rate them:

http://www.languageworkbenches.net/LWCTask-1.0.pdf

Which almost reads like a workbench spec! So this is very exciting, I have been thinking about what a MetaSharp workbench should be like and I think that I have a pretty good idea of what the external expectations are now, so this is good.

What’s funny about MetaSharp is that it is designed to solve all of the “Advanced” scenarios but currently doesn’t solve any of the “Basic” scenarios, lol. I’m not sure if that’s a good sign or a bad sign yet…

The Switch Pattern

I recently discovered a solution to a problem that has been stumping me, with regards to pattern matching, for a while. The problem is with Direct Left Recursion and it being too greedy in some cases.

For example suppose you have the following string you are trying to parse:

var input = "x.y.z";

This string represents an expression tree, in this case three reference expressions to x, y and z respectively. This is very easy to parse using direct left recursion, with the following grammar:

grammar DlrExample < Parser:
            
    Main = Expression;
    Expression 
        = target:Expression "." name:Identifier 
            -> new ReferenceExpression(target, name)
        | Identifier;
end

Hopefully above you can see that the Expression rule is referencing itself in the left most part of it’s first rule. This will cause a direct left recursion to occur which is solved by the MetaSharp packrat parser by keeping a stack of called rules and memozing returned values. You can easily add more types of expressions to this system, such as MethodInvokeExpressions that would match “x()”, for example. The solution to direct left recursion triggers something called Grow LR which will continue to invoke the Expression rule over and over, returning it’s previous result until it either fails or returns a lesser match.

The problem with this technique is that the growth stage is greedy. Meaning it will grow and match all of that expression and make it impossible to match the ending expression.

For example, an AttachDelegateStatement assumes that the last expression in the tree is a reference expression. See the below snippets for an example of this:

x.y.z += Foo; // valid
x.y().z += Foo; // valid
x.y.z() += Foo; // fail!

It is not valid for the AttachDelegateStatement to be attached to a MethodInvokeExpression, it must be a ReferenceExpression but the Grow LR will match the entire expression leaving you no way to determine if the last item is what you are wanting.

The solution to this problem is a combination of the Variable, Object and Switch patterns. The Switch pattern is the real magic here, it lets you switch the input of the stream from the standard input to projections assigned to previously parsed variables. This lets you perform pattern matching on your output directly inline. Here is an example of the solution (probably not 100% correct, for illustration purposes only) to the problem of the AttachDelegateStatement using the Switch pattern:

grammar DlrExample < Parser:
            
    Main = DelegateAttachStatement;
    Expression 
        = target:Expression "." name:Identifier "(" ")"
            -> new MethodInvokeExpression(target, names)
        | target:Expression "." name:Identifier 
            -> new ReferenceExpression(target, name)
        | Identifier;

    ReferenceExpression 
        = exp:Expression (ReferenceExpression { })(exp) -> exp;

    DelegateAttachStatement
        = target:ReferenceExpression 
          "+=" 
          method:ReferenceExpression
            -> new DelegateAttachStatement(target, method);
end

The interesting part of this is the ReferenceExpression rule, specifically the (…)(exp) which is the switch pattern. You can see that it first calls Expression but after that it is Switching on the “exp” variable. Here is the interpretation of that rule in C#:

var ReferenceExpression = Pattern.Rule(
    Pattern.Projection(
        Pattern.And(
            Pattern.Variable("exp", this.Expression),
            Pattern.Switch(
                "exp",
                Pattern.Object(
                    Pattern.Type(typeof(ReferenceExpression))))),
        s => s.Variables["exp"]));

So we’re switching the stream to the value stored in “exp”, then we are applying the Object match to verify that the result is a ReferenceExpression, if it is then the pattern is matched successfully and we simply project out exp. And remember, all of these rules are generating memos so even if this pattern fails it’s likely to be quick for other rules to match.

This is really powerful because it essentially solves the problems of the greedy Grow LR! I am also using this pattern to detect the difference between projections with single expressions and multi-statement blocks, in order to determine the need for ending semi-colons or not. This is very powerful stuff!

Object Matching in MetaSharp

I’ve been delaying this feature in MetaSharp for a while because I wasn’t entirely sure how I wanted it to work and it’s a very important feature. I also haven’t seen any other examples in the wild that matched what I’m trying to do exactly so I was slightly unsure of the syntax.

But I have finally dug in and got it working! It’s by no means set in stone, so if anyone has any good suggestions I will likely incorporate them. Feel free to send me suggestions.

If you’re wondering what I mean by Object Matching I’ll try to explain, first what it means and second why I think it’s important.

Object Matching

Most parsers in the world today are concerned with general purpose programming languages and, as a result, parsing text and transforming it into executable code. The patterns around this problem set are well known and have many implementations. However, the interesting thing is that they are largely geared towards accepting only text as an input and therefore rely on multiple patterns to solve the problems of compilers.

In MetaSharp there is a now Pattern for matching complex objects as well as characters. What this means is that your input can actually be streams of object trees instead of just strings.

For comparison, suppose you wanted to match a social security number from a string using MetaSharp. Here is how you might do it:

SSN = Number#3 “-” Number#2 “-” Number#4;

If your string input was “123-45-6789” then this SSN rule would match that. This is not all that different from regular expressions, though there are some notable differences.

But suppose what you actually had was a Customer object, which has an SSN property? With object matching to you can match on the entire object instead of just the string.

PersonWithSsn = Person { Ssn = SSN };

In this case the curly braces indicate an object match, where the object type is of Type Person and possesses the property Ssn with a value that matches the SSN rule. This is a pretty trivial example but the value of this becomes more apparent when you consider large object graphs and you have the desire to transform that object graph into something else.

Transforming Object Graphs

This is actually a very common operation in software and the standard two design patterns for doing this are the State Machine and Visitor patterns. In fact both techniques are required as multiple steps in order to implement a basic compiler. Using Object Matching patterns you can effectively create a Visitor pattern in the same grammar language as needed to create a State machine.

This is the real benefit of object matching, being able to use the same grammar to create State Machines and Visitors means that you can create every step in a compiler using a single language, tool or skill.

For example, in MetaSharp I have a sample application that plays songs using Console.Beep. It’s pretty silly but its a nice integration test for me. In this sample I have two songs and after parsing the DSL text what I used to do was to pass the AST resulting from that parse into a T4 template, which would then generate some code that would get compiled into linq expressions.

Here is an example of the T4 template I am referring to:
http://metasharp.codeplex.com/SourceControl/…/DynamicSong.template

<#@ template language=”C#” inherits=”SongMetaTemplate” hostspecific=”true” debug=”true” #>
<#@ assembly name=”DynamicSongBuilder” #>
<#@ import namespace=”DynamicSongBuilder” #>
<# foreach(var song in this.Songs) { #>
    <# foreach(var b in song.Bars) { #>
        <# foreach(var n in b.Notes) { #>
            play(<#=song.Duration #>, “<#=n.Key #>”, <#=n.Octave #>);
        <# }
    }
} #>

This works and is a legitimate technique and I don’t think it’s very popular to say this but string transformations like this have a couple serious drawbacks.

  1. The general purpose languages are hard coded, if you wanted to make this reusable you’d have to rewrite it for every language you wanted to support.
  2. You lose contextual information about your original object.
    • C# is a little better at this than some by giving you the #line directive but it’s still not ideal.
  3. It’s slow. With T4 you either get an unwanted assembly loaded into memory or you have to create a separate AppDomain which is very slow and cludgy.
  4. Tag Soup (http://www.codinghorror.com/blog/2008/07/web-development-as-tag-soup.html)

These drawbacks are usually acceptable. You’re usually only creating a website once, for example. And your views typically don’t get reused as part of another application. Being the top most part of the stack, it’s ok to lose a little context. But in a world where your intention is to create reusable grammars and inheritable grammars it’s very non-ideal.

Here is how you would implement the same transformation using a grammar with Object Matching:

grammar DynamicSongTransform:

Main = SongTransform;

SongTransform
= Song { b:Bars = [BarTransform*] }
-> BlockStatement { Statements = b.Flatten() };

BarTransform
= Bar { n:Notes = [NoteTransform*] }
-> n;

NoteTransform
= n:Note { }
-> InvokeExpression {
Target = ReferenceExpression { Name = "play" },
Parameters = [
PrimitiveExpression { Value = n.Parent.Parent.Duration.ToNumber() },
PrimitiveExpression { Value = n.Key },
PrimitiveExpression { Value = n.Octave.ToNumber() }
]
};
end

This grammar accepts a Object Stream containing a single Song object. That Song object will contain a collection of Bar object which in turn contains a collection of Note objects.

As a refresher the ‘->’ token indicates a projection. Which means the pattern to match is on the left side of the projection and if the match is successful then the right hand side is what is produced. If no projection is specified then the matched value is projected by default.

In the projection of the NoteTransform we are projecting an InvokeExpression, which has a Target and some parameters. This then gets passed down into a DynamicCompile step i created which transforms these objects into Linq expressions, which in turn translates those expressions into IL! In this way every step of our DSL is re-usable. This will work for VB or C# developers. It will also work by passing in a textual DSL or by passing in a Song AST created by other means. You could create a different textual DSL that produces the same AST and this will still work and we have debugging context data all the way to the end. Also, the general purpose code transformers are all implemented by MetaSharp so you don’t have to do that every time.

My theory is that creating a custom DSL should be as simple as creating multiple grammars and snapping them together. The next step will be to implement a general purpose UI that will let you use attributes to annotate your grammars to give hints about highlighting and other IDE related features. Keep an eye out for basic VS and NuGet integration in the near future!

Dynamic Pattern Matching in .net

For my most recent batch of work on MetaSharp I have been working on a completely dynamic version of the Grammar grammar. The reason I’ve been working on it is that I want to start working UI portions of the tool and in order to do that I needed a way to be able to dynamically compile grammars and run them.

What’s interesting is that thus far the Grammar language has been static, meaning you compile it at build-time and it results in a class that inherits from something using the standard .net Type system. So doing things dynamically is tricky because one of my goals was to still be able to “inherit” from a grammar without creating any new .net types. I managed to get this working. This has been a very interesting discovery process for me and I think it has really given me a few revelations about dynamism in type system, I’ll try to share a few of them here.

  • The only difference between dynamic and static is simply when you compile; during run-time or before run-time.
  • A dynamic language is simply expression trees + custom Type system.
  • Your Type system can be anything, it doesn’t need to actually be classes and structs, etc.

Here is an example of some unit tests I have been writing to verify certain functionality, which should hopefully give you a sampling of what it looks like to do pattern matching dynamically as well as some of the basics of MetaSharp.

Simple ‘And’ rule test

This rule says ‘a’ AND ‘b’. The CompileRule is actually adding the extra namespace and grammar declaration stuff automatically and compiling that grammar into a DynamicParser object and is returned as an IParser. Calling parse actually returns an object of Type dynamic but I have an explicit cast below as well.

[Test]
public void AndMatchTest()
{
    var dynamicParser = DynamicParser.CompileRule("'a' 'b'");

    var result = (dynamic)dynamicParser.Parse("ab");
    Assert.AreEqual('a', (char)result[0]);
    Assert.AreEqual('b', (char)result[1]);
}

Value projections

Here I’m projecting an actual double, not a string representation of a double.

[Test]
public void DoubleProjectionTest()
{
    var dynamicParser = DynamicParser.CompileRule("default -> 7.11");
    var result = (dynamic)dynamicParser.Parse("");
    Assert.AreEqual(7.11, (double)result);
}

Dynamic projections

This projection is returning a DynamicNode object. The Identifier is used instead of the Type Name. Properties can be dynamically added. This also has a variable assignment on the left hand side “a:” lets you use the a variable on the right hand side.

[Test]
public void CharacterMatchObjectProjectionTest()
{
    var dynamicParser = DynamicParser.CompileRule("a:'a' -> Test { Value = a }");
    var result = (dynamic)dynamicParser.Parse("a");
    Assert.AreEqual("Test", result.Identifier);
    Assert.AreEqual('a', (char)result.Value);
}

Matching multiple items

+ means One Or More. Here we’re matching an arbitrary number of a’s. This would fail if there were 0 a’s though.

[Test]
public void OneOrMoreMatchTest()
{
    var dynamicParser = DynamicParser.CompileRule("'a'+");
    var result = (dynamic)dynamicParser.Parse("a");
    Assert.AreEqual('a', (char)result[0]);

    result = dynamicParser.Parse("aaa");
    Assert.AreEqual('a', (char)result[0]);
    Assert.AreEqual('a', (char)result[1]);
    Assert.AreEqual('a', (char)result[2]);
}

Calling custom extensions

AsString() is actually a static method defined on Common. For now I am only searching for extensions in a very explicit whitelist. This will probably change into an Assembly whitelist eventually though.

[Test]
public void ExtensionReferenceProjectionTest()
{
    var dynamicParser = DynamicParser.CompileRule(
        @"'a' -> ""abc"".AsString()",
        typeof(MetaSharp.Transformation.Extensions.Common));

    var result = (dynamic)dynamicParser.Parse("a");
    Assert.AreEqual("abc", (string)result);
}

Static inheritance from a dynamic grammar

This one is a little crazy. Here we are actually doing the full grammar code not the abbreviated version and we are inheriting (that’s what the ‘<’ means) from BasicParser which is a static Type as you can tell by the white list. In grammar inheritance you can optionally add a Main rule which will be added to a queue of processors for the specified input. In this case BasicParser inherits from BasicInterleave which inherits from BasicTokenizer. So the input stream will be tokenized, interleaved then parsed by this dynamic grammar. Each step parses the output of the previous step. If you don’t have a Main rule you will be skipped but you can still provide rules for inheriting grammars to reference as well as override rules of grammars you are inheriting from.

[Test]
public void GrammarStaticInheritanceTest()
{
    var grammar = new GrammarGrammar();
    var unit = (GrammarUnitNode)grammar.Parse(@"
        namespace N:
            import MetaSharp.Transformation.Extensions;
            import MetaSharp.Transformation.Parsing.Common;

            grammar X < BasicParser:
                Main = a:(""a"" ""b"" ""c"") -> a.Flatten();
            end
        end");

    var parser = unit.DynamicCompile(
        "N.X",
        typeof(MetaSharp.Transformation.Extensions.Common),
        typeof(MetaSharp.Transformation.Parsing.Common.BasicParser));

    var result = (dynamic)parser.Parse("a b c");
    Assert.AreEqual("a", (string)result[0]);
    Assert.AreEqual("b", (string)result[1]);
    Assert.AreEqual("c", (string)result[2]);
}

Dynamic inheritance

This is essentially the same thing except in this case one of the dynamic grammars is inheriting from another dynamic grammar. You can create both and use them both.

[Test]
public void GrammarDynamicInheritanceDualNamespaceTest()
{
    var grammar = new GrammarGrammar();
    var unit = (GrammarUnitNode)grammar.Parse(@"
        namespace A:
            grammar X:
                Main = 'a';
            end
        end
        namespace B:
            import A;

            grammar Y < X:
            end
        end");

    var parser = unit.DynamicCompile("A.X");
    var result = (dynamic)parser.Parse("a");
    Assert.AreEqual('a', (char)result);

    parser = unit.DynamicCompile("B.Y");
    result = (dynamic)parser.Parse("a");
    Assert.AreEqual('a', (char)result);
}

Rule references and parameterized rules

You can also create as many rules as you want and reference them, including parameterized rules like below.

[Test]
public void ParameterizedRuleReferenceTest()
{
    var parser = DynamicParser.Compile(
        @"namespace N:
            import MetaSharp.Transformation.Extensions;
            grammar X:
                Main = (Expr('a'..'z') | ' ')+;
                Expr(a) = str:a+ -> str.AsString();
            end
        end",
        "N.X",
        typeof(MetaSharp.Transformation.Extensions.Common));

    var result = (dynamic)parser.Parse("hello world");
    Assert.AreEqual("hello", (string)result[0]);
    Assert.AreEqual(' ', (char)result[1]);
    Assert.AreEqual("world", (string)result[2]);
}

Direct left recursion

Direct left recursion is when, on the left hand side of a rule body you are referencing itself directly. This results in recursion but is completely solvable by PatternMatching grammars. Below the Expr rule is an example of DLR because it is referencing itself. DLR is a useful way to solve problems of forward lookup, such as binary expressions like below.

DLR is direct as opposed to indirect left recursion, where you reference a Rule which then references that Rule back directly. Indirect Left Recursion is also a solvable problem but I was not able to solve it for situations of cases of multiple nested indirect DLR. Also it results in a very confusing grammar which has diminishing returns in value. For now you get errors in the cases of indirect left recursion.

[Test]
public void LeftRecursiveReferenceTest()
{
    var parser = DynamicParser.Compile(
        @"namespace N:
            import MetaSharp.Transformation.Extensions;
            grammar X:
                Main = Expr;
                Expr = l:Expr '+' r:Expr -> Binary { Left = l, Right = r, Operator = '+' }
                        | n:Num -> n.ToNumber();
                Num = '0'..'9';
            end
        end",
        "N.X",
        typeof(MetaSharp.Transformation.Extensions.Common));

    var result = (dynamic)parser.Parse("1+2+3+4");
    Assert.AreEqual("Binary", result.Identifier);
    Assert.AreEqual("Binary", result.Right.Identifier);
    Assert.AreEqual("Binary", result.Right.Right.Identifier);
    Assert.AreEqual(1, (int)result.Left);
    Assert.AreEqual(2, (int)result.Right.Left);
    Assert.AreEqual(3, (int)result.Right.Right.Left);
    Assert.AreEqual(4, (int)result.Right.Right.Right);
}

Overriding rules

Y is overriding the Expr rule to project true instead of false. Parsing using Y will now result in a new result compared to parsing with X. You can override rules on static grammars as well.

[Test]
public void RuleDynamicOverrideDynamicTest()
{
    var unit = DynamicParser.Parse(
        @"namespace N:
            grammar X:
                Main = Expr;
                Expr = any -> false;
            end
            grammar Y < X:
                override Expr = any -> true;
            end
        end");

    var parser = unit.DynamicCompile("N.X");
    var result = parser.Parse("1");
    Assert.IsFalse((bool)result);

    parser = unit.DynamicCompile("N.Y");
    result = parser.Parse("1");
    Assert.IsTrue((bool)result);
}

There is more too of course but this is probably too long already, it’s also not 100% complete yet. I will be considering it complete (sans bugs) when I can dynamically compile the Grammar grammar using itself! Next up:

  • Silverlight
  • VS integration
  • Polish and an actual release

Computation is Pattern Matching

This is my favorite single slide from the emerging languages conference.

pick_two

I think this sums up the struggle developers of today regularly encounter quite nicely. This image comes from Jonathan Edwards’ Coherence/Subtext talk slides. He went on to then propose some very interesting ideas on how to solve this problem by managing pointers and memory in a new scheme. I’m not able to really comment on his recommendations because I didn’t fully understand them. But what I would like to propose is that there actually might be another way to solve this same problem.

I believe that Pattern Calculus (or Pattern Matching) is a unification of these three problems. It’s a superset of lambda calculus and data structures.

978-3-540-89184-0_Jay_Cover_RawData.indd

Pattern Calculus

Computing with Functions and Structures
Jay, Barry
2009, XVII, 213 p. 58 illus., Hardcover
ISBN: 978-3-540-89184-0

I have yet to read this entire book but the foreward and introduction alone provide some deep gems, such as:

This book develops a new programming style, based on pattern matching,
from pure calculus to typed calculus to programming language. It can be viewed as
a sober technical development whose worth will be assessed in time by the programming
community. However, it actually makes a far grander claim, that the pattern matching
style subsumes the other main styles within it
. This is possible because it
is the first to fully resolve the tension between functions and data structures that has
limited expressive power till now. This introduction lays out the general argument,
and then surveys the contents of the book, at the level of the parts, chapters and
results.

The pattern calculus is a new foundation for computation, in which the expressive
power of functions and of data structures are fruitfully combined within pattern matching
functions. The best of existing foundations focus on either functions (in
the λ -calculus) or on data structures (in Turing machines) or compromise on both
(as in object-orientation). By contrast, a small typed pattern calculus supports all
the main programming styles, including functional, imperative, object-oriented and
query-based styles
.

The pattern calculus is the result of a profound re-examination of a 50-year development.
It attempts to provide a unifying approach, bridging the gaps between
different programming styles and paradigms according to a new slogan – computation
is pattern matching
.

It is surprising how this elementary principle allows one to uniformly and elegantly
cover the various programming paradigms, not only concerning execution
but also typing, which itself is also realized following the idea of pattern matching.

(emphasis mine)

Code itself can be thought of as data when viewed from inside a compiler. A compiler can transform that data into something executable. This process can be repeated any number of times. Alessandro Warth of OMeta contributes to this idea in his phd dissertation.

OMeta’s key insight is the realization that all of the passes in a traditional compiler are essentially pattern matching operations:

  • a lexical analyzer finds patterns in a stream of characters to produce a stream of
    tokens;
  • a parser matches a stream of tokens against a grammar (which itself is a collection
    of productions, or patterns) to produce abstract syntax trees (ASTs);
  • a typechecker pattern-matches on ASTs to produce ASTs annotated with types;
  • more generally, visitors pattern-match on ASTs to produce other ASTs;
  • finally, a (naive) code generator pattern-matches on ASTs to produce code.

And I agree with these guys. I have been working on a MetaSharp for a while now and on some of my more ponderous days I have seen to the bottom of the rabbit hole and come to the conclusion that they are right. I’m able to see a world where an application is entirely based upon pattern matching principles. Starting with a core of Patterns you can represent and transform to and from any design pattern imaginable including those needed to create traditional compilers. Essentially this gives you the ability to author an entire application as essentially tiers of patterns and projections.

I would like to contribute to the area of Pattern Matching by talking about the promise of scalability. In traditional general purpose programming as your application grows larger it becomes more and more difficult to maintain it. The sheer volume of code becomes infeasible to make broad changes with refactoring tools, the application becomes harder and harder to grasp in its entirety. Also, design patterns implied in the code become harder to enforce as developers begin to encounter new areas for the first time. There are many challenges that arise as an application grows.

Roman Ivantsov gave an interesting talk on ERP software and the scalability challenges it faces at the 2008 Lang.Net Symposium. Basically ERP programs are humongous applications, they are complex, costly and risky. What I took away from Roman’s talk, however, is that the solution to the problem is that we need a new approach to address applications of this scale. We cannot develop these applications purely as general purpose languages and succeed.

And again, I believe him. I think he is correct. As applications get bigger they can actually take so long to develop that they are obsolete before they are actually done. This is a problem.

Maintenance cost in Volume, for traditional applications.

scalability

Which is to say as your application becomes larger and you add more and more tiers the complexity also grows. The cost is like a pyramid. There are many things that go into Maintainability but in a general sense it might be said that maintainability is a function of code size and complexity.

Pattern matching offers an alternative to this traditional conundrum. It’s maintainability illustration is more columnar.

Maintenance cost in Volume, for pattern matching based applications.

scalability_patternmatching

Which is to say, that at each tier of an application the complexity could be about the same as the previous tier, thus increasing the functionality of an application for the same volume (cost) of maintainability. Interestingly enough, for small applications or applications with only a single tier the cost is probably higher. But as you grow  you begin to reap benefits.

This is a hypothesis of mine currently, it has yet to be proven however. Also, given the state of Pattern Matching as it exists today the above promises are definitively false. However I don’t think it needs to be this way. I think it is possible to change solve this problem and usher in a new era of software development paradigms.