Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write an alias of Raku regexes?

I wrote a grammar like this:

grammar StatementFormat {
    token TOP { (<plain> | '%' <placeholder>)* }

    token plain { <-[%]> }

    token placeholder {
        | <verb>
        | <noun>
        | <adverb>
    }

    token verb {
        'v'
        {
            # some actions
        }
    }

    token noun {
        'n'
        {
            # some actions
        }
    }

    token adverb {
        'a'
        {
            # some actions
        }
    }
}

So I could use it to parse strings like "someone %v %n %a".

However, I found there were so many usages like "%v %n %a", I'd like to give it an alias, say, "%b" such that parsing "someone %b" is equivalent to parsing "someone %v %n %a".

So is there a way to do that?

Of course, token alias { 'b' { ... } } can do that. But in that way I need to repeat that action code. I am wondering if there exists a simpler way.

like image 621
lovetomato Avatar asked Jul 15 '20 11:07

lovetomato


1 Answers

So, there is one obvious way, which is to simply put the code for the actions into subroutines and then in the b alias, call them:

sub verb-action($/) { }
sub noun-action($/) { }
sub adverb-action($/) { }

grammar StatementFormat {
    # rest goes here

    token verb {
        'v'
        { verb-action($/) }
    }

    token noun {
        'n'
        { noun-action($/) }
    }

    token adverb {
        'a'
        { adverb-action($/) }
    }

    token alias {
        'b'
        {
            verb-action($/);
            noun-action($/);
            adverb-action($/);
        }
    }
}

But where'd be the fun of that?

Instead, I'd recommend using the built-in action object feature of grammars.

It goes like this: you have a separate class with the actions as methods, with the same name as the grammar actions:

class StatementFormatActions {
    method verb($/) { ... }
    method noun($/) { ... }
    method adverb($/) { ... }

}

And when you call parse, you pass an instance of that action class along:

StatementFormat.parse($string, :actions(StatementFormatActions.new));

Then when you introduce the alias token, you can also introduce an alias method:

method alias($/) {
    self.verb($/);
    self.noun($/);
    self.adverb($/);
}

Inside the actions you can also call make or $/.make(...) to attach the result of your actions to the match object (then available in$/.made) to populate an AST from your parse tree.

(You might also like my book on grammars which has several examples and more in-depth explanations. Sorry for the plug, could not resist).

like image 97
moritz Avatar answered Dec 29 '22 06:12

moritz