Why not reuse the rules and actions of other languages to easily create your grammars ? How about extending your envirnoment with your own language semantics ? GrammarTraits allow you to achieve these goals and more by providing a unit of composition for MOG rules and ASL Actions.

Similarly to classical traits, you can compose and describe requirements for rules and actions, as well as use aliasing, exclusion and overriding to resolve conficts.

What is different about this workflow, is the ability to abstract and generalize the sub-parts of your grammars and parsers so that they can be re-used and composed in different ways. Here is for example the definition of a message and msg-send as a seperate GrammarTrait. Notice that the definition focuses only on messages and does not include a specific rule for <expression>. <expression> in this case is a requirement, that can have a different definition in different grammars depending on the final composition. Just plug-n-play:

gTraitsPlugNPlay

In order to start using GrammarTraits to compose your recognizers all you need to do is declare the usage of MOGRules (the root GrammarTrait for MOG definitions) in an otherwise normal Trait:

gTraitsMOGRules

This will allow the system and the Gray algorithm to treat your GrammarTrait as part of an eventual grammar definition.

Similarly, to define a GrammarTrait for your parsers, all you need to do is declare the usage of ASLActions (the root GrammarTrait for ASL actions):

gTraitsASLActions

Pharo Recognizers and Parsers in Lan.d.s

You can now start defining and using your GrammarTraits in recognizers and parsers. For example here is how the entire Pharo Grammar included with Lan.d.s is defined using GrammarTaits:

gTraitsPharo

Similarly, The Pharo parser of Lan.d.s, is assembled the same way, using GrammarTraits of ASLActions:

gTraitsPharoParser

This decomposition of both recognizer (into GrammarTraits of MOG rules) and parser (GrammarTraits of ASL actions), does not only allow us to re-use parts of Pharo in other projects but also to easily extend and evolve our languages (which in this example happens to be Pharo itself). Let’s have a close look at an example.

Extending Pharo

We are going to extend Pharo using GrammarTraits with the following syntax and semantics:

  • Classic Control (GrammarTrait)
    • Braces blocks
    • For statement
    • While statement
    • If statement
    • Return statement
  • Imperative Style (GrammarTrait)
    • Imp. Method Declaration
    • Imp. Method Invocation
    • Var declarations and init
    • Bracket indexing
  • Functors (GrammarTrait)
    • Function Blocks
    • Functor Invocation

Each major category has two GrammarTraits (one for defining the MOG rules and one for ASL actions). Each feature in the category is implemented by one (or more) MOG or ASL methods, inside the GrammarTraits. The resulting extented grammar composition has the following form:

gTraitsExtPharoGrammar

Notice here how naturally expressed are the main composition semantics i.e.:

PharoGrammar + ClassicControl + Functors + ImperativeStyle

and how easy it is to resolve conflicts (through exclusion in this case), of core MOG rules of Pharo that are re-defined in the three new GrammarTraits:

PharoGrammar - {#message. #primaryValue. #statements. #temporariesDeclaration. #methodDeclaration}

Similarly for the parser, here is how to express the extended semantics and combine them with the original parser:

gTraitsExtPharoParser

The composition here is even easier, since most of the conflicts were already handled in the recognizer:

PharoGrammarActions - {#temporariesDeclaration} + ClassicControlParser + FunctorsParser + ImperativeStyleParser

In order to use the new parser, semantics and (optionally) alternative syntax highlighting in your classes, all you need to do is use the GrammarTrait API as follows:

gTraitsInstallAPI

To paraphrase A. Kay, the best way to predict the future is:

Object subclass: #Prediction uses: Future syntax

The results, speak for themselves. Here is an extented version of the Smalltalk postcard (from an alternative reality where Smalltalk succumbed to peer pressure and adopted a mainstream syntax):

gTraitsAltPostcard

Here is an annotated version of the postcard showing the extend and depth of the makeover:

gTraitsAltPostcardAnnotated

Remember that these are real-world byte-compiled extentions. Moreover, especially for this example, there is no run-time penalty whatsoever as the extentions are completely equivalent (at the bytecode level) with the Pharo-only version of the postcard:

gTraitsPostcard

Of course our example would not be complete, if we didn’t combine old and new syntax in the same method (proving that at least in some universes, a syntax closer to Smalltalk can be in the mainstream):

gTraitsAltMixedPostcard