Grammar Inheritance

The similarity of grammars to classes goes deeper than storing regexes in a namespace as a class might store methods. You can inherit from and extend grammars, mix roles into them, and take advantage of polymorphism. In fact, a grammar is a class which by default inherits from Grammar instead of Any.

Suppose you want to enhance the JSON grammar to allow single-line C++ or JavaScript comments, which begin with // and continue until the end of the line. The simplest enhancement is to allow such a comment in any place where whitespace is valid.

However, JSON::Tiny::Grammar only implicitly matches whitespace through the use of rules, which are like tokens but with the :sigspace modifier enabled. Implicit whitespace is matched with the inherited regex <ws>, so the simplest approach to enable single- line comments is to override that named regex:

    grammar JSON::Tiny::Grammar::WithComments
        is JSON::Tiny::Grammar {

        token ws {
            \s* [ '//' \N* \n ]?
        }
    }

    my $tester = '{
        "country":  "Austria",
        "cities": [ "Wien", "Salzburg", "Innsbruck" ],
        "population": 8353243 // data from 2009-01
    }';

    if JSON::Tiny::Grammar::WithComments.parse($tester) {
        say "It's valid (modified) JSON";
    }

The first two lines introduce a grammar that inherits from JSON::Tiny::Grammar. As subclasses inherit methods from superclasses, so any grammar rule not present in the derived grammar will come from its base grammar.

In this minimal JSON grammar, whitespace is never mandatory, so ws can match nothing at all. After optional spaces, two slashes '//' introduce a comment, after which must follow an arbitrary number of non- newline characters, and then a newline. In prose, the comment starts with '//' and extends to the rest of the line.

Inherited grammars may also add variants to proto tokens:

    grammar JSON::ExtendedNumeric is JSON::Tiny::Grammar  {
        token value:sym<nan> { <sym> }
        token value:sym<inf> { <[+-]>? <sym> }
    }

In this grammar, a call to <value> matches either one of the newly added alternatives, or any of the old alternatives from the parent grammar JSON::Tiny::Grammar. Such extensibility is difficult to achieve with ordinary, | delimited alternatives.